diff --git a/src/algorithms/PVT/libs/CMakeLists.txt b/src/algorithms/PVT/libs/CMakeLists.txt index b330bcc0f..fccec3fe2 100644 --- a/src/algorithms/PVT/libs/CMakeLists.txt +++ b/src/algorithms/PVT/libs/CMakeLists.txt @@ -1,4 +1,4 @@ -# Copyright (C) 2012-2013 (see AUTHORS file for a list of contributors) +# Copyright (C) 2012-2014 (see AUTHORS file for a list of contributors) # # This file is part of GNSS-SDR. # @@ -22,7 +22,7 @@ set(PVT_LIB_SOURCES kml_printer.cc rinex_printer.cc nmea_printer.cc -# rtcm_printer.cc + rtcm_printer.cc ) include_directories( @@ -33,10 +33,10 @@ include_directories( ${CMAKE_SOURCE_DIR}/src/algorithms/PVT/adapters ${Boost_INCLUDE_DIRS} ${ARMADILLO_INCLUDE_DIRS} - ${GLOG_INCLUDE_DIRS} ${GFlags_INCLUDE_DIRS} + ${GLOG_INCLUDE_DIRS} ) add_library(pvt_lib ${PVT_LIB_SOURCES}) add_dependencies(pvt_lib armadillo-${armadillo_RELEASE} glog-${glog_RELEASE}) -target_link_libraries(pvt_lib ${Boost_LIBRARIES} ${GFlags_LIBS} ${GLOG_LIBRARIES} ${ARMADILLO_LIBRARIES} ) +target_link_libraries(pvt_lib ${Boost_LIBRARIES} ${GFlags_LIBS} ${GLOG_LIBRARIES} ${ARMADILLO_LIBRARIES}) diff --git a/src/algorithms/PVT/libs/rtcm_printer.cc b/src/algorithms/PVT/libs/rtcm_printer.cc new file mode 100644 index 000000000..88f7b9024 --- /dev/null +++ b/src/algorithms/PVT/libs/rtcm_printer.cc @@ -0,0 +1,392 @@ +/*! + * \file rtcm_printer.cc + * \brief Implementation of a RTCM 3.2 printer for GNSS-SDR + * This class provides a implementation of a subset of the RTCM Standard 10403.2 + * for Differential GNSS Services + * + * \author Carles Fernandez-Prades, 2014. cfernandez(at)cttc.es + * + * ------------------------------------------------------------------------- + * + * Copyright (C) 2010-2014 (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 "rtcm_printer.h" +#include // for O_RDWR +#include // for tcgetattr +#include // for std::reverse +#include // for std::stringstream +#include // for to_upper_copy +#include +#include +#include +#include + + +using google::LogMessage; + +//DEFINE_string(RTCM_version, "3.2", "Specifies the RTCM Version"); + +Rtcm_Printer::Rtcm_Printer(std::string filename, bool flag_rtcm_tty_port, std::string rtcm_dump_devname) +{ + rtcm_filename = filename; + rtcm_file_descriptor.open(rtcm_filename.c_str(), std::ios::out); + if (rtcm_file_descriptor.is_open()) + { + DLOG(INFO) << "RTCM printer writing on " << rtcm_filename.c_str(); + } + + rtcm_devname = rtcm_dump_devname; + if (flag_rtcm_tty_port == true) + { + rtcm_dev_descriptor = init_serial(rtcm_devname.c_str()); + if (rtcm_dev_descriptor != -1) + { + DLOG(INFO) << "RTCM printer writing on " << rtcm_devname.c_str(); + } + } + else + { + rtcm_dev_descriptor = -1; + } + Rtcm_Printer::reset_data_fields(); + preamble = std::bitset<8>("11010011"); + reserved_field = std::bitset<6>("000000"); +} + + + + +Rtcm_Printer::~Rtcm_Printer() +{ + if (rtcm_file_descriptor.is_open()) + { + long pos; + rtcm_file_descriptor.close(); + pos = rtcm_file_descriptor.tellp(); + if (pos == 0) remove(rtcm_filename.c_str()); + } + close_serial(); +} + + + + +int Rtcm_Printer::init_serial(std::string serial_device) +{ + /*! + * Opens the serial device and sets the default baud rate for a NMEA transmission (9600,8,N,1) + */ + int fd = 0; + struct termios options; + long BAUD; + long DATABITS; + long STOPBITS; + long PARITYON; + long PARITY; + + fd = open(serial_device.c_str(), O_RDWR | O_NOCTTY | O_NDELAY); + if (fd == -1) return fd; // failed to open TTY port + + fcntl(fd, F_SETFL, 0); // clear all flags on descriptor, enable direct I/O + tcgetattr(fd, &options); // read serial port options + + BAUD = B9600; + //BAUD = B38400; + DATABITS = CS8; + STOPBITS = 0; + PARITYON = 0; + PARITY = 0; + + options.c_cflag = BAUD | DATABITS | STOPBITS | PARITYON | PARITY | CLOCAL | CREAD; + // enable receiver, set 8 bit data, ignore control lines + //options.c_cflag |= (CLOCAL | CREAD | CS8); + options.c_iflag = IGNPAR; + + // set the new port options + tcsetattr(fd, TCSANOW, &options); + return fd; +} + + + +void Rtcm_Printer::close_serial() +{ + if (rtcm_dev_descriptor != -1) + { + close(rtcm_dev_descriptor); + } +} + +void Rtcm_Printer::reset_data_fields() +{ + //DF001.reset(); + DF002.reset(); + DF003.reset(); + DF004.reset(); + DF005.reset(); + DF006.reset(); + DF007.reset(); + DF008.reset(); + DF009.reset(); + DF010.reset(); + DF011.reset(); + DF012.reset(); + DF013.reset(); + DF014.reset(); + DF015.reset(); + + // Contents of GPS Satellite Ephemeris Data, Message Type 1019 + DF071.reset(); + DF076.reset(); + DF077.reset(); + DF078.reset(); + DF079.reset(); + DF081.reset(); + DF082.reset(); + DF083.reset(); + DF084.reset(); + DF085.reset(); + DF086.reset(); + DF087.reset(); + + DF088.reset(); + DF089.reset(); + DF090.reset(); + DF091.reset(); + DF092.reset(); + DF093.reset(); + DF094.reset(); + DF095.reset(); + DF096.reset(); + DF097.reset(); + DF098.reset(); + DF099.reset(); + DF100.reset(); + DF101.reset(); + DF102.reset(); + DF103.reset(); + DF137.reset(); + + // Contents of Galileo F/NAV Satellite Ephemeris Data, Message Type 1045 + DF252.reset(); + DF289.reset(); + DF290.reset(); + DF291.reset(); + DF292.reset(); + DF293.reset(); + DF294.reset(); + DF295.reset(); + DF296.reset(); + DF297.reset(); + DF298.reset(); + DF299.reset(); + DF300.reset(); + DF301.reset(); + DF302.reset(); + DF303.reset(); + DF304.reset(); + DF305.reset(); + DF306.reset(); + DF307.reset(); + DF308.reset(); + DF309.reset(); + DF310.reset(); + DF311.reset(); + DF312.reset(); + DF314.reset(); + DF315.reset(); +} + + + +/* Stationary Antenna Reference Point, No Height Information + * Reference Station Id = 2003 + GPS Service supported, but not GLONASS or Galileo + ARP ECEF-X = 1114104.5999 meters + ARP ECEF-Y = -4850729.7108 meters + ARP ECEF-Z = 3975521.4643 meters + Expected output: D3 00 13 3E D7 D3 02 02 98 0E DE EF 34 B4 BD 62 + AC 09 41 98 6F 33 36 0B 98 + */ +std::bitset<152> Rtcm_Printer::get_M1005_test () +{ + unsigned int m1005 = 1005; + unsigned int reference_station_id = 2003; // Max: 4095 + long long int ECEF_X = 11141045999; // Resolution 0.0001 m + long long int ECEF_Y = -48507297108; // Resolution 0.0001 m + long long int ECEF_Z = 39755214643; // Resolution 0.0001 m + unsigned int itrf_realization_year = 0; // Reserved + std::bitset<1> DF001; + + DF002 = std::bitset<12>(m1005); + DF003 = std::bitset<12>(reference_station_id); + DF021 = std::bitset<6>(itrf_realization_year); + DF022 = std::bitset<1>("1"); // GPS + DF023 = std::bitset<1>("0"); // Glonass + DF024 = std::bitset<1>("0"); // Galileo + DF141 = std::bitset<1>("0"); // 0: Real, physical reference station + DF001 = std::bitset<1>("0"); // Reserved, set to 0 + DF025 = std::bitset<38>(ECEF_X); // ECEF-X in 0.0001 m + DF142 = std::bitset<1>("0"); // Single Receiver Oscillator Indicator + DF026 = std::bitset<38>(ECEF_Y); // ECEF-Y in 0.0001 m + DF364 = std::bitset<2>("00"); // Quarter Cycle Indicator + DF027 = std::bitset<38>(ECEF_Z); // ECEF-Z in 0.0001 m + + std::string message = DF002.to_string() + + DF003.to_string() + + DF021.to_string() + + DF022.to_string() + + DF023.to_string() + + DF024.to_string() + + DF141.to_string() + + DF025.to_string() + + DF142.to_string() + + DF001.to_string() + + DF026.to_string() + + DF364.to_string() + + DF027.to_string() ; + + std::bitset<152> test_msg(message); + return test_msg; +} + + + +std::string Rtcm_Printer::print_M1005_test () +{ + std::bitset<152> m1005 = get_M1005_test(); + unsigned int msg_length_bits = m1005.to_string().length(); + unsigned int msg_length_bytes = std::ceil((float)msg_length_bits / 8.0); + message_length = std::bitset<10>(msg_length_bytes); + unsigned int zeros_to_fill = 8*msg_length_bytes - msg_length_bits; + std::string b(zeros_to_fill, '0'); + std::string msg_content = m1005.to_string() + b; + std::string msg_without_crc = preamble.to_string() + + reserved_field.to_string() + + message_length.to_string() + + msg_content; + return Rtcm_Printer::add_CRC(msg_without_crc); +} + + + +std::bitset<122> Rtcm_Printer::get_M1001() +{ + unsigned int m1001 = 1001; + unsigned int reference_station_id = 1234; // Max: 4095 + DF002 = std::bitset<12>(m1001); + DF003 = std::bitset<12>(reference_station_id); + //DF004 = std::bitset<30> + //DF005 = std::bitset<1> + //DF006 = std::bitset<5> + DF007 = std::bitset<1>("0"); + //DF008 = std::bitset<3> + std::bitset<122> fake_msg; + fake_msg.reset(); + return fake_msg; +} + + + +void Rtcm_Printer::print_M1001 () +{ + std::bitset<122> m1001 = get_M1001(); + unsigned int msg_length_bits = m1001.to_string().length(); + unsigned int msg_length_bytes = std::ceil((float)msg_length_bits/8.0); + message_length = std::bitset<10>(msg_length_bytes); + unsigned int zeros_to_fill = 8*msg_length_bytes - msg_length_bits; + std::string b(zeros_to_fill, '0'); + message_length = std::bitset<10>((int)msg_length_bytes); + std::string msg_content = m1001.to_string() + b; + std::string msg_without_crc = preamble.to_string() + + reserved_field.to_string() + + message_length.to_string() + + msg_content; + std::string message = Rtcm_Printer::add_CRC(msg_without_crc); +} + + + +std::bitset<138> Rtcm_Printer::get_M1002 () +{ + std::bitset<138> fake_msg; + fake_msg.reset(); + return fake_msg; +} + +std::bitset<488> Rtcm_Printer::get_M1019 () +{ + std::bitset<488> fake_msg; + fake_msg.reset(); + return fake_msg; +} + + + +std::bitset<496> Rtcm_Printer::get_M1045 () +{ + std::bitset<496> fake_msg; + fake_msg.reset(); + return fake_msg; +} + + + + + +std::string Rtcm_Printer::add_CRC (const std::string& message_without_crc) +{ + // ****** Computes Qualcomm CRC-24Q ****** + // 1) Converts the string to a vector of unsigned char: + boost::dynamic_bitset frame_bits(message_without_crc); + std::vector bytes; + boost::to_block_range(frame_bits, std::back_inserter(bytes)); + std::reverse(bytes.begin(),bytes.end()); + + // 2) Computes CRC + CRC_RTCM.process_bytes(bytes.data(), bytes.size()); + crc_frame = std::bitset<24>(CRC_RTCM.checksum()); + + // 3) Builds the complete message + std::string complete_message = message_without_crc + crc_frame.to_string(); + return bin_to_hex(complete_message); +} + + +std::string Rtcm_Printer::bin_to_hex(const std::string& s) +{ + std::string s_aux; + std::stringstream ss; + for(int i = 0; i < s.length() - 1; i = i + 32) + { + s_aux.assign(s, i, 32); + std::bitset<32> bs(s_aux); + unsigned n = bs.to_ulong(); + ss << std::hex << n; + } + //return ss.str(); + return boost::to_upper_copy(ss.str()); +} + + diff --git a/src/algorithms/PVT/libs/rtcm_printer.h b/src/algorithms/PVT/libs/rtcm_printer.h new file mode 100644 index 000000000..586c3ebc8 --- /dev/null +++ b/src/algorithms/PVT/libs/rtcm_printer.h @@ -0,0 +1,222 @@ +/*! + * \file rtcm_printer.h + * \brief Interface of a RTCM 3.2 printer for GNSS-SDR + * This class provides a implementation of a subset of the RTCM Standard 10403.2 + * for Differential GNSS Services + * + * \author Carles Fernandez-Prades, 2014. cfernandez(at)cttc.es + * + * ------------------------------------------------------------------------- + * + * Copyright (C) 2010-2014 (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_RTCM_PRINTER_H_ +#define GNSS_SDR_RTCM_PRINTER_H_ + +#include // std::bitset +#include // std::ofstream +#include // std::cout +#include // std::string +#include +#include + + +/*! + * \brief This class provides a implementation of a subset of the RTCM Standard 10403.2 messages + */ +class Rtcm_Printer +{ +public: + /*! + * \brief Default constructor. + */ + Rtcm_Printer(std::string filename, bool flag_rtcm_tty_port, std::string rtcm_dump_filename); + + /*! + * \brief Print RTCM 3.2 messages to the initialized device + */ + //bool Print_Nmea_Line(gps_l1_ca_ls_pvt* position, bool print_average_values); + + /*! + * \brief Default destructor. + */ + ~Rtcm_Printer(); + + void print_M1001(); + std::string print_M1005_test(); +private: + std::string rtcm_filename; // String with the RTCM log filename + std::ofstream rtcm_file_descriptor; // Output file stream for RTCM log file + std::string rtcm_devname; + int rtcm_dev_descriptor; // RTCM serial device descriptor (i.e. COM port) + //gps_l1_ca_ls_pvt* d_PVT_data; + int init_serial (std::string serial_device); //serial port control + void close_serial (); + + //std::bitset<8> DF001; + std::bitset<12> DF002; + std::bitset<12> DF003; + std::bitset<30> DF004; + std::bitset<1> DF005; + std::bitset<5> DF006; + std::bitset<1> DF007; + std::bitset<3> DF008; + std::bitset<6> DF009; + std::bitset<1> DF010; + std::bitset<24> DF011; + std::bitset<20> DF012; + std::bitset<7> DF013; + std::bitset<8> DF014; + std::bitset<8> DF015; + + + std::bitset<6> DF021; + std::bitset<1> DF022; + std::bitset<1> DF023; + std::bitset<1> DF024; + std::bitset<38> DF025; + std::bitset<38> DF026; + std::bitset<38> DF027; + + // Contents of GPS Satellite Ephemeris Data, Message Type 1019 + std::bitset<8> DF071; + std::bitset<10> DF076; + std::bitset<4> DF077; + std::bitset<2> DF078; + std::bitset<14> DF079; + std::bitset<16> DF081; + std::bitset<8> DF082; + std::bitset<16> DF083; + std::bitset<22> DF084; + std::bitset<10> DF085; + std::bitset<16> DF086; + std::bitset<16> DF087; + + std::bitset<32> DF088; + std::bitset<16> DF089; + std::bitset<32> DF090; + std::bitset<16> DF091; + std::bitset<32> DF092; + std::bitset<16> DF093; + std::bitset<16> DF094; + std::bitset<32> DF095; + std::bitset<16> DF096; + std::bitset<32> DF097; + std::bitset<16> DF098; + std::bitset<32> DF099; + std::bitset<24> DF100; + std::bitset<8> DF101; + std::bitset<6> DF102; + std::bitset<1> DF103; + std::bitset<1> DF137; + + + std::bitset<1> DF141; + std::bitset<1> DF142; + + // Contents of Galileo F/NAV Satellite Ephemeris Data, Message Type 1045 + std::bitset<6> DF252; + std::bitset<12> DF289; + std::bitset<10> DF290; + std::bitset<8> DF291; + std::bitset<14> DF292; + std::bitset<14> DF293; + std::bitset<6> DF294; + std::bitset<21> DF295; + std::bitset<31> DF296; + std::bitset<16> DF297; + std::bitset<32> DF298; + std::bitset<14> DF299; + std::bitset<16> DF300; + std::bitset<32> DF301; + std::bitset<16> DF302; + std::bitset<32> DF303; + std::bitset<14> DF304; + std::bitset<16> DF305; + std::bitset<32> DF306; + std::bitset<16> DF307; + std::bitset<32> DF308; + std::bitset<16> DF309; + std::bitset<32> DF310; + std::bitset<24> DF311; + std::bitset<10> DF312; + std::bitset<2> DF314; + std::bitset<1> DF315; + + std::bitset<2> DF364; + + // Content of message header for MSM1, MSM2, MSM3, MSM4, MSM5, MSM6 and MSM7 + std::bitset<1> DF393; + std::bitset<1> DF394; + std::bitset<1> DF395; + std::bitset<1> DF396; //variable + std::bitset<1> DF409; + std::bitset<1> DF411; + std::bitset<1> DF412; + std::bitset<1> DF417; + std::bitset<1> DF418; + + // Content of Satellite data for MSM4 and MSM6 + std::vector > DF397; // 8*NSAT + std::vector > DF398; // 10*NSAT + + // Content of Satellite data for MSM5 and MSM7 + std::vector > DF399; // 14*NSAT + + // Messages + std::bitset<64> message1001_header; + std::bitset<58> message1001_content; + std::bitset<64> message1002_header; + std::bitset<74> message1002_content; + + std::bitset<488> message1019_content; + + std::bitset<496> message1045_content; + + std::bitset<169> MSM_header; // 169+X + + std::vector > MSM4_content; // 18 * Nsat + + std::vector > MSM5_content; // 36 * Nsat + + std::bitset<122> get_M1001(); + std::bitset<138> get_M1002(); // GPS observables + std::bitset<488> get_M1019(); // GPS ephemeris + std::bitset<496> get_M1045(); // Galileo ephemeris + std::bitset<152> get_M1005_test(); + + void reset_data_fields (); + + // Transport Layer + std::bitset<8> preamble; + std::bitset<6> reserved_field; + std::bitset<10> message_length; + std::bitset<24> crc_frame; + typedef boost::crc_optimal<24, 0x1864CFBu, 0x0, 0x0, false, false> crc_24_q_type; + crc_24_q_type CRC_RTCM; + std::string add_CRC(const std::string& m); + std::string bin_to_hex(const std::string& s); +}; + +#endif