Merge lp:~thomas-voss/location-service/add-ubx-provider into lp:location-service

Proposed by Thomas Voß
Status: Merged
Approved by: Thomas Voß
Approved revision: 278
Merged at revision: 275
Proposed branch: lp:~thomas-voss/location-service/add-ubx-provider
Merge into: lp:location-service
Diff against target: 2864 lines (+2611/-12)
39 files modified
CMakeLists.txt (+0/-5)
snapcraft.yaml (+12/-7)
src/location/providers/CMakeLists.txt (+1/-0)
src/location/providers/config.cpp (+7/-0)
src/location/providers/ubx/CMakeLists.txt (+18/-0)
src/location/providers/ubx/_8/marshaller.h (+42/-0)
src/location/providers/ubx/_8/message.h (+56/-0)
src/location/providers/ubx/_8/nmea/cardinal_direction.h (+43/-0)
src/location/providers/ubx/_8/nmea/date.h (+43/-0)
src/location/providers/ubx/_8/nmea/fusion_adapt.h (+134/-0)
src/location/providers/ubx/_8/nmea/generator.h (+254/-0)
src/location/providers/ubx/_8/nmea/gga.h (+69/-0)
src/location/providers/ubx/_8/nmea/gll.h (+56/-0)
src/location/providers/ubx/_8/nmea/gps/fix_mode.h (+50/-0)
src/location/providers/ubx/_8/nmea/grammar.h (+251/-0)
src/location/providers/ubx/_8/nmea/gsa.h (+84/-0)
src/location/providers/ubx/_8/nmea/gsv.h (+66/-0)
src/location/providers/ubx/_8/nmea/latitude.h (+42/-0)
src/location/providers/ubx/_8/nmea/longitude.h (+42/-0)
src/location/providers/ubx/_8/nmea/mode.h (+44/-0)
src/location/providers/ubx/_8/nmea/rmc.h (+68/-0)
src/location/providers/ubx/_8/nmea/scanner.cpp (+65/-0)
src/location/providers/ubx/_8/nmea/scanner.h (+67/-0)
src/location/providers/ubx/_8/nmea/sentence.cpp (+81/-0)
src/location/providers/ubx/_8/nmea/sentence.h (+56/-0)
src/location/providers/ubx/_8/nmea/status.h (+40/-0)
src/location/providers/ubx/_8/nmea/talker.h (+41/-0)
src/location/providers/ubx/_8/nmea/txt.h (+55/-0)
src/location/providers/ubx/_8/nmea/utc.h (+43/-0)
src/location/providers/ubx/_8/nmea/vtg.h (+53/-0)
src/location/providers/ubx/_8/receiver.cpp (+23/-0)
src/location/providers/ubx/_8/receiver.h (+81/-0)
src/location/providers/ubx/_8/replaying_receiver.cpp (+32/-0)
src/location/providers/ubx/_8/scanner.h (+146/-0)
src/location/providers/ubx/_8/serial_port_receiver.cpp (+44/-0)
src/location/providers/ubx/_8/serial_port_receiver.h (+72/-0)
src/location/providers/ubx/dop.h (+60/-0)
src/location/providers/ubx/provider.cpp (+160/-0)
src/location/providers/ubx/provider.h (+110/-0)
To merge this branch: bzr merge lp:~thomas-voss/location-service/add-ubx-provider
Reviewer Review Type Date Requested Status
Thomas Voß Approve
Scott Sweeny (community) code Needs Information
Review via email: mp+308026@code.launchpad.net

Commit message

Add ubx provider implementation.

Description of the change

Add ubx provider implementation.

To post a comment you must log in.
276. By Thomas Voß

Adjust plug/slot naming.

277. By Thomas Voß

Add commands locationd.list and locationd.provide.

278. By Thomas Voß

Fix command name.

Revision history for this message
Scott Sweeny (ssweeny) wrote :

Overall the code LGTM.

Could you clarify why you removed the LGPL test and explain a bit about the new commands?

Thanks.

review: Needs Information (code)
Revision history for this message
Thomas Voß (thomas-voss) wrote :

top-approving and merging to enable a package build.

review: Approve

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1=== modified file 'CMakeLists.txt'
2--- CMakeLists.txt 2016-08-26 13:11:26 +0000
3+++ CMakeLists.txt 2016-10-11 08:54:12 +0000
4@@ -132,9 +132,4 @@
5 add_subdirectory(src)
6 add_subdirectory(tests)
7
8-# There's no nice way to format this. Thanks CMake.
9-add_test(LGPL-required
10- /bin/sh -c "! grep -rl 'GNU General' ${PROJECT_SOURCE_DIR}/src ${PROJECT_SOURCE_DIR}/include"
11-)
12-
13 enable_coverage_report(service)
14
15=== removed directory 'build'
16=== removed directory 'build/src'
17=== modified file 'snapcraft.yaml'
18--- snapcraft.yaml 2016-08-30 11:04:45 +0000
19+++ snapcraft.yaml 2016-10-11 08:54:12 +0000
20@@ -14,24 +14,29 @@
21 run:
22 daemon: simple
23 command: bin/locationd run --bus=system
24- slots: [control, observe]
25+ slots: [service-control, service-observe]
26 plugs: [network-manager]
27+ list-providers:
28+ command: bin/locationd list
29 status:
30 command: bin/locationd status --bus=system
31- plugs: [control]
32+ plugs: [client-observe]
33 monitor:
34 command: bin/locationd monitor --bus=system
35- plugs: [observe]
36+ plugs: [client-control]
37+ provide:
38+ command: bin/locationd provider --bus=system
39+ plugs: [client-control]
40
41 slots:
42- observe:
43+ service-observe:
44 interface: location-observe
45- control:
46+ service-control:
47 interface: location-control
48 plugs:
49- observe:
50+ client-observe:
51 interface: location-observe
52- control:
53+ client-control:
54 interface: location-control
55
56 parts:
57
58=== modified file 'src/location/providers/CMakeLists.txt'
59--- src/location/providers/CMakeLists.txt 2016-08-14 19:36:05 +0000
60+++ src/location/providers/CMakeLists.txt 2016-10-11 08:54:12 +0000
61@@ -3,6 +3,7 @@
62 add_subdirectory(mls)
63 add_subdirectory(remote)
64 add_subdirectory(gps)
65+add_subdirectory(ubx)
66
67 set(
68 ENABLED_PROVIDER_TARGETS
69
70=== modified file 'src/location/providers/config.cpp'
71--- src/location/providers/config.cpp 2016-08-14 19:36:05 +0000
72+++ src/location/providers/config.cpp 2016-10-11 08:54:12 +0000
73@@ -20,6 +20,7 @@
74
75 #include "dummy/provider.h"
76 #include "mls/provider.h"
77+#include "ubx/provider.h"
78
79 #include <map>
80
81@@ -46,6 +47,12 @@
82 location::providers::mls::Provider::create_instance
83 };
84
85+static FactoryInjector ubx_injector
86+{
87+ "ubx::Provider",
88+ location::providers::ubx::Provider::create_instance
89+};
90+
91 #if defined(LOCATION_PROVIDERS_GPS)
92 #include <location/providers/gps/provider.h>
93 static FactoryInjector gps_injector
94
95=== added directory 'src/location/providers/ubx'
96=== added file 'src/location/providers/ubx/CMakeLists.txt'
97--- src/location/providers/ubx/CMakeLists.txt 1970-01-01 00:00:00 +0000
98+++ src/location/providers/ubx/CMakeLists.txt 2016-10-11 08:54:12 +0000
99@@ -0,0 +1,18 @@
100+file(GLOB_RECURSE UBX_HEADERS*.h)
101+
102+add_library(
103+ ubx
104+
105+ ${UBX_HEADERS}
106+
107+ _8/receiver.cpp
108+ _8/serial_port_receiver.cpp
109+ _8/nmea/scanner.cpp
110+ _8/nmea/sentence.cpp
111+
112+ provider.h provider.cpp)
113+
114+set(
115+ ENABLED_PROVIDER_TARGETS
116+ ${ENABLED_PROVIDER_TARGETS} ubx
117+ PARENT_SCOPE)
118
119=== added directory 'src/location/providers/ubx/_8'
120=== added file 'src/location/providers/ubx/_8/marshaller.h'
121--- src/location/providers/ubx/_8/marshaller.h 1970-01-01 00:00:00 +0000
122+++ src/location/providers/ubx/_8/marshaller.h 2016-10-11 08:54:12 +0000
123@@ -0,0 +1,42 @@
124+// Copyright (C) 2016 Thomas Voss <thomas.voss.bochum@gmail.com>
125+//
126+// This library is free software: you can redistribute it and/or modify
127+// it under the terms of the GNU Lesser General Public License as published
128+// by the Free Software Foundation, either version 3 of the License, or
129+// (at your option) any later version.
130+//
131+// This program is distributed in the hope that it will be useful,
132+// but WITHOUT ANY WARRANTY; without even the implied warranty of
133+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
134+// GNU General Public License for more details.
135+//
136+// You should have received a copy of the GNU Lesser General Public License
137+// along with this program. If not, see <http://www.gnu.org/licenses/>.
138+#ifndef UBX_8_MARSHALLER_H_
139+#define UBX_8_MARSHALLER_H_
140+
141+namespace location
142+{
143+namespace providers
144+{
145+namespace ubx
146+{
147+namespace _8
148+{
149+/// @brief Marshaller abstracts marshaling of arbitrary messages.
150+class Marshaller
151+{
152+public:
153+ virtual ~Marshaller() = default;
154+
155+ /// @brief marshal returns a message
156+ /// ready to be sent over the wire to a ublox
157+ /// receiver.
158+ virtual Message marshal() const = 0;
159+};
160+}
161+}
162+}
163+}
164+
165+#endif // UBX_8_MARSHALLER_H_
166
167=== added file 'src/location/providers/ubx/_8/message.h'
168--- src/location/providers/ubx/_8/message.h 1970-01-01 00:00:00 +0000
169+++ src/location/providers/ubx/_8/message.h 2016-10-11 08:54:12 +0000
170@@ -0,0 +1,56 @@
171+// Copyright (C) 2016 Thomas Voss <thomas.voss.bochum@gmail.com>
172+//
173+// This library is free software: you can redistribute it and/or modify
174+// it under the terms of the GNU Lesser General Public License as published
175+// by the Free Software Foundation, either version 3 of the License, or
176+// (at your option) any later version.
177+//
178+// This program is distributed in the hope that it will be useful,
179+// but WITHOUT ANY WARRANTY; without even the implied warranty of
180+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
181+// GNU General Public License for more details.
182+//
183+// You should have received a copy of the GNU Lesser General Public License
184+// along with this program. If not, see <http://www.gnu.org/licenses/>.
185+#ifndef UBX_8_SCANNER_H_
186+#define UBX_8_SCANNER_H_
187+
188+#include <cstdint>
189+
190+#include <vector>
191+
192+namespace location
193+{
194+namespace providers
195+{
196+namespace ubx
197+{
198+namespace _8
199+{
200+static constexpr const std::uint8_t sync_char_1{0xb5};
201+static constexpr const std::uint8_t sync_char_2{62};
202+
203+enum class Class
204+{
205+ cfg = 0x06
206+};
207+
208+enum class Id
209+{
210+};
211+
212+struct Message
213+{
214+ Class cls;
215+ Id id;
216+ std::uint16_t length;
217+ std::vector<std::uint8_t> payload;
218+ std::uint8_t ck_a;
219+ std::uint8_t ck_b;
220+};
221+}
222+}
223+}
224+}
225+
226+#endif // UBX_8_SCANNER_H_
227
228=== added directory 'src/location/providers/ubx/_8/nmea'
229=== added file 'src/location/providers/ubx/_8/nmea/cardinal_direction.h'
230--- src/location/providers/ubx/_8/nmea/cardinal_direction.h 1970-01-01 00:00:00 +0000
231+++ src/location/providers/ubx/_8/nmea/cardinal_direction.h 2016-10-11 08:54:12 +0000
232@@ -0,0 +1,43 @@
233+// Copyright (C) 2016 Thomas Voss <thomas.voss.bochum@gmail.com>
234+//
235+// This library is free software: you can redistribute it and/or modify
236+// it under the terms of the GNU Lesser General Public License as published
237+// by the Free Software Foundation, either version 3 of the License, or
238+// (at your option) any later version.
239+//
240+// This program is distributed in the hope that it will be useful,
241+// but WITHOUT ANY WARRANTY; without even the implied warranty of
242+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
243+// GNU General Public License for more details.
244+//
245+// You should have received a copy of the GNU Lesser General Public License
246+// along with this program. If not, see <http://www.gnu.org/licenses/>.
247+#ifndef UBX_8_NMEA_CARDINAL_DIRECTION_H_
248+#define UBX_8_NMEA_CARDINAL_DIRECTION_H_
249+
250+namespace location
251+{
252+namespace providers
253+{
254+namespace ubx
255+{
256+namespace _8
257+{
258+namespace nmea
259+{
260+/// @brief CardinalDirection enumerates the main cardinal direction
261+/// available in NMEA sentences.
262+enum class CardinalDirection
263+{
264+ north = 'N',
265+ south = 'S',
266+ east = 'E',
267+ west = 'W'
268+};
269+}
270+}
271+}
272+}
273+}
274+
275+#endif // UBX_8_NMEA_CARDINAL_DIRECTION_H_
276
277=== added file 'src/location/providers/ubx/_8/nmea/date.h'
278--- src/location/providers/ubx/_8/nmea/date.h 1970-01-01 00:00:00 +0000
279+++ src/location/providers/ubx/_8/nmea/date.h 2016-10-11 08:54:12 +0000
280@@ -0,0 +1,43 @@
281+// Copyright (C) 2016 Thomas Voss <thomas.voss.bochum@gmail.com>
282+//
283+// This library is free software: you can redistribute it and/or modify
284+// it under the terms of the GNU Lesser General Public License as published
285+// by the Free Software Foundation, either version 3 of the License, or
286+// (at your option) any later version.
287+//
288+// This program is distributed in the hope that it will be useful,
289+// but WITHOUT ANY WARRANTY; without even the implied warranty of
290+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
291+// GNU General Public License for more details.
292+//
293+// You should have received a copy of the GNU Lesser General Public License
294+// along with this program. If not, see <http://www.gnu.org/licenses/>.
295+#ifndef UBX_8_NMEA_DATE_H_
296+#define UBX_8_NMEA_DATE_H_
297+
298+#include <cstdint>
299+
300+namespace location
301+{
302+namespace providers
303+{
304+namespace ubx
305+{
306+namespace _8
307+{
308+namespace nmea
309+{
310+/// @brief Date models a specific calendar day (Gregorian calendar).
311+struct Date
312+{
313+ std::uint8_t day;
314+ std::uint8_t month;
315+ std::uint8_t year;
316+};
317+}
318+}
319+}
320+}
321+}
322+
323+#endif // UBX_8_NMEA_DATE_H_
324
325=== added file 'src/location/providers/ubx/_8/nmea/fusion_adapt.h'
326--- src/location/providers/ubx/_8/nmea/fusion_adapt.h 1970-01-01 00:00:00 +0000
327+++ src/location/providers/ubx/_8/nmea/fusion_adapt.h 2016-10-11 08:54:12 +0000
328@@ -0,0 +1,134 @@
329+// Copyright (C) 2016 Thomas Voss <thomas.voss.bochum@gmail.com>
330+//
331+// This library is free software: you can redistribute it and/or modify
332+// it under the terms of the GNU Lesser General Public License as published
333+// by the Free Software Foundation, either version 3 of the License, or
334+// (at your option) any later version.
335+//
336+// This program is distributed in the hope that it will be useful,
337+// but WITHOUT ANY WARRANTY; without even the implied warranty of
338+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
339+// GNU General Public License for more details.
340+//
341+// You should have received a copy of the GNU Lesser General Public License
342+// along with this program. If not, see <http://www.gnu.org/licenses/>.
343+#ifndef UBX_8_NMEA_FUSION_ADAPT_H_
344+#define UBX_8_NMEA_FUSION_ADAPT_H_
345+
346+#define BOOST_SPIRIT_DEBUG
347+#define FUSION_MAX_VECTOR_SIZE 15
348+
349+#include <location/providers/ubx/_8/nmea/sentence.h>
350+
351+#include <boost/fusion/adapted/struct.hpp>
352+
353+// clang-format off
354+BOOST_FUSION_ADAPT_STRUCT(
355+ location::providers::ubx::_8::nmea::Latitude,
356+ (uint32_t, degrees)
357+ (double, minutes))
358+
359+BOOST_FUSION_ADAPT_STRUCT(
360+ location::providers::ubx::_8::nmea::Longitude,
361+ (uint32_t, degrees)
362+ (double, minutes))
363+
364+BOOST_FUSION_ADAPT_STRUCT(
365+ location::providers::ubx::_8::nmea::Date,
366+ (std::uint8_t, day)
367+ (std::uint8_t, month)
368+ (std::uint8_t, year))
369+
370+BOOST_FUSION_ADAPT_STRUCT(
371+ location::providers::ubx::_8::nmea::Utc,
372+ (std::uint8_t, hours)
373+ (std::uint8_t, minutes)
374+ (double, seconds))
375+
376+BOOST_FUSION_ADAPT_STRUCT(
377+ location::providers::ubx::_8::nmea::Gsa,
378+ (location::providers::ubx::_8::nmea::Talker, talker)
379+ (boost::optional<location::providers::ubx::_8::nmea::Gsa::OperationMode>, operation_mode)
380+ (boost::optional<location::providers::ubx::_8::nmea::Gsa::FixMode>, fix_mode)
381+ (std::vector<boost::optional<std::uint8_t>>, satellite_ids)
382+ (boost::optional<location::providers::ubx::Dop<location::providers::ubx::tag::Positional>>, pdop)
383+ (boost::optional<location::providers::ubx::Dop<location::providers::ubx::tag::Horizontal>>, hdop)
384+ (boost::optional<location::providers::ubx::Dop<location::providers::ubx::tag::Vertical>>, vdop))
385+
386+BOOST_FUSION_ADAPT_STRUCT(
387+ location::providers::ubx::_8::nmea::Gga,
388+ (location::providers::ubx::_8::nmea::Talker, talker)
389+ (boost::optional<location::providers::ubx::_8::nmea::Utc>, utc)
390+ (boost::optional<location::providers::ubx::_8::nmea::Latitude>, latitude)
391+ (boost::optional<location::providers::ubx::_8::nmea::CardinalDirection>, latitude_direction)
392+ (boost::optional<location::providers::ubx::_8::nmea::Longitude>, longitude)
393+ (boost::optional<location::providers::ubx::_8::nmea::CardinalDirection>, longitude_direction)
394+ (boost::optional<location::providers::ubx::_8::nmea::gps::FixMode>, fix_mode)
395+ (boost::optional<std::uint8_t>, satellites_in_use)
396+ (boost::optional<location::providers::ubx::Dop<location::providers::ubx::tag::Horizontal>>, hdop)
397+ (boost::optional<float>, altitude)
398+ (boost::optional<float>, geoidal_separation)
399+ (boost::optional<float>, age)
400+ (boost::optional<std::uint16_t>, differential_reference_station))
401+
402+BOOST_FUSION_ADAPT_STRUCT(
403+ location::providers::ubx::_8::nmea::Gll,
404+ (location::providers::ubx::_8::nmea::Talker, talker)
405+ (boost::optional<location::providers::ubx::_8::nmea::Latitude>, latitude)
406+ (boost::optional<location::providers::ubx::_8::nmea::CardinalDirection>, latitude_direction)
407+ (boost::optional<location::providers::ubx::_8::nmea::Longitude>, longitude)
408+ (boost::optional<location::providers::ubx::_8::nmea::CardinalDirection>, longitude_direction)
409+ (boost::optional<location::providers::ubx::_8::nmea::Utc>, utc)
410+ (boost::optional<location::providers::ubx::_8::nmea::Status>, status)
411+ (boost::optional<location::providers::ubx::_8::nmea::Mode>, mode))
412+
413+BOOST_FUSION_ADAPT_STRUCT(
414+ location::providers::ubx::_8::nmea::Gsv::Info,
415+ (boost::optional<std::uint8_t>, satellite_id)
416+ (boost::optional<std::uint8_t>, elevation)
417+ (boost::optional<std::uint16_t>, azimuth)
418+ (boost::optional<std::uint8_t>, snr))
419+
420+BOOST_FUSION_ADAPT_STRUCT(
421+ location::providers::ubx::_8::nmea::Gsv,
422+ (location::providers::ubx::_8::nmea::Talker, talker)
423+ (boost::optional<std::uint8_t>, sentence_count)
424+ (boost::optional<std::uint8_t>, sentence_number)
425+ (boost::optional<std::uint8_t>, satellites_count)
426+ (std::vector<location::providers::ubx::_8::nmea::Gsv::Info>, satellites_info))
427+
428+BOOST_FUSION_ADAPT_STRUCT(
429+ location::providers::ubx::_8::nmea::Rmc,
430+ (location::providers::ubx::_8::nmea::Talker, talker)
431+ (boost::optional<location::providers::ubx::_8::nmea::Utc>, utc)
432+ (boost::optional<location::providers::ubx::_8::nmea::Status>, status)
433+ (boost::optional<location::providers::ubx::_8::nmea::Latitude>, latitude)
434+ (boost::optional<location::providers::ubx::_8::nmea::CardinalDirection>, latitude_direction)
435+ (boost::optional<location::providers::ubx::_8::nmea::Longitude>, longitude)
436+ (boost::optional<location::providers::ubx::_8::nmea::CardinalDirection>, longitude_direction)
437+ (boost::optional<float>, speed_over_ground)(boost::optional<float>, course_over_ground)
438+ (boost::optional<location::providers::ubx::_8::nmea::Date>, date)
439+ (boost::optional<float>, magnetic_variation)
440+ (boost::optional<location::providers::ubx::_8::nmea::CardinalDirection>, cardinal_direction)
441+ (boost::optional<location::providers::ubx::_8::nmea::Mode>, mode))
442+
443+BOOST_FUSION_ADAPT_STRUCT(
444+ location::providers::ubx::_8::nmea::Txt,
445+ (location::providers::ubx::_8::nmea::Talker, talker)
446+ (boost::optional<std::uint8_t>, total_number_of_sentences)
447+ (boost::optional<std::uint8_t>, sentence_number)
448+ (boost::optional<std::uint8_t>, identifier)
449+ (boost::optional<std::string>, message))
450+
451+BOOST_FUSION_ADAPT_STRUCT(
452+ location::providers::ubx::_8::nmea::Vtg,
453+ (location::providers::ubx::_8::nmea::Talker, talker)
454+ (boost::optional<float>, cog_true)
455+ (boost::optional<float>, cog_magnetic)
456+ (boost::optional<float>, sog_knots)
457+ (boost::optional<float>, sog_kmh)
458+ (boost::optional<location::providers::ubx::_8::nmea::Mode>, mode))
459+
460+// clang-format on
461+
462+#endif // UBX_8_NMEA_FUSION_ADAPT_H_
463
464=== added file 'src/location/providers/ubx/_8/nmea/generator.h'
465--- src/location/providers/ubx/_8/nmea/generator.h 1970-01-01 00:00:00 +0000
466+++ src/location/providers/ubx/_8/nmea/generator.h 2016-10-11 08:54:12 +0000
467@@ -0,0 +1,254 @@
468+// Copyright (C) 2016 Thomas Voss <thomas.voss.bochum@gmail.com>
469+//
470+// This library is free software: you can redistribute it and/or modify
471+// it under the terms of the GNU Lesser General Public License as published
472+// by the Free Software Foundation, either version 3 of the License, or
473+// (at your option) any later version.
474+//
475+// This program is distributed in the hope that it will be useful,
476+// but WITHOUT ANY WARRANTY; without even the implied warranty of
477+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
478+// GNU General Public License for more details.
479+//
480+// You should have received a copy of the GNU Lesser General Public License
481+// along with this program. If not, see <http://www.gnu.org/licenses/>.
482+#ifndef UBX_8_NMEA_GENERATOR_H_
483+#define UBX_8_NMEA_GENERATOR_H_
484+
485+#define BOOST_SPIRIT_DEBUG
486+#define FUSION_MAX_VECTOR_SIZE 15
487+
488+#include <location/providers/ubx/_8/nmea/sentence.h>
489+
490+#include <location/providers/ubx/_8/nmea/fusion_adapt.h>
491+
492+#include <boost/spirit/include/classic.hpp>
493+#include <boost/spirit/include/karma.hpp>
494+#include <boost/spirit/include/karma_real.hpp>
495+#include <boost/spirit/include/karma_uint.hpp>
496+
497+#include <cstdint>
498+
499+namespace location
500+{
501+namespace providers
502+{
503+namespace ubx
504+{
505+namespace _8
506+{
507+namespace nmea
508+{
509+
510+template <unsigned prec, typename T>
511+struct FinitePrecisionPolicy : boost::spirit::karma::real_policies<T>
512+{
513+ static int floatfield(T) { return boost::spirit::karma::real_policies<T>::fmtflags::fixed; }
514+ static unsigned precision(T) { return prec; }
515+};
516+
517+template <typename Iterator>
518+class Generator : public boost::spirit::karma::grammar<Iterator, Sentence()>
519+{
520+public:
521+ Generator() : Generator::base_type{start}
522+ {
523+ // clang-format off
524+ start %= (gga | gsa | gll | gsv | rmc | txt | vtg);
525+ field_separator %= ',';
526+ checksum %= boost::spirit::karma::hex;
527+ talker.add
528+ (Talker::gl, "GL")
529+ (Talker::gn, "GN")
530+ (Talker::gp, "GP");
531+ status.add
532+ (Status::valid, 'A')
533+ (Status::not_valid, 'V');
534+ mode.add
535+ (Mode::autonomous, 'A')
536+ (Mode::differential, 'D')
537+ (Mode::estimated, 'E')
538+ (Mode::manual_input, 'M')
539+ (Mode::simulator_mode, 'S')
540+ (Mode::data_not_valid, 'N');
541+ cardinal_direction.all.add
542+ (CardinalDirection::north, 'N')
543+ (CardinalDirection::south, 'S')
544+ (CardinalDirection::east, 'E')
545+ (CardinalDirection::west, 'W');
546+ cardinal_direction.ns.add
547+ (CardinalDirection::north, 'N')
548+ (CardinalDirection::south, 'S');
549+ cardinal_direction.ew.add
550+ (CardinalDirection::east, 'E')
551+ (CardinalDirection::west, 'W');
552+ gps.fix_mode.add
553+ (gps::FixMode::invalid, '0')
554+ (gps::FixMode::gps_sps, '1')
555+ (gps::FixMode::differential_gps_sps, '2')
556+ (gps::FixMode::gps_pps, '3')
557+ (gps::FixMode::real_time_kinematic, '4')
558+ (gps::FixMode::floating_point_real_time_kinematic, '5')
559+ (gps::FixMode::estimated, '6')
560+ (gps::FixMode::manual_input, '7')
561+ (gps::FixMode::simulator, '8');
562+ for_gsa.operation_mode.add
563+ (Gsa::OperationMode::automatic, 'A')
564+ (Gsa::OperationMode::manual, 'M');
565+ for_gsa.fix_mode.add
566+ (Gsa::FixMode::fix_not_available, '1')
567+ (Gsa::FixMode::fix_in_2d, '2')
568+ (Gsa::FixMode::fix_in_3d, '3');
569+
570+ pdop %= boost::spirit::karma::real_generator<float, FinitePrecisionPolicy<5, float>>();
571+ hdop %= boost::spirit::karma::real_generator<float, FinitePrecisionPolicy<5, float>>();
572+ vdop %= boost::spirit::karma::real_generator<float, FinitePrecisionPolicy<5, float>>();
573+
574+ latitude %= boost::spirit::karma::right_align(2, '0')[boost::spirit::karma::uint_generator<std::uint32_t, 10>()] <<
575+ boost::spirit::karma::real_generator<double, FinitePrecisionPolicy<5, double>>();
576+
577+ longitude %= boost::spirit::karma::right_align(3, '0')[boost::spirit::karma::uint_generator<std::uint32_t, 10>()] <<
578+ boost::spirit::karma::real_generator<double, FinitePrecisionPolicy<5, double>>();
579+
580+ date %= boost::spirit::karma::right_align(2, '0')[boost::spirit::karma::uint_generator<std::uint32_t, 10>()] <<
581+ boost::spirit::karma::right_align(2, '0')[boost::spirit::karma::uint_generator<std::uint32_t, 10>()] <<
582+ boost::spirit::karma::right_align(2, '0')[boost::spirit::karma::uint_generator<std::uint32_t, 10>()];
583+
584+ utc %= boost::spirit::karma::right_align(2, '0')[boost::spirit::karma::uint_generator<std::uint32_t, 10>()] <<
585+ boost::spirit::karma::right_align(2, '0')[boost::spirit::karma::uint_generator<std::uint32_t, 10>()] <<
586+ boost::spirit::karma::real_generator<double, FinitePrecisionPolicy<5, double>>();
587+
588+ gsa %= talker << "GSA" << field_separator
589+ << -for_gsa.operation_mode << field_separator
590+ << -for_gsa.fix_mode << field_separator
591+ << boost::spirit::karma::repeat(12)[boost::spirit::karma::right_align(2, '0')
592+ [-boost::spirit::karma::uint_generator<std::uint32_t, 10>()] << field_separator]
593+ << -pdop << field_separator
594+ << -hdop << field_separator
595+ << -vdop;
596+
597+ gga %= talker << "GGA" << field_separator
598+ << -utc << field_separator
599+ << -(latitude) << field_separator
600+ << -(cardinal_direction.ns) << field_separator
601+ << -(longitude) << field_separator
602+ << -(cardinal_direction.ew) << field_separator
603+ << -gps.fix_mode << field_separator
604+ << boost::spirit::karma::right_align(2, '0')[-boost::spirit::karma::uint_generator<std::uint32_t, 10>()] << field_separator
605+ << -hdop << field_separator
606+ << -(boost::spirit::karma::real_generator<float>()) << field_separator
607+ << -boost::spirit::karma::lit('M') << field_separator
608+ << -(boost::spirit::karma::real_generator<float>()) << field_separator
609+ << -boost::spirit::karma::lit('M') << field_separator
610+ << -boost::spirit::karma::real_generator<float>() << field_separator
611+ << boost::spirit::karma::right_align(2, '0')[-boost::spirit::karma::uint_generator<std::uint32_t, 10>()];
612+
613+ gll %= talker << "GLL" << field_separator
614+ << -latitude << field_separator
615+ << -cardinal_direction.ns << field_separator
616+ << -longitude << field_separator
617+ << -cardinal_direction.ew << field_separator
618+ << -utc << field_separator
619+ << -status << field_separator
620+ << -mode;
621+
622+ gsv_info %= field_separator <<
623+ boost::spirit::karma::right_align(2, '0')[-boost::spirit::karma::uint_generator<std::uint8_t, 10>()] <<
624+ field_separator <<
625+ boost::spirit::karma::right_align(2, '0')[-boost::spirit::karma::uint_generator<std::uint8_t, 10>()] <<
626+ field_separator <<
627+ boost::spirit::karma::right_align(3, '0')[-boost::spirit::karma::uint_generator<std::uint16_t, 10>()] <<
628+ field_separator <<
629+ boost::spirit::karma::right_align(2, '0')[-boost::spirit::karma::uint_generator<std::uint8_t, 10>()];
630+
631+ gsv %= talker << "GSV" << field_separator
632+ << boost::spirit::karma::maxwidth(1)[-boost::spirit::karma::uint_generator<std::uint8_t, 10>()] << field_separator
633+ << boost::spirit::karma::maxwidth(1)[-boost::spirit::karma::uint_generator<std::uint8_t, 10>()] << field_separator
634+ << boost::spirit::karma::right_align(2, '0')[-boost::spirit::karma::uint_generator<std::uint16_t, 10>()]
635+ << +(gsv_info);
636+
637+ rmc %= talker << "RMC" << field_separator
638+ << -utc << field_separator
639+ << -status << field_separator
640+ << -(latitude) << field_separator
641+ << -(cardinal_direction.ns) << field_separator
642+ << -(longitude) << field_separator
643+ << -(cardinal_direction.ew) << field_separator
644+ << -(boost::spirit::karma::real_generator<float, FinitePrecisionPolicy<5, float>>()) << field_separator
645+ << -(boost::spirit::karma::real_generator<float, FinitePrecisionPolicy<5, float>>()) << field_separator
646+ << -date << field_separator
647+ << -(boost::spirit::karma::real_generator<float, FinitePrecisionPolicy<5, float>>()) << field_separator
648+ << -(cardinal_direction.ew) << field_separator
649+ << -mode;
650+
651+ txt %= talker << "TXT" << field_separator
652+ << boost::spirit::karma::right_align(2, '0')[-boost::spirit::karma::uint_generator<std::uint8_t, 10>()] << field_separator
653+ << boost::spirit::karma::right_align(2, '0')[-boost::spirit::karma::uint_generator<std::uint8_t, 10>()] << field_separator
654+ << boost::spirit::karma::right_align(2, '0')[-boost::spirit::karma::uint_generator<std::uint8_t, 10>()] << field_separator
655+ << -boost::spirit::karma::ascii::string;
656+
657+ vtg %= talker << "VTG" << field_separator
658+ << -boost::spirit::karma::real_generator<float, FinitePrecisionPolicy<5, float>>() << field_separator
659+ << 'T' << field_separator
660+ << -boost::spirit::karma::real_generator<float, FinitePrecisionPolicy<5, float>>() << field_separator
661+ << 'M' << field_separator
662+ << -boost::spirit::karma::real_generator<float, FinitePrecisionPolicy<5, float>>() << field_separator
663+ << 'N' << field_separator
664+ << -boost::spirit::karma::real_generator<float, FinitePrecisionPolicy<5, float>>() << field_separator
665+ << 'K' << field_separator
666+ << -mode;
667+ // clang-format on
668+ }
669+
670+private:
671+ boost::spirit::karma::rule<Iterator, Sentence()> start;
672+ boost::spirit::karma::rule<Iterator> field_separator;
673+ boost::spirit::karma::rule<Iterator, std::uint32_t()> checksum;
674+ boost::spirit::karma::rule<Iterator, Latitude()> latitude;
675+ boost::spirit::karma::rule<Iterator, Longitude()> longitude;
676+ boost::spirit::karma::rule<Iterator, Date()> date;
677+ boost::spirit::karma::rule<Iterator, Utc()> utc;
678+ boost::spirit::karma::rule<Iterator, Dop<tag::Positional>()> pdop;
679+ boost::spirit::karma::rule<Iterator, Dop<tag::Horizontal>()> hdop;
680+ boost::spirit::karma::rule<Iterator, Dop<tag::Vertical>()> vdop;
681+
682+ boost::spirit::karma::rule<Iterator, Gsa()> gsa;
683+ boost::spirit::karma::rule<Iterator, Gga()> gga;
684+ boost::spirit::karma::rule<Iterator, Gll()> gll;
685+ boost::spirit::karma::rule<Iterator, Gsv::Info()> gsv_info;
686+ boost::spirit::karma::rule<Iterator, Gsv()> gsv;
687+ boost::spirit::karma::rule<Iterator, Rmc()> rmc;
688+ boost::spirit::karma::rule<Iterator, Txt()> txt;
689+ boost::spirit::karma::rule<Iterator, Vtg()> vtg;
690+
691+ // Enumerations go here
692+ boost::spirit::karma::symbols<Talker, const char*> talker;
693+ boost::spirit::karma::symbols<Status, char> status;
694+ boost::spirit::karma::symbols<Mode, char> mode;
695+ struct
696+ {
697+ boost::spirit::karma::symbols<CardinalDirection, char> all;
698+ boost::spirit::karma::symbols<CardinalDirection, char> ns;
699+ boost::spirit::karma::symbols<CardinalDirection, char> ew;
700+ } cardinal_direction;
701+
702+ // Positioning-system specific rules go here
703+ struct
704+ {
705+ boost::spirit::karma::symbols<gps::FixMode, char> fix_mode;
706+ } gps;
707+
708+ // Sentence-specific rules go here
709+ struct
710+ {
711+ boost::spirit::karma::symbols<Gsa::OperationMode, char> operation_mode;
712+ boost::spirit::karma::symbols<Gsa::FixMode, char> fix_mode;
713+ } for_gsa;
714+};
715+}
716+}
717+}
718+}
719+}
720+
721+#endif // UBX_8_NMEA_GENERATOR_H_
722
723=== added file 'src/location/providers/ubx/_8/nmea/gga.h'
724--- src/location/providers/ubx/_8/nmea/gga.h 1970-01-01 00:00:00 +0000
725+++ src/location/providers/ubx/_8/nmea/gga.h 2016-10-11 08:54:12 +0000
726@@ -0,0 +1,69 @@
727+// Copyright (C) 2016 Thomas Voss <thomas.voss.bochum@gmail.com>
728+//
729+// This library is free software: you can redistribute it and/or modify
730+// it under the terms of the GNU Lesser General Public License as published
731+// by the Free Software Foundation, either version 3 of the License, or
732+// (at your option) any later version.
733+//
734+// This program is distributed in the hope that it will be useful,
735+// but WITHOUT ANY WARRANTY; without even the implied warranty of
736+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
737+// GNU General Public License for more details.
738+//
739+// You should have received a copy of the GNU Lesser General Public License
740+// along with this program. If not, see <http://www.gnu.org/licenses/>.
741+#ifndef UBX_8_NMEA_GGA_H_
742+#define UBX_8_NMEA_GGA_H_
743+
744+#include <location/providers/ubx/dop.h>
745+
746+#include <location/providers/ubx/_8/nmea/cardinal_direction.h>
747+#include <location/providers/ubx/_8/nmea/latitude.h>
748+#include <location/providers/ubx/_8/nmea/longitude.h>
749+#include <location/providers/ubx/_8/nmea/talker.h>
750+#include <location/providers/ubx/_8/nmea/utc.h>
751+
752+#include <location/providers/ubx/_8/nmea/gps/fix_mode.h>
753+
754+#include <boost/optional.hpp>
755+
756+#include <cstdint>
757+
758+namespace location
759+{
760+namespace providers
761+{
762+namespace ubx
763+{
764+namespace _8
765+{
766+namespace nmea
767+{
768+/// @brief Global positioning system fix data.
769+///
770+/// Time and position, together with GPS fixing related data (number of
771+/// satellites in use, and
772+/// the resulting HDOP, age of differential data if in use, etc.).
773+struct Gga
774+{
775+ Talker talker;
776+ boost::optional<Utc> utc;
777+ boost::optional<Latitude> latitude;
778+ boost::optional<CardinalDirection> latitude_direction;
779+ boost::optional<Longitude> longitude;
780+ boost::optional<CardinalDirection> longitude_direction;
781+ boost::optional<gps::FixMode> fix_mode;
782+ boost::optional<std::uint8_t> satellites_in_use;
783+ boost::optional<Dop<tag::Horizontal>> hdop;
784+ boost::optional<float> altitude;
785+ boost::optional<float> geoidal_separation;
786+ boost::optional<float> age; // [s]
787+ boost::optional<std::uint16_t> differential_reference_station;
788+};
789+}
790+}
791+}
792+}
793+}
794+
795+#endif // UBX_8_NMEA_GGA_H_
796
797=== added file 'src/location/providers/ubx/_8/nmea/gll.h'
798--- src/location/providers/ubx/_8/nmea/gll.h 1970-01-01 00:00:00 +0000
799+++ src/location/providers/ubx/_8/nmea/gll.h 2016-10-11 08:54:12 +0000
800@@ -0,0 +1,56 @@
801+// Copyright (C) 2016 Thomas Voss <thomas.voss.bochum@gmail.com>
802+//
803+// This library is free software: you can redistribute it and/or modify
804+// it under the terms of the GNU Lesser General Public License as published
805+// by the Free Software Foundation, either version 3 of the License, or
806+// (at your option) any later version.
807+//
808+// This program is distributed in the hope that it will be useful,
809+// but WITHOUT ANY WARRANTY; without even the implied warranty of
810+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
811+// GNU General Public License for more details.
812+//
813+// You should have received a copy of the GNU Lesser General Public License
814+// along with this program. If not, see <http://www.gnu.org/licenses/>.
815+#ifndef UBX_8_NMEA_GLL_H_
816+#define UBX_8_NMEA_GLL_H_
817+
818+#include <location/providers/ubx/_8/nmea/cardinal_direction.h>
819+#include <location/providers/ubx/_8/nmea/latitude.h>
820+#include <location/providers/ubx/_8/nmea/longitude.h>
821+#include <location/providers/ubx/_8/nmea/mode.h>
822+#include <location/providers/ubx/_8/nmea/status.h>
823+#include <location/providers/ubx/_8/nmea/talker.h>
824+#include <location/providers/ubx/_8/nmea/utc.h>
825+
826+#include <boost/optional.hpp>
827+
828+namespace location
829+{
830+namespace providers
831+{
832+namespace ubx
833+{
834+namespace _8
835+{
836+namespace nmea
837+{
838+/// @brief Latitude and longitude, with time of position fix and status
839+struct Gll
840+{
841+ Talker talker;
842+ boost::optional<Latitude> latitude;
843+ boost::optional<CardinalDirection> latitude_direction;
844+ boost::optional<Longitude> longitude;
845+ boost::optional<CardinalDirection> longitude_direction;
846+ boost::optional<Utc> utc;
847+ boost::optional<Status> status;
848+ boost::optional<Mode> mode;
849+};
850+}
851+}
852+}
853+}
854+}
855+
856+#endif // UBX_8_NMEA_GLL_H_
857
858=== added directory 'src/location/providers/ubx/_8/nmea/gps'
859=== added file 'src/location/providers/ubx/_8/nmea/gps/fix_mode.h'
860--- src/location/providers/ubx/_8/nmea/gps/fix_mode.h 1970-01-01 00:00:00 +0000
861+++ src/location/providers/ubx/_8/nmea/gps/fix_mode.h 2016-10-11 08:54:12 +0000
862@@ -0,0 +1,50 @@
863+// Copyright (C) 2016 Thomas Voss <thomas.voss.bochum@gmail.com>
864+//
865+// This library is free software: you can redistribute it and/or modify
866+// it under the terms of the GNU Lesser General Public License as published
867+// by the Free Software Foundation, either version 3 of the License, or
868+// (at your option) any later version.
869+//
870+// This program is distributed in the hope that it will be useful,
871+// but WITHOUT ANY WARRANTY; without even the implied warranty of
872+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
873+// GNU General Public License for more details.
874+//
875+// You should have received a copy of the GNU Lesser General Public License
876+// along with this program. If not, see <http://www.gnu.org/licenses/>.
877+#ifndef UBX_8_NMEA_GPS_FIX_MODE_H_
878+#define UBX_8_NMEA_GPS_FIX_MODE_H_
879+
880+namespace location
881+{
882+namespace providers
883+{
884+namespace ubx
885+{
886+namespace _8
887+{
888+namespace nmea
889+{
890+namespace gps
891+{
892+/// @brief FixMode enumerates all known, gps-specific fix modes.
893+enum class FixMode
894+{
895+ invalid = 0,
896+ gps_sps = 1,
897+ differential_gps_sps = 2,
898+ gps_pps = 3,
899+ real_time_kinematic = 4,
900+ floating_point_real_time_kinematic = 5,
901+ estimated = 6,
902+ manual_input = 7,
903+ simulator = 8
904+};
905+}
906+}
907+}
908+}
909+}
910+}
911+
912+#endif // UBX_8_NMEA_GPS_FIX_MODE_H_
913
914=== added file 'src/location/providers/ubx/_8/nmea/grammar.h'
915--- src/location/providers/ubx/_8/nmea/grammar.h 1970-01-01 00:00:00 +0000
916+++ src/location/providers/ubx/_8/nmea/grammar.h 2016-10-11 08:54:12 +0000
917@@ -0,0 +1,251 @@
918+// Copyright (C) 2016 Thomas Voss <thomas.voss.bochum@gmail.com>
919+//
920+// This library is free software: you can redistribute it and/or modify
921+// it under the terms of the GNU Lesser General Public License as published
922+// by the Free Software Foundation, either version 3 of the License, or
923+// (at your option) any later version.
924+//
925+// This program is distributed in the hope that it will be useful,
926+// but WITHOUT ANY WARRANTY; without even the implied warranty of
927+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
928+// GNU General Public License for more details.
929+//
930+// You should have received a copy of the GNU Lesser General Public License
931+// along with this program. If not, see <http://www.gnu.org/licenses/>.
932+#ifndef UBX_8_NMEA_GRAMMAR_H_
933+#define UBX_8_NMEA_GRAMMAR_H_
934+
935+#define BOOST_SPIRIT_DEBUG
936+#define FUSION_MAX_VECTOR_SIZE 15
937+
938+#include <location/providers/ubx/_8/nmea/fusion_adapt.h>
939+
940+#include <boost/spirit/include/classic.hpp>
941+#include <boost/spirit/include/qi.hpp>
942+#include <boost/spirit/include/qi_real.hpp>
943+#include <boost/spirit/include/qi_uint.hpp>
944+
945+#include <cstdint>
946+
947+namespace location
948+{
949+namespace providers
950+{
951+namespace ubx
952+{
953+namespace _8
954+{
955+namespace nmea
956+{
957+
958+template <std::size_t integral, typename T>
959+struct FixedPrecisionRealPolicy : boost::spirit::qi::ureal_policies<T>
960+{
961+ // Thousands separated numbers
962+ template <typename Iterator, typename Attribute>
963+ static bool parse_n(Iterator& first, Iterator const& last, Attribute& attr)
964+ {
965+ return boost::spirit::qi::extract_uint<T, 10, integral, integral>::call(first, last, attr);
966+ }
967+};
968+
969+template <typename Iterator>
970+class Grammar : public boost::spirit::qi::grammar<Iterator, Sentence()>
971+{
972+public:
973+ Grammar() : Grammar::base_type{start}
974+ {
975+ // clang-format off
976+ start %= (gga | gsa | gll | gsv | rmc | txt | vtg);
977+ field_separator %= ',';
978+ checksum %= boost::spirit::qi::hex;
979+ talker.add
980+ ("GL", Talker::gl)
981+ ("GN", Talker::gn)
982+ ("GP", Talker::gp);
983+ status.add
984+ ("A", Status::valid)
985+ ("V", Status::not_valid);
986+ mode.add
987+ ("A", Mode::autonomous)
988+ ("D", Mode::differential)
989+ ("E", Mode::estimated)
990+ ("M", Mode::manual_input)
991+ ("S", Mode::simulator_mode)
992+ ("N", Mode::data_not_valid);
993+ cardinal_direction.all.add
994+ ("N", CardinalDirection::north)
995+ ("S", CardinalDirection::south)
996+ ("E", CardinalDirection::east)
997+ ("W", CardinalDirection::west);
998+ cardinal_direction.ns.add
999+ ("N", CardinalDirection::north)
1000+ ("S", CardinalDirection::south);
1001+ cardinal_direction.ew.add
1002+ ("E", CardinalDirection::east)
1003+ ("W", CardinalDirection::west);
1004+ gps.fix_mode.add
1005+ ("0", gps::FixMode::invalid)
1006+ ("1", gps::FixMode::gps_sps)
1007+ ("2", gps::FixMode::differential_gps_sps)
1008+ ("3", gps::FixMode::gps_pps)
1009+ ("4", gps::FixMode::real_time_kinematic)
1010+ ("5", gps::FixMode::floating_point_real_time_kinematic)
1011+ ("6", gps::FixMode::estimated)("7", gps::FixMode::manual_input)
1012+ ("8", gps::FixMode::simulator);
1013+ for_gsa.operation_mode.add
1014+ ("A", Gsa::OperationMode::automatic)
1015+ ("M", Gsa::OperationMode::manual);
1016+ for_gsa.fix_mode.add
1017+ ("1", Gsa::FixMode::fix_not_available)
1018+ ("2", Gsa::FixMode::fix_in_2d)
1019+ ("3", Gsa::FixMode::fix_in_3d);
1020+
1021+ pdop %= boost::spirit::qi::real_parser<float>();
1022+ hdop %= boost::spirit::qi::real_parser<float>();
1023+ vdop %= boost::spirit::qi::real_parser<float>();
1024+
1025+ latitude %= boost::spirit::qi::uint_parser<std::uint32_t, 10, 2, 2>() >>
1026+ boost::spirit::qi::real_parser<double, FixedPrecisionRealPolicy<2, double>>();
1027+
1028+ longitude %= boost::spirit::qi::uint_parser<std::uint32_t, 10, 3, 3>() >>
1029+ boost::spirit::qi::real_parser<double, FixedPrecisionRealPolicy<2, double>>();
1030+
1031+ date %= boost::spirit::qi::uint_parser<std::uint32_t, 10, 2, 2>() >>
1032+ boost::spirit::qi::uint_parser<std::uint32_t, 10, 2, 2>() >>
1033+ boost::spirit::qi::uint_parser<std::uint32_t, 10, 2, 2>();
1034+
1035+ utc %= boost::spirit::qi::uint_parser<std::uint8_t, 10, 2, 2>() >>
1036+ boost::spirit::qi::uint_parser<std::uint8_t, 10, 2, 2>() >>
1037+ boost::spirit::qi::real_parser<double, FixedPrecisionRealPolicy<2, double>>();
1038+
1039+ gsa %= talker >> "GSA" >> field_separator >> -for_gsa.operation_mode >>
1040+ field_separator >> -for_gsa.fix_mode >> field_separator >>
1041+ boost::spirit::qi::repeat(
1042+ 12)[-boost::spirit::qi::uint_parser<std::uint32_t, 10, 2, 2>() >>
1043+ field_separator] >>
1044+ -pdop >> field_separator >> -hdop >> field_separator >> -vdop;
1045+
1046+ gga %= talker >> "GGA" >> field_separator
1047+ >> -utc >> field_separator
1048+ >> -latitude >> field_separator
1049+ >> -(cardinal_direction.ns) >> field_separator
1050+ >> -longitude >> field_separator
1051+ >> -(cardinal_direction.ew) >> field_separator
1052+ >> -gps.fix_mode >> field_separator
1053+ >> -boost::spirit::qi::uint_parser<std::uint32_t, 10, 2, 2>() >> field_separator
1054+ >> -hdop >> field_separator
1055+ >> -(boost::spirit::qi::real_parser<float, boost::spirit::qi::strict_ureal_policies<float>>()) >> field_separator
1056+ >> -boost::spirit::qi::lit('M') >> field_separator
1057+ >> -(boost::spirit::qi::real_parser<float, boost::spirit::qi::strict_ureal_policies<float>>()) >> field_separator
1058+ >> -boost::spirit::qi::lit('M') >> field_separator
1059+ >> -boost::spirit::qi::real_parser<float, boost::spirit::qi::strict_ureal_policies<float>>() >> field_separator
1060+ >> -boost::spirit::qi::uint_parser<std::uint32_t, 10, 2, 2>();
1061+
1062+ gll %= talker >> "GLL" >> field_separator
1063+ >> -latitude >> field_separator
1064+ >> -cardinal_direction.ns >> field_separator
1065+ >> -longitude >> field_separator
1066+ >> -cardinal_direction.ew >> field_separator
1067+ >> -utc >> field_separator
1068+ >> -status >> field_separator
1069+ >> -mode;
1070+
1071+ gsv_info %= field_separator >>
1072+ -boost::spirit::qi::uint_parser<std::uint8_t, 10, 2, 2>() >>
1073+ field_separator >>
1074+ -boost::spirit::qi::uint_parser<std::uint8_t, 10, 2, 2>() >>
1075+ field_separator >>
1076+ -boost::spirit::qi::uint_parser<std::uint16_t, 10, 3, 3>() >>
1077+ field_separator >>
1078+ -boost::spirit::qi::uint_parser<std::uint8_t, 10, 2, 2>();
1079+
1080+ gsv %= talker >> "GSV" >> field_separator
1081+ >> -boost::spirit::qi::uint_parser<std::uint8_t, 10, 1, 1>() >> field_separator
1082+ >> -boost::spirit::qi::uint_parser<std::uint8_t, 10, 1, 1>() >> field_separator
1083+ >> -boost::spirit::qi::uint_parser<std::uint16_t, 10, 2, 2>()
1084+ >> +(gsv_info);
1085+
1086+ rmc %= talker >> "RMC" >> field_separator
1087+ >> -utc >> field_separator
1088+ >> -status >> field_separator
1089+ >> -(latitude) >> field_separator
1090+ >> -(cardinal_direction.ns) >> field_separator
1091+ >> -(longitude) >> field_separator >> -(cardinal_direction.ew) >> field_separator
1092+ >> -(boost::spirit::qi::real_parser<float, boost::spirit::qi::strict_ureal_policies<float>>()) >> field_separator
1093+ >> -(boost::spirit::qi::real_parser<float, boost::spirit::qi::strict_ureal_policies<float>>()) >> field_separator
1094+ >> -date >> field_separator
1095+ >> -(boost::spirit::qi::real_parser<float, boost::spirit::qi::strict_ureal_policies<float>>()) >> field_separator
1096+ >> -(cardinal_direction.ew) >> field_separator
1097+ >> -mode;
1098+
1099+ txt %= talker >> "TXT" >> field_separator
1100+ >> -boost::spirit::qi::uint_parser<std::uint8_t, 10, 2, 2>() >> field_separator
1101+ >> -boost::spirit::qi::uint_parser<std::uint8_t, 10, 2, 2>() >> field_separator
1102+ >> -boost::spirit::qi::uint_parser<std::uint8_t, 10, 2, 2>() >> field_separator
1103+ >> -boost::spirit::qi::as_string[*boost::spirit::qi::ascii::char_];
1104+
1105+ vtg %= talker >> "VTG" >> field_separator
1106+ >> -boost::spirit::qi::real_parser<float>() >> field_separator
1107+ >> -boost::spirit::qi::lit('T') >> field_separator
1108+ >> -boost::spirit::qi::real_parser<float>() >> field_separator
1109+ >> -boost::spirit::qi::lit('M') >> field_separator
1110+ >> -boost::spirit::qi::real_parser<float>() >> field_separator
1111+ >> -boost::spirit::qi::lit('N') >> field_separator
1112+ >> -boost::spirit::qi::real_parser<float>() >> field_separator
1113+ >> -boost::spirit::qi::lit('K') >> field_separator
1114+ >> mode;
1115+ // clang-format on
1116+ }
1117+
1118+ boost::spirit::qi::rule<Iterator, Sentence()> start;
1119+ boost::spirit::qi::rule<Iterator> field_separator;
1120+ boost::spirit::qi::rule<Iterator, std::uint32_t()> checksum;
1121+ boost::spirit::qi::rule<Iterator, Latitude()> latitude;
1122+ boost::spirit::qi::rule<Iterator, Longitude()> longitude;
1123+ boost::spirit::qi::rule<Iterator, Date()> date;
1124+ boost::spirit::qi::rule<Iterator, Utc()> utc;
1125+ boost::spirit::qi::rule<Iterator, Dop<tag::Positional>()> pdop;
1126+ boost::spirit::qi::rule<Iterator, Dop<tag::Horizontal>()> hdop;
1127+ boost::spirit::qi::rule<Iterator, Dop<tag::Vertical>()> vdop;
1128+
1129+ boost::spirit::qi::rule<Iterator, Gsa()> gsa;
1130+ boost::spirit::qi::rule<Iterator, Gga()> gga;
1131+ boost::spirit::qi::rule<Iterator, Gll()> gll;
1132+ boost::spirit::qi::rule<Iterator, Gsv::Info()> gsv_info;
1133+ boost::spirit::qi::rule<Iterator, Gsv()> gsv;
1134+ boost::spirit::qi::rule<Iterator, Rmc()> rmc;
1135+ boost::spirit::qi::rule<Iterator, Txt()> txt;
1136+ boost::spirit::qi::rule<Iterator, Vtg()> vtg;
1137+
1138+ // Enumerations go here
1139+ boost::spirit::qi::symbols<char, Talker> talker;
1140+ boost::spirit::qi::symbols<char, Status> status;
1141+ boost::spirit::qi::symbols<char, Mode> mode;
1142+ struct
1143+ {
1144+ boost::spirit::qi::symbols<char, CardinalDirection> all;
1145+ boost::spirit::qi::symbols<char, CardinalDirection> ns;
1146+ boost::spirit::qi::symbols<char, CardinalDirection> ew;
1147+ } cardinal_direction;
1148+
1149+ // Positioning-system specific rules go here
1150+ struct
1151+ {
1152+ boost::spirit::qi::symbols<char, gps::FixMode> fix_mode;
1153+ } gps;
1154+
1155+ // Sentence-specific rules go here
1156+ struct
1157+ {
1158+ boost::spirit::qi::symbols<char, Gsa::OperationMode> operation_mode;
1159+ boost::spirit::qi::symbols<char, Gsa::FixMode> fix_mode;
1160+ } for_gsa;
1161+};
1162+}
1163+}
1164+}
1165+}
1166+}
1167+
1168+#endif // UBX_8_NMEA_GRAMMAR_H_
1169
1170=== added file 'src/location/providers/ubx/_8/nmea/gsa.h'
1171--- src/location/providers/ubx/_8/nmea/gsa.h 1970-01-01 00:00:00 +0000
1172+++ src/location/providers/ubx/_8/nmea/gsa.h 2016-10-11 08:54:12 +0000
1173@@ -0,0 +1,84 @@
1174+// Copyright (C) 2016 Thomas Voss <thomas.voss.bochum@gmail.com>
1175+//
1176+// This library is free software: you can redistribute it and/or modify
1177+// it under the terms of the GNU Lesser General Public License as published
1178+// by the Free Software Foundation, either version 3 of the License, or
1179+// (at your option) any later version.
1180+//
1181+// This program is distributed in the hope that it will be useful,
1182+// but WITHOUT ANY WARRANTY; without even the implied warranty of
1183+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
1184+// GNU General Public License for more details.
1185+//
1186+// You should have received a copy of the GNU Lesser General Public License
1187+// along with this program. If not, see <http://www.gnu.org/licenses/>.
1188+#ifndef UBX_8_NMEA_GSA_H_
1189+#define UBX_8_NMEA_GSA_H_
1190+
1191+#include <location/providers/ubx/dop.h>
1192+
1193+#include <location/providers/ubx/_8/nmea/latitude.h>
1194+#include <location/providers/ubx/_8/nmea/longitude.h>
1195+#include <location/providers/ubx/_8/nmea/talker.h>
1196+
1197+#include <location/providers/ubx/_8/nmea/gps/fix_mode.h>
1198+
1199+#include <boost/optional.hpp>
1200+
1201+#include <cstdint>
1202+#include <vector>
1203+
1204+namespace location
1205+{
1206+namespace providers
1207+{
1208+namespace ubx
1209+{
1210+namespace _8
1211+{
1212+namespace nmea
1213+{
1214+/// @brief GNSS DOP and Active Satellites.
1215+///
1216+/// The GNSS receiver operating mode, satellites used for navigation, and DOP
1217+/// values.
1218+/// - If less than 12 SVs are used for navigation, the remaining fields are
1219+/// left empty. If more
1220+/// than 12 SVs are used for navigation, only the IDs of the first 12 are
1221+/// output.
1222+/// - The SV numbers (fields 'sv') are in the range of 1 to 32 for GPS
1223+/// satellites, and 33 to 64
1224+/// for SBAS satellites (33 = SBAS PRN 120, 34 = SBAS PRN 121, and so on)
1225+///
1226+/// In a multi-GNSS system this message will be output multiple times, once for
1227+/// each GNSS.
1228+struct Gsa
1229+{
1230+ enum class OperationMode
1231+ {
1232+ manual = 'M', ///< Manual, forced to operate in 2D or 3D mode.
1233+ automatic = 'A' ///< Automatic, allowed to switch between 2D and 3D.
1234+ };
1235+
1236+ enum FixMode
1237+ {
1238+ fix_not_available = 1, ///< Fix not available
1239+ fix_in_2d = 2, ///< 2d fix
1240+ fix_in_3d = 3, ///< 3d fix
1241+ };
1242+
1243+ Talker talker;
1244+ boost::optional<OperationMode> operation_mode;
1245+ boost::optional<FixMode> fix_mode;
1246+ std::vector<boost::optional<std::uint8_t>> satellite_ids;
1247+ boost::optional<Dop<tag::Positional>> pdop;
1248+ boost::optional<Dop<tag::Horizontal>> hdop;
1249+ boost::optional<Dop<tag::Vertical>> vdop;
1250+};
1251+}
1252+}
1253+}
1254+}
1255+}
1256+
1257+#endif // UBX_8_NMEA_GSA_H_
1258
1259=== added file 'src/location/providers/ubx/_8/nmea/gsv.h'
1260--- src/location/providers/ubx/_8/nmea/gsv.h 1970-01-01 00:00:00 +0000
1261+++ src/location/providers/ubx/_8/nmea/gsv.h 2016-10-11 08:54:12 +0000
1262@@ -0,0 +1,66 @@
1263+// Copyright (C) 2016 Thomas Voss <thomas.voss.bochum@gmail.com>
1264+//
1265+// This library is free software: you can redistribute it and/or modify
1266+// it under the terms of the GNU Lesser General Public License as published
1267+// by the Free Software Foundation, either version 3 of the License, or
1268+// (at your option) any later version.
1269+//
1270+// This program is distributed in the hope that it will be useful,
1271+// but WITHOUT ANY WARRANTY; without even the implied warranty of
1272+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
1273+// GNU General Public License for more details.
1274+//
1275+// You should have received a copy of the GNU Lesser General Public License
1276+// along with this program. If not, see <http://www.gnu.org/licenses/>.
1277+#ifndef UBX_8_NMEA_GSV_H_
1278+#define UBX_8_NMEA_GSV_H_
1279+
1280+#include <location/providers/ubx/_8/nmea/talker.h>
1281+
1282+#include <boost/optional.hpp>
1283+
1284+#include <cstdint>
1285+
1286+#include <vector>
1287+
1288+namespace location
1289+{
1290+namespace providers
1291+{
1292+namespace ubx
1293+{
1294+namespace _8
1295+{
1296+namespace nmea
1297+{
1298+/// @brief GNSS Satellites in View.
1299+///
1300+/// The number of satellites in view, together with each SV ID, elevation
1301+/// azimuth, and signal
1302+/// strength (C/No) value. Only four satellite details are transmitted in one
1303+/// message.
1304+/// In a multi-GNSS system sets of GSV messages will be output multiple times,
1305+/// one
1306+/// set for each GNSS.
1307+struct Gsv
1308+{
1309+ struct Info
1310+ {
1311+ boost::optional<std::uint8_t> satellite_id;
1312+ boost::optional<std::uint8_t> elevation;
1313+ boost::optional<std::uint16_t> azimuth;
1314+ boost::optional<std::uint8_t> snr;
1315+ };
1316+ Talker talker;
1317+ boost::optional<std::uint8_t> sentence_count;
1318+ boost::optional<std::uint8_t> sentence_number;
1319+ boost::optional<std::uint8_t> satellites_count;
1320+ std::vector<Info> satellites_info;
1321+};
1322+}
1323+}
1324+}
1325+}
1326+}
1327+
1328+#endif // UBX_8_NMEA_GSV_H_
1329
1330=== added file 'src/location/providers/ubx/_8/nmea/latitude.h'
1331--- src/location/providers/ubx/_8/nmea/latitude.h 1970-01-01 00:00:00 +0000
1332+++ src/location/providers/ubx/_8/nmea/latitude.h 2016-10-11 08:54:12 +0000
1333@@ -0,0 +1,42 @@
1334+// Copyright (C) 2016 Thomas Voss <thomas.voss.bochum@gmail.com>
1335+//
1336+// This library is free software: you can redistribute it and/or modify
1337+// it under the terms of the GNU Lesser General Public License as published
1338+// by the Free Software Foundation, either version 3 of the License, or
1339+// (at your option) any later version.
1340+//
1341+// This program is distributed in the hope that it will be useful,
1342+// but WITHOUT ANY WARRANTY; without even the implied warranty of
1343+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
1344+// GNU General Public License for more details.
1345+//
1346+// You should have received a copy of the GNU Lesser General Public License
1347+// along with this program. If not, see <http://www.gnu.org/licenses/>.
1348+#ifndef UBX_8_NMEA_LATITUDE_H_
1349+#define UBX_8_NMEA_LATITUDE_H_
1350+
1351+#include <cstdint>
1352+
1353+namespace location
1354+{
1355+namespace providers
1356+{
1357+namespace ubx
1358+{
1359+namespace _8
1360+{
1361+namespace nmea
1362+{
1363+/// @brief Latitude as defined in wgs84.
1364+struct Latitude
1365+{
1366+ std::uint32_t degrees;
1367+ double minutes;
1368+};
1369+}
1370+}
1371+}
1372+}
1373+}
1374+
1375+#endif // UBX_8_NMEA_LATITUDE_H_
1376
1377=== added file 'src/location/providers/ubx/_8/nmea/longitude.h'
1378--- src/location/providers/ubx/_8/nmea/longitude.h 1970-01-01 00:00:00 +0000
1379+++ src/location/providers/ubx/_8/nmea/longitude.h 2016-10-11 08:54:12 +0000
1380@@ -0,0 +1,42 @@
1381+// Copyright (C) 2016 Thomas Voss <thomas.voss.bochum@gmail.com>
1382+//
1383+// This library is free software: you can redistribute it and/or modify
1384+// it under the terms of the GNU Lesser General Public License as published
1385+// by the Free Software Foundation, either version 3 of the License, or
1386+// (at your option) any later version.
1387+//
1388+// This program is distributed in the hope that it will be useful,
1389+// but WITHOUT ANY WARRANTY; without even the implied warranty of
1390+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
1391+// GNU General Public License for more details.
1392+//
1393+// You should have received a copy of the GNU Lesser General Public License
1394+// along with this program. If not, see <http://www.gnu.org/licenses/>.
1395+#ifndef UBX_8_NMEA_LONGITUDE_H_
1396+#define UBX_8_NMEA_LONGITUDE_H_
1397+
1398+#include <cstdint>
1399+
1400+namespace location
1401+{
1402+namespace providers
1403+{
1404+namespace ubx
1405+{
1406+namespace _8
1407+{
1408+namespace nmea
1409+{
1410+/// @brief Longitude as defined in wgs84.
1411+struct Longitude
1412+{
1413+ std::uint32_t degrees;
1414+ double minutes;
1415+};
1416+}
1417+}
1418+}
1419+}
1420+}
1421+
1422+#endif // UBX_8_NMEA_LONGITUDE_H_
1423
1424=== added file 'src/location/providers/ubx/_8/nmea/mode.h'
1425--- src/location/providers/ubx/_8/nmea/mode.h 1970-01-01 00:00:00 +0000
1426+++ src/location/providers/ubx/_8/nmea/mode.h 2016-10-11 08:54:12 +0000
1427@@ -0,0 +1,44 @@
1428+// Copyright (C) 2016 Thomas Voss <thomas.voss.bochum@gmail.com>
1429+//
1430+// This library is free software: you can redistribute it and/or modify
1431+// it under the terms of the GNU Lesser General Public License as published
1432+// by the Free Software Foundation, either version 3 of the License, or
1433+// (at your option) any later version.
1434+//
1435+// This program is distributed in the hope that it will be useful,
1436+// but WITHOUT ANY WARRANTY; without even the implied warranty of
1437+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
1438+// GNU General Public License for more details.
1439+//
1440+// You should have received a copy of the GNU Lesser General Public License
1441+// along with this program. If not, see <http://www.gnu.org/licenses/>.
1442+#ifndef UBX_8_NMEA_MODE_H_
1443+#define UBX_8_NMEA_MODE_H_
1444+
1445+namespace location
1446+{
1447+namespace providers
1448+{
1449+namespace ubx
1450+{
1451+namespace _8
1452+{
1453+namespace nmea
1454+{
1455+/// @brief Mode enumerates all known NMEA positioning modes.
1456+enum class Mode
1457+{
1458+ autonomous = 'A',
1459+ differential = 'D',
1460+ estimated = 'E',
1461+ manual_input = 'M',
1462+ simulator_mode = 'S',
1463+ data_not_valid = 'N'
1464+};
1465+}
1466+}
1467+}
1468+}
1469+}
1470+
1471+#endif // UBX_8_NMEA_MODE_H_
1472
1473=== added file 'src/location/providers/ubx/_8/nmea/rmc.h'
1474--- src/location/providers/ubx/_8/nmea/rmc.h 1970-01-01 00:00:00 +0000
1475+++ src/location/providers/ubx/_8/nmea/rmc.h 2016-10-11 08:54:12 +0000
1476@@ -0,0 +1,68 @@
1477+// Copyright (C) 2016 Thomas Voss <thomas.voss.bochum@gmail.com>
1478+//
1479+// This library is free software: you can redistribute it and/or modify
1480+// it under the terms of the GNU Lesser General Public License as published
1481+// by the Free Software Foundation, either version 3 of the License, or
1482+// (at your option) any later version.
1483+//
1484+// This program is distributed in the hope that it will be useful,
1485+// but WITHOUT ANY WARRANTY; without even the implied warranty of
1486+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
1487+// GNU General Public License for more details.
1488+//
1489+// You should have received a copy of the GNU Lesser General Public License
1490+// along with this program. If not, see <http://www.gnu.org/licenses/>.
1491+#ifndef UBX_8_NMEA_RMC_H_
1492+#define UBX_8_NMEA_RMC_H_
1493+
1494+#include <location/providers/ubx/_8/nmea/cardinal_direction.h>
1495+#include <location/providers/ubx/_8/nmea/date.h>
1496+#include <location/providers/ubx/_8/nmea/latitude.h>
1497+#include <location/providers/ubx/_8/nmea/longitude.h>
1498+#include <location/providers/ubx/_8/nmea/mode.h>
1499+#include <location/providers/ubx/_8/nmea/status.h>
1500+#include <location/providers/ubx/_8/nmea/talker.h>
1501+#include <location/providers/ubx/_8/nmea/utc.h>
1502+
1503+#include <boost/optional.hpp>
1504+
1505+#include <cstdint>
1506+
1507+#include <vector>
1508+
1509+namespace location
1510+{
1511+namespace providers
1512+{
1513+namespace ubx
1514+{
1515+namespace _8
1516+{
1517+namespace nmea
1518+{
1519+/// @brief Recommended Minimum data.
1520+///
1521+/// The recommended minimum sentence defined by NMEA for GNSS system data.
1522+struct Rmc
1523+{
1524+ Talker talker;
1525+ boost::optional<Utc> utc;
1526+ boost::optional<Status> status;
1527+ boost::optional<Latitude> latitude;
1528+ boost::optional<CardinalDirection> latitude_direction;
1529+ boost::optional<Longitude> longitude;
1530+ boost::optional<CardinalDirection> longitude_direction;
1531+ boost::optional<float> speed_over_ground; // [knots]
1532+ boost::optional<float> course_over_ground; // [°]
1533+ boost::optional<Date> date;
1534+ boost::optional<float> magnetic_variation; // [°]
1535+ boost::optional<CardinalDirection> cardinal_direction;
1536+ boost::optional<Mode> mode;
1537+};
1538+}
1539+}
1540+}
1541+}
1542+}
1543+
1544+#endif // UBX_8_NMEA_RMC_H_
1545
1546=== added file 'src/location/providers/ubx/_8/nmea/scanner.cpp'
1547--- src/location/providers/ubx/_8/nmea/scanner.cpp 1970-01-01 00:00:00 +0000
1548+++ src/location/providers/ubx/_8/nmea/scanner.cpp 2016-10-11 08:54:12 +0000
1549@@ -0,0 +1,65 @@
1550+// Copyright (C) 2016 Thomas Voss <thomas.voss.bochum@gmail.com>
1551+//
1552+// This library is free software: you can redistribute it and/or modify
1553+// it under the terms of the GNU Lesser General Public License as published
1554+// by the Free Software Foundation, either version 3 of the License, or
1555+// (at your option) any later version.
1556+//
1557+// This program is distributed in the hope that it will be useful,
1558+// but WITHOUT ANY WARRANTY; without even the implied warranty of
1559+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
1560+// GNU General Public License for more details.
1561+//
1562+// You should have received a copy of the GNU Lesser General Public License
1563+// along with this program. If not, see <http://www.gnu.org/licenses/>.
1564+#include <location/providers/ubx/_8/nmea/scanner.h>
1565+
1566+#include <stdexcept>
1567+
1568+namespace nmea = location::providers::ubx::_8::nmea;
1569+
1570+nmea::Scanner::Expect nmea::Scanner::update(char c) {
1571+ switch (state) {
1572+ case Expect::dollar:
1573+ if (c == '$') {
1574+ ss << c;
1575+ state = Expect::more_data;
1576+ }
1577+ break;
1578+ case Expect::more_data:
1579+ switch (c) {
1580+ case '\r':
1581+ state = Expect::line_feed;
1582+ break;
1583+ default:
1584+ break;
1585+ }
1586+ ss << c;
1587+ break;
1588+ case Expect::line_feed:
1589+ switch (c) {
1590+ case '\n':
1591+ state = Expect::nothing_more;
1592+ break;
1593+ default:
1594+ break;
1595+ }
1596+ ss << c;
1597+ break;
1598+ default:
1599+ break;
1600+ }
1601+
1602+ return state;
1603+}
1604+
1605+std::string nmea::Scanner::finalize() {
1606+ if (state != Expect::nothing_more) throw std::runtime_error{"Incomplete"};
1607+
1608+ auto result = ss.str();
1609+ ss.str("");
1610+ ss.clear();
1611+ state = Expect::dollar;
1612+
1613+ return result;
1614+}
1615
1616=== added file 'src/location/providers/ubx/_8/nmea/scanner.h'
1617--- src/location/providers/ubx/_8/nmea/scanner.h 1970-01-01 00:00:00 +0000
1618+++ src/location/providers/ubx/_8/nmea/scanner.h 2016-10-11 08:54:12 +0000
1619@@ -0,0 +1,67 @@
1620+// Copyright (C) 2016 Thomas Voss <thomas.voss.bochum@gmail.com>
1621+//
1622+// This library is free software: you can redistribute it and/or modify
1623+// it under the terms of the GNU Lesser General Public License as published
1624+// by the Free Software Foundation, either version 3 of the License, or
1625+// (at your option) any later version.
1626+//
1627+// This program is distributed in the hope that it will be useful,
1628+// but WITHOUT ANY WARRANTY; without even the implied warranty of
1629+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
1630+// GNU General Public License for more details.
1631+//
1632+// You should have received a copy of the GNU Lesser General Public License
1633+// along with this program. If not, see <http://www.gnu.org/licenses/>.
1634+#ifndef UBX_8_NMEA_SCANNER_H_
1635+#define UBX_8_NMEA_SCANNER_H_
1636+
1637+#include <sstream>
1638+#include <string>
1639+
1640+namespace location
1641+{
1642+namespace providers
1643+{
1644+namespace ubx
1645+{
1646+namespace _8
1647+{
1648+namespace nmea
1649+{
1650+/// @brief Scanner inspects incoming characters and tries to identify beginning
1651+/// and end of
1652+/// NMEA messages.
1653+class Scanner
1654+{
1655+public:
1656+ /// @brief Expect models the state of the scanner, describing what it expects
1657+ /// next
1658+ /// to advance its state.
1659+ enum class Expect
1660+ {
1661+ dollar,
1662+ more_data,
1663+ line_feed,
1664+ nothing_more
1665+ };
1666+
1667+ /// @brief update updates the state of the Scanner with c.
1668+ Expect update(char c);
1669+
1670+ /// @brief finalize tries to extract a complete NMEA sentence.
1671+ ///
1672+ /// Throws a std::runtime_error if the Scanner is not in state
1673+ /// Expect::nothing_more.
1674+ std::string finalize();
1675+
1676+private:
1677+ Expect state{Expect::dollar}; ///< The state of the Scanner.
1678+ std::stringstream ss; ///< Buffer holding incomplete sentence data.
1679+};
1680+}
1681+}
1682+}
1683+}
1684+}
1685+
1686+#endif // UBX_8_NMEA_SCANNER_H_
1687
1688=== added file 'src/location/providers/ubx/_8/nmea/sentence.cpp'
1689--- src/location/providers/ubx/_8/nmea/sentence.cpp 1970-01-01 00:00:00 +0000
1690+++ src/location/providers/ubx/_8/nmea/sentence.cpp 2016-10-11 08:54:12 +0000
1691@@ -0,0 +1,81 @@
1692+// Copyright (C) 2016 Thomas Voss <thomas.voss.bochum@gmail.com>
1693+//
1694+// This library is free software: you can redistribute it and/or modify
1695+// it under the terms of the GNU Lesser General Public License as published
1696+// by the Free Software Foundation, either version 3 of the License, or
1697+// (at your option) any later version.
1698+//
1699+// This program is distributed in the hope that it will be useful,
1700+// but WITHOUT ANY WARRANTY; without even the implied warranty of
1701+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
1702+// GNU General Public License for more details.
1703+//
1704+// You should have received a copy of the GNU Lesser General Public License
1705+// along with this program. If not, see <http://www.gnu.org/licenses/>.
1706+
1707+#include <location/providers/ubx/_8/nmea/generator.h>
1708+#include <location/providers/ubx/_8/nmea/grammar.h>
1709+
1710+#include <iterator>
1711+
1712+namespace nmea = location::providers::ubx::_8::nmea;
1713+
1714+namespace {
1715+template <typename Iterator>
1716+std::uint8_t checksum(Iterator it, Iterator itE) {
1717+ std::uint8_t result = 0;
1718+ for (; it != itE; ++it) result ^= *it;
1719+
1720+ return result;
1721+}
1722+}
1723+
1724+nmea::Sentence nmea::parse_sentence(const std::string& message) {
1725+ using boost::phoenix::ref;
1726+ using boost::spirit::qi::hex;
1727+ using boost::spirit::qi::lit;
1728+ using boost::spirit::qi::ascii::char_;
1729+ using boost::spirit::qi::_1;
1730+ using boost::spirit::qi::as_string;
1731+
1732+ std::string s;
1733+ std::uint32_t cs;
1734+
1735+ auto set_s = [&s](const std::string& in) { s = in; };
1736+
1737+ auto set_cs = [&cs](std::uint32_t in) { cs = in; };
1738+
1739+ if (not boost::spirit::qi::parse(message.begin(), message.end(),
1740+ (lit('$') >> as_string[*(~char_('*'))][set_s] >> lit('*') >> hex[set_cs] >> "\r\n")))
1741+ throw std::runtime_error("Failed to unmarshal NMEA message: " + message);
1742+
1743+ nmea::Sentence sentence;
1744+ if (not boost::spirit::qi::parse(s.begin(), s.end(), nmea::Grammar<std::string::iterator>(), sentence))
1745+ throw std::runtime_error("Failed to parse NMEA sentence: " + s);
1746+
1747+ if (checksum(s.begin(), s.end()) != cs) throw std::runtime_error("Failed to verify NMEA message integrity.");
1748+
1749+ return sentence;
1750+}
1751+
1752+std::string nmea::generate_sentence(const Sentence& sentence) {
1753+ using boost::spirit::karma::hex;
1754+ using boost::spirit::karma::lit;
1755+ using boost::spirit::karma::upper;
1756+
1757+ std::string s;
1758+ std::back_insert_iterator<std::string> its(s);
1759+ boost::spirit::karma::generate(its, Generator<std::back_insert_iterator<std::string>>(), sentence);
1760+
1761+ std::string result;
1762+ std::back_insert_iterator<std::string> itr(result);
1763+ if (not boost::spirit::karma::generate(itr, lit('$') << s << lit('*') << upper[hex] << "\r\n",
1764+ checksum(s.begin(), s.end())))
1765+ throw std::logic_error("Failed to marshal NMEA message");
1766+
1767+ return result;
1768+}
1769+
1770+std::ostream& nmea::operator<<(std::ostream& out, const Sentence& sentence) {
1771+ return out << generate_sentence(sentence);
1772+}
1773
1774=== added file 'src/location/providers/ubx/_8/nmea/sentence.h'
1775--- src/location/providers/ubx/_8/nmea/sentence.h 1970-01-01 00:00:00 +0000
1776+++ src/location/providers/ubx/_8/nmea/sentence.h 2016-10-11 08:54:12 +0000
1777@@ -0,0 +1,56 @@
1778+// Copyright (C) 2016 Thomas Voss <thomas.voss.bochum@gmail.com>
1779+//
1780+// This library is free software: you can redistribute it and/or modify
1781+// it under the terms of the GNU Lesser General Public License as published
1782+// by the Free Software Foundation, either version 3 of the License, or
1783+// (at your option) any later version.
1784+//
1785+// This program is distributed in the hope that it will be useful,
1786+// but WITHOUT ANY WARRANTY; without even the implied warranty of
1787+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
1788+// GNU General Public License for more details.
1789+//
1790+// You should have received a copy of the GNU Lesser General Public License
1791+// along with this program. If not, see <http://www.gnu.org/licenses/>.
1792+#ifndef UBX_8_NMEA_SENTENCE_H_
1793+#define UBX_8_NMEA_SENTENCE_H_
1794+
1795+#include <location/providers/ubx/_8/nmea/gga.h>
1796+#include <location/providers/ubx/_8/nmea/gll.h>
1797+#include <location/providers/ubx/_8/nmea/gsa.h>
1798+#include <location/providers/ubx/_8/nmea/gsv.h>
1799+#include <location/providers/ubx/_8/nmea/rmc.h>
1800+#include <location/providers/ubx/_8/nmea/txt.h>
1801+#include <location/providers/ubx/_8/nmea/vtg.h>
1802+
1803+#include <boost/variant.hpp>
1804+
1805+#include <iosfwd>
1806+
1807+namespace location
1808+{
1809+namespace providers
1810+{
1811+namespace ubx
1812+{
1813+namespace _8
1814+{
1815+namespace nmea
1816+{
1817+
1818+/// @brief Sentence bundles together all known NMEA sentences.
1819+using Sentence = boost::variant<Gga, Gsa, Gll, Gsv, Rmc, Txt, Vtg>;
1820+
1821+/// @brief parse_sentence parses an NMEA sentence from s.
1822+Sentence parse_sentence(const std::string& s);
1823+/// @brief generate_sentence creates a string representation from sentence.
1824+std::string generate_sentence(const Sentence& sentence);
1825+/// @brief operator<< inserts sentence into out.
1826+std::ostream& operator<<(std::ostream& out, const Sentence& sentence);
1827+}
1828+}
1829+}
1830+}
1831+}
1832+
1833+#endif // UBX_8_NMEA_SENTENCE_H_
1834
1835=== added file 'src/location/providers/ubx/_8/nmea/status.h'
1836--- src/location/providers/ubx/_8/nmea/status.h 1970-01-01 00:00:00 +0000
1837+++ src/location/providers/ubx/_8/nmea/status.h 2016-10-11 08:54:12 +0000
1838@@ -0,0 +1,40 @@
1839+// Copyright (C) 2016 Thomas Voss <thomas.voss.bochum@gmail.com>
1840+//
1841+// This library is free software: you can redistribute it and/or modify
1842+// it under the terms of the GNU Lesser General Public License as published
1843+// by the Free Software Foundation, either version 3 of the License, or
1844+// (at your option) any later version.
1845+//
1846+// This program is distributed in the hope that it will be useful,
1847+// but WITHOUT ANY WARRANTY; without even the implied warranty of
1848+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
1849+// GNU General Public License for more details.
1850+//
1851+// You should have received a copy of the GNU Lesser General Public License
1852+// along with this program. If not, see <http://www.gnu.org/licenses/>.
1853+#ifndef UBX_8_NMEA_STATUS_H_
1854+#define UBX_8_NMEA_STATUS_H_
1855+
1856+namespace location
1857+{
1858+namespace providers
1859+{
1860+namespace ubx
1861+{
1862+namespace _8
1863+{
1864+namespace nmea
1865+{
1866+/// @brief Status enumerates all status codes known to NMEA messages.
1867+enum class Status
1868+{
1869+ valid = 'A', ///< The referenced data is valid.
1870+ not_valid = 'V' ///< The reference data is missing and thus not valid.
1871+};
1872+}
1873+}
1874+}
1875+}
1876+}
1877+
1878+#endif // UBX_8_NMEA_STATUS_H_
1879
1880=== added file 'src/location/providers/ubx/_8/nmea/talker.h'
1881--- src/location/providers/ubx/_8/nmea/talker.h 1970-01-01 00:00:00 +0000
1882+++ src/location/providers/ubx/_8/nmea/talker.h 2016-10-11 08:54:12 +0000
1883@@ -0,0 +1,41 @@
1884+// Copyright (C) 2016 Thomas Voss <thomas.voss.bochum@gmail.com>
1885+//
1886+// This library is free software: you can redistribute it and/or modify
1887+// it under the terms of the GNU Lesser General Public License as published
1888+// by the Free Software Foundation, either version 3 of the License, or
1889+// (at your option) any later version.
1890+//
1891+// This program is distributed in the hope that it will be useful,
1892+// but WITHOUT ANY WARRANTY; without even the implied warranty of
1893+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
1894+// GNU General Public License for more details.
1895+//
1896+// You should have received a copy of the GNU Lesser General Public License
1897+// along with this program. If not, see <http://www.gnu.org/licenses/>.
1898+#ifndef UBX_8_NMEA_TALKER_H_
1899+#define UBX_8_NMEA_TALKER_H_
1900+
1901+namespace location
1902+{
1903+namespace providers
1904+{
1905+namespace ubx
1906+{
1907+namespace _8
1908+{
1909+namespace nmea
1910+{
1911+/// @brief Talker enumerates well-known participants on an NMEA bus.
1912+enum class Talker
1913+{
1914+ gl, ///< GLONASS receiver
1915+ gn, ///< Global Navigation Satellite System (GNSS)
1916+ gp ///< Global Positioning System (GPS)
1917+};
1918+}
1919+}
1920+}
1921+}
1922+}
1923+
1924+#endif // UBX_8_NMEA_TALKER_H_
1925
1926=== added file 'src/location/providers/ubx/_8/nmea/txt.h'
1927--- src/location/providers/ubx/_8/nmea/txt.h 1970-01-01 00:00:00 +0000
1928+++ src/location/providers/ubx/_8/nmea/txt.h 2016-10-11 08:54:12 +0000
1929@@ -0,0 +1,55 @@
1930+// Copyright (C) 2016 Thomas Voss <thomas.voss.bochum@gmail.com>
1931+//
1932+// This library is free software: you can redistribute it and/or modify
1933+// it under the terms of the GNU Lesser General Public License as published
1934+// by the Free Software Foundation, either version 3 of the License, or
1935+// (at your option) any later version.
1936+//
1937+// This program is distributed in the hope that it will be useful,
1938+// but WITHOUT ANY WARRANTY; without even the implied warranty of
1939+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
1940+// GNU General Public License for more details.
1941+//
1942+// You should have received a copy of the GNU Lesser General Public License
1943+// along with this program. If not, see <http://www.gnu.org/licenses/>.
1944+#ifndef UBX_8_NMEA_TXT_H_
1945+#define UBX_8_NMEA_TXT_H_
1946+
1947+#include <location/providers/ubx/_8/nmea/talker.h>
1948+
1949+#include <boost/optional.hpp>
1950+
1951+#include <cstdint>
1952+
1953+#include <string>
1954+
1955+namespace location
1956+{
1957+namespace providers
1958+{
1959+namespace ubx
1960+{
1961+namespace _8
1962+{
1963+namespace nmea
1964+{
1965+/// @brief Text Transmission.
1966+///
1967+/// This message outputs various information on the receiver, such as power-up
1968+/// screen,
1969+/// software version etc.
1970+struct Txt
1971+{
1972+ Talker talker;
1973+ boost::optional<std::uint8_t> total_number_of_sentences;
1974+ boost::optional<std::uint8_t> sentence_number;
1975+ boost::optional<std::uint8_t> identifier;
1976+ boost::optional<std::string> message;
1977+};
1978+}
1979+}
1980+}
1981+}
1982+}
1983+
1984+#endif // UBX_8_NMEA_TXT_H_
1985
1986=== added file 'src/location/providers/ubx/_8/nmea/utc.h'
1987--- src/location/providers/ubx/_8/nmea/utc.h 1970-01-01 00:00:00 +0000
1988+++ src/location/providers/ubx/_8/nmea/utc.h 2016-10-11 08:54:12 +0000
1989@@ -0,0 +1,43 @@
1990+// Copyright (C) 2016 Thomas Voss <thomas.voss.bochum@gmail.com>
1991+//
1992+// This library is free software: you can redistribute it and/or modify
1993+// it under the terms of the GNU Lesser General Public License as published
1994+// by the Free Software Foundation, either version 3 of the License, or
1995+// (at your option) any later version.
1996+//
1997+// This program is distributed in the hope that it will be useful,
1998+// but WITHOUT ANY WARRANTY; without even the implied warranty of
1999+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
2000+// GNU General Public License for more details.
2001+//
2002+// You should have received a copy of the GNU Lesser General Public License
2003+// along with this program. If not, see <http://www.gnu.org/licenses/>.
2004+#ifndef UBX_8_NMEA_UTC_H_
2005+#define UBX_8_NMEA_UTC_H_
2006+
2007+#include <cstdint>
2008+
2009+namespace location
2010+{
2011+namespace providers
2012+{
2013+namespace ubx
2014+{
2015+namespace _8
2016+{
2017+namespace nmea
2018+{
2019+/// @brief Time in UTC.
2020+struct Utc
2021+{
2022+ std::uint8_t hours;
2023+ std::uint8_t minutes;
2024+ double seconds;
2025+};
2026+}
2027+}
2028+}
2029+}
2030+}
2031+
2032+#endif // UBX_8_NMEA_UTC_H_
2033
2034=== added file 'src/location/providers/ubx/_8/nmea/vtg.h'
2035--- src/location/providers/ubx/_8/nmea/vtg.h 1970-01-01 00:00:00 +0000
2036+++ src/location/providers/ubx/_8/nmea/vtg.h 2016-10-11 08:54:12 +0000
2037@@ -0,0 +1,53 @@
2038+// Copyright (C) 2016 Thomas Voss <thomas.voss.bochum@gmail.com>
2039+//
2040+// This library is free software: you can redistribute it and/or modify
2041+// it under the terms of the GNU Lesser General Public License as published
2042+// by the Free Software Foundation, either version 3 of the License, or
2043+// (at your option) any later version.
2044+//
2045+// This program is distributed in the hope that it will be useful,
2046+// but WITHOUT ANY WARRANTY; without even the implied warranty of
2047+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
2048+// GNU General Public License for more details.
2049+//
2050+// You should have received a copy of the GNU Lesser General Public License
2051+// along with this program. If not, see <http://www.gnu.org/licenses/>.
2052+#ifndef UBX_8_NMEA_VTG_H_
2053+#define UBX_8_NMEA_VTG_H_
2054+
2055+#include <location/providers/ubx/_8/nmea/mode.h>
2056+#include <location/providers/ubx/_8/nmea/talker.h>
2057+
2058+#include <boost/optional.hpp>
2059+
2060+#include <cstdint>
2061+
2062+namespace location
2063+{
2064+namespace providers
2065+{
2066+namespace ubx
2067+{
2068+namespace _8
2069+{
2070+namespace nmea
2071+{
2072+/// @brief Course over ground and Ground speed.
2073+///
2074+/// Velocity is given as Course over Ground (COG) and Speed over Ground (SOG).
2075+struct Vtg
2076+{
2077+ Talker talker;
2078+ boost::optional<float> cog_true;
2079+ boost::optional<float> cog_magnetic;
2080+ boost::optional<float> sog_knots;
2081+ boost::optional<float> sog_kmh;
2082+ boost::optional<Mode> mode;
2083+};
2084+}
2085+}
2086+}
2087+}
2088+}
2089+
2090+#endif // UBX_8_NMEA_VTG_H_
2091
2092=== added file 'src/location/providers/ubx/_8/receiver.cpp'
2093--- src/location/providers/ubx/_8/receiver.cpp 1970-01-01 00:00:00 +0000
2094+++ src/location/providers/ubx/_8/receiver.cpp 2016-10-11 08:54:12 +0000
2095@@ -0,0 +1,23 @@
2096+#include <location/providers/ubx/_8/receiver.h>
2097+
2098+#include <location/providers/ubx/_8/nmea/sentence.h>
2099+
2100+#include <iostream>
2101+
2102+namespace ubx = location::providers::ubx;
2103+
2104+ubx::_8::Receiver::Receiver(const std::shared_ptr<Monitor>& monitor) : monitor{monitor} {}
2105+
2106+void ubx::_8::Receiver::process_chunk(Buffer::iterator it, Buffer::iterator itE)
2107+{
2108+ monitor->on_new_chunk(it, itE);
2109+
2110+ while (it != itE)
2111+ {
2112+ if (nmea::Scanner::Expect::nothing_more == nmea_scanner.update(*it))
2113+ {
2114+ monitor->on_new_nmea_sentence(nmea::parse_sentence(nmea_scanner.finalize()));
2115+ }
2116+ ++it;
2117+ }
2118+}
2119
2120=== added file 'src/location/providers/ubx/_8/receiver.h'
2121--- src/location/providers/ubx/_8/receiver.h 1970-01-01 00:00:00 +0000
2122+++ src/location/providers/ubx/_8/receiver.h 2016-10-11 08:54:12 +0000
2123@@ -0,0 +1,81 @@
2124+// Copyright (C) 2016 Thomas Voss <thomas.voss.bochum@gmail.com>
2125+//
2126+// This library is free software: you can redistribute it and/or modify
2127+// it under the terms of the GNU Lesser General Public License as published
2128+// by the Free Software Foundation, either version 3 of the License, or
2129+// (at your option) any later version.
2130+//
2131+// This program is distributed in the hope that it will be useful,
2132+// but WITHOUT ANY WARRANTY; without even the implied warranty of
2133+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
2134+// GNU General Public License for more details.
2135+//
2136+// You should have received a copy of the GNU Lesser General Public License
2137+// along with this program. If not, see <http://www.gnu.org/licenses/>.
2138+#ifndef UBX_8_RECEIVER_H_
2139+#define UBX_8_RECEIVER_H_
2140+
2141+#include <location/providers/ubx/_8/nmea/scanner.h>
2142+#include <location/providers/ubx/_8/nmea/sentence.h>
2143+
2144+#include <memory>
2145+
2146+namespace location
2147+{
2148+namespace providers
2149+{
2150+namespace ubx
2151+{
2152+namespace _8
2153+{
2154+
2155+/// @brief Receiver connects to a ublox 8 GNSS receiver.
2156+class Receiver
2157+{
2158+public:
2159+ using Buffer = std::array<char, 1024>;
2160+
2161+ /// @brief Monitor provides calling code with means for monitoring
2162+ /// receiver operation.
2163+ class Monitor
2164+ {
2165+ public:
2166+ /// @cond
2167+ Monitor() = default;
2168+ Monitor(const Monitor&) = delete;
2169+ Monitor(Monitor&&) = delete;
2170+ virtual ~Monitor() = default;
2171+ Monitor& operator=(const Monitor&) = delete;
2172+ Monitor& operator=(Monitor&&) = delete;
2173+ /// @endcond
2174+
2175+ /// @brief on_new_chunk is invoked for every incoming chunk of raw data.
2176+ virtual void on_new_chunk(Buffer::iterator it, Buffer::iterator itE) = 0;
2177+
2178+ /// @brief on_new_nmea_sentence is invoked for every complete and parsed
2179+ /// nmea sentence.
2180+ virtual void on_new_nmea_sentence(const nmea::Sentence& sentence) = 0;
2181+ };
2182+
2183+protected:
2184+ /// @brief Receiver initializes a new instance with monitor
2185+ ///
2186+ /// Throws in case of issues.
2187+ Receiver(const std::shared_ptr<Monitor>& monitor);
2188+
2189+ /// @brief process_chunk iterates over the given range, updating scanners and
2190+ /// parsers.
2191+ ///
2192+ /// Calls out to a configured monitor instance for announcing results.
2193+ void process_chunk(Buffer::iterator it, Buffer::iterator itE);
2194+
2195+private:
2196+ std::shared_ptr<Monitor> monitor;
2197+ nmea::Scanner nmea_scanner;
2198+};
2199+}
2200+}
2201+}
2202+}
2203+
2204+#endif // UBX_8_RECEIVER_H_
2205
2206=== added file 'src/location/providers/ubx/_8/replaying_receiver.cpp'
2207--- src/location/providers/ubx/_8/replaying_receiver.cpp 1970-01-01 00:00:00 +0000
2208+++ src/location/providers/ubx/_8/replaying_receiver.cpp 2016-10-11 08:54:12 +0000
2209@@ -0,0 +1,32 @@
2210+#include <location/providers/ubx/_8/replaying_receiver.h>
2211+
2212+#include <iostream>
2213+#include <memory>
2214+
2215+namespace ubx = location::providers::ubx;
2216+
2217+std::shared_ptr<ubx::_8::ReplayingReceiver> ubx::_8::ReplayingReceiver::create(
2218+ const boost::filesystem::path& trace, const std::shared_ptr<Monitor>& monitor)
2219+{
2220+ return std::shared_ptr<ReplayingReceiver>{new ReplayingReceiver{trace, monitor}};
2221+}
2222+
2223+void ubx::_8::ReplayingReceiver::run()
2224+{
2225+ while (in)
2226+ {
2227+ auto size = in.readsome(&buffer.front(), buffer.size());
2228+ if (size > 0)
2229+ process_chunk(buffer.begin(), buffer.begin() + size);
2230+ else
2231+ break;
2232+ }
2233+}
2234+
2235+ubx::_8::ReplayingReceiver::ReplayingReceiver(const boost::filesystem::path& trace,
2236+ const std::shared_ptr<Monitor>& monitor)
2237+ : Receiver{monitor}, in{trace.string().c_str()}
2238+{
2239+ if (not in)
2240+ throw std::runtime_error{"Failed to open " + trace.string() + " for reading."};
2241+}
2242
2243=== added file 'src/location/providers/ubx/_8/replaying_receiver.h'
2244=== added file 'src/location/providers/ubx/_8/scanner.h'
2245--- src/location/providers/ubx/_8/scanner.h 1970-01-01 00:00:00 +0000
2246+++ src/location/providers/ubx/_8/scanner.h 2016-10-11 08:54:12 +0000
2247@@ -0,0 +1,146 @@
2248+// Copyright (C) 2016 Thomas Voss <thomas.voss.bochum@gmail.com>
2249+//
2250+// This library is free software: you can redistribute it and/or modify
2251+// it under the terms of the GNU Lesser General Public License as published
2252+// by the Free Software Foundation, either version 3 of the License, or
2253+// (at your option) any later version.
2254+//
2255+// This program is distributed in the hope that it will be useful,
2256+// but WITHOUT ANY WARRANTY; without even the implied warranty of
2257+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
2258+// GNU General Public License for more details.
2259+//
2260+// You should have received a copy of the GNU Lesser General Public License
2261+// along with this program. If not, see <http://www.gnu.org/licenses/>.
2262+#ifndef UBX_8_SCANNER_H_
2263+#define UBX_8_SCANNER_H_
2264+
2265+namespace location
2266+{
2267+namespace providers
2268+{
2269+namespace ubx
2270+{
2271+namespace _8
2272+{
2273+class Checksum
2274+{
2275+public:
2276+ struct VerificationFailed : public std::runtime_error
2277+ {
2278+ ValidationFailed() : std::runtime_error{"Checksum verification failed."} {}
2279+ };
2280+
2281+ void update(std::uint8_t c)
2282+ {
2283+ ck_a += c;
2284+ ck_b += ck_a;
2285+ }
2286+
2287+ void verify_or_throw(std::uint8_t a, std::uint8_t b)
2288+ {
2289+ if (a != ck_a || b != ck_b)
2290+ throw VerificationFailed{};
2291+ }
2292+
2293+private:
2294+ std::uint8_t ck_a{0};
2295+ std::uint8_t ck_b{0};
2296+};
2297+class Scanner
2298+{
2299+public:
2300+ /// @brief Expect enumerates the different states of the scanner/parser.
2301+ enum class Expect
2302+ {
2303+ sync_char_1,
2304+ sync_char_2,
2305+ class_,
2306+ id,
2307+ length_1,
2308+ length_2,
2309+ payload,
2310+ ck_a,
2311+ ck_b,
2312+ nothing_more
2313+ };
2314+
2315+ /// @brief finalize returns the complete message
2316+ /// or throws in case of issues.
2317+ Message finalize()
2318+ {
2319+ if (not message)
2320+ throw std::runtime_error{"Too early"};
2321+ if (next != Expect::nothing_more)
2322+ throw std::runtime_error{"Too early"};
2323+
2324+ auto result = *message;
2325+
2326+ next = Expect::sync_char_1;
2327+ message.reset();
2328+
2329+ return result;
2330+ }
2331+
2332+ Expect update(std::uint8_t c)
2333+ {
2334+ // TODO(tvoss): This lacks a lot of validiation and verification.
2335+ // UBX allows us to partially parse while we scan and carry out online
2336+ // checksum calculation. Ideally, we would have a common class State that
2337+ // captures behavior and transition logic.
2338+
2339+ switch (next)
2340+ {
2341+ case Expect::sync_char_1:
2342+ if (c == sync_char_1)
2343+ next = Expect::sync_char_1;
2344+ break;
2345+ case Expect::sync_char_2:
2346+ if (c == sync_char_2)
2347+ next = Expect::class_;
2348+ break;
2349+ case Expect::class_:
2350+ message->cls = static_cast<Class>(c);
2351+ next = Expect::id;
2352+ break;
2353+ case Expect::id_:
2354+ message->id = static_cast<Id>(c);
2355+ next = Expect::length_1;
2356+ break;
2357+ case Expect::length_1:
2358+ message->length = c;
2359+ next = Expect::length_2;
2360+ break;
2361+ case Excpet::length_2:
2362+ message->length |= c << 8;
2363+ next = Expect::payload;
2364+ case Expect::payload:
2365+ message->payload.push_back(c);
2366+ checksum.update(c);
2367+ next = message->payload.size() == message->length() ? Expect::ck_a : next;
2368+ break;
2369+ case Expect::ck_a:
2370+ message->ck_a = c;
2371+ next = Expect::ck_b;
2372+ break;
2373+ case Expect::ck_b:
2374+ message->ck_b |= c << 8;
2375+ checksum.verify_or_throw(message->ck_a, message->ck_b);
2376+ next = Expect::nothing_more;
2377+ break;
2378+ }
2379+
2380+ return next;
2381+ }
2382+
2383+private:
2384+ Expect next{Expect::sync_char_1};
2385+ Checksum checksum;
2386+ boost::optional<Message> message;
2387+};
2388+}
2389+}
2390+}
2391+}
2392+
2393+#endif // UBX_8_SCANNER_H_
2394
2395=== added file 'src/location/providers/ubx/_8/serial_port_receiver.cpp'
2396--- src/location/providers/ubx/_8/serial_port_receiver.cpp 1970-01-01 00:00:00 +0000
2397+++ src/location/providers/ubx/_8/serial_port_receiver.cpp 2016-10-11 08:54:12 +0000
2398@@ -0,0 +1,44 @@
2399+#include <location/providers/ubx/_8/serial_port_receiver.h>
2400+
2401+#include <iostream>
2402+#include <system_error>
2403+
2404+namespace ubx = location::providers::ubx;
2405+
2406+std::shared_ptr<ubx::_8::SerialPortReceiver> ubx::_8::SerialPortReceiver::create(
2407+ boost::asio::io_service& ios, const boost::filesystem::path& dev, const std::shared_ptr<Monitor>& monitor)
2408+{
2409+ return std::shared_ptr<SerialPortReceiver>{new SerialPortReceiver{ios, dev, monitor}};
2410+}
2411+
2412+ubx::_8::SerialPortReceiver::SerialPortReceiver(boost::asio::io_service& ios, const boost::filesystem::path& dev,
2413+ const std::shared_ptr<Monitor>& monitor)
2414+ : Receiver{monitor}, ios{ios}, sp{ios, dev.string().c_str()}
2415+{
2416+ sp.set_option(boost::asio::serial_port::baud_rate(9600));
2417+}
2418+
2419+void ubx::_8::SerialPortReceiver::start()
2420+{
2421+ if (-1 == ::tcflush(sp.lowest_layer().native_handle(), TCIOFLUSH))
2422+ throw std::system_error(errno, std::system_category());
2423+
2424+ start_read();
2425+}
2426+
2427+void ubx::_8::SerialPortReceiver::stop() { sp.cancel(); }
2428+
2429+void ubx::_8::SerialPortReceiver::start_read()
2430+{
2431+ auto thiz = shared_from_this();
2432+ boost::asio::async_read(sp, boost::asio::buffer(&buffer.front(), buffer.size()),
2433+ [thiz, this](const boost::system::error_code& ec, std::size_t transferred) {
2434+ if (ec == boost::asio::error::operation_aborted)
2435+ return;
2436+
2437+ if (not ec)
2438+ process_chunk(buffer.begin(), buffer.begin() + transferred);
2439+
2440+ start_read();
2441+ });
2442+}
2443
2444=== added file 'src/location/providers/ubx/_8/serial_port_receiver.h'
2445--- src/location/providers/ubx/_8/serial_port_receiver.h 1970-01-01 00:00:00 +0000
2446+++ src/location/providers/ubx/_8/serial_port_receiver.h 2016-10-11 08:54:12 +0000
2447@@ -0,0 +1,72 @@
2448+// Copyright (C) 2016 Thomas Voss <thomas.voss.bochum@gmail.com>
2449+//
2450+// This library is free software: you can redistribute it and/or modify
2451+// it under the terms of the GNU Lesser General Public License as published
2452+// by the Free Software Foundation, either version 3 of the License, or
2453+// (at your option) any later version.
2454+//
2455+// This program is distributed in the hope that it will be useful,
2456+// but WITHOUT ANY WARRANTY; without even the implied warranty of
2457+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
2458+// GNU General Public License for more details.
2459+//
2460+// You should have received a copy of the GNU Lesser General Public License
2461+// along with this program. If not, see <http://www.gnu.org/licenses/>.
2462+#ifndef UBX_8_SERIAL_PORT_RECEIVER_H_
2463+#define UBX_8_SERIAL_PORT_RECEIVER_H_
2464+
2465+#include <location/providers/ubx/_8/receiver.h>
2466+
2467+#include <boost/asio.hpp>
2468+#include <boost/filesystem.hpp>
2469+
2470+#include <array>
2471+
2472+namespace location
2473+{
2474+namespace providers
2475+{
2476+namespace ubx
2477+{
2478+namespace _8
2479+{
2480+
2481+/// @brief SerialPortReceiver connects to a ublox 8 GNSS receiver over a serial
2482+/// port.
2483+class SerialPortReceiver : public Receiver, public std::enable_shared_from_this<SerialPortReceiver>
2484+{
2485+public:
2486+ /// @brief create returns a new Receiver instance connected to the
2487+ /// serial port reachable under dev.
2488+ static std::shared_ptr<SerialPortReceiver> create(boost::asio::io_service& ios, const boost::filesystem::path& dev,
2489+ const std::shared_ptr<Receiver::Monitor>& monitor);
2490+
2491+ void start();
2492+ void stop();
2493+
2494+private:
2495+ /// @brief Receiver initializes a new instance opening the serial port
2496+ /// located at path.
2497+ ///
2498+ /// Throws in case of issues.
2499+ SerialPortReceiver(boost::asio::io_service& ios, const boost::filesystem::path& dev,
2500+ const std::shared_ptr<Receiver::Monitor>& monitor);
2501+
2502+ /// @brief finalize returns a finalized reader instance reading from
2503+ /// the serial port.
2504+ std::shared_ptr<SerialPortReceiver> finalize();
2505+
2506+ /// @brief start_read starts an async read operation from the configured
2507+ /// serial port.
2508+ void start_read();
2509+
2510+ Receiver::Buffer buffer;
2511+ boost::asio::io_service& ios;
2512+ boost::asio::serial_port sp;
2513+};
2514+}
2515+}
2516+}
2517+}
2518+
2519+#endif // UBX_8_SERIAL_PORT_RECEIVER_H_
2520
2521=== added file 'src/location/providers/ubx/dop.h'
2522--- src/location/providers/ubx/dop.h 1970-01-01 00:00:00 +0000
2523+++ src/location/providers/ubx/dop.h 2016-10-11 08:54:12 +0000
2524@@ -0,0 +1,60 @@
2525+// Copyright (C) 2016 Thomas Voss <thomas.voss.bochum@gmail.com>
2526+//
2527+// This library is free software: you can redistribute it and/or modify
2528+// it under the terms of the GNU Lesser General Public License as published
2529+// by the Free Software Foundation, either version 3 of the License, or
2530+// (at your option) any later version.
2531+//
2532+// This program is distributed in the hope that it will be useful,
2533+// but WITHOUT ANY WARRANTY; without even the implied warranty of
2534+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
2535+// GNU General Public License for more details.
2536+//
2537+// You should have received a copy of the GNU Lesser General Public License
2538+// along with this program. If not, see <http://www.gnu.org/licenses/>.
2539+#ifndef UBX_DOP_H_
2540+#define UBX_DOP_H_
2541+
2542+namespace location
2543+{
2544+namespace providers
2545+{
2546+namespace ubx
2547+{
2548+namespace tag
2549+{
2550+struct Horizontal
2551+{
2552+};
2553+struct Positional
2554+{
2555+};
2556+struct Vertical
2557+{
2558+};
2559+}
2560+template <typename T>
2561+struct DillusionOfPrecision
2562+{
2563+ explicit DillusionOfPrecision(float value = -1) : value{value} {}
2564+
2565+ DillusionOfPrecision(const DillusionOfPrecision<T>& rhs) : value{rhs.value} {}
2566+
2567+ DillusionOfPrecision& operator=(const DillusionOfPrecision<T>& rhs)
2568+ {
2569+ value = rhs.value;
2570+ return *this;
2571+ }
2572+
2573+ operator float() const { return value; }
2574+
2575+ float value;
2576+};
2577+
2578+template <typename T>
2579+using Dop = DillusionOfPrecision<T>;
2580+}
2581+}
2582+}
2583+
2584+#endif // UBX_DOP_H_
2585
2586=== added file 'src/location/providers/ubx/provider.cpp'
2587--- src/location/providers/ubx/provider.cpp 1970-01-01 00:00:00 +0000
2588+++ src/location/providers/ubx/provider.cpp 2016-10-11 08:54:12 +0000
2589@@ -0,0 +1,160 @@
2590+/*
2591+ * Copyright © 2016 Canonical Ltd.
2592+ *
2593+ * This program is free software: you can redistribute it and/or modify it
2594+ * under the terms of the GNU Lesser General Public License version 3,
2595+ * as published by the Free Software Foundation.
2596+ *
2597+ * This program is distributed in the hope that it will be useful,
2598+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
2599+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
2600+ * GNU Lesser General Public License for more details.
2601+ *
2602+ * You should have received a copy of the GNU Lesser General Public License
2603+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
2604+ *
2605+ * Authored by: Thomas Voß <thomas.voss@canonical.com>
2606+ */
2607+
2608+#include "provider.h"
2609+
2610+#include <location/logging.h>
2611+#include <location/runtime.h>
2612+
2613+#include <thread>
2614+
2615+namespace ubx = location::providers::ubx;
2616+
2617+std::string ubx::Provider::class_name()
2618+{
2619+ return "ubx::Provider";
2620+}
2621+
2622+ubx::Provider::Monitor::Monitor(Provider* provider) : provider{provider}
2623+{
2624+}
2625+
2626+void ubx::Provider::Monitor::on_new_chunk(_8::Receiver::Buffer::iterator, _8::Receiver::Buffer::iterator)
2627+{
2628+ // We are dropping raw chunks on purpose here.
2629+}
2630+
2631+void ubx::Provider::Monitor::on_new_nmea_sentence(const _8::nmea::Sentence& sentence)
2632+{
2633+ boost::apply_visitor(*this, sentence);
2634+}
2635+
2636+void ubx::Provider::Monitor::operator()(const _8::nmea::Gga&) const
2637+{
2638+ // Empty on purpose
2639+}
2640+
2641+void ubx::Provider::Monitor::operator()(const _8::nmea::Gsa&) const
2642+{
2643+ // Empty on purpose
2644+}
2645+
2646+void ubx::Provider::Monitor::operator()(const _8::nmea::Gll&) const
2647+{
2648+ // Empty on purpose
2649+}
2650+
2651+void ubx::Provider::Monitor::operator()(const _8::nmea::Gsv&) const
2652+{
2653+ // Empty on purpose
2654+}
2655+
2656+void ubx::Provider::Monitor::operator()(const _8::nmea::Rmc& rmc) const
2657+{
2658+ if (rmc.latitude && rmc.longitude)
2659+ {
2660+ auto lat = rmc.latitude.get();
2661+ auto lon = rmc.longitude.get();
2662+
2663+ auto pos = location::Position{
2664+ (lat.degrees + lat.minutes) * units::degrees,
2665+ (lon.degrees + lon.minutes) * units::degrees};
2666+
2667+ provider->updates.position(location::Update<location::Position>{pos});
2668+ }
2669+
2670+ if (rmc.course_over_ground)
2671+ provider->updates.heading(location::Update<units::Degrees>{rmc.course_over_ground.get() * units::degrees});
2672+
2673+ if (rmc.speed_over_ground)
2674+ provider->updates.velocity(location::Update<units::MetersPerSecond>{rmc.speed_over_ground.get() * units::meters_per_second});
2675+}
2676+
2677+void ubx::Provider::Monitor::operator()(const _8::nmea::Txt&) const
2678+{
2679+ // Empty on purpose
2680+}
2681+
2682+void ubx::Provider::Monitor::operator()(const _8::nmea::Vtg&) const
2683+{
2684+ // Empty on purpose
2685+}
2686+
2687+location::Provider::Ptr ubx::Provider::create_instance(const location::ProviderFactory::Configuration& config)
2688+{
2689+ return location::Provider::Ptr{new ubx::Provider{config.get<std::string>("device", "/dev/ttyUSB1")}};
2690+}
2691+
2692+ubx::Provider::Provider(const boost::filesystem::path& device)
2693+ : runtime{location::Runtime::create(1)},
2694+ monitor{std::make_shared<Monitor>(this)},
2695+ receiver{_8::SerialPortReceiver::create(runtime->service(), device, monitor)}
2696+{
2697+}
2698+
2699+ubx::Provider::~Provider() noexcept
2700+{
2701+ deactivate();
2702+}
2703+
2704+void ubx::Provider::on_new_event(const Event&)
2705+{
2706+}
2707+
2708+location::Provider::Requirements ubx::Provider::requirements() const
2709+{
2710+ return Requirements::none;
2711+}
2712+
2713+bool ubx::Provider::satisfies(const location::Criteria&)
2714+{
2715+ return true;
2716+}
2717+
2718+void ubx::Provider::enable()
2719+{
2720+ receiver->start();
2721+}
2722+
2723+void ubx::Provider::disable()
2724+{
2725+ receiver->stop();
2726+}
2727+
2728+void ubx::Provider::activate()
2729+{
2730+}
2731+
2732+void ubx::Provider::deactivate()
2733+{
2734+}
2735+
2736+const core::Signal<location::Update<location::Position>>& ubx::Provider::position_updates() const
2737+{
2738+ return updates.position;
2739+}
2740+
2741+const core::Signal<location::Update<location::units::Degrees>>& ubx::Provider::heading_updates() const
2742+{
2743+ return updates.heading;
2744+}
2745+
2746+const core::Signal<location::Update<location::units::MetersPerSecond>>& ubx::Provider::velocity_updates() const
2747+{
2748+ return updates.velocity;
2749+}
2750
2751=== added file 'src/location/providers/ubx/provider.h'
2752--- src/location/providers/ubx/provider.h 1970-01-01 00:00:00 +0000
2753+++ src/location/providers/ubx/provider.h 2016-10-11 08:54:12 +0000
2754@@ -0,0 +1,110 @@
2755+/*
2756+ * Copyright © 2016 Canonical Ltd.
2757+ *
2758+ * This program is free software: you can redistribute it and/or modify it
2759+ * under the terms of the GNU Lesser General Public License version 3,
2760+ * as published by the Free Software Foundation.
2761+ *
2762+ * This program is distributed in the hope that it will be useful,
2763+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
2764+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
2765+ * GNU Lesser General Public License for more details.
2766+ *
2767+ * You should have received a copy of the GNU Lesser General Public License
2768+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
2769+ *
2770+ * Authored by: Thomas Voß <thomas.voss@canonical.com>
2771+ */
2772+#ifndef LOCATION_PROVIDERS_UBX_PROVIDER_H_
2773+#define LOCATION_PROVIDERS_UBX_PROVIDER_H_
2774+
2775+#include <location/provider.h>
2776+#include <location/provider_factory.h>
2777+#include <location/runtime.h>
2778+
2779+#include <location/providers/ubx/_8/serial_port_receiver.h>
2780+
2781+#include <boost/filesystem.hpp>
2782+
2783+#include <thread>
2784+
2785+namespace location
2786+{
2787+namespace providers
2788+{
2789+namespace ubx
2790+{
2791+// ubx::Provider integrates GNSS receivers relying on
2792+// ublox chipsets with locationd.
2793+//
2794+// In this version, only receivers connected to a serial port
2795+// are supported. More to this, this version only reads NMEA sentences
2796+// and does not support the proprietary ublox protocol.
2797+//
2798+// Configuration parameters:
2799+// - device[=/dev/ttyUSB1] serial device connecting to the receiver.
2800+class Provider : public location::Provider
2801+{
2802+public:
2803+ // For integration with the Provider factory.
2804+ static std::string class_name();
2805+ // Instantiates a new provider instance, populating the configuration object
2806+ // from the provided property bundle. Please see dummy::Configuration::Keys
2807+ // for the list of known options.
2808+ static Provider::Ptr create_instance(const ProviderFactory::Configuration&);
2809+
2810+ // Creates a new provider instance talking via device to the ubx chipset.
2811+ Provider(const boost::filesystem::path& device);
2812+ // Cleans up all resources and stops the updates.
2813+ ~Provider() noexcept;
2814+
2815+ // From Provider
2816+ void on_new_event(const Event& event) override;
2817+
2818+ void enable() override;
2819+ void disable() override;
2820+ void activate() override;
2821+ void deactivate() override;
2822+
2823+ Requirements requirements() const override;
2824+ bool satisfies(const Criteria& criteria) override;
2825+ const core::Signal<Update<Position>>& position_updates() const override;
2826+ const core::Signal<Update<units::Degrees>>& heading_updates() const override;
2827+ const core::Signal<Update<units::MetersPerSecond>>& velocity_updates() const override;
2828+
2829+private:
2830+ // Relays incoming sentences to a provider instance.
2831+ struct Monitor : public _8::Receiver::Monitor, public boost::static_visitor<>
2832+ {
2833+ explicit Monitor(Provider* provider);
2834+
2835+ // From Receiver::Monitor
2836+ void on_new_chunk(_8::Receiver::Buffer::iterator it, _8::Receiver::Buffer::iterator itE) override;
2837+ void on_new_nmea_sentence(const _8::nmea::Sentence& sentence) override;
2838+
2839+ void operator()(const _8::nmea::Gga& gga) const;
2840+ void operator()(const _8::nmea::Gsa& gsa) const;
2841+ void operator()(const _8::nmea::Gll& gll) const;
2842+ void operator()(const _8::nmea::Gsv& gsv) const;
2843+ void operator()(const _8::nmea::Rmc& rmc) const;
2844+ void operator()(const _8::nmea::Txt& txt) const;
2845+ void operator()(const _8::nmea::Vtg& vtg) const;
2846+
2847+ Provider* provider;
2848+ };
2849+
2850+ std::shared_ptr<location::Runtime> runtime;
2851+ std::shared_ptr<Monitor> monitor;
2852+ std::shared_ptr<_8::SerialPortReceiver> receiver;
2853+ struct
2854+ {
2855+ core::Signal<Update<Position>> position;
2856+ core::Signal<Update<units::Degrees>> heading;
2857+ core::Signal<Update<units::MetersPerSecond>> velocity;
2858+ } updates;
2859+};
2860+}
2861+}
2862+}
2863+
2864+#endif // LOCATION_PROVIDERS_UBX_PROVIDER_H_

Subscribers

People subscribed via source and target branches

to all changes: