BLE under the microscope (ATTs GATTs…)

BLE under the microscope (ATTs GATTs...)

BLE under the microscope (ATTs GATTs…)

Part 1, overview

Quite a long time has already passed since the first specification for Bluetooth 4.0 was released. And, although the topic of BLE is very interesting, it still repels many developers due to its complexity. In my previous articles, I mainly considered the lowest level of the Link Layer and the Physical Layer. This made it possible to avoid such complex and confusing concepts as the Attribute Protocol (ATT) and the General Attribute Profile (GATT). However, there is nowhere to go, without understanding them, it is impossible to develop compatible devices. Today I would like to share this knowledge with you. In my article, I will rely on учебник for beginners from the Nordic site. So let's get started.

Why is everything so difficult?

In my opinion, it was immediately clear that managing devices through smartphones is a very promising and long-term topic. Therefore, it was decided to structure it immediately and to the maximum. So that manufacturers of various gadgets do not come up with their own protocols, which will then be incompatible. Hence the complexity. Already at the first stage, they tried to squeeze everything that was possible into the BLE protocol. It doesn't matter if it's useful later or not. In addition, we have provided the possibility of expanding the list of devices for the future.

Let's take a look at the picture where the BLE protocol diagram is drawn. It consists of several layers. The lowest, physical layer (PHY) is responsible for the radio channel of the device. Link Layer(LL) contains the entire sequence of bytes in the transmitted message. In previous articles, we studied it. Host Controller Interface (HCI) is an exchange protocol between BLE layers or chips if Controller and Host are implemented on different chips. The Logical Link Control and Adaptation Protocol (L2CAP) is responsible for packet formation, framing, error control, and packet assembly. The Security Manager Protocol (SMP) is responsible for encrypting packets. The General Access Profile (GAP) is responsible for the initial exchange of data between devices to determine "Who is who". It also includes scanning and advertising. In this article, I will focus on the two remaining parts of the protocol - GATT and ATT. GATT is built on top of ATT, so they are heavily intertwined.

BLE under the microscope (ATTs GATTs...)

To simplify the story, I would like to turn to an analogy. I heard it somewhere and would like to support. Think of a BLE device as a bookcase with multiple shelves. Each shelf is a separate theme. For example, we have shelves with science fiction, mathematics, encyclopedias. Each shelf contains books with a specific theme. And in some books there are even paper bookmarks with notes. In addition, we have a small paper catalog of all books. If you remember school libraries - this is a narrow box with paper cards. With this analogy, the closet is the profile of our device. Shelves are services, books are features, and catalog is an attribute table. Bookmarks in books are descriptors, which I will also talk about later, in more detail.

Everyone who has developed devices knows that many projects have similar pieces of code. The fact is that many devices have similar functionality. For example, if the devices are powered by batteries, then the problem of charging and monitoring their level will be the same. The same applies to sensors. Actually, the object-oriented approach in programming "provides the ability to create objects that connect properties and behaviors into an independent union, which can then be reused". In my opinion, a similar approach was attempted in BLE. Profiles have been developed by the Bluetooth Special Interest Group (SIG). Devices from different manufacturers that have the same profiles should work seamlessly with each other. Profiles, in turn, consist of services, and services of characteristics, supplemented by descriptors. In general, it might look like this:

BLE under the microscope (ATTs GATTs...)

For example, consider a heart rate monitor (fitness bracelet) profile diagram. It consists of two services and several characteristics. From it, the profile hierarchy immediately becomes clear. The breakpoint feature resets the total calorie expenditure count to zero.

1. Heart rate service includes three characteristics (0x180D):
    a) Mandatory heart rate characteristic (0x2A37)
    b) Optional Body Sensor Position Characteristic (0x2A38)
    c) Conditional characteristic of the heart rate control point (0x2A39)
2. Battery maintenance service (0x180F):
    a) Mandatory battery level characteristic (0x2A19)

UUID

In order for us to unambiguously refer to the profile elements (services, characteristics and descriptors), we need to number all of them somehow. For this purpose, such a concept as Universally Unique ID (UUID) or Universally Unique Identifier is introduced. The UUID is indicated in brackets of each line. And there is one peculiarity here. For UUID, we decided to use a code with a length of 16 and 128 bits. Why, you ask? In the BLE protocol, everything is subordinated to the conservation of energy. Therefore, a dimension of 16 bits is quite reasonable. It is unlikely that more than 65 jobs will be created in the near future. unique services and features. At the moment, everything they could have already been counted (remember where it came from - “he counted you too” :-)) Numbered elements profiles, services, characteristics of и descriptors you can look at the links.

However, I think everyone remembers the story of the 4-byte IP address on the Internet. At first we thought that was enough, but now we still can’t switch to a 6-byte address. In order not to repeat this mistake and give free rein to the playful hands of DIYers, SIG immediately decided to introduce 128-bit UUIDs as well. This personally reminds me of the unlicensed 433 MHz range, which was given at the mercy of all sorts of Kulibins from the radio channel. In our case, a 128-bit identifier of services and characteristics was given away. This means that we, for our services and devices, can use almost any 128-bit value. All the same, the probability of coming up with the same UUID tends to zero.

In fact, short 16-bit UUIDs have their extension to a 128-bit value. In the specification, this extension is called the Bluetooth Base UUID and has the value 00000000-0000-1000-8000-00805F9B34FB. If, for example, the 16-bit UUID of an attribute is 0x1234, then its equivalent 128-bit UUID will be 00001234-0000-1000-8000-00805F9B34FB. And even the corresponding formula is given:

                                128_bit_value = 16_bit_value * 2^96 + Bluetooth_Base_UUID

Where this magic number came from, I do not know. If any of the readers knows, let them write in the comments (A user with the nickname Sinopteek has already done this. See the comments). As for inventing 128-bit UUIDs, in principle, you can use a special generatorwhich will do it for you.

ATTS GATTs…

Actually the most interesting begins further. I will remind you that ATT is based on a client-server relationship. Now we are considering the server device. It contains information such as sensor values, light switch status, location data, and so on. Now that all the "participants of our parade" are numbered, it is necessary to somehow place them in the device's memory. To do this, we put them in a table called the attribute table. Remember this well. This is the very heart of BLE. That is what we will consider in the future. Now we will call each line an attribute. This table is located deep in the stack and, as a rule, we do not have direct access to it. We initialize it and refer to it, but what happens inside is hidden from us behind seven seals.

Consider the picture from the specification, but before that, I want to immediately draw attention to the frequent confusion in terms, namely in descriptors. The role of the descriptor is to complete the description of the characteristic. When it is necessary to expand its capabilities, then descriptors are used. They are also attributes, and, along with services and characteristics, are also located in the attribute table. We will analyze them in detail in the second part of the article. However, sometimes descriptors refer to the row number in the attribute table. This must be borne in mind. We, in order not to get confused, will use the term “attribute pointer” for these purposes.
BLE under the microscope (ATTs GATTs...)

So an attribute is a discrete value that has the following properties associated with it:
1. Attribute Handle is the index of the table corresponding to the attribute
2. Attribute Type is a UUID that describes its type
3. Attribute Value is the data indexed by the attribute pointer
4. Attribute Permissions are part of an attribute, permissions that cannot be read or written using the attribute protocol

How to understand all this? An attribute pointer is, conditionally speaking, its number in our table.
It allows the client to refer to the attribute in read or write requests. We can number our lines (attributes) from 0x0001 to 0xFFFF. In our association with the bookcase, this is the number of the card in the paper catalog. Similarly, as in the library catalog, the cards are arranged in ascending order of number. The number of each subsequent line must be greater than the previous one. As in the library, sometimes some cards are lost, so with us - there may be gaps in the line numbering. This is allowed. The main thing is that they go on the rise.

The attribute type determines what the attribute is. By analogy with the C language,
where there are boolean, numeric variables and strings, so here. By the type of attribute, we find out
what we are dealing with and how we can continue to work with this attribute. Below we will look at some specific attribute types. For example, "service declaration" (0x2800), "characteristic declaration" (0x2803), "descriptor declaration" (0x2902).

The value of an attribute is its own value, pardon the tautology. If the attribute type is a string, then the attribute value can be, for example, the slogan "Hello World !!!". If the attribute type is "service declaration", then its value is the service itself. And sometimes it is information about where to find other attributes and their properties.

Attribute permissions allow the server to understand whether read or write access is allowed.
Note that these permissions only apply to the attribute value, not to the pointer, type, or permission field itself. Those. if attribute writing is allowed, then we can change, for example, the line "Hello World !!!" on the line "Good morning". But we cannot prohibit writing a new line or, change the attribute type and designate the line as a “service declaration”. When a client accesses a server, the client requests its attributes. This lets the client know what the server can provide. Although it is not necessary to read and write values.

What it looks like

The concept of GATT is to group attributes in an attribute table together in a very specific and logical order. Let's take a closer look at the heart rate profile below. The leftmost column of this table is optional. It simply describes to us what this line (attribute) is. All other columns are already familiar to us.

BLE under the microscope (ATTs GATTs...)

At the top of each group, we always have a service declaration attribute. Its type is always 0x2800, and the pointer depends on how many attributes are already present in the table. Its permissions are always read-only, without any authentication or authorization. We will talk about these concepts a little later. The value is another UUID that defines what the service is. In the Table, the value is 0x180D, which is defined by the Bluetooth SIG as heart rate service.

After the service declaration, the characteristic declaration follows. It is similar in form to a service declaration. Its UUID is always 0x2803 and its permissions are always read-only without any authentication or authorization. Let's look at the Attribute Value field, which includes some data. It always contains a pointer, a UUID, and a set of properties. These three elements describe the subsequent declaration of the characteristic's value. The pointer naturally marks the place where the property value is declared in the attribute table. The UUID describes what type of information or value we can expect. For example, a temperature value, a light switch state, or some other arbitrary value. And finally properties that describe how you can interact with the characteristic value.

Here we are waiting for another pitfall. It is related to attribute permissions and characteristic properties. Let's take a look at the picture of the bitfield properties from the specification.

BLE under the microscope (ATTs GATTs...)

As you can see, there are also fields that provide read and write capabilities. You may wonder why we have read/write permissions on attribute and property
read/write for characteristic value? Shouldn't they always be the same? The fact is that the properties for the value of the characteristic, in fact, are only recommendations for the client, used in GATT and application layers. These are just hints about what the client can expect from the feature declaration attribute. Let's deal with this in more detail. What types of permissions does an attribute have?

1. Access Permissions:
     - reading
     - record
     - reading and writing
2. Authentication permission:
     - authentication required
     - no authentication required
3. Authorization permission:
     - authorization required
     - authorization is not required

The main difference between attribute resolution and feature properties is that the former refer to servers and the latter to clients. The server may be allowed to read the value of a characteristic, but require authentication or authorization. Therefore, when the client requests the properties of the characteristic, we will get that reading is allowed. But when we try to read, we get an error. Therefore, we can safely talk about the priority of permissions over properties. We, on the client side, cannot get knowledge about what permissions an attribute has.

Descriptor

Let's go back to our table. After declaring a characteristic value, the following attribute declarations are possible:
1. New feature declaration (a service can have many features)
2. New service declaration (the table can have many of them)
3. Descriptor declaration

In the case of a heart rate measurement characteristic, in our table, the declaration of the characteristic value is followed by the descriptor declaration. A descriptor is an attribute with additional information about a characteristic. There are several types of descriptors. We will talk about them in detail in the second part of this article. For now, we'll only touch on the Client Characteristic Configuration Descriptor (CCCD). It has a UUID of 0x2902. Using this descriptor, the client has the ability to enable indication or notification on the server. The difference between them is small, but still there. Notification does not require confirmation of receipt by the client. The indication requires this, although it occurs at the GATT level, not reaching the application level. Why so, you ask? Alas, I am not aware of this. Let me just say that Nordic experts recommend using notification. Moreover, the packet integrity check (using CRC) occurs in both cases.

Conclusion

At the end of the article, I would like to say this. The last table is somewhat confusing. However, I settled on it due to the fact that it is given in articleon which I rely. In the second part of my article, I intend to delve into the BlueTooth 4.0 specification. There we are waiting for more correct schemes and drawings. In the third part, I would like to parse the log obtained using the Wireshark program from one of the gadgets and see “live” all the theory that we are studying.

Employee of the Group of Companies "Caesar Satellite"
Pecherskikh Vladimir

Source: habr.com

Add a comment