35#include <wx/tokenzr.h>
36#include <wx/fileconf.h>
53#define N_ACTIVE_LOG_WATCHDOG 300
57static bool debug_priority =
false;
71static NmeaLog* GetDataMonitor() {
72 auto w = wxWindow::FindWindowByName(kDataMonitorWindowName);
73 return dynamic_cast<NmeaLog*
>(w);
78 log_callbacks.log_is_active = [&]() {
79 auto log = GetDataMonitor();
80 return log && log->IsVisible();
82 log_callbacks.log_message = [&](
const Logline& ll) {
83 NmeaLog* monitor = GetDataMonitor();
91 AppNavMsg(
const std::shared_ptr<const AppMsg>& msg,
const string& name)
92 :
NavMsg(NavAddr::Bus::AppMsg,
93 std::make_shared<const NavAddrPlugin>(
"AppMsg")),
94 m_to_string(msg->to_string()),
97 [[nodiscard]]
string to_string()
const override {
return m_to_string; }
99 [[nodiscard]]
string key()
const override {
return "appmsg::" + m_name; }
101 const string m_to_string;
105static void LogAppMsg(
const std::shared_ptr<const AppMsg>& msg,
107 if (!log_cb.log_is_active())
return;
108 auto navmsg = std::make_shared<AppNavMsg>(msg,
"basic-navdata");
111 log_cb.log_message(ll);
118static void SendBasicNavdata(
int vflag,
120 auto msg = std::make_shared<BasicNavDataMsg>(
122 clock_gettime(CLOCK_MONOTONIC, &msg->set_time);
123 LogAppMsg(msg,
"basic-navdata", log_callbacks);
124 AppMsgBus::GetInstance().
Notify(std::move(msg));
127static inline double GeodesicRadToDeg(
double rads) {
128 return rads * 180.0 / M_PI;
131static inline double MS2KNOTS(
double ms) {
return ms * 1.9438444924406; }
133static string GetPriorityKey(
const NavMsgPtr& msg) {
136 string this_identifier;
137 string this_address(
"0");
138 if (msg->bus == NavAddr::Bus::N0183) {
139 auto msg_0183 = std::dynamic_pointer_cast<const Nmea0183Msg>(msg);
141 string source = msg->source->to_string();
142 if (msg_0183->talker ==
"WM" && msg_0183->type ==
"HVD")
143 source =
"WMM plugin";
144 this_identifier = msg_0183->talker;
145 this_identifier += msg_0183->type;
146 key = source +
":" + this_address +
";" + this_identifier;
148 }
else if (msg->bus == NavAddr::Bus::N2000) {
149 auto msg_n2k = std::dynamic_pointer_cast<const Nmea2000Msg>(msg);
151 this_identifier = msg_n2k->PGN.to_string();
152 unsigned char n_source = msg_n2k->payload.at(7);
153 wxString km = wxString::Format(
"N2k device address: %d", n_source);
154 key = km.ToStdString() +
" ; " +
"PGN: " + this_identifier;
156 }
else if (msg->bus == NavAddr::Bus::Signalk) {
157 auto msg_sk = std::dynamic_pointer_cast<const SignalkMsg>(msg);
160 std::static_pointer_cast<const NavAddrSignalK>(msg->source);
161 string source = addr_sk->to_string();
170 const PriorityMap& priority_map) {
174 for (
const auto& it : priority_map) {
175 if (it.second == 0) key0 = it.first;
178 wxString this_key(key0.c_str());
179 wxStringTokenizer tkz(this_key,
";");
180 string source = tkz.GetNextToken().ToStdString();
181 string this_identifier = tkz.GetNextToken().ToStdString();
183 wxStringTokenizer tka(source,
":");
185 std::stringstream ss;
186 ss << tka.GetNextToken();
187 ss >> pc.active_source_address;
188 pc.active_priority = 0;
189 pc.active_source = source;
190 pc.active_identifier = this_identifier;
191 pc.recent_active_time = -1;
194static void ApplyPriorityMap(PriorityMap& priority_map,
195 const wxString& new_prio,
int category) {
196 priority_map.clear();
197 wxStringTokenizer tk(new_prio,
"|");
199 while (tk.HasMoreTokens()) {
200 wxString entry = tk.GetNextToken();
201 string s_entry(entry.c_str());
202 priority_map[s_entry] = index;
207static string GetPriorityMap(
const PriorityMap& map) {
208#define MAX_SOURCES 10
209 string sa[MAX_SOURCES];
212 for (
auto& it : map) {
213 if ((it.second >= 0) && (it.second < MAX_SOURCES)) sa[it.second] = it.first;
217 for (
int i = 0; i < MAX_SOURCES; i++) {
218 if (!sa[i].empty()) {
227static bool IsNextLowerPriorityAvailable(
const PriorityMap& map,
230 for (
auto& it : map) {
231 if (it.second > pc.active_priority) {
232 best_prio = wxMin(best_prio, it.second);
235 return best_prio != pc.active_priority;
238static void SelectNextLowerPriority(
const PriorityMap& map,
241 for (
const auto& it : map) {
242 if (it.second > pc.active_priority) {
243 best_prio = wxMin(best_prio, it.second);
246 pc.active_priority = best_prio;
247 pc.active_source.clear();
248 pc.active_identifier.clear();
254 static bool is_initialized =
false;
256 if (!is_initialized) {
257 the_instance.Initialize();
258 is_initialized =
true;
263CommBridge::CommBridge()
266 active_priority_position(
"position"),
267 active_priority_velocity(
"velocity"),
268 active_priority_heading(
"heading"),
269 active_priority_variation(
"variation"),
270 active_priority_satellites(
"satellites"),
271 active_priority_void(
"", -1),
272 m_n_log_watchdog_period(3600),
273 m_last_position_priority(0) {
274 Bind(wxEVT_TIMER, [&](wxTimerEvent&) { OnWatchdogTimer(); });
276CommBridge::~CommBridge() =
default;
278bool CommBridge::Initialize() {
279 m_log_callbacks = GetLogCallbacks();
283 PresetPriorityContainers();
288 m_watchdog_timer.SetOwner(
this, WATCHDOG_TIMER);
289 m_watchdog_timer.Start(1000, wxTIMER_CONTINUOUS);
294 m_driver_change_lstnr.
Init(
295 CommDriverRegistry::GetInstance().evt_driverlist_change,
296 [&](
const wxCommandEvent& ev) { OnDriverStateChange(); });
301void CommBridge::PresetWatchdogs() {
302 m_watchdogs.position_watchdog =
304 m_watchdogs.velocity_watchdog = 20;
305 m_watchdogs.variation_watchdog = 20;
306 m_watchdogs.heading_watchdog = 20;
307 m_watchdogs.satellite_watchdog = 20;
310void CommBridge::OnWatchdogTimer() {
312 m_watchdogs.position_watchdog--;
313 if (m_watchdogs.position_watchdog <= 0) {
314 if (m_watchdogs.position_watchdog % 5 == 0) {
316 auto msg = std::make_shared<GPSWatchdogMsg>(
317 GPSWatchdogMsg::WDSource::position, m_watchdogs.position_watchdog);
318 auto& msgbus = AppMsgBus::GetInstance();
319 LogAppMsg(msg,
"watchdog", m_log_callbacks);
320 msgbus.Notify(std::move(msg));
322 if (m_watchdogs.position_watchdog % m_n_log_watchdog_period == 0) {
324 logmsg.Printf(
" ***GPS Watchdog timeout at Lat:%g Lon: %g",
gLat,
326 wxLogMessage(logmsg);
334 active_priority_position.recent_active_time = -1;
338 if (IsNextLowerPriorityAvailable(priority_map_position,
339 active_priority_position)) {
340 SelectNextLowerPriority(priority_map_position, active_priority_position);
345 m_watchdogs.velocity_watchdog--;
346 if (m_watchdogs.velocity_watchdog <= 0) {
349 active_priority_velocity.recent_active_time = -1;
351 if (g_nNMEADebug && (m_watchdogs.velocity_watchdog == 0))
352 wxLogMessage(
" ***Velocity Watchdog timeout...");
353 if (m_watchdogs.velocity_watchdog % 5 == 0) {
355 auto msg = std::make_shared<GPSWatchdogMsg>(
356 GPSWatchdogMsg::WDSource::velocity, m_watchdogs.velocity_watchdog);
357 auto& msgbus = AppMsgBus::GetInstance();
358 msgbus.Notify(std::move(msg));
362 SelectNextLowerPriority(priority_map_velocity, active_priority_velocity);
366 m_watchdogs.heading_watchdog--;
367 if (m_watchdogs.heading_watchdog <= 0) {
369 active_priority_heading.recent_active_time = -1;
370 if (g_nNMEADebug && (m_watchdogs.heading_watchdog == 0))
371 wxLogMessage(
" ***HDT Watchdog timeout...");
375 SelectNextLowerPriority(priority_map_heading, active_priority_heading);
379 m_watchdogs.variation_watchdog--;
380 if (m_watchdogs.variation_watchdog <= 0) {
382 active_priority_variation.recent_active_time = -1;
384 if (g_nNMEADebug && (m_watchdogs.variation_watchdog == 0))
385 wxLogMessage(
" ***VAR Watchdog timeout...");
389 SelectNextLowerPriority(priority_map_variation, active_priority_variation);
393 m_watchdogs.satellite_watchdog--;
394 if (m_watchdogs.satellite_watchdog <= 0) {
398 active_priority_satellites.recent_active_time = -1;
400 if (g_nNMEADebug && (m_watchdogs.satellite_watchdog == 0))
401 wxLogMessage(
" ***SAT Watchdog timeout...");
405 SelectNextLowerPriority(priority_map_satellites,
406 active_priority_satellites);
410void CommBridge::MakeHDTFromHDM() {
413 if (!std::isnan(
gHdm)) {
416 if (std::isnan(
gVar) && (g_UserVar != 0.0))
gVar = g_UserVar;
418 if (!std::isnan(
gHdt)) {
421 else if (
gHdt >= 360)
424 m_watchdogs.heading_watchdog = gps_watchdog_timeout_ticks;
429void CommBridge::InitCommListeners() {
435 HandleN2K_129029(UnpackEvtPointer<Nmea2000Msg>(ev));
441 HandleN2K_129025(UnpackEvtPointer<Nmea2000Msg>(ev));
447 HandleN2K_129026(UnpackEvtPointer<Nmea2000Msg>(ev));
453 HandleN2K_127250(UnpackEvtPointer<Nmea2000Msg>(ev));
458 HandleN2K_127258(UnpackEvtPointer<Nmea2000Msg>(ev));
464 HandleN2K_129540(UnpackEvtPointer<Nmea2000Msg>(ev));
471 HandleN0183_RMC(UnpackEvtPointer<Nmea0183Msg>(ev));
476 HandleN0183_THS(UnpackEvtPointer<Nmea0183Msg>(ev));
481 HandleN0183_HDT(UnpackEvtPointer<Nmea0183Msg>(ev));
486 HandleN0183_HDG(UnpackEvtPointer<Nmea0183Msg>(ev));
491 HandleN0183_HDM(UnpackEvtPointer<Nmea0183Msg>(ev));
496 HandleN0183_HVD(UnpackEvtPointer<Nmea0183Msg>(ev));
501 HandleN0183_VTG(UnpackEvtPointer<Nmea0183Msg>(ev));
506 HandleN0183_GSV(UnpackEvtPointer<Nmea0183Msg>(ev));
511 HandleN0183_GGA(UnpackEvtPointer<Nmea0183Msg>(ev));
517 HandleN0183_GLL(UnpackEvtPointer<Nmea0183Msg>(ev));
527 HandleSignalK(UnpackEvtPointer<SignalkMsg>(ev));
531void CommBridge::OnDriverStateChange() {
533 PresetPriorityContainers();
536std::vector<string> CommBridge::GetPriorityMaps()
const {
537 std::vector<string> result;
538 result.push_back(GetPriorityMap(priority_map_position));
539 result.push_back(GetPriorityMap(priority_map_velocity));
540 result.push_back(GetPriorityMap(priority_map_heading));
541 result.push_back(GetPriorityMap(priority_map_variation));
542 result.push_back(GetPriorityMap(priority_map_satellites));
546void CommBridge::ApplyPriorityMaps(
const std::vector<string>& new_maps) {
547 wxString new_prio_string = wxString(new_maps[0].c_str());
548 ApplyPriorityMap(priority_map_position, new_prio_string, 0);
550 new_prio_string = wxString(new_maps[1].c_str());
551 ApplyPriorityMap(priority_map_velocity, new_prio_string, 1);
553 new_prio_string = wxString(new_maps[2].c_str());
554 ApplyPriorityMap(priority_map_heading, new_prio_string, 2);
556 new_prio_string = wxString(new_maps[3].c_str());
557 ApplyPriorityMap(priority_map_variation, new_prio_string, 3);
559 new_prio_string = wxString(new_maps[4].c_str());
560 ApplyPriorityMap(priority_map_satellites, new_prio_string, 4);
563void CommBridge::PresetPriorityContainers() {
564 PresetPriorityContainer(active_priority_position, priority_map_position);
565 PresetPriorityContainer(active_priority_velocity, priority_map_velocity);
566 PresetPriorityContainer(active_priority_heading, priority_map_heading);
567 PresetPriorityContainer(active_priority_variation, priority_map_variation);
568 PresetPriorityContainer(active_priority_satellites, priority_map_satellites);
571bool CommBridge::HandleN2K_129029(
const N2000MsgPtr& n2k_msg) {
572 std::vector<unsigned char> v = n2k_msg->payload;
576 ClearNavData(temp_data);
578 if (!m_decoder.DecodePGN129029(v, temp_data))
return false;
581 if (!N2kIsNA(temp_data.gLat) && !N2kIsNA(temp_data.gLon)) {
582 if (EvalPriority(n2k_msg, active_priority_position,
583 priority_map_position)) {
584 gLat = temp_data.gLat;
585 gLon = temp_data.gLon;
586 valid_flag += POS_UPDATE;
587 valid_flag += POS_VALID;
588 m_watchdogs.position_watchdog = gps_watchdog_timeout_ticks;
589 m_n_log_watchdog_period = N_ACTIVE_LOG_WATCHDOG;
593 if (temp_data.n_satellites >= 0) {
594 if (EvalPriority(n2k_msg, active_priority_satellites,
595 priority_map_satellites)) {
596 g_SatsInView = temp_data.n_satellites;
598 m_watchdogs.satellite_watchdog = sat_watchdog_timeout_ticks;
602 SendBasicNavdata(valid_flag, m_log_callbacks);
606bool CommBridge::HandleN2K_129025(
const N2000MsgPtr& n2k_msg) {
607 std::vector<unsigned char> v = n2k_msg->payload;
610 ClearNavData(temp_data);
612 if (!m_decoder.DecodePGN129025(v, temp_data))
return false;
615 if (!N2kIsNA(temp_data.gLat) && !N2kIsNA(temp_data.gLon)) {
616 if (EvalPriority(n2k_msg, active_priority_position,
617 priority_map_position)) {
618 gLat = temp_data.gLat;
619 gLon = temp_data.gLon;
620 valid_flag += POS_UPDATE;
621 valid_flag += POS_VALID;
622 m_watchdogs.position_watchdog = gps_watchdog_timeout_ticks;
623 m_n_log_watchdog_period = N_ACTIVE_LOG_WATCHDOG;
630 SendBasicNavdata(valid_flag, m_log_callbacks);
634bool CommBridge::HandleN2K_129026(
const N2000MsgPtr& n2k_msg) {
635 std::vector<unsigned char> v = n2k_msg->payload;
638 ClearNavData(temp_data);
640 if (!m_decoder.DecodePGN129026(v, temp_data))
return false;
643 if (!N2kIsNA(temp_data.gSog)) {
644 if (EvalPriority(n2k_msg, active_priority_velocity,
645 priority_map_velocity)) {
646 gSog = MS2KNOTS(temp_data.gSog);
647 valid_flag += SOG_UPDATE;
649 if (N2kIsNA(temp_data.gCog))
652 gCog = GeodesicRadToDeg(temp_data.gCog);
653 valid_flag += COG_UPDATE;
654 m_watchdogs.velocity_watchdog = gps_watchdog_timeout_ticks;
659 SendBasicNavdata(valid_flag, m_log_callbacks);
663bool CommBridge::HandleN2K_127250(
const N2000MsgPtr& n2k_msg) {
664 std::vector<unsigned char> v = n2k_msg->payload;
667 ClearNavData(temp_data);
669 if (!m_decoder.DecodePGN127250(v, temp_data))
return false;
672 if (!N2kIsNA(temp_data.gVar)) {
673 if (EvalPriority(n2k_msg, active_priority_variation,
674 priority_map_variation)) {
675 gVar = GeodesicRadToDeg(temp_data.gVar);
676 valid_flag += VAR_UPDATE;
677 m_watchdogs.variation_watchdog = gps_watchdog_timeout_ticks;
681 if (!N2kIsNA(temp_data.gHdt)) {
682 if (EvalPriority(n2k_msg, active_priority_heading, priority_map_heading)) {
683 gHdt = GeodesicRadToDeg(temp_data.gHdt);
684 valid_flag += HDT_UPDATE;
685 m_watchdogs.heading_watchdog = gps_watchdog_timeout_ticks;
689 if (!N2kIsNA(temp_data.gHdm)) {
690 gHdm = GeodesicRadToDeg(temp_data.gHdm);
691 if (EvalPriority(n2k_msg, active_priority_heading, priority_map_heading)) {
693 valid_flag += HDT_UPDATE;
694 if (!std::isnan(
gHdt))
695 m_watchdogs.heading_watchdog = gps_watchdog_timeout_ticks;
699 SendBasicNavdata(valid_flag, m_log_callbacks);
703bool CommBridge::HandleN2K_127258(
const N2000MsgPtr& n2k_msg) {
704 std::vector<unsigned char> v = n2k_msg->payload;
707 ClearNavData(temp_data);
709 if (!m_decoder.DecodePGN127258(v, temp_data))
return false;
712 if (!N2kIsNA(temp_data.gVar)) {
713 if (EvalPriority(n2k_msg, active_priority_variation,
714 priority_map_variation)) {
715 gVar = GeodesicRadToDeg(temp_data.gVar);
716 valid_flag += VAR_UPDATE;
717 m_watchdogs.variation_watchdog = gps_watchdog_timeout_ticks;
721 SendBasicNavdata(valid_flag, m_log_callbacks);
725bool CommBridge::HandleN2K_129540(
const N2000MsgPtr& n2k_msg) {
726 std::vector<unsigned char> v = n2k_msg->payload;
729 ClearNavData(temp_data);
731 if (!m_decoder.DecodePGN129540(v, temp_data))
return false;
733 if (temp_data.n_satellites >= 0) {
734 if (EvalPriority(n2k_msg, active_priority_satellites,
735 priority_map_satellites)) {
736 g_SatsInView = temp_data.n_satellites;
738 m_watchdogs.satellite_watchdog = sat_watchdog_timeout_ticks;
745bool CommBridge::HandleN0183_RMC(
const N0183MsgPtr& n0183_msg) {
746 string str = n0183_msg->payload;
749 ClearNavData(temp_data);
751 bool is_valid =
true;
752 if (!m_decoder.DecodeRMC(str, temp_data)) is_valid =
false;
754 if (std::isnan(temp_data.gLat) || std::isnan(temp_data.gLon))
return false;
757 if (EvalPriority(n0183_msg, active_priority_position,
758 priority_map_position)) {
760 gLat = temp_data.gLat;
761 gLon = temp_data.gLon;
762 valid_flag += POS_VALID;
763 m_watchdogs.position_watchdog = gps_watchdog_timeout_ticks;
764 m_n_log_watchdog_period = N_ACTIVE_LOG_WATCHDOG;
766 valid_flag += POS_UPDATE;
769 if (EvalPriority(n0183_msg, active_priority_velocity,
770 priority_map_velocity)) {
772 gSog = temp_data.gSog;
773 valid_flag += SOG_UPDATE;
774 gCog = temp_data.gCog;
775 valid_flag += COG_UPDATE;
776 m_watchdogs.velocity_watchdog = gps_watchdog_timeout_ticks;
780 if (!std::isnan(temp_data.gVar)) {
781 if (EvalPriority(n0183_msg, active_priority_variation,
782 priority_map_variation)) {
784 gVar = temp_data.gVar;
785 valid_flag += VAR_UPDATE;
786 m_watchdogs.variation_watchdog = gps_watchdog_timeout_ticks;
796 if ((valid_flag & POS_VALID) == POS_VALID) {
798 if (g_SatsInView < 4) {
800 m_watchdogs.satellite_watchdog = sat_watchdog_timeout_ticks;
805 SendBasicNavdata(valid_flag, m_log_callbacks);
809bool CommBridge::HandleN0183_THS(
const N0183MsgPtr& n0183_msg) {
810 string str = n0183_msg->payload;
812 ClearNavData(temp_data);
814 if (!m_decoder.DecodeTHS(str, temp_data))
return false;
817 if (EvalPriority(n0183_msg, active_priority_heading, priority_map_heading)) {
818 gHdt = temp_data.gHdt;
819 valid_flag += HDT_UPDATE;
820 m_watchdogs.heading_watchdog = gps_watchdog_timeout_ticks;
823 SendBasicNavdata(valid_flag, m_log_callbacks);
827bool CommBridge::HandleN0183_HDT(
const N0183MsgPtr& n0183_msg) {
828 string str = n0183_msg->payload;
830 ClearNavData(temp_data);
832 if (!m_decoder.DecodeHDT(str, temp_data))
return false;
835 if (EvalPriority(n0183_msg, active_priority_heading, priority_map_heading)) {
836 gHdt = temp_data.gHdt;
837 valid_flag += HDT_UPDATE;
838 m_watchdogs.heading_watchdog = gps_watchdog_timeout_ticks;
841 SendBasicNavdata(valid_flag, m_log_callbacks);
845bool CommBridge::HandleN0183_HDG(
const N0183MsgPtr& n0183_msg) {
846 string str = n0183_msg->payload;
848 ClearNavData(temp_data);
850 if (!m_decoder.DecodeHDG(str, temp_data))
return false;
855 if (!std::isnan(temp_data.gHdm)) {
856 if (EvalPriority(n0183_msg, active_priority_heading,
857 priority_map_heading)) {
858 gHdm = temp_data.gHdm;
859 m_watchdogs.heading_watchdog = gps_watchdog_timeout_ticks;
864 if (!std::isnan(temp_data.gVar)) {
865 if (EvalPriority(n0183_msg, active_priority_variation,
866 priority_map_variation)) {
867 gVar = temp_data.gVar;
868 valid_flag += VAR_UPDATE;
869 m_watchdogs.variation_watchdog = gps_watchdog_timeout_ticks;
873 if (bHDM) MakeHDTFromHDM();
875 SendBasicNavdata(valid_flag, m_log_callbacks);
879bool CommBridge::HandleN0183_HDM(
const N0183MsgPtr& n0183_msg) {
880 string str = n0183_msg->payload;
882 ClearNavData(temp_data);
884 if (!m_decoder.DecodeHDM(str, temp_data))
return false;
887 if (EvalPriority(n0183_msg, active_priority_heading, priority_map_heading)) {
888 gHdm = temp_data.gHdm;
890 valid_flag += HDT_UPDATE;
891 m_watchdogs.heading_watchdog = gps_watchdog_timeout_ticks;
894 SendBasicNavdata(valid_flag, m_log_callbacks);
898bool CommBridge::HandleN0183_HVD(
const N0183MsgPtr& n0183_msg) {
899 string str = n0183_msg->payload;
901 ClearNavData(temp_data);
903 if (!m_decoder.DecodeHVD(str, temp_data))
return false;
907 if (!std::isnan(temp_data.gVar)) {
908 if (EvalPriority(n0183_msg, active_priority_variation,
909 priority_map_variation)) {
910 gVar = temp_data.gVar;
911 valid_flag += VAR_UPDATE;
912 m_watchdogs.variation_watchdog = gps_watchdog_timeout_ticks;
916 SendBasicNavdata(valid_flag, m_log_callbacks);
920bool CommBridge::HandleN0183_VTG(
const N0183MsgPtr& n0183_msg) {
921 string str = n0183_msg->payload;
923 ClearNavData(temp_data);
925 if (!m_decoder.DecodeVTG(str, temp_data))
return false;
928 if (EvalPriority(n0183_msg, active_priority_velocity,
929 priority_map_velocity)) {
930 gSog = temp_data.gSog;
931 valid_flag += SOG_UPDATE;
932 gCog = temp_data.gCog;
933 valid_flag += COG_UPDATE;
934 m_watchdogs.velocity_watchdog = gps_watchdog_timeout_ticks;
937 SendBasicNavdata(valid_flag, m_log_callbacks);
941bool CommBridge::HandleN0183_GSV(
const N0183MsgPtr& n0183_msg) {
942 string str = n0183_msg->payload;
944 ClearNavData(temp_data);
946 if (!m_decoder.DecodeGSV(str, temp_data))
return false;
949 if (EvalPriority(n0183_msg, active_priority_satellites,
950 priority_map_satellites)) {
951 if (temp_data.n_satellites >= 0) {
952 g_SatsInView = temp_data.n_satellites;
955 m_watchdogs.satellite_watchdog = sat_watchdog_timeout_ticks;
959 SendBasicNavdata(valid_flag, m_log_callbacks);
963bool CommBridge::HandleN0183_GGA(
const N0183MsgPtr& n0183_msg) {
964 string str = n0183_msg->payload;
966 ClearNavData(temp_data);
968 bool is_valid =
true;
969 if (!m_decoder.DecodeGGA(str, temp_data)) is_valid =
false;
971 if (std::isnan(temp_data.gLat) || std::isnan(temp_data.gLon))
return false;
974 if (EvalPriority(n0183_msg, active_priority_position,
975 priority_map_position)) {
977 gLat = temp_data.gLat;
978 gLon = temp_data.gLon;
979 valid_flag += POS_VALID;
980 m_watchdogs.position_watchdog = gps_watchdog_timeout_ticks;
981 m_n_log_watchdog_period = N_ACTIVE_LOG_WATCHDOG;
983 valid_flag += POS_UPDATE;
986 if (EvalPriority(n0183_msg, active_priority_satellites,
987 priority_map_satellites)) {
989 if (temp_data.n_satellites >= 0) {
990 g_SatsInView = temp_data.n_satellites;
993 m_watchdogs.satellite_watchdog = sat_watchdog_timeout_ticks;
998 SendBasicNavdata(valid_flag, m_log_callbacks);
1002bool CommBridge::HandleN0183_GLL(
const N0183MsgPtr& n0183_msg) {
1003 string str = n0183_msg->payload;
1005 ClearNavData(temp_data);
1008 if (!m_decoder.DecodeGLL(str, temp_data)) bvalid =
false;
1010 if (std::isnan(temp_data.gLat) || std::isnan(temp_data.gLon))
return false;
1013 if (EvalPriority(n0183_msg, active_priority_position,
1014 priority_map_position)) {
1016 gLat = temp_data.gLat;
1017 gLon = temp_data.gLon;
1018 valid_flag += POS_VALID;
1019 m_watchdogs.position_watchdog = gps_watchdog_timeout_ticks;
1020 m_n_log_watchdog_period = N_ACTIVE_LOG_WATCHDOG;
1022 valid_flag += POS_UPDATE;
1025 SendBasicNavdata(valid_flag, m_log_callbacks);
1030 string str = n0183_msg->payload;
1033 wxString sentence(str.c_str());
1035 AisError ais_error = AIS_GENERIC_ERROR;
1036 ais_error = DecodeSingleVDO(sentence, &gpd);
1038 if (ais_error == AIS_NoError) {
1040 if (!std::isnan(gpd.
kLat) && !std::isnan(gpd.
kLon)) {
1041 if (EvalPriority(n0183_msg, active_priority_position,
1042 priority_map_position)) {
1045 valid_flag += POS_UPDATE;
1046 valid_flag += POS_VALID;
1047 m_watchdogs.position_watchdog = gps_watchdog_timeout_ticks;
1048 m_n_log_watchdog_period =
1049 N_ACTIVE_LOG_WATCHDOG;
1053 if (!std::isnan(gpd.
kCog) && !std::isnan(gpd.
kSog)) {
1054 if (EvalPriority(n0183_msg, active_priority_velocity,
1055 priority_map_velocity)) {
1057 valid_flag += SOG_UPDATE;
1059 valid_flag += COG_UPDATE;
1060 m_watchdogs.velocity_watchdog = gps_watchdog_timeout_ticks;
1064 if (!std::isnan(gpd.
kHdt)) {
1065 if (EvalPriority(n0183_msg, active_priority_heading,
1066 priority_map_heading)) {
1068 valid_flag += HDT_UPDATE;
1069 m_watchdogs.heading_watchdog = gps_watchdog_timeout_ticks;
1073 SendBasicNavdata(valid_flag, m_log_callbacks);
1078bool CommBridge::HandleSignalK(
const SignalKMsgPtr& sK_msg) {
1079 string str = sK_msg->raw_message;
1082 if (sK_msg->context_self != sK_msg->context) {
1087 g_ownshipMMSI_SK = sK_msg->context_self;
1090 ClearNavData(temp_data);
1092 if (!m_decoder.DecodeSignalK(str, temp_data))
return false;
1096 if (!std::isnan(temp_data.gLat) && !std::isnan(temp_data.gLon)) {
1097 if (EvalPriority(sK_msg, active_priority_position, priority_map_position)) {
1098 gLat = temp_data.gLat;
1099 gLon = temp_data.gLon;
1100 valid_flag += POS_UPDATE;
1101 valid_flag += POS_VALID;
1102 m_watchdogs.position_watchdog = gps_watchdog_timeout_ticks;
1103 m_n_log_watchdog_period = N_ACTIVE_LOG_WATCHDOG;
1107 if (!std::isnan(temp_data.gSog)) {
1108 if (EvalPriority(sK_msg, active_priority_velocity, priority_map_velocity)) {
1109 gSog = temp_data.gSog;
1110 valid_flag += SOG_UPDATE;
1111 if ((
gSog > 0.05) && !std::isnan(temp_data.gCog)) {
1112 gCog = temp_data.gCog;
1113 valid_flag += COG_UPDATE;
1115 m_watchdogs.velocity_watchdog = gps_watchdog_timeout_ticks;
1119 if (!std::isnan(temp_data.gHdt)) {
1120 if (EvalPriority(sK_msg, active_priority_heading, priority_map_heading)) {
1121 gHdt = temp_data.gHdt;
1122 valid_flag += HDT_UPDATE;
1123 m_watchdogs.heading_watchdog = gps_watchdog_timeout_ticks;
1127 if (!std::isnan(temp_data.gHdm)) {
1128 if (EvalPriority(sK_msg, active_priority_heading, priority_map_heading)) {
1129 gHdm = temp_data.gHdm;
1131 valid_flag += HDT_UPDATE;
1132 m_watchdogs.heading_watchdog = gps_watchdog_timeout_ticks;
1136 if (!std::isnan(temp_data.gVar)) {
1137 if (EvalPriority(sK_msg, active_priority_variation,
1138 priority_map_variation)) {
1139 gVar = temp_data.gVar;
1140 valid_flag += VAR_UPDATE;
1141 m_watchdogs.variation_watchdog = gps_watchdog_timeout_ticks;
1145 if (temp_data.n_satellites > 0) {
1146 if (EvalPriority(sK_msg, active_priority_satellites,
1147 priority_map_satellites)) {
1148 g_SatsInView = temp_data.n_satellites;
1150 m_watchdogs.satellite_watchdog = sat_watchdog_timeout_ticks;
1154 if (g_pMUX && g_pMUX->IsLogActive())
1157 SendBasicNavdata(valid_flag, m_log_callbacks);
1161void CommBridge::ClearPriorityMaps() {
1162 priority_map_position.clear();
1163 priority_map_velocity.clear();
1164 priority_map_heading.clear();
1165 priority_map_variation.clear();
1166 priority_map_satellites.clear();
1170 if (category ==
"position")
1171 return active_priority_position;
1172 else if (category ==
"velocity")
1173 return active_priority_velocity;
1174 else if (category ==
"heading")
1175 return active_priority_heading;
1176 else if (category ==
"variation")
1177 return active_priority_variation;
1178 else if (category ==
"satellites")
1179 return active_priority_satellites;
1181 return active_priority_void;
1184void CommBridge::UpdateAndApplyMaps(
const std::vector<string>& new_maps) {
1185 ApplyPriorityMaps(new_maps);
1187 PresetPriorityContainers();
1190bool CommBridge::LoadConfig() {
1191 if (TheBaseConfig()) {
1192 TheBaseConfig()->SetPath(
"/Settings/CommPriority");
1194 std::vector<string> new_maps;
1195 wxString pri_string;
1197 TheBaseConfig()->Read(
"PriorityPosition", &pri_string);
1198 string s_prio = string(pri_string.c_str());
1199 new_maps.push_back(s_prio);
1201 TheBaseConfig()->Read(
"PriorityVelocity", &pri_string);
1202 s_prio = string(pri_string.c_str());
1203 new_maps.push_back(s_prio);
1205 TheBaseConfig()->Read(
"PriorityHeading", &pri_string);
1206 s_prio = string(pri_string.c_str());
1207 new_maps.push_back(s_prio);
1209 TheBaseConfig()->Read(
"PriorityVariation", &pri_string);
1210 s_prio = string(pri_string.c_str());
1211 new_maps.push_back(s_prio);
1213 TheBaseConfig()->Read(
"PrioritySatellites", &pri_string);
1214 s_prio = string(pri_string.c_str());
1215 new_maps.push_back(s_prio);
1217 ApplyPriorityMaps(new_maps);
1222bool CommBridge::SaveConfig()
const {
1223 if (TheBaseConfig()) {
1224 TheBaseConfig()->SetPath(
"/Settings/CommPriority");
1226 wxString pri_string =
1227 wxString(GetPriorityMap(priority_map_position).c_str());
1228 TheBaseConfig()->Write(
"PriorityPosition", pri_string);
1230 pri_string = wxString(GetPriorityMap(priority_map_velocity).c_str());
1231 TheBaseConfig()->Write(
"PriorityVelocity", pri_string);
1233 pri_string = wxString(GetPriorityMap(priority_map_heading).c_str());
1234 TheBaseConfig()->Write(
"PriorityHeading", pri_string);
1236 pri_string = wxString(GetPriorityMap(priority_map_variation).c_str());
1237 TheBaseConfig()->Write(
"PriorityVariation", pri_string);
1239 pri_string = wxString(GetPriorityMap(priority_map_satellites).c_str());
1240 TheBaseConfig()->Write(
"PrioritySatellites", pri_string);
1245bool CommBridge::EvalPriority(
const NavMsgPtr& msg,
1247 PriorityMap& priority_map) {
1248 string this_key = GetPriorityKey(msg);
1249 if (debug_priority) printf(
"This Key: %s\n", this_key.c_str());
1252 wxStringTokenizer tkz(this_key,
";");
1253 wxString wxs_this_source = tkz.GetNextToken();
1254 string source = wxs_this_source.ToStdString();
1255 wxString wxs_this_identifier = tkz.GetNextToken();
1256 string this_identifier = wxs_this_identifier.ToStdString();
1258 wxStringTokenizer tka(wxs_this_source,
":");
1260 std::stringstream ss;
1261 ss << tka.GetNextToken();
1263 ss >> source_address;
1271 if (msg->bus == NavAddr::Bus::N0183) {
1272 if (!strncmp(active_priority.prio_class.c_str(),
"velocity", 8)) {
1273 bool pos_ok =
false;
1274 if (!strcmp(active_priority_position.active_source.c_str(),
1276 if (active_priority_position.recent_active_time != -1) {
1280 if (!pos_ok)
return false;
1287 auto it = priority_map.find(this_key);
1288 if (it == priority_map.end()) {
1290 size_t n = priority_map.size();
1291 priority_map[this_key] =
static_cast<int>(n);
1294 this_priority = priority_map[this_key];
1296 if (debug_priority) {
1297 for (
const auto& jt : priority_map) {
1298 printf(
" priority_map: %s %d\n", jt.first.c_str(),
1305 if (this_priority > active_priority.active_priority) {
1307 printf(
" Drop low priority: %s %d %d \n", source.c_str(),
1308 this_priority, active_priority.active_priority);
1313 if (this_priority < active_priority.active_priority) {
1314 active_priority.active_priority = this_priority;
1315 active_priority.active_source = source;
1316 active_priority.active_identifier = this_identifier;
1317 active_priority.active_source_address = source_address;
1318 wxDateTime now = wxDateTime::Now();
1319 active_priority.recent_active_time = now.GetTicks();
1322 printf(
" Restoring high priority: %s %d\n", source.c_str(),
1330 if (!active_priority.active_source.empty()) {
1331 if (debug_priority) printf(
"source: %s\n", source.c_str());
1333 printf(
"active_source: %s\n", active_priority.active_source.c_str());
1335 if (source != active_priority.active_source) {
1338 int lowest_priority = -10;
1339 for (
const auto& jt : priority_map) {
1340 if (jt.second > lowest_priority) lowest_priority = jt.second;
1343 priority_map[this_key] = lowest_priority + 1;
1345 printf(
" Lowering priority A: %s :%d\n", source.c_str(),
1346 priority_map[this_key]);
1354 if (msg->bus == NavAddr::Bus::N0183) {
1355 auto msg_0183 = std::dynamic_pointer_cast<const Nmea0183Msg>(msg);
1357 if (!active_priority.active_identifier.empty()) {
1359 printf(
"this_identifier: %s\n", this_identifier.c_str());
1361 printf(
"active_priority.active_identifier: %s\n",
1362 active_priority.active_identifier.c_str());
1364 if (this_identifier != active_priority.active_identifier) {
1367 if (priority_map[this_key] == active_priority.active_priority) {
1368 int lowest_priority = -10;
1369 for (
const auto& jt : priority_map) {
1370 if (jt.second > lowest_priority) lowest_priority = jt.second;
1373 priority_map[this_key] = lowest_priority + 1;
1375 printf(
" Lowering priority B: %s :%d\n", source.c_str(),
1376 priority_map[this_key]);
1387 else if (msg->bus == NavAddr::Bus::N2000) {
1388 auto msg_n2k = std::dynamic_pointer_cast<const Nmea2000Msg>(msg);
1390 if (!active_priority.active_identifier.empty()) {
1391 if (this_identifier != active_priority.active_identifier) {
1394 if (priority_map[this_key] == active_priority.active_priority) {
1395 int lowest_priority = -10;
1396 for (
const auto& jt : priority_map) {
1397 if (jt.second > lowest_priority) lowest_priority = jt.second;
1400 priority_map[this_key] = lowest_priority + 1;
1402 printf(
" Lowering priority: %s :%d\n", source.c_str(),
1403 priority_map[this_key]);
1413 active_priority.active_source = source;
1414 active_priority.active_identifier = this_identifier;
1415 active_priority.active_source_address = source_address;
1416 wxDateTime now = wxDateTime::Now();
1417 active_priority.recent_active_time = now.GetTicks();
1419 printf(
" Accepting high priority: %s %d\n", source.c_str(), this_priority);
1421 if (active_priority.prio_class ==
"position") {
1422 if (this_priority != m_last_position_priority) {
1423 m_last_position_priority = this_priority;
1426 msg_.Printf(_(
"GNSS position fix priority shift:") +
" %s\n %s \n -> %s",
1427 this_identifier.c_str(), m_last_position_source.c_str(),
1429 auto& noteman = NotificationManager::GetInstance();
1430 noteman.AddNotification(NotificationSeverity::kInformational,
1431 msg_.ToStdString());
1433 m_last_position_source = source;
void Notify(const std::shared_ptr< const AppMsg > &msg)
Send message to everyone listening to given message type.
string key() const override
Return unique key used by observable to notify/listen.
string to_string() const override
Return printable string for logging etc without trailing nl.
Process incoming messages.
bool HandleN0183_AIVDO(const N0183MsgPtr &n0183_msg)
Processes NMEA 0183 AIVDO sentences containing own vessel's AIS data.
void LogInputMessage(const std::shared_ptr< const NavMsg > &msg, bool is_filtered, bool is_error, const wxString &error_msg="") const
Logs an input message with context information.
Actual data sent between application and transport layer.
Representation of message status as determined by the multiplexer.
A regular Nmea0183 message.
See: https://github.com/OpenCPN/OpenCPN/issues/2729#issuecomment-1179506343.
virtual bool IsVisible() const =0
Return true if log is visible i.e., if it's any point using Add().
virtual void Add(const Logline &l)=0
Add a formatted string to log output.
void Init(const KeyProvider &kp, const std::function< void(ObservedEvt &ev)> &action)
Initiate an object yet not listening.
Custom event class for OpenCPN's notification system.
A parsed SignalK message over ipv4.
Decoded messages send/receive support.
CommBridge class and helpers.
Driver registration container, a singleton.
Raw messages layer, supports sending and recieving navmsg messages.
bool g_bSatValid
Indicates valid GNSS reception status based on satellite visibility and successful parsing of NMEA018...
Variables maintained by comm stack, read-only access for others.
Global variables stored in configuration file.
Extern C linked utilities.
Hooks into gui available in model.
GUI constant definitions.
Multiplexer class and helpers.
User notifications manager.
double gHdm
Magnetic heading in degrees (0-359.99).
double gVar
Magnetic variation in degrees.
double gHdt
True heading in degrees (0-359.99).
double gLat
Vessel's current latitude in decimal degrees.
double gCog
Course over ground in degrees (0-359.99).
double gSog
Speed over ground in knots.
double gLon
Vessel's current longitude in decimal degrees.
Position, course, speed, etc.
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.