蓝牙简学(四)

提示:文章写完后,目录可以自动生成,如何生成可参考右边的帮助文档

文章目录

  • HID协议
    • 一、摘要
    • 二、设备实现
      • 1. 大概要写的数据解释
      • 2. 代码例子
      • 3. 代码例子(c)


HID协议

一、摘要

HID(Human Interface Device)人体学接口设备。
由其名称可以了解HID设备是直接与人交互的设备,比如键盘、鼠标、游戏手柄、翻页笔、蓝牙自拍杆等等,其既可以使用usb接口来实现,也可以使用在蓝牙作为传输层,实现无线HID设备,也就是说,BLE HID协议规范其实是以USB HID协议规范为蓝本的,可以认为是USB HID的无线方式。

二、设备实现

1. 大概要写的数据解释

蓝牙HID设备的实现一般需要两个条件
1.在广播数据中广播HID的UUID,设备外观,设备名称等信息
2.在GATT中实现HID要求的服务和特性。

比如:
HID服务的UUID是

00001812-0000-1000-8000-00805f9b34fb

0x1812,是短uuid
键盘外观的标识符是0x03c1,
鼠标外观是0x03c2,
游戏手柄的外观是0x03c3

直接搜索下面这个文档就可以查看,更多资料放在最后最下面
Bluetooth Assigned Numbers
在这里插入图片描述
广播数据中广播的UUID,设备外观,设备名称

LengthAD TypeDate含义
0x020x010x05设备标识(flags)低功耗设备,有限发现模式
0x030x030x1218HID服务UUID
0xn0x09设备名称,自由设置完整的设备名称(utf-8编码)
0x030x190xc203设备外观

在GATT中实现HID要求的服务和特性。

类型UUID功能读写权限
服务0x1812HID服务的UUid
特性0x2a4aHID设备信息READ
特性0x2a4bHID Report Map(上报给主机的数据描述)read
特性0x2a4cHID Control Point(主机状态指示)write
特性0x2a4d数据上报(必须2908描述)读 通知
特性0x2a4d数据上报(必须2908描述)读 写
特性0x2a4e协议模式控制读 写

在这里插入图片描述
关于上面的服务和特性(也可以说是HID profile介绍,配置)详细介绍如下

0x1812是HID 服务的UUID,必须使用这个UUID实现服务

0x2a4a是 HID Information的特性UUID,主要功能是展示HID的信息,他的值是4个字节:前两个字节是HID版本,一半填入0x01,0x01,标示版本号–为1.1
第三个字节是Country Code(国家代码),视情况填,这里填0x00
第四个字节是 HID Flags,一般填入0x02,表示 Normally Connectable

0x2a4b 是Report Map()的特性UUID,主要功能是描述HID设备与HID主机数据交互的方式,即两者之间所发送的数据每一位的含义。

0x2a4c是Control Point的特性UUId,该特性一定要可写,HID主机通过该特性告知HID设备主机的状态,比如电脑休眠后会告知蓝牙鼠标也进入低功耗模式。

0x2a4d是HID设备与HID主机之间交互数据(Report)的特性UUID。对于键盘设备,当某个按键按下时,HID设备发送数据到HID主句;当开关CapsLock和ScrollLook功能时,HID主机将相关指示灯的状态发送给HID键盘。所以键盘设备需要两个UUID为0x2a4d的特性,一个用于发送数据,一个用于接受数据(使用UUID为0x2908的描述来区分)。而对于鼠标,游戏手柄这种只发送数据给电脑的设备,只需要定义一个0x2a4d的特性用来发送数据就可以了。
0x2a4e 是协议模式的特性UUID,对于键盘和鼠标这两种设备,可能也会在电脑BIOS阶段使用,此阶段的计算机没有进入系统,难以支持复杂的设备。所以键盘鼠标就有两种模式,分别是Report模式和Boot模式,系统启动前使用的是Boot模式,HID设备与HID主机之间使用固定的数据格式进行交互。系统启动完成后,HID主机会通过该特性发数据给HID设备,通知HID设备切换成Report模式,在Report模式下,数据格式由 Report Map 决定。
该特性的数据值为0x00表示Boot模式,0x01表示Report模式。

2. 代码例子

蓝牙键盘代码

from machine import Pin
import ubluetooth #导入BLE功能模块
from bluetooth import UUID

ble = ubluetooth.BLE()  #创建BLE设备
ble.active(True)  #打开BLE

ble.config(gap_name="ESP Keyboard")
ble.config(mtu=23)

HIDS = (                              # Service description: describes the service and how we communicate
    UUID(0x1812),                     # Human Interface Device
    (
        (UUID(0x2A4A), ubluetooth.FLAG_READ),       # HID information
        (UUID(0x2A4B), ubluetooth.FLAG_READ),       # HID report map
        (UUID(0x2A4C), ubluetooth.FLAG_WRITE),      # HID control point
        //一个用于发送数据,一个用于接受数据
        (UUID(0x2A4D), ubluetooth.FLAG_READ | ubluetooth.FLAG_NOTIFY, ((UUID(0x2908), 1),)),  # HID report / reference
        (UUID(0x2A4D), ubluetooth.FLAG_READ | ubluetooth.FLAG_WRITE,  ((UUID(0x2908), 1),)),  # HID report / reference
        
        (UUID(0x2A4E), ubluetooth.FLAG_READ | ubluetooth.FLAG_WRITE), # HID protocol mode
    ),
)

services = (HIDS,)
handles = ble.gatts_register_services(services)

KEYBOARD_REPORT = bytes([    # Report Description: describes what we communicate
            0x05, 0x01,      # USAGE_PAGE (Generic Desktop)
            0x09, 0x06,      # USAGE (Keyboard)
            0xa1, 0x01,      # COLLECTION (Application)
            0x85, 0x01,      #     REPORT_ID (1)
            0x75, 0x01,      #     Report Size (1)
            0x95, 0x08,      #     Report Count (8)
            0x05, 0x07,      #     Usage Page (Key Codes)
            0x19, 0xE0,      #     Usage Minimum (224)
            0x29, 0xE7,      #     Usage Maximum (231)
            0x15, 0x00,      #     Logical Minimum (0)
            0x25, 0x01,      #     Logical Maximum (1)
            0x81, 0x02,      #     Input (Data, Variable, Absolute); Modifier byte
            0x95, 0x01,      #     Report Count (1)
            0x75, 0x08,      #     Report Size (8)
            0x81, 0x01,      #     Input (Constant); Reserved byte
            0x95, 0x05,      #     Report Count (5)
            0x75, 0x01,      #     Report Size (1)
            0x05, 0x08,      #     Usage Page (LEDs)
            0x19, 0x01,      #     Usage Minimum (1)
            0x29, 0x05,      #     Usage Maximum (5)
            0x91, 0x02,      #     Output (Data, Variable, Absolute); LED report
            0x95, 0x01,      #     Report Count (1)
            0x75, 0x03,      #     Report Size (3)
            0x91, 0x01,      #     Output (Constant); LED report padding
            0x95, 0x06,      #     Report Count (6)
            0x75, 0x08,      #     Report Size (8)
            0x15, 0x00,      #     Logical Minimum (0)
            0x25, 0x65,      #     Logical Maximum (101)
            0x05, 0x07,      #     Usage Page (Key Codes)
            0x19, 0x00,      #     Usage Minimum (0)
            0x29, 0x65,      #     Usage Maximum (101)
            0x81, 0x00,      #     Input (Data, Array); Key array (6 bytes)
            0xc0             # END_COLLECTION
        ])

#设置BLE广播数据并开始广播
ble.gap_advertise(100, adv_data = b'\x02\x01\x05'
                                + b'\x03\x03\x12\x18' #HID UUID
                                + b'\x03\x19\xC1\x03' #设备外观为键盘
                                + b'\x0D\x09' + "ESP Keyboard".encode("UTF-8"))

(h_info, h_map, _, h_repin, h_d1, h_repout, h_d2, h_model,) = handles[0]
# Write service characteristics 写服务特征
ble.gatts_write(h_info, b"\x01\x01\x00\x02")     # HID info: ver=1.1, country=0, flags=normal
ble.gatts_write(h_map, KEYBOARD_REPORT)    # HID input report map
ble.gatts_write(h_d1, b"\x01\x01")  # HID reference: id=1, type=input
ble.gatts_write(h_d2, b"\x01\x02")  # HID reference: id=1, type=output
ble.gatts_write(h_model, b"\x01")   # HID Protocol Model: 0=Boot Model, 1=Report Model


key = Pin(0,Pin.IN)#IO 0 用作按键
while True:
  if key.value() == 0:
    while key.value() == 0:
      pass
    ble.gatts_notify(0, h_repin, b'\x00\x00\x1e\x00\x00\x00\x00\x00')#按键1按下
    ble.gatts_notify(0, h_repin, b'\x00\x00\x00\x00\x00\x00\x00\x00')#按键1抬起

蓝牙键盘,按下设备上IO0对应的按键,发送按键1到HID主机。

按键对应的代码可搜索HID KeyCode,这里是部分

#define _KEY_Z 0x1d // Keyboard z and Z
#define _KEY_1 0x1e // Keyboard 1 and !
#define _KEY_ENTER 0x28 // Keyboard Return (ENTER)
#define _KEY_ESC 0x29 // Keyboard ESCAPE
b'\x00\x00\x1e\x00\x00\x00\x00\x00'

这个叫ReportMap,为8个字节,是键盘发给主机的数据
第一个字节代表一些特殊的按键(Modifier按键),比如ctrl,gui
第二字节保留,第三到第八字节标示6个按键,数据值为零表示无按键按下.

3. 代码例子(c)

杰理鼠标报表分析(c)

static const u8 mouse_report_map[] = {
#if TCFG_KEYBOARD_EN
    0x05, 0x01,        // Usage Page (Generic Desktop Ctrls)
    0x09, 0x06,        // Usage (Keyboard)
    0xA1, 0x01,        // Collection (Application)
    0x85, KEYBOARD_REPORT_ID,//   Report ID (1)
    0x05, 0x07,        //   Usage Page (Kbrd/Keypad)
    0x19, 0xE0,        //   Usage Minimum (0xE0)
    0x29, 0xE7,        //   Usage Maximum (0xE7)
    0x15, 0x00,        //   Logical Minimum (0)
    0x25, 0x01,        //   Logical Maximum (1)
    0x75, 0x01,        //   Report Size (1)
    0x95, 0x08,        //   Report Count (8)
    0x81, 0x02,        //   Input (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position)
    0x95, 0x01,        //   Report Count (1)
    0x75, 0x08,        //   Report Size (8)
    0x81, 0x01,        //   Input (Const,Array,Abs,No Wrap,Linear,Preferred State,No Null Position)
    0x95, 0x03,        //   Report Count (3)
    0x75, 0x01,        //   Report Size (1)
    0x05, 0x08,        //   Usage Page (LEDs)
    0x19, 0x01,        //   Usage Minimum (Num Lock)
    0x29, 0x03,        //   Usage Maximum (Scroll Lock)
    0x91, 0x02,        //   Output (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position,Non-volatile)
    0x95, 0x05,        //   Report Count (5)
    0x75, 0x01,        //   Report Size (1)
    0x91, 0x01,        //   Output (Const,Array,Abs,No Wrap,Linear,Preferred State,No Null Position,Non-volatile)
    0x95, 0x06,        //   Report Count (6)
    0x75, 0x08,        //   Report Size (8)
    0x15, 0x00,        //   Logical Minimum (0)
    0x26, 0xFF, 0x00,  //   Logical Maximum (255)
    0x05, 0x07,        //   Usage Page (Kbrd/Keypad)
    0x19, 0x00,        //   Usage Minimum (0x00)
    0x2A, 0xFF, 0x00,  //   Usage Maximum (0xFF)
    0x81, 0x00,        //   Input (Data,Array,Abs,No Wrap,Linear,Preferred State,No Null Position)
    0xC0,              // End Collection
    0x05, 0x0C,        // Usage Page (Consumer)
    0x09, 0x01,        // Usage (Consumer Control)
    0xA1, 0x01,        // Collection (Application)
    0x85, COUSTOM_CONTROL_REPORT_ID,//   Report ID (3)
    0x75, 0x10,        //   Report Size (16)
    0x95, 0x01,        //   Report Count (1)
    0x15, 0x00,        //   Logical Minimum (0)
    0x26, 0x8C, 0x02,  //   Logical Maximum (652)
    0x19, 0x00,        //   Usage Minimum (Unassigned)
    0x2A, 0x8C, 0x02,  //   Usage Maximum (AC Send)
    0x81, 0x00,        //   Input (Data,Array,Abs,No Wrap,Linear,Preferred State,No Null Position)
    0xC0,              // End Collection

    // Dummy mouse collection starts here
    //
    0x05, 0x01,                         // USAGE_PAGE (Generic Desktop)     0
    0x09, 0x02,                         // USAGE (Mouse)                    2
    0xa1, 0x01,                         // COLLECTION (Application)         4
    0x85, MOUSE_POINT_REPORT_ID,               //   REPORT_ID (Mouse)              6
    0x09, 0x01,                         //   USAGE (Pointer)                8
    0xa1, 0x00,                         //   COLLECTION (Physical)          10
    0x05, 0x09,                         //     USAGE_PAGE (Button)          12
    0x19, 0x01,                         //     USAGE_MINIMUM (Button 1)     14
    0x29, 0x02,                         //     USAGE_MAXIMUM (Button 2)     16
    0x15, 0x00,                         //     LOGICAL_MINIMUM (0)          18
    0x25, 0x01,                         //     LOGICAL_MAXIMUM (1)          20
    0x75, 0x01,                         //     REPORT_SIZE (1)              22
    0x95, 0x02,                         //     REPORT_COUNT (2)             24
    0x81, 0x02,                         //     INPUT (Data,Var,Abs)         26
    0x95, 0x06,                         //     REPORT_COUNT (6)             28
    0x81, 0x03,                         //     INPUT (Cnst,Var,Abs)         30
    0x05, 0x01,                         //     USAGE_PAGE (Generic Desktop) 32
    0x09, 0x30,                         //     USAGE (X)                    34
    0x09, 0x31,                         //     USAGE (Y)                    36
    0x15, 0x81,                         //     LOGICAL_MINIMUM (-127)       38
    0x25, 0x7f,                         //     LOGICAL_MAXIMUM (127)        40
    0x75, 0x08,                         //     REPitORT_SIZE (8)              42
    0x95, 0x02,                         //     REPORT_COUNT (2)             44
    0x81, 0x06,                         //     INPUT (Data,Var,Rel)         46
    0xc0,                               //   END_COLLECTION                 48
    0xc0                                // END_COLLECTION

#else
    0x05, 0x01,        // Usage Page (Generic Desktop Ctrls)
    0x09, 0x02,        // Usage (Mouse)
    0xA1, 0x01,        // Collection (Application)
    0x85, 0x01,        //   Report ID (1)
    0x09, 0x01,        //   Usage (Pointer)
    0xA1, 0x00,        //   Collection (Physical)
    0x95, 0x05,        //     Report Count (5)
    0x75, 0x01,        //     Report Size (1)
    0x05, 0x09,        //     Usage Page (Button)
    0x19, 0x01,        //     Usage Minimum (0x01)
    0x29, 0x05,        //     Usage Maximum (0x05)
    0x15, 0x00,        //     Logical Minimum (0)
    0x25, 0x01,        //     Logical Maximum (1)
    0x81, 0x02,        //     Input (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position)
    0x95, 0x01,        //     Report Count (1)
    0x75, 0x03,        //     Report Size (3)
    0x81, 0x01,        //     Input (Const,Array,Abs,No Wrap,Linear,Preferred State,No Null Position)
    0x75, 0x08,        //     Report Size (8)
    0x95, 0x01,        //     Report Count (1)
    0x05, 0x01,        //     Usage Page (Generic Desktop Ctrls)
    0x09, 0x38,        //     Usage (Wheel)
    0x15, 0x81,        //     Logical Minimum (-127)
    0x25, 0x7F,        //     Logical Maximum (127)
    0x81, 0x06,        //     Input (Data,Var,Rel,No Wrap,Linear,Preferred State,No Null Position)
    0x05, 0x0C,        //     Usage Page (Consumer)
    0x0A, 0x38, 0x02,  //     Usage (AC Pan)
    0x95, 0x01,        //     Report Count (1)
    0x81, 0x06,        //     Input (Data,Var,Rel,No Wrap,Linear,Preferred State,No Null Position)
    0xC0,              //   End Collection
    0x85, 0x02,        //   Report ID (2)
    0x09, 0x01,        //   Usage (Consumer Control)
    0xA1, 0x00,        //   Collection (Physical)
    0x75, 0x0C,        //     Report Size (12)
    0x95, 0x02,        //     Report Count (2)
    0x05, 0x01,        //     Usage Page (Generic Desktop Ctrls)
    0x09, 0x30,        //     Usage (X)
    0x09, 0x31,        //     Usage (Y)
    0x16, 0x01, 0xF8,  //     Logical Minimum (-2047)
    0x26, 0xFF, 0x07,  //     Logical Maximum (2047)
    0x81, 0x06,        //     Input (Data,Var,Rel,No Wrap,Linear,Preferred State,No Null Position)
    0xC0,              //   End Collection
    0xC0,              // End Collection
#if 0
    0x05, 0x0C,        // Usage Page (Consumer)
    0x09, 0x01,        // Usage (Consumer Control)
    0xA1, 0x01,        // Collection (Application)
    0x85, 0x03,        //   Report ID (3)
    0x15, 0x00,        //   Logical Minimum (0)
    0x25, 0x01,        //   Logical Maximum (1)
    0x75, 0x01,        //   Report Size (1)
    0x95, 0x01,        //   Report Count (1)
    0x09, 0xCD,        //   Usage (Play/Pause)
    0x81, 0x06,        //   Input (Data,Var,Rel,No Wrap,Linear,Preferred State,No Null Position)
    0x0A, 0x83, 0x01,  //   Usage (AL Consumer Control Configuration)
    0x81, 0x06,        //   Input (Data,Var,Rel,No Wrap,Linear,Preferred State,No Null Position)
    0x09, 0xB5,        //   Usage (Scan Next Track)
    0x81, 0x06,        //   Input (Data,Var,Rel,No Wrap,Linear,Preferred State,No Null Position)
    0x09, 0xB6,        //   Usage (Scan Previous Track)
    0x81, 0x06,        //   Input (Data,Var,Rel,No Wrap,Linear,Preferred State,No Null Position)
    0x09, 0xEA,        //   Usage (Volume Decrement)
    0x81, 0x06,        //   Input (Data,Var,Rel,No Wrap,Linear,Preferred State,No Null Position)
    0x09, 0xE9,        //   Usage (Volume Increment)
    0x81, 0x06,        //   Input (Data,Var,Rel,No Wrap,Linear,Preferred State,No Null Position)
    0x0A, 0x25, 0x02,  //   Usage (AC Forward)
    0x81, 0x06,        //   Input (Data,Var,Rel,No Wrap,Linear,Preferred State,No Null Position)
    0x0A, 0x24, 0x02,  //   Usage (AC Back)
    0x81, 0x06,        //   Input (Data,Var,Rel,No Wrap,Linear,Preferred State,No Null Position)
    0x09, 0x05,        //   Usage (Headphone)
    0x15, 0x00,        //   Logical Minimum (0)
    0x26, 0xFF, 0x00,  //   Logical Maximum (255)
    0x75, 0x08,        //   Report Size (8)
    0x95, 0x02,        //   Report Count (2)
    0xB1, 0x02,        //   Feature (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position,Non-volatile)
    0xC0,              // End Collection
#endif

	0x05, 0x0C, 	   // Usage Page (Consumer)
    0x09, 0x01,		  // Usage (Consumer Control)
    0xA1, 0x01,		  // Collection (Application)
    0x85, 0x04,		  //   Report ID (4)
    0x75, 0x10,		  //   Report Size (16)
    0x95, 0x01,		  //   Report Count (1)
    0x15, 0x00,		  //   Logical Minimum (0)
    0x26, 0x8C, 0x02,  //   Logical Maximum (652)
    0x19, 0x00,		  //   Usage Minimum (Unassigned)
    0x2A, 0x8C, 0x02,  //   Usage Maximum (AC Send)
    0x81, 0x00,		  //   Input (Data,Array,Abs,No Wrap,Linear,Preferred State,No Null Position)
    0xC0,			  // End Collection

    0x05, 0x01,        // Usage Page (Generic Desktop Ctrls)
    0x09, 0x06,        // Usage (Keyboard)
    0xA1, 0x01,        // Collection (Application)
    0x85, 0x05,        //   Report ID (5)
    0x05, 0x07,        //   Usage Page (Kbrd/Keypad)
    0x95, 0x06,        //   Report Count (6)
    0x75, 0x08,        //   Report Size (8)
    0x15, 0x00,        //   Logical Minimum (0)
    0x26, 0xFF, 0x00,  //   Logical Maximum (255)
    0x05, 0x07,        //   Usage Page (Kbrd/Keypad)
    0x19, 0x00,        //   Usage Minimum (0x00)
    0x2A, 0xFF, 0x00,  //   Usage Maximum (0xFF)
    0x81, 0x00,        //   Input (Data,Array,Abs,No Wrap,Linear,Preferred State,No Null Position)
    0xC0,              // End Collection
    // 149 bytes
#endif
};

这是一个描述鼠标和键盘混合输入报告的HID(Human Interface Device)报告描述符。HID报告描述符用于定义设备与主机之间的通信格式,以便主机能够正确解释设备发送的数据。这段描述符描述了鼠标、消费者控制和键盘三个功能。

以下是这个报告描述符的主要部分:

1.鼠标报告(Report ID: 1):

该部分定义了鼠标的基本行为,包括鼠标按钮、坐标和滚轮。
Usage Page (Generic Desktop Ctrls) 表示使用通用桌面控制器的控制。
Usage (Mouse) 表示这是一个鼠标。
鼠标的报告数据包括5个字节,其中包括按钮状态和坐标信息。

2.用户控制报告(Report ID: 4):

该部分定义了消费者控制,如音量、播放/暂停等。
Usage Page (Consumer) 表示使用消费者控制的控制。
Usage (Consumer Control) 表示这是一个消费者控制设备。
报告数据包括一个16位的值,用于表示不同的消费者控制功能。

3.键盘报告(Report ID: 5):

该部分定义了键盘的基本行为,包括按键。
Usage Page (Generic Desktop Ctrls) 表示使用通用桌面控制器的控制。
Usage (Keyboard) 表示这是一个键盘。
报告数据包括6个字节,其中包括按键的状态。

4.Report ID: 3

这段代码块描述了一些消费者控制的相关信息,包括播放/暂停、配置、下一曲、上一曲、音量调节、前进、后退等操作。

5.Report ID: 2

这部分代码是 HID(Human Interface Device)报告描述的一部分,描述了一个具有 Report ID 为 2 的 Consumer Control 类型的输入报告。

具体描述如下:

Report ID (0x85, 0x02): 报告的唯一标识符,这里是 2。
Usage (0x09, 0x01): 使用 Consumer Control 功能。
Collection (0xA1, 0x00): 定义数据的集合,这里是 Physical(物理集合)。
Report Size (0x75, 0x0C): 每个数据项的位数,这里是 12 位。
Report Count (0x95, 0x02): 数据项的数量,这里是 2。
Usage Page (0x05, 0x01): 使用 Generic Desktop 控制页。
Usage (0x09, 0x30): 使用 X 轴。
Usage (0x09, 0x31): 使用 Y 轴。
Logical Minimum (0x16, 0x01, 0xF8): 逻辑最小值为 -2047。
Logical Maximum (0x26, 0xFF, 0x07): 逻辑最大值为 2047。
Input (0x81, 0x06): 表示这是一个输入项,具体是 Data、Var(变量)、Rel(相对),无 Wrap(不回绕),Linear(线性),Preferred State,No Null Position。
End Collection (0xC0): 结束此集合。

总体来说,这个报告描述了一个 Consumer Control 类型的输入报告,包含 X 和 Y 两个轴的信息,每个轴占用 12 位,取值范围是 -2047 到 2047。这样的报告通常用于描述类似于鼠标或者控制台遥控器等设备的输入。

一些资料:

Bluetooth Core Specification:

这是蓝牙技术的核心规范,提供了关于蓝牙协议栈、服务、特征以及UUID的详细信息。
这个规范通常包含多个卷,其中特定的UUID信息可能分布在不同的卷中。
Bluetooth Assigned Numbers:

这个文档列出了由Bluetooth SIG分配的所有标准UUID和其他数字标识符。你可以在这里找到各种服务、特征和配置文件的UUID。
GATT Specifications:

GATT(Generic Attribute Profile)是蓝牙协议栈中用于设备之间通信的一部分,包括定义了一些通用的服务和特征。相关的UUID信息可能在这里找到。
Profile Specifications:

不同的蓝牙设备和应用领域通常有特定的配置文件(Profile)规范,其中包含了定义的服务和特征以及相应的UUID。你可能需要查看与你的应用领域相关的配置文件规范。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mfbz.cn/a/356404.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

day11_oop

今日内容 零、 复习昨日 一、作业 二、封装 三、继承 四、重写 五、this和super 六、访问修饰符 零、 复习昨日 数组创建的两种方式 new int[3];new int[]{1,2,3,4}; 手写一个遍历输出数组元素的伪代码 构造方法什么作用? 创建对象,将对象的属性初始化 有参无参构造什么区别?…

高价画师的低价服务,会被AI绘画完全取代吗?

花3万块钱买一张画,值吗? 买家花三万块钱买一张网红画师眠狼的画,提前给出了参考图和要求,但最终拿到的作品却货不对板,脸和身体严重割裂,修改一次还要加一千,在互联网上闹得沸沸扬扬。 眠狼是业内著名的画手,又叠加上了网红的buff,参加过多次游戏二创活动,确实有一…

python集合是否可变总结

集合是一个无序的可变的序列。集合中的元素必须是可hash的,即不可变的数据类型。 空集合 aset() 注意a{}创建的是一个空字典。 set —— 可变集合。集合中的元素可以动态的增加或删除。 frozenset —— 不可变集合。集合中的元素不可改变。 注:对于…

C语言第十二弹--扫雷

✨个人主页: 熬夜学编程的小林 💗系列专栏: 【C语言详解】 【数据结构详解】 扫雷 1、扫雷游戏分析和设计 1.1、扫雷游戏的功能说明 1.2 游戏的分析和设计 1.2.1、数据结构的分析 1.2.2、文件结构设计 2、扫雷游戏的结构分析 2.1、用…

权威认可 | 全息网御多领域入选《CCSIP 2023中国网络安全行业全景册(第六版)》

2024年1月24日, FreeBuf咨询正式发布《CCSIP(China Cyber Security Industry Panorama)2023中国网络安全行业全景册(第六版)》。FreeBuf咨询全景图/全景册系列,以PDR网络安全模型为基础,并参考I…

springboot mongodb简单教程

(1)依赖 compile(org.springframework.boot:spring-boot-starter-data-mongodb) (2)application.properties配置文件 spring.data.mongodb.host127.0.0.1 spring.data.mongodb.port27017 spring.data.mongodb.databasetest &a…

开源大规模分布式MQTT消息服务器EMQX部署教程

1.EMQX是什么? EMQX 是一款开源的大规模分布式 MQTT 消息服务器,功能丰富,专为物联网和实时通信应用而设计。EMQX 5.0 单集群支持 MQTT 并发连接数高达 1 亿条,单服务器的传输与处理吞吐量可达每秒百万级 MQTT 消息,并…

openGaussdb5.0单点企业版部署_Centos7_x86

本文档环境:CentOS7.9 x86_64 4G1C40G python2.7.5 交互式初始化环境方式 介绍 openGauss是一款开源关系型数据库管理系统,采用木兰宽松许可证v2发行。openGauss内核深度融合华为在数据库领域多年的经验,结合企业级场景需求,持续…

回归预测 | Matlab实现CPO-LSSVM【24年新算法】冠豪猪优化最小二乘支持向量机多变量回归预测

回归预测 | Matlab实现CPO-LSSVM【24年新算法】冠豪猪优化最小二乘支持向量机多变量回归预测 目录 回归预测 | Matlab实现CPO-LSSVM【24年新算法】冠豪猪优化最小二乘支持向量机多变量回归预测效果一览基本介绍程序设计参考资料 效果一览 基本介绍 1.Matlab实现CPO-LSSVM【24年…

写静态页面——魅族导航_前端页面练习

0、效果&#xff1a; 1、html代码&#xff1a;&#xff1a; <!DOCTYPE html> <html lang"en"> <head><meta charset"UTF-8"><meta name"viewport" content"widthdevice-width, initial-scale1.0"><…

springboot+vue3支付宝接口案例-第二节-准备后端数据接口

springbootvue3支付宝接口案例-第二节-准备后端数据接口&#xff01;今天经过2个小时的折腾。准备好了我们这次测试支付宝线上支付接口的后端业务数据接口。下面为大家分享一下&#xff0c;期间发生遇到了一些弯路。 首先&#xff0c;我们本次后端接口使用的持久层框架是JPA。这…

Java基础数据结构之哈希表

概念 顺序结构以及平衡树 中&#xff0c;元素关键码与其存储位置之间没有对应的关系&#xff0c;因此在 查找一个元素时&#xff0c;必须要经过关键 码的多次比较 。 顺序查找时间复杂度为 O(N) &#xff0c;平衡树中为树的高度&#xff0c;即 O( log2N ) &#xff0c;搜索的效…

【极数系列】Flink环境搭建Linux版本 (03)

文章目录 引言01 Linux部署JDK11版本1.下载Linux版本的JDK112.创建目录3.上传并解压4.配置环境变量5.刷新环境变量6.检查jdk安装是否成功 02 Linux部署Flink1.18.0版本1.下载Flink1.18.0版本包2.上传压缩包到服务器3.修改flink-config.yaml配置4.启动服务5.浏览器访问6.停止服务…

1002. HarmonyOS 开发问题:鸿蒙 OS 技术特性是什么?

1002. HarmonyOS 开发问题&#xff1a;鸿蒙 OS 技术特性是什么? 硬件互助&#xff0c;资源共享 分布式软总线 分布式软总线是多种终端设备的统一基座&#xff0c;为设备之间的互联互通提供了统一的分布式通信能力&#xff0c;能够快速发现并连接设备&#xff0c;高效地分发…

Redis 笔记四

概要&#xff1a; 1.高并发场景秒杀抢购超卖bug实战重现 2.阿里巴巴内部高并发秒杀下单方案首次揭秘 3.基于ReddisMQ实现秒杀下单架构 4.10万订单每秒热点数据架构优化实践 5.秒杀下单MQ如何保证不丢失消息 6.解决MQ下单消息重复消费幂等机制详解 7.线上MQ百万秒杀订单发生积压…

系统架构设计师教程(十九)大数据架构设计理论与实践

大数据架构设计理论与实践 19.1 传统数据处理系统存在的问题19.2 大数据处理系统架构分析19.2.1 大数据处理系统面临挑战19.2.2 大数据处理系统架构特征19.3 Lambda架构19.3.1 Lambda架构对大数据处理系统的理解19.3.2 Lambda架构应用场景19.3.3 Lambda架构介绍19.3.4 Lambda架…

ctfshow web71

开启环境&#xff1a; c?><?php $anew DirectoryIterator("glob:///*"); foreach($a as $f) {echo($f->__toString(). );} exit(0); ?> cinclude("/flagc.txt");exit();

解决方案—幻兽帕鲁Palworld私服部署 一杯茶的功夫搭建部署一个属于自己的游戏私服

《幻兽帕鲁》是Pocketpair开发的一款开放世界生存制作游戏 &#xff0c;游戏于2024年1月18日发行抢先体验版本&#xff0c;游戏中&#xff0c;玩家可以在广阔的世界中收集神奇的生物“帕鲁”&#xff0c;派他们进行战斗、建造、做农活&#xff0c;工业生产&#xff0c;游戏目前…

2024年10大软件开发趋势

随着 2024 年的到来&#xff0c;技术进步和不断变化的市场需求正在推动软件开发领域继续呈指数级增长。对于组织和工程师来说&#xff0c;及时了解这些模式不仅有用&#xff0c;而且是保持残酷和有效的基础。在本文中&#xff0c;我们研究了预计将在 2024 年产生巨大影响的关键…

韶关一高层住宅突发火灾 富维烟火识别防止悲剧发生

近日&#xff0c;韶关市一高层住宅楼突发火灾&#xff0c;幸亏及时得到控制&#xff0c;未造成重大伤亡。这一事件再次提醒我们&#xff0c;高层建筑的火灾安全不容忽视。针对这一问题&#xff0c;北京富维图像公司的FIS智能图像识别系统显得尤为重要。 FIS系统利用已部署的监控…
最新文章