16
16
* Authored by: Thomas Voß <thomas.voss@canonical.com>
18
#include "com/ubuntu/location/providers/gps.h"
18
#include <com/ubuntu/location/providers/gps/provider.h>
19
#include <com/ubuntu/location/providers/gps/android_hardware_abstraction_layer.h>
21
//TODO(tvoss) Reenable
22
//#include <com/ubuntu/location/providers/gps/net_cpp_gps_xtra_downloader.h>
24
#include <com/ubuntu/location/logging.h>
25
#include <com/ubuntu/location/service/program_options.h>
27
#include <core/posix/fork.h>
28
#include <core/posix/this_process.h>
30
#include <core/testing/cross_process_sync.h>
20
32
#include <gmock/gmock.h>
21
33
#include <gtest/gtest.h>
23
TEST(GeoclueProvider, accessing_starting_and_stopping_gps_provider_works)
25
com::ubuntu::location::GpsProvider provider;
35
#include <boost/accumulators/accumulators.hpp>
36
#include <boost/accumulators/statistics/stats.hpp>
37
#include <boost/accumulators/statistics/mean.hpp>
38
#include <boost/accumulators/statistics/variance.hpp>
41
#include <condition_variable>
45
#include "web_server.h"
47
namespace gps = com::ubuntu::location::providers::gps;
48
namespace location = com::ubuntu::location;
54
MOCK_METHOD1(on_position_updated, void(const location::Position&));
55
MOCK_METHOD1(on_heading_updated, void(const location::Heading&));
56
MOCK_METHOD1(on_velocity_updated, void(const location::Velocity&));
57
MOCK_METHOD1(on_space_vehicles_updated, void(const std::set<location::SpaceVehicle>&));
60
struct MockSuplAssistant : public gps::HardwareAbstractionLayer::SuplAssistant
64
using namespace ::testing;
66
ON_CALL(*this, status()).WillByDefault(ReturnRef(status_));
67
ON_CALL(*this, server_ip()).WillByDefault(ReturnRef(ip_address_));
70
MOCK_CONST_METHOD0(status, const core::Property<Status>&());
71
MOCK_CONST_METHOD0(server_ip, const core::Property<IpV4Address>&());
72
MOCK_METHOD2(set_server, void(const std::string&, std::uint16_t));
73
MOCK_METHOD1(notify_data_connection_open_via_apn, void(const std::string&));
74
MOCK_METHOD0(notify_data_connection_closed, void());
75
MOCK_METHOD0(notify_data_connection_not_available, void());
77
core::Property<Status> status_;
78
core::Property<IpV4Address> ip_address_;
81
struct MockHardwareAbstractionLayer : public gps::HardwareAbstractionLayer
83
MockHardwareAbstractionLayer()
85
using namespace ::testing;
87
ON_CALL(*this, supl_assistant()).WillByDefault(ReturnRef(supl_assistant_));
88
ON_CALL(*this, start_positioning()).WillByDefault(Return(true));
89
ON_CALL(*this, stop_positioning()).WillByDefault(Return(true));
90
ON_CALL(*this, position_updates()).WillByDefault(ReturnRef(position_updates_));
91
ON_CALL(*this, heading_updates()).WillByDefault(ReturnRef(heading_updates_));
92
ON_CALL(*this, velocity_updates()).WillByDefault(ReturnRef(velocity_updates_));
93
ON_CALL(*this, space_vehicle_updates()).WillByDefault(ReturnRef(space_vehicle_updates_));
94
ON_CALL(*this, chipset_status()).WillByDefault(ReturnRef(chipset_status_));
97
MOCK_METHOD0(supl_assistant, gps::HardwareAbstractionLayer::SuplAssistant&());
98
MOCK_CONST_METHOD0(position_updates, const core::Signal<location::Position>& ());
99
MOCK_CONST_METHOD0(heading_updates, const core::Signal<location::Heading>&());
100
MOCK_CONST_METHOD0(velocity_updates, const core::Signal<location::Velocity>& ());
101
MOCK_CONST_METHOD0(space_vehicle_updates, const core::Signal<std::set<location::SpaceVehicle>>&());
102
MOCK_METHOD0(delete_all_aiding_data, void());
103
MOCK_CONST_METHOD0(chipset_status, const core::Property<gps::ChipsetStatus>&());
104
MOCK_CONST_METHOD1(is_capable_of, bool(gps::AssistanceMode));
105
MOCK_CONST_METHOD1(is_capable_of, bool(gps::PositionMode));
106
MOCK_CONST_METHOD1(is_capable_of, bool(gps::Capability capability));
107
MOCK_METHOD0(start_positioning, bool());
108
MOCK_METHOD0(stop_positioning, bool());
109
MOCK_METHOD1(set_assistance_mode, bool(gps::AssistanceMode));
110
MOCK_METHOD1(set_position_mode, bool(gps::PositionMode));
111
MOCK_METHOD1(inject_reference_position, bool(const location::Position&));
112
MOCK_METHOD2(inject_reference_time,
113
bool(const std::chrono::microseconds&,
114
const std::chrono::microseconds&));
116
MockSuplAssistant supl_assistant_;
117
core::Signal<location::Position> position_updates_;
118
core::Signal<location::Heading> heading_updates_;
119
core::Signal<location::Velocity> velocity_updates_;
120
core::Signal<std::set<location::SpaceVehicle>> space_vehicle_updates_;
121
core::Property<gps::ChipsetStatus> chipset_status_;
126
# XTRA_SERVER_QUERY (1=on, 0=off)
127
# If XTRA_SERVER_QUERY is on, the XTRA_SERVERs listed
128
# below will be ignored, and instead the servers will
129
# be queried from the modem.
131
# XTRA_SERVERs below are used only if XTRA_SERVER_QUERY
133
XTRA_SERVER_1=http://xtra1.gpsonextra.net/xtra2.bin
134
XTRA_SERVER_2=http://xtra2.gpsonextra.net/xtra2.bin
135
XTRA_SERVER_3=http://xtra3.gpsonextra.net/xtra2.bin
143
NTP_SERVER=time.gpsonextra.net
145
# NTP_SERVER=asia.pool.ntp.org
147
# NTP_SERVER=europe.pool.ntp.org
149
# NTP_SERVER=north-america.pool.ntp.org
151
# DEBUG LEVELS: 0 - none, 1 - Error, 2 - Warning, 3 - Info
152
# 4 - Debug, 5 - Verbose
153
# If DEBUG_LEVEL is commented, Android's logging levels will be used
156
# Intermediate position report, 1=enable, 0=disable
162
# GPS Capabilities bit mask
166
# ON_DEMAND_TIME = 0x10
168
# default = ON_DEMAND_TIME | MSA | MSB | SCHEDULING | GEOFENCE
171
# Accuracy threshold for intermediate positions
172
# less accurate positions are ignored, 0 for passing all positions
173
# ACCURACY_THRES=5000
175
################################
176
##### AGPS server settings #####
177
################################
179
# FOR SUPL SUPPORT, set the following
180
# SUPL_HOST=supl.host.com or IP
182
SUPL_HOST=supl.google.com
185
# FOR C2K PDE SUPPORT, set the following
186
# C2K_HOST=c2k.pde.com or IP
189
####################################
190
# LTE Positioning Profile Settings
191
####################################
192
# 0: Enable RRLP on LTE(Default)
193
# 1: Enable LPP_User_Plane on LTE
194
# 2: Enable LPP_Control_Plane
195
# 3: Enable both LPP_User_Plane and LPP_Control_Plane
198
################################
200
################################
201
# NMEA provider (1=Modem Processor, 0=Application Processor)
204
##################################################
205
# Select Positioning Protocol on A-GLONASS system
206
##################################################
210
A_GLONASS_POS_PROTOCOL_SELECT = 0
215
TEST(AndroidGpsXtraDownloader, reading_configuration_from_valid_conf_file_works)
217
std::stringstream ss{gps_conf};
219
auto config = gps::android::GpsXtraDownloader::Configuration::from_gps_conf_ini_file(ss);
221
EXPECT_EQ(3, config.xtra_hosts.size());
223
EXPECT_EQ("http://xtra1.gpsonextra.net/xtra2.bin", config.xtra_hosts.at(0));
224
EXPECT_EQ("http://xtra2.gpsonextra.net/xtra2.bin", config.xtra_hosts.at(1));
225
EXPECT_EQ("http://xtra3.gpsonextra.net/xtra2.bin", config.xtra_hosts.at(2));
228
TEST(GpsProvider, starting_updates_on_a_provider_instance_calls_into_the_hal)
230
using namespace ::testing;
232
NiceMock<MockHardwareAbstractionLayer> hal;
233
std::shared_ptr<gps::HardwareAbstractionLayer> hal_ptr(&hal, [](gps::HardwareAbstractionLayer*){});
235
gps::Provider provider(hal_ptr);
237
EXPECT_CALL(hal, start_positioning()).Times(3);
238
// Stop positioning will be called by the provider's dtor.
239
// Thus 3 explicit stops and 1 implicit.
240
EXPECT_CALL(hal, stop_positioning()).Times(4);
242
provider.start_position_updates();
243
provider.start_heading_updates();
244
provider.start_velocity_updates();
246
provider.stop_position_updates();
247
provider.stop_heading_updates();
248
provider.stop_velocity_updates();
251
TEST(GpsProvider, injecting_a_reference_position_calls_into_the_hal)
253
using namespace ::testing;
255
NiceMock<MockHardwareAbstractionLayer> hal;
256
std::shared_ptr<gps::HardwareAbstractionLayer> hal_ptr(&hal, [](gps::HardwareAbstractionLayer*){});
258
gps::Provider provider(hal_ptr);
259
location::Position pos;
260
EXPECT_CALL(hal, inject_reference_position(pos)).Times(1);
262
provider.on_reference_location_updated(pos);
265
TEST(GpsProvider, updates_from_hal_are_passed_on_by_the_provider)
267
using namespace ::testing;
269
NiceMock<MockHardwareAbstractionLayer> hal;
270
std::shared_ptr<gps::HardwareAbstractionLayer> hal_ptr(&hal, [](gps::HardwareAbstractionLayer*){});
272
UpdateTrap update_trap;
274
gps::Provider provider(hal_ptr);
275
location::Position pos;
276
location::Heading heading;
277
location::Velocity velocity;
278
std::set<location::SpaceVehicle> svs;
280
provider.updates().position.connect([&update_trap](const location::Update<location::Position>& pos)
282
update_trap.on_position_updated(pos.value);
284
provider.updates().heading.connect([&update_trap](const location::Update<location::Heading>& heading)
286
update_trap.on_heading_updated(heading.value);
288
provider.updates().velocity.connect([&update_trap](const location::Update<location::Velocity>& velocity)
290
update_trap.on_velocity_updated(velocity.value);
292
provider.updates().svs.connect([&update_trap](const location::Update<std::set<location::SpaceVehicle>>& svs)
294
update_trap.on_space_vehicles_updated(svs.value);
297
EXPECT_CALL(update_trap, on_position_updated(pos)).Times(1);
298
EXPECT_CALL(update_trap, on_heading_updated(heading)).Times(1);
299
EXPECT_CALL(update_trap, on_velocity_updated(velocity)).Times(1);
300
EXPECT_CALL(update_trap, on_space_vehicles_updated(svs)).Times(1);
302
hal.position_updates_(pos);
303
hal.heading_updates_(heading);
304
hal.velocity_updates_(velocity);
305
hal.space_vehicle_updates_(svs);
308
// TODO(tvoss): Reenable
310
TEST(GpsXtraDownloader, throws_for_missing_xtra_hosts)
312
gps::android::NetCppGpsXtraDownloader downloader;
313
EXPECT_ANY_THROW(downloader.download_xtra_data(gps::android::GpsXtraDownloader::Configuration{}));
316
TEST(GpsXtraDownloader, downloading_xtra_data_from_known_host_works)
318
static const int data_size{200};
320
core::testing::CrossProcessSync cps; // server - ready -> client
322
testing::web::server::Configuration configuration
325
[&cps](mg_connection* conn)
327
static char data[data_size];
328
for (int i = 0; i < data_size; i++)
331
std::map<std::string, std::set<std::string>> header;
333
for (int i = 0; i < conn->num_headers; i++)
335
header[conn->http_headers[i].name].insert(conn->http_headers[i].value);
338
EXPECT_TRUE(header.at("ACCEPT").count("") == 1);
339
EXPECT_TRUE(header.at("ACCEPT").count("application/vnd.wap.mms-message") == 1);
340
EXPECT_TRUE(header.at("ACCEPT").count("application/vnd.wap.sic") == 1);
341
EXPECT_TRUE(header.at("X-WAP-PROFILE")
342
.count(gps::android::GpsXtraDownloader::x_wap_profile_value) == 1);
344
mg_send_status(conn, 200);
345
mg_send_data(conn, &data, data_size);
351
auto server = core::posix::fork(
352
std::bind(testing::a_web_server(configuration), cps),
353
core::posix::StandardStream::empty);
355
cps.wait_for_signal_ready_for(std::chrono::seconds{2});
357
gps::android::GpsXtraDownloader::Configuration config;
358
config.xtra_hosts.push_back("http://127.0.0.1:5000");
360
gps::android::NetCppGpsXtraDownloader downloader;
361
auto result = downloader.download_xtra_data(config);
363
EXPECT_EQ(data_size, result.size());
364
for (int i = 0; i < data_size; i++)
365
EXPECT_EQ(i%2, result[i]);
368
TEST(GpsXtraDownloader, throws_for_unreachable_host)
370
gps::android::GpsXtraDownloader::Configuration config;
371
config.xtra_hosts.push_back("http://does_not_exist.host.com/");
373
gps::android::NetCppGpsXtraDownloader downloader;
374
EXPECT_ANY_THROW(downloader.download_xtra_data(config));
377
TEST(GpsXtraDownloader, download_attempt_throws_if_timeout_is_reached)
379
testing::web::server::Configuration web_serverconfiguration
388
core::testing::CrossProcessSync cps; // server - ready -> client
390
auto server = core::posix::fork(
391
std::bind(testing::a_web_server(web_serverconfiguration), cps),
392
core::posix::StandardStream::empty);
394
cps.wait_for_signal_ready_for(std::chrono::seconds{2});
396
gps::android::GpsXtraDownloader::Configuration download_config;
397
download_config.xtra_hosts.push_back("http://127.0.0.1:5000");
399
gps::android::NetCppGpsXtraDownloader downloader;
400
EXPECT_ANY_THROW(downloader.download_xtra_data(download_config));
404
/*****************************************************************
406
* All tests requiring hardware go here. They are named with *
407
* the suffix requires_hardware to indicate that they shouldn't *
408
* be executed as part of the usual build/test cycle. Instead *
409
* they are packaged up for later execution on an emulated or *
412
****************************************************************/
413
TEST(GpsProvider, DISABLED_accessing_starting_and_stopping_gps_provider_works_requires_hardware)
415
com::ubuntu::location::providers::gps::Provider provider;
26
416
EXPECT_NO_THROW(provider.start_position_updates());
27
417
EXPECT_NO_THROW(provider.stop_position_updates());
28
418
EXPECT_NO_THROW(provider.start_velocity_updates());
30
420
EXPECT_NO_THROW(provider.start_heading_updates());
31
421
EXPECT_NO_THROW(provider.stop_heading_updates());
424
// We are carrying out quite some positioning here and leverage that fact for feeding location
425
// and wifi/cell data to Mozilla location service instances. Please note that we feed to the mozilla location service
426
// in the general case.
427
#include <com/ubuntu/location/service/harvester.h>
429
// TODO(tvoss): Enable reporting to the Mozilla location service.
430
// #include <com/ubuntu/location/service/ichnaea_reporter.h>
434
struct NullReporter : public location::service::Harvester::Reporter
436
NullReporter() = default;
438
/** @brief Tell the reporter that it should start operating. */
443
/** @brief Tell the reporter to shut down its operation. */
449
* @brief Triggers the reporter to send off the information.
451
void report(const location::Update<location::Position>&,
452
const std::vector<location::connectivity::WirelessNetwork::Ptr>&,
453
const std::vector<location::connectivity::RadioCell::Ptr>&)
458
struct HardwareAbstractionLayerFixture : public ::testing::Test
460
// If this key is set to any value in the environment, we send off data to Mozilla location
461
// service instances. ENABLE_HARVESTING_DURING_TESTS
462
static constexpr const char* enable_harvesting{"enable_harvesting_during_tests"};
463
// The host name of the Mozilla location service instance.
464
static constexpr const char* ichnaea_host{"ichnaea_host"};
465
// The API key to submit under.
466
static constexpr const char* ichnaea_api_key{"ichnaea_api_key"};
467
// The API key to submit under.
468
static constexpr const char* ichnaea_nickname{"ichnaea_nickname"};
469
// Reference latitude value.
470
static constexpr const char* ref_lat{"ref_lat"};
471
// Reference longitude value.
472
static constexpr const char* ref_lon{"ref_lon"};
473
// Reference horizontal accuracy value.
474
static constexpr const char* ref_accuracy{"ref_accuracy"};
476
static constexpr const char* supl_host{"supl_host"};
478
static constexpr const char* supl_port{"supl_port"};
480
static location::ProgramOptions init_options()
482
location::ProgramOptions options;
484
options.environment_prefix("GPS_TEST_");
486
options.add(enable_harvesting,
487
"If this key is set to any value in the environment, "
488
"we send off data to Mozilla location service instances.",
491
options.add(ichnaea_host,
492
"The host name of the Mozilla location service instance.",
493
std::string{"https://location.services.mozilla.com"});
495
options.add(ichnaea_api_key,
496
"The API key to submit under.",
497
std::string{"ubuntu_location_service_test_cases"});
499
options.add(ichnaea_nickname,
500
"The nickname to submit under.",
501
std::string{"ubuntu_location_service"});
504
"Reference latitude value.",
508
"Reference longitude value.",
511
options.add(ref_accuracy,
512
"Reference horizontal accuracy value.",
515
options.add(supl_host,
516
"SUPL host to use for positioning benchmarks.",
517
std::string{"supl.google.com"});
519
options.add(supl_port,
520
"SUPL port to use for positioning benchmarks.",
521
std::uint16_t{7476});
526
HardwareAbstractionLayerFixture()
528
options.print(LOG(INFO));
534
// We need to make sure that we are running as root. In addition, we will stop
535
// any running location service instance prior to executing the test.
536
if (!(::getuid() == 0))
537
FAIL() << "This test has to be run as root.";
539
int rc = ::system("service ubuntu-location-service stop");
541
// We consciously ignore the return code of the command here.
542
// The location service might not have been running before and with that
543
// the command would return an error, although the precondition has been successfully
546
FAIL() << "Unable to stop the location service as part of the test setup.";
551
int rc = ::system("service ubuntu-location-service start");
555
bool IsHarvestingDuringTestsEnabled() const
557
return options.value_for_key<bool>(enable_harvesting);
560
location::ProgramOptions options = init_options();
561
bool options_parsed_from_env
563
options.parse_from_environment()
565
// The Ichnaea instance and its configuration.
566
//location::service::ichnaea::Reporter::Configuration reporter_configuration
568
// options.value_for_key<std::string>(ichnaea_host),
569
// options.value_for_key<std::string>(ichnaea_api_key),
570
// options.value_for_key<std::string>(ichnaea_nickname)
572
//std::shared_ptr<location::service::ichnaea::Reporter> reporter
574
// new location::service::ichnaea::Reporter{reporter_configuration}
576
// The harvester instance and its configuration.
577
location::service::Harvester::Configuration harvester_configuration
579
location::connectivity::platform_default_manager(),
580
location::service::Harvester::Reporter::Ptr{new NullReporter{}}
582
location::service::Harvester harvester
584
harvester_configuration
586
// Reference position for SUPL benchmarks.
587
location::Position ref_pos
589
location::wgs84::Latitude
591
options.value_for_key<double>(ref_lat) * location::units::Degrees
593
location::wgs84::Longitude
595
options.value_for_key<double>(ref_lon) * location::units::Degrees
597
location::wgs84::Altitude
599
0 * location::units::Meter
601
location::units::Quantity<location::units::Length>
603
options.value_for_key<double>(ref_accuracy) * location::units::Meters
609
TEST_F(HardwareAbstractionLayerFixture, DISABLED_provider_construction_works_requires_hardware)
612
location::ProviderFactory::instance().create_provider_for_name_with_config("gps::Provider", location::Configuration{});
616
gps::Provider provider;
620
gps::Provider::create_instance(location::Configuration{});
624
location::ProviderFactory::instance().create_provider_for_name_with_config("gps::Provider", location::Configuration{});
628
// HardwareAbstractionLayerFixture.time_to_first_fix_cold_start_without_supl_benchmark_requires_hardware
629
TEST_F(HardwareAbstractionLayerFixture, time_to_first_fix_cold_start_without_supl_benchmark_requires_hardware)
631
typedef boost::accumulators::accumulator_set<
633
boost::accumulators::stats<
634
boost::accumulators::tag::mean,
635
boost::accumulators::tag::variance
639
using boost::accumulators::mean;
640
using boost::accumulators::variance;
642
static const unsigned int trials = 3;
645
auto hal = gps::HardwareAbstractionLayer::create_default_instance();
649
State() : fix_received(false)
653
bool wait_for_fix_for(const std::chrono::seconds& seconds)
655
std::unique_lock<std::mutex> ul(guard);
656
return wait_condition.wait_for(
659
[this]() {return fix_received == true;});
662
void on_position_updated(const location::Position&)
665
wait_condition.notify_all();
670
fix_received = false;
674
std::condition_variable wait_condition;
678
// We want to run in standalone mode
679
hal->set_assistance_mode(gps::AssistanceMode::standalone);
681
// We wire up our state to position updates from the hal.
682
hal->position_updates().connect([this, &state](const location::Position& pos)
684
if (IsHarvestingDuringTestsEnabled())
685
harvester.report_position_update(location::Update<location::Position>
687
pos, location::Clock::now()
689
state.on_position_updated(pos);
692
for (unsigned int i = 0; i < trials; i++)
694
std::cout << "Executing trial " << i << " of " << trials << " trials" << std::endl;
695
// We want to force a cold start per trial.
696
hal->delete_all_aiding_data();
699
auto start = std::chrono::duration_cast<std::chrono::microseconds>(location::Clock::now().time_since_epoch());
701
hal->start_positioning();
702
// We expect a maximum cold start time of 15 minutes. The theoretical
703
// limit is 12.5 minutes, and we add up some grace period to make the
704
// test more robust (see http://en.wikipedia.org/wiki/Time_to_first_fix).
705
EXPECT_TRUE(state.wait_for_fix_for(std::chrono::seconds{15 * 60}));
706
hal->stop_positioning();
708
auto stop = std::chrono::duration_cast<std::chrono::microseconds>(location::Clock::now().time_since_epoch());
710
stats((stop - start).count());
713
std::cout << "Mean time to first fix in [ms]: "
714
<< std::chrono::duration_cast<std::chrono::milliseconds>(
715
std::chrono::microseconds(
716
static_cast<std::uint64_t>(mean(stats)))).count()
718
std::cout << "Variance in time to first fix in [ms]: "
719
<< std::chrono::duration_cast<std::chrono::milliseconds>(
720
std::chrono::microseconds(
721
static_cast<std::uint64_t>(variance(stats)))).count()
725
// HardwareAbstractionLayerFixture.time_to_first_fix_cold_start_with_supl_benchmark_requires_hardware
726
TEST_F(HardwareAbstractionLayerFixture, time_to_first_fix_cold_start_with_supl_benchmark_requires_hardware)
728
using namespace core::posix;
730
typedef boost::accumulators::accumulator_set<
732
boost::accumulators::stats<
733
boost::accumulators::tag::mean,
734
boost::accumulators::tag::variance
738
using boost::accumulators::mean;
739
using boost::accumulators::variance;
741
static const unsigned int trials = 3;
744
auto hal = gps::HardwareAbstractionLayer::create_default_instance();
748
State() : fix_received(false)
752
bool wait_for_fix_for(const std::chrono::seconds& seconds)
754
std::unique_lock<std::mutex> ul(guard);
755
return wait_condition.wait_for(
758
[this]() {return fix_received == true;});
761
void on_position_updated(const location::Position&)
764
wait_condition.notify_all();
769
fix_received = false;
773
std::condition_variable wait_condition;
777
// We wire up our state to position updates from the hal.
778
hal->position_updates().connect([this, &state](const location::Position& pos)
780
if (IsHarvestingDuringTestsEnabled())
781
harvester.report_position_update(location::Update<location::Position>
783
pos, location::Clock::now()
785
state.on_position_updated(pos);
788
for (unsigned int i = 0; i < trials; i++)
790
std::cout << "Executing trial " << i << " of " << trials << " trials" << std::endl;
792
// We want to force a cold start per trial.
793
hal->delete_all_aiding_data();
796
// We want to run in assisted mode
797
EXPECT_TRUE(hal->set_assistance_mode(gps::AssistanceMode::mobile_station_based));
799
auto supl_host = options.value_for_key<std::string>(HardwareAbstractionLayerFixture::supl_host);
800
auto supl_port = options.value_for_key<std::uint16_t>(HardwareAbstractionLayerFixture::supl_port);
802
hal->supl_assistant().set_server(supl_host, supl_port);
804
auto start = std::chrono::duration_cast<std::chrono::microseconds>(location::Clock::now().time_since_epoch());
808
hal->start_positioning();
810
std::thread injector([this, hal, &running]()
814
hal->inject_reference_position(ref_pos);
815
std::this_thread::sleep_for(std::chrono::seconds{1});
819
// We expect a maximum cold start time of 15 minutes. The theoretical
820
// limit is 12.5 minutes, and we add up some grace period to make the
821
// test more robust (see http://en.wikipedia.org/wiki/Time_to_first_fix).
822
EXPECT_TRUE(state.wait_for_fix_for(std::chrono::seconds{15 * 60}));
823
hal->stop_positioning();
826
if (injector.joinable())
830
auto stop = std::chrono::duration_cast<std::chrono::microseconds>(location::Clock::now().time_since_epoch());
832
stats((stop - start).count());
835
std::cout << "Mean time to first fix in [ms]: "
836
<< std::chrono::duration_cast<std::chrono::milliseconds>(
837
std::chrono::microseconds(
838
static_cast<std::uint64_t>(mean(stats)))).count()
840
std::cout << "Variance in time to first fix in [ms]: "
841
<< std::chrono::duration_cast<std::chrono::milliseconds>(
842
std::chrono::microseconds(
843
static_cast<std::uint64_t>(variance(stats)))).count()