11.5. Ligações¶
Quando um dispositivo central escolhe um periférico a partir do fluxo de publicidade e lhe envia um pedido de ligação, ambos os lados saem do modo de publicidade / varrimento e entram numa ligação. O rádio passa a agendar a sua atividade nos canais de dados da camada de ligação, saltando pseudo-aleatoriamente entre eles na sequência acordada no momento da ligação. Tudo acima da camada de ligação – GATT, segurança, L2CAP – corre em cima da ligação que aqui se estabelece.
11.5.1. O evento de ligação¶
Dois dispositivos numa ligação BLE não transmitem de forma contínua. Acordam um intervalo de ligação, e em cada intervalo ambos os lados acordam o rádio, trocam os pacotes que estão em fila, confirmam o que receberam e voltam a adormecer. Cada uma dessas trocas chama-se um evento de ligação.
O rádio em cada lado está acordado apenas durante os breves eventos de ligação, com tudo o resto a dormir. O periférico pode ignorar eventos sob latência do periférico.¶
Os números que governam isto são negociados no momento da ligação e a camada de ligação impõe-nos. São visíveis para a aplicação tanto como parâmetros do lado do pedido como como os valores resultantes reportados de volta.
Intervalo de ligação. 7,5 ms a 4 s, em passos de 1,25 ms. O dispositivo central escolhe o valor pedido pelo periférico, a menos que o pedido seja irrazoável. Intervalos mais curtos entregam dados com menor latência ao custo de mais atividade rádio; intervalos mais longos poupam energia mas tornam cada ida-e-volta mais lenta.
Latência do periférico. Um inteiro não negativo N. O periférico tem permissão para ignorar até N eventos de ligação sem nada para enviar, voltando a adormecer em vez de acordar o rádio para uma troca vazia. Útil para sensores que acordam para reportar uma vez por segundo mas querem um intervalo de ligação responsivo baixo para a rara mensagem imediata.
Timeout de supervisão. 100 ms a 32 s. Se qualquer um dos lados não ouvir nada do outro durante este período, a ligação é declarada perdida e ambos os lados voltam à publicidade / varrimento. O timeout deve ser maior do que
connection_interval * (1 + peripheral_latency)– a camada de ligação rejeita valores que violem isso.
aioble.Device.connect() aceita min_conn_interval_us e max_conn_interval_us para que o dispositivo central possa pedir um intervalo específico; o valor real em que o rádio se fixou pode ser lido de volta através da configuração da camada de ligação após a ligação estar ativa.
11.5.2. O que significam «central» e «periférico» dentro de uma ligação¶
Os papéis definidos no momento da publicidade mantêm-se após a ligação ser estabelecida:
O central controla o tempo – possui o lado mestre da sequência de saltos e os eventos de ligação.
O periférico é reativo. Pode pedir uma alteração aos parâmetros de ligação (um intervalo mais lento para poupar energia, por exemplo) mas o dispositivo central decide se aceita.
Os papéis são independentes de quem aloja a base 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 lado aloje serviços GATT. As câmaras seguem quase sempre a convenção: periférico + servidor para aplicações «a câmara publica dados», central + cliente para aplicações «a câmara lê de um sensor».
11.5.3. A unidade máxima de transmissão (MTU)¶
A camada de ligação transporta pacotes que são curtos por predefinição – 27 bytes de carga útil, dos quais apenas 23 estão disponíveis para GATT. Isso é suficiente para uma pequena leitura ou um comando curto, mas diminuto comparado com qualquer coisa de múltiplos bytes. Ambos os lados podem negociar isto para cima, até ao limite suportado pelo firmware do rádio (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, com um pequeno custo em memória de buffer.
11.5.4. Tempo de vida¶
Uma ligação dura até que uma das seguintes situações ocorra:
qualquer um dos lados chama
disconnect(),o timeout de supervisão dispara (fora de alcance, rádio desligado, par com falha), ou
uma falha explícita da camada de ligação (incompatibilidade de encriptação, rejeição de emparelhamento).
Quando a ligação cai, todas as operações GATT em fila ou em curso nela lançam aioble.DeviceDisconnectedError, e quaisquer blocos async with connection em que a aplicação esteja saem corretamente. Um periférico responde tipicamente voltando a aioble.advertise() e esperando pelo próximo central; um central responde fazendo novamente o varrimento ou expondo a desligação à aplicação.
O tempo de vida é uma das razões pelas quais aioble é útil. Uma API BLE síncrona teria de expor callbacks de desligação e máscaras de eventos; a versão asyncio transforma as desligações em exceções dentro da corrotina que estava à espera da operação, que é exatamente para o que a limpeza de async with foi concebida.