OpenCPN Partial API docs
Loading...
Searching...
No Matches
comm_appmsg.cpp
1/***************************************************************************
2 *
3 * Project: OpenCPN
4 * Purpose: Implement comm_appmsg.h -- Decoded application messages.
5 * Author: David Register, Alec Leamas
6 *
7 ***************************************************************************
8 * Copyright (C) 2022 by David Register, Alec Leamas *
9 * *
10 * This program is free software; you can redistribute it and/or modify *
11 * it under the terms of the GNU General Public License as published by *
12 * the Free Software Foundation; either version 2 of the License, or *
13 * (at your option) any later version. *
14 * *
15 * This program is distributed in the hope that it will be useful, *
16 * but WITHOUT ANY WARRANTY; without even the implied warranty of *
17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
18 * GNU General Public License for more details. *
19 * *
20 * You should have received a copy of the GNU General Public License *
21 * along with this program; if not, write to the *
22 * Free Software Foundation, Inc., *
23 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. *
24 **************************************************************************/
25
26// For compilers that support precompilation, includes "wx.h".
27#include <wx/wxprec.h>
28
29#ifndef WX_PRECOMP
30#include <wx/wx.h>
31#endif // precompiled headers
32
33#include <sstream>
34#include <iomanip>
35
36#include "comm_appmsg.h"
37#include "ocpn_utils.h"
38
39/* Free functions. */
40
41std::string TimeToString(const time_t t) {
42 char buff[30];
43#ifdef _MSC_VER
44 errno_t e = ctime_s(buff, sizeof(buff), &t);
45 assert(e == 0 && "Huh? ctime_s returned an error");
46 return std::string(buff);
47#else
48 const char* r = ctime_r(&t, buff);
49 assert(r != NULL && "ctime_r failed...");
50 return std::string(buff);
51#endif
52}
53
54std::string DegreesToString(double degrees) {
55 using namespace std;
56 std::stringstream buf;
57 buf << setw(2) << static_cast<int>(trunc(degrees)) << "\u00B0"
58 << static_cast<int>(trunc(degrees * 100)) % 100 << "," << setw(2)
59 << (static_cast<int>(trunc(degrees * 10000)) % 10000) % 100;
60 return buf.str();
61}
62
63double PosPartsToDegrees(float degrees, float minutes,
64 float percent_of_minute) {
65 return degrees + minutes / 60 + percent_of_minute / 6000;
66}
67
68
69/* Position implementation */
70
71Position::Position(double _lat, double _lon, Type t)
72 : lat(TypeToLat(t, _lat)), lon(TypeToLong(t, _lon)), type(t) {}
73
74Position::Position(double _lat, double _lon)
75 : lat(_lat), lon(_lon), type(LatLongToType(_lat, _lon)) {};
76
77Position::Position() : lat(0), lon(0), type(Type::Undef) {};
78
79std::string Position::to_string() const {
80 std::stringstream buf;
81 const std::string NE(TypeToStr(type));
82 auto lat_s = DegreesToString(abs(lat));
83 auto lon_s = DegreesToString(abs(lon));
84 buf << lat_s << NE[0] << " " << lon_s << NE[1];
85 return buf.str();
86}
87
88std::string Position::TypeToStr(const Type t) const {
89 switch (t) {
90 case Type::NE:
91 return "NE";
92 break;
93 case Type::NW:
94 return "NW";
95 break;
96 case Type::SE:
97 return "SE";
98 break;
99 case Type::SW:
100 return "SW";
101 break;
102 case Type::Undef:
103 return "Undefined";
104 break;
105 }
106 return "??"; // Not reached, but compiler complains.
107}
108
109Position::Type Position::LatLongToType(double lat, double lon) {
110 if (lat >= 0)
111 return lon >= 0 ? Type::NE : Type::NW;
112 else
113 return lon >= 0 ? Type::SE : Type::SW;
114}
115
116double Position::TypeToLat(Type t, double lat) {
117 return t == Type::SW || t == Type::SE ? -lat : lat;
118}
119
120double Position::TypeToLong(Type t, double lon) {
121 return t == Type::NE || t == Type::SE ? lon : -lon;
122}
123
125static double GgaPartToDouble(const std::string& s) {
126 size_t dotpos = s.find('.');
127 if (dotpos < 2) return nan("");
128 auto degrees = s.substr(0, dotpos - 2);
129 auto minutes = s.substr(dotpos - 2);
130 return std::stod(degrees) + std::stod(minutes)/60;
131
132}
133
134Position Position::ParseGGA(const std::string gga) {
135 auto parts = ocpn::split(gga.c_str(), ",");
136 if (parts.size() != 4) {
137 return Position();
138 }
139 double lat = GgaPartToDouble(parts[0]);
140 if (parts[1] == "S")
141 lat = -lat;
142 else if (parts[1] != "N")
143 lat = nan("");
144 double lon = GgaPartToDouble(parts[2]);
145 if (parts[3] == "W")
146 lon = -lon;
147 else if (parts[3] != "E")
148 lon = nan("");
149
150 return lat != nan("") && lon != nan("") ? Position(lat, lon) : Position();
151}
152
153
154/* Appmsg implementation */
155
156std::string AppMsg::TypeToString(const AppMsg::Type t) const {
157 switch (t) {
158 case AppMsg::Type::AisData:
159 return "ais-data";
160 break;
161 case AppMsg::Type::BasicNavData:
162 return "basic-nav-data";
163 break;
164 case AppMsg::Type::CustomMsg:
165 return "custom-msg";
166 break;
167 case AppMsg::Type::DataPrioNeeded:
168 return "data-prio-needed";
169 break;
170 case AppMsg::Type::GnssFix:
171 return "gnss-fix";
172 break;
173 case AppMsg::Type::GPSWatchdog:
174 return "gps-watchdog";
175 break;
176 case AppMsg::Type::Undef:
177 return "??";
178 break;
179 }
180 return "????"; // Not reached, for the compiler.
181}
GNSS Lat/Long container.
Definition: comm_appmsg.h:45
Position()
Construct a (0,0) position, type == Undef.
Definition: comm_appmsg.cpp:77
static Position ParseGGA(const std::string gga)
Parse a GGA string like "5800.588,N,01145.776,E" as present in GGA and other n0183 messages.
std::string to_string() const
Return utf string like 65°25,11N 21°12,01E.
Definition: comm_appmsg.cpp:79