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"
52#include "model/nmea_log.h"
65bool CheckSumCheck(
const std::string &sentence) {
66 size_t check_start = sentence.find(
'*');
67 if (check_start == wxString::npos || check_start > sentence.size() - 3)
70 std::string check_str = sentence.substr(check_start + 1, 2);
71 unsigned long checksum = strtol(check_str.c_str(), 0, 16);
72 if (checksum == 0L && check_str !=
"00")
return false;
74 unsigned char calculated_checksum = 0;
75 for (std::string::const_iterator i = sentence.begin() + 1;
76 i != sentence.end() && *i !=
'*'; ++i)
77 calculated_checksum ^=
static_cast<unsigned char>(*i);
79 return calculated_checksum == checksum;
83 : m_log_callbacks(cb), m_legacy_input_filter_behaviour(filter_behaviour) {
88 auto n0183_msg = std::static_pointer_cast<const Nmea0183Msg>(ptr);
89 HandleN0183(n0183_msg);
92 InitN2KCommListeners();
95 if (g_GPS_Ident.IsEmpty()) g_GPS_Ident = wxT(
"Generic");
98Multiplexer::~Multiplexer() {}
100void Multiplexer::LogOutputMessage(
const std::shared_ptr<const NavMsg> &msg,
102 if (m_log_callbacks.log_is_active()) {
103 ns.direction = NavmsgStatus::Direction::kOutput;
105 m_log_callbacks.log_message(ll);
110 bool is_filtered,
bool is_error,
111 const wxString error_msg) {
112 if (m_log_callbacks.log_is_active()) {
114 ns.direction = NavmsgStatus::Direction::kReceived;
116 ns.status = NavmsgStatus::State::kChecksumError;
119 if (m_legacy_input_filter_behaviour) {
120 ns.accepted = NavmsgStatus::Accepted::kFilteredNoOutput;
122 ns.accepted = NavmsgStatus::Accepted::kFilteredDropped;
125 ns.accepted = NavmsgStatus::Accepted::kOk;
129 ll.error_msg = error_msg;
130 m_log_callbacks.log_message(ll);
134void Multiplexer::HandleN0183(std::shared_ptr<const Nmea0183Msg> n0183_msg) {
137 const auto &drivers = CommDriverRegistry::GetInstance().
GetDrivers();
138 auto &source_driver =
FindDriver(drivers, n0183_msg->source->iface);
139 if (!source_driver)
return;
142 bool bpass_input_filter =
true;
147 std::string str = n0183_msg->payload;
153 params = drv_serial->GetParams();
157 params = drv_net->GetParams();
165 params = drv_bluetooth->GetParams();
173 params.SentencePassesFilter(n0183_msg->payload.c_str(), FILTER_INPUT);
175 bool b_error =
false;
177 for (std::string::iterator it = str.begin(); it != str.end(); ++it) {
182 bin_print.Printf(_T(
"<0x%02X>"), *it);
184 if ((*it != 0x0a) && (*it != 0x0d)) {
186 error_msg = _(
"Non-printable character in NMEA0183 message");
192 bool checksumOK = CheckSumCheck(n0183_msg->payload);
195 error_msg = _(
"NMEA0183 checksum error");
198 wxString port(n0183_msg->source->iface);
203 std::string source_iface;
205 source_iface = source_driver->iface;
208 for (
auto &driver : drivers) {
209 if (driver->bus == NavAddr::Bus::N0183) {
213 params = drv_serial->GetParams();
217 params = drv_net->GetParams();
224 params = drv_bluetooth->GetParams();
230 std::shared_ptr<const Nmea0183Msg> msg = n0183_msg;
231 if ((m_legacy_input_filter_behaviour && !bpass_input_filter) ||
232 bpass_input_filter) {
237 if ((!params.DisableEcho && params.Type == SERIAL) ||
238 driver->iface != source_iface) {
239 if (params.IOSelect == DS_TYPE_INPUT_OUTPUT ||
240 params.IOSelect == DS_TYPE_OUTPUT) {
241 bool bout_filter =
true;
242 bool bxmit_ok =
true;
243 std::string id(
"XXXXX");
244 size_t comma_pos = n0183_msg->payload.find(
",");
245 if (comma_pos != std::string::npos && comma_pos > 5)
246 id = n0183_msg->payload.substr(1, comma_pos - 1);
247 if (params.SentencePassesFilter(n0183_msg->payload.c_str(),
251 auto null_addr = std::make_shared<NavAddr>();
252 msg = std::make_shared<Nmea0183Msg>(
id, n0183_msg->payload,
254 bxmit_ok = driver->SendMessage(msg, null_addr);
259 if (m_log_callbacks.log_is_active()) {
261 ns.direction = NavmsgStatus::Direction::kOutput;
263 ns.accepted = NavmsgStatus::Accepted::kFilteredDropped;
265 if (!bxmit_ok) ns.status = NavmsgStatus::State::kTxError;
267 auto logaddr = std::make_shared<NavAddr0183>(driver->iface);
268 auto logmsg = std::make_shared<Nmea0183Msg>(
269 id, n0183_msg->payload, logaddr);
270 LogOutputMessage(logmsg, ns);
279void Multiplexer::InitN2KCommListeners() {
286 listener_N2K_All.
Listen(n2k_msg_All,
this, EVT_N2K_ALL);
288 HandleN2K_Log(UnpackEvtPointer<Nmea2000Msg>(ev));
292bool Multiplexer::HandleN2K_Log(std::shared_ptr<const Nmea2000Msg> n2k_msg) {
293 if (!m_log_callbacks.log_is_active())
return false;
295 auto payload = n2k_msg.get()->payload;
297 unsigned int pgn = 0;
298 pgn += n2k_msg.get()->payload.at(3);
299 pgn += n2k_msg.get()->payload.at(4) << 8;
300 pgn += n2k_msg.get()->payload.at(5) << 16;
303 printf(
" %d: payload\n", pgn);
304 for(
size_t i=0; i< payload.size(); i++){
305 printf(
"%02X ", payload.at(i));
308 std::string pretty = n2k_msg->to_string();
309 printf(
"%s\n\n", pretty.c_str());
313 if (payload.at(0) == 0x94) {
315 ns.direction = NavmsgStatus::Direction::kOutput;
316 LogOutputMessage(n2k_msg, ns);
319 std::string source = n2k_msg.get()->source->to_string();
322 unsigned char source_id = n2k_msg.get()->payload.at(7);
324 sprintf(ss,
"%d", source_id);
325 std::string ident = std::string(ss);
327 if (pgn == last_pgn_logged) {
332 wxString repeat_log_msg;
333 repeat_log_msg.Printf(
"...Repeated %d times\n", n_N2K_repeat);
340 log_msg.Printf(
"PGN: %d Source: %s ID: %s Desc: %s\n", pgn, source, ident,
341 N2K_LogMessage_Detail(pgn).c_str());
345 last_pgn_logged = pgn;
350std::string Multiplexer::N2K_LogMessage_Detail(
unsigned int pgn) {
351 std::string notused =
"Not used by OCPN, maybe by Plugins";
355 return "GNSS Position & DBoard: SAT System";
357 return "Position rapid";
359 return "COG/SOG rapid";
361 return "AIS Class A position report";
363 return "AIS Class B position report";
365 return "AIS Aids to Navigation (AtoN) Report";
367 return "AIS Base Station report";
369 return "AIS static data class A";
372 return "AIS static data class B part A";
374 return "AIS static data class B part B";
376 return "Heading rapid";
378 return "GNSS Sats & DBoard: SAT Status";
381 return "DBoard: Rudder data";
383 return "DBoard: Roll Pitch";
385 return "DBoard: Speed through water";
388 return "DBoard: Depth Data";
390 return "DBoard: Distance log";
392 return "DBoard: Wind data";
394 return "DBoard: Envorinment data";
397 return "System time. " + notused;
399 return "Man Overboard Notification. " + notused;
401 return "Heading/Track control. " + notused;
403 return "Rate of turn. " + notused;
405 return "Magnetic variation. " + notused;
407 return "Engine rapid param. " + notused;
409 return "Engine parameters dynamic. " + notused;
411 return "Transmission parameters dynamic. " + notused;
413 return "Trip Parameters, Engine. " + notused;
415 return "Binary status report. " + notused;
417 return "Fluid level. " + notused;
419 return "DC Detailed Status. " + notused;
421 return "Charger Status. " + notused;
423 return "Battery Status. " + notused;
425 return "Battery Configuration Status. " + notused;
427 return "Leeway. " + notused;
429 return "Windlass Control Status. " + notused;
431 return "Windlass Operating Status. " + notused;
433 return "Windlass Monitoring Status. " + notused;
435 return "Date,Time & Local offset. " + notused;
437 return "GNSS DOP data. " + notused;
439 return "Cross Track Error. " + notused;
441 return "Navigation info. " + notused;
443 return "Waypoint list. " + notused;
445 return "AIS Safety Related Broadcast Message. " + notused;
447 return "Waypoint list. " + notused;
449 return "Environmental parameters. " + notused;
451 return "Temperature. " + notused;
453 return "Humidity. " + notused;
455 return "Actual Pressure. " + notused;
457 return "Set Pressure. " + notused;
459 return "Temperature extended range. " + notused;
461 return "Meteorological Station Data. " + notused;
463 return "Trim Tab Position. " + notused;
465 return "Direction Data. " + notused;
467 return "No description. Not used by OCPN, maybe passed to plugins";
const std::vector< DriverPtr > & GetDrivers() const
void LogInputMessage(const std::shared_ptr< const NavMsg > &msg, bool is_filtered, bool is_error, const wxString error_msg="")
Logs an input message with context information.
Representation of message status as determined by the multiplexer.
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.
Custom event class for OpenCPN's notification system.
std::shared_ptr< const void > GetSharedPtr() const
Gets the event's payload data.
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.