@@ -405,3 +405,180 @@ byte readLine(char* buffer, byte bufferLength, int numberOfSeconds)
405405
406406 return readLength;
407407}
408+
409+ // Verify the NMEA checksum byte
410+ bool invalidChecksumByte (uint8_t data, uint32_t checksum)
411+ {
412+ // Convert the data into a binary value
413+ if ((data >= ' A' ) && (data <= ' F' ))
414+ data -= ' A' - 10 ;
415+ else if ((data >= ' a' ) && (data <= ' f' ))
416+ data -= ' a' - 10 ;
417+ else if ((data >= ' 0' ) && (data <= ' 9' ))
418+ data -= ' 0' ;
419+
420+ // Compare with the lower 4 bits of the checksum
421+ return ((checksum & 0xf ) != data);
422+ }
423+
424+ // Parse the NMEA and RTCM messages
425+ bool parseNmeaAndRtcmMessages (PARSE_STATE * parse, uint8_t data, bool sendMessage)
426+ {
427+ // NMEA
428+ //
429+ // |<--------------- Checksum --------------->|
430+ // | |
431+ // +----------+----------+-- *** --+----------+----------+----------+----------+
432+ // | Preamble | Message | | Asterisk | Checksum | Carriage | Linefeed |
433+ // | 8 bits | Name | | | 2 Hex | | |
434+ // | $ | G..... | | * | Bytes | 0x0d | 0x0a |
435+ // +----------+----------+-- ***---+----------+----------+----------+----------+
436+ //
437+ // RTCM Standard 10403.2 - Chapter 4, Transport Layer
438+ //
439+ // |<------------- 3 bytes ------------>|<----- length ----->|<- 3 bytes ->|
440+ // | | | |
441+ // +----------+--------+----------------+---------+----------+-------------+
442+ // | Preamble | Fill | Message Length | Message | Fill | CRC-24Q |
443+ // | 8 bits | 6 bits | 10 bits | n-bits | 0-7 bits | 24 bits |
444+ // | 0xd3 | 000000 | (in bytes) | | zeros | |
445+ // +----------+--------+----------------+---------+----------+-------------+
446+ // | |
447+ // |<-------------------------------- CRC -------------------------------->|
448+ //
449+
450+ switch (parse->state )
451+ {
452+ // Wait for the preamble byte (0xd3)
453+ case PARSE_STATE_WAIT_FOR_PREAMBLE:
454+ parse->sendMessage = false ;
455+ if (data == 0xd3 )
456+ {
457+ parse->sendMessage = sendMessage;
458+ parse->state = PARSE_STATE_RTCM_READ_LENGTH_1;
459+ }
460+ else if (data == ' $' )
461+ {
462+ parse->crc = 0 ;
463+ parse->length = 1 ;
464+ parse->nameLength = 0 ;
465+ parse->sendMessage = sendMessage;
466+ parse->state = PARSE_STATE_NMEA_FIND_COMMA;
467+ }
468+ else if ((data != ' \r ' ) && (data != ' \n ' ))
469+ {
470+ parse->invalidByte = true ;
471+ parse->invalidCharacters ++;
472+ }
473+ break ;
474+
475+ // Read the upper two bits of the length
476+ case PARSE_STATE_RTCM_READ_LENGTH_1:
477+ parse->length = data << 8 ;
478+ parse->state = PARSE_STATE_RTCM_READ_LENGTH_2;
479+ break ;
480+
481+ // Read the lower 8 bits of the length
482+ case PARSE_STATE_RTCM_READ_LENGTH_2:
483+ parse->length |= data;
484+ parse->bytesRemaining = parse->length ;
485+ parse->state = PARSE_STATE_RTCM_READ_MESSAGE_1;
486+ break ;
487+
488+ // Read the upper 8 bits of the message number
489+ case PARSE_STATE_RTCM_READ_MESSAGE_1:
490+ parse->message = data << 4 ;
491+ parse->bytesRemaining -= 1 ;
492+ parse->state = PARSE_STATE_RTCM_READ_MESSAGE_2;
493+ break ;
494+
495+ // Read the lower 4 bits of the message number
496+ case PARSE_STATE_RTCM_READ_MESSAGE_2:
497+ parse->message |= data >> 4 ;
498+ parse->bytesRemaining -= 1 ;
499+ parse->state = PARSE_STATE_RTCM_READ_DATA;
500+ break ;
501+
502+ // Read the rest of the message
503+ case PARSE_STATE_RTCM_READ_DATA:
504+ parse->bytesRemaining -= 1 ;
505+ if (parse->bytesRemaining <= 0 )
506+ parse->state = PARSE_STATE_RTCM_READ_CRC_1;
507+ break ;
508+
509+ // Read the upper 8 bits of the CRC
510+ case PARSE_STATE_RTCM_READ_CRC_1:
511+ parse->crcByte [0 ] = data;
512+ parse->state = PARSE_STATE_RTCM_READ_CRC_2;
513+ break ;
514+
515+ // Read the middle 8 bits of the CRC
516+ case PARSE_STATE_RTCM_READ_CRC_2:
517+ parse->crcByte [1 ] = data;
518+ parse->state = PARSE_STATE_RTCM_READ_CRC_3;
519+ break ;
520+
521+ // Read the lower 8 bits of the CRC
522+ case PARSE_STATE_RTCM_READ_CRC_3:
523+ parse->crcByte [2 ] = data;
524+ parse->rtcmCrc = parse->crc ;
525+ parse->rtcmPackets ++;
526+ parse->messageNumber = parse->message ;
527+ parse->printMessageNumber = true ;
528+ parse->state = PARSE_STATE_WAIT_FOR_PREAMBLE;
529+ break ;
530+
531+ // Check for the end of the message name
532+ case PARSE_STATE_NMEA_FIND_COMMA:
533+ parse->length ++;
534+ parse->crc ^= data;
535+ if (data == ' ,' )
536+ {
537+ parse->name [parse->nameLength ++] = 0 ;
538+ parse->state = PARSE_STATE_NMEA_FIND_ASTERISK;
539+ }
540+ else
541+ {
542+ if (parse->nameLength < (sizeof (parse->name ) - 1 ))
543+ parse->name [parse->nameLength ++] = data;
544+ }
545+ break ;
546+
547+ // Check for the end of the NMEA message
548+ case PARSE_STATE_NMEA_FIND_ASTERISK:
549+ parse->length ++;
550+ if (data == ' *' )
551+ {
552+ parse->nmeaChecksum = (byte)parse->crc ;
553+ parse->state = PARSE_STATE_NMEA_VERIFY_CHECKSUM_1;
554+ }
555+ else
556+ parse->crc ^= data;
557+ break ;
558+
559+ // Read the ASCII hex character representing the upper 4-bits of the checksum
560+ case PARSE_STATE_NMEA_VERIFY_CHECKSUM_1:
561+ parse->length ++;
562+ parse->checksumByte1 = data;
563+ parse->state = PARSE_STATE_NMEA_VERIFY_CHECKSUM_2;
564+ break ;
565+
566+ // Read the ASCII hex character representing the lower 4-bits of the checksum
567+ case PARSE_STATE_NMEA_VERIFY_CHECKSUM_2:
568+ parse->length ++;
569+ parse->checksumByte2 = data;
570+ if (invalidChecksumByte (parse->checksumByte1 , parse->crc >> 4 )
571+ || invalidChecksumByte (data, parse->crc ))
572+ {
573+ parse->invalidNmeaChecksum = true ;
574+ parse->invalidNmeaChecksums ++;
575+ }
576+ parse->state = PARSE_STATE_WAIT_FOR_PREAMBLE;
577+ parse->printMessageName = true ;
578+ strcpy (parse->messageName , parse->name );
579+ break ;
580+ }
581+
582+ // Let the upper layer know if this message should be sent
583+ return parse->sendMessage && sendMessage;
584+ }
0 commit comments