BLE bajo el microscopio (ATT y GATT…)

BLE bajo el microscopio (ATTs GATTs...)

BLE bajo el microscopio (ATT y GATT...)

Parte 1, revisión

Ha pasado bastante tiempo desde que se publicó la primera especificación de Bluetooth 4.0. Y, aunque el tema de BLE es muy interesante, todavía rechaza a muchos desarrolladores debido a su complejidad. En mis artículos anteriores, he tratado principalmente el nivel más bajo, el Link Layer y el Physical Layer. Esto me permitió evitar conceptos tan complejos y confusos como el protocolo de atributos (ATT) y el perfil de atributos general (GATT). Sin embargo, no hay forma de evitarlo; sin entenderlos, es imposible desarrollar dispositivos compatibles. Hoy me gustaría compartir con ustedes estos conocimientos. En mi artículo, me basaré en manual los fundamentos para principiantes del sitio de Nordic. Así que, comencemos.

¿Por qué todo es tan complicado?

En mi opinión, quedó claro desde el principio que el control de dispositivos a través de smartphones es un tema muy prometedor y de largo plazo. Por lo tanto, decidieron estructurarlo de inmediato al máximo. De esta manera, los fabricantes de varios gadgets no inventarían sus propios protocolos que luego no serían compatibles. De ahí la complejidad. Ya en la primera etapa, el protocolo BLE intentó incluir todo lo que fuera posible, sin importar si sería útil posteriormente o no. Además, se previó la posibilidad de ampliar la lista de dispositivos en el futuro.

Veamos la imagen que muestra el esquema del protocolo BLE. Se compone de varias capas. La capa más baja, la capa física (PHY), es responsable del canal de radio del dispositivo. El Link Layer (LL) contiene toda la secuencia de bytes en el mensaje transmitido. En artículos anteriores estudiamos precisamente esto. La Interfaz de Controlador de Host (HCI) es el protocolo de intercambio entre capas o chips BLE, cuando el Controller y el Host están implementados en diferentes chips. La formación de paquetes, la fragmentación en tramas, el control de errores y la recopilación de paquetes se realiza mediante el Protocolo de Control Lógico de Enlace y Adaptación (L2CAP). El Protocolo de Seguridad de Administrador (SMP) se encarga del cifrado de paquetes. El perfil de acceso general (GAP) es responsable del intercambio inicial de datos entre dispositivos, para determinar "quién es quién". Esto también incluye escaneo y publicidad. En este artículo me centraré en las dos partes restantes del protocolo: GATT y ATT. GATT es una superestructura sobre ATT, por lo que están muy entrelazados.

BLE bajo el microscopio (ATTs GATTs...)

Para simplificar la narrativa, quisiera utilizar una analogía. La escuché en algún lugar y me gustaría apoyarla. Imagina un dispositivo BLE como una estantería con varias baldas. Cada balda es un tema distinto. Por ejemplo, tenemos baldas de ciencia ficción, matemáticas, enciclopedias. En cada balda hay libros sobre el tema correspondiente. Y en algunos libros incluso hay marcapáginas con anotaciones. Además, tenemos un pequeño catálogo en papel de todos los libros. Si recuerdas las bibliotecas escolares, es una caja estrecha con tarjetas de papel. Con esta analogía, la estantería es el perfil de nuestro dispositivo. Las baldas son los servicios, los libros son las características, y el catálogo es la tabla de atributos. Los marcapáginas en los libros son los descriptores, de los que también hablaré más adelante, con más detalle.

Todos los que han desarrollado dispositivos saben que en muchos proyectos hay trozos de código similares. La razón es que muchos dispositivos tienen funciones similares. Por ejemplo, si los dispositivos funcionan con baterías, el problema de la carga y el control de su nivel será el mismo. Lo mismo se aplica a los sensores. De hecho, el enfoque orientado a objetos en la programación «ofrece la posibilidad de crear objetos que conectan propiedades y comportamientos en una unión autónoma que luego se puede reutilizar múltiples veces». En mi opinión, en BLE se ha intentado un enfoque similar. El grupo Bluetooth Special Interest Group (SIG) ha desarrollado perfiles. Los dispositivos de diferentes fabricantes que tienen perfiles idénticos deben funcionar sin problemas entre sí. Los perfiles, a su vez, constan de servicios, y los servicios de características, complementadas por descriptores. En general, esto puede verse así:

BLE bajo el microscopio (ATTs GATTs...)

Por ejemplo, consideremos el esquema del perfil de un monitor de frecuencia cardíaca (pulsera de fitness). Consiste en dos servicios y varias características. De inmediato se comprende la jerarquía del perfil. La característica del punto de control reinicia el recuento total de calorías gastadas a cero.

1. El servicio de frecuencia cardíaca incluye tres características (0x180D):
    a) Característica obligatoria de frecuencia de pulso (0x2A37)
    b) Característica opcional de posición del sensor corporal (0x2A38)
    c) Característica condicional del punto de control de frecuencia cardíaca (0x2A39)
2. Servicio de gestión de batería (0x180F):
    a) Característica obligatoria del nivel de carga de la batería (0x2A19)

UUID

Para que podamos referirnos de manera única a los elementos del perfil (servicios, características y descriptores), necesitamos numerarlos de alguna manera. Para ello se introduce el concepto de Identificador Único Universal (UUID). En los paréntesis de cada línea se indica precisamente el UUID. Y aquí hay una peculiaridad. Para el UUID se decidió utilizar un código de 16 y 128 bits de longitud. ¿Por qué, se preguntarán? En el protocolo BLE, todo está subordinado a la conservación de energía. Por lo tanto, un tamaño de 16 bits es bastante razonable. Es poco probable que en un futuro cercano se creen más de 65 mil servicios y características únicas. Hasta ahora, lo que podían, ya lo han calculado (recuerden de dónde proviene esto: "él también los contó a ustedes" :-)) Elementos numerados perfiles, servicios, características y descriptores pueden consultarlo a través de los enlaces.

Sin embargo, creo que todos recuerdan la historia de los 4 bytes de la dirección IP en Internet. Al principio se pensaba que sería suficiente, pero ahora no logramos pasar a una dirección de 6 bytes. Para no repetir este error y dar rienda suelta a las manos traviesas de los improvisadores, SIG decidió introducir también UUID de 128 bits. Esto me recuerda personalmente al rango no licenciado de 433 MHz, que fue otorgado a varios inventores del canal de radio. En nuestro caso, se otorgó el identificador de 128 bits para servicios y características. Esto significa que para nuestros servicios y dispositivos, podemos utilizar prácticamente cualquier valor de 128 bits. La probabilidad de inventar un UUID idéntico se acerca a cero.

En realidad, los UUID cortos de 16 bits tienen su extensión hasta un valor de 128 bits. En la especificación, esta extensión se llama Bluetooth Base UUID y tiene el valor 00000000-0000-1000-8000-00805F9B34FB. Si, por ejemplo, el UUID del atributo de 16 bits tiene el valor 0x1234, el UUID de 128 bits equivalente tendrá el valor 00001234-0000-1000-8000-00805F9B34FB. E incluso se proporciona la fórmula correspondiente:

                                128_bit_value = 16_bit_value * 2^96 + Bluetooth_Base_UUID

De dónde proviene este número mágico, no lo sé. Si alguien de los lectores lo sabe, que lo escriba en los comentarios (El usuario con el apodo Sinopteek ya lo ha hecho. Consulten los comentarios). En cuanto a la creación de UUID de 128 bits, en principio se puede utilizar un generador, que lo hará por usted.

ATT y GATT...

En realidad, aquí es donde comienza lo más interesante. Recuerdo que ATT se basa en la relación cliente-servidor. Ahora estamos considerando la configuración del servidor. Contiene información como valores de sensores, estado del interruptor de luz, datos de ubicación, etc. Ahora que todos los "participantes de nuestro desfile" están numerados, debemos organizarlos en la memoria del dispositivo. Para esto, los colocamos en una tabla llamada tabla de atributos. Recuerden bien esto. Es el corazón de BLE. Precisamente esto es lo que examinaremos más adelante. Ahora, cada fila la llamaremos atributo. Esta tabla se encuentra en lo profundo de la pila y, por regla general, no tenemos acceso directo a ella. La inicializamos y accedemos a ella, pero lo que sucede dentro está oculto para nosotros tras siete sellos.

Veamos la imagen de la especificación, pero antes quiero señalar de inmediato la confusión frecuente en los términos, especialmente en los descriptores. El papel de un descriptor es complementar la descripción de una característica. Cuando es necesario ampliar sus capacidades, se aplican descriptores. También son atributos y, junto con servicios y características, se encuentran en la tabla de atributos. Detallaremos esto en la segunda parte del artículo. Sin embargo, a veces, el número de fila en la tabla de atributos se denomina descriptores. Esto es importante tenerlo en cuenta. Para evitar confusiones, utilizaremos el término "indicador de atributo" para estos propósitos.
BLE bajo el microscopio (ATTs GATTs...)

Así que un atributo es un valor discreto que tiene las siguientes propiedades asociadas:
1. Indicador de atributo (Attribute Handle) — es el índice de la tabla correspondiente al atributo
2. Tipo de atributo (Attribute Type) — es el UUID que describe su tipo
3. Valor del atributo (Attribute Value) — son los datos indexados por el indicador de atributo
4. Permisos de atributos (Attribute Permissions) — son la parte del atributo, permisos que no pueden ser leídos o escritos utilizando el protocolo de atributos

¿Cómo entender todo esto? El indicador de atributo es, en términos simples, su número en nuestra tabla.
Permite al cliente referirse a un atributo en las solicitudes de lectura o escritura. Podemos numerar nuestras filas (atributos) del 0x0001 al 0xFFFF. En nuestra asociación con una biblioteca, esto es el número de la tarjeta en el catálogo de papel. De manera similar, al igual que en el catálogo de una biblioteca, las tarjetas se organizan en orden ascendente por número. El número de cada fila posterior debe ser mayor que el anterior. Al igual que en una biblioteca, algunas tarjetas a veces se pierden, por lo que pueden existir huecos en la numeración de las filas. Esto es aceptable. Lo importante es que sean ascendentemente.

El tipo de atributo define qué representa este atributo. Por analogía con el lenguaje C,
donde existen variables booleanas, numéricas y cadenas, aquí también. Por el tipo de atributo, sabemos
con qué estamos tratando y cómo debemos trabajar con este atributo. A continuación, examinaremos algunos tipos específicos de atributos. Por ejemplo, 'declaración de servicio' (0x2800), 'declaración de característica' (0x2803), 'declaración de descriptor' (0x2902).

El valor del atributo es su valor en sí, disculpen la tautología. Si el tipo de atributo es una cadena, el valor del atributo puede ser, por ejemplo, el eslogan 'Hello World !!!'. Si el tipo de atributo es 'declaración de servicio', su valor es el propio servicio. Y a veces es información sobre dónde encontrar otros atributos y sus propiedades.

Los permisos de los atributos permiten al servidor entender si el acceso a la lectura o escritura está permitido.
Tenga en cuenta que estos permisos se aplican solo al valor del atributo, no al puntero, tipo y al campo de permisos en sí. Es decir, si se permite la escritura del atributo, podemos cambiar, por ejemplo, la cadena 'Hello World !!!' a 'Good morning'. Pero no podemos prohibir la escritura de una nueva cadena o cambiar el tipo de atributo y designar la cadena como 'declaración de servicio'. Al solicitar al servidor, el cliente pide sus atributos. Esto permite al cliente conocer lo que puede ofrecer el servidor. Aunque no es necesario leer y escribir valores.

Cómo se ve esto

El concepto de GATT consiste en agrupar los atributos en la tabla de atributos de una manera muy específica y lógica. Veamos más de cerca el perfil de frecuencia cardíaca que se muestra a continuación. La columna más a la izquierda de esta tabla es opcional. Simplemente nos describe qué es esta fila (atributo). Todas las demás columnas ya nos son familiar.

BLE bajo el microscopio (ATTs GATTs...)

En la parte superior de cada grupo siempre tenemos el atributo de declaración del servicio. Su tipo siempre es 0x2800, y el puntero depende de cuántos atributos ya están presentes en la tabla. Su permisos siempre son de solo lectura, sin ninguna autenticación o autorización. Hablaremos de estos conceptos más adelante. El valor es otro UUID que define qué tipo de servicio es. En la tabla, el valor es 0x180D, que está definido por Bluetooth SIG como el servicio de frecuencia cardíaca.

Tras la declaración del servicio, sigue la declaración de la característica. Su formato es similar al de la declaración del servicio. Su UUID siempre tiene el valor 0x2803, y los permisos también son siempre de solo lectura sin ninguna autenticación o autorización. Veamos el campo Valor del Atributo, que incluye algunos datos. Siempre contiene un puntero, un UUID y un conjunto de propiedades. Estos tres elementos describen la posterior declaración del valor de la característica. El puntero, naturalmente, designa el lugar de la declaración del valor de la característica en la tabla de atributos. El UUID describe qué tipo de información o valor podemos esperar. Por ejemplo, el valor de temperatura, el estado del interruptor de luz o cualquier otro valor arbitrario. Y por último, las propiedades que describen cómo se puede interactuar con el valor de la característica.

Aquí nos espera otra trampa. Está relacionada con los permisos de los atributos y las propiedades de las características. Vamos a echar un vistazo a la imagen de las propiedades del campo de bits de la especificación.

BLE bajo el microscopio (ATTs GATTs...)

Como pueden ver, también hay campos que ofrecen capacidades de lectura y escritura. Puede preguntarse por qué tenemos permisos de lectura/escritura para el atributo y la propiedad.
¿Las lecturas/escrituras para el valor de atributo no deberían ser siempre las mismas? El hecho es que las propiedades del valor de atributo son, de hecho, solo recomendaciones para el cliente, utilizadas en GATT y en capas de aplicación. Son simplemente sugerencias sobre lo que el cliente puede esperar del atributo de declaración del atributo. Vamos a profundizar en esto. ¿Qué tipos de permisos existen para el atributo?

1. Permisos de acceso:
     — lectura
     — escritura
     — lectura y escritura
2. Permiso de autenticación:
     — se requiere autenticación
     — no se requiere autenticación
3. Permiso de autorización:
     — se requiere autorización
     — no se requiere autorización

La principal diferencia entre los permisos de los atributos y las propiedades de los atributos es que los primeros se refieren a los servidores, mientras que los segundos a los clientes. Un servidor puede tener permitido la lectura del valor de un atributo, pero puede haber un requisito de autenticación o autorización. Por lo tanto, al solicitar las propiedades del atributo por parte del cliente, obtendremos que la lectura está permitida. Pero al intentar leer, obtendremos un error. Así que se puede decir con seguridad que los permisos tienen prioridad sobre las propiedades. No podemos obtener información sobre qué permisos tiene el atributo desde el lado del cliente.

Descriptor

Regresando a nuestra tabla. Después de declarar el valor del atributo, se pueden realizar los siguientes anuncios de atributos:
1. Nueva declaración de atributo (puede haber muchos atributos en el servicio)
2. Nueva declaración de servicio (puede haber muchas en la tabla)
3. Anuncio del descriptor

En el caso de la característica de medición de la frecuencia cardíaca, en nuestra tabla, el anuncio del valor de la característica va acompañado de un anuncio del descriptor. Un descriptor es un atributo con información adicional sobre la característica. Existen varios tipos de descriptores. Hablaremos de ellos en detalle en la segunda parte de este artículo. Ahora, solo tocaremos el descriptor de configuración de características del cliente (Client Characteristic Configuration Descriptor - CCCD). Tiene un UUID igual a 0x2902. Con este descriptor, el cliente tiene la capacidad de activar la indicación o la notificación en el servidor. La diferencia entre ambas es pequeña, pero existe. La notificación no requiere confirmación de recepción por parte del cliente. La indicación sí lo requiere, aunque ocurre a nivel de GATT, sin llegar al nivel de la aplicación. ¿Por qué es así, preguntarán ustedes? Lamentablemente, no lo sé. Solo diré que los especialistas de Nordic recomiendan usar la notificación. Además, la verificación de la integridad del paquete (mediante CRC) se realiza en ambos casos.

Conclusión

Al final del artículo, me gustaría mencionar lo siguiente. La última tabla es algo confusa. Sin embargo, me detuve en ella porque se presenta en el artículo, en la que me baso. En la segunda parte de mi artículo, tengo la intención de profundizar en la especificación BlueTooth 4.0. Allí nos esperan esquemas y dibujos más precisos. En la tercera parte, quisiera analizar el log obtenido a través del programa Wireshark de uno de los dispositivos y ver en 'vivo' toda esa teoría que estamos estudiando.

Empleado del Grupo de Empresas «César Satelital»
Vladimir Pechersky

Fuente: habr.com

Compra un hosting fiable para sitios web con protección contra DDoS, servidores VPS VDS 🔥 Compra un hosting fiable para sitios web con protección contra DDoS, servidores VPS VDS | ProHoster