12.3. O formato do pacote¶
Todo byte que cruza a transmissão entre a câmera e o host faz parte de um pacote. Um pacote começa com um cabeçalho de 10 bytes, segue com uma carga de comprimento variável e termina com um CRC final de 4 bytes. Nenhum outro byte aparece na transmissão – uma vez que o host tenha visto a palavra de sincronização de 2 bytes, os próximos bytes são um cabeçalho nesta sequência exata.
12.3.1. O cabeçalho¶
Dez bytes, empacotados sem preenchimento. Cada campo:
sync– a palavra de 16 bits0xD5AAem ordem little-endian. O byte 0 na transmissão é0xAA, o byte 1 é0xD5. Um receptor que varre os bytes pode encontrar o início de um pacote procurando pelo parAA D5; qualquer coisa antes dele é tratada como lixo. A escolha do valor é deliberada:0xAAe0xD5raramente aparecem em texto imprimível, e o par dificilmente ocorre por acidente no meio de uma carga.seq– um byte. Um contador que incrementa em um para cada pacote enviado em uma dada direção. O receptor verifica se o número de sequência do próximo pacote é o esperado; se não for, a camada de confiabilidade pede uma retransmissão.chan– um byte. O ID do canal ao qual este pacote pertence. Os canais 0..31 são utilizáveis; os canais embutidosstdin,stdout,streame (opcionalmente)profileocupam IDs fixos que a câmera reserva.flags– um byte. Um campo de bits que diz ao receptor como interpretar o pacote:bit 0
ACK– este pacote é uma confirmação de um anterior.bit 1
NAK– este pacote rejeita um anterior.bit 2
RTX– este pacote é uma retransmissão.bit 3
ACK_REQ– o remetente quer que este pacote seja confirmado.bit 4
FRAGMENT– mais fragmentos seguem este em uma mensagem maior.bit 5
EVENT– este pacote carrega um evento de canal em vez de dados.os bits 6 e 7 são reservados.
opcode– um byte. O código de comando ou resposta. A biblioteca de protocolo reserva faixas de opcode por finalidade:0x00..0x0F– comandos de protocolo (SYNC, GET_CAPS, SET_CAPS, STATS, VERSION).0x10..0x1F– comandos de sistema (RESET, BOOT, INFO, EVENT, MEMORY).0x20..0x2F– comandos de canal (LIST, POLL, LOCK, UNLOCK, SHAPE, SIZE, READ, WRITE, IOCTL, EVENT).
len– dois bytes, little-endian. O número de bytes de carga que seguem o cabeçalho. Um comprimento de zero é válido – muitas confirmações e comandos pequenos não carregam carga alguma.crc– dois bytes. Um CRC-16 sobre os oito bytes anteriores do cabeçalho. Um receptor que recebe um cabeçalho com CRC inválido descarta o pacote inteiro sem sequer olhar a carga.
12.3.2. A carga¶
Zero ou mais bytes, tratados como opacos pela camada de enquadramento. O que há na carga depende do opcode: para uma resposta CHANNEL_READ são os dados reais do canal; para uma resposta GET_CAPS é uma pequena estrutura fixa; para uma escrita de canal é o que quer que o host tenha enviado.
O tamanho máximo da carga depende do tamanho do buffer de protocolo da câmera (consulte a tabela por placa em protocol.init()). Mensagens mais longas que o limite são divididas em fragmentos com a flag FRAGMENT ativada em todos, exceto no último.
12.3.3. O CRC final¶
Quatro bytes, um CRC-32 sobre a carga. Captura corrupções que o CRC do cabeçalho não consegue ver, particularmente em cargas longas onde um erro de um único bit no meio do quadro de outra forma passaria despercebido.
Dividir a verificação de integridade entre dois CRCs é deliberado. O CRC do cabeçalho protege os próprios campos de enquadramento – particularmente o comprimento da carga. Sem um CRC de cabeçalho separado, a inversão de um único bit no byte de comprimento faria o receptor ler o número errado de bytes da carga e dessincronizar completamente do fluxo de bytes; com ele, um cabeçalho danificado é rejeitado de imediato e o receptor revarre em busca da próxima palavra de sincronização. O CRC da carga então protege o corpo da mensagem como uma preocupação separada, de modo que a inversão de um bit nos dados é reportada como uma carga corrompida, em vez de confundida com um erro de enquadramento.
O formato é pequeno o bastante para ser percorrido byte a byte, e o fato de que todo pacote tem o mesmo layout – sincronização, então cabeçalho, então carga, então CRC – significa que um parser feito à mão cabe em uma tela de código. É por isso que uma pequena implementação de host em C, Python ou Rust é um projeto de fim de semana; a biblioteca de protocolo é a versão Python mantida em cada lado.