UM982 GPS Modul CRC32 Prüfsumme immer falsch

Hallo Leutz, ich ärger mich seit Tagen mit der Validierung der CRC32 Prüfsumme von der GPS Zeichenkette aus dem UM982 GPS Modul herum.

char _buffer[600];
uint16_t _buffer_pos = 0;
char _buffer_crc[9];
uint8_t _buffer_crc_pos = 0;
bool writeCRC = false;
static const uint32_t CRC32_POLYNOMIAL = 0xEDB88320;


void setup() {
  Serial3.begin(115200);
  Serial.begin(9600);
}


uint32_t crc32Value(uint32_t crc) {
  for (int i = 8; i > 0; i--) {
    if (crc & 1) {
      crc = (crc >> 1) ^ CRC32_POLYNOMIAL;

    } else {
      crc >>= 1;
    }
  }

  return crc;
}

uint32_t calculateCRC32(uint32_t length, uint8_t *buffer, uint32_t crc) {
  while (length-- != 0) {
    crc = ((crc >> 8) & 0x00FFFFFFL) ^ (crc32Value(((uint32_t)crc ^ *buffer++) & 0xff));
  }

  return crc;
}


bool crcCorrect() {
  const uint32_t crc_calculated = calculateCRC32(_buffer_pos, (uint8_t *)_buffer, 0);
  const uint32_t crc_parsed = (uint32_t)strtoul(_buffer_crc, nullptr, 16);
  return (crc_calculated == crc_parsed);
}

void printCRC(bool _b) {
  if (_b) {
    Serial.println("CRC korrekt");
  } else {
    Serial.println("CRC nicht korrekt");
  }
}

void loop() {
  if (Serial.available() > 0) {
    String receivedString = Serial.readString();
    Serial.print("Received: ");
    Serial.println(receivedString);
    Serial3.write(receivedString.c_str());
  }

  if (Serial3.available()) {
    char c = Serial3.read();
    switch (c) {
      case '#':
      case '$':
        {
          writeCRC = false;
          _buffer_pos = 0;
          _buffer_crc_pos = 0;
          _buffer[_buffer_pos++] = c;
        }
        break;
      case '*':
        {
          _buffer[_buffer_pos] = '\0';
          writeCRC = true;
        }
        break;
      case '\r':
      case '\n':
        {
          _buffer_crc[_buffer_crc_pos] = '\0';
          if (!crcCorrect()) {
            return printCRC(false);
          } else {
            return printCRC(true);
          }
        }
      default:
        {
          if (writeCRC) {
            _buffer_crc[_buffer_crc_pos++] = c;
            if (_buffer_crc_pos >= 8) {
              _buffer_crc[_buffer_crc_pos] = '\0';
              if (!crcCorrect()) {
                return printCRC(false);
              } else {
                return printCRC(true);
              }
            }
          } else {
            _buffer[_buffer_pos++] = c;
          }
        }
    }
  }
}

Ich bin erst davon ausgegangen, dass eventuell meine Serielle Verbindung bereits Fehlerhaft ist. Aber im Reverenz Manual gibt es eine Beispiel Zeichenkette und diese funktioniert auch nicht.
Also muss es am Algorithmus liegen.

Ich hatte schon mal ärger mit einer Prüfsummen Berechnung, da lag es am ende an der Bitreihenfolge. Die Bitreihenfolge sollte aber in diesem Fall trivial sein.

Ich hoffe das hier jemand Ahnung hat.

Asso, ich bin auf einem Teensy 4.1 zu Gange, also ein IMXRT1062 Mikrocontroller.

MfG FlatBed

Hallo FlatBed

Nimm eine Suchmaschine deiner Wahl und befrage das WWW nach "NMEA Checksum".

Das wäre ja zu einfach. Habe ich schon 100 mal gemacht.
auch der Quellcode von TinyGPs++ beringt mir nichts.

NMEA Zeichenketten beginnen mit einem $ und haben eine 8 Bit Prüfsumme.
Die Agra Daten sind beim UM982 Speziell aufgrund der Zeichenkettenlänge.

ChatGPT findet übrigens auch keine Offensichtlichen Fehler.

Na, dann ist ja alles im grünen Bereich.

Tolle Wurst. Zähler für nicht Konstruktive Antworten = 1

Das Problem war, das ich das Startzeichen $ bzw # mit in die Zeichenkette eingefügt hatte.

Das war mir die ganze Zeit entgangen.

Bei DeppGPT hatte ich noch mit String als Objekt gearbeitet.
und nach dem * alles mit subStr getrennt.

Jetzt werden zumindest die Agra (AGRCA) Daten validiert.
AGRICB und NMEA wird nicht erkannt. das soll ja "nur" ein XOR über alle Zeichen sein.

Das implementiere ich Später.

Ich bin nun genau so weit wie heute Vormittag.
Die 8Bit CRC Überprüfung funktioniert nicht:

#define CRC32_POLYNOMIAL 0xEDB88320L

char _buffer[600];
uint16_t _buffer_pos = 0;
char _buffer_crc[9];
uint8_t _buffer_crc_pos = 0;
bool writeCRC = false;
uint8_t parity;

void setup() {
  Serial3.begin(115200);
  Serial.begin(9600);
}

int fromHex(char a) {
  if (a >= 'A' && a <= 'F')
    return a - 'A' + 10;
  else if (a >= 'a' && a <= 'f')
    return a - 'a' + 10;
  else
    return a - '0';
}


uint32_t crc32Value(uint32_t crc) {
  for (int i = 8; i > 0; i--) {
    if (crc & 1) {
      crc = (crc >> 1) ^ CRC32_POLYNOMIAL;

    } else {
      crc >>= 1;
    }
  }

  return crc;
}

uint32_t calculateCRC32(uint32_t length, uint8_t *buffer, uint32_t crc) {
  while (length-- != 0) {
    crc = ((crc >> 8) & 0x00FFFFFFL) ^ (crc32Value(((uint32_t)crc ^ *buffer++) & 0xff));
  }
  return crc;
}

bool crcCorrect() {
  if (_buffer_crc_pos > 3) {
    const uint32_t crc_calculated = calculateCRC32(_buffer_pos, (uint8_t *)_buffer, 0);
    const uint32_t crc_parsed = (uint32_t)strtoul(_buffer_crc, nullptr, 16);
    return (crc_calculated == crc_parsed);
  } else {
    byte checksum = 16 * fromHex(_buffer_crc[0]) + fromHex(_buffer_crc[1]);
    Serial.print("checksum: ");
    Serial.println(checksum);
    Serial.print("parity: ");
    Serial.println(parity);
    return checksum == parity;
  }
}

void printCRC(bool _b) {
  if (_b) {
    Serial.println("CRC korrekt");
  } else {
    Serial.println("CRC nicht korrekt");
  }
}

void loop() {
  if (Serial.available() > 0) {
    String receivedString = Serial.readString();
    Serial.print("command: ");
    Serial.println(receivedString);
    Serial3.write(receivedString.c_str());
  }

  if (Serial3.available()) {
    char c = Serial3.read();
    switch (c) {
      case '#':
      case '$':
        {
          writeCRC = false;
          _buffer_pos = 0;
          _buffer_crc_pos = 0;
          parity = 0;
        }
        break;
      case '*':
        {
          _buffer[_buffer_pos] = '\0';
          writeCRC = true;
        }
        break;
      case '\r':
      case '\n':
        {
          _buffer_crc[_buffer_crc_pos] = '\0';
          if (!crcCorrect()) {
            return printCRC(false);
          } else {
            return printCRC(true);
          }
        }
      default:
        {
          if (writeCRC) {
            _buffer_crc[_buffer_crc_pos++] = c;
          } else {
            _buffer[_buffer_pos++] = c;
            if (c == ',') {
              parity ^= (uint8_t)c;
            } else {
              parity ^= c;
            }
          }
        }
    }
  }
}

gibt es irgendwo ein example dazu, dass man mal sieht, wie die Daten aussehen und was dann raus kommen soll?

Ja, es gibt hier ein umfangreichen Foreneintrag:

Gleich im ersten Beitrag findet man alle Datenblätter.
Ich vermute ein Problem mit der endianness.

1 Like

Keiner einer Idee?

Ich werde mal ein Neo-6m Modul an den Teensy anschließen und gucken was dann passiert.
Sollte das auch nicht funktionieren Probeire ich noch die TinyGPS++ Bibliothek aus.

Ich hatte schon mal ein Problem mit der Berechnung von einer CRC Prüfsumme.
Allerdings bei der Modualtion vom BOS Funk (FFSK Modulation).
Das ist aber wider eine andere Abstraktionsebene.

Es gibt eine neue Erkenntnis. Mit einem NEO 6M Modul funktioniert der Algorithmus auch auf dem Teensy 4.

Es liegt also am UM982. Da kann ja nur die Bytereihenfolge vertauscht sein.

ich habe das Problem gefunden.
Der Witz ist, es gab keines.

Das ist eine Verarsche von Unicore.
Wenn ich den config Befehl eingebe, muss man bei der Antwort das $ Zeichen mit in die Prüfsumme einbeziehen.
Bei den unlog befehl (oder bei einer Fehlermeldung), z.b Wiederum nicht.

Reguläre NMEA Daten z.B GPGGAH gingen die ganz Zeit oder KSXT.
Ich habe es nur nie Eingegeben, weil keiner davon ausgeht das der config Befehl anders behandelt werden muss.

Hier noch mal der ganze Salat:

#define CRC32_POLYNOMIAL 0xEDB88320L

char _buffer[600];
uint16_t _buffer_pos = 0;
char _buffer_crc[9];
uint8_t _buffer_crc_pos = 0;
bool writeCRC = false;
uint8_t parity;
uint8_t parity_unicore;

void setup() {
  Serial3.begin(115200);
  Serial.begin(9600);
}


uint32_t crc32Value(uint32_t crc) {
  for (int i = 8; i > 0; i--) {
    if (crc & 1) {
      crc = (crc >> 1) ^ CRC32_POLYNOMIAL;

    } else {
      crc >>= 1;
    }
  }

  return crc;
}

uint32_t calculateCRC32(uint32_t length, uint8_t *buffer, uint32_t crc) {
  while (length-- != 0) {
    crc = ((crc >> 8) & 0x00FFFFFFL) ^ (crc32Value(((uint32_t)crc ^ *buffer++) & 0xff));
  }
  return crc;
}

bool crcCorrect() {
  const uint32_t crc_parsed = (uint32_t)strtoul(_buffer_crc, nullptr, 16);

  if (_buffer_crc_pos > 3) {  //32Bit CRC
    const uint32_t crc_calculated = calculateCRC32(_buffer_pos, (uint8_t *)_buffer, 0);
    return (crc_calculated == crc_parsed);
  }

  bool crc_valid = crc_parsed == parity_unicore;//prüfe auf unicore "config"
  if (crc_valid) {//wenn gut return true
    return true;
  } else {//anderweitig teste regulären Datensatz z.b KSXT oder "unlog"
    return crc_parsed == parity;
  }
  return false; // unerreicht 
}

void printCRC(bool _b) {
  if (_b) {
    Serial.println("CRC korrekt");
  } else {
    Serial.println("CRC nicht korrekt");
  }
}

void loop() {
  if (Serial.available() > 0) {
    String receivedString = Serial.readString();
    Serial.print("command: ");
    Serial.println(receivedString);
    Serial3.write(receivedString.c_str());
  }

  if (Serial3.available()) {
    char c = Serial3.read();
    switch (c) {
      case '#':
      case '$':
        {
          writeCRC = false;
          _buffer_pos = 0;
          _buffer_crc_pos = 0;
          parity = 0;
          parity_unicore = 0;
          parity_unicore ^= c;
        }
        break;
      case '*':
        {
          _buffer[_buffer_pos] = '\0';
          writeCRC = true;
        }
        break;
      case '\r':
      case '\n':
        {
          _buffer_crc[_buffer_crc_pos] = '\0';
          if (!crcCorrect()) {
            return printCRC(false);
          } else {
            return printCRC(true);
          }
        }
      default:
        {
          if (writeCRC) {
            _buffer_crc[_buffer_crc_pos++] = c;
          } else {
            _buffer[_buffer_pos++] = c;
            if (c == ',') {
              parity ^= (uint8_t)c;
              parity_unicore ^= (uint8_t)c;
            } else {
              parity ^= c;
              parity_unicore ^= c;
            }
          }
        }
    }
  }
}

This topic was automatically closed 180 days after the last reply. New replies are no longer allowed.