11.5. Conexões

Uma vez que um central escolhe um periférico no fluxo de anúncios e lhe envia uma connect request, ambos os lados saem do modo de anúncio / varredura e entram em uma conexão. O rádio agora agenda sua atividade nos canais de dados da camada de enlace, saltando pseudoaleatoriamente entre eles na sequência acordada no momento da conexão. Tudo acima da camada de enlace – GATT, segurança, L2CAP – roda sobre a conexão que é estabelecida aqui.

11.5.1. O evento de conexão

Dois dispositivos em uma conexão BLE não transmitem continuamente. Eles concordam com um connection interval e, a cada intervalo, ambos os lados acordam o rádio, trocam quaisquer pacotes enfileirados, confirmam o que receberam e voltam a dormir. Cada uma dessas trocas é chamada de connection event.

Uma linha do tempo com o central na faixa superior e o periférico na faixa inferior. Em cada limite de intervalo de conexão, ambas as faixas mostram um pulso curto rotulado como "TX/RX". O espaço entre os pulsos é rotulado como "connection interval"; a duração de cada pulso é "connection event". O periférico tem alguns eventos pulados rotulados como "peripheral latency: o periférico pode pular se estiver ocioso".

O rádio de cada lado fica acordado apenas durante os breves eventos de conexão, com todo o resto dormindo. O periférico pode pular eventos sob peripheral latency.

Os números que governam isso são negociados no momento da conexão e a camada de enlace os impõe. Eles ficam visíveis para a aplicação tanto como controles do lado da solicitação quanto como os valores resultantes reportados de volta.

  • Connection interval. De 7,5 ms a 4 s, em passos de 1,25 ms. O central escolhe o valor que o periférico solicita, a menos que a solicitação seja inviável. Intervalos mais curtos entregam dados com menor latência ao custo de mais atividade de rádio; intervalos mais longos economizam energia, mas tornam cada ida e volta mais lenta.

  • Peripheral latency. Um inteiro não negativo N. O periférico tem permissão para pular até N eventos de conexão sem nada a enviar, voltando a dormir em vez de acordar o rádio para uma troca vazia. Útil para sensores que acordam para reportar uma vez por segundo, mas que querem um connection interval baixo e responsivo para a rara mensagem imediata.

  • Supervision timeout. De 100 ms a 32 s. Se qualquer um dos lados não ouvir nada do outro por esse tempo, o enlace é declarado perdido e ambos os lados voltam ao anúncio / varredura. O timeout deve ser maior que connection_interval * (1 + peripheral_latency) – a camada de enlace rejeita valores que violem isso.

aioble.Device.connect() recebe min_conn_interval_us e max_conn_interval_us para que o central possa solicitar um intervalo específico; o valor real que o rádio definiu pode ser lido de volta através da configuração da camada de enlace depois que a conexão estiver no ar.

11.5.2. O que “central” e “periférico” significam dentro de uma conexão

Os papéis definidos no momento do anúncio permanecem após a conexão ser estabelecida:

  • O central controla a temporização – ele detém o lado mestre da sequência de saltos e dos eventos de conexão.

  • O periférico é reativo. Ele pode solicitar uma mudança nos parâmetros de conexão (um intervalo mais lento para economizar energia, por exemplo), mas o central decide se aceita.

Os papéis são independentes de quem hospeda o banco de dados GATT, que é um eixo separado. Por convenção, o periférico também é o servidor GATT e o central é o cliente GATT, mas o BLE permite que qualquer um dos lados hospede serviços GATT. As câmeras quase sempre seguem a convenção: periférico + servidor para aplicações do tipo “a câmera publica dados”, central + cliente para aplicações do tipo “a câmera lê de um sensor”.

11.5.3. A unidade máxima de transmissão (MTU)

A camada de enlace transporta pacotes que são curtos por padrão – 27 bytes de payload, dos quais apenas 23 estão disponíveis para o GATT. Isso é suficiente para uma pequena leitura ou um comando curto, mas é minúsculo ao lado de qualquer coisa com múltiplos bytes. Ambos os lados podem negociar esse valor para cima, até o limite que o firmware do rádio suporta (tipicamente algumas centenas de bytes em controladores modernos).

A API aioble conduz a negociação através de aioble.DeviceConnection.exchange_mtu() e o resultado fica disponível no atributo mtu. MTUs maiores significam menos idas e voltas para qualquer valor maior que ~20 bytes, a um pequeno custo de memória de buffer.

11.5.4. Tempo de vida

Uma conexão dura até que ocorra um destes:

  • qualquer um dos lados chame disconnect(),

  • o supervision timeout dispare (fora de alcance, rádio desligado, o par travou), ou

  • uma falha explícita na camada de enlace (incompatibilidade de criptografia, rejeição de pareamento).

Quando a conexão cai, toda operação GATT enfileirada ou em trânsito nela levanta aioble.DeviceDisconnectedError, e quaisquer blocos async with connection em que a aplicação esteja são encerrados de forma limpa. Um periférico tipicamente responde voltando a aioble.advertise() e aguardando o próximo central; um central responde tanto fazendo varredura novamente quanto expondo a desconexão à aplicação.

O tempo de vida é uma das razões pelas quais aioble é útil. Uma API BLE síncrona teria que expor callbacks de desconexão e máscaras de eventos; a versão asyncio transforma desconexões em exceções dentro da corrotina que estava aguardando a operação, que é exatamente para o que a limpeza do async with foi construída.