Ottimizzazione codice

Ciao ragazzi mi servirebbe una mano per un'ottimizzazione del codice.
Visto che non sono molto bravo con stringhe, array e conversioni varie chiedo a voi per imparare.

Il codice che metto sotto è molto semplice nella logica, in pratica riceve via seriale dei dati nel seguente formato dato#crc16 (base 10)& e deve vedere se il dato è arrivato corretto. Come vedete dal codice io mi sono ricostruito la stringa in arrivo e poi ho spezzettato il tutto ma non so se è il modo migliore di operare pensando all'occupazione di memoria e alle performance, perchè a funzionare funziona.

Ecco il codice:

#include <SoftwareSerial.h>
#include <stdlib.h>
#include "crc16.h"

unsigned int myCrc16;

SoftwareSerial mySerial(2, 3); // RX, TX

String str ="";
String crcToCheck="";
String datoToCheck="";
byte checkStart;
byte checkEnd;
void setup()  
{
  // Open serial communications and wait for port to open:
  Serial.begin(57600);
  while (!Serial) {
    ; // wait for serial port to connect. Needed for Leonardo only
  }

  Serial.println("Goodnight moon!");
  mySerial.begin(57600);
}

void loop() // run over and over
{
  if (mySerial.available()){
    char c = mySerial.read();

    str = str + c;
    if ( c == '&'){
      //controllo crc
      Serial.println("Dato in arrivo: " + str);
      checkStart=str.indexOf('#');
      checkEnd=str.indexOf('&');
      crcToCheck = str.substring(checkStart+1, checkEnd);
      datoToCheck = str.substring(0, checkStart);
      Serial.println("crcToCheck " + crcToCheck);
      char buf[1];
      datoToCheck.toCharArray(buf, sizeof(datoToCheck));
      Serial.print("Dato da controllare: ");
      Serial.println(buf);
      myCrc16 = calc_crc16(buf, sizeof(buf));
      Serial.print("Crc calcolato da rx: ");
      Serial.println(myCrc16, 10);
      str = "";
      byte crcToCheckArraySize = crcToCheck.length() + 1;
      char crcToCheckArray[crcToCheckArraySize];
      crcToCheck.toCharArray(crcToCheckArray, crcToCheckArraySize);
      if ( myCrc16 == atol(crcToCheckArray) )
        Serial.println("OK");
      else
        Serial.println("ko");
    }
  }
}

Grazie

Ma il dato è lungo solo 1 carattere? Vedo infatti che dimensioni un array di char di 1 byte:

char buf[1];

Non capisco...

Inoltre attenzione a "giocare" con gli String. Non metti nessun controllo sulla dimensione massima, puoi in teoria saturare tutta la memoria.

Bè io via seriale mando un carattere per volta.
Se nel serial monitor metto la stringa "ciao" questa verrà inviata come:

c#crc&
i#crc&
a#crc&
o#crc&

quindi il dato da controllare è di 1 byte.

leo72:
Inoltre attenzione a "giocare" con gli String. Non metti nessun controllo sulla dimensione massima, puoi in teoria saturare tutta la memoria.

per questo chiedo a voi ]:smiley:

Ma fare il CRC di 1 solo carattere ogni volta mi sembra una cosa inutile.
Se vuoi essere sicuro della trasmissione, spedisci 2 volte lo stesso carattere: se il primo è diverso dal secondo, la trasmissione è arrivata corrotta. NOn c'è bisogno di un CRC :wink:

Riscriverei il codice in modo da ricomporre il testo spedito (ossia ricevere tutti i byte del messaggio) e poi calcolare il CRC su di esso.

:wink: Ok chiaro.

leo72:
Ma fare il CRC di 1 solo carattere ogni volta mi sembra una cosa inutile.

Assolutamente si, per giunta usa il CRC16, ovvero deve spedire 3 byte con un solo byte di payload, un overhead del 200% :slight_smile:
l'uso del crc ha senso solo se quando parliamo di array dati di una certa lunghezza e quando serve un ottimo livello di affidabilità delle trasmissioni-
Normalmente un banale checksum, 8 o 16 bit, è più che sufficiente per verificare l'integrità dei dati in buona parte delle applicazioni di uso comune, non andiamo a complicarci la vita quando è inutile :slight_smile:

Vabè era anche per giocare non aveva nessuno scopo finale.
Ma in linea generale è fatto bene quel codice o si pò evitare l'uso di qualche funzione/conversione?

Il metodo che dovresti usare è quello di strutturare la trasmissione : un blocco di caratteri di lunghezza fissa (il pacchetto del messaggio) + il CRC.

In questo modo ottimizzi il tutto e eviti di dover usare un carattere separatore (# nel tuo caso) che, in una normale trasmissione di bytes, potrebbe capitare nel corpo del messaggio.

In pratica, ogni "pacchetto" dovrebbe essere fatto come : XXXXXXX.........XXXXXXXCC dove le XXXXX sono un numero FISSO di caratteri (es. ogni pacchetto deve trasferire 64 bytes SEMPRE) seguito da 2 byte di CRC.

Guglielmo

Secondo me se eviti le String è meglio.

Hai dei punti del codice un pò "pericolosi":
esempio: datoToCheck.toCharArray(buf, sizeof(datoToCheck));
Tu il buf lo dichiari di 1, alla funzione passi sizeof() di datotocheck, ovvero la dimensione dell'oggetto. Se anche la sizeof ritornasse quanti caratteri formano la stringa, comunque passi un valore >1. La funzione toCharArray usa il 2° parametro per sapere quanto è grande il buf, per evitare di andare a scrivere "oltre" alla sua dimensione.

La classe String usa internamente malloc e realloc, perciò ogni volta che fai str = str + c; esegue di sotto 1kg di codice.

Secondo me se usi direttamente vettori di caratteri a cui dai una dimensione adeguata (sai in partenza a quanto dimensionarli) e poi usi le varie funzioni sui vettori di stringa (strlen, strncpy, strstr, etc.), velocizzi.

Logicamente le String semplificano il codice ma non lo ottimizzano di certo.

Concordo con nid69ita ... evita le String per le trasmissioni dati e, come ti dicevo, vai con dei semplici char[] di cui fissi a priori le dimensioni :wink:

Guglielmo

Ottimo, questo non lo sapevo ma venendo da Java è comprensibile...
Al più presto applicherò i consigli

Grazie

gpb01:
Concordo con nid69ita ... evita le String per le trasmissioni dati e, come ti dicevo, vai con dei semplici char[] di cui fissi a priori le dimensioni :wink:

Assolutamente si, anzi ancora meglio evitare sempre come la peste le string, e più in generale il C++, quando si lavora con piccole mcu 8 bit con limitatissime risorse, ANSI C forever :slight_smile:

astrobeed:
........ ANSI C forever :slight_smile:

Con me sfondi una porta aperta ... come dicevo qualche tempo fa ... ricordi LabWindows for DOS e LabWindows/CVI for Win di National Instruments ? XD

Guglielmo