diff --git a/CMakeLists.txt b/CMakeLists.txt index 534379925..196ff303f 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -402,6 +402,7 @@ set(GNSSSDR_PYTHON3_MIN_VERSION "3.4") set(GNSSSDR_MAKO_MIN_VERSION "0.4.2") set(GNSSSDR_ARMADILLO_MIN_VERSION "5.300.0") set(GNSSSDR_MATIO_MIN_VERSION "1.5.3") +set(GNSSSDR_PROTOBUF_MIN_VERSION "3.0.0") @@ -416,6 +417,7 @@ set(GNSSSDR_GNSS_SIM_LOCAL_VERSION "master") set(GNSSSDR_GPSTK_LOCAL_VERSION "2.10.6") set(GNSSSDR_MATIO_LOCAL_VERSION "1.5.14") set(GNSSSDR_PUGIXML_LOCAL_VERSION "1.9") +set(GNSSSDR_PROTOCOLBUFFERS_LOCAL_VERSION "3.7.1") if(CMAKE_VERSION VERSION_LESS "3.0.2") # Fix for CentOS 7 set(GNSSSDR_GFLAGS_LOCAL_VERSION "2.2.1") @@ -1784,6 +1786,131 @@ endif() +################################################################################ +# Protocol Buffers https://github.com/protocolbuffers/protobuf +################################################################################ +set(Protobuf_VERSION "0.0.0") +find_package(Protobuf) +set_package_properties(Protobuf PROPERTIES + URL "https://developers.google.com/protocol-buffers/" + DESCRIPTION "A language-neutral, platform-neutral extensible mechanism for serializing structured data" + PURPOSE "Used to serialize output data in a way that can be read by other applications." + TYPE REQUIRED +) +if(Protobuf_FOUND AND CMAKE_VERSION VERSION_LESS 3.9) + add_library(protobuf::libprotobuf SHARED IMPORTED) + set_target_properties(protobuf::libprotobuf PROPERTIES + IMPORTED_LINK_INTERFACE_LANGUAGES "CXX" + IMPORTED_LOCATION "${Protobuf_LIBRARY}" + INTERFACE_INCLUDE_DIRECTORIES "${Protobuf_INCLUDE_DIR}" + INTERFACE_LINK_LIBRARIES "${Protobuf_LIBRARY}" + ) + add_executable(protobuf::protoc IMPORTED) + set_target_properties(protobuf::protoc PROPERTIES + IMPORTED_LINK_INTERFACE_LANGUAGES "CXX" + IMPORTED_LOCATION "${Protobuf_PROTOC_EXECUTABLE}" + INTERFACE_LINK_LIBRARIES "${Protobuf_PROTOC_LIBRARY}" + ) +endif() +if(Protobuf_FOUND AND CMAKE_CROSSCOMPILING) + find_program(PROTOC_EXECUTABLE protoc + HINTS + /usr/local/bin/ + /usr/bin/ + NO_SYSTEM_ENVIRONMENT_PATH + ) + if(PROTOC_EXECUTABLE) + set_target_properties(protobuf::protoc PROPERTIES + IMPORTED_LINK_INTERFACE_LANGUAGES "CXX" + IMPORTED_LOCATION ${PROTOC_EXECUTABLE} + ) + else() + message(FATAL ERROR "Please install the Protocol Buffers compiter v{${Protobuf_VERSION}} in the host machine") + endif() +endif() +if((NOT Protobuf_FOUND) OR (NOT Protobuf_PROTOC_EXECUTABLE) OR (${Protobuf_VERSION} VERSION_LESS ${GNSSSDR_PROTOBUF_MIN_VERSION})) + unset(Protobuf_PROTOC_EXECUTABLE) + if(CMAKE_CROSSCOMPILING) + if(NOT Protobuf_FOUND) + ExternalProject_Add(protobuf-${GNSSSDR_PROTOCOLBUFFERS_LOCAL_VERSION} + PREFIX ${CMAKE_CURRENT_BINARY_DIR}/protobuf-${GNSSSDR_PROTOCOLBUFFERS_LOCAL_VERSION} + GIT_REPOSITORY https://github.com/protocolbuffers/protobuf + GIT_TAG v${GNSSSDR_PROTOCOLBUFFERS_LOCAL_VERSION} + SOURCE_DIR ${CMAKE_CURRENT_SOURCE_DIR}/thirdparty/protobuf/protobuf-${GNSSSDR_PROTOCOLBUFFERS_LOCAL_VERSION} + BINARY_DIR ${CMAKE_CURRENT_BINARY_DIR}/protobuf-${GNSSSDR_PROTOCOLBUFFERS_LOCAL_VERSION} + UPDATE_COMMAND ${CMAKE_CURRENT_SOURCE_DIR}/thirdparty/protobuf/protobuf-${GNSSSDR_PROTOCOLBUFFERS_LOCAL_VERSION}/autogen.sh + CONFIGURE_COMMAND "${CMAKE_CURRENT_SOURCE_DIR}/thirdparty/protobuf/protobuf-${GNSSSDR_PROTOCOLBUFFERS_LOCAL_VERSION}/configure --prefix=${CMAKE_CURRENT_BINARY_DIR}/protobuf-${GNSSSDR_PROTOCOLBUFFERS_LOCAL_VERSION} --host=$ENV{OECORE_TARGET_ARCH} --with-protoc=${PROTOC_EXECUTABLE}" + BUILD_COMMAND ${CMAKE_MAKE_PROGRAM} + INSTALL_COMMAND ${CMAKE_MAKE_PROGRAM} install + BUILD_BYPRODUCTS ${CMAKE_CURRENT_BINARY_DIR}/protobuf-${GNSSSDR_PROTOCOLBUFFERS_LOCAL_VERSION}/lib/${CMAKE_FIND_LIBRARY_PREFIXES}protobuf${CMAKE_STATIC_LIBRARY_SUFFIX} + ${CMAKE_CURRENT_BINARY_DIR}/protobuf-${GNSSSDR_PROTOCOLBUFFERS_LOCAL_VERSION}/bin/protoc + ) + endif() + else() + if(CMAKE_VERSION VERSION_LESS 3.2) + ExternalProject_Add(protobuf-${GNSSSDR_PROTOCOLBUFFERS_LOCAL_VERSION} + PREFIX ${CMAKE_CURRENT_BINARY_DIR}/protobuf-${GNSSSDR_PROTOCOLBUFFERS_LOCAL_VERSION} + GIT_REPOSITORY https://github.com/protocolbuffers/protobuf + GIT_TAG v${GNSSSDR_PROTOCOLBUFFERS_LOCAL_VERSION} + SOURCE_DIR ${CMAKE_CURRENT_SOURCE_DIR}/thirdparty/protobuf/protobuf-${GNSSSDR_PROTOCOLBUFFERS_LOCAL_VERSION} + BINARY_DIR ${CMAKE_CURRENT_BINARY_DIR}/protobuf-${GNSSSDR_PROTOCOLBUFFERS_LOCAL_VERSION} + UPDATE_COMMAND ${CMAKE_CURRENT_SOURCE_DIR}/thirdparty/protobuf/protobuf-${GNSSSDR_PROTOCOLBUFFERS_LOCAL_VERSION}/autogen.sh + CONFIGURE_COMMAND ${CMAKE_CURRENT_SOURCE_DIR}/thirdparty/protobuf/protobuf-${GNSSSDR_PROTOCOLBUFFERS_LOCAL_VERSION}/configure --prefix=${CMAKE_CURRENT_BINARY_DIR}/protobuf-${GNSSSDR_PROTOCOLBUFFERS_LOCAL_VERSION} + BUILD_COMMAND ${CMAKE_MAKE_PROGRAM} + INSTALL_COMMAND ${CMAKE_MAKE_PROGRAM} install + ) + else() + ExternalProject_Add(protobuf-${GNSSSDR_PROTOCOLBUFFERS_LOCAL_VERSION} + PREFIX ${CMAKE_CURRENT_BINARY_DIR}/protobuf-${GNSSSDR_PROTOCOLBUFFERS_LOCAL_VERSION} + GIT_REPOSITORY https://github.com/protocolbuffers/protobuf + GIT_TAG v${GNSSSDR_PROTOCOLBUFFERS_LOCAL_VERSION} + SOURCE_DIR ${CMAKE_CURRENT_SOURCE_DIR}/thirdparty/protobuf/protobuf-${GNSSSDR_PROTOCOLBUFFERS_LOCAL_VERSION} + BINARY_DIR ${CMAKE_CURRENT_BINARY_DIR}/protobuf-${GNSSSDR_PROTOCOLBUFFERS_LOCAL_VERSION} + UPDATE_COMMAND ${CMAKE_CURRENT_SOURCE_DIR}/thirdparty/protobuf/protobuf-${GNSSSDR_PROTOCOLBUFFERS_LOCAL_VERSION}/autogen.sh + CONFIGURE_COMMAND ${CMAKE_CURRENT_SOURCE_DIR}/thirdparty/protobuf/protobuf-${GNSSSDR_PROTOCOLBUFFERS_LOCAL_VERSION}/configure --prefix=${CMAKE_CURRENT_BINARY_DIR}/protobuf-${GNSSSDR_PROTOCOLBUFFERS_LOCAL_VERSION} + BUILD_COMMAND ${CMAKE_MAKE_PROGRAM} + INSTALL_COMMAND ${CMAKE_MAKE_PROGRAM} install + BUILD_BYPRODUCTS ${CMAKE_CURRENT_BINARY_DIR}/protobuf-${GNSSSDR_PROTOCOLBUFFERS_LOCAL_VERSION}/lib/${CMAKE_FIND_LIBRARY_PREFIXES}protobuf${CMAKE_STATIC_LIBRARY_SUFFIX} + ${CMAKE_CURRENT_BINARY_DIR}/protobuf-${GNSSSDR_PROTOCOLBUFFERS_LOCAL_VERSION}/bin/protoc + ) + endif() + + if(NOT TARGET protobuf::protoc) + add_executable(protobuf::protoc IMPORTED) + add_dependencies(protobuf::protoc protobuf-${GNSSSDR_PROTOCOLBUFFERS_LOCAL_VERSION}) + endif() + unset(Protobuf_PROTOC_EXECUTABLE) + set(PROTOBUF_PROTOC_EXECUTABLE "${CMAKE_CURRENT_BINARY_DIR}/protobuf-${GNSSSDR_PROTOCOLBUFFERS_LOCAL_VERSION}/bin/protoc") + set_target_properties(protobuf::protoc PROPERTIES + IMPORTED_LINK_INTERFACE_LANGUAGES "CXX" + IMPORTED_LOCATION "${CMAKE_CURRENT_BINARY_DIR}/protobuf-${GNSSSDR_PROTOCOLBUFFERS_LOCAL_VERSION}/bin/protoc" + INTERFACE_LINK_LIBRARIES "${CMAKE_CURRENT_BINARY_DIR}/protobuf-${GNSSSDR_PROTOCOLBUFFERS_LOCAL_VERSION}/lib/${CMAKE_FIND_LIBRARY_PREFIXES}protoc${CMAKE_STATIC_LIBRARY_SUFFIX}" + ) + endif() + file(MAKE_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}/protobuf-${GNSSSDR_PROTOCOLBUFFERS_LOCAL_VERSION}/include) + if(NOT TARGET protobuf::libprotobuf) + add_library(protobuf::libprotobuf STATIC IMPORTED) + add_dependencies(protobuf::libprotobuf protobuf-${GNSSSDR_PROTOCOLBUFFERS_LOCAL_VERSION}) + endif() + set_target_properties(protobuf::libprotobuf PROPERTIES + IMPORTED_LINK_INTERFACE_LANGUAGES "CXX" + IMPORTED_LOCATION "${CMAKE_CURRENT_BINARY_DIR}/protobuf-${GNSSSDR_PROTOCOLBUFFERS_LOCAL_VERSION}/lib/${CMAKE_FIND_LIBRARY_PREFIXES}protobuf${CMAKE_STATIC_LIBRARY_SUFFIX}" + INTERFACE_INCLUDE_DIRECTORIES "${CMAKE_CURRENT_BINARY_DIR}/protobuf-${GNSSSDR_PROTOCOLBUFFERS_LOCAL_VERSION}/include" + INTERFACE_LINK_LIBRARIES "${CMAKE_CURRENT_BINARY_DIR}/protobuf-${GNSSSDR_PROTOCOLBUFFERS_LOCAL_VERSION}/lib/${CMAKE_FIND_LIBRARY_PREFIXES}protobuf${CMAKE_STATIC_LIBRARY_SUFFIX}" + ) + + if(${Protobuf_VERSION} VERSION_LESS ${GNSSSDR_PROTOBUF_MIN_VERSION}) + set_package_properties(Protobuf PROPERTIES + PURPOSE "Protocol Buffers found (v${Protobuf_VERSION}) is too old (> v${GNSSSDR_PROTOBUF_MIN_VERSION} needed)." + ) + endif() + set_package_properties(Protobuf PROPERTIES + PURPOSE "Protocol Buffers v${GNSSSDR_PROTOCOLBUFFERS_LOCAL_VERSION} will be downloaded and built when doing '${CMAKE_MAKE_PROGRAM_PRETTY_NAME}'." + ) +endif() + + + ################################################################################ # Doxygen - http://www.doxygen.nl (OPTIONAL, used if found) ################################################################################ diff --git a/README.md b/README.md index da4475f41..fe1501404 100644 --- a/README.md +++ b/README.md @@ -68,7 +68,7 @@ $ sudo apt-get install build-essential cmake git libboost-dev libboost-date-time libboost-serialization-dev liblog4cpp5-dev libuhd-dev gnuradio-dev gr-osmosdr \ libblas-dev liblapack-dev libarmadillo-dev libgflags-dev libgoogle-glog-dev \ libgnutls-openssl-dev libpcap-dev python-mako python-six libmatio-dev libpugixml-dev \ - libgtest-dev + libgtest-dev libprotobuf-dev protobuf-compiler ~~~~~~ Please note that the required files from `libgtest-dev` were moved to `googletest` in Debian 9 "stretch" and Ubuntu 18.04 "bionic", and moved back again to `libgtest-dev` in Debian 10 "buster" and Ubuntu 18.10 "cosmic". @@ -86,7 +86,7 @@ If you are using Arch Linux: ~~~~~~ $ pacman -S gcc make cmake git boost boost-libs log4cpp libvolk gnuradio \ gnuradio-osmosdr blas lapack gflags google-glog openssl pugixml \ - python-mako python-six libmatio libpcap gtest + python-mako python-six libmatio libpcap gtest protobuf ~~~~~~ Once you have installed these packages, you can jump directly to [download the source code and build GNSS-SDR](#download-and-build-linux). @@ -119,7 +119,8 @@ $ sudo yum install make automake gcc gcc-c++ kernel-devel cmake git boost-devel boost-date-time boost-system boost-filesystem boost-thread boost-chrono \ boost-serialization log4cpp-devel gnuradio-devel gr-osmosdr-devel \ blas-devel lapack-devel matio-devel armadillo-devel gflags-devel \ - glog-devel openssl-devel libpcap-devel python-mako python-six pugixml-devel + glog-devel openssl-devel libpcap-devel python-mako python-six \ + pugixml-devel protobuf-devel ~~~~~~ Once you have installed these packages, you can jump directly to [download the source code and build GNSS-SDR](#download-and-build-linux). @@ -135,7 +136,7 @@ zypper install cmake git gcc-c++ boost-devel libboost_atomic-devel \ libboost_thread-devel libboost_chrono-devel libboost_serialization-devel \ log4cpp-devel gtest gnuradio-devel pugixml-devel libpcap-devel \ armadillo-devel libtool automake hdf5-devel libopenssl-devel python-Mako \ - python-six + python-six protobuf-devel ~~~~~~ Once you have installed these packages, you can jump directly to [download the source code and build GNSS-SDR](#download-and-build-linux). @@ -283,6 +284,29 @@ In case the GnuTLS library with openssl extensions package is not available in y +#### Install [Protocol Buffers](https://developers.google.com/protocol-buffers/ "Protocol Buffers' Homepage"), a portable mechanism for serialization of structured data: + +GNSS-SDR requires Protocol Buffers v3.0.0 or later. If the packages that come with your distribution are older than that (_e.g._, Ubuntu 16.04 Xenial and Debian 8 Jessie came with older versions), then you will need to install it manually. First, install the dependencies: + +~~~~~~ +$ sudo apt-get install autoconf automake libtool curl make g++ unzip +~~~~~~ + +and then: + +~~~~~~ +$ wget https://github.com/protocolbuffers/protobuf/releases/download/v3.7.1/protobuf-cpp-3.7.1.tar.gz +$ tar xvfz protobuf-cpp-3.7.1.tar.gz +$ cd protobuf-3.7.1 +$ ./autogen.sh +$ ./configure +$ make +$ sudo make install +$ sudo ldconfig +~~~~~~ + + + ### Clone GNSS-SDR's Git repository: ~~~~~~ @@ -570,6 +594,7 @@ $ sudo port install gnutls $ sudo port install google-glog +gflags $ sudo port install matio $ sudo port install pugixml +$ sudo port install protobuf3-cpp $ sudo port install py27-mako $ sudo port install py27-six $ sudo port install doxygen +docs @@ -617,6 +642,7 @@ $ brew install libmatio $ brew install log4cpp $ brew install openssl $ brew install pugixml +$ brew install protobuf $ pip install mako $ pip install six ~~~~~~ diff --git a/docs/changelog b/docs/changelog index 849d5518d..c3f61570b 100644 --- a/docs/changelog +++ b/docs/changelog @@ -26,6 +26,7 @@ - Fix bug in GLONASS dual frequency receiver. - Added a custom UDP/IP output for PVT data streaming. - Improved Monitor block with UDP/IP output for internal receiver's data streaming. +- Custom output formats described with .proto files, making easier to other applications reading them in a forward and backward-compatible fashion upon future format changes. ### Improvements in Maintainability: @@ -51,6 +52,7 @@ - The receiver now admits FPGA off-loading, allowing for real time operation at high sampling rates and higher number of signals and channels. - Fixed program termination (avoiding hangs and segfaults in some platforms/configurations). +- The Labsat_Signal_Source now terminates the receiver's execution when the end of file(s) is reached. It now accepts LabSat 2 filenames and series of LabSat 3 files. - CMake now generates a summary of enabled/disabled features. This info is also stored in a file called features.log in the building directory. - New parameter PVT.show_local_time_zone displays time in the local time zone. Subject to the proper system configuration of the machine running the software receiver. - Improved information provided to the user in case of failure. diff --git a/docs/protobuf/README.md b/docs/protobuf/README.md new file mode 100644 index 000000000..110f73f28 --- /dev/null +++ b/docs/protobuf/README.md @@ -0,0 +1,19 @@ +# Custom structured data format definitions + +Files in this folder describe structured data formats that are generated by +GNSS-SDR. They use [Protocol Buffers](https://developers.google.com/protocol-buffers/)' +[proto3](https://developers.google.com/protocol-buffers/docs/proto3) syntax. + +From those files, the protocol buffer compiler creates classes that implement +automatic encoding and parsing of the protocol buffer data with an efficient +binary format. The generated classes provide getters and setters for the fields +that make up a protocol buffer and take care of the details of reading and +writing it as a unit. Importantly, the protocol buffer format supports the idea +of extending the format over time in such a way that the code can still read +data encoded with the old format. + +Just grab these files if you are developing a client application for GNSS-SDR. +You are free to use C++, Java, Python, C#, Dart, Go or Ruby, among other +languages. A tutorial to create a simple application using Protocol Buffers and +a `.proto` file in C++ is available at +https://gnss-sdr.org/docs/tutorials/monitoring-software-receiver-internal-status/ diff --git a/docs/protobuf/gnss_synchro.proto b/docs/protobuf/gnss_synchro.proto new file mode 100644 index 000000000..b51ac1a8f --- /dev/null +++ b/docs/protobuf/gnss_synchro.proto @@ -0,0 +1,42 @@ +syntax = "proto3"; + +package gnss_sdr; + +/* GnssSynchro represents the processing measurements at a given time taken by a given processing channel */ +message GnssSynchro { + string system = 1; // GNSS constellation: "G" for GPS, "R" for Glonass, "S" for SBAS, "E" for Galileo and "C" for Beidou. + string signal = 2; // GNSS signal: "1C" for GPS L1 C/A, "1B" for Galileo E1b/c, "1G" for Glonass L1 C/A, "2S" for GPS L2 L2C(M), "2G" for Glonass L2 C/A, "L5" for GPS L5 and "5X" for Galileo E5a + + uint32 prn = 3; // PRN number + int32 channel_id = 4; // Channel number + + double acq_delay_samples = 5; // Coarse code delay estimation, in samples + double acq_doppler_hz = 6; // Coarse Doppler estimation in each channel, in Hz + uint64 acq_samplestamp_samples = 7; // Number of samples at signal SampleStamp + uint32 acq_doppler_step = 8; // Step of the frequency bin in the search grid, in Hz + bool flag_valid_acquisition = 9; // Acquisition status + + int64 fs = 10; // Sampling frequency, in samples per second + double prompt_i = 11; // In-phase (real) component of the prompt correlator output + double prompt_q = 12; // Quadrature (imaginary) component of the prompt correlator output + double cn0_db_hz = 13; // Carrier-to-Noise density ratio, in dB-Hz + double carrier_doppler_hz = 14; // Doppler estimation, in [Hz]. + double carrier_phase_rads = 15; // Carrier phase estimation, in rad + double code_phase_samples = 16; // Code phase in samples + uint64 tracking_sample_counter = 17; // Sample counter indicating the number of processed samples + bool flag_valid_symbol_output = 18; // Indicates the validity of signal tracking + int32 correlation_length_ms = 19; // Time duration of coherent correlation integration, in ms + + bool flag_valid_word = 20; // Indicates the validity of the decoded navigation message word + uint32 tow_at_current_symbol_ms = 21; // Time of week of the current symbol, in ms + + double pseudorange_m = 22; // Pseudorange computation, in m + double rx_time = 23; // Receiving time after the start of the week, in s + bool flag_valid_pseudorange = 24; // Pseudorange computation status + double interp_tow_ms = 25; // Interpolated time of week, in ms +} + +/* Observables represents a collection of GnssSynchro annotations */ +message Observables { + repeated GnssSynchro observable = 1; +} diff --git a/docs/protobuf/monitor_pvt.proto b/docs/protobuf/monitor_pvt.proto new file mode 100644 index 000000000..3a2de2397 --- /dev/null +++ b/docs/protobuf/monitor_pvt.proto @@ -0,0 +1,41 @@ +syntax = "proto3"; + +package gnss_sdr; + +/* MonitorPvt represents a search query, with pagination options to + * indicate which results to include in the response. */ +message MonitorPvt { +uint32 tow_at_current_symbol_ms = 1; // Time of week of the current symbol, in ms +uint32 week = 2; // PVT GPS week +double rx_time = 3; // PVT GPS time +double user_clk_offset = 4; // User clock offset, in s + +double pos_x = 5; // Position X component in ECEF, expressed in m +double pos_y = 6; // Position Y component in ECEF, expressed in m +double pos_z = 7; // Position Z component in ECEF, expressed in m +double vel_x = 8; // Velocity X component in ECEF, in m/s +double vel_y = 9; // Velocity Y component in ECEF, in m/s +double vel_z = 10; // Velocity Z component in ECEF, in m/s + +double cov_xx = 11; // Position variance in the Y component, in m2 +double cov_yy = 12; // Position variance in the Y component, in m2 +double cov_zz = 13; // Position variance in the Z component, in m2 +double cov_xy = 14; // Position XY covariance, in m2 +double cov_yz = 15; // Position YZ covariance, in m2 +double cov_zx = 16; // Position ZX covariance, in m2 + +double latitude = 17; // Latitude, in deg. Positive: North +double longitude = 18; // Longitude, in deg. Positive: East +double height = 19; // Height, in m + +uint32 valid_sats = 20; // Number of valid satellites +uint32 solution_status = 21; // RTKLIB solution status +uint32 solution_type = 22; // RTKLIB solution type (0: xyz-ecef, 1: enu-baseline) +float ar_ratio_factor = 23; // Ambiguity resolution ratio factor for validation +float ar_ratio_threshold = 24; // Ambiguity resolution ratio threshold for validation + +double gdop = 25; // Geometric Dilution of Precision +double pdop = 26; // Position (3D) Dilution of Precision +double hdop = 27; // Horizontal Dilution of Precision +double vdop = 28; // Vertical Dilution of Precision +} diff --git a/src/algorithms/PVT/adapters/rtklib_pvt.cc b/src/algorithms/PVT/adapters/rtklib_pvt.cc index bbb4cdc2d..440036116 100644 --- a/src/algorithms/PVT/adapters/rtklib_pvt.cc +++ b/src/algorithms/PVT/adapters/rtklib_pvt.cc @@ -741,6 +741,11 @@ Rtklib_Pvt::Rtklib_Pvt(ConfigurationInterface* configuration, pvt_output_parameters.monitor_enabled = configuration->property(role + ".enable_monitor", false); pvt_output_parameters.udp_addresses = configuration->property(role + ".monitor_client_addresses", std::string("127.0.0.1")); pvt_output_parameters.udp_port = configuration->property(role + ".monitor_udp_port", 1234); + pvt_output_parameters.protobuf_enabled = configuration->property(role + ".enable_protobuf", true); + if (configuration->property("Monitor.enable_protobuf", false) == true) + { + pvt_output_parameters.protobuf_enabled = true; + } // Show time in local zone pvt_output_parameters.show_local_time_zone = configuration->property(role + ".show_local_time_zone", false); diff --git a/src/algorithms/PVT/gnuradio_blocks/rtklib_pvt_gs.cc b/src/algorithms/PVT/gnuradio_blocks/rtklib_pvt_gs.cc index 54ca099a5..e97ce2129 100644 --- a/src/algorithms/PVT/gnuradio_blocks/rtklib_pvt_gs.cc +++ b/src/algorithms/PVT/gnuradio_blocks/rtklib_pvt_gs.cc @@ -347,7 +347,7 @@ rtklib_pvt_gs::rtklib_pvt_gs(uint32_t nchannels, std::sort(udp_addr_vec.begin(), udp_addr_vec.end()); udp_addr_vec.erase(std::unique(udp_addr_vec.begin(), udp_addr_vec.end()), udp_addr_vec.end()); - udp_sink_ptr = std::unique_ptr(new Monitor_Pvt_Udp_Sink(udp_addr_vec, conf_.udp_port)); + udp_sink_ptr = std::unique_ptr(new Monitor_Pvt_Udp_Sink(udp_addr_vec, conf_.udp_port, conf_.protobuf_enabled)); } else { diff --git a/src/algorithms/PVT/libs/CMakeLists.txt b/src/algorithms/PVT/libs/CMakeLists.txt index 879dd9cba..2cdae5daf 100644 --- a/src/algorithms/PVT/libs/CMakeLists.txt +++ b/src/algorithms/PVT/libs/CMakeLists.txt @@ -16,6 +16,7 @@ # along with GNSS-SDR. If not, see . # +protobuf_generate_cpp(PROTO_SRCS PROTO_HDRS ${CMAKE_SOURCE_DIR}/docs/protobuf/monitor_pvt.proto) set(PVT_LIB_SOURCES pvt_solution.cc @@ -31,6 +32,7 @@ set(PVT_LIB_SOURCES rtklib_solver.cc pvt_conf.cc monitor_pvt_udp_sink.cc + ${PROTO_SRCS} ) set(PVT_LIB_HEADERS @@ -48,6 +50,8 @@ set(PVT_LIB_HEADERS pvt_conf.h monitor_pvt_udp_sink.h monitor_pvt.h + serdes_monitor_pvt.h + ${PROTO_HDRS} ) list(SORT PVT_LIB_HEADERS) @@ -61,6 +65,7 @@ target_link_libraries(pvt_libs PUBLIC Armadillo::armadillo Boost::date_time + protobuf::libprotobuf algorithms_libs_rtklib core_system_parameters PRIVATE @@ -72,9 +77,12 @@ target_link_libraries(pvt_libs Matio::matio ) +get_filename_component(PROTO_INCLUDE_HEADERS ${PROTO_HDRS} DIRECTORY) + target_include_directories(pvt_libs PUBLIC ${CMAKE_SOURCE_DIR}/src/core/receiver + ${PROTO_INCLUDE_HEADERS} ) target_compile_definitions(pvt_libs PRIVATE -DGNSS_SDR_VERSION="${VERSION}") diff --git a/src/algorithms/PVT/libs/monitor_pvt_udp_sink.cc b/src/algorithms/PVT/libs/monitor_pvt_udp_sink.cc index 2982ec401..9ffb034d8 100644 --- a/src/algorithms/PVT/libs/monitor_pvt_udp_sink.cc +++ b/src/algorithms/PVT/libs/monitor_pvt_udp_sink.cc @@ -35,7 +35,7 @@ #include -Monitor_Pvt_Udp_Sink::Monitor_Pvt_Udp_Sink(std::vector addresses, const uint16_t& port) : socket{io_service} +Monitor_Pvt_Udp_Sink::Monitor_Pvt_Udp_Sink(std::vector addresses, const uint16_t& port, bool protobuf_enabled) : socket{io_service} { for (const auto& address : addresses) { @@ -70,15 +70,29 @@ Monitor_Pvt_Udp_Sink::Monitor_Pvt_Udp_Sink(std::vector addresses, c monitor_pvt.pdop = 0.0; monitor_pvt.hdop = 0.0; monitor_pvt.vdop = 0.0; + + use_protobuf = protobuf_enabled; + if (use_protobuf) + { + serdes = Serdes_Monitor_Pvt(); + } } bool Monitor_Pvt_Udp_Sink::write_monitor_pvt(const Monitor_Pvt& monitor_pvt) { - std::ostringstream archive_stream; - boost::archive::binary_oarchive oa{archive_stream}; - oa << monitor_pvt; - std::string outbound_data = archive_stream.str(); + std::string outbound_data; + if (use_protobuf == false) + { + std::ostringstream archive_stream; + boost::archive::binary_oarchive oa{archive_stream}; + oa << monitor_pvt; + outbound_data = archive_stream.str(); + } + else + { + outbound_data = serdes.createProtobuffer(monitor_pvt); + } for (const auto& endpoint : endpoints) { diff --git a/src/algorithms/PVT/libs/monitor_pvt_udp_sink.h b/src/algorithms/PVT/libs/monitor_pvt_udp_sink.h index bf132bad4..291629400 100644 --- a/src/algorithms/PVT/libs/monitor_pvt_udp_sink.h +++ b/src/algorithms/PVT/libs/monitor_pvt_udp_sink.h @@ -33,12 +33,13 @@ #define GNSS_SDR_MONITOR_PVT_UDP_SINK_H_ #include "monitor_pvt.h" +#include "serdes_monitor_pvt.h" #include class Monitor_Pvt_Udp_Sink { public: - Monitor_Pvt_Udp_Sink(std::vector addresses, const uint16_t &port); + Monitor_Pvt_Udp_Sink(std::vector addresses, const uint16_t &port, bool protobuf_enabled); bool write_monitor_pvt(const Monitor_Pvt &monitor_pvt); private: @@ -47,6 +48,8 @@ private: boost::system::error_code error; std::vector endpoints; Monitor_Pvt monitor_pvt; + Serdes_Monitor_Pvt serdes; + bool use_protobuf; }; diff --git a/src/algorithms/PVT/libs/pvt_conf.cc b/src/algorithms/PVT/libs/pvt_conf.cc index bd74b4900..5244a9592 100644 --- a/src/algorithms/PVT/libs/pvt_conf.cc +++ b/src/algorithms/PVT/libs/pvt_conf.cc @@ -69,6 +69,7 @@ Pvt_Conf::Pvt_Conf() rtcm_output_file_path = std::string("."); monitor_enabled = false; + protobuf_enabled = true; udp_port = 0; show_local_time_zone = false; diff --git a/src/algorithms/PVT/libs/pvt_conf.h b/src/algorithms/PVT/libs/pvt_conf.h index f22eb8fe2..31f3d19a0 100644 --- a/src/algorithms/PVT/libs/pvt_conf.h +++ b/src/algorithms/PVT/libs/pvt_conf.h @@ -80,6 +80,7 @@ public: std::string rtcm_output_file_path; bool monitor_enabled; + bool protobuf_enabled; std::string udp_addresses; int udp_port; diff --git a/src/algorithms/PVT/libs/serdes_monitor_pvt.h b/src/algorithms/PVT/libs/serdes_monitor_pvt.h new file mode 100644 index 000000000..e2a6e8cd5 --- /dev/null +++ b/src/algorithms/PVT/libs/serdes_monitor_pvt.h @@ -0,0 +1,138 @@ +/*! + * \file serdes_monitor_pvt.h + * \brief Serialization / Deserialization of Monitor_Pvt objects using + * Protocol Buffers + * \author Carles Fernandez-Prades, 2019. cfernandez(at)cttc.es + * + * ------------------------------------------------------------------------- + * + * Copyright (C) 2010-2019 (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 . + * + * ------------------------------------------------------------------------- + */ + +#ifndef GNSS_SDR_SERDES_MONITOR_PVT_H_ +#define GNSS_SDR_SERDES_MONITOR_PVT_H_ + +#include "monitor_pvt.h" +#include "monitor_pvt.pb.h" // file created by Protocol Buffers at compile time + + +/*! + * \brief This class implements serialization and deserialization of + * Monitor_Pvt objects using Protocol Buffers. + */ +class Serdes_Monitor_Pvt +{ +public: + Serdes_Monitor_Pvt() + { + // Verify that the version of the library that we linked against is + // compatible with the version of the headers we compiled against. + GOOGLE_PROTOBUF_VERIFY_VERSION; + monitor_.New(); + } + ~Serdes_Monitor_Pvt() + { + // google::protobuf::ShutdownProtobufLibrary(); + } + + inline std::string createProtobuffer(const Monitor_Pvt& monitor) //!< Serialization into a string + { + monitor_.Clear(); + + std::string data; + + monitor_.set_tow_at_current_symbol_ms(monitor.TOW_at_current_symbol_ms); + monitor_.set_week(monitor.week); + monitor_.set_rx_time(monitor.RX_time); + monitor_.set_user_clk_offset(monitor.user_clk_offset); + monitor_.set_pos_x(monitor.pos_x); + monitor_.set_pos_y(monitor.pos_y); + monitor_.set_pos_z(monitor.pos_z); + monitor_.set_vel_x(monitor.vel_x); + monitor_.set_vel_y(monitor.vel_y); + monitor_.set_vel_z(monitor.vel_z); + monitor_.set_cov_xx(monitor.cov_xx); + monitor_.set_cov_yy(monitor.cov_yy); + monitor_.set_cov_zz(monitor.cov_zz); + monitor_.set_cov_xy(monitor.cov_xy); + monitor_.set_cov_yz(monitor.cov_yz); + monitor_.set_cov_yz(monitor.cov_yz); + monitor_.set_latitude(monitor.latitude); + monitor_.set_longitude(monitor.longitude); + monitor_.set_height(monitor.height); + monitor_.set_valid_sats(monitor.valid_sats); + monitor_.set_solution_status(monitor.solution_status); + monitor_.set_solution_type(monitor.solution_type); + monitor_.set_ar_ratio_factor(monitor.AR_ratio_factor); + monitor_.set_ar_ratio_threshold(monitor.AR_ratio_threshold); + monitor_.set_gdop(monitor.gdop); + monitor_.set_pdop(monitor.pdop); + monitor_.set_hdop(monitor.hdop); + monitor_.set_vdop(monitor.vdop); + + monitor_.SerializeToString(&data); + return data; + } + + + inline Monitor_Pvt readProtobuffer(const gnss_sdr::MonitorPvt& mon) //!< Deserialization + { + Monitor_Pvt monitor; + + monitor.TOW_at_current_symbol_ms = mon.tow_at_current_symbol_ms(); + monitor.week = mon.week(); + monitor.RX_time = mon.rx_time(); + monitor.user_clk_offset = mon.user_clk_offset(); + monitor.pos_x = mon.pos_x(); + monitor.pos_y = mon.pos_y(); + monitor.pos_z = mon.pos_z(); + monitor.vel_x = mon.vel_x(); + monitor.vel_y = mon.vel_y(); + monitor.vel_z = mon.vel_z(); + monitor.cov_xx = mon.cov_xx(); + monitor.cov_yy = mon.cov_yy(); + monitor.cov_zz = mon.cov_zz(); + monitor.cov_xy = mon.cov_xy(); + monitor.cov_yz = mon.cov_yz(); + monitor.cov_zx = mon.cov_zx(); + monitor.latitude = mon.latitude(); + monitor.longitude = mon.longitude(); + monitor.height = mon.height(); + monitor.valid_sats = static_cast(mon.valid_sats()); + monitor.solution_status = static_cast(mon.solution_status()); + monitor.solution_type = static_cast(mon.solution_type()); + monitor.AR_ratio_factor = mon.ar_ratio_factor(); + monitor.AR_ratio_threshold = mon.ar_ratio_threshold(); + monitor.gdop = mon.gdop(); + monitor.pdop = mon.pdop(); + monitor.hdop = mon.hdop(); + monitor.vdop = mon.vdop(); + + return monitor; + } + +private: + gnss_sdr::MonitorPvt monitor_; +}; + +#endif // GNSS_SDR_SERDES_MONITOR_PVT_H_ diff --git a/src/core/monitor/CMakeLists.txt b/src/core/monitor/CMakeLists.txt index 4549006c4..12ac7bee5 100644 --- a/src/core/monitor/CMakeLists.txt +++ b/src/core/monitor/CMakeLists.txt @@ -16,15 +16,19 @@ # along with GNSS-SDR. If not, see . # +protobuf_generate_cpp(PROTO_SRCS PROTO_HDRS ${CMAKE_SOURCE_DIR}/docs/protobuf/gnss_synchro.proto) set(CORE_MONITOR_LIBS_SOURCES gnss_synchro_monitor.cc gnss_synchro_udp_sink.cc + ${PROTO_SRCS} ) set(CORE_MONITOR_LIBS_HEADERS gnss_synchro_monitor.h gnss_synchro_udp_sink.h + serdes_gnss_synchro.h + ${PROTO_HDRS} ) list(SORT CORE_MONITOR_LIBS_HEADERS) @@ -42,11 +46,19 @@ target_link_libraries(core_monitor Boost::serialization Boost::system Gnuradio::runtime + protobuf::libprotobuf core_system_parameters PRIVATE Gnuradio::pmt ) +get_filename_component(PROTO_INCLUDE_HEADERS ${PROTO_HDRS} DIRECTORY) + +target_include_directories(core_monitor + PUBLIC + ${PROTO_INCLUDE_HEADERS} +) + if(OS_IS_MACOSX) if(CMAKE_CXX_COMPILER_ID STREQUAL "Clang") # not AppleClang target_compile_definitions(core_monitor @@ -65,7 +77,10 @@ if(ENABLE_CLANG_TIDY) endif() endif() + + set_property(TARGET core_monitor APPEND PROPERTY INTERFACE_INCLUDE_DIRECTORIES + $ $ ) diff --git a/src/core/monitor/gnss_synchro_monitor.cc b/src/core/monitor/gnss_synchro_monitor.cc index d52fb10d7..28e26cdf4 100644 --- a/src/core/monitor/gnss_synchro_monitor.cc +++ b/src/core/monitor/gnss_synchro_monitor.cc @@ -41,26 +41,29 @@ gnss_synchro_monitor_sptr gnss_synchro_make_monitor(unsigned int n_channels, int decimation_factor, int udp_port, - const std::vector& udp_addresses) + const std::vector& udp_addresses, + bool enable_protobuf) { return gnss_synchro_monitor_sptr(new gnss_synchro_monitor(n_channels, decimation_factor, udp_port, - udp_addresses)); + udp_addresses, + enable_protobuf)); } gnss_synchro_monitor::gnss_synchro_monitor(unsigned int n_channels, int decimation_factor, int udp_port, - const std::vector& udp_addresses) : gr::sync_block("gnss_synchro_monitor", - gr::io_signature::make(n_channels, n_channels, sizeof(Gnss_Synchro)), - gr::io_signature::make(0, 0, 0)) + const std::vector& udp_addresses, + bool enable_protobuf) : gr::sync_block("gnss_synchro_monitor", + gr::io_signature::make(n_channels, n_channels, sizeof(Gnss_Synchro)), + gr::io_signature::make(0, 0, 0)) { d_decimation_factor = decimation_factor; d_nchannels = n_channels; - udp_sink_ptr = std::unique_ptr(new Gnss_Synchro_Udp_Sink(udp_addresses, udp_port)); + udp_sink_ptr = std::unique_ptr(new Gnss_Synchro_Udp_Sink(udp_addresses, udp_port, enable_protobuf)); count = 0; } diff --git a/src/core/monitor/gnss_synchro_monitor.h b/src/core/monitor/gnss_synchro_monitor.h index 03c37ab28..27f23e7c1 100644 --- a/src/core/monitor/gnss_synchro_monitor.h +++ b/src/core/monitor/gnss_synchro_monitor.h @@ -50,7 +50,8 @@ using gnss_synchro_monitor_sptr = boost::shared_ptr; gnss_synchro_monitor_sptr gnss_synchro_make_monitor(unsigned int n_channels, int decimation_factor, int udp_port, - const std::vector& udp_addresses); + const std::vector& udp_addresses, + bool enable_protobuf); /*! * \brief This class implements a monitoring block which allows sending @@ -63,12 +64,14 @@ private: friend gnss_synchro_monitor_sptr gnss_synchro_make_monitor(unsigned int n_channels, int decimation_factor, int udp_port, - const std::vector& udp_addresses); + const std::vector& udp_addresses, + bool enable_protobuf); gnss_synchro_monitor(unsigned int n_channels, int decimation_factor, int udp_port, - const std::vector& udp_addresses); + const std::vector& udp_addresses, + bool enable_protobuf); unsigned int d_nchannels; int d_decimation_factor; diff --git a/src/core/monitor/gnss_synchro_udp_sink.cc b/src/core/monitor/gnss_synchro_udp_sink.cc index 23cb236c4..ae1100d63 100644 --- a/src/core/monitor/gnss_synchro_udp_sink.cc +++ b/src/core/monitor/gnss_synchro_udp_sink.cc @@ -35,8 +35,13 @@ #include #include -Gnss_Synchro_Udp_Sink::Gnss_Synchro_Udp_Sink(std::vector addresses, const uint16_t& port) : socket{io_service} +Gnss_Synchro_Udp_Sink::Gnss_Synchro_Udp_Sink(std::vector addresses, const uint16_t& port, bool enable_protobuf) : socket{io_service} { + use_protobuf = enable_protobuf; + if (enable_protobuf) + { + serdes = Serdes_Gnss_Synchro(); + } for (const auto& address : addresses) { boost::asio::ip::udp::endpoint endpoint(boost::asio::ip::address::from_string(address, error), port); @@ -47,11 +52,18 @@ Gnss_Synchro_Udp_Sink::Gnss_Synchro_Udp_Sink(std::vector addresses, bool Gnss_Synchro_Udp_Sink::write_gnss_synchro(const std::vector& stocks) { - std::ostringstream archive_stream; - boost::archive::binary_oarchive oa{archive_stream}; - oa << stocks; - std::string outbound_data = archive_stream.str(); - + std::string outbound_data; + if (use_protobuf == false) + { + std::ostringstream archive_stream; + boost::archive::binary_oarchive oa{archive_stream}; + oa << stocks; + outbound_data = archive_stream.str(); + } + else + { + outbound_data = serdes.createProtobuffer(stocks); + } for (const auto& endpoint : endpoints) { socket.open(endpoint.protocol(), error); diff --git a/src/core/monitor/gnss_synchro_udp_sink.h b/src/core/monitor/gnss_synchro_udp_sink.h index bfaebf45d..f3d5f2830 100644 --- a/src/core/monitor/gnss_synchro_udp_sink.h +++ b/src/core/monitor/gnss_synchro_udp_sink.h @@ -33,6 +33,7 @@ #define GNSS_SDR_GNSS_SYNCHRO_UDP_SINK_H_ #include "gnss_synchro.h" +#include "serdes_gnss_synchro.h" #include #include #include @@ -47,7 +48,7 @@ class Gnss_Synchro_Udp_Sink { public: - Gnss_Synchro_Udp_Sink(std::vector addresses, const uint16_t& port); + Gnss_Synchro_Udp_Sink(std::vector addresses, const uint16_t& port, bool enable_protobuf); bool write_gnss_synchro(const std::vector& stocks); private: @@ -56,6 +57,8 @@ private: boost::system::error_code error; std::vector endpoints; std::vector stocks; + Serdes_Gnss_Synchro serdes; + bool use_protobuf; }; diff --git a/src/core/monitor/serdes_gnss_synchro.h b/src/core/monitor/serdes_gnss_synchro.h new file mode 100644 index 000000000..cbab0bd48 --- /dev/null +++ b/src/core/monitor/serdes_gnss_synchro.h @@ -0,0 +1,160 @@ +/*! + * \file serdes_gnss_synchro.h + * \brief Serialization / Deserialization of Gnss_Synchro objects using + * Protocol Buffers + * \author Carles Fernandez-Prades, 2019. cfernandez(at)cttc.es + * + * ------------------------------------------------------------------------- + * + * Copyright (C) 2010-2019 (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 . + * + * ------------------------------------------------------------------------- + */ + +#ifndef GNSS_SDR_SERDES_GNSS_SYNCHRO_H_ +#define GNSS_SDR_SERDES_GNSS_SYNCHRO_H_ + +#include "gnss_synchro.h" +#include "gnss_synchro.pb.h" // file created by Protocol Buffers at compile time +#include // for memcpy +#include + + +/*! + * \brief This class implements serialization and deserialization of + * Gnss_Synchro objects using Protocol Buffers. + */ +class Serdes_Gnss_Synchro +{ +public: + Serdes_Gnss_Synchro() + { + // Verify that the version of the library that we linked against is + // compatible with the version of the headers we compiled against. + GOOGLE_PROTOBUF_VERIFY_VERSION; + observables.New(); + } + ~Serdes_Gnss_Synchro() + { + google::protobuf::ShutdownProtobufLibrary(); + } + + inline std::string createProtobuffer(const std::vector& vgs) //!< Serialization into a string + { + observables.Clear(); + + std::string data; + for (auto gs : vgs) + { + gnss_sdr::GnssSynchro* obs = observables.add_observable(); + char c[2]; + c[0] = gs.System; + c[1] = '\0'; + const std::string sys(c); + + char cc[3]; + cc[0] = gs.Signal[0]; + cc[1] = gs.Signal[1]; + cc[2] = '\0'; + const std::string sig(cc); + + obs->set_system(sys); + obs->set_signal(sig); + obs->set_prn(gs.PRN); + obs->set_channel_id(gs.Channel_ID); + + obs->set_acq_delay_samples(gs.Acq_delay_samples); + obs->set_acq_doppler_hz(gs.Acq_doppler_hz); + obs->set_acq_samplestamp_samples(gs.Acq_samplestamp_samples); + obs->set_acq_doppler_step(gs.Acq_doppler_step); + obs->set_flag_valid_acquisition(gs.Flag_valid_acquisition); + + obs->set_fs(gs.fs); + obs->set_prompt_i(gs.Prompt_I); + obs->set_prompt_q(gs.Prompt_Q); + obs->set_cn0_db_hz(gs.CN0_dB_hz); + obs->set_carrier_doppler_hz(gs.Carrier_Doppler_hz); + obs->set_code_phase_samples(gs.Code_phase_samples); + obs->set_tracking_sample_counter(gs.Tracking_sample_counter); + obs->set_flag_valid_symbol_output(gs.Flag_valid_symbol_output); + obs->set_correlation_length_ms(gs.correlation_length_ms); + + obs->set_fs(gs.Flag_valid_word); + obs->set_fs(gs.TOW_at_current_symbol_ms); + + obs->set_pseudorange_m(gs.Pseudorange_m); + obs->set_rx_time(gs.RX_time); + obs->set_flag_valid_pseudorange(gs.Flag_valid_pseudorange); + obs->set_interp_tow_ms(gs.interp_TOW_ms); + } + observables.SerializeToString(&data); + return data; + } + + + inline std::vector readProtobuffer(const gnss_sdr::Observables& obs) //!< Deserialization + { + std::vector vgs; + vgs.reserve(obs.observable_size()); + + for (int i = 0; i < obs.observable_size(); ++i) + { + const gnss_sdr::GnssSynchro& gs_read = obs.observable(i); + Gnss_Synchro gs = Gnss_Synchro(); + const std::string& sys = gs_read.system(); + gs.System = *sys.c_str(); + const std::string& sig = gs_read.signal(); + std::memcpy(static_cast(gs.Signal), sig.c_str(), 3); + gs.PRN = gs_read.prn(); + gs.Channel_ID = gs_read.channel_id(); + + gs.Acq_delay_samples = gs_read.acq_delay_samples(); + gs.Acq_doppler_hz = gs_read.acq_doppler_hz(); + gs.Acq_samplestamp_samples = gs_read.acq_samplestamp_samples(); + gs.Acq_doppler_step = gs_read.acq_doppler_step(); + gs.Flag_valid_acquisition = gs_read.flag_valid_acquisition(); + + gs.fs = gs_read.fs(); + gs.Prompt_I = gs_read.prompt_i(); + gs.Prompt_Q = gs_read.prompt_q(); + gs.CN0_dB_hz = gs_read.cn0_db_hz(); + gs.Carrier_Doppler_hz = gs_read.carrier_doppler_hz(); + gs.Tracking_sample_counter = gs_read.tracking_sample_counter(); + gs.Flag_valid_symbol_output = gs_read.flag_valid_symbol_output(); + gs.correlation_length_ms = gs_read.correlation_length_ms(); + + gs.Flag_valid_word = gs_read.flag_valid_word(); + gs.TOW_at_current_symbol_ms = gs_read.tow_at_current_symbol_ms(); + + gs.Pseudorange_m = gs_read.pseudorange_m(); + gs.RX_time = gs_read.rx_time(); + gs.Flag_valid_pseudorange = gs_read.flag_valid_pseudorange(); + gs.interp_TOW_ms = gs_read.interp_tow_ms(); + + vgs.push_back(gs); + } + return vgs; + } +private: + gnss_sdr::Observables observables; +}; + +#endif // GNSS_SDR_SERDES_GNSS_SYNCHRO_H_ diff --git a/src/core/receiver/gnss_flowgraph.cc b/src/core/receiver/gnss_flowgraph.cc index 25f0549d1..33ae8ca26 100644 --- a/src/core/receiver/gnss_flowgraph.cc +++ b/src/core/receiver/gnss_flowgraph.cc @@ -215,7 +215,7 @@ void GNSSFlowgraph::connect() } DLOG(INFO) << "blocks connected internally"; -// Signal Source (i) > Signal conditioner (i) > + // Signal Source (i) > Signal conditioner (i) > #ifndef ENABLE_FPGA int RF_Channels = 0; int signal_conditioner_ID = 0; @@ -444,20 +444,20 @@ void GNSSFlowgraph::connect() // create a FIR low pass filter std::vector taps; - // float beta = 7.0; - // float halfband = 0.5; - // float fractional_bw = 0.4; - // float rate = 1.0 / static_cast(decimation); + // float beta = 7.0; + // float halfband = 0.5; + // float fractional_bw = 0.4; + // float rate = 1.0 / static_cast(decimation); // - // float trans_width = rate * (halfband - fractional_bw); - // float mid_transition_band = rate * halfband - trans_width / 2.0; + // float trans_width = rate * (halfband - fractional_bw); + // float mid_transition_band = rate * halfband - trans_width / 2.0; // - // taps = gr::filter::firdes::low_pass(1.0, - // 1.0, - // mid_transition_band, - // trans_width, - // gr::filter::firdes::win_type::WIN_KAISER, - // beta); + // taps = gr::filter::firdes::low_pass(1.0, + // 1.0, + // mid_transition_band, + // trans_width, + // gr::filter::firdes::win_type::WIN_KAISER, + // beta); taps = gr::filter::firdes::low_pass(1.0, fs, @@ -526,7 +526,6 @@ void GNSSFlowgraph::connect() } #endif - // Signal Source > Signal conditioner >> Channels >> Observables try { @@ -556,6 +555,7 @@ void GNSSFlowgraph::connect() } } } + // Put channels fixed to a given satellite at the beginning of the vector, then the rest std::vector vector_of_channels; for (unsigned int i = 0; i < channels_count_; i++) @@ -1169,7 +1169,6 @@ void GNSSFlowgraph::apply_action(unsigned int who, unsigned int what) } acq_channels_count_++; DLOG(INFO) << "Channel " << ch_index << " Starting acquisition " << channels_[ch_index]->get_signal().get_satellite() << ", Signal " << channels_[ch_index]->get_signal().get_signal_str(); - #ifndef ENABLE_FPGA channels_[ch_index]->start_acquisition(); #else @@ -1704,7 +1703,11 @@ void GNSSFlowgraph::init() * Instantiate the receiver monitor block, if required */ enable_monitor_ = configuration_->property("Monitor.enable_monitor", false); - + bool enable_protobuf = configuration_->property("Monitor.enable_protobuf", true); + if (configuration_->property("PVT.enable_protobuf", false) == true) + { + enable_protobuf = true; + } std::string address_string = configuration_->property("Monitor.client_addresses", std::string("127.0.0.1")); std::vector udp_addr_vec = split_string(address_string, '_'); std::sort(udp_addr_vec.begin(), udp_addr_vec.end()); @@ -1715,7 +1718,7 @@ void GNSSFlowgraph::init() GnssSynchroMonitor_ = gnss_synchro_make_monitor(channels_count_, configuration_->property("Monitor.decimation_factor", 1), configuration_->property("Monitor.udp_port", 1234), - udp_addr_vec); + udp_addr_vec, enable_protobuf); } } diff --git a/src/tests/test_main.cc b/src/tests/test_main.cc index 1aa5e558a..05df98d35 100644 --- a/src/tests/test_main.cc +++ b/src/tests/test_main.cc @@ -66,6 +66,7 @@ DECLARE_string(log_dir); #include "unit-tests/control-plane/gnss_block_factory_test.cc" #include "unit-tests/control-plane/gnss_flowgraph_test.cc" #include "unit-tests/control-plane/in_memory_configuration_test.cc" +#include "unit-tests/control-plane/protobuf_test.cc" #include "unit-tests/control-plane/string_converter_test.cc" #include "unit-tests/signal-processing-blocks/acquisition/galileo_e1_pcps_8ms_ambiguous_acquisition_gsoc2013_test.cc" #include "unit-tests/signal-processing-blocks/acquisition/galileo_e1_pcps_ambiguous_acquisition_gsoc2013_test.cc" @@ -119,6 +120,7 @@ DECLARE_string(log_dir); #include "unit-tests/signal-processing-blocks/pvt/rinex_printer_test.cc" #include "unit-tests/signal-processing-blocks/pvt/rtcm_printer_test.cc" #include "unit-tests/signal-processing-blocks/pvt/rtcm_test.cc" +#include "unit-tests/signal-processing-blocks/pvt/serdes_monitor_pvt_test.cc" #include "unit-tests/signal-processing-blocks/telemetry_decoder/galileo_fnav_inav_decoder_test.cc" #include "unit-tests/system-parameters/glonass_gnav_ephemeris_test.cc" #include "unit-tests/system-parameters/glonass_gnav_nav_message_test.cc" diff --git a/src/tests/unit-tests/control-plane/protobuf_test.cc b/src/tests/unit-tests/control-plane/protobuf_test.cc new file mode 100644 index 000000000..95d83a519 --- /dev/null +++ b/src/tests/unit-tests/control-plane/protobuf_test.cc @@ -0,0 +1,107 @@ +/*! + * \file protobuf_test.cc + * \brief This file implements tests for Serdes_Gnss_Synchro + * \author Carles Fernandez-Prades, 2019. cfernandez(at)cttc.es + * + * ------------------------------------------------------------------------- + * + * Copyright (C) 2010-2019 (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 "serdes_gnss_synchro.h" + +TEST(Protobuf, Works) +{ + uint32_t prn_true = 17; + uint32_t prn_true2 = 23; + std::string sys = "G"; + std::string sig = "1C"; + + Gnss_Synchro gs = Gnss_Synchro(); + gs.System = *sys.c_str(); + std::memcpy(static_cast(gs.Signal), sig.c_str(), 3); + gs.PRN = prn_true; + + gs.Channel_ID = 3; + + gs.Acq_delay_samples = 431; + gs.Acq_doppler_hz = 1234; + gs.Acq_samplestamp_samples = 10000; + gs.Acq_doppler_step = 125; + gs.Flag_valid_acquisition = true; + + gs.fs = 10000000; + gs.Prompt_I = 10000.0; + gs.Prompt_Q = 0.01; + gs.CN0_dB_hz = 39; + gs.Carrier_Doppler_hz = 321; + gs.Tracking_sample_counter = 11000; + gs.Flag_valid_symbol_output = false; + gs.correlation_length_ms = 1; + + gs.Flag_valid_word = false; + gs.TOW_at_current_symbol_ms = 12345; + + gs.Pseudorange_m = 22000002.1; + gs.RX_time = 4321; + gs.Flag_valid_pseudorange = false; + gs.interp_TOW_ms = 20; + + gs.Pseudorange_m = 22000002.1; + gs.Carrier_phase_rads = 45.4; + gs.Carrier_Doppler_hz = 321; + gs.CN0_dB_hz = 39; + + Serdes_Gnss_Synchro serdes = Serdes_Gnss_Synchro(); + + // Create a vector of Gnss_Synchro objects + std::vector vgs; + vgs.push_back(gs); + gs.PRN = prn_true2; + vgs.push_back(gs); + + // Serialize data + std::string serialized_data = serdes.createProtobuffer(vgs); + + // Recover data from serialization + gnss_sdr::Observables obs; + obs.ParseFromString(serialized_data); + + // Check that recovered data is ok + + // We can access like this: + std::vector vgs_read = serdes.readProtobuffer(obs); + Gnss_Synchro gs_read = vgs_read[0]; + uint32_t prn_read = gs_read.PRN; + uint32_t prn_read2 = vgs_read[1].PRN; + + // or without the need of gnss_synchro: + int obs_size = obs.observable_size(); + uint32_t prn_read3 = obs.observable(0).prn(); + + EXPECT_EQ(prn_true, prn_read); + EXPECT_EQ(prn_true2, prn_read2); + EXPECT_EQ(prn_true, prn_read3); + EXPECT_EQ(2, obs_size); +} diff --git a/src/tests/unit-tests/signal-processing-blocks/pvt/serdes_monitor_pvt_test.cc b/src/tests/unit-tests/signal-processing-blocks/pvt/serdes_monitor_pvt_test.cc new file mode 100644 index 000000000..eb586f147 --- /dev/null +++ b/src/tests/unit-tests/signal-processing-blocks/pvt/serdes_monitor_pvt_test.cc @@ -0,0 +1,47 @@ +/*! + * \file serdes_monitor_pvt_test.cc + * \brief Implements Unit Test for the serdes_monitor_pvt class. + * \author Carles Fernandez_prades, 2019. cfernandez(at)cttc.es + * + * ------------------------------------------------------------------------- + * + * Copyright (C) 2010-2019 (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 "serdes_monitor_pvt.h" + +TEST(Serdes_Monitor_Pvt_Test, Simpletest) +{ + Monitor_Pvt monitor = Monitor_Pvt(); + double true_latitude = 23.4; + monitor.latitude = true_latitude; + + Serdes_Monitor_Pvt serdes = Serdes_Monitor_Pvt(); + std::string serialized_data = serdes.createProtobuffer(monitor); + + gnss_sdr::MonitorPvt mon; + mon.ParseFromString(serialized_data); + + double read_latitude = mon.latitude(); + EXPECT_NEAR(true_latitude, read_latitude, 0.000001); +}