11.5. Verbindingen

Zodra een central een peripheral uit de advertentiestroom kiest en er een connect request naartoe stuurt, verlaten beide kanten de advertentie- / scanmodus en gaan ze over naar een verbinding. De radio plant zijn activiteit nu op de datakanalen van de link layer en springt er pseudo-willekeurig tussen volgens de bij het verbinden afgesproken volgorde. Alles boven de link layer – GATT, beveiliging, L2CAP – draait bovenop de verbinding die hier tot stand komt.

11.5.1. Het verbindingsevenement

Twee apparaten in een BLE-verbinding streamen niet voortdurend. Ze spreken een connection interval af, en bij elk interval maken beide kanten de radio wakker, wisselen ze de in de wachtrij staande pakketten uit, bevestigen ze wat ze hebben ontvangen en gaan ze weer slapen. Elk van die uitwisselingen heet een connection event.

Een tijdlijn met de central op het bovenste spoor en de peripheral op het onderste spoor. Bij elke connection-interval-grens tonen beide sporen een korte puls met het label "TX/RX". De ruimte tussen pulsen heeft het label "connection interval"; de duur van elke puls is "connection event". De peripheral heeft een paar overgeslagen events met het label "peripheral latency: peripheral mag overslaan als inactief".

De radio aan elke kant is alleen wakker tijdens de korte connection events; al het andere slaapt. De peripheral mag events overslaan onder peripheral latency.

De getallen die dit regelen worden bij het verbinden onderhandeld en de link layer dwingt ze af. Ze zijn voor de applicatie zichtbaar als instelknoppen aan de verzoekkant en als de resulterende waarden die teruggemeld worden.

  • Connection interval. 7,5 ms tot 4 s, in stappen van 1,25 ms. De central kiest de waarde die de peripheral vraagt, tenzij het verzoek onredelijk is. Kortere intervallen leveren data met lagere latentie maar ten koste van meer radioactiviteit; langere besparen energie maar maken elke round trip trager.

  • Peripheral latency. Een niet-negatief geheel getal N. De peripheral mag tot N connection events overslaan wanneer er niets te verzenden is, en in plaats daarvan weer gaan slapen in plaats van de radio te wekken voor een lege uitwisseling. Handig voor sensoren die eens per seconde wakker worden om te rapporteren, maar voor het zeldzame onmiddellijke bericht toch een laag, responsief connection interval willen.

  • Supervision timeout. 100 ms tot 32 s. Als een van beide kanten zo lang niets van de ander hoort, wordt de link als verloren beschouwd en gaan beide kanten terug naar adverteren / scannen. De timeout moet langer zijn dan connection_interval * (1 + peripheral_latency) – de link layer weigert waarden die dat schenden.

aioble.Device.connect() neemt min_conn_interval_us en max_conn_interval_us zodat de central een bepaald bereik kan aanvragen; de feitelijke waarde waar de radio op uitkwam kan na het opzetten van de verbinding worden teruggelezen via de configuratie van de link layer.

11.5.2. Wat “central” en “peripheral” binnen een verbinding betekenen

De rollen die bij het adverteren zijn ingesteld blijven gelden nadat de verbinding tot stand is gekomen:

  • De central stuurt de timing aan – hij beheert de masterkant van de hopping-sequence en de connection events.

  • De peripheral is reactief. Hij kan een wijziging van de verbindingsparameters aanvragen (bijvoorbeeld een trager interval om energie te besparen), maar de central beslist of dit wordt geaccepteerd.

De rollen staan los van wie de GATT-database host, wat een aparte as is. Volgens afspraak is de peripheral ook de GATT-server en de central de GATT-client, maar BLE staat toe dat beide kanten GATT-services hosten. Camera’s volgen vrijwel altijd de afspraak: peripheral + server voor toepassingen waarin “de camera data publiceert”, central + client voor toepassingen waarin “de camera van een sensor leest”.

11.5.3. De maximum transmission unit (MTU)

De link layer vervoert pakketten die standaard kort zijn – 27 bytes payload, waarvan er maar 23 beschikbaar zijn voor GATT. Dat is genoeg voor een kleine meting of een kort commando, maar nietig naast iets met meerdere bytes. Beide kanten kunnen dit naar boven onderhandelen, tot aan de limiet die de radio-firmware ondersteunt (doorgaans enkele honderden bytes op moderne controllers).

De aioble-API stuurt de onderhandeling aan via aioble.DeviceConnection.exchange_mtu() en het resultaat komt beschikbaar via het attribuut mtu. Grotere MTU’s betekenen minder round trips voor elke waarde groter dan ~20 bytes, tegen een kleine kost aan buffergeheugen.

11.5.4. Levensduur

Een verbinding duurt voort totdat een van de volgende gebeurt:

  • een van beide kanten roept disconnect() aan,

  • de supervision timeout afgaat (buiten bereik, radio uit, peer gecrasht), of

  • een expliciete link-layer-fout optreedt (encryptie-mismatch, weigering van pairing).

Wanneer de verbinding wegvalt, werpt elke GATT-bewerking die erop in de wachtrij staat of onderweg is een aioble.DeviceDisconnectedError, en eventuele async with connection-blokken waarin de applicatie zit worden netjes verlaten. Een peripheral reageert doorgaans door terug te gaan naar aioble.advertise() en op de volgende central te wachten; een central reageert door opnieuw te scannen of de disconnect aan de applicatie kenbaar te maken.

De levensduur is een van de redenen waarom aioble nuttig is. Een synchrone BLE-API zou disconnect-callbacks en event-maskers moeten blootstellen; de asyncio-versie zet disconnects om in excepties binnen de coroutine die op de bewerking wachtte, en daar is async with-opruiming juist voor gebouwd.