35#include <wx/tokenzr.h>
36#include <wx/fileconf.h>
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"
68wxDEFINE_EVENT(EVT_DRIVER_CHANGE, wxCommandEvent);
72#define N_ACTIVE_LOG_WATCHDOG 300
76bool debug_priority = 0;
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));
101static inline double GeodesicRadToDeg(
double rads) {
102 return rads * 180.0 / M_PI;
105static inline double MS2KNOTS(
double ms) {
return ms * 1.9438444924406; }
110EVT_TIMER(WATCHDOG_TIMER, CommBridge::OnWatchdogTimer)
115CommBridge::~CommBridge() {}
117bool CommBridge::Initialize() {
118 InitializePriorityContainers();
122 PresetPriorityContainers();
127 m_watchdog_timer.SetOwner(
this, WATCHDOG_TIMER);
128 m_watchdog_timer.Start(1000, wxTIMER_CONTINUOUS);
129 n_LogWatchdogPeriod = 3600;
136 driver_change_listener.
Listen(
137 CommDriverRegistry::GetInstance().evt_driverlist_change.key,
this,
139 Bind(EVT_DRIVER_CHANGE, [&](wxCommandEvent ev) { OnDriverStateChange(); });
144void CommBridge::PresetWatchdogs() {
145 m_watchdogs.position_watchdog =
147 m_watchdogs.velocity_watchdog = 20;
148 m_watchdogs.variation_watchdog = 20;
149 m_watchdogs.heading_watchdog = 20;
150 m_watchdogs.satellite_watchdog = 20;
153void CommBridge::SelectNextLowerPriority(
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);
162 pc.active_priority = best_prio;
163 pc.active_source.clear();
164 pc.active_identifier.clear();
167void CommBridge::OnWatchdogTimer(wxTimerEvent& event) {
169 m_watchdogs.position_watchdog--;
170 if (m_watchdogs.position_watchdog <= 0) {
171 if (m_watchdogs.position_watchdog % 5 == 0) {
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));
178 if (m_watchdogs.position_watchdog % n_LogWatchdogPeriod == 0) {
180 logmsg.Printf(_T(
" ***GPS Watchdog timeout at Lat:%g Lon: %g"),
182 wxLogMessage(logmsg);
190 active_priority_position.recent_active_time = -1;
194 SelectNextLowerPriority(priority_map_position, active_priority_position);
198 m_watchdogs.velocity_watchdog--;
199 if (m_watchdogs.velocity_watchdog <= 0) {
202 active_priority_velocity.recent_active_time = -1;
204 if (g_nNMEADebug && (m_watchdogs.velocity_watchdog == 0))
205 wxLogMessage(_T(
" ***Velocity Watchdog timeout..."));
206 if (m_watchdogs.velocity_watchdog % 5 == 0) {
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));
215 SelectNextLowerPriority(priority_map_velocity, active_priority_velocity);
219 m_watchdogs.heading_watchdog--;
220 if (m_watchdogs.heading_watchdog <= 0) {
222 active_priority_heading.recent_active_time = -1;
223 if (g_nNMEADebug && (m_watchdogs.heading_watchdog == 0))
224 wxLogMessage(_T(
" ***HDT Watchdog timeout..."));
228 SelectNextLowerPriority(priority_map_heading, active_priority_heading);
232 m_watchdogs.variation_watchdog--;
233 if (m_watchdogs.variation_watchdog <= 0) {
235 active_priority_variation.recent_active_time = -1;
237 if (g_nNMEADebug && (m_watchdogs.variation_watchdog == 0))
238 wxLogMessage(_T(
" ***VAR Watchdog timeout..."));
242 SelectNextLowerPriority(priority_map_variation, active_priority_variation);
246 m_watchdogs.satellite_watchdog--;
247 if (m_watchdogs.satellite_watchdog <= 0) {
251 active_priority_satellites.recent_active_time = -1;
253 if (g_nNMEADebug && (m_watchdogs.satellite_watchdog == 0))
254 wxLogMessage(_T(
" ***SAT Watchdog timeout..."));
258 SelectNextLowerPriority(priority_map_satellites,
259 active_priority_satellites);
263void CommBridge::MakeHDTFromHDM() {
266 if (!std::isnan(gHdm)) {
269 if (std::isnan(gVar) && (g_UserVar != 0.0)) gVar = g_UserVar;
271 if (!std::isnan(gHdt)) {
274 else if (gHdt >= 360)
277 m_watchdogs.heading_watchdog = gps_watchdog_timeout_ticks;
282void CommBridge::InitCommListeners() {
284 auto& msgbus = NavMsgBus::GetInstance();
288 Nmea2000Msg n2k_msg_129029(
static_cast<uint64_t
>(129029));
289 listener_N2K_129029.
Listen(n2k_msg_129029,
this, EVT_N2K_129029);
292 HandleN2K_129029(UnpackEvtPointer<Nmea2000Msg>(ev));
297 Nmea2000Msg n2k_msg_129025(
static_cast<uint64_t
>(129025));
298 listener_N2K_129025.
Listen(n2k_msg_129025,
this, EVT_N2K_129025);
300 HandleN2K_129025(UnpackEvtPointer<Nmea2000Msg>(ev));
305 Nmea2000Msg n2k_msg_129026(
static_cast<uint64_t
>(129026));
306 listener_N2K_129026.
Listen(n2k_msg_129026,
this, EVT_N2K_129026);
308 HandleN2K_129026(UnpackEvtPointer<Nmea2000Msg>(ev));
313 Nmea2000Msg n2k_msg_127250(
static_cast<uint64_t
>(127250));
314 listener_N2K_127250.
Listen(n2k_msg_127250,
this, EVT_N2K_127250);
316 HandleN2K_127250(UnpackEvtPointer<Nmea2000Msg>(ev));
321 Nmea2000Msg n2k_msg_129540(
static_cast<uint64_t
>(129540));
322 listener_N2K_129540.
Listen(n2k_msg_129540,
this, EVT_N2K_129540);
324 HandleN2K_129540(UnpackEvtPointer<Nmea2000Msg>(ev));
330 listener_N0183_RMC.
Listen(n0183_msg_RMC,
this, EVT_N0183_RMC);
333 HandleN0183_RMC(UnpackEvtPointer<Nmea0183Msg>(ev));
338 listener_N0183_HDT.
Listen(n0183_msg_HDT,
this, EVT_N0183_HDT);
341 HandleN0183_HDT(UnpackEvtPointer<Nmea0183Msg>(ev));
346 listener_N0183_HDG.
Listen(n0183_msg_HDG,
this, EVT_N0183_HDG);
349 HandleN0183_HDG(UnpackEvtPointer<Nmea0183Msg>(ev));
354 listener_N0183_HDM.
Listen(n0183_msg_HDM,
this, EVT_N0183_HDM);
357 HandleN0183_HDM(UnpackEvtPointer<Nmea0183Msg>(ev));
362 listener_N0183_VTG.
Listen(n0183_msg_VTG,
this, EVT_N0183_VTG);
365 HandleN0183_VTG(UnpackEvtPointer<Nmea0183Msg>(ev));
370 listener_N0183_GSV.
Listen(n0183_msg_GSV,
this, EVT_N0183_GSV);
373 HandleN0183_GSV(UnpackEvtPointer<Nmea0183Msg>(ev));
378 listener_N0183_GGA.
Listen(n0183_msg_GGA,
this, EVT_N0183_GGA);
381 HandleN0183_GGA(UnpackEvtPointer<Nmea0183Msg>(ev));
386 listener_N0183_GLL.
Listen(n0183_msg_GLL,
this, EVT_N0183_GLL);
389 HandleN0183_GLL(UnpackEvtPointer<Nmea0183Msg>(ev));
394 listener_N0183_AIVDO.
Listen(n0183_msg_AIVDO,
this, EVT_N0183_AIVDO);
402 listener_SignalK.
Listen(sk_msg,
this, EVT_SIGNALK);
405 HandleSignalK(UnpackEvtPointer<SignalkMsg>(ev));
409void CommBridge::OnDriverStateChange() {
411 PresetPriorityContainers();
414std::string CommBridge::GetPriorityMap(
415 std::unordered_map<std::string, int>& map) {
416#define MAX_SOURCES 10
417 std::string sa[MAX_SOURCES];
420 for (
auto& it : map) {
421 if ((it.second >= 0) && (it.second < MAX_SOURCES)) sa[it.second] = it.first;
425 for (
int i = 0; i < MAX_SOURCES; i++) {
435std::vector<std::string> CommBridge::GetPriorityMaps() {
436 std::vector<std::string> result;
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));
447void CommBridge::ApplyPriorityMap(
448 std::unordered_map<std::string, int>& priority_map, wxString& new_prio,
450 priority_map.clear();
451 wxStringTokenizer tk(new_prio,
"|");
453 while (tk.HasMoreTokens()) {
454 wxString entry = tk.GetNextToken();
455 std::string s_entry(entry.c_str());
456 priority_map[s_entry] = index;
461void CommBridge::ApplyPriorityMaps(std::vector<std::string> new_maps) {
462 wxString new_prio_string;
464 new_prio_string = wxString(new_maps[0].c_str());
465 ApplyPriorityMap(priority_map_position, new_prio_string, 0);
467 new_prio_string = wxString(new_maps[1].c_str());
468 ApplyPriorityMap(priority_map_velocity, new_prio_string, 1);
470 new_prio_string = wxString(new_maps[2].c_str());
471 ApplyPriorityMap(priority_map_heading, new_prio_string, 2);
473 new_prio_string = wxString(new_maps[3].c_str());
474 ApplyPriorityMap(priority_map_variation, new_prio_string, 3);
476 new_prio_string = wxString(new_maps[4].c_str());
477 ApplyPriorityMap(priority_map_satellites, new_prio_string, 4);
480void CommBridge::PresetPriorityContainer(
482 const std::unordered_map<std::string, int>& priority_map) {
486 for (
auto& it : priority_map) {
487 if (it.second == 0) key0 = it.first;
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();
497 wxStringTokenizer tka(wxs_this_source, _T(
":"));
499 int source_address = atoi(tka.GetNextToken().ToStdString().c_str());
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;
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);
516bool CommBridge::HandleN2K_129029(std::shared_ptr<const Nmea2000Msg> n2k_msg) {
517 std::vector<unsigned char> v = n2k_msg->payload;
521 unsigned char* c = (
unsigned char*)&pgn;
527 ClearNavData(temp_data);
529 if (!m_decoder.DecodePGN129029(v, temp_data))
return false;
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;
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;
549 m_watchdogs.satellite_watchdog = sat_watchdog_timeout_ticks;
553 SendBasicNavdata(valid_flag);
557bool CommBridge::HandleN2K_129025(std::shared_ptr<const Nmea2000Msg> n2k_msg) {
558 std::vector<unsigned char> v = n2k_msg->payload;
561 ClearNavData(temp_data);
563 if (!m_decoder.DecodePGN129025(v, temp_data))
return false;
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;
581 SendBasicNavdata(valid_flag);
585bool CommBridge::HandleN2K_129026(std::shared_ptr<const Nmea2000Msg> n2k_msg) {
586 std::vector<unsigned char> v = n2k_msg->payload;
589 ClearNavData(temp_data);
591 if (!m_decoder.DecodePGN129026(v, temp_data))
return false;
594 if (!N2kIsNA(temp_data.gSog)) {
595 if (EvalPriority(n2k_msg, active_priority_velocity,
596 priority_map_velocity)) {
597 gSog = MS2KNOTS(temp_data.gSog);
598 valid_flag += SOG_UPDATE;
600 if (N2kIsNA(temp_data.gCog))
603 gCog = GeodesicRadToDeg(temp_data.gCog);
604 valid_flag += COG_UPDATE;
605 m_watchdogs.velocity_watchdog = gps_watchdog_timeout_ticks;
610 SendBasicNavdata(valid_flag);
614bool CommBridge::HandleN2K_127250(std::shared_ptr<const Nmea2000Msg> n2k_msg) {
615 std::vector<unsigned char> v = n2k_msg->payload;
618 ClearNavData(temp_data);
620 if (!m_decoder.DecodePGN127250(v, temp_data))
return false;
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;
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;
640 if (!N2kIsNA(temp_data.gHdm)) {
641 gHdm = GeodesicRadToDeg(temp_data.gHdm);
642 if (EvalPriority(n2k_msg, active_priority_heading, priority_map_heading)) {
644 valid_flag += HDT_UPDATE;
645 if (!std::isnan(gHdt))
646 m_watchdogs.heading_watchdog = gps_watchdog_timeout_ticks;
650 SendBasicNavdata(valid_flag);
654bool CommBridge::HandleN2K_129540(std::shared_ptr<const Nmea2000Msg> n2k_msg) {
655 std::vector<unsigned char> v = n2k_msg->payload;
658 ClearNavData(temp_data);
660 if (!m_decoder.DecodePGN129540(v, temp_data))
return false;
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;
668 m_watchdogs.satellite_watchdog = sat_watchdog_timeout_ticks;
675bool CommBridge::HandleN0183_RMC(std::shared_ptr<const Nmea0183Msg> n0183_msg) {
676 std::string str = n0183_msg->payload;
679 ClearNavData(temp_data);
682 if (!m_decoder.DecodeRMC(str, temp_data)) bvalid =
false;
684 if (std::isnan(temp_data.gLat) || std::isnan(temp_data.gLon))
return false;
687 if (EvalPriority(n0183_msg, active_priority_position,
688 priority_map_position)) {
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;
696 valid_flag += POS_UPDATE;
699 if (EvalPriority(n0183_msg, active_priority_velocity,
700 priority_map_velocity)) {
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;
710 if (!std::isnan(temp_data.gVar)) {
711 if (EvalPriority(n0183_msg, active_priority_variation,
712 priority_map_variation)) {
714 gVar = temp_data.gVar;
715 valid_flag += VAR_UPDATE;
716 m_watchdogs.variation_watchdog = gps_watchdog_timeout_ticks;
721 SendBasicNavdata(valid_flag);
725bool CommBridge::HandleN0183_HDT(std::shared_ptr<const Nmea0183Msg> n0183_msg) {
726 std::string str = n0183_msg->payload;
728 ClearNavData(temp_data);
730 if (!m_decoder.DecodeHDT(str, temp_data))
return false;
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;
739 SendBasicNavdata(valid_flag);
743bool CommBridge::HandleN0183_HDG(std::shared_ptr<const Nmea0183Msg> n0183_msg) {
744 std::string str = n0183_msg->payload;
746 ClearNavData(temp_data);
748 if (!m_decoder.DecodeHDG(str, temp_data))
return 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;
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;
768 if (bHDM) MakeHDTFromHDM();
770 SendBasicNavdata(valid_flag);
774bool CommBridge::HandleN0183_HDM(std::shared_ptr<const Nmea0183Msg> n0183_msg) {
775 std::string str = n0183_msg->payload;
777 ClearNavData(temp_data);
779 if (!m_decoder.DecodeHDM(str, temp_data))
return false;
782 if (EvalPriority(n0183_msg, active_priority_heading, priority_map_heading)) {
783 gHdm = temp_data.gHdm;
785 valid_flag += HDT_UPDATE;
786 m_watchdogs.heading_watchdog = gps_watchdog_timeout_ticks;
789 SendBasicNavdata(valid_flag);
793bool CommBridge::HandleN0183_VTG(std::shared_ptr<const Nmea0183Msg> n0183_msg) {
794 std::string str = n0183_msg->payload;
796 ClearNavData(temp_data);
798 if (!m_decoder.DecodeVTG(str, temp_data))
return false;
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;
810 SendBasicNavdata(valid_flag);
814bool CommBridge::HandleN0183_GSV(std::shared_ptr<const Nmea0183Msg> n0183_msg) {
815 std::string str = n0183_msg->payload;
817 ClearNavData(temp_data);
819 if (!m_decoder.DecodeGSV(str, temp_data))
return false;
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;
828 m_watchdogs.satellite_watchdog = sat_watchdog_timeout_ticks;
832 SendBasicNavdata(valid_flag);
836bool CommBridge::HandleN0183_GGA(std::shared_ptr<const Nmea0183Msg> n0183_msg) {
837 std::string str = n0183_msg->payload;
839 ClearNavData(temp_data);
842 if (!m_decoder.DecodeGGA(str, temp_data)) bvalid =
false;
844 if (std::isnan(temp_data.gLat) || std::isnan(temp_data.gLon))
return false;
847 if (EvalPriority(n0183_msg, active_priority_position,
848 priority_map_position)) {
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;
856 valid_flag += POS_UPDATE;
859 if (EvalPriority(n0183_msg, active_priority_satellites,
860 priority_map_satellites)) {
862 if (temp_data.n_satellites >= 0) {
863 g_SatsInView = temp_data.n_satellites;
866 m_watchdogs.satellite_watchdog = sat_watchdog_timeout_ticks;
871 SendBasicNavdata(valid_flag);
875bool CommBridge::HandleN0183_GLL(std::shared_ptr<const Nmea0183Msg> n0183_msg) {
876 std::string str = n0183_msg->payload;
878 ClearNavData(temp_data);
881 if (!m_decoder.DecodeGLL(str, temp_data)) bvalid =
false;
883 if (std::isnan(temp_data.gLat) || std::isnan(temp_data.gLon))
return false;
886 if (EvalPriority(n0183_msg, active_priority_position,
887 priority_map_position)) {
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;
895 valid_flag += POS_UPDATE;
898 SendBasicNavdata(valid_flag);
903 std::shared_ptr<const Nmea0183Msg> n0183_msg) {
904 std::string str = n0183_msg->payload;
907 wxString sentence(str.c_str());
911 AisError nerr = AIS_GENERIC_ERROR;
912 nerr = DecodeSingleVDO(sentence, &gpd);
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)) {
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;
927 if (!std::isnan(gpd.
kCog) && !std::isnan(gpd.
kSog)) {
928 if (EvalPriority(n0183_msg, active_priority_velocity,
929 priority_map_velocity)) {
931 valid_flag += SOG_UPDATE;
933 valid_flag += COG_UPDATE;
934 m_watchdogs.velocity_watchdog = gps_watchdog_timeout_ticks;
938 if (!std::isnan(gpd.
kHdt)) {
939 if (EvalPriority(n0183_msg, active_priority_heading,
940 priority_map_heading)) {
942 valid_flag += HDT_UPDATE;
943 m_watchdogs.heading_watchdog = gps_watchdog_timeout_ticks;
947 SendBasicNavdata(valid_flag);
952bool CommBridge::HandleSignalK(std::shared_ptr<const SignalkMsg> sK_msg) {
953 std::string str = sK_msg->raw_message;
956 if (sK_msg->context_self != sK_msg->context)
return false;
958 g_ownshipMMSI_SK = sK_msg->context_self;
961 ClearNavData(temp_data);
963 if (!m_decoder.DecodeSignalK(str, temp_data))
return false;
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;
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;
986 m_watchdogs.velocity_watchdog = gps_watchdog_timeout_ticks;
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;
998 if (!std::isnan(temp_data.gHdm)) {
999 if (EvalPriority(sK_msg, active_priority_heading, priority_map_heading)) {
1000 gHdm = temp_data.gHdm;
1002 valid_flag += HDT_UPDATE;
1003 m_watchdogs.heading_watchdog = gps_watchdog_timeout_ticks;
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;
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;
1023 m_watchdogs.satellite_watchdog = sat_watchdog_timeout_ticks;
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;";
1038 if (content.empty()) content =
"Not used by OCPN, maybe passed to plugins";
1041 std::string source = sK_msg->source->to_string();
1045 SendBasicNavdata(valid_flag);
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;
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();
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();
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";
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;
1080 active_priority_void.active_priority = -1;
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();
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;
1104 return active_priority_void;
1107void CommBridge::UpdateAndApplyMaps(std::vector<std::string> new_maps) {
1108 ApplyPriorityMaps(new_maps);
1110 PresetPriorityContainers();
1113bool CommBridge::LoadConfig(
void) {
1114 if (TheBaseConfig()) {
1115 TheBaseConfig()->SetPath(
"/Settings/CommPriority");
1117 std::vector<std::string> new_maps;
1119 wxString pri_string;
1121 TheBaseConfig()->Read(
"PriorityPosition", &pri_string);
1122 s_prio = std::string(pri_string.c_str());
1123 new_maps.push_back(s_prio);
1125 TheBaseConfig()->Read(
"PriorityVelocity", &pri_string);
1126 s_prio = std::string(pri_string.c_str());
1127 new_maps.push_back(s_prio);
1129 TheBaseConfig()->Read(
"PriorityHeading", &pri_string);
1130 s_prio = std::string(pri_string.c_str());
1131 new_maps.push_back(s_prio);
1133 TheBaseConfig()->Read(
"PriorityVariation", &pri_string);
1134 s_prio = std::string(pri_string.c_str());
1135 new_maps.push_back(s_prio);
1137 TheBaseConfig()->Read(
"PrioritySatellites", &pri_string);
1138 s_prio = std::string(pri_string.c_str());
1139 new_maps.push_back(s_prio);
1141 ApplyPriorityMaps(new_maps);
1146bool CommBridge::SaveConfig(
void) {
1147 if (TheBaseConfig()) {
1148 TheBaseConfig()->SetPath(
"/Settings/CommPriority");
1150 wxString pri_string;
1151 pri_string = wxString(GetPriorityMap(priority_map_position).c_str());
1152 TheBaseConfig()->Write(
"PriorityPosition", pri_string);
1154 pri_string = wxString(GetPriorityMap(priority_map_velocity).c_str());
1155 TheBaseConfig()->Write(
"PriorityVelocity", pri_string);
1157 pri_string = wxString(GetPriorityMap(priority_map_heading).c_str());
1158 TheBaseConfig()->Write(
"PriorityHeading", pri_string);
1160 pri_string = wxString(GetPriorityMap(priority_map_variation).c_str());
1161 TheBaseConfig()->Write(
"PriorityVariation", pri_string);
1163 pri_string = wxString(GetPriorityMap(priority_map_satellites).c_str());
1164 TheBaseConfig()->Write(
"PrioritySatellites", pri_string);
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();
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);
1179 this_identifier = msg_0183->talker;
1180 this_identifier += msg_0183->type;
1182 }
else if (msg->bus == NavAddr::Bus::N2000) {
1183 auto msg_n2k = std::dynamic_pointer_cast<const Nmea2000Msg>(msg);
1185 this_identifier = msg_n2k->PGN.to_string();
1186 unsigned char n_source = msg_n2k->payload.at(7);
1188 sprintf(ss,
"%d", n_source);
1189 this_address = std::string(ss);
1191 }
else if (msg->bus == NavAddr::Bus::Signalk) {
1192 auto msg_sk = std::dynamic_pointer_cast<const SignalkMsg>(msg);
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;
1202 return source +
":" + this_address +
";" + this_identifier;
1205bool CommBridge::EvalPriority(
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());
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();
1218 wxStringTokenizer tka(wxs_this_source, _T(
":"));
1220 int source_address = atoi(tka.GetNextToken().ToStdString().c_str());
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(),
1232 if (active_priority_position.recent_active_time != -1) {
1236 if (!pos_ok)
return false;
1242 auto it = priority_map.find(this_key);
1243 if (it == priority_map.end()) {
1245 size_t n = priority_map.size();
1246 priority_map[this_key] = n;
1249 this_priority = priority_map[this_key];
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(),
1259 if (this_priority > active_priority.active_priority) {
1261 printf(
" Drop low priority: %s %d %d \n", source.c_str(),
1262 this_priority, active_priority.active_priority);
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();
1276 printf(
" Restoring high priority: %s %d\n", source.c_str(),
1284 if (active_priority.active_source.size()) {
1285 if (debug_priority) printf(
"source: %s\n", source.c_str());
1287 printf(
"active_source: %s\n", active_priority.active_source.c_str());
1289 if (source.compare(active_priority.active_source) != 0) {
1292 int lowest_priority = -10;
1293 for (
auto it = priority_map.begin(); it != priority_map.end(); it++) {
1294 if (it->second > lowest_priority) lowest_priority = it->second;
1297 priority_map[this_key] = lowest_priority + 1;
1299 printf(
" Lowering priority A: %s :%d\n", source.c_str(),
1300 priority_map[this_key]);
1308 if (msg->bus == NavAddr::Bus::N0183) {
1309 auto msg_0183 = std::dynamic_pointer_cast<const Nmea0183Msg>(msg);
1311 if (active_priority.active_identifier.size()) {
1313 printf(
"this_identifier: %s\n", this_identifier.c_str());
1315 printf(
"active_priority.active_identifier: %s\n",
1316 active_priority.active_identifier.c_str());
1318 if (this_identifier.compare(active_priority.active_identifier) != 0) {
1321 if (priority_map[this_key] == active_priority.active_priority) {
1322 int lowest_priority = -10;
1323 for (
auto it = priority_map.begin(); it != priority_map.end();
1325 if (it->second > lowest_priority) lowest_priority = it->second;
1328 priority_map[this_key] = lowest_priority + 1;
1330 printf(
" Lowering priority B: %s :%d\n", source.c_str(),
1331 priority_map[this_key]);
1342 else if (msg->bus == NavAddr::Bus::N2000) {
1343 auto msg_n2k = std::dynamic_pointer_cast<const Nmea2000Msg>(msg);
1345 if (active_priority.active_identifier.size()) {
1346 if (this_identifier.compare(active_priority.active_identifier) != 0) {
1349 if (priority_map[this_key] == active_priority.active_priority) {
1350 int lowest_priority = -10;
1351 for (
auto it = priority_map.begin(); it != priority_map.end();
1353 if (it->second > lowest_priority) lowest_priority = it->second;
1356 priority_map[this_key] = lowest_priority + 1;
1358 printf(
" Lowering priority: %s :%d\n", source.c_str(),
1359 priority_map[this_key]);
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();
1375 printf(
" Accepting high priority: %s %d\n", source.c_str(), this_priority);
void Notify(const std::shared_ptr< const AppMsg > &msg)
Send message to everyone listening to given message type.
bool HandleN0183_AIVDO(std::shared_ptr< const Nmea0183Msg > n0183_msg)
Processes NMEA 0183 AIVDO sentences containing own vessel's AIS data.
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.
Custom event class for OpenCPN's notification system.
A parsed SignalK message over ipv4.
Driver registration container, a singleton.
Raw messages layer, supports sending and recieving navmsg messages.
A generic position and navigation data structure.
double kCog
Course over ground in degrees.
double kHdt
True heading in degrees.
double kLat
Latitude in decimal degrees.
double kSog
Speed over ground in knots.
double kLon
Longitude in decimal degrees.