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