BLE onder de microscoop (ATT's GATT's…)

BLE Onder de Microscoop (ATT's GATT's...)

BLE onder de microscoop (ATT en GATT...)

Deel 1, overzicht

Er is al behoorlijk wat tijd verstreken sinds de eerste specificatie van Bluetooth 4.0 uitkwam. En hoewel het onderwerp BLE heel interessant is, schrikken veel ontwikkelaars er nog steeds van, vanwege de complexiteit. In mijn eerdere artikelen heb ik voornamelijk het onderste niveau, de Link Layer en Physical Layer, behandeld. Dit maakte het mogelijk om niet te hoeven ingaan op complexe en verwarrende concepten zoals het Attributenprotocool (ATT) en het Gemeenschappelijk Attributenprofiel (GATT). Maar we kunnen niet om hen heen; zonder deze kennis is het onmogelijk om compatibele apparaten te ontwikkelen. Vandaag wil ik deze kennis met jullie delen. In mijn artikel zal ik mij baseren op een handleiding voor beginners van de Nordic-website. Laten we beginnen.

Waarom is alles zo ingewikkeld?

Naar mijn mening was het meteen duidelijk dat het besturen van apparaten via smartphones een zeer veelbelovend en langdurig thema is. Daarom is besloten om het meteen en zo goed mogelijk te structureren. Zodat fabrikanten van verschillende gadgets niet hun eigen protocollen gaan verzinnen, die later incompatible zullen zijn. Dit is waar de complexiteit vandaan komt. Al in de eerste fase probeerden ze alles wat maar mogelijk was in het BLE-protocol te proppen. En het maakt niet uit of dit later nuttig zal blijken of niet. Bovendien is er rekening gehouden met de mogelijkheid om de lijst met apparaten in de toekomst uit te breiden.

Laten we naar de afbeelding kijken, waarop het schema van het BLE-protocol is getekend. Het bestaat uit verschillende lagen. De onderste, fysieke laag (PHY) is verantwoordelijk voor het radiokanaal van het apparaat. De Link Layer (LL) bevat alle byte-sequenties in het verzonden bericht. In eerdere artikelen hebben we specifiek dit niveau bestudeerd. De Host Controller Interface (HCI) is het protocol voor gegevensuitwisseling tussen lagen of chips van BLE, als de controller en host op verschillende chips zijn geïmplementeerd. De Logical Link Control and Adaptation Protocol (L2CAP) is verantwoordelijk voor het vormen van pakketten, het segmenteren, de foutcontrole en het assembleren van pakketten. De Security Manager Protocol (SMP) is verantwoordelijk voor de encryptie van pakketten. Het Generic Access Profile (GAP) zorgt voor de initiële gegevensuitwisseling tussen apparaten, om te bepalen “Wie is wie”. Dit omvat ook scannen en adverteren. In dit artikel zal ik me concentreren op de twee overige delen van het protocol — GATT en ATT. GATT is een uitbreiding van ATT, waardoor ze sterk verweven zijn.

BLE Onder de Microscoop (ATT's GATT's...)

Om het verhaal te vereenvoudigen, wil ik een analogie aanhalen. Ik heb deze ergens gehoord en zou deze willen ondersteunen. Stel u een BLE-apparaat voor als een boekenplank met verschillende planken. Elke plank vertegenwoordigt een apart thema. Bijvoorbeeld, we hebben planken voor fictie, wiskunde, encyclopedieën. Op elke plank staan boeken met het bijbehorende onderwerp. En in sommige boeken zijn zelfs papieren bladwijzers met aantekeningen. Daarnaast hebben we een kleine papieren catalogus van alle boeken. Als u zich de schoolbibliotheken herinnert: dit is een smalle lade met papieren kaartjes. In deze analogie is de kast het profiel van ons apparaat. De planken zijn de diensten, de boeken zijn de kenmerken, en de catalogus is de tabel met attributen. De bladwijzers in de boeken zijn de descriptors, waar ik later ook meer over zal vertellen.

Iedereen die apparaten ontwikkelt, weet dat er in veel projecten vergelijkbare stukken code zijn. Het punt is dat veel apparaten vergelijkbare functionaliteit hebben. Bijvoorbeeld, als apparaten op batterijen werken, is het probleem van opladen en het controleren van hun niveau hetzelfde. Hetzelfde geldt voor sensoren. Eigenlijk biedt de objectgeoriënteerde benadering van programmeren de mogelijkheid om objecten te creëren die eigenschappen en gedragingen combineren tot een zelfstandige combinatie die vervolgens herhaaldelijk gebruikt kan worden.Naar mijn mening is er in BLE geprobeerd een soortgelijke benadering te hanteren. Een groep van de Bluetooth Special Interest Group (SIG) heeft profielen ontwikkeld. Apparaten van verschillende fabrikanten met dezelfde profielen moeten zonder problemen met elkaar kunnen werken. Profielen bestaan op hun beurt uit diensten, en diensten uit kenmerken, aangevuld met descriptors. In het algemeen kan dit er als volgt uitzien:

BLE Onder de Microscoop (ATT's GATT's...)

Bijvoorbeeld, laten we het profiel van een hartslagmonitor (fitnessarmband) bekijken. Dit bestaat uit twee diensten en meerdere kenmerken. Hieruit wordt de hiërarchie van het profiel meteen duidelijk. De kenmerken van het controlepunt reset de totale calorieteller naar nul.

1. De hartslagdienst omvat drie kenmerken (0x180D):
    a) Verplichte hartslagkenmerk (0x2A37)
    b) Optioneel kenmerk van de lichaamssensorpositie (0x2A38)
    c) Voorwaardelijk kenmerk van het hartslagcontrolepunt (0x2A39)
2. De batterijondersteuningsdienst (0x180F):
    a) Vereiste eigenschap van het batterijniveau (0x2A19)

UUID

Om ervoor te zorgen dat we duidelijk kunnen verwijzen naar de elementen van het profiel (diensten, kenmerken en descriptoren), moeten we ze op de een of andere manier nummeren. Hiervoor wordt het begrip Universally Unique ID (UUID) of Universeel Uniek Identificatienummer geïntroduceerd. In haakjes achter elke regel staat de UUID. En hier is een speciale eigenschap. Voor UUID is besloten om een code van 16 en 128 bits lang te gebruiken. Waarom, vraagt u zich af? In het BLE-protocol is alles gericht op energiebesparing. Daarom is een grootte van 16 bits volkomen logisch. Het is onwaarschijnlijk dat er in de nabije toekomst meer dan 65.000 unieke diensten en kenmerken worden gecreëerd. Tot nu toe is alles wat mogelijk was al berekend (herinner u zich waar dit vandaan komt — „hij heeft u ook geteld” :-)) Genummerde elementen profielen, diensten, kenmerken en descriptoren kunt u bekijken via de links.

Echter, ik denk dat iedereen zich het verhaal over de 4 bytes IP-adressen op het internet herinnert. Eerst dachten ze dat het genoeg zou zijn, en nu kunnen we maar niet overstappen op 6-byte adressen. Om deze fout niet te herhalen en de nieuwsgierige handen van hobbyisten niet te veel ruimte te geven, besloot SIG meteen ook 128-bit UUID's in te voeren. Dit doet me denken aan het ongeautoriseerde bereik van 433 MHz, dat werd toevertrouwd aan allerlei hobbyisten van radiokanalen. In ons geval is de 128-bit identifier van diensten en kenmerken toevertrouwd aan hen. Dit betekent dat wij voor onze diensten en apparaten praktisch elke 128-bit waarde kunnen gebruiken. De kans om een identieke UUID te verzinnen, neigt naar nul.

Eigenlijk hebben korte 16-bit UUID's hun uitbreiding naar een 128-bit waarde. In de specificatie wordt deze uitbreiding de Bluetooth Base UUID genoemd en heeft de waarde 00000000-0000-1000-8000-00805F9B34FB. Als bijvoorbeeld de waarde van een 16-bit UUID attribuut 0x1234 is, dan heeft de overeenkomende 128-bit UUID de waarde 00001234-0000-1000-8000-00805F9B34FB. Er is zelfs een bijbehorende formule:

                                128_bit_value = 16_bit_value * 2^96 + Bluetooth_Base_UUID

Waar dit magische getal vandaan komt, weet ik niet. Als iemand van de lezers het weet — laat het me weten in de opmerkingen (Gebruiker met de nickname Sinopteek heeft dat al gedaan. Bekijk de opmerkingen). Wat betreft het verzinnen van 128-bit UUID's, in principe kunt u gebruikmaken van een speciale generator, die dit voor u zal doen.

ATTs GATTs…

Eigenlijk begint hier het meest interessante. Ik herinner eraan dat ATT is gebaseerd op een client-server relatie. Momenteel kijken we naar de serverstructuur. Deze bevat informatie zoals sensorwaarden, de status van de lichtschakelaar, locatiegegevens, enz. Nu, wanneer alle 'deelnemers aan onze parade' zijn genummerd, moeten we ze op een bepaalde manier in het geheugen van het apparaat plaatsen. Hiervoor plaatsen we ze in een tabel die de attributentabel wordt genoemd. Onthoud dit goed. Dit is het hart van BLE. Dit gaan we verder onderzoeken. Nu noemen we elke regel een attribuut. Deze tabel bevindt zich diep in de stack en, over het algemeen, hebben we geen directe toegang tot deze. We initialiseren het en benaderen het, maar wat er van binnen gebeurt, is voor ons verborgen achter zeven zegels.

Laten we de afbeelding uit de specificatie bekijken, maar voordat we dat doen, wil ik meteen wijzen op verwarring rond de terminologie, met name over de descriptors. De rol van een descriptor is om de beschrijving van een kenmerk aan te vullen. Wanneer we de mogelijkheden ervan willen uitbreiden, gebruiken we de descriptors. Ze zijn ook attributen en bevinden zich samen met services en kenmerken in de attributentabel. We zullen ze in detail bespreken in het tweede deel van het artikel. Maar soms worden descriptors aangeduid als het regelnummer in de attributentabel. Dit moet in gedachten worden gehouden. Om verwarring te voorkomen, zullen we voor deze doelen de term 'attribuutpointer' gebruiken.
BLE Onder de Microscoop (ATT's GATT's...)

Dus een attribuut is een discreet waarde met de volgende eigenschappen die eraan zijn verbonden:
1. Attribuutpointer (Attribute Handle) - dit is de index van de tabel die overeenkomt met het attribuut.
2. Attribuuttype (Attribute Type) - dit is de UUID die het type beschrijft.
3. Attribuutwaarde (Attribute Value) - dit zijn de gegevens die door de attribuutpointer worden geïndexeerd.
4. Attribuutmachtigingen (Attribute Permissions) - dit is een deel van het attribuut, machtigingen die niet kunnen worden gelezen of geschreven met behulp van het attribuutprotocol.

Hoe moeten we dit begrijpen? De attribuutpointer is, voor alle doeleinden, zijn nummer in onze tabel.
Het stelt de klant in staat om te verwijzen naar een attribuut in lees- of schrijfopdrachten. We kunnen onze regels (attributen) nummeren van 0x0001 tot 0xFFFF. In onze associatie met een boekenplank is dit het kaartnummer in een papieren catalogus. Evenzo, zoals in de bibliotheekcatalogus, worden de kaarten in oplopende volgorde genummerd. Het nummer van elke volgende regel moet groter zijn dan de vorige. Net als in een bibliotheek kunnen er soms kaarten verloren gaan, en zo kunnen er in onze nummering van regels hiaten zijn. Dit is toegestaan. Het belangrijkste is dat ze oplopen.

Het type attribuut bepaalt wat dit attribuut is. In lijn met de programmeertaal C,
waar er boolean, numerieke variabelen en strings zijn, zo is het hier ook. Aan de hand van het attribuuttype weten we
waarmee we te maken hebben en hoe we verder met dit attribuut moeten werken. Hieronder bekijken we enkele specifieke types van attributen. Bijvoorbeeld 'serviceverklaring' (0x2800), 'kenmerkverklaring' (0x2803), 'descriptorverklaring' (0x2902).

De waarde van het attribuut is eigenlijk zijn waarde, excuses voor de tautologie. Als het attribuuttype een string is, kan de waarde van het attribuut bijvoorbeeld de slogan 'Hello World !!!' zijn. Als het attribuuttype 'serviceverklaring' is, dan vertegenwoordigt de waarde zelf de dienst. Soms is het ook informatie over waar andere attributen en hun eigenschappen te vinden zijn.

De rechten van attributen stellen de server in staat om te begrijpen of de toegang tot lezen of schrijven is toegestaan.
Let op dat deze rechten alleen van toepassing zijn op de waarde van het attribuut en niet op de pointer, het type en het veld van de rechten zelf. Dit betekent dat als schrijven van het attribuut is toegestaan, we bijvoorbeeld de regel 'Hello World !!!' kunnen wijzigen in de regel 'Good morning'. Maar we kunnen het schrijven van een nieuwe regel niet verbieden of het type van het attribuut veranderen en de regel aanduiden als 'serviceverklaring'. Wanneer een klant contact opneemt met de server, vraagt de klant om zijn attributen. Dit stelt de klant in staat om te begrijpen wat de server kan aanbieden. Hoewel het niet noodzakelijk is om waarden te lezen en te schrijven.

Hoe het eruit ziet

Het GATT-concept draait om het groeperen van attributen in de attributentabel in een zeer specifieke en logische volgorde. Laten we eens nader kijken naar het hartslagprofiel hieronder. De meest linkse kolom van deze tabel is optioneel. Het beschrijft gewoon waar deze rij (attribuut) voor staat. Alle andere kolommen zijn ons al bekend.

BLE Onder de Microscoop (ATT's GATT's...)

Bovenaan elke groep hebben we altijd het service-aankondigingsattribuut. Het type is altijd 0x2800, en de pointer hangt af van het aantal attributen dat al in de tabel aanwezig is. De permissies zijn altijd alleen-lezen, zonder enige validatie of autorisatie. We zullen deze concepten later bespreken. De waarde is een andere UUID die definieert welke service dit is. In de tabel is de waarde 0x180D, dat door Bluetooth SIG wordt gedefinieerd als de hartslagservice.

Na de service-aankondiging volgt de kenmerk-aankondiging. Deze lijkt qua vorm op de service-aankondiging. De UUID heeft altijd de waarde 0x2803, en de permissies zijn ook altijd alleen-lezen zonder enige validatie of autorisatie. Laten we eens kijken naar het veld Attribute Value, dat enkele gegevens bevat. Het bevat altijd een pointer, UUID en een set eigenschappen. Deze drie elementen beschrijven de daaropvolgende aankondiging van de waarde van het kenmerk. De pointer geeft natuurlijk de locatie van de waarde van het kenmerk aan in de attributentabel. De UUID beschrijft welk type informatie of waarde we kunnen verwachten. Bijvoorbeeld, een temperatuurwaarde, de status van een lichtschakelaar of een andere willekeurige waarde. En tenslotte zijn er de eigenschappen, die beschrijven hoe we met de kenmerkwaarde kunnen interageren.

Hier wacht ons weer een andere valkuil. Deze betreft de permissies van attributen en de eigenschappen van kenmerken. Laten we naar de afbeelding van de bitveld-eigenschappen in de specificatie kijken.

BLE Onder de Microscoop (ATT's GATT's...)

Zoals je ziet, zijn er hier ook velden die lees- en schrijfmogelijkheden bieden. Je vraagt je misschien af waarom we lees/schrijf-permissies hebben voor het attribuut en de eigenschap.
Lezen/schrijven voor de waarde van de eigenschap? Moeten ze niet altijd hetzelfde zijn? Het feit is dat eigenschappen voor de waarde van de eigenschap feitelijk slechts aanbevelingen zijn voor de klant, gebruikt in GATT en toepassingslagen. Het zijn simpelweg aanwijzingen over wat de klant kan verwachten van de karakteristiek in de advertentie. Laten we dit wat dieper bekijken. Welke soorten permissies zijn er voor de attribuut?

1. Toegangsrechten:
     — lezen
     — schrijven
     — lezen en schrijven
2. Authenticatierechten:
     — authenticatie vereist
     — authenticatie niet vereist
3. Autorisatierechten:
     — autorisatie vereist
     — autorisatie niet vereist

Het belangrijkste verschil tussen de rechten van attributen en de eigenschappen van kenmerken is dat de eerste betrekking hebben op servers, terwijl de tweede betrekking hebben op klanten. Een server kan het lezen van de waarde van een eigenschap zijn toegestaan, maar kan tegelijkertijd eisen voor authenticatie of autorisatie stellen. Daarom, wanneer een klant om de eigenschappen van het kenmerk vraagt, zullen we krijgen dat lezen is toegestaan. Maar bij een poging om te lezen, zullen we een fout krijgen. Daarom kunnen we gerust zeggen dat rechten voorrang hebben boven eigenschappen. Kennis over welke rechten er voor het attribuut zijn, kunnen we, vanuit de klant gezien, niet verkrijgen.

Descriptor

Laten we terugkeren naar onze tabel. Na de verklaring van de waarde van de eigenschap, zijn de volgende verklaringen voor attributen mogelijk:
1. Nieuwe verklaring van het kenmerk (in de service kunnen er veel kenmerken zijn)
2. Nieuwe verklaring van de service (in de tabel kunnen er veel zijn)
3. Verklaring van de descriptor

In het geval van de eigenschap die de hartslagfrequentie meet, wordt in onze tabel de waarde van de eigenschap begeleid door de aankondiging van de descriptor. Een descriptor is een attribuut met extra informatie over de eigenschap. Er zijn verschillende soorten descriptors. Daarover zullen we uitvoerig spreken in het tweede deel van dit artikel. Voor nu bespreken we alleen de client characteristic configuration descriptor (CCCD). Deze heeft een UUID gelijk aan 0x2902. Met deze descriptor kan de client op de server notificatie of indicatie inschakelen. Het verschil tussen hen is klein, maar bestaat wel. Notificatie vereist geen bevestiging van ontvangst door de client. Indicatie vereist dat echter, hoewel dit op GATT-niveau gebeurt, zonder het applicatieniveau te bereiken. Waarom zo, vraagt u zich af? Helaas weet ik dat niet. Ik kan alleen zeggen dat de specialisten van Nordic aanbevelen om notificatie te gebruiken. Bovendien vindt de integriteitscontrole van het pakket (via CRC) in beide gevallen plaats.

Conclusie

Aan het einde van het artikel wil ik het volgende zeggen. De laatste tabel is enigszins verwarrend. Ik heb echter voor deze gekozen omdat deze wordt gepresenteerd in artikel, waarop ik me baseer. In het tweede deel van mijn artikel ben ik van plan dieper in te gaan op de BlueTooth 4.0-specificatie. Daar zullen meer nauwkeurige schema's en tekeningen op ons wachten. In het derde deel wil ik de log bespreken die is verkregen met behulp van het programma Wireshark van een van de gadgets en 'in het echt' zien wat we samen hebben bestudeerd.

Medewerker van de Groep Bedrijven «Caesar Satellit»
Pecherskiy Vladimir

Bron: habr.com

Koop betrouwbare webhosting met bescherming tegen DDoS, VPS VDS servers 🔥 Koop betrouwbare webhosting met bescherming tegen DDoS, VPS VDS servers | ProHoster