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 ==
"HDG")
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();
253CommBridge::CommBridge()
256 active_priority_position(
"position"),
257 active_priority_velocity(
"velocity"),
258 active_priority_heading(
"heading"),
259 active_priority_variation(
"variation"),
260 active_priority_satellites(
"satellites"),
261 active_priority_void(
"", -1),
262 m_n_log_watchdog_period(3600),
263 m_last_position_priority(0) {
264 Bind(wxEVT_TIMER, [&](wxTimerEvent&) { OnWatchdogTimer(); });
266CommBridge::~CommBridge() =
default;
268bool CommBridge::Initialize() {
269 m_log_callbacks = GetLogCallbacks();
273 PresetPriorityContainers();
278 m_watchdog_timer.SetOwner(
this, WATCHDOG_TIMER);
279 m_watchdog_timer.Start(1000, wxTIMER_CONTINUOUS);
284 m_driver_change_lstnr.
Init(
285 CommDriverRegistry::GetInstance().evt_driverlist_change,
286 [&](
const wxCommandEvent& ev) { OnDriverStateChange(); });
291void CommBridge::PresetWatchdogs() {
292 m_watchdogs.position_watchdog =
294 m_watchdogs.velocity_watchdog = 20;
295 m_watchdogs.variation_watchdog = 20;
296 m_watchdogs.heading_watchdog = 20;
297 m_watchdogs.satellite_watchdog = 20;
300void CommBridge::OnWatchdogTimer() {
302 m_watchdogs.position_watchdog--;
303 if (m_watchdogs.position_watchdog <= 0) {
304 if (m_watchdogs.position_watchdog % 5 == 0) {
306 auto msg = std::make_shared<GPSWatchdogMsg>(
307 GPSWatchdogMsg::WDSource::position, m_watchdogs.position_watchdog);
308 auto& msgbus = AppMsgBus::GetInstance();
309 LogAppMsg(msg,
"watchdog", m_log_callbacks);
310 msgbus.Notify(std::move(msg));
312 if (m_watchdogs.position_watchdog % m_n_log_watchdog_period == 0) {
314 logmsg.Printf(
" ***GPS Watchdog timeout at Lat:%g Lon: %g",
gLat,
316 wxLogMessage(logmsg);
324 active_priority_position.recent_active_time = -1;
328 if (IsNextLowerPriorityAvailable(priority_map_position,
329 active_priority_position)) {
330 SelectNextLowerPriority(priority_map_position, active_priority_position);
335 m_watchdogs.velocity_watchdog--;
336 if (m_watchdogs.velocity_watchdog <= 0) {
339 active_priority_velocity.recent_active_time = -1;
341 if (g_nNMEADebug && (m_watchdogs.velocity_watchdog == 0))
342 wxLogMessage(
" ***Velocity Watchdog timeout...");
343 if (m_watchdogs.velocity_watchdog % 5 == 0) {
345 auto msg = std::make_shared<GPSWatchdogMsg>(
346 GPSWatchdogMsg::WDSource::velocity, m_watchdogs.velocity_watchdog);
347 auto& msgbus = AppMsgBus::GetInstance();
348 msgbus.Notify(std::move(msg));
352 SelectNextLowerPriority(priority_map_velocity, active_priority_velocity);
356 m_watchdogs.heading_watchdog--;
357 if (m_watchdogs.heading_watchdog <= 0) {
359 active_priority_heading.recent_active_time = -1;
360 if (g_nNMEADebug && (m_watchdogs.heading_watchdog == 0))
361 wxLogMessage(
" ***HDT Watchdog timeout...");
365 SelectNextLowerPriority(priority_map_heading, active_priority_heading);
369 m_watchdogs.variation_watchdog--;
370 if (m_watchdogs.variation_watchdog <= 0) {
372 active_priority_variation.recent_active_time = -1;
374 if (g_nNMEADebug && (m_watchdogs.variation_watchdog == 0))
375 wxLogMessage(
" ***VAR Watchdog timeout...");
379 SelectNextLowerPriority(priority_map_variation, active_priority_variation);
383 m_watchdogs.satellite_watchdog--;
384 if (m_watchdogs.satellite_watchdog <= 0) {
388 active_priority_satellites.recent_active_time = -1;
390 if (g_nNMEADebug && (m_watchdogs.satellite_watchdog == 0))
391 wxLogMessage(
" ***SAT Watchdog timeout...");
395 SelectNextLowerPriority(priority_map_satellites,
396 active_priority_satellites);
400void CommBridge::MakeHDTFromHDM() {
403 if (!std::isnan(
gHdm)) {
406 if (std::isnan(
gVar) && (g_UserVar != 0.0))
gVar = g_UserVar;
408 if (!std::isnan(
gHdt)) {
411 else if (
gHdt >= 360)
414 m_watchdogs.heading_watchdog = gps_watchdog_timeout_ticks;
419void CommBridge::InitCommListeners() {
425 HandleN2K_129029(UnpackEvtPointer<Nmea2000Msg>(ev));
431 HandleN2K_129025(UnpackEvtPointer<Nmea2000Msg>(ev));
437 HandleN2K_129026(UnpackEvtPointer<Nmea2000Msg>(ev));
443 HandleN2K_127250(UnpackEvtPointer<Nmea2000Msg>(ev));
449 HandleN2K_129540(UnpackEvtPointer<Nmea2000Msg>(ev));
456 HandleN0183_RMC(UnpackEvtPointer<Nmea0183Msg>(ev));
461 HandleN0183_THS(UnpackEvtPointer<Nmea0183Msg>(ev));
466 HandleN0183_HDT(UnpackEvtPointer<Nmea0183Msg>(ev));
471 HandleN0183_HDG(UnpackEvtPointer<Nmea0183Msg>(ev));
476 HandleN0183_HDM(UnpackEvtPointer<Nmea0183Msg>(ev));
481 HandleN0183_VTG(UnpackEvtPointer<Nmea0183Msg>(ev));
486 HandleN0183_GSV(UnpackEvtPointer<Nmea0183Msg>(ev));
491 HandleN0183_GGA(UnpackEvtPointer<Nmea0183Msg>(ev));
497 HandleN0183_GLL(UnpackEvtPointer<Nmea0183Msg>(ev));
507 HandleSignalK(UnpackEvtPointer<SignalkMsg>(ev));
511void CommBridge::OnDriverStateChange() {
513 PresetPriorityContainers();
516std::vector<string> CommBridge::GetPriorityMaps()
const {
517 std::vector<string> result;
518 result.push_back(GetPriorityMap(priority_map_position));
519 result.push_back(GetPriorityMap(priority_map_velocity));
520 result.push_back(GetPriorityMap(priority_map_heading));
521 result.push_back(GetPriorityMap(priority_map_variation));
522 result.push_back(GetPriorityMap(priority_map_satellites));
526void CommBridge::ApplyPriorityMaps(
const std::vector<string>& new_maps) {
527 wxString new_prio_string = wxString(new_maps[0].c_str());
528 ApplyPriorityMap(priority_map_position, new_prio_string, 0);
530 new_prio_string = wxString(new_maps[1].c_str());
531 ApplyPriorityMap(priority_map_velocity, new_prio_string, 1);
533 new_prio_string = wxString(new_maps[2].c_str());
534 ApplyPriorityMap(priority_map_heading, new_prio_string, 2);
536 new_prio_string = wxString(new_maps[3].c_str());
537 ApplyPriorityMap(priority_map_variation, new_prio_string, 3);
539 new_prio_string = wxString(new_maps[4].c_str());
540 ApplyPriorityMap(priority_map_satellites, new_prio_string, 4);
543void CommBridge::PresetPriorityContainers() {
544 PresetPriorityContainer(active_priority_position, priority_map_position);
545 PresetPriorityContainer(active_priority_velocity, priority_map_velocity);
546 PresetPriorityContainer(active_priority_heading, priority_map_heading);
547 PresetPriorityContainer(active_priority_variation, priority_map_variation);
548 PresetPriorityContainer(active_priority_satellites, priority_map_satellites);
551bool CommBridge::HandleN2K_129029(
const N2000MsgPtr& n2k_msg) {
552 std::vector<unsigned char> v = n2k_msg->payload;
556 ClearNavData(temp_data);
558 if (!m_decoder.DecodePGN129029(v, temp_data))
return false;
561 if (!N2kIsNA(temp_data.gLat) && !N2kIsNA(temp_data.gLon)) {
562 if (EvalPriority(n2k_msg, active_priority_position,
563 priority_map_position)) {
564 gLat = temp_data.gLat;
565 gLon = temp_data.gLon;
566 valid_flag += POS_UPDATE;
567 valid_flag += POS_VALID;
568 m_watchdogs.position_watchdog = gps_watchdog_timeout_ticks;
569 m_n_log_watchdog_period = N_ACTIVE_LOG_WATCHDOG;
573 if (temp_data.n_satellites >= 0) {
574 if (EvalPriority(n2k_msg, active_priority_satellites,
575 priority_map_satellites)) {
576 g_SatsInView = temp_data.n_satellites;
578 m_watchdogs.satellite_watchdog = sat_watchdog_timeout_ticks;
582 SendBasicNavdata(valid_flag, m_log_callbacks);
586bool CommBridge::HandleN2K_129025(
const N2000MsgPtr& n2k_msg) {
587 std::vector<unsigned char> v = n2k_msg->payload;
590 ClearNavData(temp_data);
592 if (!m_decoder.DecodePGN129025(v, temp_data))
return false;
595 if (!N2kIsNA(temp_data.gLat) && !N2kIsNA(temp_data.gLon)) {
596 if (EvalPriority(n2k_msg, active_priority_position,
597 priority_map_position)) {
598 gLat = temp_data.gLat;
599 gLon = temp_data.gLon;
600 valid_flag += POS_UPDATE;
601 valid_flag += POS_VALID;
602 m_watchdogs.position_watchdog = gps_watchdog_timeout_ticks;
603 m_n_log_watchdog_period = N_ACTIVE_LOG_WATCHDOG;
610 SendBasicNavdata(valid_flag, m_log_callbacks);
614bool CommBridge::HandleN2K_129026(
const N2000MsgPtr& n2k_msg) {
615 std::vector<unsigned char> v = n2k_msg->payload;
618 ClearNavData(temp_data);
620 if (!m_decoder.DecodePGN129026(v, temp_data))
return false;
623 if (!N2kIsNA(temp_data.gSog)) {
624 if (EvalPriority(n2k_msg, active_priority_velocity,
625 priority_map_velocity)) {
626 gSog = MS2KNOTS(temp_data.gSog);
627 valid_flag += SOG_UPDATE;
629 if (N2kIsNA(temp_data.gCog))
632 gCog = GeodesicRadToDeg(temp_data.gCog);
633 valid_flag += COG_UPDATE;
634 m_watchdogs.velocity_watchdog = gps_watchdog_timeout_ticks;
639 SendBasicNavdata(valid_flag, m_log_callbacks);
643bool CommBridge::HandleN2K_127250(
const N2000MsgPtr& n2k_msg) {
644 std::vector<unsigned char> v = n2k_msg->payload;
647 ClearNavData(temp_data);
649 if (!m_decoder.DecodePGN127250(v, temp_data))
return false;
652 if (!N2kIsNA(temp_data.gVar)) {
653 if (EvalPriority(n2k_msg, active_priority_variation,
654 priority_map_variation)) {
655 gVar = GeodesicRadToDeg(temp_data.gVar);
656 valid_flag += VAR_UPDATE;
657 m_watchdogs.variation_watchdog = gps_watchdog_timeout_ticks;
661 if (!N2kIsNA(temp_data.gHdt)) {
662 if (EvalPriority(n2k_msg, active_priority_heading, priority_map_heading)) {
663 gHdt = GeodesicRadToDeg(temp_data.gHdt);
664 valid_flag += HDT_UPDATE;
665 m_watchdogs.heading_watchdog = gps_watchdog_timeout_ticks;
669 if (!N2kIsNA(temp_data.gHdm)) {
670 gHdm = GeodesicRadToDeg(temp_data.gHdm);
671 if (EvalPriority(n2k_msg, active_priority_heading, priority_map_heading)) {
673 valid_flag += HDT_UPDATE;
674 if (!std::isnan(
gHdt))
675 m_watchdogs.heading_watchdog = gps_watchdog_timeout_ticks;
679 SendBasicNavdata(valid_flag, m_log_callbacks);
683bool CommBridge::HandleN2K_129540(
const N2000MsgPtr& n2k_msg) {
684 std::vector<unsigned char> v = n2k_msg->payload;
687 ClearNavData(temp_data);
689 if (!m_decoder.DecodePGN129540(v, temp_data))
return false;
691 if (temp_data.n_satellites >= 0) {
692 if (EvalPriority(n2k_msg, active_priority_satellites,
693 priority_map_satellites)) {
694 g_SatsInView = temp_data.n_satellites;
696 m_watchdogs.satellite_watchdog = sat_watchdog_timeout_ticks;
703bool CommBridge::HandleN0183_RMC(
const N0183MsgPtr& n0183_msg) {
704 string str = n0183_msg->payload;
707 ClearNavData(temp_data);
709 bool is_valid =
true;
710 if (!m_decoder.DecodeRMC(str, temp_data)) is_valid =
false;
712 if (std::isnan(temp_data.gLat) || std::isnan(temp_data.gLon))
return false;
715 if (EvalPriority(n0183_msg, active_priority_position,
716 priority_map_position)) {
718 gLat = temp_data.gLat;
719 gLon = temp_data.gLon;
720 valid_flag += POS_VALID;
721 m_watchdogs.position_watchdog = gps_watchdog_timeout_ticks;
722 m_n_log_watchdog_period = N_ACTIVE_LOG_WATCHDOG;
724 valid_flag += POS_UPDATE;
727 if (EvalPriority(n0183_msg, active_priority_velocity,
728 priority_map_velocity)) {
730 gSog = temp_data.gSog;
731 valid_flag += SOG_UPDATE;
732 gCog = temp_data.gCog;
733 valid_flag += COG_UPDATE;
734 m_watchdogs.velocity_watchdog = gps_watchdog_timeout_ticks;
738 if (!std::isnan(temp_data.gVar)) {
739 if (EvalPriority(n0183_msg, active_priority_variation,
740 priority_map_variation)) {
742 gVar = temp_data.gVar;
743 valid_flag += VAR_UPDATE;
744 m_watchdogs.variation_watchdog = gps_watchdog_timeout_ticks;
754 if ((valid_flag & POS_VALID) == POS_VALID) {
756 if (g_SatsInView < 4) {
758 m_watchdogs.satellite_watchdog = sat_watchdog_timeout_ticks;
763 SendBasicNavdata(valid_flag, m_log_callbacks);
767bool CommBridge::HandleN0183_THS(
const N0183MsgPtr& n0183_msg) {
768 string str = n0183_msg->payload;
770 ClearNavData(temp_data);
772 if (!m_decoder.DecodeTHS(str, temp_data))
return false;
775 if (EvalPriority(n0183_msg, active_priority_heading, priority_map_heading)) {
776 gHdt = temp_data.gHdt;
777 valid_flag += HDT_UPDATE;
778 m_watchdogs.heading_watchdog = gps_watchdog_timeout_ticks;
781 SendBasicNavdata(valid_flag, m_log_callbacks);
785bool CommBridge::HandleN0183_HDT(
const N0183MsgPtr& n0183_msg) {
786 string str = n0183_msg->payload;
788 ClearNavData(temp_data);
790 if (!m_decoder.DecodeHDT(str, temp_data))
return false;
793 if (EvalPriority(n0183_msg, active_priority_heading, priority_map_heading)) {
794 gHdt = temp_data.gHdt;
795 valid_flag += HDT_UPDATE;
796 m_watchdogs.heading_watchdog = gps_watchdog_timeout_ticks;
799 SendBasicNavdata(valid_flag, m_log_callbacks);
803bool CommBridge::HandleN0183_HDG(
const N0183MsgPtr& n0183_msg) {
804 string str = n0183_msg->payload;
806 ClearNavData(temp_data);
808 if (!m_decoder.DecodeHDG(str, temp_data))
return false;
813 if (!std::isnan(temp_data.gHdm)) {
814 if (EvalPriority(n0183_msg, active_priority_heading,
815 priority_map_heading)) {
816 gHdm = temp_data.gHdm;
817 m_watchdogs.heading_watchdog = gps_watchdog_timeout_ticks;
822 if (!std::isnan(temp_data.gVar)) {
823 if (EvalPriority(n0183_msg, active_priority_variation,
824 priority_map_variation)) {
825 gVar = temp_data.gVar;
826 valid_flag += VAR_UPDATE;
827 m_watchdogs.variation_watchdog = gps_watchdog_timeout_ticks;
831 if (bHDM) MakeHDTFromHDM();
833 SendBasicNavdata(valid_flag, m_log_callbacks);
837bool CommBridge::HandleN0183_HDM(
const N0183MsgPtr& n0183_msg) {
838 string str = n0183_msg->payload;
840 ClearNavData(temp_data);
842 if (!m_decoder.DecodeHDM(str, temp_data))
return false;
845 if (EvalPriority(n0183_msg, active_priority_heading, priority_map_heading)) {
846 gHdm = temp_data.gHdm;
848 valid_flag += HDT_UPDATE;
849 m_watchdogs.heading_watchdog = gps_watchdog_timeout_ticks;
852 SendBasicNavdata(valid_flag, m_log_callbacks);
856bool CommBridge::HandleN0183_VTG(
const N0183MsgPtr& n0183_msg) {
857 string str = n0183_msg->payload;
859 ClearNavData(temp_data);
861 if (!m_decoder.DecodeVTG(str, temp_data))
return false;
864 if (EvalPriority(n0183_msg, active_priority_velocity,
865 priority_map_velocity)) {
866 gSog = temp_data.gSog;
867 valid_flag += SOG_UPDATE;
868 gCog = temp_data.gCog;
869 valid_flag += COG_UPDATE;
870 m_watchdogs.velocity_watchdog = gps_watchdog_timeout_ticks;
873 SendBasicNavdata(valid_flag, m_log_callbacks);
877bool CommBridge::HandleN0183_GSV(
const N0183MsgPtr& n0183_msg) {
878 string str = n0183_msg->payload;
880 ClearNavData(temp_data);
882 if (!m_decoder.DecodeGSV(str, temp_data))
return false;
885 if (EvalPriority(n0183_msg, active_priority_satellites,
886 priority_map_satellites)) {
887 if (temp_data.n_satellites >= 0) {
888 g_SatsInView = temp_data.n_satellites;
891 m_watchdogs.satellite_watchdog = sat_watchdog_timeout_ticks;
895 SendBasicNavdata(valid_flag, m_log_callbacks);
899bool CommBridge::HandleN0183_GGA(
const N0183MsgPtr& n0183_msg) {
900 string str = n0183_msg->payload;
902 ClearNavData(temp_data);
904 bool is_valid =
true;
905 if (!m_decoder.DecodeGGA(str, temp_data)) is_valid =
false;
907 if (std::isnan(temp_data.gLat) || std::isnan(temp_data.gLon))
return false;
910 if (EvalPriority(n0183_msg, active_priority_position,
911 priority_map_position)) {
913 gLat = temp_data.gLat;
914 gLon = temp_data.gLon;
915 valid_flag += POS_VALID;
916 m_watchdogs.position_watchdog = gps_watchdog_timeout_ticks;
917 m_n_log_watchdog_period = N_ACTIVE_LOG_WATCHDOG;
919 valid_flag += POS_UPDATE;
922 if (EvalPriority(n0183_msg, active_priority_satellites,
923 priority_map_satellites)) {
925 if (temp_data.n_satellites >= 0) {
926 g_SatsInView = temp_data.n_satellites;
929 m_watchdogs.satellite_watchdog = sat_watchdog_timeout_ticks;
934 SendBasicNavdata(valid_flag, m_log_callbacks);
938bool CommBridge::HandleN0183_GLL(
const N0183MsgPtr& n0183_msg) {
939 string str = n0183_msg->payload;
941 ClearNavData(temp_data);
944 if (!m_decoder.DecodeGLL(str, temp_data)) bvalid =
false;
946 if (std::isnan(temp_data.gLat) || std::isnan(temp_data.gLon))
return false;
949 if (EvalPriority(n0183_msg, active_priority_position,
950 priority_map_position)) {
952 gLat = temp_data.gLat;
953 gLon = temp_data.gLon;
954 valid_flag += POS_VALID;
955 m_watchdogs.position_watchdog = gps_watchdog_timeout_ticks;
956 m_n_log_watchdog_period = N_ACTIVE_LOG_WATCHDOG;
958 valid_flag += POS_UPDATE;
961 SendBasicNavdata(valid_flag, m_log_callbacks);
966 string str = n0183_msg->payload;
969 wxString sentence(str.c_str());
971 AisError ais_error = AIS_GENERIC_ERROR;
972 ais_error = DecodeSingleVDO(sentence, &gpd);
974 if (ais_error == AIS_NoError) {
976 if (!std::isnan(gpd.
kLat) && !std::isnan(gpd.
kLon)) {
977 if (EvalPriority(n0183_msg, active_priority_position,
978 priority_map_position)) {
981 valid_flag += POS_UPDATE;
982 valid_flag += POS_VALID;
983 m_watchdogs.position_watchdog = gps_watchdog_timeout_ticks;
984 m_n_log_watchdog_period =
985 N_ACTIVE_LOG_WATCHDOG;
989 if (!std::isnan(gpd.
kCog) && !std::isnan(gpd.
kSog)) {
990 if (EvalPriority(n0183_msg, active_priority_velocity,
991 priority_map_velocity)) {
993 valid_flag += SOG_UPDATE;
995 valid_flag += COG_UPDATE;
996 m_watchdogs.velocity_watchdog = gps_watchdog_timeout_ticks;
1000 if (!std::isnan(gpd.
kHdt)) {
1001 if (EvalPriority(n0183_msg, active_priority_heading,
1002 priority_map_heading)) {
1004 valid_flag += HDT_UPDATE;
1005 m_watchdogs.heading_watchdog = gps_watchdog_timeout_ticks;
1009 SendBasicNavdata(valid_flag, m_log_callbacks);
1014bool CommBridge::HandleSignalK(
const SignalKMsgPtr& sK_msg) {
1015 string str = sK_msg->raw_message;
1018 if (sK_msg->context_self != sK_msg->context) {
1023 g_ownshipMMSI_SK = sK_msg->context_self;
1026 ClearNavData(temp_data);
1028 if (!m_decoder.DecodeSignalK(str, temp_data))
return false;
1032 if (!std::isnan(temp_data.gLat) && !std::isnan(temp_data.gLon)) {
1033 if (EvalPriority(sK_msg, active_priority_position, priority_map_position)) {
1034 gLat = temp_data.gLat;
1035 gLon = temp_data.gLon;
1036 valid_flag += POS_UPDATE;
1037 valid_flag += POS_VALID;
1038 m_watchdogs.position_watchdog = gps_watchdog_timeout_ticks;
1039 m_n_log_watchdog_period = N_ACTIVE_LOG_WATCHDOG;
1043 if (!std::isnan(temp_data.gSog)) {
1044 if (EvalPriority(sK_msg, active_priority_velocity, priority_map_velocity)) {
1045 gSog = temp_data.gSog;
1046 valid_flag += SOG_UPDATE;
1047 if ((
gSog > 0.05) && !std::isnan(temp_data.gCog)) {
1048 gCog = temp_data.gCog;
1049 valid_flag += COG_UPDATE;
1051 m_watchdogs.velocity_watchdog = gps_watchdog_timeout_ticks;
1055 if (!std::isnan(temp_data.gHdt)) {
1056 if (EvalPriority(sK_msg, active_priority_heading, priority_map_heading)) {
1057 gHdt = temp_data.gHdt;
1058 valid_flag += HDT_UPDATE;
1059 m_watchdogs.heading_watchdog = gps_watchdog_timeout_ticks;
1063 if (!std::isnan(temp_data.gHdm)) {
1064 if (EvalPriority(sK_msg, active_priority_heading, priority_map_heading)) {
1065 gHdm = temp_data.gHdm;
1067 valid_flag += HDT_UPDATE;
1068 m_watchdogs.heading_watchdog = gps_watchdog_timeout_ticks;
1072 if (!std::isnan(temp_data.gVar)) {
1073 if (EvalPriority(sK_msg, active_priority_variation,
1074 priority_map_variation)) {
1075 gVar = temp_data.gVar;
1076 valid_flag += VAR_UPDATE;
1077 m_watchdogs.variation_watchdog = gps_watchdog_timeout_ticks;
1081 if (temp_data.n_satellites > 0) {
1082 if (EvalPriority(sK_msg, active_priority_satellites,
1083 priority_map_satellites)) {
1084 g_SatsInView = temp_data.n_satellites;
1086 m_watchdogs.satellite_watchdog = sat_watchdog_timeout_ticks;
1090 if (g_pMUX && g_pMUX->IsLogActive())
1093 SendBasicNavdata(valid_flag, m_log_callbacks);
1097void CommBridge::ClearPriorityMaps() {
1098 priority_map_position.clear();
1099 priority_map_velocity.clear();
1100 priority_map_heading.clear();
1101 priority_map_variation.clear();
1102 priority_map_satellites.clear();
1106 if (category ==
"position")
1107 return active_priority_position;
1108 else if (category ==
"velocity")
1109 return active_priority_velocity;
1110 else if (category ==
"heading")
1111 return active_priority_heading;
1112 else if (category ==
"variation")
1113 return active_priority_variation;
1114 else if (category ==
"satellites")
1115 return active_priority_satellites;
1117 return active_priority_void;
1120void CommBridge::UpdateAndApplyMaps(
const std::vector<string>& new_maps) {
1121 ApplyPriorityMaps(new_maps);
1123 PresetPriorityContainers();
1126bool CommBridge::LoadConfig() {
1127 if (TheBaseConfig()) {
1128 TheBaseConfig()->SetPath(
"/Settings/CommPriority");
1130 std::vector<string> new_maps;
1131 wxString pri_string;
1133 TheBaseConfig()->Read(
"PriorityPosition", &pri_string);
1134 string s_prio = string(pri_string.c_str());
1135 new_maps.push_back(s_prio);
1137 TheBaseConfig()->Read(
"PriorityVelocity", &pri_string);
1138 s_prio = string(pri_string.c_str());
1139 new_maps.push_back(s_prio);
1141 TheBaseConfig()->Read(
"PriorityHeading", &pri_string);
1142 s_prio = string(pri_string.c_str());
1143 new_maps.push_back(s_prio);
1145 TheBaseConfig()->Read(
"PriorityVariation", &pri_string);
1146 s_prio = string(pri_string.c_str());
1147 new_maps.push_back(s_prio);
1149 TheBaseConfig()->Read(
"PrioritySatellites", &pri_string);
1150 s_prio = string(pri_string.c_str());
1151 new_maps.push_back(s_prio);
1153 ApplyPriorityMaps(new_maps);
1158bool CommBridge::SaveConfig()
const {
1159 if (TheBaseConfig()) {
1160 TheBaseConfig()->SetPath(
"/Settings/CommPriority");
1162 wxString pri_string =
1163 wxString(GetPriorityMap(priority_map_position).c_str());
1164 TheBaseConfig()->Write(
"PriorityPosition", pri_string);
1166 pri_string = wxString(GetPriorityMap(priority_map_velocity).c_str());
1167 TheBaseConfig()->Write(
"PriorityVelocity", pri_string);
1169 pri_string = wxString(GetPriorityMap(priority_map_heading).c_str());
1170 TheBaseConfig()->Write(
"PriorityHeading", pri_string);
1172 pri_string = wxString(GetPriorityMap(priority_map_variation).c_str());
1173 TheBaseConfig()->Write(
"PriorityVariation", pri_string);
1175 pri_string = wxString(GetPriorityMap(priority_map_satellites).c_str());
1176 TheBaseConfig()->Write(
"PrioritySatellites", pri_string);
1181bool CommBridge::EvalPriority(
const NavMsgPtr& msg,
1183 PriorityMap& priority_map) {
1184 string this_key = GetPriorityKey(msg);
1185 if (debug_priority) printf(
"This Key: %s\n", this_key.c_str());
1188 wxStringTokenizer tkz(this_key,
";");
1189 wxString wxs_this_source = tkz.GetNextToken();
1190 string source = wxs_this_source.ToStdString();
1191 wxString wxs_this_identifier = tkz.GetNextToken();
1192 string this_identifier = wxs_this_identifier.ToStdString();
1194 wxStringTokenizer tka(wxs_this_source,
":");
1196 std::stringstream ss;
1197 ss << tka.GetNextToken();
1199 ss >> source_address;
1207 if (msg->bus == NavAddr::Bus::N0183) {
1208 if (!strncmp(active_priority.prio_class.c_str(),
"velocity", 8)) {
1209 bool pos_ok =
false;
1210 if (!strcmp(active_priority_position.active_source.c_str(),
1212 if (active_priority_position.recent_active_time != -1) {
1216 if (!pos_ok)
return false;
1223 auto it = priority_map.find(this_key);
1224 if (it == priority_map.end()) {
1226 size_t n = priority_map.size();
1227 priority_map[this_key] =
static_cast<int>(n);
1230 this_priority = priority_map[this_key];
1232 if (debug_priority) {
1233 for (
const auto& jt : priority_map) {
1234 printf(
" priority_map: %s %d\n", jt.first.c_str(),
1241 if (this_priority > active_priority.active_priority) {
1243 printf(
" Drop low priority: %s %d %d \n", source.c_str(),
1244 this_priority, active_priority.active_priority);
1249 if (this_priority < active_priority.active_priority) {
1250 active_priority.active_priority = this_priority;
1251 active_priority.active_source = source;
1252 active_priority.active_identifier = this_identifier;
1253 active_priority.active_source_address = source_address;
1254 wxDateTime now = wxDateTime::Now();
1255 active_priority.recent_active_time = now.GetTicks();
1258 printf(
" Restoring high priority: %s %d\n", source.c_str(),
1266 if (!active_priority.active_source.empty()) {
1267 if (debug_priority) printf(
"source: %s\n", source.c_str());
1269 printf(
"active_source: %s\n", active_priority.active_source.c_str());
1271 if (source != active_priority.active_source) {
1274 int lowest_priority = -10;
1275 for (
const auto& jt : priority_map) {
1276 if (jt.second > lowest_priority) lowest_priority = jt.second;
1279 priority_map[this_key] = lowest_priority + 1;
1281 printf(
" Lowering priority A: %s :%d\n", source.c_str(),
1282 priority_map[this_key]);
1290 if (msg->bus == NavAddr::Bus::N0183) {
1291 auto msg_0183 = std::dynamic_pointer_cast<const Nmea0183Msg>(msg);
1293 if (!active_priority.active_identifier.empty()) {
1295 printf(
"this_identifier: %s\n", this_identifier.c_str());
1297 printf(
"active_priority.active_identifier: %s\n",
1298 active_priority.active_identifier.c_str());
1300 if (this_identifier != active_priority.active_identifier) {
1303 if (priority_map[this_key] == active_priority.active_priority) {
1304 int lowest_priority = -10;
1305 for (
const auto& jt : priority_map) {
1306 if (jt.second > lowest_priority) lowest_priority = jt.second;
1309 priority_map[this_key] = lowest_priority + 1;
1311 printf(
" Lowering priority B: %s :%d\n", source.c_str(),
1312 priority_map[this_key]);
1323 else if (msg->bus == NavAddr::Bus::N2000) {
1324 auto msg_n2k = std::dynamic_pointer_cast<const Nmea2000Msg>(msg);
1326 if (!active_priority.active_identifier.empty()) {
1327 if (this_identifier != active_priority.active_identifier) {
1330 if (priority_map[this_key] == active_priority.active_priority) {
1331 int lowest_priority = -10;
1332 for (
const auto& jt : priority_map) {
1333 if (jt.second > lowest_priority) lowest_priority = jt.second;
1336 priority_map[this_key] = lowest_priority + 1;
1338 printf(
" Lowering priority: %s :%d\n", source.c_str(),
1339 priority_map[this_key]);
1349 active_priority.active_source = source;
1350 active_priority.active_identifier = this_identifier;
1351 active_priority.active_source_address = source_address;
1352 wxDateTime now = wxDateTime::Now();
1353 active_priority.recent_active_time = now.GetTicks();
1355 printf(
" Accepting high priority: %s %d\n", source.c_str(), this_priority);
1357 if (active_priority.prio_class ==
"position") {
1358 if (this_priority != m_last_position_priority) {
1359 m_last_position_priority = this_priority;
1362 msg_.Printf(_(
"GNSS position fix priority shift:") +
" %s\n %s \n -> %s",
1363 this_identifier.c_str(), m_last_position_source.c_str(),
1365 auto& noteman = NotificationManager::GetInstance();
1366 noteman.AddNotification(NotificationSeverity::kInformational,
1367 msg_.ToStdString());
1369 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.
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.