28#include <wx/msw/winundef.h>
37#if defined(HAVE_READLINK) && !defined(HAVE_LIBGEN_H)
38#error Using readlink(3) requires libgen.h which cannot be found.
45#include "model/config_vars.h"
46#include "model/conn_params.h"
58 explicit RawKey(
const std::string &key) : m_key(key) {}
59 [[nodiscard]] std::string
GetKey()
const override {
return m_key; }
65static std::string N2K_LogMessage_Detail(
unsigned int pgn) {
66 std::string not_used =
"Not used by OCPN, maybe by Plugins";
70 return "GNSS Position & DBoard: SAT System";
72 return "Position rapid";
74 return "COG/SOG rapid";
76 return "AIS Class A position report";
78 return "AIS Class B position report";
80 return "AIS Aids to Navigation (AtoN) Report";
82 return "AIS Base Station report";
84 return "AIS static data class A";
87 return "AIS static data class B part A";
89 return "AIS static data class B part B";
91 return "Heading rapid";
93 return "GNSS Sats & DBoard: SAT Status";
96 return "DBoard: Rudder data";
98 return "DBoard: Roll Pitch";
100 return "DBoard: Speed through water";
103 return "DBoard: Depth Data";
105 return "DBoard: Distance log";
107 return "DBoard: Wind data";
109 return "DBoard: Environment data";
112 return "System time. " + not_used;
114 return "Man Overboard Notification. " + not_used;
116 return "Heading/Track control. " + not_used;
118 return "Rate of turn. " + not_used;
120 return "Magnetic variation. " + not_used;
122 return "Engine rapid param. " + not_used;
124 return "Engine parameters dynamic. " + not_used;
126 return "Transmission parameters dynamic. " + not_used;
128 return "Trip Parameters, Engine. " + not_used;
130 return "Binary status report. " + not_used;
132 return "Fluid level. " + not_used;
134 return "DC Detailed Status. " + not_used;
136 return "Charger Status. " + not_used;
138 return "Battery Status. " + not_used;
140 return "Battery Configuration Status. " + not_used;
142 return "Leeway. " + not_used;
144 return "Windlass Control Status. " + not_used;
146 return "Windlass Operating Status. " + not_used;
148 return "Windlass Monitoring Status. " + not_used;
150 return "Date,Time & Local offset. " + not_used;
152 return "GNSS DOP data. " + not_used;
154 return "Cross Track Error. " + not_used;
156 return "Navigation info. " + not_used;
158 return "Waypoint list. " + not_used;
160 return "AIS Safety Related Broadcast Message. " + not_used;
162 return "Waypoint list. " + not_used;
164 return "Environmental parameters. " + not_used;
166 return "Temperature. " + not_used;
168 return "Humidity. " + not_used;
170 return "Actual Pressure. " + not_used;
172 return "Set Pressure. " + not_used;
174 return "Temperature extended range. " + not_used;
176 return "Meteorological Station Data. " + not_used;
178 return "Trim Tab Position. " + not_used;
180 return "Direction Data. " + not_used;
182 return "No description. Not used by OCPN, maybe passed to plugins";
186Multiplexer::Multiplexer(
const MuxLogCallbacks &cb,
bool &filter_behaviour)
188 : m_log_callbacks(cb),
189 m_legacy_input_filter_behaviour(filter_behaviour),
190 m_new_msgtype_lstnr(
NavMsgBus::GetInstance().new_msg_event,
192 m_n2k_repeat_count(0),
193 m_last_pgn_logged(0) {
194 if (g_GPS_Ident.IsEmpty()) g_GPS_Ident =
"Generic";
197Multiplexer::~Multiplexer() =
default;
199void Multiplexer::LogOutputMessage(
const std::shared_ptr<const NavMsg> &msg,
201 if (m_log_callbacks.log_is_active()) {
202 ns.direction = NavmsgStatus::Direction::kOutput;
204 m_log_callbacks.log_message(ll);
209 bool is_filtered,
bool is_error,
210 const wxString &error_msg)
const {
211 if (m_log_callbacks.log_is_active()) {
213 ns.direction = NavmsgStatus::Direction::kHandled;
215 ns.status = NavmsgStatus::State::kChecksumError;
218 if (m_legacy_input_filter_behaviour) {
219 ns.accepted = NavmsgStatus::Accepted::kFilteredNoOutput;
221 ns.accepted = NavmsgStatus::Accepted::kFilteredDropped;
224 ns.accepted = NavmsgStatus::Accepted::kOk;
228 ll.error_msg = error_msg;
229 m_log_callbacks.log_message(ll);
233void Multiplexer::HandleN0183(
234 const std::shared_ptr<const Nmea0183Msg> &n0183_msg)
const {
236 const auto &drivers = CommDriverRegistry::GetInstance().
GetDrivers();
237 auto &source_driver =
FindDriver(drivers, n0183_msg->source->iface);
238 if (!source_driver) {
240 if ((n0183_msg->source->iface !=
"virtual")) {
245 std::string error_msg;
246 if (n0183_msg->state == NavMsg::State::kCannotParse)
247 error_msg = _(
"Unparsable NMEA0183 message").ToStdString();
248 else if (n0183_msg->state == NavMsg::State::kBadChecksum)
249 error_msg = _(
"NMEA0183 checksum error").ToStdString();
250 bool is_filtered = n0183_msg->state == NavMsg::State::kFiltered;
251 bool cs_error = n0183_msg->state == NavMsg::State::kBadChecksum;
256 std::string source_iface;
258 source_iface = source_driver->iface;
261 for (
auto &driver : drivers) {
262 if (!driver)
continue;
263 if (driver->bus == NavAddr::Bus::N0183) {
267 bool passes_input_filter = n0183_msg->state != NavMsg::State::kFiltered;
270 std::shared_ptr<const Nmea0183Msg> msg = n0183_msg;
271 if ((m_legacy_input_filter_behaviour && !passes_input_filter) ||
272 passes_input_filter) {
277 if ((!params_.DisableEcho && params_.Type == SERIAL) ||
278 driver->iface != source_iface) {
279 if (params_.IOSelect == DS_TYPE_INPUT_OUTPUT ||
280 params_.IOSelect == DS_TYPE_OUTPUT) {
281 bool bout_filter =
true;
282 bool bxmit_ok =
true;
283 std::string id(
"XXXXX");
284 size_t comma_pos = n0183_msg->payload.find(
',');
285 if (comma_pos != std::string::npos && comma_pos > 5)
286 id = n0183_msg->payload.substr(1, comma_pos - 1);
287 if (params_.SentencePassesFilter(n0183_msg->payload.c_str(),
290 auto null_addr = std::make_shared<NavAddr>();
291 msg = std::make_shared<Nmea0183Msg>(
id, n0183_msg->payload,
293 bxmit_ok = driver->SendMessage(msg, null_addr);
298 if (m_log_callbacks.log_is_active()) {
300 ns.direction = NavmsgStatus::Direction::kOutput;
302 ns.accepted = NavmsgStatus::Accepted::kFilteredDropped;
304 if (!bxmit_ok) ns.status = NavmsgStatus::State::kTxError;
306 auto logaddr = std::make_shared<NavAddr0183>(driver->iface);
307 auto logmsg = std::make_shared<Nmea0183Msg>(
308 id, n0183_msg->payload, logaddr);
309 LogOutputMessage(logmsg, ns);
318bool Multiplexer::HandleN2kLog(
319 const std::shared_ptr<const Nmea2000Msg> &n2k_msg) {
320 if (!m_log_callbacks.log_is_active())
return false;
322 auto payload = n2k_msg->payload;
324 unsigned int pgn = 0;
325 pgn += n2k_msg->payload.at(3);
326 pgn += n2k_msg->payload.at(4) << 8;
327 pgn += n2k_msg->payload.at(5) << 16;
330 if (payload.at(0) == 0x94) {
332 ns.direction = NavmsgStatus::Direction::kOutput;
333 LogOutputMessage(n2k_msg, ns);
336 std::string source = n2k_msg->source->to_string();
339 unsigned char source_id = n2k_msg->payload.at(7);
341 sprintf(ss,
"%d", source_id);
342 std::string ident = std::string(ss);
344 if (pgn == m_last_pgn_logged) {
345 m_n2k_repeat_count++;
348 if (m_n2k_repeat_count) {
349 wxString repeat_log_msg;
350 repeat_log_msg.Printf(
"...Repeated %d times\n", m_n2k_repeat_count);
352 m_n2k_repeat_count = 0;
356 log_msg.Printf(
"PGN: %d Source: %s ID: %s Desc: %s\n", pgn, source, ident,
357 N2K_LogMessage_Detail(pgn).c_str());
361 m_last_pgn_logged = pgn;
366void Multiplexer::OnNewMessageType() {
367 for (
auto msg_key :
NavMsgBus::GetInstance().GetActiveMessages()) {
368 if (m_listeners.find(msg_key) != m_listeners.end())
continue;
371 case NavAddr::Bus::N0183:
372 m_listeners[msg_key] =
374 HandleN0183(UnpackEvtPointer<Nmea0183Msg>(ev));
378 case NavAddr::Bus::N2000:
379 m_listeners[msg_key] =
381 HandleN2kLog(UnpackEvtPointer<Nmea2000Msg>(ev));
NMEA0183 basic parsing common parts:
const std::vector< DriverPtr > & GetDrivers() const
Interface implemented by classes which listens.
Handle logging and forwarding of incoming n0183/n2k messages.
void LogInputMessage(const std::shared_ptr< const NavMsg > &msg, bool is_filtered, bool is_error, const wxString &error_msg="") const
Logs an input message with context information.
The raw message layer, a singleton.
static NavAddr::Bus GetBusByKey(const std::string &key)
Return bus corresponding to given key.
Representation of message status as determined by the multiplexer.
Define an action to be performed when a KeyProvider is notified.
Custom event class for OpenCPN's notification system.
KeyProvider wrapper for a plain key string.
std::string GetKey() const override
Get the Key object from the Key Provider.
DriverPtr & FindDriver(const std::vector< DriverPtr > &drivers, const std::string &iface, const NavAddr::Bus _bus)
Search list of drivers for a driver with given interface string.
Driver registration container, a singleton.
Raw messages layer, supports sending and recieving navmsg messages.
Multiplexer class and helpers.
std::vector< std::string > split(const char *token_string, const std::string &delimiter)
Return vector of items in s separated by delimiter.
Basic DataMonitor logging interface: LogLine (reflects a line in the log) and NmeaLog,...