OpenCPN Partial API docs
Loading...
Searching...
No Matches
comm_drv_n0183.cpp
1/***************************************************************************
2 *
3 * Project: OpenCPN
4 * Purpose: Implement the comm_drv_n0183.h -- Nmea0183 driver base
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
32
34
36static bool Is0183ChecksumOk(const std::string& sentence) {
37 const size_t cs_start = sentence.find('*');
38 if (cs_start == std::string::npos || cs_start > sentence.size() - 3)
39 return false; // Not found, or didn't have 2 characters following it.
40
41 const std::string cs_str = sentence.substr(cs_start + 1, 2);
42 const unsigned long checksum = strtol(cs_str.c_str(), nullptr, 16);
43 if (checksum == 0L && cs_str != "00") return false;
44
45 unsigned char calculated_checksum = 0;
46 for (const char c : sentence.substr(1, cs_start - 1))
47 calculated_checksum ^= static_cast<unsigned char>(c);
48 return calculated_checksum == checksum;
49}
50
57static std::string GetPayloadSentence(const std::string& sentence) {
58 size_t start_pos = sentence.find('$');
59 if (start_pos == std::string::npos) start_pos = sentence.find('!');
60 if (start_pos == std::string::npos) return "";
61 if (sentence.size() < start_pos + 6) return "";
62 return sentence.substr(start_pos);
63}
64
65CommDriverN0183::CommDriverN0183() : AbstractCommDriver(NavAddr::Bus::N0183) {}
66
67CommDriverN0183::CommDriverN0183(NavAddr::Bus, const std::string& s)
68 : AbstractCommDriver(NavAddr::Bus::N0183, s) {}
69
70CommDriverN0183::~CommDriverN0183() = default;
71
72void CommDriverN0183::SendToListener(const std::string& payload,
73 DriverListener& listener,
74 const ConnectionParams& params) {
75 const std::string sentence = GetPayloadSentence(payload);
76 if (sentence.empty()) return;
77 assert(sentence[0] == '$' || sentence[0] == '!');
78 assert(sentence.size() >= 6);
79
80 const bool is_garbage =
81 sentence.size() > 128 ||
82 std::any_of(sentence.begin(), sentence.end(),
83 [](char c) { return !isprint(c) && c != '\n' && c != '\r'; });
84 const bool has_checksum =
85 sentence.find('*', sentence.size() - 6) != std::string::npos;
86
87 NavMsg::State state;
88 if (is_garbage)
89 state = NavMsg::State::kCannotParse;
90 else if (!params.SentencePassesFilter(sentence, FILTER_INPUT))
91 state = NavMsg::State::kFiltered;
92 else if (has_checksum && !Is0183ChecksumOk(sentence))
93 state = NavMsg::State::kBadChecksum;
94 else
95 state = NavMsg::State::kOk;
96
97 std::string id =
98 state == NavMsg::State::kCannotParse ? "TRASH" : sentence.substr(1, 5);
99 auto msg =
100 std::make_shared<const Nmea0183Msg>(id, sentence, GetAddress(), state);
101 if (is_garbage) {
102 auto msg = std::make_shared<const Nmea0183Msg>("TRASH", payload,
103 GetAddress(), state);
104 listener.Notify(std::move(msg));
105 } else {
106 // We notify based on full message, including the Talker ID
107 const std::string id = sentence.substr(1, 5);
108 auto msg =
109 std::make_shared<const Nmea0183Msg>(id, sentence, GetAddress(), state);
110 listener.Notify(std::move(msg));
111 }
112}
Common interface for all drivers.
Definition comm_driver.h:67
void SendToListener(const std::string &payload, DriverListener &listener, const ConnectionParams &params)
Wrap argument string in NavMsg pointer, forward to listener.
Interface for handling incoming messages.
Definition comm_driver.h:52
virtual void Notify(std::shared_ptr< const NavMsg > message)=0
Handle a received message.
Where messages are sent to or received from.
NMEA0183 drivers common base.