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"
47 #include "model/comm_drv_registry.h"
49 #include "model/comm_drv_n0183_net.h"
50 #include "model/comm_drv_n0183_android_bt.h"
51 #include "model/comm_navmsg_bus.h"
66 static 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;
89 static bool is_same_device(
const char *port1,
const char *port2) {
90 std::string dev1 = do_readlink(port1);
91 std::string dev2 = do_readlink(port2);
97 static 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");
121 Multiplexer::~Multiplexer() {}
123 void Multiplexer::LogOutputMessageColor(
const wxString &msg,
124 const wxString &stream_name,
125 const wxString &color) {
126 if (m_log_callbacks.log_is_active()) {
127 wxDateTime now = wxDateTime::Now();
130 ss = now.FormatISOTime();
132 ss.Prepend(_T(
"--> "));
134 ss.Append(stream_name);
139 m_log_callbacks.log_message(ss.ToStdString());
143 void Multiplexer::LogOutputMessage(
const wxString &msg, wxString stream_name,
146 LogOutputMessageColor(msg, stream_name, _T(
"<CORAL>"));
148 LogOutputMessageColor(msg, stream_name, _T(
"<BLUE>"));
151 void Multiplexer::LogInputMessage(
const wxString &msg,
152 const wxString &stream_name,
bool b_filter,
154 if (m_log_callbacks.log_is_active()) {
155 wxDateTime now = wxDateTime::Now();
158 ss = now.FormatISOTime();
161 ss.Append(stream_name);
165 ss.Prepend(_T(
"<RED>"));
168 if (m_legacy_input_filter_behaviour)
169 ss.Prepend(_T(
"<CORAL>"));
171 ss.Prepend(_T(
"<MAROON>"));
173 ss.Prepend(_T(
"<GREEN>"));
175 m_log_callbacks.log_message(ss.ToStdString());
179 void Multiplexer::HandleN0183(std::shared_ptr<const Nmea0183Msg> n0183_msg) {
182 const auto& drivers = CommDriverRegistry::GetInstance().
GetDrivers();
183 auto source_driver = FindDriver(drivers, n0183_msg->source->iface);
186 bool bpass_input_filter =
true;
191 if (m_log_callbacks.log_is_active()) {
192 std::string str = n0183_msg->payload;
197 std::dynamic_pointer_cast<CommDriverN0183Serial>(source_driver);
199 params = drv_serial->GetParams();
201 auto drv_net = std::dynamic_pointer_cast<CommDriverN0183Net>(source_driver);
203 params = drv_net->GetParams();
207 auto drv_bluetooth = std::dynamic_pointer_cast<CommDriverN0183AndroidBT>(source_driver);
209 params = drv_bluetooth->GetParams();
216 bpass_input_filter = params.SentencePassesFilter(n0183_msg->payload.c_str(),
219 bool b_error =
false;
220 for (std::string::iterator it = str.begin(); it != str.end(); ++it) {
225 bin_print.Printf(_T(
"<0x%02X>"), *it);
227 if ((*it != 0x0a) && (*it != 0x0d)) b_error =
true;
240 wxString port(n0183_msg->source->iface);
241 LogInputMessage(fmsg, port, !bpass_input_filter, b_error);
246 std::string source_iface;
248 source_iface = source_driver->iface;
252 for (
auto& driver : drivers) {
254 if (driver->bus == NavAddr::Bus::N0183) {
257 std::dynamic_pointer_cast<CommDriverN0183Serial>(driver);
259 params = drv_serial->GetParams();
261 auto drv_net = std::dynamic_pointer_cast<CommDriverN0183Net>(driver);
263 params = drv_net->GetParams();
267 auto drv_bluetooth = std::dynamic_pointer_cast<CommDriverN0183AndroidBT>(driver);
269 params = drv_bluetooth->GetParams();
275 if ((m_legacy_input_filter_behaviour && !bpass_input_filter) ||
276 bpass_input_filter) {
281 if ((!params.DisableEcho && params.Type == SERIAL) || driver->iface != source_iface) {
282 if (params.IOSelect == DS_TYPE_INPUT_OUTPUT ||
283 params.IOSelect == DS_TYPE_OUTPUT)
285 bool bout_filter =
true;
286 bool bxmit_ok =
true;
287 if (params.SentencePassesFilter(n0183_msg->payload.c_str(),
289 bxmit_ok = driver->SendMessage(n0183_msg,
290 std::make_shared<NavAddr0183>(driver->iface));
297 LogOutputMessageColor(fmsg, driver->iface, _T(
"<BLUE>"));
299 LogOutputMessageColor(fmsg, driver->iface, _T(
"<RED>"));
301 LogOutputMessageColor(fmsg, driver->iface, _T(
"<CORAL>"));
309 void Multiplexer::InitN2KCommListeners() {
311 auto& msgbus = NavMsgBus::GetInstance();
319 listener_N2K_All.
Listen(n2k_msg_All,
this, EVT_N2K_ALL);
321 HandleN2K_Log(UnpackEvtPointer<Nmea2000Msg>(ev));
325 bool Multiplexer::HandleN2K_Log(std::shared_ptr<const Nmea2000Msg> n2k_msg) {
326 if (!m_log_callbacks.log_is_active())
330 unsigned int pgn = 0;
331 pgn += n2k_msg.get()->payload.at(3);
332 pgn += n2k_msg.get()->payload.at(4) << 8;
333 pgn += n2k_msg.get()->payload.at(5) << 16;
336 std::string source = n2k_msg.get()->source->to_string();
339 unsigned char source_id = n2k_msg.get()->payload.at(7);
341 sprintf(ss,
"%d", source_id);
342 std::string ident = std::string(ss);
344 if (pgn == last_pgn_logged) {
350 wxString repeat_log_msg;
351 repeat_log_msg.Printf(
"...Repeated %d times\n", n_N2K_repeat);
352 LogInputMessage(repeat_log_msg,
"N2000",
false,
false);
358 log_msg.Printf(
"PGN: %d Source: %s ID: %s Desc: %s\n", pgn, source,
359 ident,N2K_LogMessage_Detail(pgn, n2k_msg).c_str());
361 LogInputMessage(log_msg,
"N2000",
false,
false);
363 last_pgn_logged = pgn;
368 std::string Multiplexer::N2K_LogMessage_Detail(
unsigned int pgn, std::shared_ptr<const Nmea2000Msg> n2k_msg) {
369 std::string notused =
"Not used by OCPN, maybe by Plugins";
373 return "GNSS Position & DBoard: SAT System";
376 return "Position rapid";
379 return "COG/SOG rapid";
382 return "AIS Class A position report";
385 return "AIS Class B position report";
388 return "AIS Aids to Navigation (AtoN) Report";
391 return "AIS Base Station report";
394 return "AIS static data class A";
397 return "AIS static data class B part A";
400 return "AIS static data class B part B";
403 return "Heading rapid";
406 return "GNSS Sats & DBoard: SAT Status";
410 return "DBoard: Rudder data";
413 return "DBoard: Roll Pitch";
416 return "DBoard: Speed through water";
419 return "DBoard: Depth Data";
422 return "DBoard: Distance log";
425 return "DBoard: Wind data";
428 return "DBoard: Envorinment data";
432 return "System time. " + notused;
435 return "Man Overboard Notification. " + notused;
438 return "Heading/Track control. " + notused;
441 return "Rate of turn. " + notused;
444 return "Magnetic variation. " + notused;
447 return "Engine rapid param. " + notused;
450 return "Engine parameters dynamic. " + notused;
453 return "Transmission parameters dynamic. " + notused;
456 return "Trip Parameters, Engine. " + notused;
459 return "Binary status report. " + notused;
462 return "Fluid level. " + notused;
465 return "DC Detailed Status. " + notused;
468 return "Charger Status. " + notused;
471 return "Battery Status. " + notused;
474 return "Battery Configuration Status. " + notused;
477 return "Leeway. " + notused;
480 return "Windlass Control Status. " + notused;
483 return "Windlass Operating Status. " + notused;
486 return "Windlass Monitoring Status. " + notused;
489 return "Date,Time & Local offset. " + notused;
492 return "GNSS DOP data. " + notused;
495 return "Cross Track Error. " + notused;
498 return "Navigation info. " + notused;
501 return "Waypoint list. " + notused;
504 return "AIS Safety Related Broadcast Message. " + notused;
507 return "Waypoint list. " + notused;
510 return "Environmental parameters. " + notused;
513 return "Temperature. " + notused;
516 return "Humidity. " + notused;
519 return "Actual Pressure. " + notused;
522 return "Set Pressure. " + notused;
525 return "Temperature extended range. " + notused;
528 return "Meteorological Station Data. " + notused;
531 return "Trim Tab Position. " + notused;
534 return "Direction Data. " + notused;
537 return "No description. Not used by OCPN, maybe passed to plugins";
const std::vector< DriverPtr > & GetDrivers()
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.
wxDEFINE_EVENT(REST_IO_EVT, ObservedEvt)
Event from IO thread to main.