Skip to content

Commit b9cdcc1

Browse files
committed
NMEA: Don't return NMEA sentence early
1 parent b4bb8c3 commit b9cdcc1

File tree

4 files changed

+149
-57
lines changed

4 files changed

+149
-57
lines changed

Examples/Mixed_Parser/Mixed_Parser.ino

Lines changed: 19 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,10 @@
1010
// Constants
1111
//----------------------------------------
1212

13+
// Define the indexes into the parserTable array
14+
#define NMEA_PARSER_INDEX 0
15+
#define UBLOX_PARSER_INDEX 1
16+
1317
// Build the table listing all of the parsers
1418
SEMP_PARSE_ROUTINE const parserTable[] =
1519
{
@@ -144,6 +148,8 @@ const DataStream dataStream[] =
144148
// Locals
145149
//----------------------------------------
146150

151+
int byteOffset;
152+
int dataIndex;
147153
uint32_t dataOffset;
148154
SEMP_PARSE_STATE *parse;
149155

@@ -154,7 +160,6 @@ SEMP_PARSE_STATE *parse;
154160
// Initialize the system
155161
void setup()
156162
{
157-
int dataIndex;
158163
int rawDataBytes;
159164

160165
delay(1000);
@@ -181,10 +186,10 @@ void setup()
181186
sempEnableDebugOutput(parse);
182187
for (dataIndex = 0; dataIndex < DATA_STREAM_ENTRIES; dataIndex++)
183188
{
184-
for (int offset = 0; offset < dataStream[dataIndex].length; offset++)
189+
for (byteOffset = 0; byteOffset < dataStream[dataIndex].length; byteOffset++)
185190
{
186191
// Update the parser state based on the incoming byte
187-
sempParseNextByte(parse, dataStream[dataIndex].data[offset]);
192+
sempParseNextByte(parse, dataStream[dataIndex].data[byteOffset]);
188193
dataOffset += 1;
189194
}
190195
}
@@ -204,19 +209,27 @@ void processMessage(SEMP_PARSE_STATE *parse, uint16_t type)
204209
{
205210
SEMP_SCRATCH_PAD *scratchPad = (SEMP_SCRATCH_PAD *)parse->scratchPad;
206211
static bool displayOnce = true;
212+
uint32_t byteIndex;
207213
uint32_t offset;
208214

209215
// Display the raw message
210216
Serial.println();
211217
switch (type) // Index into parserTable array
212218
{
213-
case 0:
214-
offset = dataOffset + 1 + 2 - parse->length;
219+
case NMEA_PARSER_INDEX:
220+
// Determine the raw data stream offset
221+
offset = dataOffset + 2 - parse->length;
222+
byteIndex = byteOffset + 2 - parse->length;
223+
while (dataStream[dataIndex].data[byteIndex] != '$')
224+
{
225+
offset -= 1;
226+
byteIndex -= 1;
227+
}
215228
Serial.printf("Valid NMEA Sentence: %s, %d bytes at 0x%08x (%d)\r\n",
216229
scratchPad->nmea.sentenceName, parse->length, offset, offset);
217230
break;
218231

219-
case 1:
232+
case UBLOX_PARSER_INDEX:
220233
offset = dataOffset + 1 - parse->length;
221234
Serial.printf("Valid u-blox message: %d bytes at 0x%08x (%d)\r\n",
222235
parse->length, offset, offset);

Examples/Multiple_Parsers/Multiple_Parsers.ino

Lines changed: 15 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -153,6 +153,8 @@ const int ubloxParserNameCount = sizeof(ubloxParserNames) / sizeof(ubloxParserNa
153153
// Locals
154154
//----------------------------------------
155155

156+
int byteOffset;
157+
int dataIndex;
156158
uint32_t dataOffset;
157159
SEMP_PARSE_STATE *nmeaParser;
158160
SEMP_PARSE_STATE *ubloxParser;
@@ -164,7 +166,6 @@ SEMP_PARSE_STATE *ubloxParser;
164166
// Initialize the system
165167
void setup()
166168
{
167-
int dataIndex;
168169
int rawDataBytes;
169170

170171
delay(1000);
@@ -197,11 +198,11 @@ void setup()
197198
sempEnableDebugOutput(ubloxParser);
198199
for (dataIndex = 0; dataIndex < DATA_STREAM_ENTRIES; dataIndex++)
199200
{
200-
for (int offset = 0; offset < dataStream[dataIndex].length; offset++)
201+
for (byteOffset = 0; byteOffset < dataStream[dataIndex].length; byteOffset++)
201202
{
202203
// Update the parser state based on the incoming byte
203-
sempParseNextByte(nmeaParser, dataStream[dataIndex].data[offset]);
204-
sempParseNextByte(ubloxParser, dataStream[dataIndex].data[offset]);
204+
sempParseNextByte(nmeaParser, dataStream[dataIndex].data[byteOffset]);
205+
sempParseNextByte(ubloxParser, dataStream[dataIndex].data[byteOffset]);
205206
dataOffset += 1;
206207
}
207208
}
@@ -223,12 +224,21 @@ void loop()
223224
void nmeaSentence(SEMP_PARSE_STATE *parse, uint16_t type)
224225
{
225226
SEMP_SCRATCH_PAD *scratchPad = (SEMP_SCRATCH_PAD *)parse->scratchPad;
227+
uint32_t byteIndex;
226228
static bool displayOnce = true;
227229
uint32_t offset;
228230

231+
// Determine the raw data stream offset
232+
offset = dataOffset + 2 - parse->length;
233+
byteIndex = byteOffset + 2 - parse->length;
234+
while (dataStream[dataIndex].data[byteIndex] != '$')
235+
{
236+
offset -= 1;
237+
byteIndex -= 1;
238+
}
239+
229240
// Display the raw sentence
230241
Serial.println();
231-
offset = dataOffset + 1 + 2 - parse->length;
232242
Serial.printf("Valid NMEA Sentence: %s, %d bytes at 0x%08x (%d)\r\n",
233243
scratchPad->nmea.sentenceName, parse->length, offset, offset);
234244
dumpBuffer(parse->buffer, parse->length);

Examples/NMEA_Test/NMEA_Test.ino

Lines changed: 8 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -54,10 +54,10 @@ const uint8_t rawDataStream[] =
5454
// Invalid character in the sentence name
5555
"$G@RMC,210230,A,3855.4487,N,09446.0071,W,0.0,076.2,130495,003.8,E*69\r\n" // 631
5656
"$G[RMC,210230,A,3855.4487,N,09446.0071,W,0.0,076.2,130495,003.8,E*69\r\n" // 701
57-
"$GaRMC,210230,A,3855.4487,N,09446.0071,W,0.0,076.2,130495,003.8,E*69\r\n" // 771
58-
"$GzRMC,210230,A,3855.4487,N,09446.0071,W,0.0,076.2,130495,003.8,E*69\r\n" // 841
5957

6058
// Bad checksum
59+
"$GaRMC,210230,A,3855.4487,N,09446.0071,W,0.0,076.2,130495,003.8,E*69\r\n" // 771
60+
"$GzRMC,210230,A,3855.4487,N,09446.0071,W,0.0,076.2,130495,003.8,E*69\r\n" // 841
6161
"$GPRMC,210230,A,3855.4487,N,09446.0071,W,0.0,076.2,130495,003.8,E*68\r\n" // 911
6262

6363
// Sentence too long by a single byte
@@ -126,10 +126,14 @@ void processMessage(SEMP_PARSE_STATE *parse, uint16_t type)
126126
static bool displayOnce = true;
127127
uint32_t offset;
128128

129+
// Determine the raw data stream offset
130+
offset = dataOffset + 1 + 2 - parse->length;
131+
while (rawDataStream[offset] != '$')
132+
offset -= 1;
133+
129134
// Display the raw message
130135
Serial.println();
131-
offset = dataOffset + 1 + 2 - parse->length;
132-
Serial.printf("Valid NMEA Sentence: %s, %d bytes at 0x%08x (%d)\r\n",
136+
Serial.printf("Valid NMEA Sentence: %s, %d bytes at 0x%08x (%d)\r\n",
133137
scratchPad->nmea.sentenceName, parse->length, offset, offset);
134138
dumpBuffer(parse->buffer, parse->length);
135139

src/Parse_NMEA.cpp

Lines changed: 107 additions & 42 deletions
Original file line numberDiff line numberDiff line change
@@ -39,75 +39,136 @@ License: MIT. Please see LICENSE.md for more details
3939
// |<-------- Checksum -------->|
4040
//
4141

42-
// Read the line termination
43-
bool sempNmeaLineTermination(SEMP_PARSE_STATE *parse, uint8_t data)
42+
// Validate the checksum
43+
void sempNmeaValidateChecksum(SEMP_PARSE_STATE *parse)
4444
{
4545
int checksum;
46+
SEMP_SCRATCH_PAD *scratchPad = (SEMP_SCRATCH_PAD *)parse->scratchPad;
4647

47-
// Process the line termination
48-
if ((data == '\r') || (data == '\n'))
48+
// Convert the checksum characters into binary
49+
checksum = sempAsciiToNibble(parse->buffer[parse->length - 2]) << 4;
50+
checksum |= sempAsciiToNibble(parse->buffer[parse->length - 1]);
51+
52+
// Validate the checksum
53+
if ((checksum == parse->crc) || (parse->badCrc && (!parse->badCrc(parse))))
54+
{
55+
// Always add the carriage return and line feed
56+
parse->buffer[parse->length++] = '\r';
57+
parse->buffer[parse->length++] = '\n';
58+
59+
// Zero terminate the NMEA sentence, don't count this in the length
60+
parse->buffer[parse->length] = 0;
61+
62+
// Process this NMEA sentence
63+
parse->eomCallback(parse, parse->type); // Pass parser array index
64+
}
65+
else
66+
// Display the checksum error
67+
sempPrintf(parse->printDebug,
68+
"SEMP: %s NMEA %s, 0x%04x (%d) bytes, bad checksum, "
69+
"received 0x%c%c, computed: 0x%02x",
70+
parse->parserName,
71+
scratchPad->nmea.sentenceName,
72+
parse->length, parse->length,
73+
parse->buffer[parse->length - 2],
74+
parse->buffer[parse->length - 1],
75+
parse->crc);
76+
}
77+
78+
// Read the linefeed
79+
bool sempNmeaLineFeed(SEMP_PARSE_STATE *parse, uint8_t data)
80+
{
81+
int checksum;
82+
83+
// Don't add the current character to the length
84+
parse->length -= 1;
85+
86+
// Process the LF
87+
if (data == '\n')
88+
{
89+
// Pass the sentence to the upper layer
90+
sempNmeaValidateChecksum(parse);
91+
92+
// Start searching for a preamble byte
93+
parse->state = sempFirstByte;
4994
return true;
95+
}
96+
97+
// Pass the sentence to the upper layer
98+
sempNmeaValidateChecksum(parse);
5099

51100
// Start searching for a preamble byte
52101
return sempFirstByte(parse, data);
53102
}
54103

55-
// Read the second checksum byte
56-
bool sempNmeaChecksumByte2(SEMP_PARSE_STATE *parse, uint8_t data)
104+
// Read the remaining carriage return
105+
bool sempNmeaCarriageReturn(SEMP_PARSE_STATE *parse, uint8_t data)
57106
{
58-
int checksum;
59-
SEMP_SCRATCH_PAD *scratchPad = (SEMP_SCRATCH_PAD *)parse->scratchPad;
107+
// Don't add the current character to the length
108+
parse->length -= 1;
60109

61-
// Convert the checksum characters into binary
62-
checksum = sempAsciiToNibble(parse->buffer[parse->length - 1]);
63-
checksum |= sempAsciiToNibble(parse->buffer[parse->length - 2]) << 4;
64-
65-
// Validate the checksum character
66-
if (checksum < 0)
110+
// Process the CR
111+
if (data == '\r')
67112
{
68-
// Invalid checksum character
69-
sempPrintf(parse->printDebug,
70-
"SEMP %s: NMEA invalid second checksum character",
71-
parse->parserName);
113+
// Pass the sentence to the upper layer
114+
sempNmeaValidateChecksum(parse);
72115

73116
// Start searching for a preamble byte
74-
return sempFirstByte(parse, data);
117+
parse->state = sempFirstByte;
118+
return true;
75119
}
76120

77-
// Add CR and LF to the sentence
78-
parse->buffer[parse->length++] = '\r';
79-
parse->buffer[parse->length++] = '\n';
121+
// Pass the sentence to the upper layer
122+
sempNmeaValidateChecksum(parse);
80123

81-
// Zero terminate the string, don't count this in the length
82-
parse->buffer[parse->length] = 0;
124+
// Start searching for a preamble byte
125+
return sempFirstByte(parse, data);
126+
}
83127

84-
// Validate the checksum
85-
if ((checksum == parse->crc)
86-
|| (parse->badCrc && (!parse->badCrc(parse))))
128+
// Read the line termination
129+
bool sempNmeaLineTermination(SEMP_PARSE_STATE *parse, uint8_t data)
130+
{
131+
int checksum;
132+
133+
// Don't add the current character to the length
134+
parse->length -= 1;
135+
136+
// Process the line termination
137+
if (data == '\r')
87138
{
88-
// Process this NMEA sentence
89-
parse->eomCallback(parse, parse->type); // Pass parser array index
139+
parse->state = sempNmeaLineFeed;
140+
return true;
141+
}
142+
else if (data == '\n')
143+
{
144+
parse->state = sempNmeaCarriageReturn;
145+
return true;
146+
}
147+
148+
// Pass the sentence to the upper layer
149+
sempNmeaValidateChecksum(parse);
150+
151+
// Start searching for a preamble byte
152+
return sempFirstByte(parse, data);
153+
}
90154

91-
// Remove any CR or LF that follow
155+
// Read the second checksum byte
156+
bool sempNmeaChecksumByte2(SEMP_PARSE_STATE *parse, uint8_t data)
157+
{
158+
// Validate the checksum character
159+
if (sempAsciiToNibble(parse->buffer[parse->length - 1]) >= 0)
160+
{
92161
parse->state = sempNmeaLineTermination;
93-
parse->length = 0;
94162
return true;
95163
}
96164

97-
// Display the checksum error
165+
// Invalid checksum character
98166
sempPrintf(parse->printDebug,
99-
"SEMP: %s NMEA %s, %2d bytes, bad checksum, "
100-
"received 0x%c%c, computed: 0x%02x",
101-
parse->parserName,
102-
scratchPad->nmea.sentenceName,
103-
parse->length,
104-
parse->buffer[parse->length - 4],
105-
parse->buffer[parse->length - 3],
106-
parse->crc);
167+
"SEMP %s: NMEA invalid second checksum character",
168+
parse->parserName);
107169

108170
// Start searching for a preamble byte
109-
parse->state = sempFirstByte;
110-
return false;
171+
return sempFirstByte(parse, data);
111172
}
112173

113174
// Read the first checksum byte
@@ -231,6 +292,10 @@ const char * sempNmeaGetStateName(const SEMP_PARSE_STATE *parse)
231292
return "sempNmeaChecksumByte2";
232293
if (parse->state == sempNmeaLineTermination)
233294
return "sempNmeaLineTermination";
295+
if (parse->state == sempNmeaCarriageReturn)
296+
return "sempNmeaCarriageReturn";
297+
if (parse->state == sempNmeaLineFeed)
298+
return "sempNmeaLineFeed";
234299
if (parse->state == sempNmeaHashPreamble)
235300
return "sempNmeaHashPreamble";
236301
return nullptr;

0 commit comments

Comments
 (0)