Merge lp:~thomas-voss/location-service/enable-assist-now-online into lp:location-service
- enable-assist-now-online
- Merge into next
Proposed by
Thomas Voß
Status: | Merged |
---|---|
Approved by: | Thomas Voß |
Approved revision: | 299 |
Merged at revision: | 297 |
Proposed branch: | lp:~thomas-voss/location-service/enable-assist-now-online |
Merge into: | lp:location-service |
Prerequisite: | lp:~thomas-voss/location-service/enable-ublox-protocol |
Diff against target: |
1717 lines (+1011/-196) 24 files modified
prebuilt/meta/hooks/configure (+15/-0) snapcraft.yaml (+5/-2) src/location/cmds/run.cpp (+4/-0) src/location/cmds/test.cpp (+9/-1) src/location/cmds/test.h (+3/-0) src/location/providers/ubx/CMakeLists.txt (+4/-1) src/location/providers/ubx/_8/assist_now_online_client.cpp (+160/-0) src/location/providers/ubx/_8/assist_now_online_client.h (+105/-0) src/location/providers/ubx/_8/cfg/rst.cpp (+43/-0) src/location/providers/ubx/_8/cfg/rst.h (+84/-0) src/location/providers/ubx/_8/gnss_id.cpp (+10/-3) src/location/providers/ubx/_8/gnss_id.h (+1/-0) src/location/providers/ubx/_8/message.h (+2/-0) src/location/providers/ubx/_8/nmea/scanner.cpp (+2/-2) src/location/providers/ubx/_8/receiver.cpp (+32/-3) src/location/providers/ubx/_8/receiver.h (+4/-4) src/location/providers/ubx/_8/scanner.cpp (+17/-11) src/location/providers/ubx/_8/scanner.h (+3/-0) src/location/providers/ubx/_8/serial_port_receiver.cpp (+32/-20) src/location/providers/ubx/_8/serial_port_receiver.h (+8/-2) src/location/providers/ubx/provider.cpp (+290/-117) src/location/providers/ubx/provider.h (+53/-23) src/location/runtime_tests.cpp (+123/-6) src/location/runtime_tests.h (+2/-1) |
To merge this branch: | bzr merge lp:~thomas-voss/location-service/enable-assist-now-online |
Related bugs: |
Reviewer | Review Type | Date Requested | Status |
---|---|---|---|
Simon Fels (community) | Approve | ||
Thomas Voß | Pending | ||
Review via email: mp+320795@code.launchpad.net |
Commit message
Enable AssistNow for ublox 8 receivers.
Support assisted GNSS scenarios and add infrastructure to
query the ublox AssistNow online service.
Description of the change
Enable AssistNow for ublox 8 receivers.
Support assisted GNSS scenarios and add infrastructure to
query the ublox AssistNow online service.
To post a comment you must log in.
Revision history for this message
Simon Fels (morphis) : | # |
review:
Needs Fixing
- 297. By Thomas Voß
-
Document dropping of exceptions in Receiver:
:process_ chunk.
- 298. By Thomas Voß
-
Introduce locationd.test to the snap.
- 299. By Thomas Voß
-
Fix a couple of issues found during testing.
- 300. By Thomas Voß
-
Make the number of trials in testing configurable via an env variable.
Preview Diff
[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1 | === modified file 'prebuilt/meta/hooks/configure' |
2 | --- prebuilt/meta/hooks/configure 2017-01-09 09:16:58 +0000 |
3 | +++ prebuilt/meta/hooks/configure 2017-03-29 20:24:25 +0000 |
4 | @@ -4,3 +4,18 @@ |
5 | mkdir -p $SNAP_DATA/ubx/provider |
6 | echo "$path" > $SNAP_DATA/ubx/provider/path |
7 | fi |
8 | + |
9 | +if enable=$(snapctl get ubx.provider.assistnow.enable); then |
10 | + mkdir -p $SNAP_DATA/ubx/provider/assist_now |
11 | + echo "$enable" > $SNAP_DATA/ubx/provider/assist_now/enable |
12 | +fi |
13 | + |
14 | +if token=$(snapctl get ubx.provider.assistnow.token); then |
15 | + mkdir -p $SNAP_DATA/ubx/provider/assist_now |
16 | + echo "$token" > $SNAP_DATA/ubx/provider/assist_now/token |
17 | +fi |
18 | + |
19 | +if timeout=$(snapctl get ubx.provider.assistnow.acquisition_timeout); then |
20 | + mkdir -p $SNAP_DATA/ubx/provider/assist_now |
21 | + echo "$timeout" > $SNAP_DATA/ubx/provider/assist_now/acquisition_timeout |
22 | +fi |
23 | |
24 | === modified file 'snapcraft.yaml' |
25 | --- snapcraft.yaml 2017-03-07 10:01:34 +0000 |
26 | +++ snapcraft.yaml 2017-03-29 20:24:25 +0000 |
27 | @@ -12,7 +12,7 @@ |
28 | daemon: simple |
29 | command: bin/locationd run --bus=system |
30 | slots: [service-control, service-observe] |
31 | - plugs: [ubx, network-manager] |
32 | + plugs: [ubx, network, network-manager] |
33 | list-providers: |
34 | command: bin/locationd list |
35 | status: |
36 | @@ -23,7 +23,10 @@ |
37 | plugs: [client-control, client-observe] |
38 | provide: |
39 | command: bin/locationd provider --bus=system |
40 | - plugs: [client-control] |
41 | + plugs: [client-control, network] |
42 | + test: |
43 | + command: bin/locationd test |
44 | + plugs: [ubx, network] |
45 | |
46 | slots: |
47 | service-observe: |
48 | |
49 | === modified file 'src/location/cmds/run.cpp' |
50 | --- src/location/cmds/run.cpp 2017-03-09 10:07:56 +0000 |
51 | +++ src/location/cmds/run.cpp 2017-03-29 20:24:25 +0000 |
52 | @@ -74,6 +74,10 @@ |
53 | { |
54 | engine->add_provider(location::providers::ubx::Provider::create_instance(ProviderFactory::Configuration{})); |
55 | } |
56 | + catch (const std::exception& e) |
57 | + { |
58 | + ctxt.cout << "Error adding UBX provider: " << e.what() << std::endl; |
59 | + } |
60 | catch (...) |
61 | { |
62 | ctxt.cout << "Error adding UBX provider." << std::endl; |
63 | |
64 | === modified file 'src/location/cmds/test.cpp' |
65 | --- src/location/cmds/test.cpp 2016-06-30 09:15:49 +0000 |
66 | +++ src/location/cmds/test.cpp 2017-03-29 20:24:25 +0000 |
67 | @@ -25,8 +25,16 @@ |
68 | location::cmds::Test::Test() |
69 | : CommandWithFlagsAndAction{cli::Name{"test"}, cli::Usage{"test"}, cli::Description{"executes runtime tests against the gps provider."}} |
70 | { |
71 | + flag(cli::make_flag(cli::Name{"test-suite"}, cli::Description{"test-suite that should be executed"}, test_suite)); |
72 | + |
73 | action([this](const Context& ctxt) |
74 | { |
75 | - return location::execute_runtime_tests(ctxt.cout, ctxt.cout); |
76 | + if (not test_suite) |
77 | + { |
78 | + ctxt.cout << "Missing parameter test-suite." << std::endl; |
79 | + return EXIT_FAILURE; |
80 | + } |
81 | + |
82 | + return execute_runtime_tests(*test_suite, ctxt.cout, ctxt.cout); |
83 | }); |
84 | } |
85 | |
86 | === modified file 'src/location/cmds/test.h' |
87 | --- src/location/cmds/test.h 2016-08-24 14:12:05 +0000 |
88 | +++ src/location/cmds/test.h 2017-03-29 20:24:25 +0000 |
89 | @@ -35,6 +35,9 @@ |
90 | public: |
91 | // List initializes a new instance. |
92 | Test(); |
93 | + |
94 | +private: |
95 | + Optional<std::string> test_suite; // The test suite that should be executed. |
96 | }; |
97 | } |
98 | } |
99 | |
100 | === modified file 'src/location/providers/ubx/CMakeLists.txt' |
101 | --- src/location/providers/ubx/CMakeLists.txt 2017-03-29 20:24:25 +0000 |
102 | +++ src/location/providers/ubx/CMakeLists.txt 2017-03-29 20:24:25 +0000 |
103 | @@ -7,6 +7,8 @@ |
104 | |
105 | bits.h |
106 | |
107 | + _8/assist_now_online_client.h |
108 | + _8/assist_now_online_client.cpp |
109 | _8/checksum.h |
110 | _8/checksum.cpp |
111 | _8/gnss_id.h |
112 | @@ -25,11 +27,12 @@ |
113 | _8/ack/ack.cpp |
114 | _8/ack/nak.h |
115 | _8/ack/nak.cpp |
116 | - _8/cfg/cfg.h |
117 | _8/cfg/gnss.h |
118 | _8/cfg/gnss.cpp |
119 | _8/cfg/msg.h |
120 | _8/cfg/msg.cpp |
121 | + _8/cfg/rst.h |
122 | + _8/cfg/rst.cpp |
123 | _8/nav/pvt.h |
124 | _8/nav/pvt.cpp |
125 | _8/nav/sat.h |
126 | |
127 | === added file 'src/location/providers/ubx/_8/assist_now_online_client.cpp' |
128 | --- src/location/providers/ubx/_8/assist_now_online_client.cpp 1970-01-01 00:00:00 +0000 |
129 | +++ src/location/providers/ubx/_8/assist_now_online_client.cpp 2017-03-29 20:24:25 +0000 |
130 | @@ -0,0 +1,160 @@ |
131 | +// Copyright (C) 2017 Thomas Voss <thomas.voss.bochum@gmail.com> |
132 | +// |
133 | +// This library is free software: you can redistribute it and/or modify |
134 | +// it under the terms of the GNU Lesser General Public License as published |
135 | +// by the Free Software Foundation, either version 3 of the License, or |
136 | +// (at your option) any later version. |
137 | +// |
138 | +// This program is distributed in the hope that it will be useful, |
139 | +// but WITHOUT ANY WARRANTY; without even the implied warranty of |
140 | +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
141 | +// GNU General Public License for more details. |
142 | +// |
143 | +// You should have received a copy of the GNU Lesser General Public License |
144 | +// along with this program. If not, see <http://www.gnu.org/licenses/>. |
145 | + |
146 | +#include <location/providers/ubx/_8/assist_now_online_client.h> |
147 | + |
148 | +#include <core/net/uri.h> |
149 | +#include <core/net/http/response.h> |
150 | + |
151 | +#include <iostream> |
152 | + |
153 | +namespace _8 = location::providers::ubx::_8; |
154 | +namespace http = core::net::http; |
155 | + |
156 | +namespace |
157 | +{ |
158 | + |
159 | +template<typename T> |
160 | +std::string join(const std::set<T>& set) |
161 | +{ |
162 | + std::stringstream ss; bool first = true; |
163 | + |
164 | + for (auto element : set) |
165 | + { |
166 | + if (!first) |
167 | + ss << ","; |
168 | + |
169 | + ss << element; |
170 | + first = false; |
171 | + } |
172 | + |
173 | + return ss.str(); |
174 | +} |
175 | + |
176 | +template<typename T, typename U> |
177 | +std::string join(const std::set<std::pair<T, U>>& set) |
178 | +{ |
179 | + std::stringstream ss; bool first = true; |
180 | + |
181 | + for (auto element : set) |
182 | + { |
183 | + if (!first) |
184 | + ss << ","; |
185 | + |
186 | + ss << element.first << ":" << element.second; |
187 | + first = false; |
188 | + } |
189 | + |
190 | + return ss.str(); |
191 | +} |
192 | + |
193 | +} // namespace |
194 | + |
195 | +_8::AssistNowOnlineClient::AssistNowOnlineClient(const std::shared_ptr<http::Client>& http_client) |
196 | + : http_client{http_client}, worker{[this]() { _8::AssistNowOnlineClient::http_client->run(); }} |
197 | +{ |
198 | +} |
199 | + |
200 | +_8::AssistNowOnlineClient::~AssistNowOnlineClient() |
201 | +{ |
202 | + http_client->stop(); |
203 | + if (worker.joinable()) |
204 | + worker.join(); |
205 | +} |
206 | + |
207 | +void _8::AssistNowOnlineClient::request_assistance_data(const Parameters& parameters, const std::function<void(const Result<std::string>&)>& cb) |
208 | +{ |
209 | + core::net::Uri::QueryParameters query |
210 | + { |
211 | + {"gnss", join(parameters.gnss)}, |
212 | + {"datatype", join(parameters.data_types)} |
213 | + }; |
214 | + |
215 | + if (parameters.filter_on_pos) |
216 | + query.push_back({"filteronpos", "notstrictlyneeded"}); |
217 | + |
218 | + if (!parameters.filter_on_svs.empty()) |
219 | + query.push_back({"filteronsvs", join(parameters.filter_on_svs)}); |
220 | + |
221 | + if (parameters.position) |
222 | + { |
223 | + const auto& position = parameters.position.get(); |
224 | + query.push_back({"lat", std::to_string(position.latitude().value())}); |
225 | + query.push_back({"lon", std::to_string(position.longitude().value())}); |
226 | + |
227 | + if (position.altitude()) |
228 | + { |
229 | + const auto& altitude = position.altitude().get(); |
230 | + query.push_back({"alt", std::to_string(altitude.value())}); |
231 | + } |
232 | + |
233 | + if (position.accuracy().horizontal()) |
234 | + { |
235 | + const auto& accuracy = position.accuracy().horizontal().get(); |
236 | + query.push_back({"pacc", std::to_string(accuracy.value())}); |
237 | + } |
238 | + } |
239 | + |
240 | + auto uri = service_url + parameters.token; |
241 | + for (const auto& param : query) |
242 | + uri += (boost::format("&%1%=%2%") % param.first % param.second).str(); |
243 | + |
244 | + auto request = http_client->get(http::Request::Configuration::from_uri_as_string(uri)); |
245 | + http::Request::Handler handler; |
246 | + |
247 | + handler.on_response([cb](const http::Response& response) |
248 | + { |
249 | + if (response.status == http::Status::ok) |
250 | + cb(make_result(response.body)); |
251 | + else |
252 | + cb(make_error_result<std::string>( |
253 | + std::make_exception_ptr( |
254 | + std::runtime_error{response.body}))); |
255 | + }); |
256 | + |
257 | + handler.on_error([cb](const core::net::Error& error) |
258 | + { |
259 | + cb(make_error_result<std::string>(std::make_exception_ptr(error))); |
260 | + }); |
261 | + |
262 | + request->async_execute(handler); |
263 | +} |
264 | + |
265 | +bool _8::operator<(AssistNowOnlineClient::DataType lhs, AssistNowOnlineClient::DataType rhs) |
266 | +{ |
267 | + using UT = typename std::underlying_type<AssistNowOnlineClient::DataType>::type; |
268 | + return static_cast<UT>(lhs) < static_cast<UT>(rhs); |
269 | +} |
270 | + |
271 | +std::ostream& _8::operator<<(std::ostream& out, AssistNowOnlineClient::DataType rhs) |
272 | +{ |
273 | + switch (rhs) |
274 | + { |
275 | + case AssistNowOnlineClient::DataType::almanac: |
276 | + out << "alm"; |
277 | + break; |
278 | + case AssistNowOnlineClient::DataType::ephemeris: |
279 | + out << "eph"; |
280 | + break; |
281 | + case AssistNowOnlineClient::DataType::position: |
282 | + out << "pos"; |
283 | + break; |
284 | + case AssistNowOnlineClient::DataType::aux: |
285 | + out << "aux"; |
286 | + break; |
287 | + } |
288 | + |
289 | + return out; |
290 | +} |
291 | |
292 | === added file 'src/location/providers/ubx/_8/assist_now_online_client.h' |
293 | --- src/location/providers/ubx/_8/assist_now_online_client.h 1970-01-01 00:00:00 +0000 |
294 | +++ src/location/providers/ubx/_8/assist_now_online_client.h 2017-03-29 20:24:25 +0000 |
295 | @@ -0,0 +1,105 @@ |
296 | +// Copyright (C) 2017 Thomas Voss <thomas.voss.bochum@gmail.com> |
297 | +// |
298 | +// This library is free software: you can redistribute it and/or modify |
299 | +// it under the terms of the GNU Lesser General Public License as published |
300 | +// by the Free Software Foundation, either version 3 of the License, or |
301 | +// (at your option) any later version. |
302 | +// |
303 | +// This program is distributed in the hope that it will be useful, |
304 | +// but WITHOUT ANY WARRANTY; without even the implied warranty of |
305 | +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
306 | +// GNU General Public License for more details. |
307 | +// |
308 | +// You should have received a copy of the GNU Lesser General Public License |
309 | +// along with this program. If not, see <http://www.gnu.org/licenses/>. |
310 | + |
311 | +#ifndef UBX_8_ASSIST_NOW_ONLINE_CLIENT_H_ |
312 | +#define UBX_8_ASSIST_NOW_ONLINE_CLIENT_H_ |
313 | + |
314 | +#include <location/providers/ubx/_8/gnss_id.h> |
315 | + |
316 | +#include <location/optional.h> |
317 | +#include <location/position.h> |
318 | +#include <location/result.h> |
319 | + |
320 | +#include <core/net/http/client.h> |
321 | + |
322 | +#include <chrono> |
323 | +#include <cstdint> |
324 | +#include <iosfwd> |
325 | +#include <set> |
326 | +#include <string> |
327 | +#include <thread> |
328 | + |
329 | +namespace location |
330 | +{ |
331 | +namespace providers |
332 | +{ |
333 | +namespace ubx |
334 | +{ |
335 | +namespace _8 |
336 | +{ |
337 | + |
338 | +class AssistNowOnlineClient |
339 | +{ |
340 | +public: |
341 | + static constexpr const char* service_url{"http://online-live1.services.u-blox.com/GetOnlineData.ashx?token="}; |
342 | + |
343 | + enum class DataType |
344 | + { |
345 | + ephemeris = 0, |
346 | + almanac = 1, |
347 | + aux = 2, |
348 | + position = 3 |
349 | + }; |
350 | + |
351 | + struct Parameters |
352 | + { |
353 | + // The authorization token supplied by u-blox when a client registers to |
354 | + // use the service. |
355 | + std::string token; |
356 | + // List of the GNSS for which data should be |
357 | + // returned. Valid GNSS are: GnssId::gps, GnssId::qzss and GnssId::glonass. |
358 | + std::set<GnssId> gnss; |
359 | + // List of data types required by the client. |
360 | + std::set<DataType> data_types; |
361 | + // Approximate user latitude, longitude and altitude in WGS 84 expressed in degrees and |
362 | + // fractional degrees. |
363 | + Optional<Position> position; |
364 | + // The timing accuracy (see time parameters note below). |
365 | + Optional<std::chrono::seconds> time_accuracy; |
366 | + // Typical latency between the time the server receives the request, and |
367 | + // the time when the assistance data arrives at the u-blox receiver. The |
368 | + // server can use this value to correct the time being transmitted to the |
369 | + // client. |
370 | + Optional<std::chrono::seconds> latency; |
371 | + // If set to true, the ephemeris data returned to the client will only contain |
372 | + // data for the satellites which are likely to be visible from the |
373 | + // approximate position provided by the lat, lon, alt and pacc parameters. |
374 | + bool filter_on_pos = false; |
375 | + // List of u-blox gnssId:svId pairs. The ephemeris data |
376 | + // returned to the client will only contain data for the listed satellites. |
377 | + std::set<std::pair<GnssId, std::uint32_t>> filter_on_svs; |
378 | + }; |
379 | + |
380 | + explicit AssistNowOnlineClient(const std::shared_ptr<core::net::http::Client>& http_client); |
381 | + ~AssistNowOnlineClient(); |
382 | + |
383 | + // request_asisstance_data reaches out to the AssistNow service via the configured http client |
384 | + // with parameters, reporting the assistance data blob to cb (on success). |
385 | + void request_assistance_data(const Parameters& parameters, const std::function<void(const Result<std::string>&)>& cb); |
386 | + |
387 | +private: |
388 | + std::shared_ptr<core::net::http::Client> http_client; |
389 | + std::thread worker; |
390 | +}; |
391 | + |
392 | +bool operator<(AssistNowOnlineClient::DataType lhs, AssistNowOnlineClient::DataType rhs); |
393 | +std::ostream& operator<<(std::ostream& out, AssistNowOnlineClient::DataType rhs); |
394 | + |
395 | +} // namespace _8 |
396 | +} // namespace ubx |
397 | +} // namespace providers |
398 | +} // namepsace location |
399 | + |
400 | +#endif // UBX_8_ASSIST_NOW_ONLINE_CLIENT_H_ |
401 | |
402 | === added file 'src/location/providers/ubx/_8/cfg/rst.cpp' |
403 | --- src/location/providers/ubx/_8/cfg/rst.cpp 1970-01-01 00:00:00 +0000 |
404 | +++ src/location/providers/ubx/_8/cfg/rst.cpp 2017-03-29 20:24:25 +0000 |
405 | @@ -0,0 +1,43 @@ |
406 | +// Copyright (C) 2016 Thomas Voss <thomas.voss.bochum@gmail.com> |
407 | +// |
408 | +// This library is free software: you can redistribute it and/or modify |
409 | +// it under the terms of the GNU Lesser General Public License as published |
410 | +// by the Free Software Foundation, either version 3 of the License, or |
411 | +// (at your option) any later version. |
412 | +// |
413 | +// This program is distributed in the hope that it will be useful, |
414 | +// but WITHOUT ANY WARRANTY; without even the implied warranty of |
415 | +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
416 | +// GNU General Public License for more details. |
417 | +// |
418 | +// You should have received a copy of the GNU Lesser General Public License |
419 | +// along with this program. If not, see <http://www.gnu.org/licenses/>. |
420 | + |
421 | +#include <location/providers/ubx/_8/cfg/rst.h> |
422 | + |
423 | +#include <location/providers/ubx/bits.h> |
424 | +#include <location/providers/ubx/_8/writer.h> |
425 | + |
426 | +#include <cstdint> |
427 | +#include <iostream> |
428 | + |
429 | +namespace cfg = location::providers::ubx::_8::cfg; |
430 | + |
431 | +std::size_t cfg::Rst::size() const |
432 | +{ |
433 | + return 4; |
434 | +} |
435 | + |
436 | +void cfg::Rst::write(Writer& writer) const |
437 | +{ |
438 | + writer.write_unsigned_short(bits); |
439 | + writer.write_unsigned_char(mode); |
440 | + writer.write_unsigned_char(0); |
441 | +} |
442 | + |
443 | +std::ostream& cfg::operator<<(std::ostream& out, const cfg::Rst& rst) |
444 | +{ |
445 | + return out << "cfg-rst:" << std::endl |
446 | + << " bits: " << rst.bits << std::endl |
447 | + << " mode: " << rst.mode << std::endl; |
448 | +} |
449 | |
450 | === added file 'src/location/providers/ubx/_8/cfg/rst.h' |
451 | --- src/location/providers/ubx/_8/cfg/rst.h 1970-01-01 00:00:00 +0000 |
452 | +++ src/location/providers/ubx/_8/cfg/rst.h 2017-03-29 20:24:25 +0000 |
453 | @@ -0,0 +1,84 @@ |
454 | +// Copyright (C) 2016 Thomas Voss <thomas.voss.bochum@gmail.com> |
455 | +// |
456 | +// This library is free software: you can redistribute it and/or modify |
457 | +// it under the terms of the GNU Lesser General Public License as published |
458 | +// by the Free Software Foundation, either version 3 of the License, or |
459 | +// (at your option) any later version. |
460 | +// |
461 | +// This program is distributed in the hope that it will be useful, |
462 | +// but WITHOUT ANY WARRANTY; without even the implied warranty of |
463 | +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
464 | +// GNU General Public License for more details. |
465 | +// |
466 | +// You should have received a copy of the GNU Lesser General Public License |
467 | +// along with this program. If not, see <http://www.gnu.org/licenses/>. |
468 | + |
469 | +#ifndef UBX_8_CFG_RST_H_ |
470 | +#define UBX_8_CFG_RST_H_ |
471 | + |
472 | +#include <cstdint> |
473 | +#include <iosfwd> |
474 | + |
475 | +namespace location |
476 | +{ |
477 | +namespace providers |
478 | +{ |
479 | +namespace ubx |
480 | +{ |
481 | +namespace _8 |
482 | +{ |
483 | + |
484 | +class Writer; |
485 | + |
486 | +namespace cfg |
487 | +{ |
488 | + |
489 | +struct Rst |
490 | +{ |
491 | + static constexpr std::uint8_t class_id{0x06}; |
492 | + static constexpr std::uint8_t message_id{0x04}; |
493 | + |
494 | + enum Bits |
495 | + { |
496 | + eph = 1 << 0, |
497 | + alm = 1 << 1, |
498 | + health = 1 << 2, |
499 | + klob = 1 << 3, |
500 | + pos = 1 << 4, |
501 | + clkd = 1 << 5, |
502 | + osc = 1 << 6, |
503 | + utc = 1 << 7, |
504 | + rtc = 1 << 8, |
505 | + aop = 1 << 15, |
506 | + |
507 | + hot_start = 0, |
508 | + warm_start = eph, |
509 | + cold_start = eph | alm | health | klob | pos | clkd | osc | utc | rtc | aop |
510 | + }; |
511 | + |
512 | + enum Mode |
513 | + { |
514 | + hardware_reset = 0x00, |
515 | + controlled_software_reset = 0x01, |
516 | + controlled_software_reset_gnss = 0x02, |
517 | + hardware_reset_after_shutdown = 0x04, |
518 | + controlled_gnss_stop = 0x08, |
519 | + controlled_gnss_start = 0x09 |
520 | + }; |
521 | + |
522 | + std::size_t size() const; |
523 | + void write(Writer& writer) const; |
524 | + |
525 | + Bits bits; |
526 | + Mode mode; |
527 | +}; |
528 | + |
529 | +std::ostream& operator<<(std::ostream& out, const Rst& rst); |
530 | + |
531 | +} // namespace cfg |
532 | +} // namespace _8 |
533 | +} // namespace ubx |
534 | +} // namespace providers |
535 | +} // namespace location |
536 | + |
537 | +#endif // UBX_8_CFG_RST_H_ |
538 | |
539 | === modified file 'src/location/providers/ubx/_8/gnss_id.cpp' |
540 | --- src/location/providers/ubx/_8/gnss_id.cpp 2017-03-29 20:24:25 +0000 |
541 | +++ src/location/providers/ubx/_8/gnss_id.cpp 2017-03-29 20:24:25 +0000 |
542 | @@ -16,6 +16,7 @@ |
543 | #include <location/providers/ubx/_8/gnss_id.h> |
544 | |
545 | #include <iostream> |
546 | +#include <type_traits> |
547 | |
548 | namespace _8 = location::providers::ubx::_8; |
549 | |
550 | @@ -25,12 +26,18 @@ |
551 | { |
552 | case GnssId::gps: out << "gps"; break; |
553 | case GnssId::sbas: out << "sbas"; break; |
554 | - case GnssId::galileo: out << "galileo"; break; |
555 | - case GnssId::beidou: out << "beidou"; break; |
556 | + case GnssId::galileo: out << "gal"; break; |
557 | + case GnssId::beidou: out << "bds"; break; |
558 | case GnssId::imes: out << "imes"; break; |
559 | case GnssId::qzss: out << "qzss"; break; |
560 | - case GnssId::glonass: out << "glonass"; break; |
561 | + case GnssId::glonass: out << "glo"; break; |
562 | } |
563 | |
564 | return out; |
565 | } |
566 | + |
567 | +bool _8::operator<(GnssId lhs, GnssId rhs) |
568 | +{ |
569 | + using UT = typename std::underlying_type<GnssId>::type; |
570 | + return static_cast<UT>(lhs) < static_cast<UT>(rhs); |
571 | +} |
572 | |
573 | === modified file 'src/location/providers/ubx/_8/gnss_id.h' |
574 | --- src/location/providers/ubx/_8/gnss_id.h 2017-03-29 20:24:25 +0000 |
575 | +++ src/location/providers/ubx/_8/gnss_id.h 2017-03-29 20:24:25 +0000 |
576 | @@ -41,6 +41,7 @@ |
577 | |
578 | }; |
579 | |
580 | +bool operator<(GnssId lhs, GnssId rhs); |
581 | std::ostream& operator<<(std::ostream& out, GnssId gnss_id); |
582 | |
583 | } // namespace _8 |
584 | |
585 | === modified file 'src/location/providers/ubx/_8/message.h' |
586 | --- src/location/providers/ubx/_8/message.h 2017-03-29 20:24:25 +0000 |
587 | +++ src/location/providers/ubx/_8/message.h 2017-03-29 20:24:25 +0000 |
588 | @@ -20,6 +20,7 @@ |
589 | #include <location/providers/ubx/_8/ack/nak.h> |
590 | #include <location/providers/ubx/_8/cfg/gnss.h> |
591 | #include <location/providers/ubx/_8/cfg/msg.h> |
592 | +#include <location/providers/ubx/_8/cfg/rst.h> |
593 | #include <location/providers/ubx/_8/nav/pvt.h> |
594 | #include <location/providers/ubx/_8/nav/sat.h> |
595 | |
596 | @@ -39,6 +40,7 @@ |
597 | ack::Nak, |
598 | cfg::Gnss, |
599 | cfg::Msg, |
600 | + cfg::Rst, |
601 | nav::Pvt, |
602 | nav::Sat |
603 | >; |
604 | |
605 | === modified file 'src/location/providers/ubx/_8/nmea/scanner.cpp' |
606 | --- src/location/providers/ubx/_8/nmea/scanner.cpp 2017-03-29 20:24:25 +0000 |
607 | +++ src/location/providers/ubx/_8/nmea/scanner.cpp 2017-03-29 20:24:25 +0000 |
608 | @@ -23,6 +23,7 @@ |
609 | switch (state) { |
610 | case Expect::dollar: |
611 | if (c == '$') { |
612 | + ss = std::stringstream{}; |
613 | ss << c; |
614 | state = Expect::more_data; |
615 | } |
616 | @@ -58,8 +59,7 @@ |
617 | if (state != Expect::nothing_more) throw std::runtime_error{"Incomplete"}; |
618 | |
619 | auto result = ss.str(); |
620 | - ss.str(""); |
621 | - ss.clear(); |
622 | + ss = std::stringstream{}; |
623 | state = Expect::dollar; |
624 | |
625 | return result; |
626 | |
627 | === modified file 'src/location/providers/ubx/_8/receiver.cpp' |
628 | --- src/location/providers/ubx/_8/receiver.cpp 2017-03-29 20:24:25 +0000 |
629 | +++ src/location/providers/ubx/_8/receiver.cpp 2017-03-29 20:24:25 +0000 |
630 | @@ -26,6 +26,11 @@ |
631 | { |
632 | return ubx::_8::encode_message(msg); |
633 | } |
634 | + |
635 | + std::vector<std::uint8_t> operator()(const ubx::_8::cfg::Rst& rst) const |
636 | + { |
637 | + return ubx::_8::encode_message(rst); |
638 | + } |
639 | }; |
640 | |
641 | } // namespace |
642 | @@ -44,11 +49,35 @@ |
643 | auto result = ubx_scanner.update(*it); |
644 | |
645 | if (std::get<0>(result) == Scanner::Expect::nothing_more) |
646 | - monitor->on_new_ubx_message(ubx_scanner.finalize()); |
647 | - if (!std::get<1>(result)) |
648 | + { |
649 | + try |
650 | + { |
651 | + monitor->on_new_ubx_message(ubx_scanner.finalize()); |
652 | + } |
653 | + catch (...) |
654 | + { |
655 | + // Dropping the exception as there is hardly any reasonable measure |
656 | + // we can take. Both scanners are designed to recover from issues, and we |
657 | + // we just trap the exception here to guarantee that we keep on consuming the |
658 | + // entire buffer. |
659 | + } |
660 | + } |
661 | + else if (!std::get<1>(result)) |
662 | { |
663 | if (nmea::Scanner::Expect::nothing_more == nmea_scanner.update(*it)) |
664 | - monitor->on_new_nmea_sentence(nmea::parse_sentence(nmea_scanner.finalize())); |
665 | + { |
666 | + try |
667 | + { |
668 | + monitor->on_new_nmea_sentence(nmea::parse_sentence(nmea_scanner.finalize())); |
669 | + } |
670 | + catch (...) |
671 | + { |
672 | + // Dropping the exception as there is hardly any reasonable measure |
673 | + // we can take. Both scanners are designed to recover from issues, and we |
674 | + // we just trap the exception here to guarantee that we keep on consuming the |
675 | + // entire buffer. |
676 | + } |
677 | + } |
678 | } |
679 | ++it; |
680 | } |
681 | |
682 | === modified file 'src/location/providers/ubx/_8/receiver.h' |
683 | --- src/location/providers/ubx/_8/receiver.h 2017-03-29 20:24:25 +0000 |
684 | +++ src/location/providers/ubx/_8/receiver.h 2017-03-29 20:24:25 +0000 |
685 | @@ -38,7 +38,7 @@ |
686 | class Receiver |
687 | { |
688 | public: |
689 | - using Buffer = std::array<char, 1024>; |
690 | + using Buffer = std::array<std::uint8_t, 4096>; |
691 | |
692 | /// @brief Monitor provides calling code with means for monitoring |
693 | /// receiver operation. |
694 | @@ -66,6 +66,9 @@ |
695 | /// @brief send_message encodes and sends 'message' to the receiver. |
696 | void send_message(const Message& message); |
697 | |
698 | + /// @brief send_encoded_message sends out data to the receiver. |
699 | + virtual void send_encoded_message(const std::vector<std::uint8_t> &data) = 0; |
700 | + |
701 | protected: |
702 | /// @brief Receiver initializes a new instance with monitor |
703 | /// |
704 | @@ -78,9 +81,6 @@ |
705 | /// Calls out to a configured monitor instance for announcing results. |
706 | void process_chunk(Buffer::iterator it, Buffer::iterator itE); |
707 | |
708 | - /// @brief send_encoded_message sends out data to the receiver. |
709 | - virtual void send_encoded_message(const std::vector<std::uint8_t>& data) = 0; |
710 | - |
711 | private: |
712 | std::shared_ptr<Monitor> monitor; |
713 | ubx::_8::nmea::Scanner nmea_scanner; |
714 | |
715 | === modified file 'src/location/providers/ubx/_8/scanner.cpp' |
716 | --- src/location/providers/ubx/_8/scanner.cpp 2017-03-29 20:24:25 +0000 |
717 | +++ src/location/providers/ubx/_8/scanner.cpp 2017-03-29 20:24:25 +0000 |
718 | @@ -65,15 +65,12 @@ |
719 | { |
720 | bool consumed = false; |
721 | |
722 | - // TODO(tvoss): This lacks a lot of validiation and verification. |
723 | - // UBX allows us to partially parse while we scan and carry out online |
724 | - // checksum calculation. Ideally, we would have a common class State that |
725 | - // captures behavior and transition logic. |
726 | switch (next) |
727 | { |
728 | case Expect::sync_char_1: |
729 | if (c == sync_char_1) |
730 | { |
731 | + reset(); |
732 | next = Expect::sync_char_2; |
733 | consumed = true; |
734 | } |
735 | @@ -143,16 +140,27 @@ |
736 | if (next != Expect::nothing_more) |
737 | throw std::logic_error{"Not ready for extraction."}; |
738 | |
739 | + struct Scope |
740 | + { |
741 | + Scope(Scanner& scanner) : scanner{scanner} {} |
742 | + ~Scope() { scanner.reset(); } |
743 | + |
744 | + Scanner& scanner; |
745 | + } scope{*this}; |
746 | + |
747 | if (ck_a != checksum.ck_a() || ck_b != checksum.ck_b()) |
748 | - throw std::runtime_error{"Verification failed."}; |
749 | + throw std::runtime_error("Failed to verify ubx protocol message integrity."); |
750 | |
751 | auto it = factories.find(std::make_tuple(class_id, message_id)); |
752 | |
753 | if (it == factories.end()) |
754 | - throw std::runtime_error{"Could not decode message."}; |
755 | - |
756 | - auto result = it->second(payload); |
757 | - |
758 | + throw std::runtime_error{"Failed to decode ubx protocol message."}; |
759 | + |
760 | + return it->second(payload); |
761 | +} |
762 | + |
763 | +void _8::Scanner::reset() |
764 | +{ |
765 | checksum = Checksum{}; |
766 | next = Expect::sync_char_1; |
767 | class_id = 0; |
768 | @@ -161,6 +169,4 @@ |
769 | payload.clear(); |
770 | payload_iterator = payload.end(); |
771 | ck_a = ck_b = 0; |
772 | - |
773 | - return result; |
774 | } |
775 | |
776 | === modified file 'src/location/providers/ubx/_8/scanner.h' |
777 | --- src/location/providers/ubx/_8/scanner.h 2017-03-29 20:24:25 +0000 |
778 | +++ src/location/providers/ubx/_8/scanner.h 2017-03-29 20:24:25 +0000 |
779 | @@ -58,6 +58,9 @@ |
780 | Message finalize(); |
781 | |
782 | private: |
783 | + |
784 | + void reset(); |
785 | + |
786 | Expect next; |
787 | Checksum checksum; |
788 | std::uint8_t class_id; |
789 | |
790 | === modified file 'src/location/providers/ubx/_8/serial_port_receiver.cpp' |
791 | --- src/location/providers/ubx/_8/serial_port_receiver.cpp 2017-03-29 20:24:25 +0000 |
792 | +++ src/location/providers/ubx/_8/serial_port_receiver.cpp 2017-03-29 20:24:25 +0000 |
793 | @@ -15,51 +15,63 @@ |
794 | |
795 | ubx::_8::SerialPortReceiver::SerialPortReceiver(boost::asio::io_service& ios, const boost::filesystem::path& dev, |
796 | const std::shared_ptr<Monitor>& monitor) |
797 | - : Receiver{monitor}, ios{ios}, sp{ios, dev.string().c_str()} |
798 | + : Receiver{monitor}, ios{ios}, serial_port{ios, dev.string().c_str()} |
799 | { |
800 | + serial_port.set_option(boost::asio::serial_port::baud_rate(9600)); |
801 | } |
802 | |
803 | void ubx::_8::SerialPortReceiver::send_encoded_message(const std::vector<std::uint8_t>& data) |
804 | { |
805 | - ios.dispatch([this, data]() |
806 | + auto thiz = shared_from_this(); |
807 | + std::weak_ptr<SerialPortReceiver> wp{thiz}; |
808 | + |
809 | + ios.dispatch([this, wp, data]() |
810 | { |
811 | - boost::asio::write(sp, boost::asio::buffer(data), boost::asio::transfer_all()); |
812 | + if (auto sp = wp.lock()) |
813 | + boost::asio::write(serial_port, boost::asio::buffer(data), boost::asio::transfer_all()); |
814 | }); |
815 | } |
816 | |
817 | void ubx::_8::SerialPortReceiver::start() |
818 | { |
819 | + ::tcflush(serial_port.lowest_layer().native_handle(), TCIFLUSH); |
820 | start_read(); |
821 | } |
822 | |
823 | void ubx::_8::SerialPortReceiver::stop() |
824 | { |
825 | - sp.cancel(); |
826 | + serial_port.cancel(); |
827 | } |
828 | |
829 | void ubx::_8::SerialPortReceiver::start_read() |
830 | { |
831 | auto thiz = shared_from_this(); |
832 | - boost::asio::async_read(sp, boost::asio::buffer(&buffer.front(), buffer.size()), |
833 | - [thiz, this](const boost::system::error_code& ec, std::size_t transferred) { |
834 | + std::weak_ptr<SerialPortReceiver> wp{thiz}; |
835 | + |
836 | + boost::asio::async_read(serial_port, boost::asio::buffer(&buffer.front(), buffer.size()), |
837 | + [this, wp](const boost::system::error_code& ec, std::size_t transferred) { |
838 | if (ec == boost::asio::error::operation_aborted) |
839 | return; |
840 | - if (not ec) |
841 | + |
842 | + if (auto sp = wp.lock()) |
843 | { |
844 | - try |
845 | - { |
846 | - process_chunk(buffer.begin(), buffer.begin() + transferred); |
847 | - } |
848 | - catch(const std::exception& e) |
849 | - { |
850 | - LOG(WARNING) << "Error processing NMEA chunk: " << e.what(); |
851 | - } |
852 | - catch(...) |
853 | - { |
854 | - LOG(WARNING) << "Error processing NMEA chunk."; |
855 | - } |
856 | + if (not ec) |
857 | + { |
858 | + try |
859 | + { |
860 | + process_chunk(buffer.begin(), buffer.begin() + transferred); |
861 | + } |
862 | + catch(const std::exception& e) |
863 | + { |
864 | + LOG(WARNING) << "Error processing data chunk: " << e.what(); |
865 | + } |
866 | + catch(...) |
867 | + { |
868 | + LOG(WARNING) << "Error processing data chunk."; |
869 | + } |
870 | |
871 | - start_read(); |
872 | + start_read(); |
873 | + } |
874 | } |
875 | }); |
876 | } |
877 | |
878 | === modified file 'src/location/providers/ubx/_8/serial_port_receiver.h' |
879 | --- src/location/providers/ubx/_8/serial_port_receiver.h 2017-03-29 20:24:25 +0000 |
880 | +++ src/location/providers/ubx/_8/serial_port_receiver.h 2017-03-29 20:24:25 +0000 |
881 | @@ -21,6 +21,7 @@ |
882 | #include <boost/filesystem.hpp> |
883 | |
884 | #include <array> |
885 | +#include <atomic> |
886 | |
887 | namespace location |
888 | { |
889 | @@ -44,10 +45,15 @@ |
890 | void start(); |
891 | void stop(); |
892 | |
893 | -protected: |
894 | void send_encoded_message(const std::vector<std::uint8_t>& data) override; |
895 | |
896 | private: |
897 | + enum class State |
898 | + { |
899 | + running, |
900 | + stopped |
901 | + }; |
902 | + |
903 | /// @brief Receiver initializes a new instance opening the serial port |
904 | /// located at path. |
905 | /// |
906 | @@ -65,7 +71,7 @@ |
907 | |
908 | Receiver::Buffer buffer; |
909 | boost::asio::io_service& ios; |
910 | - boost::asio::serial_port sp; |
911 | + boost::asio::serial_port serial_port; |
912 | }; |
913 | } |
914 | } |
915 | |
916 | === modified file 'src/location/providers/ubx/provider.cpp' |
917 | --- src/location/providers/ubx/provider.cpp 2017-03-29 20:24:25 +0000 |
918 | +++ src/location/providers/ubx/provider.cpp 2017-03-29 20:24:25 +0000 |
919 | @@ -20,6 +20,7 @@ |
920 | |
921 | #include <location/logging.h> |
922 | #include <location/runtime.h> |
923 | +#include <location/events/reference_position_updated.h> |
924 | #include <location/glib/runtime.h> |
925 | |
926 | #include <location/providers/ubx/_8/cfg/gnss.h> |
927 | @@ -27,8 +28,11 @@ |
928 | #include <location/providers/ubx/_8/nav/pvt.h> |
929 | #include <location/providers/ubx/_8/nav/sat.h> |
930 | |
931 | +#include <core/net/http/client.h> |
932 | #include <core/posix/this_process.h> |
933 | |
934 | +#include <boost/lexical_cast.hpp> |
935 | + |
936 | #include <fstream> |
937 | #include <iostream> |
938 | #include <iterator> |
939 | @@ -37,31 +41,54 @@ |
940 | namespace env = core::posix::this_process::env; |
941 | namespace ubx = location::providers::ubx; |
942 | |
943 | +namespace |
944 | +{ |
945 | + |
946 | +struct SettingsHelper |
947 | +{ |
948 | + template<typename T> |
949 | + static T get_value(std::string key, T&& default_value) |
950 | + { |
951 | + static const std::string snap_path = env::get("SNAP_DATA"); |
952 | + |
953 | + boost::filesystem::path path{snap_path}; |
954 | + std::replace(key.begin(), key.end(), '.', '/'); |
955 | + path /= key; |
956 | + |
957 | + LOG(INFO) << "Reading setting from " << path.string(); |
958 | + |
959 | + std::ifstream in{path.string().c_str()}; |
960 | + T value{default_value}; in >> value; |
961 | + |
962 | + return value; |
963 | + } |
964 | +}; |
965 | + |
966 | +} |
967 | + |
968 | std::string ubx::Provider::class_name() |
969 | { |
970 | return "ubx::Provider"; |
971 | } |
972 | |
973 | -ubx::Provider::Monitor::Monitor(Provider* provider) : provider{provider} |
974 | -{ |
975 | -} |
976 | - |
977 | void ubx::Provider::Monitor::on_new_ubx_message(const _8::Message& message) |
978 | { |
979 | VLOG(1) << message; |
980 | - if (provider->protocol == Provider::Protocol::ubx) |
981 | - boost::apply_visitor(*this, message); |
982 | + if (auto sp = provider.lock()) |
983 | + if (sp->configuration.protocol == Provider::Protocol::ubx) |
984 | + boost::apply_visitor(*this, message); |
985 | } |
986 | |
987 | |
988 | void ubx::Provider::Monitor::on_new_nmea_sentence(const _8::nmea::Sentence& sentence) |
989 | { |
990 | VLOG(1) << sentence; |
991 | - if (provider->protocol == Provider::Protocol::nmea) |
992 | - boost::apply_visitor(*this, sentence); |
993 | + if (auto sp = provider.lock()) |
994 | + if (sp->configuration.protocol == Provider::Protocol::nmea) |
995 | + boost::apply_visitor(*this, sentence); |
996 | } |
997 | |
998 | -void ubx::Provider::Monitor::operator()(const _8::nmea::Gga& gga) const |
999 | +void ubx::Provider::Monitor::operator()(const _8::nmea::Gga& gga) |
1000 | { |
1001 | if (gga.latitude && gga.longitude) |
1002 | { |
1003 | @@ -82,14 +109,19 @@ |
1004 | if (gga.hdop) |
1005 | position.accuracy().horizontal(gga.hdop.get() * 3. * units::meters); |
1006 | |
1007 | - glib::Runtime::instance()->dispatch([this, position]() |
1008 | + auto thiz = shared_from_this(); |
1009 | + std::weak_ptr<ubx::Provider::Monitor> wp{thiz}; |
1010 | + |
1011 | + glib::Runtime::instance()->dispatch([position, wp]() |
1012 | { |
1013 | - provider->updates.position(location::Update<location::Position>{position}); |
1014 | + if (auto sp = wp.lock()) |
1015 | + if (auto spp = sp->provider.lock()) |
1016 | + spp->updates.position(location::Update<location::Position>{position}); |
1017 | }); |
1018 | } |
1019 | } |
1020 | |
1021 | -void ubx::Provider::Monitor::operator()(const _8::nav::Pvt& pvt) const |
1022 | +void ubx::Provider::Monitor::operator()(const _8::nav::Pvt& pvt) |
1023 | { |
1024 | if (pvt.fix_type == _8::nav::Pvt::FixType::no_fix) |
1025 | return; |
1026 | @@ -110,72 +142,218 @@ |
1027 | units::Degrees heading = pvt.heading.vehicle * units::degrees; |
1028 | units::MetersPerSecond speed = pvt.speed_over_ground * 1e-3 * units::meters_per_second; |
1029 | |
1030 | - glib::Runtime::instance()->dispatch([this, position, heading, speed]() |
1031 | + auto thiz = shared_from_this(); |
1032 | + std::weak_ptr<ubx::Provider::Monitor> wp{thiz}; |
1033 | + |
1034 | + glib::Runtime::instance()->dispatch([position, heading, speed, wp]() |
1035 | { |
1036 | - provider->updates.position(location::Update<location::Position>{position}); |
1037 | - provider->updates.heading(location::Update<units::Degrees>{heading}); |
1038 | - provider->updates.velocity(location::Update<units::MetersPerSecond>{speed}); |
1039 | + if (auto sp = wp.lock()) |
1040 | + { |
1041 | + if (auto spp = sp->provider.lock()) |
1042 | + { |
1043 | + spp->updates.position(location::Update<location::Position>{position}); |
1044 | + spp->updates.heading(location::Update<units::Degrees>{heading}); |
1045 | + spp->updates.velocity(location::Update<units::MetersPerSecond>{speed}); |
1046 | + } |
1047 | + } |
1048 | }); |
1049 | } |
1050 | |
1051 | -void ubx::Provider::Monitor::operator()(const _8::nmea::Gsa&) const |
1052 | -{ |
1053 | - // Empty on purpose |
1054 | -} |
1055 | - |
1056 | -void ubx::Provider::Monitor::operator()(const _8::nmea::Gll&) const |
1057 | -{ |
1058 | - // Empty on purpose |
1059 | -} |
1060 | - |
1061 | -void ubx::Provider::Monitor::operator()(const _8::nmea::Gsv&) const |
1062 | -{ |
1063 | - // Empty on purpose |
1064 | -} |
1065 | - |
1066 | -void ubx::Provider::Monitor::operator()(const _8::nmea::Rmc&) const |
1067 | -{ |
1068 | - // Empty on purpose |
1069 | -} |
1070 | - |
1071 | -void ubx::Provider::Monitor::operator()(const _8::nmea::Txt&) const |
1072 | -{ |
1073 | - // Empty on purpose |
1074 | -} |
1075 | - |
1076 | -void ubx::Provider::Monitor::operator()(const _8::nmea::Vtg& vtg) const |
1077 | -{ |
1078 | - glib::Runtime::instance()->dispatch([this, vtg]() |
1079 | +void ubx::Provider::Monitor::operator()(const _8::nmea::Gsa&) |
1080 | +{ |
1081 | + // Empty on purpose |
1082 | +} |
1083 | + |
1084 | +void ubx::Provider::Monitor::operator()(const _8::nmea::Gll&) |
1085 | +{ |
1086 | + // Empty on purpose |
1087 | +} |
1088 | + |
1089 | +void ubx::Provider::Monitor::operator()(const _8::nmea::Gsv&) |
1090 | +{ |
1091 | + // Empty on purpose |
1092 | +} |
1093 | + |
1094 | +void ubx::Provider::Monitor::operator()(const _8::nmea::Rmc&) |
1095 | +{ |
1096 | + // Empty on purpose |
1097 | +} |
1098 | + |
1099 | +void ubx::Provider::Monitor::operator()(const _8::nmea::Txt&) |
1100 | +{ |
1101 | + // Empty on purpose |
1102 | +} |
1103 | + |
1104 | +void ubx::Provider::Monitor::operator()(const _8::nmea::Vtg& vtg) |
1105 | +{ |
1106 | + auto thiz = shared_from_this(); |
1107 | + std::weak_ptr<ubx::Provider::Monitor> wp{thiz}; |
1108 | + |
1109 | + glib::Runtime::instance()->dispatch([vtg, wp]() |
1110 | { |
1111 | - if (vtg.cog_true) |
1112 | - provider->updates.heading( |
1113 | - Update<units::Degrees>( |
1114 | - vtg.cog_true.get() * units::degrees)); |
1115 | - if (vtg.sog_kmh) |
1116 | - provider->updates.velocity( |
1117 | - Update<units::MetersPerSecond>( |
1118 | - vtg.sog_kmh.get() * 1000./3600. * units::meters_per_second)); |
1119 | + if (auto sp = wp.lock()) |
1120 | + { |
1121 | + if (vtg.cog_true) |
1122 | + if (auto spp = sp->provider.lock()) |
1123 | + spp->updates.heading( |
1124 | + Update<units::Degrees>( |
1125 | + vtg.cog_true.get() * units::degrees)); |
1126 | + if (vtg.sog_kmh) |
1127 | + if (auto spp = sp->provider.lock()) |
1128 | + spp->updates.velocity( |
1129 | + Update<units::MetersPerSecond>( |
1130 | + vtg.sog_kmh.get() * 1000./3600. * units::meters_per_second)); |
1131 | + } |
1132 | }); |
1133 | } |
1134 | |
1135 | location::Provider::Ptr ubx::Provider::create_instance(const location::ProviderFactory::Configuration& config) |
1136 | { |
1137 | - std::string device_path = "/dev/ttyACM0"; |
1138 | - std::ifstream in(env::get("SNAP_DATA") + "/ubx/provider/path"); |
1139 | - in >> device_path; |
1140 | - |
1141 | - return location::Provider::Ptr{new ubx::Provider{ |
1142 | - Protocol::ubx, config.get<std::string>("device", device_path)}}; |
1143 | -} |
1144 | - |
1145 | -ubx::Provider::Provider(Protocol protocol, const boost::filesystem::path& device) |
1146 | - : protocol{protocol}, |
1147 | + Configuration configuration |
1148 | + { |
1149 | + Protocol::ubx, |
1150 | + config.get<std::string>( |
1151 | + "device", SettingsHelper::get_value<std::string>( |
1152 | + "ubx.provider.path", |
1153 | + "/dev/ttyACM1" |
1154 | + ) |
1155 | + ), |
1156 | + { |
1157 | + SettingsHelper::get_value<std::string>( |
1158 | + "ubx.provider.assist_now.enable", |
1159 | + "false" |
1160 | + ) == "true", |
1161 | + SettingsHelper::get_value<std::string>( |
1162 | + "ubx.provider.assist_now.token", |
1163 | + "" |
1164 | + ), |
1165 | + boost::posix_time::seconds( |
1166 | + boost::lexical_cast<std::uint64_t>( |
1167 | + SettingsHelper::get_value<std::string>( |
1168 | + "ubx.provider.assist_now.acquisition_timeout", |
1169 | + "5" |
1170 | + ) |
1171 | + ) |
1172 | + ) |
1173 | + } |
1174 | + }; |
1175 | + |
1176 | + return ubx::Provider::create(configuration); |
1177 | +} |
1178 | + |
1179 | +// Create a new instance with configuration. |
1180 | +std::shared_ptr<ubx::Provider> ubx::Provider::create(const Configuration& configuration) |
1181 | +{ |
1182 | + auto sp = std::shared_ptr<Provider>{new Provider{configuration}}; |
1183 | + return sp->finalize_construction(); |
1184 | +} |
1185 | + |
1186 | + |
1187 | +ubx::Provider::Provider(const Configuration& configuration) |
1188 | + : configuration{configuration}, |
1189 | runtime{location::Runtime::create(1)}, |
1190 | - monitor{std::make_shared<Monitor>(this)}, |
1191 | - receiver{_8::SerialPortReceiver::create(runtime->service(), device, monitor)} |
1192 | -{ |
1193 | + monitor{std::make_shared<Monitor>()}, |
1194 | + receiver{_8::SerialPortReceiver::create(runtime->service(), configuration.device, monitor)}, |
1195 | + assist_now_online_client{std::make_shared<_8::AssistNowOnlineClient>(core::net::http::make_client())}, |
1196 | + acquisition_timer{runtime->service()} |
1197 | +{ |
1198 | runtime->start(); |
1199 | |
1200 | + configure_gnss(); |
1201 | + configure_protocol(); |
1202 | +} |
1203 | + |
1204 | +ubx::Provider::~Provider() noexcept |
1205 | +{ |
1206 | + deactivate(); |
1207 | + runtime->stop(); |
1208 | +} |
1209 | + |
1210 | +void ubx::Provider::reset() |
1211 | +{ |
1212 | + receiver->send_message(_8::cfg::Rst{_8::cfg::Rst::Bits::cold_start, _8::cfg::Rst::Mode::controlled_software_reset_gnss}); |
1213 | +} |
1214 | + |
1215 | +void ubx::Provider::on_new_event(const Event&) |
1216 | +{ |
1217 | + // TODO(tvoss): Use incoming reference position updates |
1218 | + // to query assistance data. |
1219 | +} |
1220 | + |
1221 | +location::Provider::Requirements ubx::Provider::requirements() const |
1222 | +{ |
1223 | + return Requirements::none; |
1224 | +} |
1225 | + |
1226 | +bool ubx::Provider::satisfies(const location::Criteria&) |
1227 | +{ |
1228 | + return true; |
1229 | +} |
1230 | + |
1231 | +void ubx::Provider::enable() |
1232 | +{ |
1233 | +} |
1234 | + |
1235 | +void ubx::Provider::disable() |
1236 | +{ |
1237 | +} |
1238 | + |
1239 | +void ubx::Provider::activate() |
1240 | +{ |
1241 | + receiver->start(); |
1242 | + |
1243 | + if (configuration.assist_now.enable) |
1244 | + { |
1245 | + auto thiz = shared_from_this(); |
1246 | + std::weak_ptr<Provider> wp{thiz}; |
1247 | + |
1248 | + acquisition_timer.expires_from_now(configuration.assist_now.acquisition_timeout); |
1249 | + acquisition_timer.async_wait([this, wp](boost::system::error_code ec) |
1250 | + { |
1251 | + if (auto sp = wp.lock()) |
1252 | + if (!ec) request_assist_now_online_data(Optional<Position>{}); |
1253 | + }); |
1254 | + } |
1255 | +} |
1256 | + |
1257 | +void ubx::Provider::deactivate() |
1258 | +{ |
1259 | + receiver->stop(); |
1260 | + acquisition_timer.cancel(); |
1261 | +} |
1262 | + |
1263 | +const core::Signal<location::Update<location::Position>>& ubx::Provider::position_updates() const |
1264 | +{ |
1265 | + return updates.position; |
1266 | +} |
1267 | + |
1268 | +const core::Signal<location::Update<location::units::Degrees>>& ubx::Provider::heading_updates() const |
1269 | +{ |
1270 | + return updates.heading; |
1271 | +} |
1272 | + |
1273 | +const core::Signal<location::Update<location::units::MetersPerSecond>>& ubx::Provider::velocity_updates() const |
1274 | +{ |
1275 | + return updates.velocity; |
1276 | +} |
1277 | + |
1278 | +std::shared_ptr<ubx::Provider> ubx::Provider::finalize_construction() |
1279 | +{ |
1280 | + auto thiz = shared_from_this(); |
1281 | + std::weak_ptr<ubx::Provider> wp{thiz}; |
1282 | + |
1283 | + updates.position.connect([wp](const Update<Position>&) |
1284 | + { |
1285 | + if (auto sp = wp.lock()) |
1286 | + sp->acquisition_timer.cancel(); |
1287 | + }); |
1288 | + |
1289 | + monitor->provider = wp; |
1290 | + return thiz; |
1291 | +} |
1292 | + |
1293 | +void ubx::Provider::configure_gnss() |
1294 | +{ |
1295 | _8::cfg::Gnss::Gps gps; |
1296 | gps.l1ca = true; |
1297 | gps.enable = true; |
1298 | @@ -207,8 +385,11 @@ |
1299 | gnss.sbas = sbas; |
1300 | |
1301 | receiver->send_message(gnss); |
1302 | +} |
1303 | |
1304 | - if (protocol == Protocol::ubx) |
1305 | +void ubx::Provider::configure_protocol() |
1306 | +{ |
1307 | + if (configuration.protocol == Protocol::ubx) |
1308 | { |
1309 | _8::cfg::Msg cfg_msg{ubx::_8::nav::Pvt::class_id, ubx::_8::nav::Pvt::message_id, { 0 }}; |
1310 | cfg_msg.rate[_8::cfg::Msg::Port::usb] = 1; |
1311 | @@ -221,55 +402,47 @@ |
1312 | } |
1313 | } |
1314 | |
1315 | -ubx::Provider::~Provider() noexcept |
1316 | -{ |
1317 | - deactivate(); |
1318 | - runtime->stop(); |
1319 | -} |
1320 | - |
1321 | -void ubx::Provider::on_new_event(const Event&) |
1322 | -{ |
1323 | -} |
1324 | - |
1325 | -location::Provider::Requirements ubx::Provider::requirements() const |
1326 | -{ |
1327 | - return Requirements::none; |
1328 | -} |
1329 | - |
1330 | -bool ubx::Provider::satisfies(const location::Criteria&) |
1331 | -{ |
1332 | - return true; |
1333 | -} |
1334 | - |
1335 | -void ubx::Provider::enable() |
1336 | -{ |
1337 | -} |
1338 | - |
1339 | -void ubx::Provider::disable() |
1340 | -{ |
1341 | -} |
1342 | - |
1343 | -void ubx::Provider::activate() |
1344 | -{ |
1345 | - receiver->start(); |
1346 | -} |
1347 | - |
1348 | -void ubx::Provider::deactivate() |
1349 | -{ |
1350 | - receiver->stop(); |
1351 | -} |
1352 | - |
1353 | -const core::Signal<location::Update<location::Position>>& ubx::Provider::position_updates() const |
1354 | -{ |
1355 | - return updates.position; |
1356 | -} |
1357 | - |
1358 | -const core::Signal<location::Update<location::units::Degrees>>& ubx::Provider::heading_updates() const |
1359 | -{ |
1360 | - return updates.heading; |
1361 | -} |
1362 | - |
1363 | -const core::Signal<location::Update<location::units::MetersPerSecond>>& ubx::Provider::velocity_updates() const |
1364 | -{ |
1365 | - return updates.velocity; |
1366 | +void ubx::Provider::request_assist_now_online_data(const Optional<Position>& position) |
1367 | +{ |
1368 | + auto thiz = shared_from_this(); |
1369 | + std::weak_ptr<Provider> wp{thiz}; |
1370 | + |
1371 | + _8::AssistNowOnlineClient::Parameters params; |
1372 | + params.token = configuration.assist_now.token; |
1373 | + params.gnss = {_8::GnssId::gps, _8::GnssId::glonass, _8::GnssId::galileo}; |
1374 | + params.data_types = |
1375 | + { |
1376 | + _8::AssistNowOnlineClient::DataType::almanac, |
1377 | + _8::AssistNowOnlineClient::DataType::ephemeris |
1378 | + }; |
1379 | + params.position = position; |
1380 | + |
1381 | + assist_now_online_client->request_assistance_data(params, [this, wp](const Result<std::string>& result) |
1382 | + { |
1383 | + if (result) |
1384 | + { |
1385 | + if (auto sp = wp.lock()) |
1386 | + { |
1387 | + LOG(INFO) << "Successfully queried assistance data, injecting into chipset now."; |
1388 | + receiver->send_encoded_message( |
1389 | + std::vector<std::uint8_t>( |
1390 | + result.value().begin(), result.value().end())); |
1391 | + } |
1392 | + } |
1393 | + else |
1394 | + { |
1395 | + try |
1396 | + { |
1397 | + result.rethrow(); |
1398 | + } |
1399 | + catch (const std::exception& e) |
1400 | + { |
1401 | + LOG(WARNING) << "Failed to query AssistNow for aiding data: " << e.what() << std::endl; |
1402 | + } |
1403 | + catch (...) |
1404 | + { |
1405 | + LOG(WARNING) << "Failed to query AssistNow for aiding data." << std::endl; |
1406 | + } |
1407 | + } |
1408 | + }); |
1409 | } |
1410 | |
1411 | === modified file 'src/location/providers/ubx/provider.h' |
1412 | --- src/location/providers/ubx/provider.h 2017-03-29 20:24:25 +0000 |
1413 | +++ src/location/providers/ubx/provider.h 2017-03-29 20:24:25 +0000 |
1414 | @@ -22,6 +22,7 @@ |
1415 | #include <location/provider_factory.h> |
1416 | #include <location/runtime.h> |
1417 | |
1418 | +#include <location/providers/ubx/_8/assist_now_online_client.h> |
1419 | #include <location/providers/ubx/_8/serial_port_receiver.h> |
1420 | |
1421 | #include <boost/filesystem.hpp> |
1422 | @@ -43,9 +44,28 @@ |
1423 | // |
1424 | // Configuration parameters: |
1425 | // - device[=/dev/ttyUSB1] serial device connecting to the receiver. |
1426 | -class Provider : public location::Provider |
1427 | +class Provider : public location::Provider, public std::enable_shared_from_this<Provider> |
1428 | { |
1429 | public: |
1430 | + enum class Protocol |
1431 | + { |
1432 | + ubx, // Rely on ubx. |
1433 | + nmea // Rely on nmea. |
1434 | + }; |
1435 | + |
1436 | + // Configuration bundles all construction time parameters. |
1437 | + struct Configuration |
1438 | + { |
1439 | + Protocol protocol; // The protocol used for communicating with the receiver. |
1440 | + boost::filesystem::path device; // Serial device used for communicating with the receiver. |
1441 | + struct |
1442 | + { |
1443 | + bool enable; // Whether or not the provider should use AssistNow. |
1444 | + std::string token; // Token for validating requests to the AssistNow service. |
1445 | + boost::posix_time::seconds acquisition_timeout; // Query assistance data after this many seconds. |
1446 | + } assist_now; // All parameters for configuring AssistNow go here. |
1447 | + }; |
1448 | + |
1449 | // For integration with the Provider factory. |
1450 | static std::string class_name(); |
1451 | // Instantiates a new provider instance, populating the configuration object |
1452 | @@ -53,17 +73,16 @@ |
1453 | // for the list of known options. |
1454 | static Provider::Ptr create_instance(const ProviderFactory::Configuration&); |
1455 | |
1456 | - enum class Protocol |
1457 | - { |
1458 | - ubx, // Rely on ubx. |
1459 | - nmea // Rely on nmea. |
1460 | - }; |
1461 | + // Create a new instance with configuration. |
1462 | + static std::shared_ptr<Provider> create(const Configuration& configuration); |
1463 | |
1464 | - // Creates a new provider instance talking via device to the ubx chipset. |
1465 | - Provider(Protocol protocol, const boost::filesystem::path& device); |
1466 | // Cleans up all resources and stops the updates. |
1467 | ~Provider() noexcept; |
1468 | |
1469 | + // Resets the chipset and drops all cached data. |
1470 | + // The next positioning request will be a cold start. |
1471 | + void reset(); |
1472 | + |
1473 | // From Provider |
1474 | void on_new_event(const Event& event) override; |
1475 | |
1476 | @@ -80,10 +99,8 @@ |
1477 | |
1478 | private: |
1479 | // Relays incoming sentences to a provider instance. |
1480 | - struct Monitor : public _8::Receiver::Monitor, public boost::static_visitor<> |
1481 | + struct Monitor : public std::enable_shared_from_this<ubx::Provider::Monitor>, public _8::Receiver::Monitor, public boost::static_visitor<> |
1482 | { |
1483 | - explicit Monitor(Provider* provider); |
1484 | - |
1485 | // From Receiver::Monitor |
1486 | void on_new_ubx_message(const _8::Message& message) override; |
1487 | void on_new_nmea_sentence(const _8::nmea::Sentence& sentence) override; |
1488 | @@ -91,23 +108,36 @@ |
1489 | template<typename T> |
1490 | void operator()(const T&) const {} |
1491 | |
1492 | - void operator()(const _8::nav::Pvt& pvt) const; |
1493 | - |
1494 | - void operator()(const _8::nmea::Gga& gga) const; |
1495 | - void operator()(const _8::nmea::Gsa& gsa) const; |
1496 | - void operator()(const _8::nmea::Gll& gll) const; |
1497 | - void operator()(const _8::nmea::Gsv& gsv) const; |
1498 | - void operator()(const _8::nmea::Rmc& rmc) const; |
1499 | - void operator()(const _8::nmea::Txt& txt) const; |
1500 | - void operator()(const _8::nmea::Vtg& vtg) const; |
1501 | - |
1502 | - Provider* provider; |
1503 | + void operator()(const _8::nav::Pvt& pvt); |
1504 | + |
1505 | + void operator()(const _8::nmea::Gga& gga); |
1506 | + void operator()(const _8::nmea::Gsa& gsa); |
1507 | + void operator()(const _8::nmea::Gll& gll); |
1508 | + void operator()(const _8::nmea::Gsv& gsv); |
1509 | + void operator()(const _8::nmea::Rmc& rmc); |
1510 | + void operator()(const _8::nmea::Txt& txt); |
1511 | + void operator()(const _8::nmea::Vtg& vtg); |
1512 | + |
1513 | + std::weak_ptr<Provider> provider; |
1514 | }; |
1515 | |
1516 | - Protocol protocol; |
1517 | + // Creates a new provider instance talking via device to the ubx chipset. |
1518 | + Provider(const Configuration& configuration); |
1519 | + |
1520 | + std::shared_ptr<Provider> finalize_construction(); |
1521 | + |
1522 | + void configure_gnss(); |
1523 | + void configure_protocol(); |
1524 | + |
1525 | + void request_assist_now_online_data(const Optional<Position>& position); |
1526 | + |
1527 | + Configuration configuration; |
1528 | std::shared_ptr<location::Runtime> runtime; |
1529 | std::shared_ptr<Monitor> monitor; |
1530 | std::shared_ptr<_8::SerialPortReceiver> receiver; |
1531 | + std::shared_ptr<_8::AssistNowOnlineClient> assist_now_online_client; |
1532 | + boost::asio::deadline_timer acquisition_timer; |
1533 | + |
1534 | struct |
1535 | { |
1536 | core::Signal<Update<Position>> position; |
1537 | |
1538 | === modified file 'src/location/runtime_tests.cpp' |
1539 | --- src/location/runtime_tests.cpp 2016-08-24 14:12:05 +0000 |
1540 | +++ src/location/runtime_tests.cpp 2017-03-29 20:24:25 +0000 |
1541 | @@ -20,12 +20,17 @@ |
1542 | #include <location/runtime_tests.h> |
1543 | |
1544 | #include <location/clock.h> |
1545 | +#include <location/glib/runtime.h> |
1546 | #include <location/providers/gps/hardware_abstraction_layer.h> |
1547 | +#include <location/providers/ubx/provider.h> |
1548 | + |
1549 | +#include <core/posix/this_process.h> |
1550 | |
1551 | #include <boost/accumulators/accumulators.hpp> |
1552 | #include <boost/accumulators/statistics/stats.hpp> |
1553 | #include <boost/accumulators/statistics/mean.hpp> |
1554 | #include <boost/accumulators/statistics/variance.hpp> |
1555 | +#include <boost/lexical_cast.hpp> |
1556 | |
1557 | #include <cstdlib> |
1558 | |
1559 | @@ -35,6 +40,7 @@ |
1560 | #include <mutex> |
1561 | #include <thread> |
1562 | |
1563 | +namespace env = core::posix::this_process::env; |
1564 | namespace gps = location::providers::gps; |
1565 | |
1566 | namespace |
1567 | @@ -172,14 +178,125 @@ |
1568 | return 0; |
1569 | } |
1570 | #else |
1571 | -int snr_and_ttff(std::ostream&, std::ostream&) { return 0; } |
1572 | +int snr_and_ttff(const std::string& test_suite, std::ostream&, std::ostream&) { return 0; } |
1573 | #endif // LOCATION_PROVIDERS_GPS |
1574 | + |
1575 | +int ubx(std::ostream& cout, std::ostream& cerr) |
1576 | +{ |
1577 | + typedef boost::accumulators::accumulator_set< |
1578 | + double, |
1579 | + boost::accumulators::stats< |
1580 | + boost::accumulators::tag::mean, |
1581 | + boost::accumulators::tag::variance |
1582 | + > |
1583 | + > Statistics; |
1584 | + |
1585 | + using boost::accumulators::mean; |
1586 | + using boost::accumulators::variance; |
1587 | + |
1588 | + const unsigned int trials = boost::lexical_cast<unsigned int>(env::get("UBX_PROVIDER_TEST_TRIALS", "15")); |
1589 | + |
1590 | + Statistics stats; |
1591 | + location::providers::ubx::Provider::Configuration configuration |
1592 | + { |
1593 | + location::providers::ubx::Provider::Protocol::ubx, |
1594 | + env::get_or_throw("UBX_PROVIDER_TEST_DEVICE"), |
1595 | + { |
1596 | + env::get("UBX_PROVIDER_TEST_ASSIST_NOW_ENABLE", "false") == "true", |
1597 | + env::get_or_throw("UBX_PROVIDER_TEST_ASSIST_NOW_TOKEN"), |
1598 | + boost::posix_time::seconds( |
1599 | + boost::lexical_cast<std::uint64_t>( |
1600 | + env::get("UBX_PROVIDER_TEST_ASSIST_NOW_ACQUISITION_TIMEOUT", "5"))) |
1601 | + } |
1602 | + }; |
1603 | + auto provider = location::providers::ubx::Provider::create(configuration); |
1604 | + |
1605 | + struct State |
1606 | + { |
1607 | + State() : worker{[this]() { runtime.run(); }}, fix_received(false) |
1608 | + { |
1609 | + } |
1610 | + |
1611 | + ~State() |
1612 | + { |
1613 | + runtime.stop(); |
1614 | + if (worker.joinable()) |
1615 | + worker.join(); |
1616 | + } |
1617 | + |
1618 | + bool wait_for_fix_for(const std::chrono::seconds& seconds) |
1619 | + { |
1620 | + std::unique_lock<std::mutex> ul(guard); |
1621 | + return wait_condition.wait_for( |
1622 | + ul, |
1623 | + seconds, |
1624 | + [this]() {return fix_received == true;}); |
1625 | + } |
1626 | + |
1627 | + void on_position_updated(const location::Position&) |
1628 | + { |
1629 | + fix_received = true; |
1630 | + wait_condition.notify_all(); |
1631 | + } |
1632 | + |
1633 | + void reset() |
1634 | + { |
1635 | + fix_received = false; |
1636 | + } |
1637 | + |
1638 | + location::glib::Runtime runtime; |
1639 | + std::thread worker; |
1640 | + std::mutex guard; |
1641 | + std::condition_variable wait_condition; |
1642 | + bool fix_received; |
1643 | + } state; |
1644 | + |
1645 | + provider->position_updates().connect([&state](const location::Update<location::Position>& update) |
1646 | + { |
1647 | + state.on_position_updated(update.value); |
1648 | + }); |
1649 | + |
1650 | + for (unsigned int i = 0; i < trials; i++) |
1651 | + { |
1652 | + provider->reset(); |
1653 | + |
1654 | + state.reset(); |
1655 | + auto start = std::chrono::duration_cast<std::chrono::microseconds>(location::Clock::now().time_since_epoch()); |
1656 | + { |
1657 | + provider->activate(); |
1658 | + |
1659 | + // We expect a maximum cold start time of 15 minutes. The theoretical |
1660 | + // limit is 12.5 minutes, and we add up some grace period to make the |
1661 | + // test more robust (see http://en.wikipedia.org/wiki/Time_to_first_fix). |
1662 | + expect<true, std::runtime_error>(state.wait_for_fix_for(std::chrono::seconds{15 * 60}), "Wait for fix timed out."); |
1663 | + provider->deactivate(); |
1664 | + } |
1665 | + auto stop = std::chrono::duration_cast<std::chrono::microseconds>(location::Clock::now().time_since_epoch()); |
1666 | + |
1667 | + stats((stop - start).count()); |
1668 | + } |
1669 | + |
1670 | + cout << "Mean time to first fix in [ms]: " |
1671 | + << std::chrono::duration_cast<std::chrono::milliseconds>( |
1672 | + std::chrono::microseconds( |
1673 | + static_cast<std::uint64_t>(mean(stats)))).count() |
1674 | + << std::endl; |
1675 | + cout << "Std.dev. in time to first fix in [ms]: " |
1676 | + << std::chrono::duration_cast<std::chrono::milliseconds>( |
1677 | + std::chrono::microseconds( |
1678 | + static_cast<std::uint64_t>(std::sqrt(variance(stats))))).count() |
1679 | + << std::endl; |
1680 | + |
1681 | + return 0; |
1682 | } |
1683 | |
1684 | -int location::execute_runtime_tests(std::ostream& cout, std::ostream& cerr) |
1685 | +} // namespace |
1686 | + |
1687 | +int location::execute_runtime_tests(const std::string& test_suite, std::ostream& cout, std::ostream& cerr) |
1688 | { |
1689 | - Fixture fixture; // This throws in case of issues. |
1690 | - auto rc = snr_and_ttff(cout, cerr); if (rc != 0) return rc; |
1691 | - // Other runtime tests go here; |
1692 | - return rc; |
1693 | + if (test_suite == "android-gps") |
1694 | + return snr_and_ttff(cout, cerr); |
1695 | + else if (test_suite == "ubx") |
1696 | + return ubx(cout, cerr); |
1697 | + return 0; |
1698 | } |
1699 | |
1700 | === modified file 'src/location/runtime_tests.h' |
1701 | --- src/location/runtime_tests.h 2016-06-30 09:13:21 +0000 |
1702 | +++ src/location/runtime_tests.h 2017-03-29 20:24:25 +0000 |
1703 | @@ -19,12 +19,13 @@ |
1704 | #define LOCATION_RUNTIME_TESTS_H_ |
1705 | |
1706 | #include <iosfwd> |
1707 | +#include <string> |
1708 | |
1709 | namespace location |
1710 | { |
1711 | // execute_runtime_tests runs all configured runtime tests. |
1712 | // Returns 0 if successful. |
1713 | -int execute_runtime_tests(std::ostream& cout, std::ostream& cerr); |
1714 | +int execute_runtime_tests(const std::string& test_suite, std::ostream& cout, std::ostream& cerr); |
1715 | } |
1716 | |
1717 | #endif // LOCATION_RUNTIME_TESTS_H_ |
LGTM