
BLE sota un microscopi (ATTы GATTы...)
Part 1, visió general
Ja ha passat força temps des que es va publicar la primera especificació per a Bluetooth 4.0. I, tot i que el tema BLE és molt interessant, encara desanima molts desenvolupadors per la seva complexitat. En els meus articles anteriors, vaig mirar principalment el nivell més baix, la capa d'enllaç i la capa física. Això ens va permetre evitar haver de recórrer a conceptes tan complexos i confusos com el Protocol d'Atributs (ATT) i el Perfil General d'Atributs (GATT). No obstant això, no hi ha on anar, sense entendre'ls, és impossible desenvolupar dispositius compatibles. Avui m'agradaria compartir aquest coneixement amb vosaltres. En el meu article confiaré per a principiants del lloc web nòrdic. Així que comencem.
Per què tot és tan difícil?
Al meu entendre, de seguida va quedar clar que la gestió de dispositius mitjançant telèfons intel·ligents és un tema molt prometedor i de llarga durada. Per això, van decidir estructurar-lo immediatament i al màxim. Perquè els fabricants de diversos aparells no tinguin els seus propis protocols, que llavors seran incompatibles. D'aquí la dificultat. Ja en la primera etapa, van intentar introduir tot el possible al protocol BLE. I no importa si serà útil més endavant o no. A més, preveien la possibilitat d'ampliar la llista de dispositius per al futur.
Fem una ullada a la imatge on es dibuixa el diagrama del protocol BLE. Consta de diverses capes. La capa física més baixa (PHY) és responsable del canal de ràdio del dispositiu. Link Layer (LL) conté tota la seqüència de bytes del missatge transmès. En articles anteriors vam estudiar exactament això. Host Controller Interface (HCI) és un protocol d'intercanvi entre capes o xips BLE si el controlador i l'amfitrió s'implementen en xips diferents. El protocol d'adaptació i control d'enllaços lògics (L2CAP) és responsable de la formació de paquets, l'enquadrament, el control d'errors i el muntatge de paquets. El protocol SMP (Security Manager Protocol) és l'encarregat de xifrar els paquets. El perfil d'accés general (GAP) és responsable de l'intercanvi inicial de dades entre dispositius per determinar "Qui és qui". També inclou l'escaneig i la publicitat. En aquest article em centraré en les dues parts restants del protocol: GATT i ATT. GATT és una superestructura de ATT, de manera que estan estretament entrellaçats.

Per simplificar la història, m'agradaria recórrer a una analogia. Ho vaig sentir en algun lloc i m'agradaria donar-hi suport. Penseu en un dispositiu BLE com una prestatgeria amb diversos prestatges. Cada prestatge és un tema independent. Per exemple, tenim prestatgeries amb ciència ficció, matemàtiques i enciclopèdies. A cada prestatge hi ha llibres amb un tema determinat. I alguns llibres fins i tot tenen marcadors de paper amb notes. A més, disposem d'un petit catàleg en paper de tots els llibres. Si recordeu, les biblioteques escolars són una caixa estreta amb cartolines de paper. Amb aquesta analogia, l'armari és el perfil del nostre dispositiu. Les prestatgeries són serveis, els llibres són característiques i el catàleg és una taula d'atributs. Els marcadors dels llibres són descriptors, dels quals també parlaré més endavant amb més detall.
Qualsevol que hagi desenvolupat dispositius sap que molts projectes tenen peces de codi similars. El fet és que molts dispositius tenen una funcionalitat similar. Per exemple, si els dispositius funcionen amb bateries, el problema de carregar i controlar el seu nivell serà el mateix. El mateix passa amb els sensors. En realitat, un enfocament de programació orientat a objectes "ofereix la capacitat de crear objectes que combinen propietats i comportaments en una unió autònoma que després es pot reutilitzar". Al meu entendre, BLE va intentar un enfocament similar. Els perfils van ser desenvolupats pel Bluetooth Special Interest Group (SIG). Els dispositius de diferents fabricants que tinguin els mateixos perfils haurien de funcionar entre si sense dificultats. Els perfils, al seu torn, consisteixen en serveis i serveis de característiques, complementats amb descriptors. En general podria semblar així:

Per exemple, considereu el diagrama de perfil d'un monitor de freqüència cardíaca (braçalet de fitness). Consta de dos serveis i diverses característiques. A partir d'això, la jerarquia del perfil es fa clara de seguida. La característica del punt de control restableix el recompte total de despesa calòrica a zero.
1. El servei de freqüència cardíaca inclou tres característiques (0x180D):
a) Característica de freqüència cardíaca obligatòria (0x2A37)
b) Característica de posició del sensor corporal opcional (0x2A38)
c) Característiques condicionals del punt de control de la freqüència cardíaca (0x2A39)
2. Servei de manteniment de la bateria (0x180F):
a) Característica obligatòria del nivell de càrrega de la bateria (0x2A19)
UUID
Perquè puguem accedir de manera única als elements del perfil (serveis, característiques i descriptors), hem de numerar-los tots d'alguna manera. Amb aquesta finalitat, s'introdueix un concepte com l'identificador únic universal (UUID) o l'identificador únic universal. L'UUID s'indica entre parèntesis de cada línia. I aquí hi ha una peculiaritat. Per a UUID, vam decidir utilitzar un codi de 16 i 128 bits de longitud. Perque preguntes? Al protocol BLE, tot es refereix a l'estalvi d'energia. Per tant, la dimensió de 16 bits és força raonable. És poc probable que se'n creïn més de 65 mil en un futur proper. serveis i característiques úniques. De moment, tot el que ja s'haurien pogut comptar (recordeu d'on venia això - "ell també us va comptar" :-)) Elements numerats , , и podeu mirar els enllaços.
Tanmateix, crec que tothom recorda la història amb 4 bytes d'adreces IP a Internet. Al principi vam pensar que n'hi havia prou, però ara encara no podem canviar a una adreça de 6 bytes. Per no repetir aquest error i donar via lliure a les mans juganeres dels bricolants, SIG immediatament va decidir introduir UUID de 128 bits. Això personalment em recorda la banda de 433 MHz sense llicència, que es va donar a tot tipus de Kulibins des del canal de ràdio. En el nostre cas, es va extreure un identificador de 128 bits de serveis i característiques. Això vol dir que nosaltres, per als nostres serveis i dispositius, podem utilitzar gairebé qualsevol valor de 128 bits. De totes maneres, la probabilitat d'aconseguir el mateix UUID tendeix a zero.
De fet, els UUID curts de 16 bits tenen la seva extensió a un valor de 128 bits. A l'especificació, aquesta extensió s'anomena UUID de base Bluetooth i té el valor 00000000-0000-1000-8000-00805F9B34FB. Si, per exemple, l'UUID d'atribut de 16 bits té el valor 0x1234, l'UUID equivalent de 128 bits tindrà el valor 00001234-0000-1000-8000-00805F9B34FB. I fins i tot es dóna la fórmula corresponent:
128_bit_value = 16_bit_value * 2^96 + Bluetooth_Base_UUID
No sé d'on prové aquest número màgic. Si algun dels lectors ho sap, que escrigui als comentaris (Un usuari amb el sobrenom de Sinopteek ja ho ha fet. Vegeu els comentaris). Pel que fa a crear UUID de 128 bits, en principi podeu utilitzar un especial qui ho farà per tu.
ATTy GATTy...
De fet, llavors comença la diversió. Us recordo que ATT es basa en una relació client-servidor. Ara estem mirant el dispositiu servidor. Conté informació com els valors del sensor, l'estat de l'interruptor de llum, les dades d'ubicació, etc. Ara que tots els "participants de la nostra desfilada" estan numerats, hem de col·locar-los d'alguna manera a la memòria del dispositiu. Per fer-ho, els posem en una taula anomenada taula d'atributs. Recordeu-ho bé. Aquest és el cor de BLE. Això és el que considerarem més endavant. Ara anomenarem a cada línia un atribut. Aquesta taula es troba profundament a la pila i, per regla general, no hi tenim accés directe. L'iniciem i hi accedim, però el que passa a dins se'ns amaga darrere de set segells.
Mirem la imatge de l'especificació, però abans d'això, m'agradaria cridar immediatament l'atenció sobre la freqüent confusió en termes, és a dir, en descriptors. La funció del descriptor és complementar la descripció de la característica. Quan cal ampliar les seves capacitats, s'utilitzen descriptors. També són atributs i, igual que els serveis i les característiques, es troben a la taula d'atributs. Els examinarem amb detall a la segona part de l'article. Tanmateix, de vegades els descriptors fan referència al número de fila de la taula d'atributs. Això s'ha de tenir en compte. Per evitar confusions, utilitzarem el terme "punter d'atribut" per a aquests propòsits.

Per tant, un atribut és un valor discret que té les propietats següents associades:
1. El maneig de l'atribut és l'índex de la taula corresponent a l'atribut
2. El tipus d'atribut és un UUID que descriu el seu tipus
3. El valor de l'atribut són les dades indexades pel punter d'atribut
4. Els permisos d'atribut són la part d'un atribut, els permisos, que no es poden llegir ni escriure mitjançant el protocol d'atributs
Com entendre tot això? El punter d'atribut és, relativament parlant, el seu nombre a la nostra taula.
Permet que un client faci referència a un atribut en sol·licituds de lectura o escriptura. Podem numerar les nostres línies (atributs) de 0x0001 a 0xFFFF. En la nostra associació amb la prestatgeria, aquest és el número de targeta del catàleg en paper. De la mateixa manera, com en el catàleg de la biblioteca, les fitxes es disposen en ordre creixent de nombre. El número de cada línia posterior ha de ser més gran que l'anterior. Igual que a la biblioteca, de vegades es perden algunes targetes, de manera que amb nosaltres, pot haver-hi buits en la numeració de línies. Això està permès. El més important és que van progressivament.
El tipus d'atribut determina què representa l'atribut. Per analogia amb el llenguatge C,
on hi ha variables booleanes, numèriques i cadenes, així que és aquí. Per tipus d'atribut reconeixem
amb què estem tractant i com podem continuar treballant amb aquest atribut. A continuació veurem alguns tipus específics d'atributs. Per exemple, "declaració de servei" (0x2800), "declaració de característiques" (0x2803), "declaració de descriptor" (0x2902).
El valor d'un atribut és el seu significat real, perdoneu la tautologia. Si el tipus d'atribut és una cadena, el valor de l'atribut pot ser, per exemple, l'eslògan "Hola món !!!". Si el tipus d'atribut és una "declaració de servei", el seu valor és el propi servei. I de vegades es tracta d'informació sobre on trobar altres atributs i les seves propietats.
Els permisos d'atribut permeten al servidor entendre si es permet l'accés de lectura o escriptura.
Tingueu en compte que aquests permisos només s'apliquen al valor de l'atribut, i no al propi camp del punter, tipus o permís. Aquells. si es permet l'enregistrament d'atributs, podem canviar, per exemple, la línia "Hello World !!!" a la línia "Bon dia". Però no podem prohibir escriure una línia nova ni canviar el tipus d'atribut i designar la línia com a "declaració de servei". Quan un client contacta amb un servidor, el client demana els seus atributs. Això permet al client saber què pot proporcionar el servidor. Encara que no cal llegir i escriure els valors.
Com sembla
El concepte de GATT és agrupar els atributs en una taula d'atributs en un ordre molt específic i lògic. Fem una ullada més de prop al perfil de freqüència cardíaca a continuació. La columna més a l'esquerra d'aquesta taula és opcional. Simplement ens descriu què és aquesta línia (atribut). La resta de columnes ja ens són familiars.

A la part superior de cada grup sempre tenim un atribut de declaració de servei. El seu tipus és sempre 0x2800, i el punter depèn de quants atributs ja hi ha presents a la taula. Els seus permisos són sempre de només lectura, sense cap autenticació ni autorització. D'aquests conceptes parlarem una mica més endavant. El valor és un altre UUID que identifica quin és el servei. A la taula, el valor és 0x180D, que el SIG Bluetooth defineix com a servei de freqüència cardíaca.
Després de l'anunci del servei, arriba l'anunci de la característica. Té una forma similar a una declaració de servei. El seu UUID és sempre 0x2803 i els seus permisos són sempre de només lectura sense cap autenticació o autorització. Vegem el camp Valor de l'atribut, que inclou algunes dades. Sempre conté un punter, un UUID i un conjunt de propietats. Aquests tres elements descriuen la declaració posterior del valor característic. El punter denota naturalment la ubicació de la declaració de valor de característica a la taula d'atributs. L'UUID descriu quin tipus d'informació o valor podem esperar. Per exemple, el valor de la temperatura, l'estat de l'interruptor de la llum o algun altre valor arbitrari. I finalment propietats, que descriuen com es pot interactuar amb el valor característic.
Aquí ens espera una altra trampa. S'associa amb permisos d'atributs i propietats característiques. Vegem la imatge de les propietats del camp de bits de l'especificació.

Com podeu veure, també hi ha camps aquí que proporcionen capacitats de lectura i escriptura. Potser us preguntareu per què tenim permisos de lectura/escriptura per a atributs i propietats
llegir/escriptura del valor característic? No haurien de ser sempre els mateixos? El fet és que les propietats del valor característic són en realitat només recomanacions per al client que s'utilitzen a les capes d'aplicació i GATT. Aquests són simplement pistes sobre què pot esperar el client de l'atribut de declaració característica. Vegem-ho amb més detall. Quins tipus de permisos té un atribut?
1. Permisos d'accés:
- lectura
- registre
- Llegeix i escriu
2. Permís d'autenticació:
- Cal autenticació
- No cal autenticació
3. Permís d'autorització:
- Cal autorització
- No cal autorització
La principal diferència entre la resolució d'atributs i les propietats característiques és que les primeres s'apliquen als servidors, i les segones als clients. Es pot permetre que el servidor llegeixi el valor de la característica, però pot requerir autenticació o autorització. Per tant, quan el client sol·liciti les propietats de la característica, rebem que es permet la lectura. Però quan intentem llegir, obtenim un error. Per tant, podem parlar amb seguretat de la prioritat dels permisos sobre les propietats. Pel costat del client, no podem obtenir coneixement de quins permisos té un atribut.
Descriptor
Tornem a la nostra taula. Després de declarar el valor d'una característica, són possibles les declaracions d'atributs següents:
1. Nova declaració de característiques (un servei pot tenir moltes característiques)
2. Nova declaració de servei (pot ser que n'hi hagi molts a la taula)
3. Declaració d'un maneig
En el cas de la característica de mesura de la freqüència cardíaca, a la nostra taula, la declaració del valor de la característica va acompanyada de la declaració del descriptor. Un descriptor és un atribut amb informació addicional sobre una característica. Hi ha diversos tipus de descriptors. En parlarem amb detall a la segona part d'aquest article. De moment, només tocarem el descriptor de configuració de característiques del client (CCCD). Té un UUID igual a 0x2902. Mitjançant aquest descriptor, el client té la capacitat d'habilitar la indicació o notificació al servidor. La diferència entre ells és petita, però encara hi ha. La notificació no requereix confirmació de recepció per part del client. La indicació ho requereix, encara que es produeix a nivell GATT, no arribant al nivell d'aplicació. Per què, et preguntes? Ai, això no ho sé. Permeteu-me dir que els experts nòrdics recomanen utilitzar les notificacions. A més, la comprovació de la integritat del paquet (utilitzant CRC) es produeix en ambdós casos.
Conclusió
Al final de l'article m'agradaria dir això. L'última taula és una mica confusa. Tanmateix, l'he escollit perquè està cedit , en què confio. A la segona part del meu article, tinc la intenció d'aprofundir en l'especificació de BlueTooth 4.0. Allà ens esperen esquemes i dibuixos més correctes. A la tercera part, m'agradaria analitzar el registre obtingut amb el programa Wireshark d'un dels gadgets i veure "en directe" tota la teoria que estem estudiant.
Empleat del Grup d'Empreses
Pecherskikh Vladimir
Font: www.habr.com
