OpenCPN Partial API docs
Loading...
Searching...
No Matches
comm_appmsg.cpp
Go to the documentation of this file.
1/***************************************************************************
2 * Copyright (C) 2022 by David Register *
3 * Copyright (C) 2022 Alec Leamas *
4 * *
5 * This program is free software; you can redistribute it and/or modify *
6 * it under the terms of the GNU General Public License as published by *
7 * the Free Software Foundation; either version 2 of the License, or *
8 * (at your option) any later version. *
9 * *
10 * This program is distributed in the hope that it will be useful, *
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of *
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
13 * GNU General Public License for more details. *
14 * *
15 * You should have received a copy of the GNU General Public License *
16 * along with this program; if not, see <https://www.gnu.org/licenses/>. *
17 **************************************************************************/
18
25// For compilers that support precompilation, includes "wx.h".
26#include <wx/wxprec.h>
27
28#ifndef WX_PRECOMP
29#include <wx/wx.h>
30#endif // precompiled headers
31
32#include <sstream>
33#include <iomanip>
34
35#include "model/comm_appmsg.h"
36#include "model/ocpn_utils.h"
37
38static const auto kUtfDegrees = wxString::FromUTF8(u8"\u00B0");
39
40/* Free functions. */
41
42std::string TimeToString(const time_t t) {
43 char buff[30];
44#ifdef _MSC_VER
45 errno_t e = ctime_s(buff, sizeof(buff), &t);
46 assert(e == 0 && "Huh? ctime_s returned an error");
47#else
48 const char* r = ctime_r(&t, buff);
49 assert(r != NULL && "ctime_r failed...");
50#endif
51 return std::string(buff, strlen(buff) - 1); // Drop trailing '\n'
52}
53
54std::string DegreesToString(double degrees) {
55 using namespace std;
56 std::stringstream buf;
57 buf << setw(2) << static_cast<int>(trunc(degrees)) << kUtfDegrees
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/* Position implementation */
69
70Position::Position(double _lat, double _lon, Type t)
71 : lat(TypeToLat(t, _lat)), lon(TypeToLong(t, _lon)), type(t) {}
72
73Position::Position(double _lat, double _lon)
74 : lat(_lat), lon(_lon), type(LatLongToType(_lat, _lon)) {};
75
76Position::Position() : lat(0), lon(0), type(Type::Undef) {};
77
78std::string Position::to_string() const {
79 std::stringstream buf;
80 const std::string NE(TypeToStr(type));
81 auto lat_s = DegreesToString(abs(lat));
82 auto lon_s = DegreesToString(abs(lon));
83 buf << lat_s << NE[0] << " " << lon_s << NE[1];
84 return buf.str();
85}
86
87std::string Position::TypeToStr(const Type t) const {
88 switch (t) {
89 case Type::NE:
90 return "NE";
91 break;
92 case Type::NW:
93 return "NW";
94 break;
95 case Type::SE:
96 return "SE";
97 break;
98 case Type::SW:
99 return "SW";
100 break;
101 case Type::Undef:
102 return "Undefined";
103 break;
104 }
105 return "??"; // Not reached, but compiler complains.
106}
107
108Position::Type Position::LatLongToType(double lat, double lon) {
109 if (lat >= 0)
110 return lon >= 0 ? Type::NE : Type::NW;
111 else
112 return lon >= 0 ? Type::SE : Type::SW;
113}
114
115double Position::TypeToLat(Type t, double lat) {
116 return t == Type::SW || t == Type::SE ? -lat : lat;
117}
118
119double Position::TypeToLong(Type t, double lon) {
120 return t == Type::NE || t == Type::SE ? lon : -lon;
121}
122
124static double GgaPartToDouble(const std::string& s) {
125 size_t dotpos = s.find('.');
126 if (dotpos < 2) return nan("");
127 auto degrees = s.substr(0, dotpos - 2);
128 auto minutes = s.substr(dotpos - 2);
129 return std::stod(degrees) + std::stod(minutes) / 60;
130}
131
132Position Position::ParseGGA(const std::string gga) {
133 auto parts = ocpn::split(gga.c_str(), ",");
134 if (parts.size() != 4) {
135 return Position();
136 }
137 double lat = GgaPartToDouble(parts[0]);
138 if (parts[1] == "S")
139 lat = -lat;
140 else if (parts[1] != "N")
141 lat = nan("");
142 double lon = GgaPartToDouble(parts[2]);
143 if (parts[3] == "W")
144 lon = -lon;
145 else if (parts[3] != "E")
146 lon = nan("");
147
148 return lat != nan("") && lon != nan("") ? Position(lat, lon) : Position();
149}
150
151/* Appmsg implementation */
152
153std::string AppMsg::TypeToString(const AppMsg::Type t) const {
154 switch (t) {
155 case AppMsg::Type::AisData:
156 return "ais-data";
157 break;
158 case AppMsg::Type::BasicNavData:
159 return "basic-nav-data";
160 break;
161 case AppMsg::Type::CustomMsg:
162 return "custom-msg";
163 break;
164 case AppMsg::Type::DataPrioNeeded:
165 return "data-prio-needed";
166 break;
167 case AppMsg::Type::GnssFix:
168 return "gnss-fix";
169 break;
170 case AppMsg::Type::GPSWatchdog:
171 return "gps-watchdog";
172 break;
173 case AppMsg::Type::Undef:
174 return "??";
175 break;
176 }
177 return "????"; // Not reached, for the compiler.
178}
179
180std::string BasicNavDataMsg::to_string() const {
181 std::stringstream ss;
182 ss << AppMsg::to_string() << " pos: " << pos.to_string() << " sog: " << sog
183 << " cog: " << cog << " var: " << var << " hdt: " << hdt
184 << " vflag: " << vflag << " set_time: " << TimeToString(set_time.tv_sec);
185 return ss.str();
186}
187std::string AisData::to_string() const {
188 std::stringstream ss;
189 ss << TimeToString(time) << " " << pos.to_string() << " sog: " << sog
190 << " cog: " << cog << " heading: " << heading
191 << " rate of turn: " << rate_of_turn << "type: 0x" << std::hex << type
192 << " name " << name << " callsign " << callsign << " dest: " << dest
193 << " length " << std::dec << length << " beam: " << beam
194 << " draft: " << draft << " status: 0x" << std::hex << status;
195 return ss.str();
196}
Position()
Construct a (0,0) position, type == Undef.
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.
Decoded messages definitions.
std::vector< std::string > split(const char *token_string, const std::string &delimiter)
Return vector of items in s separated by delimiter.
Miscellaneous utilities, many of which string related.