OpenCPN Partial API docs
comm_bridge.cpp
1 /***************************************************************************
2  *
3  * Project: OpenCPN
4  * Purpose:
5  * Author: David Register, Alec Leamas
6  *
7  ***************************************************************************
8  * Copyright (C) 2022 by David Register, Alec Leamas *
9  * *
10  * This program is free software; you can redistribute it and/or modify *
11  * it under the terms of the GNU General Public License as published by *
12  * the Free Software Foundation; either version 2 of the License, or *
13  * (at your option) any later version. *
14  * *
15  * This program is distributed in the hope that it will be useful, *
16  * but WITHOUT ANY WARRANTY; without even the implied warranty of *
17  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
18  * GNU General Public License for more details. *
19  * *
20  * You should have received a copy of the GNU General Public License *
21  * along with this program; if not, write to the *
22  * Free Software Foundation, Inc., *
23  * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. *
24  **************************************************************************/
25 
26 // For compilers that support precompilation, includes "wx.h".
27 #include <wx/wxprec.h>
28 
29 #ifndef WX_PRECOMP
30 #include <wx/wx.h>
31 #endif // precompiled headers
32 
33 #include <wx/event.h>
34 #include <wx/string.h>
35 #include <wx/tokenzr.h>
36 #include <wx/fileconf.h>
37 
38 #include "model/comm_ais.h"
39 #include "model/comm_appmsg_bus.h"
40 #include "model/comm_bridge.h"
41 #include "model/comm_drv_registry.h"
42 #include "model/comm_navmsg_bus.h"
43 #include "model/comm_vars.h"
44 #include "model/config_vars.h"
45 #include "model/idents.h"
46 #include "model/ocpn_types.h"
47 #include "model/own_ship.h"
48 #include "model/multiplexer.h"
49 
50 
51 // comm event definitions
52 wxDEFINE_EVENT(EVT_N2K_129029, ObservedEvt);
53 wxDEFINE_EVENT(EVT_N2K_129025, ObservedEvt);
54 wxDEFINE_EVENT(EVT_N2K_129026, ObservedEvt);
55 wxDEFINE_EVENT(EVT_N2K_127250, ObservedEvt);
56 wxDEFINE_EVENT(EVT_N2K_129540, ObservedEvt);
57 
58 wxDEFINE_EVENT(EVT_N0183_RMC, ObservedEvt);
59 wxDEFINE_EVENT(EVT_N0183_HDT, ObservedEvt);
60 wxDEFINE_EVENT(EVT_N0183_HDG, ObservedEvt);
61 wxDEFINE_EVENT(EVT_N0183_HDM, ObservedEvt);
62 wxDEFINE_EVENT(EVT_N0183_VTG, ObservedEvt);
63 wxDEFINE_EVENT(EVT_N0183_GSV, ObservedEvt);
64 wxDEFINE_EVENT(EVT_N0183_GGA, ObservedEvt);
65 wxDEFINE_EVENT(EVT_N0183_GLL, ObservedEvt);
66 wxDEFINE_EVENT(EVT_N0183_AIVDO, ObservedEvt);
67 
68 wxDEFINE_EVENT(EVT_DRIVER_CHANGE, wxCommandEvent);
69 
70 wxDEFINE_EVENT(EVT_SIGNALK, ObservedEvt);
71 
72 #define N_ACTIVE_LOG_WATCHDOG 300
73 
74 extern Multiplexer* g_pMUX;
75 
76 bool debug_priority = 0;
77 
78 void ClearNavData(NavData &d){
79  d.gLat = NAN;
80  d.gLon = NAN;
81  d.gSog = NAN;
82  d.gCog = NAN;
83  d.gHdt = NAN;
84  d.gHdm = NAN;
85  d.gVar = NAN;
86  d.n_satellites = -1;
87  d.SID = 0;
88 }
89 
94 static void SendBasicNavdata(int vflag) {
95  auto msg = std::make_shared<BasicNavDataMsg>(
96  gLat, gLon, gSog, gCog, gVar, gHdt, vflag, wxDateTime::Now().GetTicks());
97  AppMsgBus::GetInstance().Notify(std::move(msg));
98 }
99 
100 
101 static inline double GeodesicRadToDeg(double rads) {
102  return rads * 180.0 / M_PI;
103 }
104 
105 static inline double MS2KNOTS(double ms) {
106  return ms * 1.9438444924406;
107 }
108 
109 // CommBridge implementation
110 
111 BEGIN_EVENT_TABLE(CommBridge, wxEvtHandler)
112 EVT_TIMER(WATCHDOG_TIMER, CommBridge::OnWatchdogTimer)
113 END_EVENT_TABLE()
114 
116 
117 CommBridge::~CommBridge() {}
118 
119 bool CommBridge::Initialize() {
120 
121  InitializePriorityContainers();
122  ClearPriorityMaps();
123 
124  LoadConfig();
125  PresetPriorityContainers();
126 
127  // Clear the watchdogs
128  PresetWatchdogs();
129 
130  m_watchdog_timer.SetOwner(this, WATCHDOG_TIMER);
131  m_watchdog_timer.Start(1000, wxTIMER_CONTINUOUS);
132  n_LogWatchdogPeriod = 3600; //every 60 minutes,
133  //reduced after first position Rx
134 
135  // Initialize the comm listeners
136  InitCommListeners();
137 
138  // Initialize a listener for driver state changes
139  driver_change_listener.Listen(
140  CommDriverRegistry::GetInstance().evt_driverlist_change.key, this,
141  EVT_DRIVER_CHANGE);
142  Bind(EVT_DRIVER_CHANGE, [&](wxCommandEvent ev) {
143  OnDriverStateChange(); });
144 
145 
146  return true;
147 }
148 
149 void CommBridge::PresetWatchdogs() {
150  m_watchdogs.position_watchdog = 20; // A bit longer watchdog for startup latency.
151  m_watchdogs.velocity_watchdog = 20;
152  m_watchdogs.variation_watchdog = 20;
153  m_watchdogs.heading_watchdog = 20;
154  m_watchdogs.satellite_watchdog = 20;
155 }
156 
157 void CommBridge::SelectNextLowerPriority(const std::unordered_map<std::string, int> &map,
158  PriorityContainer &pc) {
159 
160  int best_prio = 100;
161  for (auto it = map.begin(); it != map.end(); it++) {
162  if (it->second > pc.active_priority){
163  best_prio = wxMin(best_prio, it->second);
164  }
165  }
166 
167  pc.active_priority = best_prio;
168  pc.active_source.clear();
169  pc.active_identifier.clear();
170 
171 }
172 
173 void CommBridge::OnWatchdogTimer(wxTimerEvent& event) {
174  // Update and check watchdog timer for GPS data source
175  m_watchdogs.position_watchdog--;
176  if (m_watchdogs.position_watchdog <= 0) {
177  if (m_watchdogs.position_watchdog % 5 == 0) {
178  // Send AppMsg telling of watchdog expiry
179  auto msg = std::make_shared<GPSWatchdogMsg>(GPSWatchdogMsg::WDSource::position,
180  m_watchdogs.position_watchdog);
181  auto& msgbus = AppMsgBus::GetInstance();
182  msgbus.Notify(std::move(msg));
183 
184  if (m_watchdogs.position_watchdog % n_LogWatchdogPeriod == 0) {
185  wxString logmsg;
186  logmsg.Printf(_T(" ***GPS Watchdog timeout at Lat:%g Lon: %g"), gLat,
187  gLon);
188  wxLogMessage(logmsg);
189  }
190  }
191 
192  gSog = NAN;
193  gCog = NAN;
194  gRmcDate.Empty();
195  gRmcTime.Empty();
196 
197  // Are there any other lower priority sources?
198  // If so, adopt that one.
199  SelectNextLowerPriority(priority_map_position, active_priority_position);
200  }
201 
202  // Update and check watchdog timer for SOG/COG data source
203  m_watchdogs.velocity_watchdog--;
204  if (m_watchdogs.velocity_watchdog <= 0) {
205  gSog = NAN;
206  gCog = NAN;
207  if (g_nNMEADebug && (m_watchdogs.velocity_watchdog == 0))
208  wxLogMessage(_T(" ***Velocity Watchdog timeout..."));
209  if (m_watchdogs.velocity_watchdog % 5 == 0) {
210  // Send AppMsg telling of watchdog expiry
211  auto msg = std::make_shared<GPSWatchdogMsg>(GPSWatchdogMsg::WDSource::velocity,
212  m_watchdogs.velocity_watchdog);
213  auto& msgbus = AppMsgBus::GetInstance();
214  msgbus.Notify(std::move(msg));
215  }
216  // Are there any other lower priority sources?
217  // If so, adopt that one.
218  SelectNextLowerPriority(priority_map_velocity, active_priority_velocity);
219  }
220 
221  // Update and check watchdog timer for True Heading data source
222  m_watchdogs.heading_watchdog--;
223  if (m_watchdogs.heading_watchdog <= 0) {
224  gHdt = NAN;
225  if (g_nNMEADebug && (m_watchdogs.heading_watchdog == 0))
226  wxLogMessage(_T(" ***HDT Watchdog timeout..."));
227 
228  // Are there any other lower priority sources?
229  // If so, adopt that one.
230  SelectNextLowerPriority(priority_map_heading, active_priority_heading);
231  }
232 
233  // Update and check watchdog timer for Magnetic Variation data source
234  m_watchdogs.variation_watchdog--;
235  if (m_watchdogs.variation_watchdog <= 0) {
236  g_bVAR_Rx = false;
237  if (g_nNMEADebug && (m_watchdogs.variation_watchdog == 0))
238  wxLogMessage(_T(" ***VAR Watchdog timeout..."));
239 
240  // Are there any other lower priority sources?
241  // If so, adopt that one.
242  SelectNextLowerPriority(priority_map_variation, active_priority_variation);
243  }
244 
245  // Update and check watchdog timer for GSV, GGA and SignalK (Satellite data)
246  m_watchdogs.satellite_watchdog--;
247  if (m_watchdogs.satellite_watchdog <= 0) {
248  g_bSatValid = false;
249  g_SatsInView = 0;
250  g_priSats = 99;
251  if (g_nNMEADebug && (m_watchdogs.satellite_watchdog == 0))
252  wxLogMessage(_T(" ***SAT Watchdog timeout..."));
253 
254  // Are there any other lower priority sources?
255  // If so, adopt that one.
256  SelectNextLowerPriority(priority_map_satellites, active_priority_satellites);
257  }
258 }
259 
260 void CommBridge::MakeHDTFromHDM() {
261  // Here is the one place we try to create gHdt from gHdm and gVar,
262 
263 
264  if (!std::isnan(gHdm)) {
265  // Set gVar if needed from manual entry. gVar will be overwritten if
266  // WMM plugin is available
267  if (std::isnan(gVar) && (g_UserVar != 0.0)) gVar = g_UserVar;
268  gHdt = gHdm + gVar;
269  if (!std::isnan(gHdt)) {
270  if (gHdt < 0)
271  gHdt += 360.0;
272  else if (gHdt >= 360)
273  gHdt -= 360.0;
274 
275  m_watchdogs.heading_watchdog = gps_watchdog_timeout_ticks;
276  }
277  }
278 }
279 
280 void CommBridge::InitCommListeners() {
281  // Initialize the comm listeners
282  auto& msgbus = NavMsgBus::GetInstance();
283 
284  // GNSS Position Data PGN 129029
285  //----------------------------------
286  Nmea2000Msg n2k_msg_129029(static_cast<uint64_t>(129029));
287  listener_N2K_129029.Listen(n2k_msg_129029, this, EVT_N2K_129029);
288 
289  Bind(EVT_N2K_129029, [&](ObservedEvt ev) {
290  HandleN2K_129029(UnpackEvtPointer<Nmea2000Msg>(ev));
291  });
292 
293  // Position rapid PGN 129025
294  //-----------------------------
295  Nmea2000Msg n2k_msg_129025(static_cast<uint64_t>(129025));
296  listener_N2K_129025.Listen(n2k_msg_129025, this, EVT_N2K_129025);
297  Bind(EVT_N2K_129025, [&](ObservedEvt ev) {
298  HandleN2K_129025(UnpackEvtPointer<Nmea2000Msg>(ev));
299  });
300 
301  // COG SOG rapid PGN 129026
302  //-----------------------------
303  Nmea2000Msg n2k_msg_129026(static_cast<uint64_t>(129026));
304  listener_N2K_129026.Listen(n2k_msg_129026, this, EVT_N2K_129026);
305  Bind(EVT_N2K_129026, [&](ObservedEvt ev) {
306  HandleN2K_129026(UnpackEvtPointer<Nmea2000Msg>(ev));
307  });
308 
309  // Heading rapid PGN 127250
310  //-----------------------------
311  Nmea2000Msg n2k_msg_127250(static_cast<uint64_t>(127250));
312  listener_N2K_127250.Listen(n2k_msg_127250, this, EVT_N2K_127250);
313  Bind(EVT_N2K_127250, [&](ObservedEvt ev) {
314  HandleN2K_127250(UnpackEvtPointer<Nmea2000Msg>(ev));
315  });
316 
317  // GNSS Satellites in View PGN 129540
318  //-----------------------------
319  Nmea2000Msg n2k_msg_129540(static_cast<uint64_t>(129540));
320  listener_N2K_129540.Listen(n2k_msg_129540, this, EVT_N2K_129540);
321  Bind(EVT_N2K_129540, [&](ObservedEvt ev) {
322  HandleN2K_129540(UnpackEvtPointer<Nmea2000Msg>(ev));
323  });
324 
325 
326  // NMEA0183
327  // RMC
328  Nmea0183Msg n0183_msg_RMC("RMC");
329  listener_N0183_RMC.Listen(n0183_msg_RMC, this, EVT_N0183_RMC);
330 
331  Bind(EVT_N0183_RMC, [&](ObservedEvt ev) {
332  HandleN0183_RMC(UnpackEvtPointer<Nmea0183Msg>(ev));
333  });
334 
335  // HDT
336  Nmea0183Msg n0183_msg_HDT("HDT");
337  listener_N0183_HDT.Listen(n0183_msg_HDT, this, EVT_N0183_HDT);
338 
339  Bind(EVT_N0183_HDT, [&](ObservedEvt ev) {
340  HandleN0183_HDT(UnpackEvtPointer<Nmea0183Msg>(ev));
341  });
342 
343  // HDG
344  Nmea0183Msg n0183_msg_HDG("HDG");
345  listener_N0183_HDG.Listen(n0183_msg_HDG, this, EVT_N0183_HDG);
346 
347  Bind(EVT_N0183_HDG, [&](ObservedEvt ev) {
348  HandleN0183_HDG(UnpackEvtPointer<Nmea0183Msg>(ev));
349  });
350 
351  // HDM
352  Nmea0183Msg n0183_msg_HDM("HDM");
353  listener_N0183_HDM.Listen(n0183_msg_HDM, this, EVT_N0183_HDM);
354 
355  Bind(EVT_N0183_HDM, [&](ObservedEvt ev) {
356  HandleN0183_HDM(UnpackEvtPointer<Nmea0183Msg>(ev));
357  });
358 
359  // VTG
360  Nmea0183Msg n0183_msg_VTG("VTG");
361  listener_N0183_VTG.Listen(n0183_msg_VTG, this, EVT_N0183_VTG);
362 
363  Bind(EVT_N0183_VTG, [&](ObservedEvt ev) {
364  HandleN0183_VTG(UnpackEvtPointer<Nmea0183Msg>(ev));
365  });
366 
367  // GSV
368  Nmea0183Msg n0183_msg_GSV("GSV");
369  listener_N0183_GSV.Listen(n0183_msg_GSV, this, EVT_N0183_GSV);
370 
371  Bind(EVT_N0183_GSV, [&](ObservedEvt ev) {
372  HandleN0183_GSV(UnpackEvtPointer<Nmea0183Msg>(ev));
373  });
374 
375  // GGA
376  Nmea0183Msg n0183_msg_GGA("GGA");
377  listener_N0183_GGA.Listen(n0183_msg_GGA, this, EVT_N0183_GGA);
378 
379  Bind(EVT_N0183_GGA, [&](ObservedEvt ev) {
380  HandleN0183_GGA(UnpackEvtPointer<Nmea0183Msg>(ev));
381  });
382 
383  // GLL
384  Nmea0183Msg n0183_msg_GLL("GLL");
385  listener_N0183_GLL.Listen(n0183_msg_GLL, this, EVT_N0183_GLL);
386 
387  Bind(EVT_N0183_GLL, [&](ObservedEvt ev) {
388  HandleN0183_GLL(UnpackEvtPointer<Nmea0183Msg>(ev));
389  });
390 
391  // AIVDO
392  Nmea0183Msg n0183_msg_AIVDO("AIVDO");
393  listener_N0183_AIVDO.Listen(n0183_msg_AIVDO, this, EVT_N0183_AIVDO);
394 
395  Bind(EVT_N0183_AIVDO, [&](ObservedEvt ev) {
396  HandleN0183_AIVDO(UnpackEvtPointer<Nmea0183Msg>(ev));
397  });
398 
399  // SignalK
400  SignalkMsg sk_msg;
401  listener_SignalK.Listen(sk_msg, this, EVT_SIGNALK);
402 
403  Bind(EVT_SIGNALK, [&](ObservedEvt ev) {
404  HandleSignalK(UnpackEvtPointer<SignalkMsg>(ev));
405  });
406 
407 }
408 
409 void CommBridge::OnDriverStateChange(){
410 
411  // Reset all active priority states
412  PresetPriorityContainers();
413 
414 }
415 
416 std::string CommBridge::GetPriorityMap(std::unordered_map<std::string, int> &map){
417 
418  #define MAX_SOURCES 10
419  std::string sa[MAX_SOURCES];
420  std::string result;
421 
422  for (auto& it: map) {
423  if ((it.second >= 0) && (it.second < MAX_SOURCES))
424  sa[it.second] = it.first;
425  }
426 
427  //build the packed string result
428  for (int i=0 ; i < MAX_SOURCES ; i++){
429  if (sa[i].size()) {
430  result += sa[i];
431  result += "|";
432  }
433  }
434 
435  return result;
436 }
437 
438 
439 
440 std::vector<std::string> CommBridge::GetPriorityMaps(){
441 
442  std::vector<std::string> result;
443 
444  result.push_back(GetPriorityMap(priority_map_position));
445  result.push_back(GetPriorityMap(priority_map_velocity));
446  result.push_back(GetPriorityMap(priority_map_heading));
447  result.push_back(GetPriorityMap(priority_map_variation));
448  result.push_back(GetPriorityMap(priority_map_satellites));
449 
450 
451  return result;
452 }
453 
454 void CommBridge::ApplyPriorityMap(std::unordered_map<std::string, int>& priority_map, wxString &new_prio, int category){
455  priority_map.clear();
456  wxStringTokenizer tk(new_prio, "|");
457  int index = 0;
458  while (tk.HasMoreTokens()) {
459  wxString entry = tk.GetNextToken();
460  std::string s_entry(entry.c_str());
461  priority_map[s_entry] = index;
462  index++;
463  }
464 }
465 
466 
467 void CommBridge::ApplyPriorityMaps(std::vector<std::string> new_maps){
468 
469  wxString new_prio_string;
470 
471  new_prio_string = wxString( new_maps[0].c_str());
472  ApplyPriorityMap(priority_map_position, new_prio_string, 0);
473 
474  new_prio_string = wxString( new_maps[1].c_str());
475  ApplyPriorityMap(priority_map_velocity, new_prio_string, 1);
476 
477  new_prio_string = wxString( new_maps[2].c_str());
478  ApplyPriorityMap(priority_map_heading, new_prio_string, 2);
479 
480  new_prio_string = wxString( new_maps[3].c_str());
481  ApplyPriorityMap(priority_map_variation, new_prio_string, 3);
482 
483  new_prio_string = wxString( new_maps[4].c_str());
484  ApplyPriorityMap(priority_map_satellites, new_prio_string, 4);
485 }
486 
487 void CommBridge::PresetPriorityContainer(PriorityContainer &pc,
488  const std::unordered_map<std::string, int> &priority_map){
489  // Extract some info from the preloaded map
490  // Find the key corresponding to priority 0, the highest
491  std::string key0;
492  for (auto& it: priority_map) {
493  if (it.second == 0)
494  key0 = it.first;
495  }
496 
497  wxString this_key(key0.c_str());
498  wxStringTokenizer tkz(this_key, _T(";"));
499  wxString wxs_this_source = tkz.GetNextToken();
500  std::string source = wxs_this_source.ToStdString();
501  wxString wxs_this_identifier = tkz.GetNextToken();
502  std::string this_identifier = wxs_this_identifier.ToStdString();
503 
504  wxStringTokenizer tka(wxs_this_source, _T(":"));
505  tka.GetNextToken();
506  int source_address = atoi(tka.GetNextToken().ToStdString().c_str());
507 
508  pc.active_priority = 0;
509  pc.active_source = source;
510  pc.active_identifier = this_identifier;
511  pc.active_source_address = source_address;
512 }
513 
514 
515 void CommBridge::PresetPriorityContainers(){
516  PresetPriorityContainer(active_priority_position, priority_map_position);
517  PresetPriorityContainer(active_priority_velocity, priority_map_velocity);
518  PresetPriorityContainer(active_priority_heading, priority_map_heading);
519  PresetPriorityContainer(active_priority_variation, priority_map_variation);
520  PresetPriorityContainer(active_priority_satellites, priority_map_satellites);
521 }
522 
523 
524 bool CommBridge::HandleN2K_129029(std::shared_ptr<const Nmea2000Msg> n2k_msg) {
525 
526  std::vector<unsigned char> v = n2k_msg->payload;
527 
528  // extract and verify PGN
529  uint64_t pgn = 0;
530  unsigned char *c = (unsigned char *)&pgn;
531  *c++ = v.at(3);
532  *c++ = v.at(4);
533  *c++ = v.at(5);
534 
535  NavData temp_data;
536  ClearNavData(temp_data);
537 
538  if (!m_decoder.DecodePGN129029(v, temp_data))
539  return false;
540 
541  int valid_flag = 0;
542  if (!N2kIsNA(temp_data.gLat) && !N2kIsNA(temp_data.gLon)){
543  if (EvalPriority(n2k_msg, active_priority_position, priority_map_position)) {
544  gLat = temp_data.gLat;
545  gLon = temp_data.gLon;
546  valid_flag += POS_UPDATE;
547  valid_flag += POS_VALID;
548  m_watchdogs.position_watchdog = gps_watchdog_timeout_ticks;
549  n_LogWatchdogPeriod = N_ACTIVE_LOG_WATCHDOG; // allow faster dog log
550  }
551  }
552 
553  if (temp_data.n_satellites >= 0){
554  if (EvalPriority(n2k_msg, active_priority_satellites, priority_map_satellites)) {
555  g_SatsInView = temp_data.n_satellites;
556  g_bSatValid = true;
557  m_watchdogs.satellite_watchdog = sat_watchdog_timeout_ticks;
558  }
559  }
560 
561  SendBasicNavdata(valid_flag);
562  return true;
563 }
564 
565 bool CommBridge::HandleN2K_129025(std::shared_ptr<const Nmea2000Msg> n2k_msg) {
566 
567  std::vector<unsigned char> v = n2k_msg->payload;
568 
569  NavData temp_data;
570  ClearNavData(temp_data);
571 
572  if (!m_decoder.DecodePGN129025(v, temp_data))
573  return false;
574 
575  int valid_flag = 0;
576  if (!N2kIsNA(temp_data.gLat) && !N2kIsNA(temp_data.gLon)){
577  if (EvalPriority(n2k_msg, active_priority_position, priority_map_position)) {
578  gLat = temp_data.gLat;
579  gLon = temp_data.gLon;
580  valid_flag += POS_UPDATE;
581  valid_flag += POS_VALID;
582  m_watchdogs.position_watchdog = gps_watchdog_timeout_ticks;
583  n_LogWatchdogPeriod = N_ACTIVE_LOG_WATCHDOG; // allow faster dog log
584  }
585  }
586  //FIXME (dave) How to notify user of errors?
587  else{
588  }
589 
590  SendBasicNavdata(valid_flag);
591  return true;
592 }
593 
594 bool CommBridge::HandleN2K_129026(std::shared_ptr<const Nmea2000Msg> n2k_msg) {
595 
596  std::vector<unsigned char> v = n2k_msg->payload;
597 
598  NavData temp_data;
599  ClearNavData(temp_data);
600 
601  if (!m_decoder.DecodePGN129026(v, temp_data))
602  return false;
603 
604  int valid_flag = 0;
605  if (!N2kIsNA(temp_data.gSog)){ // gCog as reported by net may be NaN, but OK
606  if (EvalPriority(n2k_msg, active_priority_velocity, priority_map_velocity)) {
607  gSog = MS2KNOTS(temp_data.gSog);
608  valid_flag += SOG_UPDATE;
609 
610  if (N2kIsNA(temp_data.gCog))
611  gCog = NAN;
612  else
613  gCog = GeodesicRadToDeg(temp_data.gCog);
614  valid_flag += COG_UPDATE;
615  m_watchdogs.velocity_watchdog = gps_watchdog_timeout_ticks;
616  }
617  }
618  else{
619  }
620 
621  SendBasicNavdata(valid_flag);
622  return true;
623 }
624 
625 bool CommBridge::HandleN2K_127250(std::shared_ptr<const Nmea2000Msg> n2k_msg) {
626 
627  std::vector<unsigned char> v = n2k_msg->payload;
628 
629  NavData temp_data;
630  ClearNavData(temp_data);
631 
632  if (!m_decoder.DecodePGN127250(v, temp_data))
633  return false;
634 
635  int valid_flag = 0;
636  if (!N2kIsNA(temp_data.gVar)){
637  if (EvalPriority(n2k_msg, active_priority_variation, priority_map_variation)) {
638  gVar = GeodesicRadToDeg(temp_data.gVar);
639  valid_flag += VAR_UPDATE;
640  m_watchdogs.variation_watchdog = gps_watchdog_timeout_ticks;
641  }
642  }
643 
644  if (!N2kIsNA(temp_data.gHdt)){
645  if (EvalPriority(n2k_msg, active_priority_heading, priority_map_heading)) {
646  gHdt = GeodesicRadToDeg(temp_data.gHdt);
647  valid_flag += HDT_UPDATE;
648  m_watchdogs.heading_watchdog = gps_watchdog_timeout_ticks;
649  }
650  }
651 
652  if (!N2kIsNA(temp_data.gHdm)){
653  gHdm = GeodesicRadToDeg(temp_data.gHdm);
654  if (EvalPriority(n2k_msg, active_priority_heading, priority_map_heading)) {
655  MakeHDTFromHDM();
656  valid_flag += HDT_UPDATE;
657  if(!std::isnan(gHdt))
658  m_watchdogs.heading_watchdog = gps_watchdog_timeout_ticks;
659  }
660  }
661 
662  SendBasicNavdata(valid_flag);
663  return true;
664 }
665 
666 bool CommBridge::HandleN2K_129540(std::shared_ptr<const Nmea2000Msg> n2k_msg) {
667 
668  std::vector<unsigned char> v = n2k_msg->payload;
669 
670  NavData temp_data;
671  ClearNavData(temp_data);
672 
673  if (!m_decoder.DecodePGN129540(v, temp_data))
674  return false;
675 
676  int valid_flag = 0;
677  if (temp_data.n_satellites >= 0){
678  if (EvalPriority(n2k_msg, active_priority_satellites, priority_map_satellites)) {
679  g_SatsInView = temp_data.n_satellites;
680  g_bSatValid = true;
681  m_watchdogs.satellite_watchdog = sat_watchdog_timeout_ticks;
682  }
683  }
684 
685  return true;
686 }
687 
688 bool CommBridge::HandleN0183_RMC(std::shared_ptr<const Nmea0183Msg> n0183_msg) {
689  std::string str = n0183_msg->payload;
690 
691  NavData temp_data;
692  ClearNavData(temp_data);
693 
694  bool bvalid = true;
695  if (!m_decoder.DecodeRMC(str, temp_data))
696  bvalid = false;
697 
698  int valid_flag = 0;
699  if (EvalPriority(n0183_msg, active_priority_position, priority_map_position)) {
700  if(bvalid) {
701  gLat = temp_data.gLat;
702  gLon = temp_data.gLon;
703  valid_flag += POS_VALID;
704  m_watchdogs.position_watchdog = gps_watchdog_timeout_ticks;
705  n_LogWatchdogPeriod = N_ACTIVE_LOG_WATCHDOG; // allow faster dog log
706  }
707  valid_flag += POS_UPDATE;
708  }
709 
710  if (EvalPriority(n0183_msg, active_priority_velocity, priority_map_velocity)) {
711  if(bvalid) {
712  gSog = temp_data.gSog;
713  valid_flag += SOG_UPDATE;
714  gCog = temp_data.gCog;
715  valid_flag += COG_UPDATE;
716  m_watchdogs.velocity_watchdog = gps_watchdog_timeout_ticks;
717  }
718  }
719 
720  if (!std::isnan(temp_data.gVar)){
721  if (EvalPriority(n0183_msg, active_priority_variation, priority_map_variation)) {
722  if(bvalid) {
723  gVar = temp_data.gVar;
724  valid_flag += VAR_UPDATE;
725  m_watchdogs.variation_watchdog = gps_watchdog_timeout_ticks;
726  }
727  }
728  }
729 
730  SendBasicNavdata(valid_flag);
731  return true;
732 }
733 
734 bool CommBridge::HandleN0183_HDT(std::shared_ptr<const Nmea0183Msg> n0183_msg) {
735  std::string str = n0183_msg->payload;
736  NavData temp_data;
737  ClearNavData(temp_data);
738 
739  if (!m_decoder.DecodeHDT(str, temp_data))
740  return false;
741 
742  int valid_flag = 0;
743  if (EvalPriority(n0183_msg, active_priority_heading, priority_map_heading)) {
744  gHdt = temp_data.gHdt;
745  valid_flag += HDT_UPDATE;
746  m_watchdogs.heading_watchdog = gps_watchdog_timeout_ticks;
747  }
748 
749 
750  SendBasicNavdata(valid_flag);
751  return true;
752 }
753 
754 bool CommBridge::HandleN0183_HDG(std::shared_ptr<const Nmea0183Msg> n0183_msg) {
755  std::string str = n0183_msg->payload;
756  NavData temp_data;
757  ClearNavData(temp_data);
758 
759  if (!m_decoder.DecodeHDG(str, temp_data)) return false;
760 
761  int valid_flag = 0;
762 
763  bool bHDM = false;
764  if (EvalPriority(n0183_msg, active_priority_heading, priority_map_heading)) {
765  gHdm = temp_data.gHdm;
766  m_watchdogs.heading_watchdog = gps_watchdog_timeout_ticks;
767  bHDM = true;
768  }
769 
770  if (!std::isnan(temp_data.gVar)){
771  if (EvalPriority(n0183_msg, active_priority_variation, priority_map_variation)) {
772  gVar = temp_data.gVar;
773  valid_flag += VAR_UPDATE;
774  m_watchdogs.variation_watchdog = gps_watchdog_timeout_ticks;
775  }
776  }
777 
778  if (bHDM)
779  MakeHDTFromHDM();
780 
781  SendBasicNavdata(valid_flag);
782  return true;
783 }
784 
785 bool CommBridge::HandleN0183_HDM(std::shared_ptr<const Nmea0183Msg> n0183_msg) {
786  std::string str = n0183_msg->payload;
787  NavData temp_data;
788  ClearNavData(temp_data);
789 
790  if (!m_decoder.DecodeHDM(str, temp_data)) return false;
791 
792  int valid_flag = 0;
793 
794  if (EvalPriority(n0183_msg, active_priority_heading, priority_map_heading)) {
795  gHdm = temp_data.gHdm;
796  MakeHDTFromHDM();
797  valid_flag += HDT_UPDATE;
798  m_watchdogs.heading_watchdog = gps_watchdog_timeout_ticks;
799  }
800 
801  SendBasicNavdata(valid_flag);
802  return true;
803 }
804 
805 bool CommBridge::HandleN0183_VTG(std::shared_ptr<const Nmea0183Msg> n0183_msg) {
806  std::string str = n0183_msg->payload;
807  NavData temp_data;
808  ClearNavData(temp_data);
809 
810  if (!m_decoder.DecodeVTG(str, temp_data)) return false;
811 
812  int valid_flag = 0;
813 
814  if (EvalPriority(n0183_msg, active_priority_velocity, priority_map_velocity)) {
815  gSog = temp_data.gSog;
816  valid_flag += SOG_UPDATE;
817  gCog = temp_data.gCog;
818  valid_flag += COG_UPDATE;
819  m_watchdogs.velocity_watchdog = gps_watchdog_timeout_ticks;
820  }
821 
822  SendBasicNavdata(valid_flag);
823  return true;
824 }
825 
826 bool CommBridge::HandleN0183_GSV(std::shared_ptr<const Nmea0183Msg> n0183_msg) {
827  std::string str = n0183_msg->payload;
828  NavData temp_data;
829  ClearNavData(temp_data);
830 
831  if (!m_decoder.DecodeGSV(str, temp_data)) return false;
832 
833  int valid_flag = 0;
834 
835  if (EvalPriority(n0183_msg, active_priority_satellites, priority_map_satellites)) {
836  if (temp_data.n_satellites >= 0){
837  g_SatsInView = temp_data.n_satellites;
838  g_bSatValid = true;
839 
840  m_watchdogs.satellite_watchdog = sat_watchdog_timeout_ticks;
841  }
842  }
843 
844  SendBasicNavdata(valid_flag);
845  return true;
846 }
847 
848 bool CommBridge::HandleN0183_GGA(std::shared_ptr<const Nmea0183Msg> n0183_msg) {
849  std::string str = n0183_msg->payload;
850  NavData temp_data;
851  ClearNavData(temp_data);
852 
853  bool bvalid = true;
854  if (!m_decoder.DecodeGGA(str, temp_data))
855  bvalid = false;;
856 
857  int valid_flag = 0;
858 
859  if (EvalPriority(n0183_msg, active_priority_position, priority_map_position)) {
860  if (bvalid) {
861  gLat = temp_data.gLat;
862  gLon = temp_data.gLon;
863  valid_flag += POS_VALID;
864  m_watchdogs.position_watchdog = gps_watchdog_timeout_ticks;
865  n_LogWatchdogPeriod = N_ACTIVE_LOG_WATCHDOG; // allow faster dog log
866  }
867  valid_flag += POS_UPDATE;
868  }
869 
870  if (EvalPriority(n0183_msg, active_priority_satellites, priority_map_satellites)) {
871  if (bvalid) {
872  if (temp_data.n_satellites >= 0) {
873  g_SatsInView = temp_data.n_satellites;
874  g_bSatValid = true;
875 
876  m_watchdogs.satellite_watchdog = sat_watchdog_timeout_ticks;
877  }
878  }
879  }
880 
881  SendBasicNavdata(valid_flag);
882  return true;
883 }
884 
885 bool CommBridge::HandleN0183_GLL(std::shared_ptr<const Nmea0183Msg> n0183_msg) {
886  std::string str = n0183_msg->payload;
887  NavData temp_data;
888  ClearNavData(temp_data);
889 
890  bool bvalid = true;
891  if (!m_decoder.DecodeGLL(str, temp_data))
892  bvalid = false;
893 
894  int valid_flag = 0;
895 
896  if (EvalPriority(n0183_msg, active_priority_position, priority_map_position)) {
897  if (bvalid) {
898  gLat = temp_data.gLat;
899  gLon = temp_data.gLon;
900  valid_flag += POS_VALID;
901  m_watchdogs.position_watchdog = gps_watchdog_timeout_ticks;
902  n_LogWatchdogPeriod = N_ACTIVE_LOG_WATCHDOG; // allow faster dog log
903  }
904  valid_flag += POS_UPDATE;
905  }
906 
907  SendBasicNavdata(valid_flag);
908  return true;
909 }
910 
911 bool CommBridge::HandleN0183_AIVDO(
912  std::shared_ptr<const Nmea0183Msg> n0183_msg) {
913  std::string str = n0183_msg->payload;
914 
915  GenericPosDatEx gpd;
916  wxString sentence(str.c_str());
917 
918  int valid_flag = 0;
919 
920  AisError nerr = AIS_GENERIC_ERROR;
921  nerr = DecodeSingleVDO(sentence, &gpd);
922 
923  if (nerr == AIS_NoError) {
924 
925  if (!std::isnan(gpd.kLat) && !std::isnan(gpd.kLon)){
926  if (EvalPriority(n0183_msg, active_priority_position, priority_map_position)) {
927  gLat = gpd.kLat;
928  gLon = gpd.kLon;
929  valid_flag += POS_UPDATE;
930  valid_flag += POS_VALID;
931  m_watchdogs.position_watchdog = gps_watchdog_timeout_ticks;
932  n_LogWatchdogPeriod = N_ACTIVE_LOG_WATCHDOG; // allow faster dog log
933  }
934  }
935 
936  if (!std::isnan(gpd.kCog) && !std::isnan(gpd.kSog)){
937  if (EvalPriority(n0183_msg, active_priority_velocity, priority_map_velocity)) {
938  gSog = gpd.kSog;
939  valid_flag += SOG_UPDATE;
940  gCog = gpd.kCog;
941  valid_flag += COG_UPDATE;
942  m_watchdogs.velocity_watchdog = gps_watchdog_timeout_ticks;
943  }
944  }
945 
946  if (!std::isnan(gpd.kHdt)) {
947  if (EvalPriority(n0183_msg, active_priority_heading, priority_map_heading)) {
948  gHdt = gpd.kHdt;
949  valid_flag += HDT_UPDATE;
950  m_watchdogs.heading_watchdog = gps_watchdog_timeout_ticks;
951  }
952  }
953 
954  SendBasicNavdata(valid_flag);
955  }
956  return true;
957 }
958 
959 bool CommBridge::HandleSignalK(std::shared_ptr<const SignalkMsg> sK_msg){
960  std::string str = sK_msg->raw_message;
961 
962  // Here we ignore messages involving contexts other than ownship
963  if (sK_msg->context_self != sK_msg->context)
964  return false;
965 
966  g_ownshipMMSI_SK = sK_msg->context_self;
967 
968  NavData temp_data;
969  ClearNavData(temp_data);
970 
971  if (!m_decoder.DecodeSignalK(str, temp_data)) return false;
972 
973  int valid_flag = 0;
974 
975  if (!std::isnan(temp_data.gLat) && !std::isnan(temp_data.gLon)){
976  if (EvalPriority(sK_msg, active_priority_position, priority_map_position)) {
977  gLat = temp_data.gLat;
978  gLon = temp_data.gLon;
979  valid_flag += POS_UPDATE;
980  valid_flag += POS_VALID;
981  m_watchdogs.position_watchdog = gps_watchdog_timeout_ticks;
982  n_LogWatchdogPeriod = N_ACTIVE_LOG_WATCHDOG; // allow faster dog log
983  }
984  }
985 
986  if (!std::isnan(temp_data.gSog)){
987  if (EvalPriority(sK_msg, active_priority_velocity, priority_map_velocity)) {
988  gSog = temp_data.gSog;
989  valid_flag += SOG_UPDATE;
990  if((gSog > 0.05) && !std::isnan(temp_data.gCog)){
991  gCog = temp_data.gCog;
992  valid_flag += COG_UPDATE;
993  }
994  m_watchdogs.velocity_watchdog = gps_watchdog_timeout_ticks;
995  }
996  }
997 
998  if (!std::isnan(temp_data.gHdt)){
999  if (EvalPriority(sK_msg, active_priority_heading, priority_map_heading)) {
1000  gHdt = temp_data.gHdt;
1001  valid_flag += HDT_UPDATE;
1002  m_watchdogs.heading_watchdog = gps_watchdog_timeout_ticks;
1003  }
1004  }
1005 
1006  if (!std::isnan(temp_data.gHdm)){
1007  if (EvalPriority(sK_msg, active_priority_heading, priority_map_heading)) {
1008  gHdm = temp_data.gHdm;
1009  MakeHDTFromHDM();
1010  valid_flag += HDT_UPDATE;
1011  m_watchdogs.heading_watchdog = gps_watchdog_timeout_ticks;
1012  }
1013  }
1014 
1015  if (!std::isnan(temp_data.gVar)){
1016  if (EvalPriority(sK_msg, active_priority_variation, priority_map_variation)) {
1017  gVar = temp_data.gVar;
1018  valid_flag += VAR_UPDATE;
1019  m_watchdogs.variation_watchdog = gps_watchdog_timeout_ticks;
1020  }
1021  }
1022 
1023  bool sat_update = false;
1024  if (temp_data.n_satellites > 0){
1025  if (EvalPriority(sK_msg, active_priority_satellites, priority_map_satellites)) {
1026  g_SatsInView = temp_data.n_satellites;
1027  g_bSatValid = true;
1028  sat_update = true;
1029  m_watchdogs.satellite_watchdog = sat_watchdog_timeout_ticks;
1030  }
1031  }
1032 
1033  if (g_pMUX && g_pMUX->IsLogActive()) {
1034  std::string logmsg = "Self: ";
1035  std::string content;
1036  if (valid_flag & POS_UPDATE) content += "POS;";
1037  if (valid_flag & POS_VALID) content += "POS_Valid;";
1038  if (valid_flag & SOG_UPDATE) content += "SOG;";
1039  if (valid_flag & COG_UPDATE) content += "COG;";
1040  if (valid_flag & HDT_UPDATE) content += "HDT;";
1041  if (valid_flag & VAR_UPDATE) content += "VAR;";
1042  if (sat_update) content += "SAT;";
1043 
1044  if (content.empty())
1045  content = "Not used by OCPN, maybe passed to plugins";
1046 
1047  logmsg += content;
1048  std::string source = sK_msg->source->to_string();
1049  g_pMUX->LogInputMessage( logmsg, source, false, false);
1050  }
1051 
1052  SendBasicNavdata(valid_flag);
1053  return true;
1054 }
1055 
1056 
1057 void CommBridge::InitializePriorityContainers(){
1058  active_priority_position.active_priority = 0;
1059  active_priority_velocity.active_priority = 0;
1060  active_priority_heading.active_priority = 0;
1061  active_priority_variation.active_priority = 0;
1062  active_priority_satellites.active_priority = 0;
1063 
1064  active_priority_position.active_source.clear();
1065  active_priority_velocity.active_source.clear();
1066  active_priority_heading.active_source.clear();
1067  active_priority_variation.active_source.clear();
1068  active_priority_satellites.active_source.clear();
1069 
1070  active_priority_position.active_identifier.clear();
1071  active_priority_velocity.active_identifier.clear();
1072  active_priority_heading.active_identifier.clear();
1073  active_priority_variation.active_identifier.clear();
1074  active_priority_satellites.active_identifier.clear();
1075 
1076  active_priority_position.pcclass = "position";
1077  active_priority_velocity.pcclass = "velocity";
1078  active_priority_heading.pcclass = "heading";
1079  active_priority_variation.pcclass = "variation";
1080  active_priority_satellites.pcclass = "satellites";
1081 
1082  active_priority_position.active_source_address = -1;
1083  active_priority_velocity.active_source_address = -1;
1084  active_priority_heading.active_source_address = -1;
1085  active_priority_variation.active_source_address = -1;
1086  active_priority_satellites.active_source_address = -1;
1087 
1088  active_priority_void.active_priority = -1;
1089 
1090  }
1091 
1092 void CommBridge::ClearPriorityMaps(){
1093  priority_map_position.clear();
1094  priority_map_velocity.clear();
1095  priority_map_heading.clear();
1096  priority_map_variation.clear();
1097  priority_map_satellites.clear();
1098 }
1099 
1100 PriorityContainer& CommBridge::GetPriorityContainer(const std::string category){
1101  if (!category.compare("position"))
1102  return active_priority_position;
1103  else if (!category.compare("velocity"))
1104  return active_priority_velocity;
1105  else if (!category.compare("heading"))
1106  return active_priority_heading;
1107  else if (!category.compare("variation"))
1108  return active_priority_variation;
1109  else if (!category.compare("satellites"))
1110  return active_priority_satellites;
1111  else
1112  return active_priority_void;
1113 }
1114 
1115 void CommBridge::UpdateAndApplyMaps(std::vector<std::string> new_maps){
1116  ApplyPriorityMaps(new_maps);
1117  SaveConfig();
1118  PresetPriorityContainers();
1119 }
1120 
1121 
1122 bool CommBridge::LoadConfig( void )
1123 {
1124  if( TheBaseConfig() ) {
1125  TheBaseConfig()->SetPath("/Settings/CommPriority");
1126 
1127  std::vector<std::string> new_maps;
1128  std::string s_prio;
1129  wxString pri_string;
1130 
1131  TheBaseConfig()->Read("PriorityPosition", &pri_string );
1132  s_prio = std::string(pri_string.c_str());
1133  new_maps.push_back(s_prio);
1134 
1135  TheBaseConfig()->Read("PriorityVelocity", &pri_string );
1136  s_prio = std::string(pri_string.c_str());
1137  new_maps.push_back(s_prio);
1138 
1139  TheBaseConfig()->Read("PriorityHeading", &pri_string );
1140  s_prio = std::string(pri_string.c_str());
1141  new_maps.push_back(s_prio);
1142 
1143  TheBaseConfig()->Read("PriorityVariation", &pri_string );
1144  s_prio = std::string(pri_string.c_str());
1145  new_maps.push_back(s_prio);
1146 
1147  TheBaseConfig()->Read("PrioritySatellites", &pri_string );
1148  s_prio = std::string(pri_string.c_str());
1149  new_maps.push_back(s_prio);
1150 
1151  ApplyPriorityMaps(new_maps);
1152  }
1153  return true;
1154 }
1155 
1156 bool CommBridge::SaveConfig( void )
1157 {
1158  if( TheBaseConfig() ) {
1159  TheBaseConfig()->SetPath("/Settings/CommPriority");
1160 
1161  wxString pri_string;
1162  pri_string = wxString(GetPriorityMap(priority_map_position).c_str());
1163  TheBaseConfig()->Write( "PriorityPosition", pri_string );
1164 
1165  pri_string = wxString(GetPriorityMap(priority_map_velocity).c_str());
1166  TheBaseConfig()->Write( "PriorityVelocity", pri_string );
1167 
1168  pri_string = wxString(GetPriorityMap(priority_map_heading).c_str());
1169  TheBaseConfig()->Write( "PriorityHeading", pri_string );
1170 
1171  pri_string = wxString(GetPriorityMap(priority_map_variation).c_str());
1172  TheBaseConfig()->Write( "PriorityVariation", pri_string );
1173 
1174  pri_string = wxString(GetPriorityMap(priority_map_satellites).c_str());
1175  TheBaseConfig()->Write( "PrioritySatellites", pri_string );
1176  }
1177 
1178  return true;
1179 }
1180 
1181 
1182 std::string CommBridge::GetPriorityKey(std::shared_ptr <const NavMsg> msg){
1183  std::string source = msg->source->to_string();
1184  std::string listener_key = msg->key();
1185 
1186 
1187  std::string this_identifier;
1188  std::string this_address("0");
1189  if(msg->bus == NavAddr::Bus::N0183){
1190  auto msg_0183 = std::dynamic_pointer_cast<const Nmea0183Msg>(msg);
1191  if (msg_0183){
1192  this_identifier = msg_0183->talker;
1193  this_identifier += msg_0183->type;
1194  }
1195  }
1196  else if(msg->bus == NavAddr::Bus::N2000){
1197  auto msg_n2k = std::dynamic_pointer_cast<const Nmea2000Msg>(msg);
1198  if (msg_n2k){
1199  this_identifier = msg_n2k->PGN.to_string();
1200  unsigned char n_source = msg_n2k->payload.at(7);
1201  char ss[4];
1202  sprintf(ss,"%d",n_source);
1203  this_address = std::string(ss);
1204  }
1205  }
1206  else if(msg->bus == NavAddr::Bus::Signalk){
1207  auto msg_sk = std::dynamic_pointer_cast<const SignalkMsg>(msg);
1208  if (msg_sk){
1209  auto addr_sk = std::static_pointer_cast<const NavAddrSignalK>(msg->source);
1210  source = addr_sk->to_string();
1211  this_identifier = "signalK";
1212  this_address = msg->source->iface;
1213  }
1214  }
1215 
1216 
1217  return source + ":" + this_address + ";" + this_identifier;
1218 
1219 }
1220 
1221 bool CommBridge::EvalPriority(std::shared_ptr <const NavMsg> msg,
1222  PriorityContainer& active_priority,
1223  std::unordered_map<std::string, int>& priority_map) {
1224 
1225  std::string this_key = GetPriorityKey(msg);
1226  if (debug_priority) printf("This Key: %s\n", this_key.c_str());
1227 
1228  // Pull some identifiers from the unique key
1229  wxStringTokenizer tkz(this_key, _T(";"));
1230  wxString wxs_this_source = tkz.GetNextToken();
1231  std::string source = wxs_this_source.ToStdString();
1232  wxString wxs_this_identifier = tkz.GetNextToken();
1233  std::string this_identifier = wxs_this_identifier.ToStdString();
1234 
1235  wxStringTokenizer tka(wxs_this_source, _T(":"));
1236  tka.GetNextToken();
1237  int source_address = atoi(tka.GetNextToken().ToStdString().c_str());
1238 
1239  // Fetch the established priority for the message
1240  int this_priority;
1241 
1242  auto it = priority_map.find(this_key);
1243  if (it == priority_map.end()) {
1244  // Not found, so make it default highest priority
1245  priority_map[this_key] = 0;
1246  }
1247 
1248  this_priority = priority_map[this_key];
1249 
1250  for (auto it = priority_map.begin(); it != priority_map.end(); it++) {
1251  if (debug_priority) printf(" priority_map: %s %d\n", it->first.c_str(), it->second);
1252  }
1253 
1254  //Incoming message priority lower than currently active priority?
1255  // If so, drop the message
1256  if (this_priority > active_priority.active_priority){
1257  if (debug_priority) printf(" Drop low priority: %s %d %d \n", source.c_str(), this_priority,
1258  active_priority.active_priority);
1259  return false;
1260  }
1261 
1262  // A channel returning, after being watchdogged out.
1263  if (this_priority < active_priority.active_priority){
1264  active_priority.active_priority = this_priority;
1265  active_priority.active_source = source;
1266  active_priority.active_identifier = this_identifier;
1267  active_priority.active_source_address = source_address;
1268 
1269  if (debug_priority) printf(" Restoring high priority: %s %d\n", source.c_str(), this_priority);
1270  return true;
1271  }
1272 
1273 
1274  // Do we see two sources with the same priority?
1275  // If so, we take the first one, and deprioritize this one.
1276 
1277  if (active_priority.active_source.size()){
1278 
1279  if (debug_priority) printf("source: %s\n", source.c_str());
1280  if (debug_priority) printf("active_source: %s\n", active_priority.active_source.c_str());
1281 
1282  if (source.compare(active_priority.active_source) != 0){
1283 
1284  // Auto adjust the priority of the this message down
1285  //First, find the lowest priority in use in this map
1286  int lowest_priority = -10; // safe enough
1287  for (auto it = priority_map.begin(); it != priority_map.end(); it++) {
1288  if (it->second > lowest_priority)
1289  lowest_priority = it->second;
1290  }
1291 
1292  priority_map[this_key] = lowest_priority + 1;
1293  if (debug_priority) printf(" Lowering priority A: %s :%d\n", source.c_str(), priority_map[this_key]);
1294  return false;
1295  }
1296  }
1297 
1298  // For N0183 message, has the Mnemonic (id) changed?
1299  // Example: RMC and AIVDO from same source.
1300 
1301 
1302  if(msg->bus == NavAddr::Bus::N0183){
1303  auto msg_0183 = std::dynamic_pointer_cast<const Nmea0183Msg>(msg);
1304  if (msg_0183){
1305  if (active_priority.active_identifier.size()){
1306 
1307  if (debug_priority) printf("this_identifier: %s\n", this_identifier.c_str());
1308  if (debug_priority) printf("active_priority.active_identifier: %s\n", active_priority.active_identifier.c_str());
1309 
1310  if (this_identifier.compare(active_priority.active_identifier) != 0){
1311  // if necessary, auto adjust the priority of the this message down
1312  //and drop it
1313  if (priority_map[this_key] == active_priority.active_priority){
1314  int lowest_priority = -10; // safe enough
1315  for (auto it = priority_map.begin(); it != priority_map.end(); it++) {
1316  if (it->second > lowest_priority)
1317  lowest_priority = it->second;
1318  }
1319 
1320  priority_map[this_key] = lowest_priority + 1;
1321  if (debug_priority) printf(" Lowering priority B: %s :%d\n", source.c_str(), priority_map[this_key]);
1322  }
1323 
1324  return false;
1325  }
1326  }
1327  }
1328  }
1329 
1330  // Similar for n2k PGN...
1331 
1332  else if(msg->bus == NavAddr::Bus::N2000){
1333  auto msg_n2k = std::dynamic_pointer_cast<const Nmea2000Msg>(msg);
1334  if (msg_n2k){
1335  if (active_priority.active_identifier.size()){
1336  if (this_identifier.compare(active_priority.active_identifier) != 0){
1337  // if necessary, auto adjust the priority of the this message down
1338  //and drop it
1339  if (priority_map[this_key] == active_priority.active_priority){
1340  int lowest_priority = -10; // safe enough
1341  for (auto it = priority_map.begin(); it != priority_map.end(); it++) {
1342  if (it->second > lowest_priority)
1343  lowest_priority = it->second;
1344  }
1345 
1346  priority_map[this_key] = lowest_priority + 1;
1347  if (debug_priority) printf(" Lowering priority: %s :%d\n", source.c_str(), priority_map[this_key]);
1348  }
1349 
1350  return false;
1351  }
1352  }
1353  }
1354  }
1355 
1356 
1357  // Update the records
1358  active_priority.active_source = source;
1359  active_priority.active_identifier = this_identifier;
1360  active_priority.active_source_address = source_address;
1361  if (debug_priority) printf(" Accepting high priority: %s %d\n", source.c_str(), this_priority);
1362 
1363  return true;
1364 }
void Notify(std::shared_ptr< const AppMsg > msg)
Send message to everyone listening to given message type.
A regular Nmea0183 message.
Definition: comm_navmsg.h:250
See: https://github.com/OpenCPN/OpenCPN/issues/2729#issuecomment-1179506343.
Definition: comm_navmsg.h:220
void Listen(const std::string &key, wxEvtHandler *listener, wxEventType evt)
Set object to send wxEventType ev to listener on changes in key.
Definition: observable.cpp:98
Adds a std::shared<void> element to wxCommandEvent.
Definition: ocpn_plugin.h:1652
A parsed SignalK message over ipv4.
Definition: comm_navmsg.h:319
wxDEFINE_EVENT(REST_IO_EVT, ObservedEvt)
Event from IO thread to main.