Hallo,
Ik heb een mobilofoon die ik met een arduino wil besturen.
Daarvoor heb ik een UART poort ter beschikking.
Data wordt verstuurd met de HRNP standaard.
Bij iedere array bytes hoort een checksum.
Deze staat op positie 10 en 11 in de array.
Maar ik kom er niet uit hoe ik deze checksum in een arduino moet berekenen.
In de manual staat de volgende omschrijving:
“Checksum” filed indicates the checking code of data and HRNP header,
it occupies 2 bytes. If this value is 0, means that this message does not need to check.
The algorithm of checksum is as same as UDP/IP, this checksum is the 16 bits one’s
complement of the one’s complement sum of all 16 bits words in the header and data.
Er zijn ook een aantal voorbeelden:
- 7E 03 00 00 20 10 00 01 00 13 5B A6 02 C6 00 00 00 6C 03
De checksum bytes zijn 5B A6
- 7E 03 00 00 20 10 00 02 00 19 58 A3 02 03 00 06 00 00 02 0B 02 00 00 1A 03
De checksum bytes zijn 58 A3
Kan iemand mij op weg helpen hoe ik van een array bytes als bovenstaand de checksum kan berekenen?
Peter.
tel alle woorden(16 bits) bij elkaar op, als het groter is dan FFFF dan de carry (ofwel de overflow erbij optellen alsof het ook een 16 bits woord is.
de uitkomst inverteren, ofwel overal waar een 1 staat een 0 maken en overal waar een 0 staat een 1 maken, dat kan bijv. met XOR FFFF
en dat is dan je uitkomst.
Bedankt voor de hulp shooter.
Je hulp was erg verhelderend.
Dit is wat nu werkt voor mij:
unsigned long calc_checksum (byte* in, int len) {
unsigned long tot=0;
for (int i=0; i<len; i+=2) {
tot += (in[i]<<8) + (in[i+1]);
if (tot >= 0xFFFF) tot -= 0xFFFF;
}
tot = tot ^ 0xFFFF;
return tot;
}
bijna goed, je vergeet de carry (dus alles hoger dan FFFF) die moet je apart opslaan en er als laatste bijtellen (1 keer maar dus als daar carry ontstaat dan niet nog een keer.
jij gebruikt een long hiervoor dus gewoon alles wat groter is een AND met FFFF0000 doen die opschuiven naar LSB (>>16) en dan erbij tellen.
die IF heb je helemaal niet nodig.
Heb je een link naar de "HRNP standaard."
Bevatten berichten altijd een even aantal bytes?
Een extra 16 bit pointer maakt het optellen simpler.
unsigned int calc_checksum (byte* in, int len)
{
unsigned long crc = 0;
uint16_t *p = (uint16_t*) in;
for (int idx=0 ; idx < len; idx += 2) crc += p[idx];
crc = (( (crc & 0xFFFF0000) >> 16) + crc) & 0xFFFF;
return crc ^ 0xFFFF;
}
Heb helaas geen link.
Het aantal bytes is afhankelijk van de payload.
De code die jij stuurt Rob geeft weer hele andere waarden, daarmee krijg ik de voorbeelden niet werkend.
Maar het laatste stukje van je code verwerkt de carry wel goed.
Dus alles bij elkaar kom ik dan op onderstaande.
Dit alles kan ongetwijfeld nog een stuk strakker geschreven worden maar daar heb ik niet zoveel ervaring mee.
unsigned int calc_checksum (byte* in, int len) {
unsigned long crc=0;
unsigned int a = 0;
byte b = 0;
for (int i=0; i<len; i+=2) {
a=0; b=0;
a = in[i]<<8;
if (i+1 < len) b = in[i+1];
crc += a + b;
}
crc = (( (crc & 0xFFFF0000) >> 16) + crc) & 0xFFFF;
crc = crc ^ 0xFFFF;
return crc;
}
Volgens mij heb ik zo een juiste checksum.
Dank voor jullie hulp.