OpenCPN Partial API docs
Loading...
Searching...
No Matches
comm_drv_loopback.cpp
Go to the documentation of this file.
1/**************************************************************************
2 * Copyright (C) 2025 Alec Leamas *
3 * *
4 * This program is free software; you can redistribute it and/or modify *
5 * it under the terms of the GNU General Public License as published by *
6 * the Free Software Foundation; either version 2 of the License, or *
7 * (at your option) any later version. *
8 * *
9 * This program is distributed in the hope that it will be useful, *
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of *
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
12 * GNU General Public License for more details. *
13 * *
14 * You should have received a copy of the GNU General Public License *
15 * along with this program; if not, see <https://www.gnu.org/licenses/>. *
16 **************************************************************************/
17
24// For compilers that support precompilation, includes "wx.h".
25#include <wx/wxprec.h>
26
27#ifndef WX_PRECOMP
28#include <wx/wx.h>
29#endif
30
31#include <algorithm>
32#include <cctype>
33#include <memory>
34#include <string>
35#include <vector>
36
37#include <wx/log.h>
38#include <wx/string.h>
39
40#include "nlohmann/json.hpp"
41
43#include "model/comm_navmsg.h"
44#include "model/ocpn_utils.h"
45
46using namespace std;
47
48using NavMsgPtr = shared_ptr<const NavMsg>;
49
50static string NextWord(std::string& line) {
51 if (line.empty()) return "";
52 size_t space_pos = line.find(" ");
53 if (space_pos == string::npos) space_pos = line.size();
54 string word(line.substr(0, space_pos));
55 line = ocpn::ltrim(line.substr(space_pos));
56 return word;
57}
58
59static unsigned HexNibbleValue(char c) {
60 c = tolower(c);
61 if (c >= '0' && c <= '9') return c - '0';
62 if (c >= 'a' && c <= 'f') return 10 + c - 'a';
63 return -1;
64}
65
66static unsigned char HexByteValue(const string& text) {
67 unsigned value;
68 if (text.size() == 1) {
69 value = HexNibbleValue(text[0]);
70 } else {
71 value = 16 * HexNibbleValue(text[0]) + HexNibbleValue(text[1]);
72 }
73 return static_cast<unsigned char>(value);
74}
75
76static NavMsgPtr Parse2000(const std::string& iface, const string& type,
77 const std::string& msg) {
78 vector<unsigned char> payload;
79 auto hexbytes = ocpn::split(msg, " ");
80 for (const auto& byte : hexbytes) payload.push_back(HexByteValue(byte));
81 uint64_t pgn;
82 try {
83 pgn = stoi(type);
84 } catch (invalid_argument&) {
85 return {nullptr};
86 }
87 return make_shared<Nmea2000Msg>(
88 pgn, payload, make_shared<NavAddr2000>(iface, N2kName(pgn)));
89}
90
91static NavMsgPtr Parse0183(const string& iface, const string& type,
92 const string& msg) {
93 return make_shared<Nmea0183Msg>(type, msg, make_shared<NavAddr0183>(iface));
94}
95
96static NavMsgPtr ParseSignalk(const string& iface, const string& type,
97 const string& msg) {
98 std::string context;
99 try {
100 nlohmann::json root = nlohmann::json::parse(msg);
101 if (root.contains("context")) context = root["context"].get<std::string>();
102 } catch (nlohmann::json::exception&) {
103 }
104 return make_shared<SignalkMsg>(type, context, msg, iface);
105}
106
107NavMsgPtr LoopbackDriver::ParsePluginMessage(const string& msg) {
108 int space_count = count(msg.begin(), msg.end(), ' ');
109 if (space_count < 3) {
110 return {nullptr};
111 }
112 std::string msg_(msg);
113 auto protocol = ocpn::tolower(NextWord(msg_));
114 auto iface = NextWord(msg_);
115 auto type = NextWord(msg_);
116
117 if (protocol == "nmea2000") return Parse2000(iface, type, msg_);
118 if (protocol == "nmea0183") return Parse0183(iface, type, msg_);
119 if (protocol == "signalk") return ParseSignalk(iface, type, msg_);
120 return {nullptr};
121}
const std::string iface
Physical device for 0183, else a unique string.
Definition comm_driver.h:95
static std::shared_ptr< const NavMsg > ParsePluginMessage(const std::string &msg)
Parse a string as provided by plugin and convert to a navmsg.
Loopback driver, treat sent messages as received.
Raw, undecoded messages definitions.
std::string tolower(const std::string &input)
Return copy of s with all characters converted to lower case.
std::vector< std::string > split(const char *token_string, const std::string &delimiter)
Return vector of items in s separated by delimiter.
std::string ltrim(const std::string &arg)
Strip possibly leading space characters in s.
Miscellaneous utilities, many of which string related.
N2k uses CAN which defines the basic properties of messages.
Definition comm_navmsg.h:70