12.4. Handshake e negoziazione delle capacità¶
La camera e l’host arrivano entrambi al trasporto con le proprie idee su come dovrebbe funzionare il protocollo: quali modalità CRC, se le ACK sono obbligatorie, qual è il payload più grande che possono bufferizzare. Prima che inizi il traffico reale, si scambiano un handshake che fissa quei parametri per il resto della sessione.
12.4.1. L’host apre la connessione¶
Il lato camera avvia lo stack del protocollo all’avvio (oppure l’applicazione lo riavvia con protocol.init() per cambiare i parametri), poi resta in attesa silenziosa di un host. Dal punto di vista della camera non c’è nulla da fare finché non arriva un pacchetto.
Il lato host apre il trasporto – porta USB o UART – e invia immediatamente un pacchetto PROTO_SYNC (opcode 0x00). Questo pacchetto ha un payload magico che permette alla camera di riconoscerlo anche se entrambi i lati hanno perso la sincronizzazione, ed è l’unico pacchetto a cui la camera risponde mai prima che le capacità siano negoziate.
Se la camera non risponde entro il timeout di ritrasmissione, l’host invia di nuovo PROTO_SYNC, fino a rtx_retries volte. Dopodiché rinuncia e segnala un fallimento della connessione. Il tentativo di ripetizione è ciò che fa funzionare «scollega, ricollega, riavvia lo script host» senza che la camera debba sapere che l’host se n’è andato.
12.4.2. Scambio delle capacità¶
Una volta che la camera conferma la sincronizzazione, l’host invia PROTO_GET_CAPS (opcode 0x01) per chiedere cosa supporta la camera. Il payload di risposta riporta:
Validazione CRC abilitata o disabilitata
Tracciamento del numero di sequenza abilitato o disabilitato
ACK abilitate o disabilitate
Notifiche di eventi abilitate o disabilitate
La dimensione massima del payload della camera in byte
Il conteggio attuale dei tentativi di ritrasmissione, il timeout e i parametri di polling
L’host li confronta con la propria configurazione. Se l’host deve cambiare qualcuno di essi – per esempio, per negoziare un payload massimo più piccolo perché il suo buffer di ricezione è più piccolo di quello della camera – invia PROTO_SET_CAPS (opcode 0x02) con i nuovi valori. La camera riconfigura il suo stack e conferma. Da qui in poi, ogni pacchetto che attraversa la linea segue quel contratto condiviso.
Se l’host non sovrascrive nulla, le impostazioni predefinite sono tutte attive: validazione CRC, tracciamento del numero di sequenza, ACK e notifiche di eventi. Il payload massimo predefinito è il buffer per scheda della camera meno 14 byte di overhead di framing (l’intestazione di 10 byte più il CRC di payload finale di 4 byte). Per la maggior parte del lavoro da camera a laptop le impostazioni predefinite sono il giusto punto di partenza; la pagina sull’affidabilità spiega quando e perché un’applicazione decide di disattivarne alcune parti.
12.4.3. Scoperta dei canali¶
Dopo le capacità, l’host invia CHANNEL_LIST (opcode 0x20). La camera risponde con un elenco di canali registrati – i quattro integrati (stdin, stdout, stream, profile) più tutti quelli che l’applicazione ha registrato con protocol.register(). Ogni voce contiene l’ID del canale, il suo nome e i suoi flag di capacità (sola lettura, sola scrittura, bloccabile).
L’host conserva l’elenco e lo usa in seguito quando il codice applicativo richiede channel_read("frame") o channel_write("config", ...) – il nome viene risolto in un ID di canale una sola volta, dopodiché ogni pacchetto successivo su quel canale usa direttamente l’ID.
Se la camera registra un nuovo canale dopo l’elenco iniziale – cosa comune quando un’applicazione inizia a essere eseguita dopo l’handshake – la camera emette un pacchetto evento CHANNEL_REGISTERED. L’host li ascolta e aggiorna il proprio elenco interno di canali, così uno script host che si è collegato presto vede comparire i canali appena registrati senza riavviare.
L’handshake richiede alcuni round-trip durante l’impostazione della connessione e poi non si ripete mai. Il traffico a regime sono solo pacchetti: byte incorniciati in entrata, byte incorniciati in uscita, gli ID dei canali già noti a entrambi i lati.