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.
43#include "model/multiplexer.h"
45#include "model/config_vars.h"
46#include "model/conn_params.h"
50#include "model/comm_drv_n0183_android_bt.h"
66static std::string do_readlink(
const char *link) {
68 const char *colon = strchr(link,
':');
69 const char *path = colon ? colon + 1 : link;
71 char target[PATH_MAX + 1] = {0};
72 int r = readlink(path, target,
sizeof(target));
73 if (r == -1 && (errno == EINVAL || errno == ENOENT)) {
78 wxLogDebug(
"Error reading device link %s: %s", path, strerror(errno));
84 char buff[PATH_MAX + 1];
85 memcpy(buff, path, std::min(strlen(path) + 1, (
size_t)PATH_MAX));
86 return std::string(dirname(buff)) +
"/" + target;
89static bool is_same_device(
const char *port1,
const char *port2) {
90 std::string dev1 = do_readlink(port1);
91 std::string dev2 = do_readlink(port2);
97static bool inline is_same_device(
const char *port1,
const char *port2) {
98 return strcmp(port1, port2) == 0;
104 : m_log_callbacks(cb), m_legacy_input_filter_behaviour(filter_behaviour) {
105 auto &msgbus = NavMsgBus::GetInstance();
110 auto ptr = ev.GetSharedPtr();
111 auto n0183_msg = std::static_pointer_cast<const Nmea0183Msg>(ptr);
112 HandleN0183(n0183_msg);
115 InitN2KCommListeners();
118 if (g_GPS_Ident.IsEmpty()) g_GPS_Ident = wxT(
"Generic");
121Multiplexer::~Multiplexer() {}
123static const wxChar SYMBOL_INPUT = 0x2190;
124static const wxChar SYMBOL_OUTPUT = 0x2192;
125static const wxChar SYMBOL_ERROR = 0x2716;
126static const wxChar SYMBOL_FILTERED = 0x269F;
127static const wxChar SYMBOL_DROPPED = 0x2298;
128static const wxChar SYMBOL_ACCEPTED = 0x2713;
130void Multiplexer::LogOutputMessageColor(
const wxString &msg,
131 const wxString &stream_name,
132 const wxString &color) {
133 if (m_log_callbacks.log_is_active()) {
134 wxDateTime now = wxDateTime::Now();
137 ss = now.FormatISOTime();
139 ss.Append(
" ").Append(SYMBOL_OUTPUT).Append(
" ");
140 if (color ==
"<RED>") {
141 ss.Append(SYMBOL_ERROR);
142 }
else if (color ==
"<CORAL>") {
143 ss.Append(SYMBOL_DROPPED);
145 ss.Append(SYMBOL_ACCEPTED);
148 ss.Append(stream_name);
153 m_log_callbacks.log_message(ss);
157void Multiplexer::LogOutputMessage(
const wxString &msg, wxString stream_name,
160 LogOutputMessageColor(msg, stream_name, _T(
"<CORAL>"));
162 LogOutputMessageColor(msg, stream_name, _T(
"<BLUE>"));
166 const wxString &stream_name,
bool b_filter,
167 bool b_error,
const wxString error_msg) {
168 if (m_log_callbacks.log_is_active()) {
169 wxDateTime now = wxDateTime::Now();
172 ss = now.FormatISOTime();
174 ss.Append(
" ").Append(SYMBOL_INPUT);
177 ss.Append(
" ").Append(SYMBOL_ERROR);
180 if (m_legacy_input_filter_behaviour) {
181 ss.Prepend(
"<CORAL>");
182 ss.Append(
" ").Append(SYMBOL_FILTERED);
184 ss.Prepend(
"<MAROON>");
185 ss.Append(
" ").Append(SYMBOL_DROPPED);
188 ss.Prepend(
"<GREEN>");
189 ss.Append(
" ").Append(SYMBOL_ACCEPTED);
193 ss.Append(stream_name);
198 if (!error_msg.IsEmpty())
199 ss.Append(error_msg);
201 ss.Append(_(
"Unknown error"));
203 m_log_callbacks.log_message(ss);
207void Multiplexer::HandleN0183(std::shared_ptr<const Nmea0183Msg> n0183_msg) {
210 const auto &drivers = CommDriverRegistry::GetInstance().
GetDrivers();
211 auto &source_driver =
FindDriver(drivers, n0183_msg->source->iface);
214 bool bpass_input_filter =
true;
219 if (m_log_callbacks.log_is_active()) {
220 std::string str = n0183_msg->payload;
227 params = drv_serial->GetParams();
231 params = drv_net->GetParams();
239 params = drv_bluetooth->GetParams();
247 params.SentencePassesFilter(n0183_msg->payload.c_str(), FILTER_INPUT);
249 bool b_error =
false;
251 for (std::string::iterator it = str.begin(); it != str.end(); ++it) {
256 bin_print.Printf(_T(
"<0x%02X>"), *it);
258 if ((*it != 0x0a) && (*it != 0x0d)) {
260 error_msg = _(
"Non-printable character in NMEA0183 message");
274 wxString port(n0183_msg->source->iface);
280 std::string source_iface;
282 source_iface = source_driver->iface;
285 for (
auto &driver : drivers) {
286 if (driver->bus == NavAddr::Bus::N0183) {
290 params = drv_serial->GetParams();
294 params = drv_net->GetParams();
301 params = drv_bluetooth->GetParams();
307 if ((m_legacy_input_filter_behaviour && !bpass_input_filter) ||
308 bpass_input_filter) {
313 if ((!params.DisableEcho && params.Type == SERIAL) ||
314 driver->iface != source_iface) {
315 if (params.IOSelect == DS_TYPE_INPUT_OUTPUT ||
316 params.IOSelect == DS_TYPE_OUTPUT) {
317 bool bout_filter =
true;
318 bool bxmit_ok =
true;
319 if (params.SentencePassesFilter(n0183_msg->payload.c_str(),
322 std::string id(
"XXXXX");
323 unsigned comma_pos = n0183_msg->payload.find(
",");
324 if (comma_pos != std::string::npos && comma_pos > 5)
325 id = n0183_msg->payload.substr(1, comma_pos - 1);
326 auto null_addr = std::make_shared<NavAddr>();
327 auto msg = std::make_shared<Nmea0183Msg>(
id, n0183_msg->payload,
329 bxmit_ok = driver->SendMessage(msg, null_addr);
336 LogOutputMessageColor(fmsg, driver->iface, _T(
"<BLUE>"));
338 LogOutputMessageColor(fmsg, driver->iface, _T(
"<RED>"));
340 LogOutputMessageColor(fmsg, driver->iface, _T(
"<CORAL>"));
348void Multiplexer::InitN2KCommListeners() {
350 auto &msgbus = NavMsgBus::GetInstance();
358 listener_N2K_All.
Listen(n2k_msg_All,
this, EVT_N2K_ALL);
360 HandleN2K_Log(UnpackEvtPointer<Nmea2000Msg>(ev));
364bool Multiplexer::HandleN2K_Log(std::shared_ptr<const Nmea2000Msg> n2k_msg) {
365 if (!m_log_callbacks.log_is_active())
return false;
368 unsigned int pgn = 0;
369 pgn += n2k_msg.get()->payload.at(3);
370 pgn += n2k_msg.get()->payload.at(4) << 8;
371 pgn += n2k_msg.get()->payload.at(5) << 16;
374 std::string source = n2k_msg.get()->source->to_string();
377 unsigned char source_id = n2k_msg.get()->payload.at(7);
379 sprintf(ss,
"%d", source_id);
380 std::string ident = std::string(ss);
382 if (pgn == last_pgn_logged) {
387 wxString repeat_log_msg;
388 repeat_log_msg.Printf(
"...Repeated %d times\n", n_N2K_repeat);
395 log_msg.Printf(
"PGN: %d Source: %s ID: %s Desc: %s\n", pgn, source, ident,
396 N2K_LogMessage_Detail(pgn, n2k_msg).c_str());
400 last_pgn_logged = pgn;
404std::string Multiplexer::N2K_LogMessage_Detail(
405 unsigned int pgn, std::shared_ptr<const Nmea2000Msg> n2k_msg) {
406 std::string notused =
"Not used by OCPN, maybe by Plugins";
410 return "GNSS Position & DBoard: SAT System";
413 return "Position rapid";
416 return "COG/SOG rapid";
419 return "AIS Class A position report";
422 return "AIS Class B position report";
425 return "AIS Aids to Navigation (AtoN) Report";
428 return "AIS Base Station report";
431 return "AIS static data class A";
434 return "AIS static data class B part A";
437 return "AIS static data class B part B";
440 return "Heading rapid";
443 return "GNSS Sats & DBoard: SAT Status";
447 return "DBoard: Rudder data";
450 return "DBoard: Roll Pitch";
453 return "DBoard: Speed through water";
456 return "DBoard: Depth Data";
459 return "DBoard: Distance log";
462 return "DBoard: Wind data";
465 return "DBoard: Envorinment data";
469 return "System time. " + notused;
472 return "Man Overboard Notification. " + notused;
475 return "Heading/Track control. " + notused;
478 return "Rate of turn. " + notused;
481 return "Magnetic variation. " + notused;
484 return "Engine rapid param. " + notused;
487 return "Engine parameters dynamic. " + notused;
490 return "Transmission parameters dynamic. " + notused;
493 return "Trip Parameters, Engine. " + notused;
496 return "Binary status report. " + notused;
499 return "Fluid level. " + notused;
502 return "DC Detailed Status. " + notused;
505 return "Charger Status. " + notused;
508 return "Battery Status. " + notused;
511 return "Battery Configuration Status. " + notused;
514 return "Leeway. " + notused;
517 return "Windlass Control Status. " + notused;
520 return "Windlass Operating Status. " + notused;
523 return "Windlass Monitoring Status. " + notused;
526 return "Date,Time & Local offset. " + notused;
529 return "GNSS DOP data. " + notused;
532 return "Cross Track Error. " + notused;
535 return "Navigation info. " + notused;
538 return "Waypoint list. " + notused;
541 return "AIS Safety Related Broadcast Message. " + notused;
544 return "Waypoint list. " + notused;
547 return "Environmental parameters. " + notused;
550 return "Temperature. " + notused;
553 return "Humidity. " + notused;
556 return "Actual Pressure. " + notused;
559 return "Set Pressure. " + notused;
562 return "Temperature extended range. " + notused;
565 return "Meteorological Station Data. " + notused;
568 return "Trim Tab Position. " + notused;
571 return "Direction Data. " + notused;
574 return "No description. Not used by OCPN, maybe passed to plugins";
const std::vector< DriverPtr > & GetDrivers() const
void LogInputMessage(const wxString &msg, const wxString &stream_name, bool b_filter, bool b_error=false, const wxString error_msg=wxEmptyString)
Logs an input message with context information.
static std::string MessageKey(const char *type="ALL")
Return key which should be used to listen to given message type.
See: https://github.com/OpenCPN/OpenCPN/issues/2729#issuecomment-1179506343.
void Listen(const std::string &key, wxEvtHandler *listener, wxEventType evt)
Set object to send wxEventType ev to listener on changes in key.
Adds a std::shared<void> element to wxCommandEvent.
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.