BLE sotto il microscopio (ATT e GATT…)

BLE al microscopio (ATT e GATT...)

BLE al microscopio (ATT e GATT...)

Parte 1, panoramica

È passato un bel po' di tempo da quando è stata pubblicata la prima specifica di Bluetooth 4.0. E, sebbene il tema BLE sia molto interessante, continua a scoraggiare molti sviluppatori a causa della sua complessità. Nei miei articoli precedenti ho principalmente affrontato i livelli più bassi: Link Layer e Physical Layer. Questo ha permesso di non dover affrontare concetti complessi e confusi come il protocollo degli attributi (ATT) e il profilo generale degli attributi (GATT). Tuttavia, non si può fare a meno di comprenderli, poiché senza di essi è impossibile sviluppare dispositivi compatibili. Oggi vorrei condividere con voi queste conoscenze. Nel mio articolo mi baserò su un tutorial per principianti dal sito Nordic. Quindi, iniziamo.

Perché è tutto così complicato?

Dal mio punto di vista, era subito chiaro che il controllo dei dispositivi tramite smartphone è un tema molto promettente e di lungo termine. Pertanto, è stato deciso di strutturarlo subito e al massimo. In modo che i produttori di vari gadget non inventassero i propri protocolli, che poi non sarebbero stati compatibili. Da qui derivano le complessità. Già nella prima fase, nel protocollo BLE si è cercato di includere tutto ciò che era possibile. E non importa se sarà utile in seguito o meno. Inoltre, è stata prevista la possibilità di ampliare l'elenco dei dispositivi in futuro.

Diamo un'occhiata all'immagine dove è rappresentato lo schema del protocollo BLE. Esso è composto da diversi livelli. Il livello più basso, il livello fisico (PHY), è responsabile del canale radio del dispositivo. Il Link Layer (LL) contiene tutta la sequenza di byte nel messaggio trasmesso. Nei miei articoli precedenti abbiamo studiato proprio questo. L'Host Controller Interface (HCI) è il protocollo di scambio tra i livelli o i chip BLE, se il Controller e l'Host sono implementati su chip diversi. La creazione dei pacchetti, la suddivisione in frame, il controllo degli errori e la raccolta dei pacchetti è responsabilità del Logical Link Control and Adaptation Protocol (L2CAP). La crittografia dei pacchetti è gestita dal Security Manager Protocol (SMP). Il profilo di accesso generale (GAP) è responsabile dello scambio iniziale di dati tra i dispositivi, per determinare «Chi è chi». Esso comprende anche scanning e advertising. In questo articolo mi concentrerò sulle due parti rimanenti del protocollo: GATT e ATT. GATT è un'estensione di ATT, quindi sono fortemente intrecciati.

BLE al microscopio (ATT e GATT...)

Per semplificare la narrazione, vorrei ricorrere a un'analogia. L'ho sentita da qualche parte e vorrei sostenerla. Immaginate un dispositivo BLE come una libreria con diversi ripiani. Ogni ripiano rappresenta un tema separato. Ad esempio, abbiamo ripiani di fantascienza, matematica, enciclopedie. Su ogni ripiano ci sono libri riguardanti il tema specifico. E in alcuni libri ci sono anche segnalibri con annotazioni. Inoltre, abbiamo un piccolo catalogo cartaceo di tutti i libri. Se vi ricordate delle biblioteche scolastiche, questo è un cassetto stretto con schede cartacee. In questa analogia, la libreria rappresenta il profilo del nostro dispositivo. I ripiani sono i servizi, i libri sono le caratteristiche e il catalogo è la tabella degli attributi. I segnalibri nei libri sono i descrittori, di cui parlerò più dettagliatamente in seguito.

Tutti coloro che hanno sviluppato dispositivi sanno che molti progetti contengono pezzi di codice simili. Il fatto è che molti dispositivi hanno funzionalità simili. Ad esempio, se i dispositivi funzionano con batterie, il problema della ricarica e del controllo del loro livello sarà lo stesso. Lo stesso vale per i sensori. Infatti, l'approccio orientato agli oggetti nella programmazione “offre la possibilità di creare oggetti che collegano proprietà e comportamenti in un'alleanza autonoma, che può poi essere riutilizzata più volte”. A mio parere, nel BLE è stato fatto un tentativo simile. Il gruppo Bluetooth Special Interest Group (SIG) ha sviluppato profili. Dispositivi di diversi produttori, che presentano profili identici, devono funzionare senza difficoltà tra loro. I profili, a loro volta, consistono di servizi, e i servizi di caratteristiche, completate da descrittori. In generale, questo può apparire così:

BLE al microscopio (ATT e GATT...)

Per esempio, consideriamo lo schema del profilo heart rate monitor (braccialetto fitness). Esso è composto da due servizi e diverse caratteristiche. Da esso risulta immediatamente chiara la gerarchia del profilo. La caratteristica del punto di controllo azzera il conteggio totale delle calorie bruciate.

1. Il servizio di frequenza cardiaca include tre caratteristiche (0x180D):
    a) Caratteristica obbligatoria della frequenza cardiaca (0x2A37)
    b) Caratteristica opzionale della posizione del sensore corporeo (0x2A38)
    c) Caratteristica condizionale del punto di controllo della frequenza cardiaca (0x2A39)
2. Servizio di gestione della batteria (0x180F):
    a) Caratteristica obbligatoria del livello di carica della batteria (0x2A19)

UUID

Affinché possiamo riferirci in modo univoco agli elementi del profilo (servizi, caratteristiche e descrittori), è necessario numerarli in qualche modo. A questo scopo viene introdotto il concetto di Universally Unique ID (UUID) o Identificatore Unico Universale. Nelle parentesi di ciascuna riga è indicato l'UUID. E c'è una particolarità. Per l'UUID si è deciso di utilizzare un codice lungo 16 e 128 bit. Perché, vi chiederete? Nel protocollo BLE tutto è subordinato al risparmio energetico. Pertanto, una dimensione di 16 bit è piuttosto ragionevole. È improbabile che nel prossimo futuro vengano creati più di 65.000 servizi e caratteristiche unici. Attualmente, ciò che potevamo, già lo abbiamo conteggiato (ricordate da dove viene — «lui ha contato anche voi» :-)) Elementi numerati profili, servizi, caratteristiche e descrittori potete visualizzarli nei link.

Tuttavia, penso che tutti ricordino la storia dei 4 byte degli indirizzi IP su Internet. Inizialmente si pensava che fosse sufficiente, e ora non riusciamo a passare a un indirizzo a 6 byte. Per non ripetere questo errore e dare spazio a mani disordinate di artigiani, SIG ha deciso fin da subito di introdurre anche gli UUID a 128 bit. Questo, per me, ricorda la banda non autorizzata da 433 MHz, che è stata lasciata agli artigiani del canale radio. Nel nostro caso, è stato lasciato un identificatore di servizi e caratteristiche a 128 bit. Ciò significa che possiamo utilizzare praticamente qualsiasi valore a 128 bit per i nostri servizi e dispositivi. La probabilità di inventare un UUID identico è comunque prossima allo zero.

In realtà, gli UUID brevi a 16 bit hanno una loro estensione fino a un valore a 128 bit. Nella specifica, questa estensione è chiamata Bluetooth Base UUID e ha valore 00000000-0000-1000-8000-00805F9B34FB. Ad esempio, se l'UUID a 16 bit dell'attributo ha valore 0x1234, allora l'equivalente a 128 bit avrà valore 00001234-0000-1000-8000-00805F9B34FB. Viene anche fornita la formula corrispondente:

                                128_bit_value = 16_bit_value * 2^96 + Bluetooth_Base_UUID

Da dove provenga questo numero magico, non lo so. Se qualcuno dei lettori lo sa — lo scriva nei commenti (l'utente con il nickname Sinopteek lo ha già fatto. Vedi i commenti). Per quanto riguarda l'invenzione di UUID a 128 bit, in linea di principio, è possibile utilizzare un apposito generatore, che lo farà per voi.

ATTи GATTи…

Dunque, ora inizia la parte più interessante. Ricordo che ATT si basa su una relazione client-server. Ora stiamo esaminando il dispositivo del server. Contiene informazioni come valori dei sensori, stato dell'interruttore della luce, dati sulla posizione, ecc. Adesso che tutti i "partecipanti al nostro corteo" sono numerati, dobbiamo in qualche modo allocarli nella memoria del dispositivo. Per farlo, li inseriamo in una tabella chiamata tabella degli attributi. Ricordate bene questo. È il cuore del BLE. È ciò che esamineremo in seguito. Ora chiameremo ogni riga un attributo. Questa tabella si trova in profondità nello stack e, di solito, non abbiamo accesso diretto ad essa. La inizializziamo e vi accediamo, ma ciò che accade all'interno è nascosto a noi dietro sette sigilli.

Consideriamo l'immagine dalla specifica, tuttavia prima di ciò, voglio richiamare l'attenzione su una comune confusione nei termini, in particolare nei descrittori. Il ruolo del descrittore è quello di completare la descrizione di una caratteristica. Quando è necessario ampliarne le funzionalità, si utilizzano i descrittori. Anch'essi sono attributi e, come i servizi e le caratteristiche, si trovano nella tabella degli attributi. Li esamineremo dettagliatamente nella seconda parte dell'articolo. Tuttavia, a volte i descrittori vengono chiamati numero di riga nella tabella degli attributi. È da tenere presente. Per non confonderci, utilizzeremo il termine "puntatore dell'attributo" per questi scopi.
BLE al microscopio (ATT e GATT...)

Quindi, un attributo è un valore discreto che ha le seguenti proprietà associate:
1. Puntatore dell'attributo (Attribute Handle) — è l'indice della tabella corrispondente all'attributo
2. Tipo di attributo (Attribute Type) — è il UUID che descrive il suo tipo
3. Valore dell'attributo (Attribute Value) — sono i dati indicizzati dal puntatore dell'attributo
4. Permessi degli attributi (Attribute Permissions) — è la parte dell'attributo, permessi che non possono essere letti o scritti utilizzando il protocollo degli attributi

Come si interpreta tutto questo? Il puntatore dell'attributo è, in termini algebrici, il suo numero nella nostra tabella.
Consente al cliente di fare riferimento a un attributo nelle richieste di lettura o scrittura. Possiamo numerare le nostre righe (attributi) da 0x0001 a 0xFFFF. Nella nostra associazione con la libreria, questo corrisponde al numero della scheda nel catalogo cartaceo. Allo stesso modo, nel catalogo della biblioteca, le schede sono disposte in ordine crescente di numero. Il numero di ogni riga successiva deve essere maggiore di quello precedente. Come in una biblioteca, a volte si perdono alcune schede, quindi anche nella numerazione delle righe possono esserci intervalli. Questo è consentito. È importante che siano in ordine crescente.

Il tipo di attributo determina cosa rappresenta un dato attributo. Analogamente al linguaggio C,
dove ci sono variabili booleane, numeriche e stringhe, anche qui. Dal tipo di attributo capiamo
con cosa abbiamo a che fare e come dobbiamo lavorare ulteriormente con questo attributo. Di seguito esamineremo alcuni tipi specifici di attributi. Ad esempio, "dichiarazione di servizio" (0x2800), "dichiarazione di caratteristica" (0x2803), "dichiarazione di descrittore" (0x2902).

Il valore dell'attributo è proprio il suo valore, scusate per la tautologia. Se il tipo di attributo è una stringa, allora il valore dell'attributo può essere, ad esempio, uno slogan "Hello World !!!". Se il tipo di attributo è "dichiarazione di servizio", il suo valore è il servizio stesso. A volte, è anche un'informazione su dove trovare altri attributi e le loro proprietà.

I permessi degli attributi consentono al server di capire se l'accesso per la lettura o la scrittura è consentito.
Si noti che questi permessi si applicano solo al valore dell'attributo, e non al puntatore, al tipo e al campo stesso dei permessi. Cioè, se la scrittura dell'attributo è consentita, possiamo cambiare, ad esempio, la stringa "Hello World !!!" in "Good morning". Ma non possiamo vietare la scrittura di una nuova riga o cambiare il tipo di attributo e designare la riga come "dichiarazione di servizio". Quando un client si rivolge al server, richiede i suoi attributi. Questo consente al cliente di scoprire cosa può fornire il server. Anche se non è obbligatorio leggere e scrivere valori.

Come appare

Il concetto di GATT consiste nel raggruppare gli attributi in una tabella degli attributi insieme in un ordine molto specifico e logico. Esaminiamo più da vicino il profilo della frequenza cardiaca riportato di seguito. La colonna più a sinistra di questa tabella è facoltativa. Essa descrive semplicemente cosa rappresenta questa riga (attributo). Tutte le altre colonne ci sono già familiari.

BLE al microscopio (ATT e GATT...)

Nella parte superiore di ogni gruppo abbiamo sempre l'attributo di dichiarazione del servizio. Il suo tipo è sempre 0x2800, e il puntatore dipende da quanti attributi sono già presenti nella tabella. Le sue autorizzazioni sono sempre disponibili solo in lettura, senza alcuna autenticazione o autorizzazione. Di questi concetti parleremo più avanti. Il valore è un altro UUID che determina di che tipo di servizio si tratta. Nella tabella il valore è 0x180D, che viene definito dal Bluetooth SIG come servizio di frequenza cardiaca.

Dopo la dichiarazione del servizio, segue la dichiarazione della caratteristica. Ha una forma simile a quella della dichiarazione del servizio. Il suo UUID è sempre 0x2803, e le autorizzazioni sono sempre disponibili solo in lettura senza alcuna autenticazione o autorizzazione. Esaminiamo il campo Valore dell'Attributo, che include alcuni dati. Contiene sempre un puntatore, un UUID e un insieme di proprietà. Questi tre elementi descrivono la successiva dichiarazione del valore della caratteristica. Il puntatore indica naturalmente la posizione della dichiarazione del valore della caratteristica nella tabella degli attributi. L'UUID descrive che tipo di informazione o valore ci possiamo aspettare. Ad esempio, un valore di temperatura, lo stato di un interruttore della luce o un altro valore arbitrario. E infine, le proprietà, che descrivono come si può interagire con il valore della caratteristica.

Qui ci aspetta un altro tranello. È legato alle autorizzazioni degli attributi e alle proprietà delle caratteristiche. Diamo un'occhiata all'immagine delle proprietà del campo bitario della specifica.

BLE al microscopio (ATT e GATT...)

Come potete vedere, qui ci sono anche campi che offrono possibilità di lettura e scrittura. Potreste chiedervi perché abbiamo autorizzazioni di lettura/scrittura per l'attributo e la proprietà.
Letture/scritture per il valore della caratteristica? Non dovrebbero essere sempre uguali? Il fatto è che le proprietà per il valore della caratteristica sono, in effetti, solo raccomandazioni per il cliente, utilizzate in GATT e nei livelli applicativi. Sono semplici suggerimenti su cosa il cliente può aspettarsi dall'attributo della dichiarazione della caratteristica. Esaminiamo questo più nel dettaglio. Quali tipi di autorizzazioni esistono per l'attributo?

1. Autorizzazioni di accesso:
     — lettura
     — scrittura
     — lettura e scrittura
2. Autorizzazione all'autenticazione:
     — autenticazione richiesta
     — autenticazione non richiesta
3. Autorizzazione all'autorizzazione:
     — autorizzazione richiesta
     — autorizzazione non richiesta

La principale differenza tra le autorizzazioni degli attributi e le proprietà delle caratteristiche risiede nel fatto che le prime si riferiscono ai server, mentre le seconde ai clienti. Un server può avere l'autorizzazione a leggere il valore della caratteristica, ma può esserci una richiesta di autenticazione o autorizzazione. Pertanto, quando il cliente richiede le proprietà della caratteristica, otteniamo che la lettura è consentita. Ma nel tentativo di leggere si riceverà un errore. Quindi si può tranquillamente affermare che le autorizzazioni hanno la precedenza sulle proprietà. La conoscenza delle autorizzazioni disponibili per l'attributo non può essere ricevuta dal lato del cliente.

Descrittore

Tornando alla nostra tabella. Dopo la dichiarazione del valore della caratteristica, sono possibili le seguenti dichiarazioni degli attributi:
1. Nuova dichiarazione della caratteristica (nel servizio possono esserci molte caratteristiche)
2. Nuova dichiarazione del servizio (nella tabella possono essercene molte)
3. Dichiarazione del descrittore

Nel caso della caratteristica di misurazione della frequenza cardiaca, nella nostra tabella, l'annuncio del valore della caratteristica è accompagnato dall'annuncio del descrittore. Il descrittore è un attributo con informazioni aggiuntive sulla caratteristica. Esistono diversi tipi di descrittori. Di questi parleremo nel dettaglio nella seconda parte di questo articolo. Ora ci occuperemo solo del descrittore di configurazione delle caratteristiche del client (Client Characteristic Configuration Descriptor - CCCD). Ha un UUID pari a 0x2902. Con questo descrittore, il client ha la possibilità di attivare sul server l'indicazione o la notifica. La differenza tra di essi è piccola, ma comunque esiste. La notifica non richiede conferma di ricezione da parte del client. L'indicazione, invece, richiede questa conferma, anche se avviene a livello GATT, senza arrivare a livello applicativo. Perché è così, vi chiederete? Purtroppo, non lo so. Posso solo dire che gli specialisti della Nordic consigliano di utilizzare la notifica. Soprattutto perché il controllo dell'integrità del pacchetto (tramite CRC) avviene in entrambi i casi.

Conclusione

Alla fine dell'articolo vorrei dire questo. L'ultima tabella è piuttosto confusa. Tuttavia, mi sono fermato su di essa perché è fornita in abbiamo chiarito il corretto completamento dei programmi che utilizzano il mediastreamer., su cui mi baso. Nella seconda parte del mio articolo intendo approfondire la specifica BlueTooth 4.0. Lì ci aspettano schemi e disegni più corretti. Nella terza parte, vorrei analizzare il log ottenuto tramite il programma Wireshark da uno dei gadget e vedere 'dal vivo' tutta quella teoria che stiamo studiando.

Dipendente del Gruppo Aziendale «Cesare Satellit»
Pechersky Vladimir

Fonte: habr.com

Acquista hosting affidabile per siti web con protezione DDoS, VPS VDS server 🔥 Acquista hosting affidabile per siti web con protezione DDoS, VPS VDS server | ProHoster