Carattere di controllo stringa

Salve. Come sapete per chi non è abituato pensare è sconsigliato.e io caddi in tentazione.
Avrei bisogno di fare una sorta di controllo su una stringa, per intenderci come mandare una stringa via seriale, aggiungere un carattere di controllo. Alla ricezione verificare che corrisponda.
Simile a un crc direte voi,
Quasi, dico io. Perché vorrei che sia un carattere, possibilmente sulla tastiera, ma sicuramente non un barrazero, visto che lavoro con stringhe (di C, barrazero terminate) la presenza di un barrazero mi fermerebbe.
Suggerimenti?

Non sono sicuro di aver capito quello che ti serve...
Comunque in altri linguaggi, quando mi serve un terminatore o separatore per stringe di solito uso \t (tab) che in ascii dovrebbe essere il 9. Che però difficilmente puoi digitare da tastiera... o forse no, dipende dall'ambiente...
In alternativa uso un carattere "poco usato" nella normale prassi... tipo il ~ (ascii 126)

Aspetta, la notte ha portato consiglio...
Se ti serve un carattere di controllo ma vuoi che risulti sempre un carattere "stampabile" puoi usare il sistema del codice fiscale. 3 tabelle di conversione, 4 calcoli e sei apposto.

Se i caratteri, invece che uno, possono essere due, allora la cosa è semplice ... calcoli un normale CRC8 ed il byte che viene fuori, lo rappresenti con DUE caratteri ASCII che possono andare da 0x30 a 0x39 ('0' .. '9') e da 0x41 a 0x46 ('A' .. 'F') :wink:

Guglielmo

Stavo per dare la stessa soluzione di Guglielmo che come sempre mi ha preceduto:-)
Praticamente calcoli un checksum (più che un CRC direi, per semplicità) di un byte (mascheri sempre 0xFF) dei caratteri che compongono la stringa, poi questo checksum lo codifichi in esadecimale con 2 caratteri. Ovviamente poi devi sapere dove si trova il checksum, ad esempio a fine stringa (il che implica anche la presenza di un terminatore o separatore, come un CR '\r' ad esempio ma vediamo un problema alla volta).

Una cosa di questo tipo:

void setup() {
  Serial.begin(9600);
  char linea[] = "ABC";
  Serial.print(linea);
  Serial.println(getChecksum(linea), HEX);
}

byte getChecksum(char *msg) {
  byte chk = 0;
  for (int i=0; i<strlen(msg); ++i) {
    chk = (chk + msg[i])&0xFF;
  }
  return chk;
}

void loop() { 
  
}

I caratteri "ABC" hanno codici ASCII 65, 66 e 67, per cui 65+66+67=198 che in esadecimale è 0xC6 per cui l'ouput sarà "ABCC6". nel ricevente prenderai l'intera riga di testo (visto che col println termina con un '\r') e separando gli ultimi 2 caratteri li riconverti da hex in byte, e confronti questo valore con quello ottenuto ricalcolando il getChecksum() sui precedenti caratteri.

Spero ti possa essere utile questa "imbeccata".

Grazie a tutti , molto gentili. Stasera spero di trovare il tempo di proseguire
Credo che userò la soluzione di docdoc, ma ho un dubbio
Perché un and bitwise su 8 uno?
È come se non ci fosse? O sbaglio?

Standardoil:
Perché un and bitwise su 8 uno? È come se non ci fosse? O sbaglio?

Perché la somma "chk + msg*" potrebbe superare 255, e tu vuoi limitare il checksum ad un solo byte.*
Quindi ad esempio se avessi chk=190 e msg*=90 il totale farebbe 280, che non puoi mettere in un byte.*
Ma 280 in binario è 100011000 quindi 9 bit, per cui facendo un AND con maschera 0xFF avrei 100011000 & 11111111 = 00011000 ossia 24 (o 0x18) che è sempre 1 byte.

Allora mi sono perso. Credevo che bastasse usare una variabile byte. Boh, stasera provo
PS grazie

Concordo con Standardoil ... se la variabile è di UN byte (e chk è dichiarata byte) NON potrà MAI superare il valore di 255, dopo di che tornerà a 0 e zero e il 9 bit andrà perso quindi ... quel AND con 0xFF non serve assolutamnete a nulla.

Diverso il caso se si fosse usato un 'int' o un tipo più capiente ...

Guglielmo

Per inciso, se si vuole usare un algoritmo un po' più serio di quel giochino (in cui basta molto poco per fregarlo), in AVR libc si sono già pronte funzioni per il CRC16 ed il CRC8 ... si può benissimo usare quella per il CRC8 ed ottenere un qualche cosa di decisamente più sicuro. :wink:

Guglielmo

Essendo un checksum non preciso, quindi con totale condizionato a non superare 255, si potrebbe condizionare il totale e portarlo tra 33 e 126, che in tabella ascii sono tutti caratteri presenti su tastiera (da ! fino a ~ ). chk=map(chk,0,255,33,126);
Logicamente un chksum non preciso.

Oh, calmini...
Lasciate qualcosa da inventare anche me

Che sarebbe uno scherzo, ma non trovo mai le faccine

Fermo restando che secondo me il modo migliore per rappresentare in formato ASCII un campo di checksum di 8 bit è la forma esadecimale già consigliata 00..FF, considera che la somma (come pure lo xor) soffre dalla proprietà commutativa, cioè le stringhe casa acas saac ecc danno tutte lo stesso identico checksum.

Il CRC è il metodo più sicuro (anche se non infallibile) per rilevare un errore, ma anche una via di mezzo più semplice, formata da somma più rotazione, è sempre molto meglio di qualsiasi semplice somma/sottrazione/xor/parità ecc, perché almeno la proprietà commutativa viene gabbata (non sono importanti solo i caratteri ma anche la loro posizione).

>Claudio_FF: ... mi ricordi i bei tempi (1980) in cui andavo in giro a fare "analisi di protocolli" con ... questo:


:smiley: :smiley: :smiley:

Guglielmo

P.S.: Atlantic Research Corporation - Interview 3600

Claudio_FF:
..ma anche una via di mezzo più semplice, formata da somma più rotazione, ...

@claudio, cosa intendi per rotazione ? dei bit ?

vabbeh, basta.
chiudo i giochi altrimenti mi fate vergognare
ho pensato che per i miei limitati scopi una cosa del genere va benssimo

char caratteredicontrollo(char messaggio[])
{
    // restituisce il carattere di controllo per il messaggio in ingresso
    int appoggio = 0;
    byte index = 0;

    while (messaggio[index])
    {
        appoggio = index + appoggio + messaggio[index++];
    }

    return (char)(appoggio % 93) + 33;
}

ho pensato:
spazio numerico di 93, ecco la ragione del modulo 93
una somma continua, che sta in un int, (sono pochi caratteri), con in piu' INDEX, per togliere la prorpietà commutativa
Per claudio_ff, lo avevo già pensato prima del tuo post, ma grazie comunque, non sapevo come chiamarla
un aumento di 33 per partire con un carattere di tastiera,
cast(r)ato a char,
non posso provare adesso, mi manca tutto il resto del progetto, ma credo che possa andare
i miei scopi sono limitati, come ho detto, e siccome devo provare da tastiera, non posso usare caratteri strani o codici ascii non corrispondenti a tasti, altrettanto devo essere sicuro che non venga mai restituito un ottetto di zeri (\0), che sarebbbero un fine stringa e mi abortirebbero altre parti del progetto
vi basti sapere che finora la funzione si limitava a restituire sempre X maisucolo, tanto fino a seriale HW su usb non serve un vero controllo errori
in futuro magari elimino il constrain a 93
va da se che vi ringrazio tutti, dentro qui ci sono tutti i vostri spunti, gli errori invece sono tutti miei

Standardoil:
con in piu' INDEX, per togliere la prorpietà commutativa

L'idea è interessante ma mi sembra che non la tolga, diciamo che nel computo totale in qualche modo viene inserita anche la lunghezza della stringa, che è un vantaggio rispetto alla semplice somma nel caso in cui le stringhe abbiano lunghezze molto diverse.

nid69ita:
cosa intendi per rotazione ? dei bit ?

Si, qualcosa del genere (dove chk è una variabile a 8 bit):
chk = n + (chk<<1 | chk>>7);ma anche:

chk = n ^ (chk<<1 | chk>>7);

gpb01:
Interview 3600

Io invece me ne ricordo il peso :smiley:

ragione tieni, quindi non mi serve aggiungere index, vabbe' le stringhe sono tutte uguali come lunghezza, posso toglierla dal definitivo
stay tuned, il progetto prosegue

gpb01:
Concordo con Standardoil ... se la variabile è di UN byte (e chk è dichiarata byte) NON potrà MAI superare il valore di 255, dopo di che tornerà a 0 e zero e il 9 bit andrà perso quindi ... quel AND con 0xFF non serve assolutamnete a nulla.

Si verissimo, ma io per "pulizia" della logica tendo sempre a forzare i miei cast e non delegare implicitamente al linguaggio, per sapere sempre cosa sto facendo e perché... :wink:

Confermo, stay Tuned, spero con poche ore di lavoro, leggasi due tre serate di hobby, di arrivare ad avere qualcosa di mostrabile