Existem várias maneiras de escrever um protocolo serial, dependendo da funcionalidade desejada e da verificação de erros necessária.
Algumas das coisas comuns que você vê nos protocolos ponto a ponto são:
Fim da mensagem
Os protocolos ASCII mais simples têm apenas uma sequência de caracteres no final da mensagem, geralmente \r
ou \n
é isso que é impresso quando a tecla Enter é pressionada. Protocolos binários podem usar 0x03
ou algum outro byte comum.
Início da mensagem
O problema de ter apenas o final da mensagem é que você não sabe quais outros bytes já foram recebidos ao enviar sua mensagem. Esses bytes seriam prefixados para a mensagem e causariam uma interpretação incorreta. Por exemplo, se o Arduino acabou de acordar, pode haver algum lixo no buffer serial. Para contornar isso, você inicia uma sequência de mensagens. No seu exemplo ^
, em protocolos binários frequentemente0x02
Verificação de erros
Se a mensagem puder ser corrompida, precisamos de uma verificação de erro. Pode ser uma soma de verificação ou um erro de CRC ou outra coisa.
Escape Characters
Pode ser que a soma de verificação seja adicionada a um caractere de controle, como o byte 'start of message' ou 'end of message', ou a mensagem contenha um valor igual a um caractere de controle. A solução é introduzir um caractere de escape. O caractere de escape é colocado antes de um caractere de controle modificado para que o caractere de controle real não esteja presente. Por exemplo, se um caractere inicial for 0x02, usando o caractere de escape 0x10, podemos enviar o valor 0x02 na mensagem como o par de bytes 0x10 0x12 (caractere de controle XOR do byte)
Número do pacote
Se uma mensagem estiver corrompida, poderemos solicitar um reenvio com uma mensagem nack ou tentar novamente, mas se várias mensagens forem enviadas, apenas a última mensagem poderá ser reenviada. Em vez disso, o pacote pode receber um número que rola após um certo número de mensagens. Por exemplo, se esse número for 16, o dispositivo transmissor poderá armazenar as últimas 16 mensagens enviadas e, se alguma estiver corrompida, o dispositivo receptor poderá solicitar um reenvio usando o número do pacote.
comprimento
Frequentemente, em protocolos binários, você vê um byte de comprimento que informa ao dispositivo receptor quantos caracteres há na mensagem. Isso adiciona outro nível de verificação de erro, como se o número correto de bytes não tivesse sido recebido, e ocorreu um erro.
Específico para Arduino
Ao criar um protocolo para o Arduino, a primeira consideração é a confiabilidade do canal de comunicação. Se você estiver enviando pela maioria dos meios sem fio, XBee, WiFi, etc, já existe uma verificação de erros e novas tentativas e, portanto, não faz sentido colocá-las em seu protocolo. Se você enviar o RS422 por alguns quilômetros, será necessário. As coisas que eu incluiria são o início e o final dos caracteres da mensagem, como você fez. Minha implementação típica se parece com:
>messageType,data1,data2,…,dataN\n
A delimitação das partes dos dados com uma vírgula permite uma análise fácil e a mensagem é enviada usando ASCII. Os protocolos ASCII são ótimos porque você pode digitar mensagens no monitor serial.
Se você deseja um protocolo binário, talvez para diminuir o tamanho das mensagens, será necessário implementar escape se um byte de dados puder ser o mesmo que um byte de controle. Os caracteres de controle binário são melhores para sistemas em que o espectro completo de verificação de erros e novas tentativas é desejado. A carga útil ainda pode ser ASCII, se desejado.
Eu não tenho nenhum conhecimento formal em protocolos seriais, mas eu os usei algumas vezes e mais ou menos resolvi esse esquema:
(Cabeçalho do pacote) (byte ID) (dados) (soma de verificação do fletcher16) (Rodapé do pacote)
Eu costumo fazer o cabeçalho 2 bytes e o rodapé 1 byte. Meu analisador despeja tudo quando vê um novo cabeçalho de pacote e tenta analisar a mensagem se encontrar um rodapé. Se a soma de verificação falhar, ela não descartará a mensagem, mas continuará adicionando até que o caractere de rodapé seja encontrado e uma soma de verificação seja bem-sucedida. Dessa forma, o rodapé precisa ter apenas um byte, pois as colisões não atrapalham a mensagem.
O ID é arbitrário, às vezes com o comprimento da seção de dados sendo a mordidela inferior (4 bits). Um segundo bit de comprimento poderia ser usado, mas normalmente não me incomodo, pois o comprimento não precisa ser conhecido para analisar corretamente, portanto, ver o comprimento certo para um determinado ID é apenas mais uma confirmação de que a mensagem estava correta.
A soma de verificação fletcher16 é uma soma de verificação de 2 bytes com quase a mesma qualidade que a CRC, mas é muito mais fácil de implementar. alguns detalhes aqui . O código pode ser tão simples como este:
Também usei um sistema de chamada e respone para mensagens críticas, onde o PC envia uma mensagem a cada 500 ms ou mais, até que receba uma mensagem OK com uma soma de verificação de toda a mensagem original como dados (incluindo a soma de verificação original).
Obviamente, esse esquema não é adequado para ser digitado em um terminal como seria o seu exemplo. Seu protocolo parece muito bom por estar limitado ao ASCII e, com certeza, é mais fácil para um projeto rápido que você deseja ler e enviar mensagens diretamente. Para projetos maiores, é bom ter a densidade de um protocolo binário e a segurança de uma soma de verificação.
fonte
Se você gosta de padrões, pode dar uma olhada na codificação ASN.1 / BER TLV. ASN.1 é uma linguagem usada para descrever estruturas de dados, feitas especificamente para comunicação. O BER é um método TLV de codificação dos dados estruturados usando ASN.1. O problema é que a codificação ASN.1 pode ser complicada na melhor das hipóteses. Criar um compilador ASN.1 completo é um projeto em si (e particularmente complicado, pense meses ).
Provavelmente é melhor manter apenas a estrutura TLV. O TLV consiste basicamente em três elementos: um tag, um comprimento e um campo de valor. A tag define o tipo dos dados (sequência de texto, sequência de octetos, número inteiro etc.) e o comprimento o comprimento do valor .
No BER, o T também indica se o valor é um conjunto de estruturas TLV (um nó construído) ou diretamente um valor (um nó primitivo). Dessa forma, você pode criar uma árvore em binário, muito parecido com XML (mas sem a sobrecarga de XML).
Exemplo:
é um número inteiro (tag
02
) com um comprimento do valor de 1 (comprimento01
) e do valor -1 (valorFF
). No ASN.1 / BER, os números inteiros são números endian grandes, mas é claro que você pode usar seu próprio formato.é uma sequência (uma lista) com o comprimento 7 que contém dois números inteiros, um com o valor -1 e outro com o valor 255. As duas codificações inteiras juntas formam o valor da sequência.
Você pode simplesmente jogar isso em um decodificador on-line também, não é legal?
Você também pode usar comprimento indefinido no BER, o que permitirá transmitir dados. Nesse caso, você precisa analisar sua árvore corretamente. Eu consideraria um tópico avançado, você precisa saber sobre a amplitude e a profundidade da primeira análise, por exemplo.
O uso de um esquema TLV basicamente permite que você pense em qualquer tipo de estrutura de dados e a codifique. O ASN.1 vai muito além disso, fornecendo identificadores exclusivos (OIDs), opções (muito como uniões C), inclui outras estruturas do ASN.1 etc. etc., mas isso pode ser um exagero para o seu projeto. Provavelmente, as estruturas definidas pela ASN.1 mais conhecidas atualmente são os certificados usados pelo seu navegador.
fonte
Caso contrário, você tem o básico coberto. Seus comandos podem ser criados e lidos por humanos e máquinas, o que é uma grande vantagem. Você pode adicionar uma soma de verificação para detectar um comando mal formado ou um danificado em trânsito, especialmente se o seu canal incluir um cabo longo ou um link de rádio.
Se você precisar de força industrial (seu dispositivo não deve causar ou permitir que alguém se machuque ou morra; você precisa de altas taxas de dados, recuperação de falhas, detecção de pacotes ausentes etc.), consulte alguns dos protocolos e práticas de design padrão.
fonte