Gestione remota di I/O digitali

Alla fine è tornato comodo anche a me, ho aggiunto anche la possibilità di ricevere un CRC8 in formato HEX (due caratteri aggiuntivi dopo il *)

Le variabili di lavoro:

#define   MODULE_ADDR  '0'     // indirizzo/nome del modulo
#define   MAX_LEN_BUF  16      // lunghezza massima payload
#define   CRC_ON       false   // controllo CRC disattivo
byte      rxBufi;              // indice buffer, alla fine=numero byte ricevuti
byte      rxBuf[MAX_LEN_BUF];  // buffer di ricezione
boolean   onBroad = false;     // true se ricevuto indirizzo broadcast '&'

Le funzioni di supporto:

//------------------------------------------------------------------------------
// SNAP CRC8 - initial val 0 - reflect data in - reflect crc out - polynom 31h
//------------------------------------------------------------------------------
void crcUpdate(byte &crc, byte n)
{
    crc ^= n;
    for(byte i=8; i; i--)
    {
        byte lsb = crc & 1;
        crc >>= 1;
        if(lsb) crc ^= 0x8C;  // reflected polynom
    }
}
boolean isAsciiHex(byte n)
{
    return (n >= '0' && n <= '9') ? true : (n >= 'A' && n <= 'F') ? true : false;
}
//------------------------------------------------------------------------------
byte hexToInt(byte n)
{
    byte m = n - '0';
    return (m > 9) ? m - 7 : m;
}

La ricezione:

//------------------------------------------------------------------------------
//  FORMATO CON CRC:   #<addr><msg>*<crc>  ESEMPIO: #0L01*0F
//  FORMATO SENZA CRC: #<addr><msg>*       ESEMPIO: #0L01*
//  #          -> start char
//  <addr>     -> 1 char (& = broadcast)
//  <payload>  -> 0..MAX_LEN_BUF char
//  *          -> end msg char
//  <crc>      -> 2 char hex SNAP CRC8 facoltativi
//------------------------------------------------------------------------------
boolean ricevuto()
{
    static byte stat = 0;
    static byte crc;
    static byte crcH;

    while(Serial.available())
    {
        byte rx = Serial.read();

        if(rx == '#') { rxBufi = onBroad = crc = 0;  stat = 1; }  // start

        else if(rx < ' ')  stat = 0;  // esclude 0..31  128..255

        else
            switch (stat)
            {
            case 1:  // ricezione indirizzo modulo
                if(CRC_ON) crcUpdate(crc, rx);
                if(rx == MODULE_ADDR)  stat = 2;
                else if(rx == '&') {   onBroad = true;  stat = 2;  }
                else                   stat = 0;
                break;

            case 2:  // ricezione dati
                if(rx == '*')  // fine dati
                {
                    if(CRC_ON)  stat = 3;
                    else {     stat = 0;  return true; }
                }
                else if(rxBufi == MAX_LEN_BUF)  stat = 0;  // over buffer
                else  // salva byte
                {
                    if(CRC_ON) crcUpdate(crc, rx);
                    rxBuf[rxBufi++] = rx;
                }
                break;

            case 3:  // ricezione carattere alto crc8
                if(isAsciiHex(rx)) { crcH = hexToInt(rx);  stat = 4; }
                else                 stat = 0;
                break;

            case 4:  // ricezione carattere basso crc8
                stat = 0;
                if (isAsciiHex(rx)  &&  crc == (crcH << 4) + hexToInt(rx))
                    return true;
            }//switch
    }//while
    return false;
}

Quando la funzione ritorna true, rxBufi contiene il numero di caratteri ricevuti e onBroad vale true se l'indirizzo era '&'.

I caratteri ricevuti nel buffer non comprendono: start, indirizzo, fine, eventuale crc.

L'eventuale crc si calcola sui soli caratteri racchiusi tra # e * (quindi indirizzo e dati)

La funzione cerca, tra tutti i caratteri presenti in quel momento nel buffer di ricezione seriale, una sequenza valida, scartando tutto il resto e ritornando true appena ne trova una. Qualche carattere può restare nel buffer seriale e verrà analizzato/scartato alla successiva chiamata, qualsiasi sequenza errata viene ignorata senza alcun avviso.

La risposta alla domanda se limitare la comunicazione all' ASCII la rendeva intrinsecamente più adatta/sicura a rilevare/evitare gli errori è: NO

Se c'è la possibilità di linea errorata serve proprio un CRC.

Un normale checksum o uno xor ad esempio non rilevano differenze tra 0L01 e 01L0.