MCU & FPGA UART (Serial) Protocolos auto-sincronizáveis em sistemas embarcados

Protocolos auto-sincronizáveis em sistemas embarcados


COBS (Consistent Overhead Byte Stuffing): framing determinístico e recuperação real

O COBS surge como resposta direta às fragilidades do SLIP. Ele parte de um princípio simples, porém poderoso: eliminar completamente um valor do payload (normalmente 0x00) e usá-lo exclusivamente como delimitador de pacote. Com isso, o framing torna-se determinístico, auto-sincronizável e com overhead previsível.

Diferente do SLIP, o COBS não depende de escapes condicionais. Ele reorganiza os dados em blocos prefixados por comprimento, garantindo que o delimitador nunca apareça dentro do pacote codificado. O resultado é um fluxo que se re-sincroniza sozinho após erros, sem estados frágeis.


Ideia central do COBS

  • O byte 0x00 não aparece no payload codificado
  • Cada bloco começa com um contador (1–255)
  • O contador indica quantos bytes não-zero vêm a seguir
  • Um 0x00 no payload original “quebra” o bloco

No fluxo final:

[bloco][bloco][bloco] 0x00

O 0x00 marca fim de pacote, sempre.


Exemplo conceitual

Payload original:

11 22 00 33 44 55

Após COBS:

03 11 22 04 33 44 55 00

Interpretação:

  • 03 → dois bytes seguem (11 22)
  • 04 → três bytes seguem (33 44 55)
  • 00 → fim de pacote

Mesmo que um byte se perca, o receptor re-encontra o próximo 0x00 e volta a alinhar o stream.


Encoder COBS — implementação didática em C

#include <stdint.h>
#include <stddef.h>

size_t cobs_encode(const uint8_t *input, size_t length, uint8_t *output)
{
    size_t read_index = 0;
    size_t write_index = 1;
    size_t code_index = 0;
    uint8_t code = 1;

    while (read_index < length) {
        if (input[read_index] == 0) {
            output[code_index] = code;
            code = 1;
            code_index = write_index++;
            read_index++;
        } else {
            output[write_index++] = input[read_index++];
            code++;
            if (code == 0xFF) {
                output[code_index] = code;
                code = 1;
                code_index = write_index++;
            }
        }
    }

    output[code_index] = code;
    output[write_index++] = 0x00; // delimitador
    return write_index;
}

Observe duas propriedades importantes:

  • Sem estados frágeis
  • Overhead máximo conhecido: 1 byte a cada 254 bytes

Isso é ouro em sistemas de tempo real.


Decoder COBS — recuperação previsível

int cobs_decode(const uint8_t *input, size_t length, uint8_t *output)
{
    size_t read_index = 0;
    size_t write_index = 0;

    while (read_index < length) {
        uint8_t code = input[read_index++];
        if (code == 0 || read_index + code - 1 > length) {
            return -1; // erro de framing
        }

        for (uint8_t i = 1; i < code; i++) {
            output[write_index++] = input[read_index++];
        }

        if (code != 0xFF && read_index < length) {
            output[write_index++] = 0x00;
        }
    }

    return (int)write_index;
}

Aqui está o ponto-chave: erros são detectáveis e localizados. Um pacote inválido pode ser descartado sem corromper o fluxo seguinte.


Por que COBS é realmente auto-sincronizável

Em termos de engenharia de protocolo, o COBS atende aos critérios mais exigentes:

  • Delimitador único e inequívoco (0x00)
  • Parsing puramente streaming
  • Recuperação após erro sem reset global
  • Complexidade O(n)
  • Nenhuma dependência de temporização

Por isso ele é amplamente usado em:

  • UART industrial
  • SPI em modo streaming
  • CAN encapsulado
  • RPC embarcado
  • Gateways MCU ↔ Linux

Boas e más escolhas com COBS

Boas escolhas

  • Transporte binário puro
  • Protocolos próprios
  • Links com ruído
  • Sistemas distribuídos
  • Integração com CRC externo

Más escolhas

  • Payload textual humano
  • Mensagens muito pequenas (overhead irrelevante, mas sem ganho)
  • Quando já existe framing físico (ex: CAN clássico)

Comparação direta: SLIP × COBS

CritérioSLIPCOBS
Auto-sincronizaçãoFracaForte
OverheadVariávelDeterminístico
Recuperação de erroLimitadaPrevisível
Parsing streamingFrágilRobusto
Uso em produçãoRaroComum

O COBS não “parece” simples à primeira vista, mas é simples onde importa: no comportamento do sistema.


Conclusão parcial

Se SLIP é didático, o COBS é engenharia madura. Ele não tenta ser semântico, não tenta ser bonito — ele transporta bytes com dignidade.

Na próxima seção, vamos entrar no CBOR:

  • O que ele resolve (e o que não resolve)
  • Por que ele não substitui COBS
  • Como combinar COBS + CBOR corretamente
0 0 votos
Classificação do artigo
Inscrever-se
Notificar de
guest
0 Comentários
mais antigos
mais recentes Mais votado
Feedbacks embutidos
Ver todos os comentários

Related Post

0
Adoraria saber sua opinião, comente.x