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 "model/comm_appmsg.h"
37#include "model/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/* 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}
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.