GATT defines a few procedures for discovering the services from a GATT database located on a GATT Server. These procedures rely on Attribute Protocol (ATT) operations.
One of those procedures is the Discover All Primary Services, which uses ATT’s Read By Group Type request/response.
The parameters for this request are:
In order to discover all primary services, you need to set the starting handle to 0x0001, the ending handle to 0xFFFF (these are the minimum and maximum values for attribute handles, so the search will be performed over the entire database) and the attribute type to 0x2800, which is the UUID for the <<Primary Service>> declaration.
The response from the Server will include a list of tuples corresponding to found services, each tuple consisting of:
The end-group handle is useful for two things.
One is to know the borders of each service, i.e. not only where it starts, but also where it ends. Keep in mind that attribute handles are not necessarily consecutive, so the start of a new service may very well not be equal to the end of the previous service plus one.
The other use is that obviously not all services can be sent in a single response if there are many services on the Server. The Server only sends as many as it can fit in the ATT packet. So the Client must continue the search, but for the next request he will not set the starting handle parameter to 0x0001, but instead it will set it to the last end-group handle from the previous response, plus one.
For example, let’s say the Server has this database structure (UUIDs are purely fictional):
After the first request (0x0001-0xFFFF), the Read By Group Type response will include these bytes, in order (LSB first):
The next service type is a 128-bit UUID, so the Server cannot include it in the response and it stops after the first two services.
The Client, upon seeing that the last service in this list ended at 0x0009, proceeds to sending a new Read By Group Type request with this handle range: 0x0010-0xFFFF.
The response will only include Service 3, so the Client will need to issue a third request with the range: 0x0019-0xFFFF.
After the third response, the Client will continue with a 4th request, with the range: 0x0031-0xFFFF. This time, it will get an Error Response with message “Attribute Not Found”.
Thus, it can safely conclude that Primary Service Discovery is complete.
See Bluetooth Core 4.1 specification, vol. 3, section 4.4.1 for more details and examples.