/** * \brief Find tail of packet ("\r\n") in buffer and check control sum (CRC). * @param buff a constant character pointer of packets buffer. * @param buff_sz buffer size. * @param res_crc a integer pointer for return CRC of packet (must be defined). * @return Number of bytes to packet tail. */ int nmea_find_tail(const char *buff, int buff_sz, int *res_crc) { static const int tail_sz = 3 /* *[CRC] */ + 2 /* \r\n */; const char *end_buff = buff + buff_sz; // EDIT: the end_buff can be a char instead a pointer to the last location of buffer int nread = 0; int crc = 0; NMEA_ASSERT(buff && res_crc); *res_crc = -1; for(;buff < end_buff; ++buff, ++nread) { if(('$' == *buff) && nread) { buff = 0; break; } else if('*' == *buff) { if(buff + tail_sz <= end_buff && '\r' == buff[3] && '\n' == buff[4]) { *res_crc = nmea_atoi(buff + 1, 2, 16); nread = buff_sz - (int)(end_buff - (buff + tail_sz)); if(*res_crc != crc) { *res_crc = -1; buff = 0; } } break; } else if(nread) crc ^= (int)*buff; } if(*res_crc < 0 && buff) nread = 0; return nread; }
/** * Find the tail ("\r\n") of a sentence in a string and check the checksum of the sentence. * * @param s the string * @param len the length of the string * @param checksum a pointer to the location where the checksum (as specified * in the sentence) should be stored (will be -1 if the checksum did not match * the calculated checksum or a new sentence was found in s after the start of s) * @return Number of bytes from the start of the string until the tail or 0 * when no sentence was found */ int nmea_parse_get_sentence_length(const char *s, const int len, int *checksum) { static const int tail_sz = 1 + 2 + 2 /* *xx\r\n */; const char * s_end = s + len; int nread = 0; int cksum = 0; assert(s); assert(checksum); *checksum = -1; for (; s < s_end; s++, nread++) { if ((*s == '$') && nread) { /* found a new sentence start marker _after_ the first character of s */ s = NULL; /* do not reset nread when exiting */ break; } if ('*' == *s) { /* found a sentence checksum marker */ if (((s + tail_sz) <= s_end) && ('\r' == s[3]) && ('\n' == s[4])) { *checksum = nmea_atoi(s + 1, 2, 16); nread = len - (int) (s_end - (s + tail_sz)); if (*checksum != cksum) { *checksum = -1; s = NULL; /* do not reset nread when exiting */ } } break; } if (nread) { cksum ^= (int) *s; } } if (s && (*checksum < 0)) nread = 0; return nread; }
static bool nmea_parse_sentence_character(nmeaPARSER *parser, const char * c) { assert(parser); /* always reset when we encounter a start-of-sentence character */ if (*c == '$') { reset_sentence_parser(parser, READ_SENTENCE); parser->buffer.buffer[parser->buffer.length++] = *c; return false; } /* just return when we haven't encountered a start-of-sentence character yet */ if (parser->sentence_parser.state == SKIP_UNTIL_START) { return false; } /* this character belongs to the sentence */ /* check whether the sentence still fits in the buffer */ if (parser->buffer.length >= SENTENCE_SIZE) { reset_sentence_parser(parser, SKIP_UNTIL_START); return false; } parser->buffer.buffer[parser->buffer.length++] = *c; switch (parser->sentence_parser.state) { case READ_SENTENCE: if (*c == '*') { parser->sentence_parser.state = READ_CHECKSUM; parser->sentence_parser.sentence_checksum_chars_count = 0; } else if (*c == first_eol_char) { parser->sentence_parser.state = READ_EOL; parser->sentence_parser.sentence_eol_chars_count = 1; } else if (isInvalidNMEACharacter(c)) { reset_sentence_parser(parser, SKIP_UNTIL_START); } else { parser->sentence_parser.calculated_checksum ^= (int) *c; } break; case READ_CHECKSUM: if (!isHexChar(*c)) { reset_sentence_parser(parser, SKIP_UNTIL_START); } else { switch (parser->sentence_parser.sentence_checksum_chars_count) { case 0: parser->sentence_parser.sentence_checksum_chars[0] = *c; parser->sentence_parser.sentence_checksum_chars[1] = 0; parser->sentence_parser.sentence_checksum_chars_count = 1; break; case 1: parser->sentence_parser.sentence_checksum_chars[1] = *c; parser->sentence_parser.sentence_checksum_chars_count = 2; parser->sentence_parser.sentence_checksum = nmea_atoi(parser->sentence_parser.sentence_checksum_chars, 2, 16); parser->sentence_parser.has_checksum = true; parser->sentence_parser.state = READ_EOL; break; default: reset_sentence_parser(parser, SKIP_UNTIL_START); break; } } break; case READ_EOL: switch (parser->sentence_parser.sentence_eol_chars_count) { case 0: if (*c != first_eol_char) { reset_sentence_parser(parser, SKIP_UNTIL_START); } else { parser->sentence_parser.sentence_eol_chars_count = 1; } break; case 1: if (*c != second_eol_char) { reset_sentence_parser(parser, SKIP_UNTIL_START); } else { parser->sentence_parser.state = SKIP_UNTIL_START; return (!parser->sentence_parser.sentence_checksum_chars_count || (parser->sentence_parser.sentence_checksum_chars_count && (parser->sentence_parser.sentence_checksum == parser->sentence_parser.calculated_checksum))); } break; default: reset_sentence_parser(parser, SKIP_UNTIL_START); break; } break; /* can't occur, but keep compiler happy */ case SKIP_UNTIL_START: default: break; } return false; }