Client 使用此过程来发现Server上的主服务,使用Discover All Primary Services 或Discover Primary Services By Service UUID 子过程发现Server 公开的Primary服务,可以发现所有Primary服务或者通过UUID 发现某个特定Primary服务。待Client 发现主要服务后,可以通过Find Included Services 过程发现该主要服务所包含的其它服务。
有两个子过程可用于主服务发现:发现所有主服务和通过服务UUID发现主服务。
一、Discover All Primary Services
此子过程用于发现服务器上的所有主服务。
GATT是如何发现服务的呢?GATT协议是基于ATT协议,Client由APP层发送一个发现服务的command,APP层将这个command往下发送至GATT层,GATT收到后再往下ATT层发送,包含有APP层给的start handle 、end handle等,ATT的命令就是READ_BY_GROUP_TYPE_REQ,Client将请求发送至对端Server,对端Server的ATT收到请求后,寻找所需要的所有服务,找完所有的服务后,通过READ_BY_GROUP_TYPE_RSP响应,发送到Client的ATT层,ATT层再往上汇报,最终反馈给APP层,用户就可以得到所需要的所有服务。
当收到ATT_ERROR_RSP且错误代码设置为属性或“按类型读取组响应”中的结束组句柄为0xFFFF时,此子过程将完成。
如果在发现服务器上的所有主服务之前找到了所需的主服务,则允许提前结束子过程。
二、Discover Primary Services By Service UUID
当只知道服务UUID时,客户端将此子过程用于发现服务器上的特定主服务。特定的主服务可能在服务器上存在多次。正在发现的主服务由服务UUID标识。
跟Discover All Primary Services发现流程一样,只不过基于ATT的命令有所不同,Discover Primary Services By Service UUID是用FIND_BY_TYPE_VALUE_REQ,属性值设置为16位蓝牙UUID或128位UUID一起使用。start handle设置为0x0001,end handle设置为0xFFFF。Client将请求发送至对端Server,对端Server的ATT收到请求后,FIND_BY_TYPE_VALUE_REQ,寻找所有的服务,再和所需要的UUID进行对比,符合UUID的服务,通过FIND_BY_TYPE_VALUE_RSP响应,发送到Client的ATT层,ATT层再往上汇报,最终反馈给APP层,用户就可以得到所需要UUID的服务。
如果返回正在搜索的服务UUID的属性handle范围,而结束发现handle不是0xFFFF,则可以再次发出FIND_BY_TYPE_VALUE_REQ。并将start handle设置为大于FIND_BY_TYPE_VALUE_RSP PDU中的最后一个属性句柄范围+1。比如Server响应的handle是0x0200到0x0214,那么下一次的Client的start handle就是0x0215,end handle 是0xFFFF。
如果在发现服务器上支持的指定服务UUID的所有主服务之前找到了所需的主服务,则允许提前结束子过程。