diff --git a/CMakeLists.txt b/CMakeLists.txt index 0eb1ff6e9..e98c6af33 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -59,6 +59,9 @@ if(ENABLE_PACKAGING) set(ENABLE_GENERIC_ARCH ON) endif(ENABLE_PACKAGING) +# Testing +option(ENABLE_SYSTEM_TESTING "Builds system tests" OFF) +option(ENABLE_UNIT_TESTING "Builds unit tests" ON) ############################### # GNSS-SDR version information @@ -296,29 +299,31 @@ endif(NOT ENABLE_GENERIC_ARCH) # Googletest - https://github.com/google/googletest ################################################################################ enable_testing() -if(EXISTS $ENV{GTEST_DIR}) - set(GTEST_DIR $ENV{GTEST_DIR}) -endif(EXISTS $ENV{GTEST_DIR}) -if(GTEST_DIR) - message(STATUS "Googletest root folder set at ${GTEST_DIR}") - find_path(LIBGTEST_DEV_DIR NAMES src/gtest-all.cc PATHS ${GTEST_DIR}) - if(LIBGTEST_DEV_DIR) - message (STATUS "Googletest has been found.") - else(LIBGTEST_DEV_DIR) - message (FATAL_ERROR " Googletest source code has not been found at ${GTEST_DIR}.") - endif(LIBGTEST_DEV_DIR) - find_path(GTEST_INCLUDE_DIRS NAMES gtest/gtest.h PATHS ${GTEST_DIR}/include) -else(GTEST_DIR) - find_path(LIBGTEST_DEV_DIR NAMES src/gtest-all.cc PATHS /usr/src/gtest /opt/local/src/gtest-1.7.0) - find_path(GTEST_INCLUDE_DIRS NAMES gtest/gtest.h PATHS /usr/include /opt/local/src/gtest-1.7.0/include) - if(LIBGTEST_DEV_DIR) - message (STATUS "Googletest (libgtest-dev package) has been found.") - else(LIBGTEST_DEV_DIR) - message (STATUS " Googletest has not been found.") - message (STATUS " Googletest will be downloaded and built automatically ") - message (STATUS " when doing 'make'. ") - endif(LIBGTEST_DEV_DIR) -endif(GTEST_DIR) +if(ENABLE_UNIT_TESTING OR ENABLE_SYSTEM_TESTING) + if(EXISTS $ENV{GTEST_DIR}) + set(GTEST_DIR $ENV{GTEST_DIR}) + endif(EXISTS $ENV{GTEST_DIR}) + if(GTEST_DIR) + message(STATUS "Googletest root folder set at ${GTEST_DIR}") + find_path(LIBGTEST_DEV_DIR NAMES src/gtest-all.cc PATHS ${GTEST_DIR}) + if(LIBGTEST_DEV_DIR) + message (STATUS "Googletest has been found.") + else(LIBGTEST_DEV_DIR) + message (FATAL_ERROR " Googletest source code has not been found at ${GTEST_DIR}.") + endif(LIBGTEST_DEV_DIR) + find_path(GTEST_INCLUDE_DIRS NAMES gtest/gtest.h PATHS ${GTEST_DIR}/include) + else(GTEST_DIR) + find_path(LIBGTEST_DEV_DIR NAMES src/gtest-all.cc PATHS /usr/src/gtest /opt/local/src/gtest-1.7.0) + find_path(GTEST_INCLUDE_DIRS NAMES gtest/gtest.h PATHS /usr/include /opt/local/src/gtest-1.7.0/include) + if(LIBGTEST_DEV_DIR) + message (STATUS "Googletest (libgtest-dev package) has been found.") + else(LIBGTEST_DEV_DIR) + message (STATUS " Googletest has not been found.") + message (STATUS " Googletest will be downloaded and built automatically ") + message (STATUS " when doing 'make'. ") + endif(LIBGTEST_DEV_DIR) + endif(GTEST_DIR) +endif(ENABLE_UNIT_TESTING OR ENABLE_SYSTEM_TESTING) diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 368063869..fbce5e499 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -19,5 +19,7 @@ add_subdirectory(algorithms) add_subdirectory(core) add_subdirectory(main) -add_subdirectory(tests) +if(ENABLE_UNIT_TESTING OR ENABLE_SYSTEM_TESTING) + add_subdirectory(tests) +endif(ENABLE_UNIT_TESTING OR ENABLE_SYSTEM_TESTING) add_subdirectory(utils) diff --git a/src/algorithms/PVT/gnuradio_blocks/galileo_e1_pvt_cc.cc b/src/algorithms/PVT/gnuradio_blocks/galileo_e1_pvt_cc.cc index a9717e568..0b17a2b2a 100644 --- a/src/algorithms/PVT/gnuradio_blocks/galileo_e1_pvt_cc.cc +++ b/src/algorithms/PVT/gnuradio_blocks/galileo_e1_pvt_cc.cc @@ -198,6 +198,16 @@ galileo_e1_pvt_cc::galileo_e1_pvt_cc(unsigned int nchannels, bool dump, std::str } } } + + // Create Sys V message queue + first_fix = true; + sysv_msg_key = 1101; + int msgflg = IPC_CREAT | 0666; + if ((sysv_msqid = msgget(sysv_msg_key, msgflg )) == -1) + { + std::cout << "GNSS-SDR can not create message queues!" << std::endl; + throw new std::exception(); + } } @@ -227,6 +237,21 @@ void galileo_e1_pvt_cc::print_receiver_status(Gnss_Synchro** channels_synchroniz } +bool galileo_e1_pvt_cc::send_sys_v_ttff_msg(ttff_msgbuf ttff) +{ + /* Fill Sys V message structures */ + int msgsend_size; + ttff_msgbuf msg; + msg.ttff = ttff.ttff; + msgsend_size = sizeof(msg.ttff); + msg.mtype = 1; /* default message ID */ + + /* SEND SOLUTION OVER A MESSAGE QUEUE */ + /* non-blocking Sys V message send */ + msgsnd(sysv_msqid, &msg, msgsend_size, IPC_NOWAIT); + return true; +} + int galileo_e1_pvt_cc::general_work (int noutput_items __attribute__((unused)), gr_vector_int &ninput_items __attribute__((unused)), gr_vector_const_void_star &input_items, gr_vector_void_star &output_items __attribute__((unused))) { @@ -267,6 +292,17 @@ int galileo_e1_pvt_cc::general_work (int noutput_items __attribute__((unused)), if (pvt_result == true) { + if( first_fix == true) + { + std::cout << "First position fix at " << boost::posix_time::to_simple_string(d_ls_pvt->d_position_UTC_time) + << " UTC is Lat = " << d_ls_pvt->d_latitude_d << " [deg], Long = " << d_ls_pvt->d_longitude_d + << " [deg], Height= " << d_ls_pvt->d_height_m << " [m]" << std::endl; + ttff_msgbuf ttff; + ttff.mtype = 1; + ttff.ttff = d_sample_counter; + send_sys_v_ttff_msg(ttff); + first_fix = false; + } d_kml_dump->print_position(d_ls_pvt, d_flag_averaging); d_geojson_printer->print_position(d_ls_pvt, d_flag_averaging); d_nmea_printer->Print_Nmea_Line(d_ls_pvt, d_flag_averaging); diff --git a/src/algorithms/PVT/gnuradio_blocks/galileo_e1_pvt_cc.h b/src/algorithms/PVT/gnuradio_blocks/galileo_e1_pvt_cc.h index bcb13137f..638417905 100644 --- a/src/algorithms/PVT/gnuradio_blocks/galileo_e1_pvt_cc.h +++ b/src/algorithms/PVT/gnuradio_blocks/galileo_e1_pvt_cc.h @@ -33,6 +33,9 @@ #include #include +#include +#include +#include #include #include #include "nmea_printer.h" @@ -134,6 +137,15 @@ private: std::shared_ptr d_ls_pvt; bool pseudoranges_pairCompare_min(const std::pair& a, const std::pair& b); + bool first_fix; + key_t sysv_msg_key; + int sysv_msqid; + typedef struct { + long mtype;//required by sys v message + double ttff; + } ttff_msgbuf; + bool send_sys_v_ttff_msg(ttff_msgbuf ttff); + public: ~galileo_e1_pvt_cc (); //!< Default destructor diff --git a/src/algorithms/PVT/gnuradio_blocks/gps_l1_ca_pvt_cc.cc b/src/algorithms/PVT/gnuradio_blocks/gps_l1_ca_pvt_cc.cc index 3f656e86c..8119fe986 100644 --- a/src/algorithms/PVT/gnuradio_blocks/gps_l1_ca_pvt_cc.cc +++ b/src/algorithms/PVT/gnuradio_blocks/gps_l1_ca_pvt_cc.cc @@ -179,6 +179,21 @@ std::map gps_l1_ca_pvt_cc::get_GPS_L1_ephemeris_map() return d_ls_pvt->gps_ephemeris_map; } +bool gps_l1_ca_pvt_cc::send_sys_v_ttff_msg(ttff_msgbuf ttff) +{ + /* Fill Sys V message structures */ + int msgsend_size; + ttff_msgbuf msg; + msg.ttff = ttff.ttff; + msgsend_size = sizeof(msg.ttff); + msg.mtype = 1; /* default message ID */ + + /* SEND SOLUTION OVER A MESSAGE QUEUE */ + /* non-blocking Sys V message send */ + msgsnd(sysv_msqid, &msg, msgsend_size, IPC_NOWAIT); + return true; +} + gps_l1_ca_pvt_cc::gps_l1_ca_pvt_cc(unsigned int nchannels, bool dump, std::string dump_filename, int averaging_depth, @@ -284,6 +299,16 @@ gps_l1_ca_pvt_cc::gps_l1_ca_pvt_cc(unsigned int nchannels, } } } + + // Create Sys V message queue + first_fix = true; + sysv_msg_key = 1101; + int msgflg = IPC_CREAT | 0666; + if ((sysv_msqid = msgget(sysv_msg_key, msgflg )) == -1) + { + std::cout << "GNSS-SDR can not create message queues!" << std::endl; + throw new std::exception(); + } } @@ -349,6 +374,17 @@ int gps_l1_ca_pvt_cc::general_work (int noutput_items __attribute__((unused)), g pvt_result = d_ls_pvt->get_PVT(gnss_pseudoranges_map, d_rx_time, d_flag_averaging); if (pvt_result == true) { + if( first_fix == true) + { + std::cout << "First position fix at " << boost::posix_time::to_simple_string(d_ls_pvt->d_position_UTC_time) + << " UTC is Lat = " << d_ls_pvt->d_latitude_d << " [deg], Long = " << d_ls_pvt->d_longitude_d + << " [deg], Height= " << d_ls_pvt->d_height_m << " [m]" << std::endl; + ttff_msgbuf ttff; + ttff.mtype = 1; + ttff.ttff = d_sample_counter; + send_sys_v_ttff_msg(ttff); + first_fix = false; + } d_kml_printer->print_position(d_ls_pvt, d_flag_averaging); d_geojson_printer->print_position(d_ls_pvt, d_flag_averaging); d_nmea_printer->Print_Nmea_Line(d_ls_pvt, d_flag_averaging); diff --git a/src/algorithms/PVT/gnuradio_blocks/gps_l1_ca_pvt_cc.h b/src/algorithms/PVT/gnuradio_blocks/gps_l1_ca_pvt_cc.h index fbe2dda93..f0b3b0258 100644 --- a/src/algorithms/PVT/gnuradio_blocks/gps_l1_ca_pvt_cc.h +++ b/src/algorithms/PVT/gnuradio_blocks/gps_l1_ca_pvt_cc.h @@ -32,6 +32,9 @@ #include #include +#include +#include +#include #include #include "nmea_printer.h" #include "kml_printer.h" @@ -137,6 +140,15 @@ private: std::map gnss_pseudoranges_map; + bool first_fix; + key_t sysv_msg_key; + int sysv_msqid; + typedef struct { + long mtype;//required by sys v message + double ttff; + } ttff_msgbuf; + bool send_sys_v_ttff_msg(ttff_msgbuf ttff); + public: /*! diff --git a/src/algorithms/PVT/gnuradio_blocks/hybrid_pvt_cc.cc b/src/algorithms/PVT/gnuradio_blocks/hybrid_pvt_cc.cc index af5f0b236..9f4aabe13 100644 --- a/src/algorithms/PVT/gnuradio_blocks/hybrid_pvt_cc.cc +++ b/src/algorithms/PVT/gnuradio_blocks/hybrid_pvt_cc.cc @@ -275,6 +275,16 @@ hybrid_pvt_cc::hybrid_pvt_cc(unsigned int nchannels, bool dump, std::string dump } } } + + // Create Sys V message queue + first_fix = true; + sysv_msg_key = 1101; + int msgflg = IPC_CREAT | 0666; + if ((sysv_msqid = msgget(sysv_msg_key, msgflg )) == -1) + { + std::cout << "GNSS-SDR can not create message queues!" << std::endl; + throw new std::exception(); + } } @@ -304,6 +314,22 @@ void hybrid_pvt_cc::print_receiver_status(Gnss_Synchro** channels_synchronizatio } +bool hybrid_pvt_cc::send_sys_v_ttff_msg(ttff_msgbuf ttff) +{ + /* Fill Sys V message structures */ + int msgsend_size; + ttff_msgbuf msg; + msg.ttff = ttff.ttff; + msgsend_size = sizeof(msg.ttff); + msg.mtype = 1; /* default message ID */ + + /* SEND SOLUTION OVER A MESSAGE QUEUE */ + /* non-blocking Sys V message send */ + msgsnd(sysv_msqid, &msg, msgsend_size, IPC_NOWAIT); + return true; +} + + int hybrid_pvt_cc::general_work (int noutput_items __attribute__((unused)), gr_vector_int &ninput_items __attribute__((unused)), gr_vector_const_void_star &input_items, gr_vector_void_star &output_items __attribute__((unused))) { diff --git a/src/algorithms/PVT/gnuradio_blocks/hybrid_pvt_cc.h b/src/algorithms/PVT/gnuradio_blocks/hybrid_pvt_cc.h index 10e7b4224..21ccfeff4 100644 --- a/src/algorithms/PVT/gnuradio_blocks/hybrid_pvt_cc.h +++ b/src/algorithms/PVT/gnuradio_blocks/hybrid_pvt_cc.h @@ -34,6 +34,9 @@ #include #include #include +#include +#include +#include #include #include "nmea_printer.h" #include "kml_printer.h" @@ -137,6 +140,15 @@ private: std::map gnss_pseudoranges_map; bool pseudoranges_pairCompare_min(const std::pair& a, const std::pair& b); + bool first_fix; + key_t sysv_msg_key; + int sysv_msqid; + typedef struct { + long mtype;//required by sys v message + double ttff; + } ttff_msgbuf; + bool send_sys_v_ttff_msg(ttff_msgbuf ttff); + public: /*! * \brief Get latest set of GPS L1 ephemeris from PVT block diff --git a/src/core/receiver/control_thread.cc b/src/core/receiver/control_thread.cc index ac7f9dee2..7a5e9a371 100644 --- a/src/core/receiver/control_thread.cc +++ b/src/core/receiver/control_thread.cc @@ -37,6 +37,9 @@ #include #include #include +#include +#include +#include #include #include #include @@ -126,6 +129,7 @@ void ControlThread::run() assist_GNSS(); // start the keyboard_listener thread keyboard_thread_ = boost::thread(&ControlThread::keyboard_listener, this); + sysv_queue_thread_ = boost::thread(&ControlThread::sysv_queue_listener, this); // Main loop to read and process the control messages while (flowgraph_->running() && !stop_) @@ -141,9 +145,11 @@ void ControlThread::run() //Join keyboard thread #ifdef OLD_BOOST keyboard_thread_.timed_join(boost::posix_time::seconds(1)); + sysv_queue_thread_.timed_join(boost::posix_time::seconds(1)); #endif #ifndef OLD_BOOST keyboard_thread_.try_join_until(boost::chrono::steady_clock::now() + boost::chrono::milliseconds(1000)); + sysv_queue_thread_.try_join_until(boost::chrono::steady_clock::now() + boost::chrono::milliseconds(1000)); #endif LOG(INFO) << "Flowgraph stopped"; @@ -510,6 +516,41 @@ void ControlThread::gps_acq_assist_data_collector() } } +void ControlThread::sysv_queue_listener() +{ + typedef struct { + long mtype; //required by sys v message + double ttff; + } ttff_msgbuf; + bool read_queue = true; + ttff_msgbuf msg; + double ttff_msg = 0.0; + int msgrcv_size = sizeof(msg.ttff); + int msqid; + key_t key = 1102; + // wait for the queue to be created + + while(read_queue) + { + while((msqid = msgget(key, 0644)) == -1){} + if (msgrcv(msqid, &msg, msgrcv_size, 1, 0) != -1) + { + + ttff_msg = msg.ttff; + if(ttff_msg == 200) + { + std::cout << "Quit order received, stopping GNSS-SDR !!" << std::endl; + std::unique_ptr cmf(new ControlMessageFactory()); + if (control_queue_ != gr::msg_queue::sptr()) + { + control_queue_->handle(cmf->GetQueueMessage(200, 0)); + } + read_queue = false; + } + } + } +} + void ControlThread::keyboard_listener() { diff --git a/src/core/receiver/control_thread.h b/src/core/receiver/control_thread.h index 5d893c911..b44a81894 100644 --- a/src/core/receiver/control_thread.h +++ b/src/core/receiver/control_thread.h @@ -155,9 +155,11 @@ private: unsigned int processed_control_messages_; unsigned int applied_actions_; boost::thread keyboard_thread_; + boost::thread sysv_queue_thread_; boost::thread gps_acq_assist_data_collector_thread_; void keyboard_listener(); + void sysv_queue_listener(); // default filename for assistance data const std::string eph_default_xml_filename = "./gps_ephemeris.xml"; diff --git a/src/core/receiver/in_memory_configuration.cc b/src/core/receiver/in_memory_configuration.cc index affec742f..e1983e617 100644 --- a/src/core/receiver/in_memory_configuration.cc +++ b/src/core/receiver/in_memory_configuration.cc @@ -36,7 +36,9 @@ #include "string_converter.h" InMemoryConfiguration::InMemoryConfiguration() -{} +{ + std::unique_ptr converter_(new StringConverter); +} InMemoryConfiguration::~InMemoryConfiguration() diff --git a/src/tests/CMakeLists.txt b/src/tests/CMakeLists.txt index ad1fc14fc..d755ef93a 100644 --- a/src/tests/CMakeLists.txt +++ b/src/tests/CMakeLists.txt @@ -164,14 +164,14 @@ endif(ENABLE_CUDA) add_definitions(-DTEST_PATH="${CMAKE_SOURCE_DIR}/src/tests/") +if(ENABLE_UNIT_TESTING) + add_executable(run_tests ${CMAKE_CURRENT_SOURCE_DIR}/test_main.cc) -add_executable(run_tests ${CMAKE_CURRENT_SOURCE_DIR}/test_main.cc) - -add_custom_command(TARGET run_tests POST_BUILD + add_custom_command(TARGET run_tests POST_BUILD COMMAND ${CMAKE_COMMAND} -E copy $ ${CMAKE_SOURCE_DIR}/install/$) -target_link_libraries(run_tests ${CLANG_FLAGS} + target_link_libraries(run_tests ${CLANG_FLAGS} ${Boost_LIBRARIES} ${GFLAGS_LIBS} ${GLOG_LIBRARIES} @@ -191,8 +191,8 @@ target_link_libraries(run_tests ${CLANG_FLAGS} pvt_gr_blocks ${VOLK_GNSSSDR_LIBRARIES} ${ORC_LIBRARIES} ${GNSS_SDR_TEST_OPTIONAL_LIBS} -) - + ) +endif(ENABLE_UNIT_TESTING) ######################################################### # Adding Tests to Ctest @@ -372,3 +372,33 @@ endif(NOT ${GTEST_DIR_LOCAL}) add_dependencies(check control_thread_test flowgraph_test gnss_block_test gnuradio_block_test trk_test) + + +# Addition of System Tests +if(ENABLE_SYSTEM_TESTING) + add_executable(ttff + ${CMAKE_CURRENT_SOURCE_DIR}/system-tests/ttff_gps_l1.cc ) + if(NOT ${GTEST_DIR_LOCAL}) + add_dependencies(ttff gtest-${gtest_RELEASE}) + else(NOT ${GTEST_DIR_LOCAL}) + add_dependencies(ttff gtest) + endif(NOT ${GTEST_DIR_LOCAL}) + target_link_libraries(ttff + ${Boost_LIBRARIES} + ${GFLAGS_LIBS} + ${GLOG_LIBRARIES} + ${GTEST_LIBRARIES} + ${GNURADIO_RUNTIME_LIBRARIES} + ${GNURADIO_BLOCKS_LIBRARIES} + ${GNURADIO_FILTER_LIBRARIES} + ${GNURADIO_ANALOG_LIBRARIES} + ${VOLK_GNSSSDR_LIBRARIES} ${ORC_LIBRARIES} + gnss_sp_libs + gnss_rx + gnss_system_parameters + ) + add_custom_command(TARGET ttff POST_BUILD + COMMAND ${CMAKE_COMMAND} -E copy $ + ${CMAKE_SOURCE_DIR}/install/$ + ) +endif(ENABLE_SYSTEM_TESTING) \ No newline at end of file diff --git a/src/tests/system-tests/ttff_gps_l1.cc b/src/tests/system-tests/ttff_gps_l1.cc new file mode 100644 index 000000000..00d8988b0 --- /dev/null +++ b/src/tests/system-tests/ttff_gps_l1.cc @@ -0,0 +1,409 @@ +/*! + * \file ttff_gps_l1.cc + * \brief This class implements a test for measuring + * the Time-To-First-Fix + * \author Carles Fernandez-Prades, 2016. cfernandez(at)cttc.es + * + * + * ------------------------------------------------------------------------- + * + * Copyright (C) 2010-2016 (see AUTHORS file for a list of contributors) + * + * GNSS-SDR is a software defined Global Navigation + * Satellite Systems receiver + * + * This file is part of GNSS-SDR. + * + * GNSS-SDR is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * GNSS-SDR is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with GNSS-SDR. If not, see . + * + * ------------------------------------------------------------------------- + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "concurrent_map.h" +#include "concurrent_queue.h" +#include "control_thread.h" +#include "file_configuration.h" +#include "in_memory_configuration.h" +#include "gnss_flowgraph.h" +#include "gps_acq_assist.h" + + +DEFINE_int32(fs_in, 4000000, "Sampling rate, in Ms/s"); +DEFINE_int32(max_measurement_duration, 90, "Maximum time waiting for a position fix, in seconds"); +DEFINE_int32(num_measurements, 2, "Number of measurements"); +DEFINE_string(device_address, "192.168.40.2", "USRP device IP address"); +DEFINE_string(subdevice, "A:0", "USRP subdevice"); + + +// For GPS NAVIGATION (L1) +concurrent_queue global_gps_acq_assist_queue; +concurrent_map global_gps_acq_assist_map; + +std::vector TTFF_v; + +typedef struct { + long mtype; // required by SysV message + double ttff; +} ttff_msgbuf; + +const int decimation_factor = 1; + +class TTFF_GPS_L1_CA_Test: public ::testing::Test +{ +public: + void config_1(); + void config_2(); + void print_TTFF_report(const std::vector & ttff_v); + + std::shared_ptr config; + std::shared_ptr config2; + + const double central_freq = 1575420000.0; + const double gain_dB = 40.0; + + const int number_of_taps = 11; + const int number_of_bands = 2; + const float band1_begin = 0.0; + const float band1_end = 0.48; + const float band2_begin = 0.52; + const float band2_end = 1.0; + const float ampl1_begin = 1.0; + const float ampl1_end = 1.0; + const float ampl2_begin = 0.0; + const float ampl2_end = 0.0; + const float band1_error = 1.0; + const float band2_error = 1.0; + const int grid_density = 16; + const float zero = 0.0; + const int number_of_channels = 8; + const int in_acquisition = 1; + + const float threshold = 0.01; + const float doppler_max = 8000.0; + const float doppler_step = 500.0; + const int max_dwells = 1; + const int tong_init_val = 2; + const int tong_max_val = 10; + const int tong_max_dwells = 30; + const int coherent_integration_time_ms = 1; + + const float pll_bw_hz = 30.0; + const float dll_bw_hz = 4.0; + const float early_late_space_chips = 0.5; + + const int display_rate_ms = 500; + const int output_rate_ms = 100; + const int averaging_depth = 10; +}; + + +void TTFF_GPS_L1_CA_Test::config_1() +{ + config = std::make_shared(); + // Set the Signal Source + config->set_property("GNSS-SDR.internal_fs_hz", std::to_string(FLAGS_fs_in)); + config->set_property("SignalSource.item_type", "cshort"); + config->set_property("SignalSource.implementation", "UHD_Signal_Source"); + config->set_property("SignalSource.freq", std::to_string(central_freq)); + config->set_property("SignalSource.sampling_frequency", std::to_string(FLAGS_fs_in)); + config->set_property("SignalSource.gain", std::to_string(gain_dB)); + config->set_property("SignalSource.subdevice", FLAGS_subdevice); + config->set_property("SignalSource.samples", std::to_string(FLAGS_fs_in * FLAGS_max_measurement_duration)); + config->set_property("SignalSource.device_address", FLAGS_device_address); + + // Set the Signal Conditioner + config->set_property("SignalConditioner.implementation", "Signal_Conditioner"); + config->set_property("DataTypeAdapter.implementation", "Pass_Through"); + config->set_property("DataTypeAdapter.item_type", "cshort"); + config->set_property("InputFilter.implementation", "Fir_Filter"); + config->set_property("InputFilter.dump", "false"); + config->set_property("InputFilter.input_item_type", "cshort"); + config->set_property("InputFilter.output_item_type", "gr_complex"); + config->set_property("InputFilter.taps_item_type", "float"); + config->set_property("InputFilter.number_of_taps", std::to_string(number_of_taps)); + config->set_property("InputFilter.number_of_bands", std::to_string(number_of_bands)); + config->set_property("InputFilter.band1_begin", std::to_string(band1_begin)); + config->set_property("InputFilter.band1_end", std::to_string(band1_end)); + config->set_property("InputFilter.band2_begin", std::to_string(band2_begin)); + config->set_property("InputFilter.band2_end", std::to_string(band2_end)); + config->set_property("InputFilter.ampl1_begin", std::to_string(ampl1_begin)); + config->set_property("InputFilter.ampl1_end", std::to_string(ampl1_end)); + config->set_property("InputFilter.ampl2_begin", std::to_string(ampl2_begin)); + config->set_property("InputFilter.ampl2_end", std::to_string(ampl2_end)); + config->set_property("InputFilter.band1_error", std::to_string(band1_error)); + config->set_property("InputFilter.band2_error", std::to_string(band2_error)); + config->set_property("InputFilter.filter_type", "bandpass"); + config->set_property("InputFilter.grid_density", std::to_string(grid_density)); + config->set_property("InputFilter.sampling_frequency", std::to_string(FLAGS_fs_in)); + config->set_property("InputFilter.IF", std::to_string(zero)); + config->set_property("Resampler.implementation", "Pass_Through"); + config->set_property("Resampler.dump", "false"); + config->set_property("Resampler.item_type", "gr_complex"); + config->set_property("Resampler.sample_freq_in", std::to_string(FLAGS_fs_in)); + config->set_property("Resampler.sample_freq_out", std::to_string(FLAGS_fs_in)); + + // Set the number of Channels + config->set_property("Channels_1C.count", std::to_string(number_of_channels)); + config->set_property("Channels.in_acquisition", std::to_string(in_acquisition)); + config->set_property("Channel.signal", "1C"); + + // Set Acquisition + config->set_property("Acquisition_1C.implementation", "GPS_L1_CA_PCPS_Tong_Acquisition"); + config->set_property("Acquisition_1C.item_type", "gr_complex"); + config->set_property("Acquisition_1C.if", std::to_string(zero)); + config->set_property("Acquisition_1C.coherent_integration_time_ms", std::to_string(coherent_integration_time_ms)); + config->set_property("Acquisition_1C.threshold", std::to_string(threshold)); + config->set_property("Acquisition_1C.doppler_max", std::to_string(doppler_max)); + config->set_property("Acquisition_1C.doppler_step", std::to_string(doppler_step)); + config->set_property("Acquisition_1C.bit_transition_flag", "false"); + config->set_property("Acquisition_1C.max_dwells", std::to_string(max_dwells)); + config->set_property("Acquisition_1C.tong_init_val", std::to_string(tong_init_val)); + config->set_property("Acquisition_1C.tong_max_val", std::to_string(tong_max_val)); + config->set_property("Acquisition_1C.tong_max_dwells", std::to_string(tong_max_dwells)); + + // Set Tracking + config->set_property("Tracking_1C.implementation", "GPS_L1_CA_DLL_PLL_Tracking"); + config->set_property("Tracking_1C.item_type", "gr_complex"); + config->set_property("Tracking_1C.if", std::to_string(zero)); + config->set_property("Tracking_1C.dump", "false"); + config->set_property("Tracking_1C.dump_filename", "./tracking_ch_"); + config->set_property("Tracking_1C.pll_bw_hz", std::to_string(pll_bw_hz)); + config->set_property("Tracking_1C.dll_bw_hz", std::to_string(dll_bw_hz)); + config->set_property("Tracking_1C.early_late_space_chips", std::to_string(early_late_space_chips)); + + // Set Telemetry + config->set_property("TelemetryDecoder_1C.implementation", "GPS_L1_CA_Telemetry_Decoder"); + config->set_property("TelemetryDecoder_1C.dump", "false"); + config->set_property("TelemetryDecoder_1C.decimation_factor", std::to_string(decimation_factor)); + + // Set Observables + config->set_property("Observables.implementation", "GPS_L1_CA_Observables"); + config->set_property("Observables.dump", "false"); + config->set_property("Observables.dump_filename", "./observables.dat"); + + // Set PVT + config->set_property("PVT.implementation", "GPS_L1_CA_PVT"); + config->set_property("PVT.averaging_depth", std::to_string(averaging_depth)); + config->set_property("PVT.flag_averaging", "true"); + config->set_property("PVT.output_rate_ms", std::to_string(output_rate_ms)); + config->set_property("PVT.display_rate_ms", std::to_string(display_rate_ms)); + config->set_property("PVT.dump_filename", "./PVT"); + config->set_property("PVT.nmea_dump_filename", "./gnss_sdr_pvt.nmea"); + config->set_property("PVT.flag_nmea_tty_port", "false"); + config->set_property("PVT.nmea_dump_devname", "/dev/pts/4"); + config->set_property("PVT.flag_rtcm_server", "false"); + config->set_property("PVT.flag_rtcm_tty_port", "false"); + config->set_property("PVT.rtcm_dump_devname", "/dev/pts/1"); + config->set_property("PVT.dump", "false"); +} + + +void TTFF_GPS_L1_CA_Test::config_2() +{ + std::string path = std::string(TEST_PATH); + std::string filename = path + "../../conf/gnss-sdr_GPS_L1_USRP_X300_realtime.conf"; + config2 = std::make_shared(filename); + config2->set_property("SignalSource.samples", std::to_string(FLAGS_fs_in * FLAGS_max_measurement_duration)); +} + + +void receive_msg() +{ + ttff_msgbuf msg; + ttff_msgbuf msg_stop; + msg_stop.mtype = 1; + msg_stop.ttff = 200; + double ttff_msg = 0.0; + int msgrcv_size = sizeof(msg.ttff); + int msqid; + int msqid_stop; + key_t key = 1101; + key_t key_stop = 1102; + // wait for the queue to be created + while((msqid = msgget(key, 0644)) == -1){} + + if (msgrcv(msqid, &msg, msgrcv_size, 1, 0) != -1) + { + ttff_msg = msg.ttff; + if( (ttff_msg != 0) && (ttff_msg != -1)) + { + TTFF_v.push_back(ttff_msg / (1000.0 / decimation_factor) ); + LOG(INFO) << "Valid Time-To-First-Fix: " << ttff_msg / (1000.0 / decimation_factor ) << "[s]"; + // Stop the receiver + while((msqid_stop = msgget(key_stop, 0644)) == -1){} + double msgsend_size = sizeof(msg_stop.ttff); + msgsnd(msqid_stop, &msg_stop, msgsend_size, IPC_NOWAIT); + } + + if(ttff_msg != -1) + { + receive_msg(); + } + } + return; +} + + +void TTFF_GPS_L1_CA_Test::print_TTFF_report(const std::vector & ttff_v) +{ + std::vector ttff = ttff_v; + double sum = std::accumulate(ttff.begin(), ttff.end(), 0.0); + double mean = sum / ttff.size(); + double sq_sum = std::inner_product(ttff.begin(), ttff.end(), ttff.begin(), 0.0); + double stdev = std::sqrt(sq_sum / ttff.size() - mean * mean); + auto max_ttff = std::max_element(std::begin(ttff), std::end(ttff)); + auto min_ttff = std::min_element(std::begin(ttff), std::end(ttff)); + std::cout << "---------------------------" << std::endl; + std::cout << " Time-To-First-Fix Report" << std::endl; + std::cout << "---------------------------" << std::endl; + std::cout << "Valid measurements (" << ttff.size() << "/" << FLAGS_num_measurements << "): "; + for(double ttff_ : ttff) std::cout << ttff_ << " "; + std::cout << std::endl; + std::cout << "TTFF mean: " << mean << " [s]" << std::endl; + if (ttff.size() > 0) + { + std::cout << "TTFF max: " << *max_ttff << " [s]" << std::endl; + std::cout << "TTFF min: " << *min_ttff << " [s]" << std::endl; + } + std::cout << "TTFF stdev: " << stdev << " [s]" << std::endl; + std::cout << "---------------------------" << std::endl; +} + + +TEST_F(TTFF_GPS_L1_CA_Test, ColdStart) +{ + unsigned int num_measurements = 0; + + config_1(); + // Ensure Cold Start + config->set_property("GNSS-SDR.SUPL_gps_enabled", "false"); + config->set_property("GNSS-SDR.SUPL_read_gps_assistance_xml", "false"); + + config_2(); + // Ensure Cold Start + config2->set_property("GNSS-SDR.SUPL_read_gps_assistance_xml", "false"); + config2->set_property("GNSS-SDR.SUPL_read_gps_assistance_xml", "false"); + config2->set_property("PVT.flag_rtcm_server", "false"); + + for(int n = 0; n < FLAGS_num_measurements; n++) + { + // Create a new ControlThread object with a smart pointer + std::unique_ptr control_thread(new ControlThread(config)); + + // record startup time + struct timeval tv; + gettimeofday(&tv, NULL); + long long int begin = tv.tv_sec * 1000000 + tv.tv_usec; + + std::cout << "Starting measurement " << num_measurements + 1 << " / " << FLAGS_num_measurements << std::endl; + + // start receiver + try + { + control_thread->run(); + } + catch( boost::exception & e ) + { + std::cout << "Boost exception: " << boost::diagnostic_information(e); + } + catch(std::exception const& ex) + { + std::cout << "STD exception: " << ex.what(); + } + + // stop clock + gettimeofday(&tv, NULL); + long long int end = tv.tv_sec * 1000000 + tv.tv_usec; + double ttff = static_cast(end - begin) / 1000000.0; + + std::shared_ptr flowgraph = control_thread->flowgraph(); + EXPECT_FALSE(flowgraph->running()); + + num_measurements = num_measurements + 1; + std::cout << "Just finished measurement " << num_measurements << ", which took " << ttff << " seconds." << std::endl; + if(n < FLAGS_num_measurements - 1) + { + std::srand(std::time(0)); // use current time as seed for random generator + int random_variable = std::rand(); + float random_variable_0_1 = static_cast(random_variable) / static_cast( RAND_MAX ); + int random_delay_s = static_cast(random_variable_0_1 * 25.0); + std::cout << "Waiting a random amount of time (from 5 to 30 s) to start new measurement... " << std::endl; + std::cout << "This time will wait " << random_delay_s + 5 << " s." << std::endl << std::endl; + std::this_thread::sleep_until(std::chrono::system_clock::now() + std::chrono::seconds(5) + std::chrono::seconds(random_delay_s)); + } + } + + // Print TTFF report + print_TTFF_report(TTFF_v); +} + + + +int main(int argc, char **argv) +{ + std::cout << "Running Time-To-First-Fix test..." << std::endl; + int res = 0; + TTFF_v.clear(); + testing::InitGoogleTest(&argc, argv); + google::ParseCommandLineFlags(&argc, &argv, true); + google::InitGoogleLogging(argv[0]); + + // Create SysV message queue to read TFFF measurements + key_t sysv_msg_key; + int sysv_msqid; + sysv_msg_key = 1101; + int msgflg = IPC_CREAT | 0666; + if ((sysv_msqid = msgget(sysv_msg_key, msgflg )) == -1) + { + std::cout<<"GNSS-SDR can not create message queues!" << std::endl; + throw new std::exception(); + } + + + // Start queue thread + std::thread receive_msg_thread(receive_msg); + + // Run the Tests + try + { + res = RUN_ALL_TESTS(); + } + catch(...) + { + LOG(WARNING) << "Unexpected catch"; + } + + // Terminate the queue thread + ttff_msgbuf msg; + msg.mtype = 1; + msg.ttff = -1; + int msgsend_size; + msgsend_size = sizeof(msg.ttff); + msgsnd(sysv_msqid, &msg, msgsend_size, IPC_NOWAIT); + receive_msg_thread.join(); + google::ShutDownCommandLineFlags(); + return res; +}