蓝牙4.2:GATT、SPP、属性表、服务、特征

GATT&ATT处于蓝牙结构里主机(host)这一层级里

ATT基本属性:用通俗的话来说,ATT相当于设备的数据库。比如LED灯的状态。

GATT属性:定义了两个角色,GATTS(服务器)和GATTC(客户端),GATT独立与GAP角色,GATTS提供数据,客户端访问数据。一个设备可以同时充当服务器和客户端。

GATT独立于GAP,如何理解,下面是解释:GATT全称是通用属性配置文件,它的主要作用将设备各种数据组织成服务和特征,并通过协议进行读写、写入属性值、以方便设备间的信息通信,比如心率检测仪通过GATT将心率数据提供给其他设备。GAP全称是通用访问配置文件,它的主要作用是管理蓝牙设备的连接、设备发现以及设备角色的定义和管理,决定了设备如何进行广播、扫描、发起连接、和接收连接等操作,以及连接过程中扮演的角色,如中心设备和外围设备。简单来说,GAP负责蓝牙设备连接,GATT则负责数据的传输

GATT数据交互过程可以这样理解,GATT可以提供一个数据交换的通道,ATT是设备的属性,那如何去获取这个状态的数据呢?这时可以将LED灯的状态当成ATT,这个ATT信息存储在GATTS中,同时再搭建一个GATTC,此时客户端就可以通过请求GATTS服务,GATTS接收到请求后会发出GATT响应,将ATT里的内容,也就是LED的状态信息发送给GATTC。这个流程可以类似对比HTTP的流程,但是二者协议本质上是有差别的。

仍然以ESP32作为示例,打开官方demo进行进一步理解,相应示例位于该文件目录下

红框是具体要实现的功能:通过一块ESP32点亮另外一块ESP32的LED灯。蓝框是用于分析和参考,也就是一些结构体的定义规范需要参考该文件。

首先了解一下什么是SPP:指的是串口仿真协议(serial port profile),它是蓝牙协议中的一种,用于蓝牙设备之间模拟串口通信。其核心功能是允许蓝牙设备之间像传统串口线连接一样进行数据传输,它将蓝牙链路抽象成一个虚拟的串口,使得设备可以通过虚拟串口收发数据,就好像他们有物理串口连接一样。比如stm32串口挂了一个zigbee的集成模块,可以直接进行设备数据的交互,这个spp就充当了串口的功能,只不过是虚拟的,物理层面是不存在的。

现在我们来看SPP示例中初始化的流程和SPP的运行流程

图1 SPP初始化流程

1-6步都是之前文章提过的,是一个标准的ESP32蓝牙初始化流程。

图2 SPP运行流程

为什么是先从GATT APP注册开始?直接跳到了示例初始化的第八步?是因为在APP注册后,会产生GATT注册回调,GATT注册回调又会产生GAP回调,所以流程是没问题的。图中流程并非完全线性,而是一个不断跳转的过程。

图3 GATTS&GAP回调过程

这是GATTS&GAP回调的过程,绿色代表事件,蓝色代表执行的动作。SPP流程从注册APP开始,在开始注册时便会触发GATTS事件回调,对应图1中的第八步,在配置好广播数据之后,便触发了“设置广播数据”事件,此时就会触发GAP事件回调,这就解释了图2中流程为什么是从APP注册开始,而在图1中却处于第八步而不是第六步。在完成“配置广播数据”后,会进行“属性表创建”,同时也会开额外一个线程,产生并发,进行“开始广播操作”。“创建属性表”再次触发GATTS事件回调,然后开始进行“开始服务”

【补充说明:

属性表:类似于数据库,当客户端与服务器建立连接后,服务器会为每个服务分配一个属性句柄,并将其告知客户端,蓝牙内的所有成员(服务、特征、描述符)均有唯一的句柄,类似于指针,可以通过句柄去快速访问某一属性,并对属性进行操作

服务:一组相关特征的分类,由特征、UUID、服务属性句柄组成,它是对设备提供服务功能或数据上一种逻辑上的分组和抽象,每个服务都有一个唯一的UUID和服务属性句柄,用于区分不同类型的服务,例如,常见的心率服务,其 UUID 是一个特定的值,它包含了与心率监测相关的各种特征,如心率测量值、心率传感器状态等。

特征:特征值特征属性、描述符、特征UUID、属性句柄构成,类似于结构体,结构体名称叫服务,成员是一个或者多个特征、每个特征内含五个成员,一个特征值,一个特征属性,一个描述符、一个特征UUID,一个属性句柄,其中特征值是具体的数值a,特征属性是指对于该数值a的操作权限,如可写,可读等,描述符是指该数值a的数据格式、取值范围等,特征UUID是指设定一个唯一的编号定义该特征,以区分不同特征,属性句柄同上。UUID和属性句柄起互补作用,UUID主要用于查询搜索,句柄主要用于实际的操作

这样说太抽象了,举个例子吧,dht11采集温湿度,那么这个dht11就是一个服务,这个服务由两个特征组成,分别是温度和湿度,以温度特征为例,它记录了温度数据(特征值)数据是否可读可写(特征属性)、数据类型或取值范围(描述符)、dht11的定位编号(特征UUID)、特定属性句柄

结构大概就是这样,可以参考一下

 图4 GATTC回调过程

图5 GAP回调过程

GATT流程总结:GATTC向GATTS发送GATT请求,GATTC发送目标UUID,GATTS根据该UUID去寻找对应的服务,并将该服务的UUID和句柄范围返回到GATTC,随后GATTC可以发起特征发现请求,GATTS会在该句柄范围内去进行遍历,寻找目标特征,然后将目标特征的UUID和句柄返回到GATTC,GATTC拿到特定句柄后,便可直接通过句柄对特征值进行读写操作了。一般来说,UUID用于搜索,句柄用于特定操作。

先理清属性表、服务、特征的结构,再理清通信流程,多借助豆包或deepseek可能会更好理解。

下一章开始上ESP32蓝牙代码

### 使用 Docker 部署网页文件 #### 准备工作环境 为了使用 Docker部署网页文件,需要先确保目标机器上已经安装并配置好 Docker 引擎。对于云平台如 Azure 的用户来说,可以通过选择预配置选项 "Docker on Ubuntu Server" 快速搭建运行环境[^2]。 #### 创建项目结构 创建一个新的目录用于存放网站资源以及必要的构建脚本。在这个例子中假设该路径为 `/path/to/webapp`: ```bash mkdir -p /path/to/webapp/html && cd $_ echo "<html><body>Hello from Docker!</body></html>" > index.html ``` 上述命令会建立一个简单的 HTML 文件作为示例页面内容。 #### 编写 Dockerfile 接下来,在项目的根目录下编写 `Dockerfile` 描述镜像的组装过程。这里采用 Nginx 服务器来托管静态站点: ```dockerfile FROM nginx:alpine COPY html /usr/share/nginx/html EXPOSE 80 CMD ["nginx", "-g", "daemon off;"] ``` 这段定义指定了基础映像为基础精简版 NGINX,并复制本地的 HTML 文件夹到容器内的默认发布位置;最后暴露 HTTP 端口并启动服务进程[^3]。 #### 构建与推送镜像 完成以上准备工作之后就可以利用下面这条指令编译自定义镜像了: ```bash docker build -t my-web-app . ``` 如果打算将此镜像上传至远程仓库以便其他节点拉取,则需指定完整的标签名(例如包含用户名字的空间地址),并通过登录认证后执行 push 操作。 #### 启动容器实例 当一切就绪时,可以借助如下方式快速激活应用: ```bash docker run -d -p 80:80 --name web-server my-web-app ``` 这一步骤将会以前台守护模式开启新的容器,并将其内部监听的服务端口映射到宿主机相同编号之上,从而实现外部访问支持[^1]。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值