Keep vanetza-idf in obu-firmware, so a plain clone builds the firmware
obu-firmware builds against the vanetza-idf C-ITS library, which until now came from the colleague's microbu-esp32c5 tree beside the repository and was not tracked here, so a clone of this repository could not build the firmware it ships. The library alone is now part of obu-firmware, as obu-firmware/external/vanetza-idf: their external/vanetza-idf at commit cf4b99f, unchanged (9775 files; see its PROVENANCE.md). CMake takes it from there by default; -DVANETZA_IDF_DIR still points the build elsewhere. The rest of the colleague's tree (their own VAM firmware, PKI tooling, station-link Python tools, the V2X2MAP bridge) stays out of this repository and gitignored; nothing is pushed to their repository. NOTES.md, docs/06, TODO.md and the pcap verifier's usage line point at the new location.
This commit is contained in:
@@ -0,0 +1,5 @@
|
||||
add_vanetza_component(gnss nmea.cpp)
|
||||
target_link_libraries(gnss PUBLIC Boost::date_time)
|
||||
|
||||
add_test_subdirectory(tests)
|
||||
|
||||
@@ -0,0 +1,155 @@
|
||||
#include "nmea.hpp"
|
||||
#include "wgs84point.hpp"
|
||||
#include <boost/date_time/gregorian/gregorian.hpp>
|
||||
#include <boost/date_time/posix_time/posix_time.hpp>
|
||||
#include <boost/format.hpp>
|
||||
#include <cassert>
|
||||
#include <cmath>
|
||||
#include <iomanip>
|
||||
#include <sstream>
|
||||
|
||||
namespace vanetza
|
||||
{
|
||||
namespace nmea
|
||||
{
|
||||
|
||||
using namespace vanetza::units;
|
||||
|
||||
/**
|
||||
* Print latitude data in BBBB.BBBB, b format.
|
||||
* BBBB.BBBB are degrees and minutes (ddmm.mm)
|
||||
* b is N or S
|
||||
*/
|
||||
void print_latitude(std::ostream& os, const Wgs84Point& point)
|
||||
{
|
||||
double degrees = point.lat.value();
|
||||
double minutes = std::modf(std::abs(degrees), °rees) * 60.0;
|
||||
os << boost::format("%02d%07.4f") % degrees % minutes;
|
||||
os << "," << (point.lat.value() >= 0.0 ? "N" : "S");
|
||||
}
|
||||
|
||||
/**
|
||||
* Print longitude data in LLLL.LLLL, l format.
|
||||
* LLLL.LLLL are degrees and minutes (ddmm.mm)
|
||||
* l is E or W
|
||||
*/
|
||||
void print_longitude(std::ostream& os, const Wgs84Point& point)
|
||||
{
|
||||
double degrees = point.lon.value();
|
||||
double minutes = std::modf(std::abs(degrees), °rees) * 60.0;
|
||||
os << boost::format("%02d%07.4f") % degrees % minutes;
|
||||
os << "," << (point.lon.value() >= 0.0 ? "E" : "W");
|
||||
}
|
||||
|
||||
namespace detail
|
||||
{
|
||||
|
||||
struct latitude
|
||||
{
|
||||
latitude(const Wgs84Point& p) : point(p) {}
|
||||
friend std::ostream& operator<<(std::ostream& os, const latitude& lat)
|
||||
{
|
||||
print_latitude(os, lat.point);
|
||||
return os;
|
||||
}
|
||||
|
||||
const Wgs84Point& point;
|
||||
};
|
||||
|
||||
struct longitude
|
||||
{
|
||||
longitude(const Wgs84Point& p) : point(p) {}
|
||||
friend std::ostream& operator<<(std::ostream& os, const longitude& lon)
|
||||
{
|
||||
print_longitude(os, lon.point);
|
||||
return os;
|
||||
}
|
||||
|
||||
const Wgs84Point& point;
|
||||
};
|
||||
|
||||
} // namespace detail
|
||||
|
||||
detail::latitude latitude(const Wgs84Point& p) { return detail::latitude(p); }
|
||||
detail::longitude longitude(const Wgs84Point& p) { return detail::longitude(p); }
|
||||
|
||||
/**
|
||||
* Finish NMEA sentence with *XX where XX is the calculated checksum
|
||||
* \param smsg NMEA sentence with leading $ but without trailing *XX
|
||||
* \return finished NMEA sentence
|
||||
*/
|
||||
std::string finish(std::stringstream& smsg)
|
||||
{
|
||||
std::string msg = smsg.str();
|
||||
unsigned sum = checksum(++msg.begin(), msg.end());
|
||||
msg += boost::str(boost::format("*%02X") % static_cast<unsigned>(sum));
|
||||
return msg;
|
||||
}
|
||||
|
||||
std::string gprmc(const time& ptime, const Wgs84Point& wgs84,
|
||||
NauticalVelocity ground_speed, TrueNorth heading)
|
||||
{
|
||||
/**
|
||||
* Magnetic declination for central europe is about 1 degree east (2010), see this map for reference:
|
||||
* http://upload.wikimedia.org/wikipedia/commons/d/dd/World_Magnetic_Model_Main_Field_Declination_D_2010.png
|
||||
*/
|
||||
const double magnetic_angle = 1.0;
|
||||
const char magnetic_direction = 'E';
|
||||
|
||||
std::stringstream smsg;
|
||||
smsg << std::uppercase << std::fixed;
|
||||
auto* tfacet = new boost::posix_time::time_facet("%H%M%S");
|
||||
auto* dfacet = new boost::gregorian::date_facet("%d%m%y");
|
||||
smsg.imbue(std::locale(smsg.getloc(), tfacet));
|
||||
smsg.imbue(std::locale(smsg.getloc(), dfacet));
|
||||
|
||||
smsg << "$GPRMC,";
|
||||
smsg << ptime << ","; // HHMMSS
|
||||
smsg << static_cast<char>(RMCStatus::Valid) << ",";
|
||||
smsg << latitude(wgs84) << "," << longitude(wgs84) << ",";
|
||||
smsg << std::setprecision(1) << ground_speed.value() << ","; // GG.G
|
||||
smsg << std::setprecision(1) << std::fmod(heading.value(), 360.0) << ","; // RR.R
|
||||
smsg << ptime.date() << ","; // DDMMYY
|
||||
smsg << std::setprecision(1) << magnetic_angle << "," << magnetic_direction << ","; // M.M, E/W
|
||||
smsg << static_cast<char>(FAAMode::Autonomous);
|
||||
|
||||
return finish(smsg);
|
||||
}
|
||||
|
||||
std::string gpgga(const time& ptime, const Wgs84Point& wgs84, Quality quality, Length hdop)
|
||||
{
|
||||
const unsigned satellites = 6; // Arbitrary number of used GPS satellites
|
||||
const double height = 0.0; // SUMO map is flat
|
||||
const double separation = 0.0; // Geoidal separation, can it be calculated?
|
||||
|
||||
std::stringstream smsg;
|
||||
smsg << std::uppercase << std::fixed;
|
||||
auto* facet = new boost::posix_time::time_facet("%H%M%s");
|
||||
smsg.imbue(std::locale(smsg.getloc(), facet));
|
||||
|
||||
smsg << "$GPGGA,";
|
||||
smsg << ptime << ","; // HHMMSS.ss
|
||||
smsg << latitude(wgs84) << "," << longitude(wgs84) << ",";
|
||||
smsg << static_cast<std::underlying_type<Quality>::type>(quality) << ","; // Q
|
||||
smsg << std::setw(2) << std::setfill('0') << satellites << ","; // NN
|
||||
smsg << std::setprecision(1) << hdop.value() << ","; // D.D
|
||||
smsg << std::setprecision(1) << height << ",M,"; // H.H, h
|
||||
smsg << std::setprecision(1) << separation << ",M,"; // G.G, g
|
||||
smsg << ","; // AA, RRRR (both optional)
|
||||
|
||||
return finish(smsg);
|
||||
}
|
||||
|
||||
uint8_t checksum(std::string::const_iterator begin, std::string::const_iterator end)
|
||||
{
|
||||
assert(begin <= end);
|
||||
uint8_t sum = 0;
|
||||
for (; begin != end; ++begin) {
|
||||
sum ^= *begin;
|
||||
}
|
||||
return sum;
|
||||
}
|
||||
|
||||
} // namespace nmea
|
||||
} // namespace vanetza
|
||||
|
||||
@@ -0,0 +1,58 @@
|
||||
#ifndef NMEA_HPP_EJIHQ65L
|
||||
#define NMEA_HPP_EJIHQ65L
|
||||
|
||||
#include <vanetza/units/angle.hpp>
|
||||
#include <vanetza/units/velocity.hpp>
|
||||
#include <vanetza/units/length.hpp>
|
||||
#include <boost/date_time/posix_time/posix_time_types.hpp>
|
||||
#include <cstdint>
|
||||
#include <string>
|
||||
|
||||
namespace vanetza
|
||||
{
|
||||
|
||||
// forward declaration
|
||||
struct Wgs84Point;
|
||||
|
||||
namespace nmea
|
||||
{
|
||||
typedef boost::posix_time::ptime time;
|
||||
|
||||
enum class Quality
|
||||
{
|
||||
Unavailable = 0,
|
||||
GPS = 1,
|
||||
DGPS = 2,
|
||||
PPS = 3,
|
||||
RTK = 4,
|
||||
Float_RTK = 5,
|
||||
Estimated = 6,
|
||||
Manual = 7,
|
||||
Simulation = 8
|
||||
};
|
||||
|
||||
enum class RMCStatus : char
|
||||
{
|
||||
Warning = 'V',
|
||||
Valid = 'A'
|
||||
};
|
||||
|
||||
enum class FAAMode : char
|
||||
{
|
||||
Autonomous = 'A',
|
||||
Differential = 'D',
|
||||
Estimated = 'E',
|
||||
Manual = 'M',
|
||||
Simulated = 'S',
|
||||
Invalid = 'N'
|
||||
};
|
||||
|
||||
std::string gprmc(const time&, const Wgs84Point&, units::NauticalVelocity ground, units::TrueNorth heading);
|
||||
std::string gpgga(const time&, const Wgs84Point&, Quality, units::Length hdop);
|
||||
uint8_t checksum(std::string::const_iterator, std::string::const_iterator);
|
||||
|
||||
} // namespace nmea
|
||||
} // namespace vanetza
|
||||
|
||||
#endif /* NMEA_HPP_EJIHQ65L */
|
||||
|
||||
@@ -0,0 +1,5 @@
|
||||
include(UseGTest)
|
||||
configure_gtest_directory(LINK_LIBRARIES gnss)
|
||||
|
||||
add_gtest(NMEA nmea.cpp)
|
||||
|
||||
@@ -0,0 +1,37 @@
|
||||
#include <gtest/gtest.h>
|
||||
#include <vanetza/gnss/nmea.hpp>
|
||||
#include <vanetza/gnss/wgs84point.hpp>
|
||||
#include <string>
|
||||
|
||||
using namespace vanetza;
|
||||
|
||||
TEST(NMEA, gprmc) {
|
||||
using namespace boost::posix_time;
|
||||
using namespace boost::gregorian;
|
||||
nmea::time time(date(2013, 12, 5), time_duration(10, 32, 15));
|
||||
Wgs84Point position(49.8234932 * units::degree, -12.5343 * units::degree);
|
||||
units::NauticalVelocity speed(9.358 * units::metric::knots);
|
||||
units::TrueNorth heading(273.4 * units::true_north_degrees);
|
||||
|
||||
std::string rmc = nmea::gprmc(time, position, speed, heading);
|
||||
EXPECT_EQ("$GPRMC,103215,A,4949.4096,N,1232.0580,W,9.4,273.4,051213,1.0,E,A*33", rmc);
|
||||
}
|
||||
|
||||
TEST(NMEA, gpgga) {
|
||||
using namespace boost::posix_time;
|
||||
using namespace boost::gregorian;
|
||||
nmea::time time(date(2013, 11, 30), time_duration(19, 55, 59));
|
||||
Wgs84Point position(-0.34 * units::degree, 165.39999 * units::degree);
|
||||
nmea::Quality quality = nmea::Quality::DGPS;
|
||||
units::Length hdop = 3.532 * units::si::meters;
|
||||
|
||||
std::string gga = nmea::gpgga(time, position, quality, hdop);
|
||||
EXPECT_EQ("$GPGGA,195559.000000,0020.4000,S,16523.9994,E,2,06,3.5,0.0,M,0.0,M,,*4E", gga);
|
||||
}
|
||||
|
||||
TEST(NMEA, checksum) {
|
||||
std::string s = {0, 1, 2, 3, 4, 5};
|
||||
auto c = nmea::checksum(s.begin(), s.end());
|
||||
EXPECT_EQ(c, 0x01);
|
||||
}
|
||||
|
||||
@@ -0,0 +1,20 @@
|
||||
#ifndef WGS84POINT_HPP_GAHDJKCG
|
||||
#define WGS84POINT_HPP_GAHDJKCG
|
||||
|
||||
#include <vanetza/units/angle.hpp>
|
||||
|
||||
namespace vanetza
|
||||
{
|
||||
|
||||
struct Wgs84Point
|
||||
{
|
||||
typedef units::GeoAngle angle_type;
|
||||
Wgs84Point(angle_type latitude, angle_type longitude) : lat(latitude), lon(longitude) {}
|
||||
angle_type lat;
|
||||
angle_type lon;
|
||||
};
|
||||
|
||||
} // namespace vanetza
|
||||
|
||||
#endif /* WGS84POINT_HPP_GAHDJKCG */
|
||||
|
||||
Reference in New Issue
Block a user