Skip to content

Commit c2a73b1

Browse files
authored
Merge pull request #47 from sparkfun/Add_SPARTN
Add SPARTN and Septentrio SBF
2 parents d0f853d + b26b3f0 commit c2a73b1

File tree

17 files changed

+1848
-2
lines changed

17 files changed

+1848
-2
lines changed

README.md

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
SparkFun Extensible Message Parser
22
========================================
33

4-
The SparkFun Extensible Message Parser provides a base set of routines to construct serial stream parsers. On top of this are several GNSS protocol parsers for NMEA, RTCM, u-blox and Unicore. Some of SparkFun's RTK products use these parsers. Users may add protocol parse routines to enable the base routines to parse other protocols. Examples are provided for various parse configurations.
4+
The SparkFun Extensible Message Parser provides a base set of routines to construct serial stream parsers. On top of this are several GNSS protocol parsers for NMEA, RTCM, u-blox UBX, SPARTN, Septentrio SBF and Unicore. Some of SparkFun's RTK products use these parsers. Users may add protocol parse routines to enable the base routines to parse other protocols. Examples are provided for various parse configurations.
55

66
License Information
77
-------------------

examples/Mixed_Parser/Mixed_Parser.ino

+3
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,9 @@
11
/*
22
SparkFun mixed parser example sketch
33
4+
This example demonstrates how to create a mixed parser -
5+
here we parse u-blox UBX and NMEA using a single mixed parser
6+
47
License: MIT. Please see LICENSE.md for more details
58
*/
69

examples/Multiple_Parsers/Multiple_Parsers.ino

+3
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,9 @@
11
/*
22
SparkFun multiple parser example sketch
33
4+
This example demonstrates how to use multiple parsers -
5+
here two separate parsers parse u-blox UBX and NMEA
6+
47
License: MIT. Please see LICENSE.md for more details
58
*/
69

examples/NMEA_Test/NMEA_Test.ino

+2
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,8 @@
11
/*
22
SparkFun NMEA test example sketch
33
4+
This example demonstrates how to parse a NMEA data stream
5+
46
License: MIT. Please see LICENSE.md for more details
57
*/
68

examples/RTCM_Test/RTCM_Test.ino

+2
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,8 @@
11
/*
22
SparkFun RTCM test example sketch
33
4+
This example demonstrates how to parse a RTCM data stream
5+
46
License: MIT. Please see LICENSE.md for more details
57
*/
68

examples/SBF_Test/SBF_TEST.ino

+210
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,210 @@
1+
/*
2+
SparkFun SBF test example sketch
3+
4+
This example demonstrates how to parse a Septentrio SBF data stream
5+
6+
License: MIT. Please see LICENSE.md for more details
7+
*/
8+
9+
#include <SparkFun_Extensible_Message_Parser.h> //http://librarymanager/All#SparkFun_Extensible_Message_Parser
10+
11+
//----------------------------------------
12+
// Constants
13+
//----------------------------------------
14+
15+
// Build the table listing all of the parsers
16+
SEMP_PARSE_ROUTINE const parserTable[] =
17+
{
18+
sempSbfPreamble
19+
};
20+
const int parserCount = sizeof(parserTable) / sizeof(parserTable[0]);
21+
22+
const char * const parserNames[] =
23+
{
24+
"SBF parser"
25+
};
26+
const int parserNameCount = sizeof(parserNames) / sizeof(parserNames[0]);
27+
28+
// Provide some valid and invalid SBF messages
29+
const uint8_t rawDataStream[] =
30+
{
31+
// Invalid data - must skip over
32+
0, 1, 2, 3, 4, 5, 6, 7, // 0
33+
34+
// SBF Block 5914 (ReceiverTime)
35+
0x24, 0x40, 0x06, 0xFE, 0x1A, 0x17, 0x18, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x80, 0x80,
36+
0x80, 0x80, 0x80, 0x80, 0x12, 0x00, 0x00, 0x00,
37+
38+
// SBF Block 5914 (ReceiverTime) - invalid length
39+
0x24, 0x40, 0x06, 0xFE, 0x1A, 0x17, 0x17, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x80, 0x80,
40+
0x80, 0x80, 0x80, 0x80, 0x12, 0x00, 0x00, 0x00,
41+
42+
// SBF Block 5914 (ReceiverTime) - invalid CRC
43+
0x24, 0x40, 0x06, 0xFE, 0x1A, 0x17, 0x18, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x80, 0x80,
44+
0xFF, 0x80, 0x80, 0x80, 0x12, 0x00, 0x00, 0x00,
45+
46+
// Invalid data - must skip over
47+
0, 1, 2, 3, 4, 5, 6, 7, // 0
48+
49+
// SBF Block 4007 (PVTGeodetic)
50+
0x24, 0x40, 0xC4, 0x86, 0xA7, 0x4F, 0x60, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x01,
51+
0x00, 0x00, 0x00, 0x20, 0x5F, 0xA0, 0x12, 0xC2, 0x00, 0x00, 0x00, 0x20, 0x5F, 0xA0, 0x12, 0xC2,
52+
0x00, 0x00, 0x00, 0x20, 0x5F, 0xA0, 0x12, 0xC2, 0xF9, 0x02, 0x95, 0xD0, 0xF9, 0x02, 0x95, 0xD0,
53+
0xF9, 0x02, 0x95, 0xD0, 0xF9, 0x02, 0x95, 0xD0, 0xF9, 0x02, 0x95, 0xD0, 0x00, 0x00, 0x00, 0x20,
54+
0x5F, 0xA0, 0x12, 0xC2, 0xF9, 0x02, 0x95, 0xD0, 0xFF, 0xFF, 0xFF, 0x00, 0xFF, 0xFF, 0xFF, 0xFF,
55+
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0B, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00,
56+
57+
};
58+
59+
// Number of bytes in the rawDataStream
60+
#define RAW_DATA_BYTES (sizeof(rawDataStream) / sizeof(rawDataStream[0]))
61+
62+
// Account for the largest SBF messages
63+
#define BUFFER_LENGTH 2048
64+
65+
//----------------------------------------
66+
// Locals
67+
//----------------------------------------
68+
69+
uint32_t dataOffset;
70+
SEMP_PARSE_STATE *parse;
71+
72+
//----------------------------------------
73+
// Test routine
74+
//----------------------------------------
75+
76+
// Initialize the system
77+
void setup()
78+
{
79+
delay(1000);
80+
81+
Serial.begin(115200);
82+
Serial.println();
83+
Serial.println("SBF_Test example sketch");
84+
Serial.println();
85+
86+
// Initialize the parser
87+
parse = sempBeginParser(parserTable, parserCount,
88+
parserNames, parserNameCount,
89+
0, BUFFER_LENGTH, processMessage, "SBF_Test");
90+
if (!parse)
91+
reportFatalError("Failed to initialize the parser");
92+
93+
// Obtain a raw data stream from somewhere
94+
Serial.printf("Raw data stream: %d bytes\r\n", RAW_DATA_BYTES);
95+
96+
// The raw data stream is passed to the parser one byte at a time
97+
sempEnableDebugOutput(parse);
98+
for (dataOffset = 0; dataOffset < RAW_DATA_BYTES; dataOffset++)
99+
// Update the parser state based on the incoming byte
100+
sempParseNextByte(parse, rawDataStream[dataOffset]);
101+
102+
// Done parsing the data
103+
sempStopParser(&parse);
104+
}
105+
106+
// Main loop processing after system is initialized
107+
void loop()
108+
{
109+
// Nothing to do here...
110+
}
111+
112+
// Call back from within parser, for end of message
113+
// Process a complete message incoming from parser
114+
void processMessage(SEMP_PARSE_STATE *parse, uint16_t type)
115+
{
116+
SEMP_SCRATCH_PAD *scratchPad = (SEMP_SCRATCH_PAD *)parse->scratchPad;
117+
118+
uint32_t offset;
119+
120+
// Display the raw message
121+
Serial.println();
122+
offset = dataOffset + 1 - parse->length;
123+
Serial.printf("Valid SBF message block %d : %d bytes at 0x%08lx (%ld)\r\n",
124+
scratchPad->sbf.sbfID,
125+
parse->length, offset, offset);
126+
dumpBuffer(parse->buffer, parse->length);
127+
128+
// Display Block Number
129+
Serial.print("SBF Block Number: ");
130+
Serial.println(sempSbfGetBlockNumber(parse));
131+
132+
// If this is PVTGeodetic, extract some data
133+
if (sempSbfGetBlockNumber(parse) == 4007)
134+
{
135+
Serial.printf("TOW: %ld\r\n", sempSbfGetU4(parse, 8));
136+
Serial.printf("Mode: %d\r\n", sempSbfGetU1(parse, 14));
137+
Serial.printf("Error: %d\r\n", sempSbfGetU1(parse, 15));
138+
Serial.printf("Latitude: %.7g\r\n", sempSbfGetF8(parse, 16) * 180.0 / PI);
139+
Serial.printf("Longitude: %.7g\r\n", sempSbfGetF8(parse, 24) * 180.0 / PI);
140+
}
141+
142+
// Display the parser state
143+
static bool displayOnce = true;
144+
if (displayOnce)
145+
{
146+
displayOnce = false;
147+
Serial.println();
148+
sempPrintParserConfiguration(parse, &Serial);
149+
}
150+
}
151+
152+
// Display the contents of a buffer
153+
void dumpBuffer(const uint8_t *buffer, uint16_t length)
154+
{
155+
int bytes;
156+
const uint8_t *end;
157+
int index;
158+
uint32_t offset;
159+
160+
end = &buffer[length];
161+
offset = 0;
162+
while (buffer < end)
163+
{
164+
// Determine the number of bytes to display on the line
165+
bytes = end - buffer;
166+
if (bytes > (16 - (offset & 0xf)))
167+
bytes = 16 - (offset & 0xf);
168+
169+
// Display the offset
170+
Serial.printf("0x%08lx: ", offset);
171+
172+
// Skip leading bytes
173+
for (index = 0; index < (offset & 0xf); index++)
174+
Serial.printf(" ");
175+
176+
// Display the data bytes
177+
for (index = 0; index < bytes; index++)
178+
Serial.printf("%02x ", buffer[index]);
179+
180+
// Separate the data bytes from the ASCII
181+
for (; index < (16 - (offset & 0xf)); index++)
182+
Serial.printf(" ");
183+
Serial.printf(" ");
184+
185+
// Skip leading bytes
186+
for (index = 0; index < (offset & 0xf); index++)
187+
Serial.printf(" ");
188+
189+
// Display the ASCII values
190+
for (index = 0; index < bytes; index++)
191+
Serial.printf("%c", ((buffer[index] < ' ') || (buffer[index] >= 0x7f)) ? '.' : buffer[index]);
192+
Serial.printf("\r\n");
193+
194+
// Set the next line of data
195+
buffer += bytes;
196+
offset += bytes;
197+
}
198+
}
199+
200+
// Print the error message every 15 seconds
201+
void reportFatalError(const char *errorMsg)
202+
{
203+
while (1)
204+
{
205+
Serial.print("HALTED: ");
206+
Serial.print(errorMsg);
207+
Serial.println();
208+
sleep(15);
209+
}
210+
}

0 commit comments

Comments
 (0)