Manipolare dati seriale

Salve raga, sto utilizzando per la prima volta la seriale (tramite xbee) e sto "creando" un protocollo di comunicazione tra tx ed rx. Detto questo e facendo alcune prove, inizializzando anche la seriale sul pc per vedere i dati ricevuti dall'rx, ho notato che in caso il segnale tra i 2 xbee non sia eccellente, la seriale riporta caratteri "strausi" (lasciatemi passare il termine :grinning: ). Il protocollo che vorrei utilizzare è semplicissimo ed è del tipo: "NUM1,NUM2,NUM3,NUM4,....ecc...., NUMn" e va a capo Cosa succede: siccome ricevuti i dati in seriale poi li manipolo con substring (utilizzo le virgole che delimitano tutti i valori) avevo bisogno di una funzione che in VB richiamavo con un semplice comando, adesso spiego meglio: (Esempio in VB)

dim CIAO as string = 3
if CIAO.isNumber() = true then .......

Non faceva altro che verificare se il valore memorizzato in una variabile di tipo string era effettivamente anche un numero e quindi poteva essere usato con tutte le sue proprietà di number (ad esempio per i cicli for/while) Questo perchè: se dovessi avere problemi di comunicazione (e quindi ricevere non dei numeri, ma dei caratteri del tipo èy&%%%%\_°) questo dato ricevuto non deve essere preso in considerazione e ne tanto meno bloccare la comunicazione/esecuzione del programma sull'rx.

String lettura

void setup() {
  Serial.begin(9600);
  sXbee.begin(9600);
}

void loop() {
  if (sXbee.available()) {
    char c = sXbee.read();
    if (c != '\n') {
      lettura += c;
    }
    else
    {
      //qui passo al vaglio le substring
    }
  }
}

Quindi le substring a loro volta verranno memorizzate in int (il problema è che non ho la certezza di aver ricevuto un numero)... Chi mi suggerisce una buona guida (ita/eng) per poter raggiungere il mio risultato?

Credo che in c la cosa più vicina alla funzione isNumber che utilizzi in VB sia la isDigit, che però lavora su un carattere alla volta, quindi dovrai ciclare sulle varie sotto stringhe, una cosa del tipo:

char *token;
const char sep[2] = ",";
token = strtok(lettura, sep);
while( token != NULL )
{
  byte length = strlen (token);
  byte idx = 0;
  bool bIsDigit = true;
  whil(bIsDigit && idx <lenght)
  {
   bIsDigit = isdigit(token[idx]);
   idx++;
  }
  if(bIsDigit)
  {
  }
  token = strtok(NULL, sep);
}

Ti porgo un altro quesito se posso: Stringa di trasmissione: 123,456,789,012,345 E se ricevessi per esempio 123,456,78as/&,012,345 Il problema sarebbe proprio quel 78as/& che lui vedrebbe (se non ho interpretato male il codice che hai postato) come 78 ma che in origine era 789. o peggio ancora 123,456,78/%èè2,345 in questo caso salta la virgola e confonde 2 valori (in questo caso il 3° con il 4°) diventando un 782. Penso che dovrei strutturare sì il tuo suggerimento, ma il tutto sotto array, in modo tale da saltare la lettura dell'intera stringa (diventando, di fatto, una stringa spazzatura poiché non attendibile) fino alla ricezione della nuova stringa. In questo caso solo se viene completata la lettura senza errori (o meglio senza caratteri non ammessi) il codice eseguirebbe le istruzioni con i dati ricevuti.

Quando di ha bisogno di sapere se ci sono stati errori di trasmissione, si prende il blocco, si calcola un CRC e si trasmette anche quello ... chi riceve, prende il blocco, ricalcola il CRC e, se non corrisponde con quello ricevuto comunica al mittente di ritrasmettere il blocco.

In pratica ... devi mettere in piedi un 'protocollo' con tanto di CRC/BCC di controllo finale.

Guglielmo

Concordo con gpb, chi ti garantisce che gli errori di trasmissione cambino sempre numeri in altri caratteri, e non numeri in altri numeri?

SukkoPera: Concordo con gpb, chi ti garantisce che gli errori di trasmissione cambino sempre numeri in altri caratteri, e non numeri in altri numeri?

Infatti mi era nato lo stesso dubbio... Ci sono esempi/librerie(/documentazione di qualsiasi tipo) inerenti al CRC in arduino?

C'è di meglio: http://www.nongnu.org/avr-libc/user-manual/group__util__crc.html

Aspetta.... questo postato da te gpb01 ?

miky_police: Aspetta.... questo postato da te gpb01 ?

Anche, li hai vari tipi di CRC (8, 16, 32) adatti a blocchi di dimensioni diversi e con sicurezza crescente.

Guglielmo

gpb01 scusami, ma non riesco a capire quale è più adatto al mio scopo. Dimensioni e sicurezza sono proporzionali/inversamente proporzionali o slegati da proporzionalità? Io fondamentalmente devo trasmettere 3 valori numerici. Penso che il CRC8 sia già sufficiente. Scaricando il file zip e includendolo ho notato che vi sono solo il CRC16 e CRC32. Il CRC8 è quello postato più avanti nel medesimo 3d? Questo è un CRC8 affidabile? Leggo a fondo pagina che nel tentativo di migliorarlo ha dovuto postare una versione più vecchia a causa (cito testualmente dal link citato)

calcolava CRC solo per vettori con elementi diversi da 0

.
Pertanto questo

//CRC-8 - algoritmo basato sulle formule di CRC-8 di Dallas/Maxim
//codice pubblicato sotto licenza GNU GPL 3.0
byte CRC8(const byte *data, byte len) {
  byte crc = 0x00;
  while (len--) {
    byte extract = *data++;
    for (byte tempI = 8; tempI; tempI--) {
      byte sum = (crc ^ extract) & 0x01;
      crc >>= 1;
      if (sum) {
        crc ^= 0x8C;
      }
      extract >>= 1;
    }
  }
  return crc;
}

è efficiente per il mio scopo?

Ops... scusa sukkopera :( non avevo notato del tutto il tuo reply... Adesso vedo meglio anche quella postata da te...!!!

Allora, ho fatto delle ricerche per quanto riguarda il CRC8 e su come possa implementarlo nel mio progetto… ammetto che ancora non mi è chiarissimo come funziona ma alla fine è come un checksum…
Il problema adesso è un altro. Ho scaricato FASTCRC e l’ho inclusa come libreria nell’ide, ho aperto l’esempio del CRC8 e l’ho caricato su arduino, ho aperto la seriale ed il risultato è 0xF4 ovvero 244 in DEC.
Fin qui tutto ok, ma siccome voglio confutare che questo dato sia corretto ho clonato l’esempio e ci ho aggiunto il CRC8 riportato dal mio post #9.
Risultato: io ottengo 0xF2 quindi 242…
Ho provato a cambiare la variabile utilizzata nel FastCRC in byte (anche se nel mio piccolo sapevo già che sarebbe stata la stessa cosa infatti il risultato non cambia).
A questo punto non potendo escludere la non attendibilità dell’uno piuttosto che l’altro (a causa dei miei limiti di conoscenza, o meglio ancora la correttezza di entrambi) chiedo a voi il perché (che ovviamente un perché ce l’avrà).
di seguito vi riporto l’esempio di fastCRC8 originale da libreria che restituisce 0xF4

/*
  FastCRC-Example

  (c) Frank Boesing 2014
*/

#include <FastCRC.h>

FastCRC8 CRC8;

uint8_t buf[9] = {'1', '2', '3', '4', '5', '6', '7', '8', '9'};

void setup() {

  delay(1500);
  Serial.begin(115200);

  Serial.println("CRC Example");
  Serial.println();

  Serial.print("SMBUS-CRC of \"");

  for (unsigned int i = 0; i < sizeof(buf); i++) {
    Serial.print((char) buf[i]);
  }

  Serial.print("\" is: 0x");
  Serial.println( CRC8.smbus(buf, sizeof(buf)), HEX );

}


void loop() {
}

e questa è la prova che io ho fatto (molto spartana) includendo il codice per calcolare il crc8, reperito da altra fonte e già postato da me in precedenza, con l’esempio di FastCRC per ottenere un riscontro in seriale…

/*
  FastCRC-Example

  (c) Frank Boesing 2014
*/

#include <FastCRC.h>

//CRC-8 - algoritmo basato sulle formule di CRC-8 di Dallas/Maxim
//codice pubblicato sotto licenza GNU GPL 3.0
byte CCRC8(const byte *data, byte len) {
  byte crc = 0x00;
  while (len--) {
    byte extract = *data++;
    for (byte tempI = 8; tempI; tempI--) {
      byte sum = (crc ^ extract) & 0x01;
      crc >>= 1;
      if (sum) {
        crc ^= 0x8C;
      }
      extract >>= 1;
    }
  }
  return crc;
}

FastCRC8 CRC8;

byte buf[9] = {'1', '2', '3', '4', '5', '6', '7', '8', '9'};

void setup() {

  delay(1500);
  Serial.begin(115200);

  Serial.println("CRC Example");
  Serial.println();

  Serial.print("SMBUS-CRC of \"");

  for (unsigned int i = 0; i < sizeof(buf); i++) {
    Serial.print((char) buf[i]);
  }

  Serial.print("\" is: 0x");
  Serial.println( CRC8.smbus(buf, sizeof(buf)), HEX );

  byte AA[9] = {1,2,3,4,5,6,7,8,9};
  byte myCRC = CCRC8(AA, 9);
  Serial.println(myCRC);

}


void loop() {
}

Quindi in ultimo, la domanda viene da se… quali dei 2 utilizzare per un calcolo corretto???
Aggiungo: a me non farebbe differenza utilizzare quello più idoneo, poiché ai fini del mio progetto trasmetterei un CRC con una tipologia di calcolo che sarebbe uguale a quella della ricevente per confrontarlo… quindi se calcolo in modo errato il crc per trasmetterlo, anche la ricevente farà il medesimo calcolo, pertanto (paradossalmente) i due CRC corrisponderebbero e quindi comunque è sinonimo della trasmissione completa di tutti i byte…

Ogni algoritmo di calcolo di un CRC usa dei "polinomi" ... diversi i "polinomi", diverso il risultato ...

Due algoritmi diversi, con polinomi diversi generano CRC differenti, ma entrambi esatti se ricontrollati con lo stesso algoritmo.

Scegline uno ed usa solo quello.

Guglielmo

Grazie Guglielmo

o meglio ancora la correttezza di entrambi

C.V.D.