2012-08-28 17:14:18 +00:00
|
|
|
/*!
|
|
|
|
* \file kml_printer.cc
|
|
|
|
* \brief Implementation of a NMEA 2.1 printer for GNSS-SDR
|
|
|
|
* This class provides a implementation of a subset of the NMEA-0183 standard for interfacing
|
|
|
|
* marine electronic devices as defined by the National Marine Electronics Association (NMEA).
|
|
|
|
* See http://www.nmea.org/ for the NMEA 183 standard
|
|
|
|
*
|
|
|
|
* \author Javier Arribas, 2012. jarribas(at)cttc.es
|
|
|
|
*
|
|
|
|
*
|
|
|
|
* -------------------------------------------------------------------------
|
|
|
|
*
|
2018-05-13 20:49:11 +00:00
|
|
|
* Copyright (C) 2010-2018 (see AUTHORS file for a list of contributors)
|
2012-08-28 17:14:18 +00:00
|
|
|
*
|
|
|
|
* 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
|
2015-01-08 18:49:59 +00:00
|
|
|
* (at your option) any later version.
|
2012-08-28 17:14:18 +00:00
|
|
|
*
|
|
|
|
* 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
|
2018-05-13 20:49:11 +00:00
|
|
|
* along with GNSS-SDR. If not, see <https://www.gnu.org/licenses/>.
|
2012-08-28 17:14:18 +00:00
|
|
|
*
|
|
|
|
* -------------------------------------------------------------------------
|
|
|
|
*/
|
|
|
|
|
2014-01-14 23:22:54 +00:00
|
|
|
#include "nmea_printer.h"
|
2018-11-05 14:39:56 +00:00
|
|
|
#include "rtklib_solution.h"
|
2014-01-14 23:22:54 +00:00
|
|
|
#include <boost/date_time/posix_time/posix_time.hpp>
|
2018-10-27 22:42:28 +00:00
|
|
|
#include <boost/filesystem/operations.hpp> // for create_directories, exists
|
|
|
|
#include <boost/filesystem/path.hpp> // for path, operator<<
|
|
|
|
#include <boost/filesystem/path_traits.hpp> // for filesystem
|
2012-08-28 17:14:18 +00:00
|
|
|
#include <glog/logging.h>
|
2018-08-11 11:56:24 +00:00
|
|
|
#include <cstdint>
|
2018-02-26 02:15:53 +00:00
|
|
|
#include <fcntl.h>
|
|
|
|
#include <termios.h>
|
2014-01-14 23:22:54 +00:00
|
|
|
|
2012-08-28 17:14:18 +00:00
|
|
|
|
|
|
|
using google::LogMessage;
|
|
|
|
|
|
|
|
|
2018-10-27 22:42:28 +00:00
|
|
|
Nmea_Printer::Nmea_Printer(std::string filename, bool flag_nmea_output_file, bool flag_nmea_tty_port, std::string nmea_dump_devname, const std::string& base_path)
|
2012-08-28 17:14:18 +00:00
|
|
|
{
|
2018-10-27 22:42:28 +00:00
|
|
|
nmea_base_path = base_path;
|
|
|
|
d_flag_nmea_output_file = flag_nmea_output_file;
|
|
|
|
if (d_flag_nmea_output_file == true)
|
2012-08-28 17:14:18 +00:00
|
|
|
{
|
2018-10-27 22:42:28 +00:00
|
|
|
boost::filesystem::path full_path(boost::filesystem::current_path());
|
|
|
|
const boost::filesystem::path p(nmea_base_path);
|
|
|
|
if (!boost::filesystem::exists(p))
|
|
|
|
{
|
|
|
|
std::string new_folder;
|
|
|
|
for (auto& folder : boost::filesystem::path(nmea_base_path))
|
|
|
|
{
|
|
|
|
new_folder += folder.string();
|
|
|
|
boost::system::error_code ec;
|
|
|
|
if (!boost::filesystem::exists(new_folder))
|
|
|
|
{
|
|
|
|
if (!boost::filesystem::create_directory(new_folder, ec))
|
|
|
|
{
|
|
|
|
std::cout << "Could not create the " << new_folder << " folder." << std::endl;
|
|
|
|
nmea_base_path = full_path.string();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
new_folder += boost::filesystem::path::preferred_separator;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
nmea_base_path = p.string();
|
|
|
|
}
|
|
|
|
|
|
|
|
if ((nmea_base_path.compare(".") != 0) and (d_flag_nmea_output_file == true))
|
|
|
|
{
|
|
|
|
std::cout << "NMEA files will be stored at " << nmea_base_path << std::endl;
|
|
|
|
}
|
|
|
|
|
|
|
|
nmea_base_path = nmea_base_path + boost::filesystem::path::preferred_separator;
|
|
|
|
|
|
|
|
nmea_filename = nmea_base_path + filename;
|
|
|
|
|
|
|
|
nmea_file_descriptor.open(nmea_filename.c_str(), std::ios::out);
|
|
|
|
if (nmea_file_descriptor.is_open())
|
|
|
|
{
|
|
|
|
DLOG(INFO) << "NMEA printer writing on " << nmea_filename.c_str();
|
|
|
|
}
|
2018-10-28 00:02:28 +00:00
|
|
|
else
|
|
|
|
{
|
|
|
|
std::cout << "File " << nmea_filename << " cannot be saved. Wrong permissions?" << std::endl;
|
|
|
|
}
|
2012-08-28 17:14:18 +00:00
|
|
|
}
|
2012-08-29 15:32:00 +00:00
|
|
|
|
2012-10-28 11:38:50 +00:00
|
|
|
nmea_devname = nmea_dump_devname;
|
|
|
|
if (flag_nmea_tty_port == true)
|
|
|
|
{
|
|
|
|
nmea_dev_descriptor = init_serial(nmea_devname.c_str());
|
|
|
|
if (nmea_dev_descriptor != -1)
|
|
|
|
{
|
|
|
|
DLOG(INFO) << "NMEA printer writing on " << nmea_devname.c_str();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
nmea_dev_descriptor = -1;
|
|
|
|
}
|
2015-11-25 13:03:59 +00:00
|
|
|
print_avg_pos = false;
|
2012-08-28 17:14:18 +00:00
|
|
|
}
|
|
|
|
|
2012-10-28 11:38:50 +00:00
|
|
|
|
2012-08-28 17:14:18 +00:00
|
|
|
Nmea_Printer::~Nmea_Printer()
|
|
|
|
{
|
|
|
|
if (nmea_file_descriptor.is_open())
|
|
|
|
{
|
2012-10-28 11:38:50 +00:00
|
|
|
nmea_file_descriptor.close();
|
2012-08-28 17:14:18 +00:00
|
|
|
}
|
2012-08-29 15:32:00 +00:00
|
|
|
close_serial();
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2018-03-03 01:03:39 +00:00
|
|
|
int Nmea_Printer::init_serial(std::string serial_device)
|
2012-10-28 11:38:50 +00:00
|
|
|
{
|
|
|
|
/*!
|
|
|
|
* Opens the serial device and sets the default baud rate for a NMEA transmission (9600,8,N,1)
|
|
|
|
*/
|
|
|
|
int fd = 0;
|
|
|
|
struct termios options;
|
2018-08-11 11:56:24 +00:00
|
|
|
int64_t BAUD;
|
|
|
|
int64_t DATABITS;
|
|
|
|
int64_t STOPBITS;
|
|
|
|
int64_t PARITYON;
|
|
|
|
int64_t PARITY;
|
2012-10-28 11:38:50 +00:00
|
|
|
|
|
|
|
fd = open(serial_device.c_str(), O_RDWR | O_NOCTTY | O_NDELAY);
|
2018-10-27 22:42:28 +00:00
|
|
|
if (fd == -1) return fd; // failed to open TTY port
|
2012-08-29 15:32:00 +00:00
|
|
|
|
2018-03-03 01:03:39 +00:00
|
|
|
if (fcntl(fd, F_SETFL, 0) == -1) LOG(INFO) << "Error enabling direct I/O"; // clear all flags on descriptor, enable direct I/O
|
|
|
|
tcgetattr(fd, &options); // read serial port options
|
2012-08-29 15:32:00 +00:00
|
|
|
|
2018-03-03 01:03:39 +00:00
|
|
|
BAUD = B9600;
|
2018-10-27 22:42:28 +00:00
|
|
|
// BAUD = B38400;
|
2012-08-29 15:32:00 +00:00
|
|
|
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
|
2018-10-27 22:42:28 +00:00
|
|
|
// options.c_cflag |= (CLOCAL | CREAD | CS8);
|
2012-08-29 15:32:00 +00:00
|
|
|
options.c_iflag = IGNPAR;
|
|
|
|
|
|
|
|
// set the new port options
|
|
|
|
tcsetattr(fd, TCSANOW, &options);
|
|
|
|
return fd;
|
2012-08-28 17:14:18 +00:00
|
|
|
}
|
|
|
|
|
2012-10-28 11:38:50 +00:00
|
|
|
|
2018-03-03 01:03:39 +00:00
|
|
|
void Nmea_Printer::close_serial()
|
2012-08-29 15:32:00 +00:00
|
|
|
{
|
2012-10-28 11:38:50 +00:00
|
|
|
if (nmea_dev_descriptor != -1)
|
|
|
|
{
|
|
|
|
close(nmea_dev_descriptor);
|
|
|
|
}
|
2012-08-29 15:32:00 +00:00
|
|
|
}
|
2012-08-28 17:14:18 +00:00
|
|
|
|
2012-10-28 11:38:50 +00:00
|
|
|
|
2018-05-07 07:13:45 +00:00
|
|
|
bool Nmea_Printer::Print_Nmea_Line(const std::shared_ptr<rtklib_solver>& pvt_data, bool print_average_values)
|
2012-08-28 17:14:18 +00:00
|
|
|
{
|
2012-10-28 11:38:50 +00:00
|
|
|
std::string GPRMC;
|
|
|
|
std::string GPGGA;
|
|
|
|
std::string GPGSA;
|
|
|
|
std::string GPGSV;
|
|
|
|
|
|
|
|
// set the new PVT data
|
|
|
|
d_PVT_data = pvt_data;
|
2015-11-25 13:03:59 +00:00
|
|
|
print_avg_pos = print_average_values;
|
2012-10-28 11:38:50 +00:00
|
|
|
|
|
|
|
// generate the NMEA sentences
|
|
|
|
|
2018-10-27 22:42:28 +00:00
|
|
|
// GPRMC
|
2012-10-28 11:38:50 +00:00
|
|
|
GPRMC = get_GPRMC();
|
2018-10-27 22:42:28 +00:00
|
|
|
// GPGGA (Global Positioning System Fixed Data)
|
2012-10-28 11:38:50 +00:00
|
|
|
GPGGA = get_GPGGA();
|
2018-10-27 22:42:28 +00:00
|
|
|
// GPGSA
|
2012-10-28 11:38:50 +00:00
|
|
|
GPGSA = get_GPGSA();
|
2018-10-27 22:42:28 +00:00
|
|
|
// GPGSV
|
2012-10-28 11:38:50 +00:00
|
|
|
GPGSV = get_GPGSV();
|
|
|
|
|
|
|
|
// write to log file
|
2018-10-27 22:42:28 +00:00
|
|
|
if (d_flag_nmea_output_file)
|
2018-03-03 01:03:39 +00:00
|
|
|
{
|
2018-10-27 22:42:28 +00:00
|
|
|
try
|
|
|
|
{
|
|
|
|
// GPRMC
|
|
|
|
nmea_file_descriptor << GPRMC;
|
|
|
|
// GPGGA (Global Positioning System Fixed Data)
|
|
|
|
nmea_file_descriptor << GPGGA;
|
|
|
|
// GPGSA
|
|
|
|
nmea_file_descriptor << GPGSA;
|
|
|
|
// GPGSV
|
|
|
|
nmea_file_descriptor << GPGSV;
|
|
|
|
}
|
|
|
|
catch (const std::exception& ex)
|
|
|
|
{
|
|
|
|
DLOG(INFO) << "NMEA printer can not write on output file" << nmea_filename.c_str();
|
|
|
|
}
|
2018-03-03 01:03:39 +00:00
|
|
|
}
|
2012-08-28 17:14:18 +00:00
|
|
|
|
2018-10-27 22:42:28 +00:00
|
|
|
// write to serial device
|
2018-03-03 01:03:39 +00:00
|
|
|
if (nmea_dev_descriptor != -1)
|
2012-10-28 11:38:50 +00:00
|
|
|
{
|
2018-03-03 01:03:39 +00:00
|
|
|
if (write(nmea_dev_descriptor, GPRMC.c_str(), GPRMC.length()) == -1)
|
2015-11-24 16:57:05 +00:00
|
|
|
{
|
|
|
|
DLOG(INFO) << "NMEA printer cannot write on serial device" << nmea_devname.c_str();
|
|
|
|
return false;
|
|
|
|
}
|
2018-03-03 01:03:39 +00:00
|
|
|
if (write(nmea_dev_descriptor, GPGGA.c_str(), GPGGA.length()) == -1)
|
2015-11-24 16:57:05 +00:00
|
|
|
{
|
|
|
|
DLOG(INFO) << "NMEA printer cannot write on serial device" << nmea_devname.c_str();
|
|
|
|
return false;
|
|
|
|
}
|
2018-03-03 01:03:39 +00:00
|
|
|
if (write(nmea_dev_descriptor, GPGSA.c_str(), GPGSA.length()) == -1)
|
2015-11-24 16:57:05 +00:00
|
|
|
{
|
|
|
|
DLOG(INFO) << "NMEA printer cannot write on serial device" << nmea_devname.c_str();
|
|
|
|
return false;
|
|
|
|
}
|
2018-03-03 01:03:39 +00:00
|
|
|
if (write(nmea_dev_descriptor, GPGSV.c_str(), GPGSV.length()) == -1)
|
2015-11-24 16:57:05 +00:00
|
|
|
{
|
|
|
|
DLOG(INFO) << "NMEA printer cannot write on serial device" << nmea_devname.c_str();
|
|
|
|
return false;
|
|
|
|
}
|
2012-10-28 11:38:50 +00:00
|
|
|
}
|
|
|
|
return true;
|
2012-08-28 17:14:18 +00:00
|
|
|
}
|
|
|
|
|
2012-10-28 11:38:50 +00:00
|
|
|
|
|
|
|
char Nmea_Printer::checkSum(std::string sentence)
|
|
|
|
{
|
|
|
|
char check = 0;
|
|
|
|
// iterate over the string, XOR each byte with the total sum:
|
|
|
|
for (unsigned int c = 0; c < sentence.length(); c++)
|
|
|
|
{
|
|
|
|
check = char(check ^ sentence.at(c));
|
|
|
|
}
|
|
|
|
// return the result
|
|
|
|
return check;
|
2012-08-28 17:14:18 +00:00
|
|
|
}
|
|
|
|
|
2012-10-28 11:38:50 +00:00
|
|
|
|
2012-08-28 17:14:18 +00:00
|
|
|
std::string Nmea_Printer::latitude_to_hm(double lat)
|
|
|
|
{
|
2012-10-28 11:38:50 +00:00
|
|
|
bool north;
|
2012-08-28 17:14:18 +00:00
|
|
|
if (lat < 0.0)
|
2012-10-28 11:38:50 +00:00
|
|
|
{
|
|
|
|
north = false;
|
2018-03-03 01:03:39 +00:00
|
|
|
lat = -lat;
|
2012-10-28 11:38:50 +00:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
north = true;
|
|
|
|
}
|
2012-08-28 17:14:18 +00:00
|
|
|
|
2014-09-12 18:23:39 +00:00
|
|
|
int deg = static_cast<int>(lat);
|
|
|
|
double mins = lat - static_cast<double>(deg);
|
2018-03-03 01:03:39 +00:00
|
|
|
mins *= 60.0;
|
2012-08-28 17:14:18 +00:00
|
|
|
std::ostringstream out_string;
|
|
|
|
out_string.setf(std::ios::fixed, std::ios::floatfield);
|
|
|
|
out_string.fill('0');
|
|
|
|
out_string.width(2);
|
|
|
|
out_string << deg;
|
2017-08-25 09:42:02 +00:00
|
|
|
out_string.width(2);
|
|
|
|
out_string << static_cast<int>(mins) << ".";
|
|
|
|
out_string.width(4);
|
|
|
|
out_string << static_cast<int>((mins - static_cast<double>(static_cast<int>(mins))) * 1e4);
|
2012-08-28 17:14:18 +00:00
|
|
|
|
2012-10-28 11:38:50 +00:00
|
|
|
if (north == true)
|
|
|
|
{
|
|
|
|
out_string << ",N";
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
out_string << ",S";
|
|
|
|
}
|
2012-08-28 17:14:18 +00:00
|
|
|
return out_string.str();
|
|
|
|
}
|
|
|
|
|
2012-10-28 11:38:50 +00:00
|
|
|
|
2012-08-28 17:14:18 +00:00
|
|
|
std::string Nmea_Printer::longitude_to_hm(double longitude)
|
|
|
|
{
|
2012-10-28 11:38:50 +00:00
|
|
|
bool east;
|
2012-08-28 17:14:18 +00:00
|
|
|
if (longitude < 0.0)
|
2012-10-28 11:38:50 +00:00
|
|
|
{
|
|
|
|
east = false;
|
2018-03-03 01:03:39 +00:00
|
|
|
longitude = -longitude;
|
2012-10-28 11:38:50 +00:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
east = true;
|
|
|
|
}
|
2014-09-12 16:27:19 +00:00
|
|
|
int deg = static_cast<int>(longitude);
|
|
|
|
double mins = longitude - static_cast<double>(deg);
|
2018-03-03 01:03:39 +00:00
|
|
|
mins *= 60.0;
|
2012-08-28 17:14:18 +00:00
|
|
|
std::ostringstream out_string;
|
|
|
|
out_string.setf(std::ios::fixed, std::ios::floatfield);
|
|
|
|
out_string.width(3);
|
|
|
|
out_string.fill('0');
|
|
|
|
out_string << deg;
|
2017-08-25 09:42:02 +00:00
|
|
|
out_string.width(2);
|
|
|
|
out_string << static_cast<int>(mins) << ".";
|
|
|
|
out_string.width(4);
|
|
|
|
out_string << static_cast<int>((mins - static_cast<double>(static_cast<int>(mins))) * 1e4);
|
2012-08-28 17:14:18 +00:00
|
|
|
|
2014-09-12 18:23:39 +00:00
|
|
|
if (east == true)
|
2012-10-28 11:38:50 +00:00
|
|
|
{
|
|
|
|
out_string << ",E";
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
out_string << ",W";
|
|
|
|
}
|
2012-08-28 17:14:18 +00:00
|
|
|
return out_string.str();
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
std::string Nmea_Printer::get_UTC_NMEA_time(boost::posix_time::ptime d_position_UTC_time)
|
|
|
|
{
|
2018-10-27 22:42:28 +00:00
|
|
|
// UTC Time: hhmmss.sss
|
2012-10-28 11:38:50 +00:00
|
|
|
std::stringstream sentence_str;
|
2012-08-28 17:14:18 +00:00
|
|
|
|
2012-10-28 11:38:50 +00:00
|
|
|
boost::posix_time::time_duration td = d_position_UTC_time.time_of_day();
|
|
|
|
int utc_hours;
|
|
|
|
int utc_mins;
|
|
|
|
int utc_seconds;
|
|
|
|
int utc_milliseconds;
|
2012-08-28 17:14:18 +00:00
|
|
|
|
2012-10-28 11:38:50 +00:00
|
|
|
utc_hours = td.hours();
|
|
|
|
utc_mins = td.minutes();
|
|
|
|
utc_seconds = td.seconds();
|
2018-03-03 01:03:39 +00:00
|
|
|
utc_milliseconds = td.total_milliseconds() - td.total_seconds() * 1000;
|
2012-08-28 17:14:18 +00:00
|
|
|
|
2018-03-03 01:03:39 +00:00
|
|
|
if (utc_hours < 10) sentence_str << "0"; // two digits for hours
|
2012-08-28 17:14:18 +00:00
|
|
|
sentence_str << utc_hours;
|
|
|
|
|
2018-03-03 01:03:39 +00:00
|
|
|
if (utc_mins < 10) sentence_str << "0"; // two digits for minutes
|
2012-08-28 17:14:18 +00:00
|
|
|
sentence_str << utc_mins;
|
|
|
|
|
2018-03-03 01:03:39 +00:00
|
|
|
if (utc_seconds < 10) sentence_str << "0"; // two digits for seconds
|
2012-08-28 17:14:18 +00:00
|
|
|
sentence_str << utc_seconds;
|
|
|
|
|
|
|
|
if (utc_milliseconds < 10)
|
2012-10-28 11:38:50 +00:00
|
|
|
{
|
2018-03-03 01:03:39 +00:00
|
|
|
sentence_str << ".00"; // three digits for ms
|
2012-10-28 11:38:50 +00:00
|
|
|
sentence_str << utc_milliseconds;
|
|
|
|
}
|
2012-08-28 17:14:18 +00:00
|
|
|
else if (utc_milliseconds < 100)
|
2012-10-28 11:38:50 +00:00
|
|
|
{
|
2018-03-03 01:03:39 +00:00
|
|
|
sentence_str << ".0"; // three digits for ms
|
2012-10-28 11:38:50 +00:00
|
|
|
sentence_str << utc_milliseconds;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2018-03-03 01:03:39 +00:00
|
|
|
sentence_str << "."; // three digits for ms
|
2012-10-28 11:38:50 +00:00
|
|
|
sentence_str << utc_milliseconds;
|
|
|
|
}
|
2012-08-28 17:14:18 +00:00
|
|
|
return sentence_str.str();
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2012-10-28 11:38:50 +00:00
|
|
|
std::string Nmea_Printer::get_GPRMC()
|
|
|
|
{
|
|
|
|
// Sample -> $GPRMC,161229.487,A,3723.2475,N,12158.3416,W,0.13,309.62,120598,*10
|
2017-08-16 10:45:00 +00:00
|
|
|
bool valid_fix = d_PVT_data->is_valid_position();
|
2012-08-28 17:14:18 +00:00
|
|
|
|
2012-10-28 11:38:50 +00:00
|
|
|
// ToDo: Compute speed and course over ground
|
|
|
|
double speed_over_ground_knots = 0;
|
|
|
|
double course_over_ground_deg = 0;
|
2012-08-28 17:14:18 +00:00
|
|
|
|
2018-10-27 22:42:28 +00:00
|
|
|
// boost::posix_time::ptime d_position_UTC_time=boost::posix_time::microsec_clock::universal_time();
|
2012-08-28 17:14:18 +00:00
|
|
|
|
2012-10-28 11:38:50 +00:00
|
|
|
std::stringstream sentence_str;
|
2012-08-28 17:14:18 +00:00
|
|
|
|
2018-10-27 22:42:28 +00:00
|
|
|
// GPRMC (RMC-Recommended,Minimum Specific GNSS Data)
|
2012-10-28 11:38:50 +00:00
|
|
|
std::string sentence_header;
|
|
|
|
sentence_header = "$GPRMC,";
|
|
|
|
sentence_str << sentence_header;
|
2012-08-28 17:14:18 +00:00
|
|
|
|
2018-10-27 22:42:28 +00:00
|
|
|
// UTC Time: hhmmss.sss
|
2017-08-16 10:45:00 +00:00
|
|
|
sentence_str << get_UTC_NMEA_time(d_PVT_data->get_position_UTC_time());
|
2012-08-28 17:14:18 +00:00
|
|
|
|
2018-10-27 22:42:28 +00:00
|
|
|
// Status: A: data valid, V: data NOT valid
|
2012-10-28 11:38:50 +00:00
|
|
|
if (valid_fix == true)
|
|
|
|
{
|
|
|
|
sentence_str << ",A";
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
sentence_str << ",V";
|
|
|
|
};
|
2012-08-28 17:14:18 +00:00
|
|
|
|
2015-11-25 13:03:59 +00:00
|
|
|
if (print_avg_pos == true)
|
2012-10-28 11:38:50 +00:00
|
|
|
{
|
|
|
|
// Latitude ddmm.mmmm,(N or S)
|
2017-08-16 10:45:00 +00:00
|
|
|
sentence_str << "," << latitude_to_hm(d_PVT_data->get_avg_latitude());
|
2012-10-28 11:38:50 +00:00
|
|
|
// longitude dddmm.mmmm,(E or W)
|
2017-08-16 10:45:00 +00:00
|
|
|
sentence_str << "," << longitude_to_hm(d_PVT_data->get_avg_longitude());
|
2012-10-28 11:38:50 +00:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
// Latitude ddmm.mmmm,(N or S)
|
2017-08-16 10:45:00 +00:00
|
|
|
sentence_str << "," << latitude_to_hm(d_PVT_data->get_latitude());
|
2012-10-28 11:38:50 +00:00
|
|
|
// longitude dddmm.mmmm,(E or W)
|
2017-08-16 10:45:00 +00:00
|
|
|
sentence_str << "," << longitude_to_hm(d_PVT_data->get_longitude());
|
2012-10-28 11:38:50 +00:00
|
|
|
}
|
2012-08-28 17:14:18 +00:00
|
|
|
|
2018-10-27 22:42:28 +00:00
|
|
|
// Speed over ground (knots)
|
2012-10-28 11:38:50 +00:00
|
|
|
sentence_str << ",";
|
2012-08-28 17:14:18 +00:00
|
|
|
sentence_str.setf(std::ios::fixed, std::ios::floatfield);
|
|
|
|
sentence_str.precision(2);
|
|
|
|
sentence_str << speed_over_ground_knots;
|
|
|
|
|
2018-10-27 22:42:28 +00:00
|
|
|
// course over ground (degrees)
|
2012-10-28 11:38:50 +00:00
|
|
|
sentence_str << ",";
|
2012-08-28 17:14:18 +00:00
|
|
|
sentence_str.setf(std::ios::fixed, std::ios::floatfield);
|
|
|
|
sentence_str.precision(2);
|
|
|
|
sentence_str << course_over_ground_deg;
|
|
|
|
|
|
|
|
// Date ddmmyy
|
2017-08-16 10:45:00 +00:00
|
|
|
boost::gregorian::date sentence_date = d_PVT_data->get_position_UTC_time().date();
|
2012-10-28 11:38:50 +00:00
|
|
|
unsigned int year = sentence_date.year();
|
|
|
|
unsigned int day = sentence_date.day();
|
|
|
|
unsigned int month = sentence_date.month();
|
2012-08-28 17:14:18 +00:00
|
|
|
|
2012-10-28 11:38:50 +00:00
|
|
|
sentence_str << ",";
|
2012-08-28 17:14:18 +00:00
|
|
|
sentence_str.width(2);
|
|
|
|
sentence_str.fill('0');
|
2012-10-28 11:38:50 +00:00
|
|
|
sentence_str << day;
|
2012-08-28 17:14:18 +00:00
|
|
|
sentence_str.width(2);
|
|
|
|
sentence_str.fill('0');
|
2012-10-28 11:38:50 +00:00
|
|
|
sentence_str << month;
|
2012-08-28 17:14:18 +00:00
|
|
|
|
|
|
|
std::stringstream year_strs;
|
2012-10-28 11:38:50 +00:00
|
|
|
year_strs << std::dec << year;
|
|
|
|
sentence_str << std::dec << year_strs.str().substr(2);
|
2012-08-28 17:14:18 +00:00
|
|
|
|
2018-10-27 22:42:28 +00:00
|
|
|
// Magnetic Variation (degrees)
|
2012-08-28 17:14:18 +00:00
|
|
|
// ToDo: Implement magnetic compass
|
2012-10-28 11:38:50 +00:00
|
|
|
sentence_str << ",";
|
2012-08-28 17:14:18 +00:00
|
|
|
|
2018-10-27 22:42:28 +00:00
|
|
|
// Magnetic Variation (E or W)
|
2012-08-28 17:14:18 +00:00
|
|
|
// ToDo: Implement magnetic compass
|
2012-10-28 11:38:50 +00:00
|
|
|
sentence_str << ",";
|
2012-08-28 17:14:18 +00:00
|
|
|
|
|
|
|
// Checksum
|
|
|
|
char checksum;
|
|
|
|
std::string tmpstr;
|
2012-10-28 11:38:50 +00:00
|
|
|
tmpstr = sentence_str.str();
|
2012-08-28 17:14:18 +00:00
|
|
|
checksum = checkSum(tmpstr.substr(1));
|
2012-10-28 11:38:50 +00:00
|
|
|
sentence_str << "*";
|
2012-08-28 17:14:18 +00:00
|
|
|
sentence_str.width(2);
|
|
|
|
sentence_str.fill('0');
|
2014-09-12 16:27:19 +00:00
|
|
|
sentence_str << std::hex << static_cast<int>(checksum);
|
2012-08-28 17:14:18 +00:00
|
|
|
|
|
|
|
// end NMEA sentence
|
2012-10-28 11:38:50 +00:00
|
|
|
sentence_str << "\r\n";
|
2012-08-28 17:14:18 +00:00
|
|
|
return sentence_str.str();
|
|
|
|
}
|
|
|
|
|
2012-10-28 11:38:50 +00:00
|
|
|
|
2012-08-28 17:14:18 +00:00
|
|
|
std::string Nmea_Printer::get_GPGSA()
|
|
|
|
{
|
2018-10-27 22:42:28 +00:00
|
|
|
// $GPGSA,A,3,07,02,26,27,09,04,15, , , , , ,1.8,1.0,1.5*33
|
2012-10-28 11:38:50 +00:00
|
|
|
// GSA-GNSS DOP and Active Satellites
|
2017-08-16 10:45:00 +00:00
|
|
|
bool valid_fix = d_PVT_data->is_valid_position();
|
|
|
|
int n_sats_used = d_PVT_data->get_num_valid_observations();
|
2018-05-07 07:13:45 +00:00
|
|
|
double pdop = d_PVT_data->get_pdop();
|
|
|
|
double hdop = d_PVT_data->get_hdop();
|
|
|
|
double vdop = d_PVT_data->get_vdop();
|
2012-10-28 11:38:50 +00:00
|
|
|
|
|
|
|
std::stringstream sentence_str;
|
|
|
|
std::string sentence_header;
|
|
|
|
sentence_header = "$GPGSA,";
|
|
|
|
sentence_str << sentence_header;
|
|
|
|
|
|
|
|
// mode1:
|
|
|
|
// (M) Manual-forced to operate in 2D or 3D mode
|
|
|
|
// (A) Automatic-allowed to automatically switch 2D/3D
|
|
|
|
std::string mode1 = "M";
|
|
|
|
sentence_str << mode1;
|
|
|
|
|
|
|
|
// mode2:
|
|
|
|
// 1 fix not available
|
|
|
|
// 2 fix 2D
|
|
|
|
// 3 fix 3D
|
2018-03-03 01:03:39 +00:00
|
|
|
if (valid_fix == true)
|
2012-10-28 11:38:50 +00:00
|
|
|
{
|
|
|
|
sentence_str << ",3";
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
sentence_str << ",1";
|
|
|
|
};
|
|
|
|
|
|
|
|
// Used satellites
|
2018-03-03 01:03:39 +00:00
|
|
|
for (int i = 0; i < 12; i++)
|
2012-10-28 11:38:50 +00:00
|
|
|
{
|
|
|
|
sentence_str << ",";
|
|
|
|
if (i < n_sats_used)
|
|
|
|
{
|
|
|
|
sentence_str.width(2);
|
|
|
|
sentence_str.fill('0');
|
2017-08-16 10:45:00 +00:00
|
|
|
sentence_str << d_PVT_data->get_visible_satellites_ID(i);
|
2012-10-28 11:38:50 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// PDOP
|
|
|
|
sentence_str << ",";
|
2012-08-28 17:14:18 +00:00
|
|
|
sentence_str.setf(std::ios::fixed, std::ios::floatfield);
|
|
|
|
sentence_str.width(2);
|
|
|
|
sentence_str.precision(1);
|
|
|
|
sentence_str.fill('0');
|
|
|
|
sentence_str << pdop;
|
2018-10-27 22:42:28 +00:00
|
|
|
// HDOP
|
2018-03-03 01:03:39 +00:00
|
|
|
sentence_str << ",";
|
2012-08-28 17:14:18 +00:00
|
|
|
sentence_str.setf(std::ios::fixed, std::ios::floatfield);
|
|
|
|
sentence_str.width(2);
|
|
|
|
sentence_str.precision(1);
|
|
|
|
sentence_str.fill('0');
|
|
|
|
sentence_str << hdop;
|
2018-10-27 22:42:28 +00:00
|
|
|
// VDOP
|
2012-10-28 11:38:50 +00:00
|
|
|
sentence_str << ",";
|
2012-08-28 17:14:18 +00:00
|
|
|
sentence_str.setf(std::ios::fixed, std::ios::floatfield);
|
|
|
|
sentence_str.width(2);
|
|
|
|
sentence_str.precision(1);
|
|
|
|
sentence_str.fill('0');
|
|
|
|
sentence_str << vdop;
|
|
|
|
|
|
|
|
// Checksum
|
|
|
|
char checksum;
|
|
|
|
std::string tmpstr;
|
2012-10-28 11:38:50 +00:00
|
|
|
tmpstr = sentence_str.str();
|
2012-08-28 17:14:18 +00:00
|
|
|
checksum = checkSum(tmpstr.substr(1));
|
2012-10-28 11:38:50 +00:00
|
|
|
sentence_str << "*";
|
2012-08-28 17:14:18 +00:00
|
|
|
sentence_str.width(2);
|
|
|
|
sentence_str.fill('0');
|
2014-09-12 16:27:19 +00:00
|
|
|
sentence_str << std::hex << static_cast<int>(checksum);
|
2012-08-28 17:14:18 +00:00
|
|
|
|
|
|
|
// end NMEA sentence
|
2013-07-04 13:47:40 +00:00
|
|
|
sentence_str << "\r\n";
|
2012-10-28 11:38:50 +00:00
|
|
|
return sentence_str.str();
|
2012-08-28 17:14:18 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2012-10-28 11:38:50 +00:00
|
|
|
std::string Nmea_Printer::get_GPGSV()
|
|
|
|
{
|
|
|
|
// GSV-GNSS Satellites in View
|
2018-11-05 14:39:56 +00:00
|
|
|
// $GPGSV,2,1,07,07,79,048,42,02,51,062,43,26,36,256,42,27,27,138,42*71
|
2012-10-28 11:38:50 +00:00
|
|
|
// Notice that NMEA 2.1 only supports 12 channels
|
|
|
|
std::stringstream sentence_str;
|
2018-11-05 14:39:56 +00:00
|
|
|
unsigned char buff[200];
|
|
|
|
outnmea_gsv(buff, &d_PVT_data->pvt_sol, *d_PVT_data->pvt_ssat);
|
|
|
|
sentence_str << buff;
|
2012-10-28 11:38:50 +00:00
|
|
|
return sentence_str.str();
|
|
|
|
}
|
2012-08-28 17:14:18 +00:00
|
|
|
|
|
|
|
|
2012-10-28 11:38:50 +00:00
|
|
|
std::string Nmea_Printer::get_GPGGA()
|
|
|
|
{
|
2018-10-27 22:42:28 +00:00
|
|
|
// boost::posix_time::ptime d_position_UTC_time=boost::posix_time::microsec_clock::universal_time();
|
2017-08-16 10:45:00 +00:00
|
|
|
bool valid_fix = d_PVT_data->is_valid_position();
|
2018-03-03 01:03:39 +00:00
|
|
|
int n_channels = d_PVT_data->get_num_valid_observations(); //d_nchannels
|
2018-05-07 07:13:45 +00:00
|
|
|
double hdop = d_PVT_data->get_hdop();
|
2012-10-28 11:38:50 +00:00
|
|
|
double MSL_altitude;
|
2012-08-28 17:14:18 +00:00
|
|
|
|
2017-08-16 10:45:00 +00:00
|
|
|
if (d_PVT_data->is_averaging() == true)
|
2012-10-28 11:38:50 +00:00
|
|
|
{
|
2017-08-16 10:45:00 +00:00
|
|
|
MSL_altitude = d_PVT_data->get_avg_height();
|
2012-10-28 11:38:50 +00:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2017-08-16 10:45:00 +00:00
|
|
|
MSL_altitude = d_PVT_data->get_height();
|
2012-10-28 11:38:50 +00:00
|
|
|
}
|
2012-08-28 17:14:18 +00:00
|
|
|
|
2012-10-28 11:38:50 +00:00
|
|
|
std::stringstream sentence_str;
|
2012-08-28 17:14:18 +00:00
|
|
|
|
2018-10-27 22:42:28 +00:00
|
|
|
// GPGGA (Global Positioning System Fixed Data)
|
2012-10-28 11:38:50 +00:00
|
|
|
std::string sentence_header;
|
|
|
|
sentence_header = "$GPGGA,";
|
|
|
|
sentence_str << sentence_header;
|
2012-08-28 17:14:18 +00:00
|
|
|
|
2018-10-27 22:42:28 +00:00
|
|
|
// UTC Time: hhmmss.sss
|
2017-08-16 10:45:00 +00:00
|
|
|
sentence_str << get_UTC_NMEA_time(d_PVT_data->get_position_UTC_time());
|
2012-08-28 17:14:18 +00:00
|
|
|
|
2017-08-16 10:45:00 +00:00
|
|
|
if (d_PVT_data->is_averaging() == true)
|
2012-10-28 11:38:50 +00:00
|
|
|
{
|
|
|
|
// Latitude ddmm.mmmm,(N or S)
|
2017-08-16 10:45:00 +00:00
|
|
|
sentence_str << "," << latitude_to_hm(d_PVT_data->get_avg_latitude());
|
2012-10-28 11:38:50 +00:00
|
|
|
// longitude dddmm.mmmm,(E or W)
|
2017-08-16 10:45:00 +00:00
|
|
|
sentence_str << "," << longitude_to_hm(d_PVT_data->get_avg_longitude());
|
2012-10-28 11:38:50 +00:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
// Latitude ddmm.mmmm,(N or S)
|
2017-08-16 10:45:00 +00:00
|
|
|
sentence_str << "," << latitude_to_hm(d_PVT_data->get_latitude());
|
2012-10-28 11:38:50 +00:00
|
|
|
// longitude dddmm.mmmm,(E or W)
|
2017-08-16 10:45:00 +00:00
|
|
|
sentence_str << "," << longitude_to_hm(d_PVT_data->get_longitude());
|
2012-10-28 11:38:50 +00:00
|
|
|
}
|
2012-08-28 17:14:18 +00:00
|
|
|
|
|
|
|
// Position fix indicator
|
|
|
|
// 0 - Fix not available or invalid
|
|
|
|
// 1 - GPS SPS Mode, fix valid
|
|
|
|
// 2 - Differential GPS, SPS Mode, fix valid
|
|
|
|
// 3-5 - Not supported
|
|
|
|
// 6 - Dead Reckoning Mode, fix valid
|
|
|
|
// ToDo: Update PVT module to identify the fix mode
|
|
|
|
|
2012-10-28 11:38:50 +00:00
|
|
|
if (valid_fix == true)
|
|
|
|
{
|
|
|
|
sentence_str << ",1";
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
sentence_str << ",0";
|
|
|
|
}
|
2012-08-28 17:14:18 +00:00
|
|
|
|
|
|
|
// Number of satellites used in PVT
|
2012-10-28 11:38:50 +00:00
|
|
|
sentence_str << ",";
|
|
|
|
if (n_channels < 10)
|
|
|
|
{
|
|
|
|
sentence_str << '0' << n_channels;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
sentence_str << n_channels;
|
|
|
|
}
|
2012-08-28 17:14:18 +00:00
|
|
|
|
|
|
|
// HDOP
|
2012-10-28 11:38:50 +00:00
|
|
|
sentence_str << ",";
|
2012-08-28 17:14:18 +00:00
|
|
|
sentence_str.setf(std::ios::fixed, std::ios::floatfield);
|
|
|
|
sentence_str.width(2);
|
|
|
|
sentence_str.precision(1);
|
|
|
|
sentence_str.fill('0');
|
|
|
|
sentence_str << hdop;
|
|
|
|
|
|
|
|
// MSL Altitude
|
2012-10-28 11:38:50 +00:00
|
|
|
sentence_str << ",";
|
2012-08-28 17:14:18 +00:00
|
|
|
sentence_str.precision(1);
|
2012-10-28 11:38:50 +00:00
|
|
|
sentence_str << MSL_altitude;
|
|
|
|
sentence_str << ",M";
|
2012-08-28 17:14:18 +00:00
|
|
|
|
|
|
|
// Geoid-to-ellipsoid separation. Ellipsoid altitude = MSL Altitude + Geoid Separation.
|
|
|
|
// ToDo: Compute this value
|
2012-10-28 11:38:50 +00:00
|
|
|
sentence_str << ",";
|
|
|
|
sentence_str << "0.0";
|
|
|
|
sentence_str << ",M";
|
2012-08-28 17:14:18 +00:00
|
|
|
|
|
|
|
// Age of Diff. Corr. (Seconds) Null fields when DGPS is not used
|
|
|
|
// Diff. Ref. Station ID (0000)
|
|
|
|
// ToDo: Implement this fields for Differential GPS
|
2012-10-28 11:38:50 +00:00
|
|
|
sentence_str << ",";
|
|
|
|
sentence_str << "0.0,0000";
|
2012-08-28 17:14:18 +00:00
|
|
|
|
|
|
|
// Checksum
|
|
|
|
char checksum;
|
|
|
|
std::string tmpstr;
|
2012-10-28 11:38:50 +00:00
|
|
|
tmpstr = sentence_str.str();
|
2012-08-28 17:14:18 +00:00
|
|
|
checksum = checkSum(tmpstr.substr(1));
|
2012-10-28 11:38:50 +00:00
|
|
|
sentence_str << "*";
|
2012-08-28 17:14:18 +00:00
|
|
|
sentence_str.width(2);
|
|
|
|
sentence_str.fill('0');
|
2014-09-12 16:27:19 +00:00
|
|
|
sentence_str << std::hex << static_cast<int>(checksum);
|
2012-08-28 17:14:18 +00:00
|
|
|
|
|
|
|
// end NMEA sentence
|
2012-10-28 11:38:50 +00:00
|
|
|
sentence_str << "\r\n";
|
2012-08-28 17:14:18 +00:00
|
|
|
return sentence_str.str();
|
2018-10-27 22:42:28 +00:00
|
|
|
// $GPGGA,104427.591,5920.7009,N,01803.2938,E,1,05,3.3,78.2,M,23.2,M,0.0,0000*4A
|
2012-08-28 17:14:18 +00:00
|
|
|
}
|