12.4. Handshake e negociação de capacidades¶
A câmara e o anfitrião chegam ambos ao transporte com as suas próprias ideias sobre como o protocolo deve funcionar: que modos CRC, se os ACKs são obrigatórios, qual o tamanho máximo do payload que conseguem colocar em buffer. Antes de o tráfego real começar, trocam um handshake que fixa esses parâmetros para o resto da sessão.
12.4.1. O anfitrião abre a ligação¶
O lado da câmara inicia a pilha de protocolo no arranque (ou a aplicação reinicia-a com protocol.init() para alterar parâmetros), ficando depois à espera de um anfitrião. Do ponto de vista da câmara, não há nada a fazer até chegar um pacote.
O lado do anfitrião abre o transporte – porta USB ou UART – e envia imediatamente um pacote PROTO_SYNC (opcode 0x00). Este pacote tem um payload mágico que permite à câmara reconhecê-lo mesmo que ambos os lados estejam fora de sincronização, e é o único pacote ao qual a câmara responde antes de as capacidades serem negociadas.
Se a câmara não responder dentro do tempo limite de retransmissão, o anfitrião envia PROTO_SYNC novamente, até rtx_retries vezes. Depois disso desiste e reporta uma falha de ligação. A retransmissão é o que faz «desligar, religar, reiniciar o script do anfitrião» funcionar sem que a câmara precise de saber que o anfitrião se foi embora.
12.4.2. Troca de capacidades¶
Assim que a câmara reconhece a sincronização, o anfitrião envia PROTO_GET_CAPS (opcode 0x01) para perguntar o que a câmara suporta. O payload da resposta indica:
Validação CRC ativada ou desativada
Rastreamento de número de sequência ativado ou desativado
ACKs ativados ou desativados
Notificações de eventos ativadas ou desativadas
O tamanho máximo de payload da câmara em bytes
A contagem atual de tentativas de retransmissão, tempo limite e parâmetros de sondagem
O anfitrião compara esses valores com a sua própria configuração. Se o anfitrião precisar de alterar algum deles – por exemplo, para negociar um payload máximo menor porque o seu buffer de receção é mais pequeno do que o da câmara – envia PROTO_SET_CAPS (opcode 0x02) com os novos valores. A câmara reconfigura a sua pilha e reconhece. A partir daqui, todos os pacotes que cruzam a linha seguem esse contrato partilhado.
Se o anfitrião não substituir nada, as predefinições estão todas ativas: validação CRC, rastreamento de número de sequência, ACKs e notificações de eventos. O payload máximo predefinido é o buffer por placa da câmara menos 14 bytes de overhead de enquadramento (o cabeçalho de 10 bytes mais o CRC de payload final de 4 bytes). Para a maioria do trabalho câmara-para-portátil, as predefinições são o ponto de partida correto; a página de fiabilidade explica quando e por que razão uma aplicação desativa partes delas.
12.4.3. Descoberta de canais¶
Após as capacidades, o anfitrião envia CHANNEL_LIST (opcode 0x20). A câmara responde com uma lista de canais registados – os quatro integrados (stdin, stdout, stream, profile) mais os que a aplicação registou com protocol.register(). Cada entrada contém o ID do canal, o seu nome e os seus indicadores de capacidade (só leitura, só escrita, bloqueável).
O anfitrião guarda a lista e usa-a mais tarde quando o código da aplicação pede channel_read("frame") ou channel_write("config", ...) – o nome é convertido num ID de canal uma vez, e depois cada pacote subsequente nesse canal usa o ID diretamente.
Se a câmara registar um novo canal após a lista inicial – comum quando uma aplicação começa a ser executada após o handshake – a câmara emite um pacote de evento CHANNEL_REGISTERED. O anfitrião fica à escuta desses eventos e atualiza a sua lista interna de canais, para que um script de anfitrião que se ligou cedo veja novos canais registados aparecer sem reiniciar.
O handshake demora algumas viagens de ida e volta na configuração da ligação e depois nunca se repete. O tráfego em estado estável são apenas pacotes: bytes enquadrados a entrar, bytes enquadrados a sair, os IDs de canal já conhecidos em ambos os lados.