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 this_identifier = msg_0183->talker;
143 this_identifier += msg_0183->type;
144 key = source +
":" + this_address +
";" + this_identifier;
146 }
else if (msg->bus == NavAddr::Bus::N2000) {
147 auto msg_n2k = std::dynamic_pointer_cast<const Nmea2000Msg>(msg);
149 this_identifier = msg_n2k->PGN.to_string();
150 unsigned char n_source = msg_n2k->payload.at(7);
151 wxString km = wxString::Format(
"N2k device address: %d", n_source);
152 key = km.ToStdString() +
" ; " +
"PGN: " + this_identifier;
154 }
else if (msg->bus == NavAddr::Bus::Signalk) {
155 auto msg_sk = std::dynamic_pointer_cast<const SignalkMsg>(msg);
158 std::static_pointer_cast<const NavAddrSignalK>(msg->source);
159 string source = addr_sk->to_string();
168 const PriorityMap& priority_map) {
172 for (
const auto& it : priority_map) {
173 if (it.second == 0) key0 = it.first;
176 wxString this_key(key0.c_str());
177 wxStringTokenizer tkz(this_key,
";");
178 string source = tkz.GetNextToken().ToStdString();
179 string this_identifier = tkz.GetNextToken().ToStdString();
181 wxStringTokenizer tka(source,
":");
183 std::stringstream ss;
184 ss << tka.GetNextToken();
185 ss >> pc.active_source_address;
186 pc.active_priority = 0;
187 pc.active_source = source;
188 pc.active_identifier = this_identifier;
189 pc.recent_active_time = -1;
192static void ApplyPriorityMap(PriorityMap& priority_map,
193 const wxString& new_prio,
int category) {
194 priority_map.clear();
195 wxStringTokenizer tk(new_prio,
"|");
197 while (tk.HasMoreTokens()) {
198 wxString entry = tk.GetNextToken();
199 string s_entry(entry.c_str());
200 priority_map[s_entry] = index;
205static string GetPriorityMap(
const PriorityMap& map) {
206#define MAX_SOURCES 10
207 string sa[MAX_SOURCES];
210 for (
auto& it : map) {
211 if ((it.second >= 0) && (it.second < MAX_SOURCES)) sa[it.second] = it.first;
215 for (
int i = 0; i < MAX_SOURCES; i++) {
216 if (!sa[i].empty()) {
225static bool IsNextLowerPriorityAvailable(
const PriorityMap& map,
228 for (
auto& it : map) {
229 if (it.second > pc.active_priority) {
230 best_prio = wxMin(best_prio, it.second);
233 return best_prio != pc.active_priority;
236static void SelectNextLowerPriority(
const PriorityMap& map,
239 for (
const auto& it : map) {
240 if (it.second > pc.active_priority) {
241 best_prio = wxMin(best_prio, it.second);
244 pc.active_priority = best_prio;
245 pc.active_source.clear();
246 pc.active_identifier.clear();
251CommBridge::CommBridge()
254 active_priority_position(
"position"),
255 active_priority_velocity(
"velocity"),
256 active_priority_heading(
"heading"),
257 active_priority_variation(
"variation"),
258 active_priority_satellites(
"satellites"),
259 active_priority_void(
"", -1),
260 m_n_log_watchdog_period(3600),
261 m_last_position_priority(0) {
262 Bind(wxEVT_TIMER, [&](wxTimerEvent&) { OnWatchdogTimer(); });
264CommBridge::~CommBridge() =
default;
266bool CommBridge::Initialize() {
267 m_log_callbacks = GetLogCallbacks();
271 PresetPriorityContainers();
276 m_watchdog_timer.SetOwner(
this, WATCHDOG_TIMER);
277 m_watchdog_timer.Start(1000, wxTIMER_CONTINUOUS);
282 m_driver_change_lstnr.
Init(
283 CommDriverRegistry::GetInstance().evt_driverlist_change,
284 [&](
const wxCommandEvent& ev) { OnDriverStateChange(); });
289void CommBridge::PresetWatchdogs() {
290 m_watchdogs.position_watchdog =
292 m_watchdogs.velocity_watchdog = 20;
293 m_watchdogs.variation_watchdog = 20;
294 m_watchdogs.heading_watchdog = 20;
295 m_watchdogs.satellite_watchdog = 20;
298void CommBridge::OnWatchdogTimer() {
300 m_watchdogs.position_watchdog--;
301 if (m_watchdogs.position_watchdog <= 0) {
302 if (m_watchdogs.position_watchdog % 5 == 0) {
304 auto msg = std::make_shared<GPSWatchdogMsg>(
305 GPSWatchdogMsg::WDSource::position, m_watchdogs.position_watchdog);
306 auto& msgbus = AppMsgBus::GetInstance();
307 LogAppMsg(msg,
"watchdog", m_log_callbacks);
308 msgbus.Notify(std::move(msg));
310 if (m_watchdogs.position_watchdog % m_n_log_watchdog_period == 0) {
312 logmsg.Printf(
" ***GPS Watchdog timeout at Lat:%g Lon: %g",
gLat,
314 wxLogMessage(logmsg);
322 active_priority_position.recent_active_time = -1;
326 if (IsNextLowerPriorityAvailable(priority_map_position,
327 active_priority_position)) {
328 SelectNextLowerPriority(priority_map_position, active_priority_position);
333 m_watchdogs.velocity_watchdog--;
334 if (m_watchdogs.velocity_watchdog <= 0) {
337 active_priority_velocity.recent_active_time = -1;
339 if (g_nNMEADebug && (m_watchdogs.velocity_watchdog == 0))
340 wxLogMessage(
" ***Velocity Watchdog timeout...");
341 if (m_watchdogs.velocity_watchdog % 5 == 0) {
343 auto msg = std::make_shared<GPSWatchdogMsg>(
344 GPSWatchdogMsg::WDSource::velocity, m_watchdogs.velocity_watchdog);
345 auto& msgbus = AppMsgBus::GetInstance();
346 msgbus.Notify(std::move(msg));
350 SelectNextLowerPriority(priority_map_velocity, active_priority_velocity);
354 m_watchdogs.heading_watchdog--;
355 if (m_watchdogs.heading_watchdog <= 0) {
357 active_priority_heading.recent_active_time = -1;
358 if (g_nNMEADebug && (m_watchdogs.heading_watchdog == 0))
359 wxLogMessage(
" ***HDT Watchdog timeout...");
363 SelectNextLowerPriority(priority_map_heading, active_priority_heading);
367 m_watchdogs.variation_watchdog--;
368 if (m_watchdogs.variation_watchdog <= 0) {
370 active_priority_variation.recent_active_time = -1;
372 if (g_nNMEADebug && (m_watchdogs.variation_watchdog == 0))
373 wxLogMessage(
" ***VAR Watchdog timeout...");
377 SelectNextLowerPriority(priority_map_variation, active_priority_variation);
381 m_watchdogs.satellite_watchdog--;
382 if (m_watchdogs.satellite_watchdog <= 0) {
386 active_priority_satellites.recent_active_time = -1;
388 if (g_nNMEADebug && (m_watchdogs.satellite_watchdog == 0))
389 wxLogMessage(
" ***SAT Watchdog timeout...");
393 SelectNextLowerPriority(priority_map_satellites,
394 active_priority_satellites);
398void CommBridge::MakeHDTFromHDM() {
401 if (!std::isnan(
gHdm)) {
404 if (std::isnan(
gVar) && (g_UserVar != 0.0))
gVar = g_UserVar;
406 if (!std::isnan(
gHdt)) {
409 else if (
gHdt >= 360)
412 m_watchdogs.heading_watchdog = gps_watchdog_timeout_ticks;
417void CommBridge::InitCommListeners() {
423 HandleN2K_129029(UnpackEvtPointer<Nmea2000Msg>(ev));
429 HandleN2K_129025(UnpackEvtPointer<Nmea2000Msg>(ev));
435 HandleN2K_129026(UnpackEvtPointer<Nmea2000Msg>(ev));
441 HandleN2K_127250(UnpackEvtPointer<Nmea2000Msg>(ev));
447 HandleN2K_129540(UnpackEvtPointer<Nmea2000Msg>(ev));
454 HandleN0183_RMC(UnpackEvtPointer<Nmea0183Msg>(ev));
459 HandleN0183_THS(UnpackEvtPointer<Nmea0183Msg>(ev));
464 HandleN0183_HDT(UnpackEvtPointer<Nmea0183Msg>(ev));
469 HandleN0183_HDG(UnpackEvtPointer<Nmea0183Msg>(ev));
474 HandleN0183_HDM(UnpackEvtPointer<Nmea0183Msg>(ev));
479 HandleN0183_VTG(UnpackEvtPointer<Nmea0183Msg>(ev));
484 HandleN0183_GSV(UnpackEvtPointer<Nmea0183Msg>(ev));
489 HandleN0183_GGA(UnpackEvtPointer<Nmea0183Msg>(ev));
495 HandleN0183_GLL(UnpackEvtPointer<Nmea0183Msg>(ev));
505 HandleSignalK(UnpackEvtPointer<SignalkMsg>(ev));
509void CommBridge::OnDriverStateChange() {
511 PresetPriorityContainers();
514std::vector<string> CommBridge::GetPriorityMaps()
const {
515 std::vector<string> result;
516 result.push_back(GetPriorityMap(priority_map_position));
517 result.push_back(GetPriorityMap(priority_map_velocity));
518 result.push_back(GetPriorityMap(priority_map_heading));
519 result.push_back(GetPriorityMap(priority_map_variation));
520 result.push_back(GetPriorityMap(priority_map_satellites));
524void CommBridge::ApplyPriorityMaps(
const std::vector<string>& new_maps) {
525 wxString new_prio_string = wxString(new_maps[0].c_str());
526 ApplyPriorityMap(priority_map_position, new_prio_string, 0);
528 new_prio_string = wxString(new_maps[1].c_str());
529 ApplyPriorityMap(priority_map_velocity, new_prio_string, 1);
531 new_prio_string = wxString(new_maps[2].c_str());
532 ApplyPriorityMap(priority_map_heading, new_prio_string, 2);
534 new_prio_string = wxString(new_maps[3].c_str());
535 ApplyPriorityMap(priority_map_variation, new_prio_string, 3);
537 new_prio_string = wxString(new_maps[4].c_str());
538 ApplyPriorityMap(priority_map_satellites, new_prio_string, 4);
541void CommBridge::PresetPriorityContainers() {
542 PresetPriorityContainer(active_priority_position, priority_map_position);
543 PresetPriorityContainer(active_priority_velocity, priority_map_velocity);
544 PresetPriorityContainer(active_priority_heading, priority_map_heading);
545 PresetPriorityContainer(active_priority_variation, priority_map_variation);
546 PresetPriorityContainer(active_priority_satellites, priority_map_satellites);
549bool CommBridge::HandleN2K_129029(
const N2000MsgPtr& n2k_msg) {
550 std::vector<unsigned char> v = n2k_msg->payload;
554 ClearNavData(temp_data);
556 if (!m_decoder.DecodePGN129029(v, temp_data))
return false;
559 if (!N2kIsNA(temp_data.gLat) && !N2kIsNA(temp_data.gLon)) {
560 if (EvalPriority(n2k_msg, active_priority_position,
561 priority_map_position)) {
562 gLat = temp_data.gLat;
563 gLon = temp_data.gLon;
564 valid_flag += POS_UPDATE;
565 valid_flag += POS_VALID;
566 m_watchdogs.position_watchdog = gps_watchdog_timeout_ticks;
567 m_n_log_watchdog_period = N_ACTIVE_LOG_WATCHDOG;
571 if (temp_data.n_satellites >= 0) {
572 if (EvalPriority(n2k_msg, active_priority_satellites,
573 priority_map_satellites)) {
574 g_SatsInView = temp_data.n_satellites;
576 m_watchdogs.satellite_watchdog = sat_watchdog_timeout_ticks;
580 SendBasicNavdata(valid_flag, m_log_callbacks);
584bool CommBridge::HandleN2K_129025(
const N2000MsgPtr& n2k_msg) {
585 std::vector<unsigned char> v = n2k_msg->payload;
588 ClearNavData(temp_data);
590 if (!m_decoder.DecodePGN129025(v, temp_data))
return false;
593 if (!N2kIsNA(temp_data.gLat) && !N2kIsNA(temp_data.gLon)) {
594 if (EvalPriority(n2k_msg, active_priority_position,
595 priority_map_position)) {
596 gLat = temp_data.gLat;
597 gLon = temp_data.gLon;
598 valid_flag += POS_UPDATE;
599 valid_flag += POS_VALID;
600 m_watchdogs.position_watchdog = gps_watchdog_timeout_ticks;
601 m_n_log_watchdog_period = N_ACTIVE_LOG_WATCHDOG;
608 SendBasicNavdata(valid_flag, m_log_callbacks);
612bool CommBridge::HandleN2K_129026(
const N2000MsgPtr& n2k_msg) {
613 std::vector<unsigned char> v = n2k_msg->payload;
616 ClearNavData(temp_data);
618 if (!m_decoder.DecodePGN129026(v, temp_data))
return false;
621 if (!N2kIsNA(temp_data.gSog)) {
622 if (EvalPriority(n2k_msg, active_priority_velocity,
623 priority_map_velocity)) {
624 gSog = MS2KNOTS(temp_data.gSog);
625 valid_flag += SOG_UPDATE;
627 if (N2kIsNA(temp_data.gCog))
630 gCog = GeodesicRadToDeg(temp_data.gCog);
631 valid_flag += COG_UPDATE;
632 m_watchdogs.velocity_watchdog = gps_watchdog_timeout_ticks;
637 SendBasicNavdata(valid_flag, m_log_callbacks);
641bool CommBridge::HandleN2K_127250(
const N2000MsgPtr& n2k_msg) {
642 std::vector<unsigned char> v = n2k_msg->payload;
645 ClearNavData(temp_data);
647 if (!m_decoder.DecodePGN127250(v, temp_data))
return false;
650 if (!N2kIsNA(temp_data.gVar)) {
651 if (EvalPriority(n2k_msg, active_priority_variation,
652 priority_map_variation)) {
653 gVar = GeodesicRadToDeg(temp_data.gVar);
654 valid_flag += VAR_UPDATE;
655 m_watchdogs.variation_watchdog = gps_watchdog_timeout_ticks;
659 if (!N2kIsNA(temp_data.gHdt)) {
660 if (EvalPriority(n2k_msg, active_priority_heading, priority_map_heading)) {
661 gHdt = GeodesicRadToDeg(temp_data.gHdt);
662 valid_flag += HDT_UPDATE;
663 m_watchdogs.heading_watchdog = gps_watchdog_timeout_ticks;
667 if (!N2kIsNA(temp_data.gHdm)) {
668 gHdm = GeodesicRadToDeg(temp_data.gHdm);
669 if (EvalPriority(n2k_msg, active_priority_heading, priority_map_heading)) {
671 valid_flag += HDT_UPDATE;
672 if (!std::isnan(
gHdt))
673 m_watchdogs.heading_watchdog = gps_watchdog_timeout_ticks;
677 SendBasicNavdata(valid_flag, m_log_callbacks);
681bool CommBridge::HandleN2K_129540(
const N2000MsgPtr& n2k_msg) {
682 std::vector<unsigned char> v = n2k_msg->payload;
685 ClearNavData(temp_data);
687 if (!m_decoder.DecodePGN129540(v, temp_data))
return false;
689 if (temp_data.n_satellites >= 0) {
690 if (EvalPriority(n2k_msg, active_priority_satellites,
691 priority_map_satellites)) {
692 g_SatsInView = temp_data.n_satellites;
694 m_watchdogs.satellite_watchdog = sat_watchdog_timeout_ticks;
701bool CommBridge::HandleN0183_RMC(
const N0183MsgPtr& n0183_msg) {
702 string str = n0183_msg->payload;
705 ClearNavData(temp_data);
707 bool is_valid =
true;
708 if (!m_decoder.DecodeRMC(str, temp_data)) is_valid =
false;
710 if (std::isnan(temp_data.gLat) || std::isnan(temp_data.gLon))
return false;
713 if (EvalPriority(n0183_msg, active_priority_position,
714 priority_map_position)) {
716 gLat = temp_data.gLat;
717 gLon = temp_data.gLon;
718 valid_flag += POS_VALID;
719 m_watchdogs.position_watchdog = gps_watchdog_timeout_ticks;
720 m_n_log_watchdog_period = N_ACTIVE_LOG_WATCHDOG;
722 valid_flag += POS_UPDATE;
725 if (EvalPriority(n0183_msg, active_priority_velocity,
726 priority_map_velocity)) {
728 gSog = temp_data.gSog;
729 valid_flag += SOG_UPDATE;
730 gCog = temp_data.gCog;
731 valid_flag += COG_UPDATE;
732 m_watchdogs.velocity_watchdog = gps_watchdog_timeout_ticks;
736 if (!std::isnan(temp_data.gVar)) {
737 if (EvalPriority(n0183_msg, active_priority_variation,
738 priority_map_variation)) {
740 gVar = temp_data.gVar;
741 valid_flag += VAR_UPDATE;
742 m_watchdogs.variation_watchdog = gps_watchdog_timeout_ticks;
752 if ((valid_flag & POS_VALID) == POS_VALID) {
754 if (g_SatsInView < 4) {
756 m_watchdogs.satellite_watchdog = sat_watchdog_timeout_ticks;
761 SendBasicNavdata(valid_flag, m_log_callbacks);
765bool CommBridge::HandleN0183_THS(
const N0183MsgPtr& n0183_msg) {
766 string str = n0183_msg->payload;
768 ClearNavData(temp_data);
770 if (!m_decoder.DecodeTHS(str, temp_data))
return false;
773 if (EvalPriority(n0183_msg, active_priority_heading, priority_map_heading)) {
774 gHdt = temp_data.gHdt;
775 valid_flag += HDT_UPDATE;
776 m_watchdogs.heading_watchdog = gps_watchdog_timeout_ticks;
779 SendBasicNavdata(valid_flag, m_log_callbacks);
783bool CommBridge::HandleN0183_HDT(
const N0183MsgPtr& n0183_msg) {
784 string str = n0183_msg->payload;
786 ClearNavData(temp_data);
788 if (!m_decoder.DecodeHDT(str, temp_data))
return false;
791 if (EvalPriority(n0183_msg, active_priority_heading, priority_map_heading)) {
792 gHdt = temp_data.gHdt;
793 valid_flag += HDT_UPDATE;
794 m_watchdogs.heading_watchdog = gps_watchdog_timeout_ticks;
797 SendBasicNavdata(valid_flag, m_log_callbacks);
801bool CommBridge::HandleN0183_HDG(
const N0183MsgPtr& n0183_msg) {
802 string str = n0183_msg->payload;
804 ClearNavData(temp_data);
806 if (!m_decoder.DecodeHDG(str, temp_data))
return false;
811 if (EvalPriority(n0183_msg, active_priority_heading, priority_map_heading)) {
812 gHdm = temp_data.gHdm;
813 m_watchdogs.heading_watchdog = gps_watchdog_timeout_ticks;
817 if (!std::isnan(temp_data.gVar)) {
818 if (EvalPriority(n0183_msg, active_priority_variation,
819 priority_map_variation)) {
820 gVar = temp_data.gVar;
821 valid_flag += VAR_UPDATE;
822 m_watchdogs.variation_watchdog = gps_watchdog_timeout_ticks;
826 if (bHDM) MakeHDTFromHDM();
828 SendBasicNavdata(valid_flag, m_log_callbacks);
832bool CommBridge::HandleN0183_HDM(
const N0183MsgPtr& n0183_msg) {
833 string str = n0183_msg->payload;
835 ClearNavData(temp_data);
837 if (!m_decoder.DecodeHDM(str, temp_data))
return false;
840 if (EvalPriority(n0183_msg, active_priority_heading, priority_map_heading)) {
841 gHdm = temp_data.gHdm;
843 valid_flag += HDT_UPDATE;
844 m_watchdogs.heading_watchdog = gps_watchdog_timeout_ticks;
847 SendBasicNavdata(valid_flag, m_log_callbacks);
851bool CommBridge::HandleN0183_VTG(
const N0183MsgPtr& n0183_msg) {
852 string str = n0183_msg->payload;
854 ClearNavData(temp_data);
856 if (!m_decoder.DecodeVTG(str, temp_data))
return false;
859 if (EvalPriority(n0183_msg, active_priority_velocity,
860 priority_map_velocity)) {
861 gSog = temp_data.gSog;
862 valid_flag += SOG_UPDATE;
863 gCog = temp_data.gCog;
864 valid_flag += COG_UPDATE;
865 m_watchdogs.velocity_watchdog = gps_watchdog_timeout_ticks;
868 SendBasicNavdata(valid_flag, m_log_callbacks);
872bool CommBridge::HandleN0183_GSV(
const N0183MsgPtr& n0183_msg) {
873 string str = n0183_msg->payload;
875 ClearNavData(temp_data);
877 if (!m_decoder.DecodeGSV(str, temp_data))
return false;
880 if (EvalPriority(n0183_msg, active_priority_satellites,
881 priority_map_satellites)) {
882 if (temp_data.n_satellites >= 0) {
883 g_SatsInView = temp_data.n_satellites;
886 m_watchdogs.satellite_watchdog = sat_watchdog_timeout_ticks;
890 SendBasicNavdata(valid_flag, m_log_callbacks);
894bool CommBridge::HandleN0183_GGA(
const N0183MsgPtr& n0183_msg) {
895 string str = n0183_msg->payload;
897 ClearNavData(temp_data);
899 bool is_valid =
true;
900 if (!m_decoder.DecodeGGA(str, temp_data)) is_valid =
false;
902 if (std::isnan(temp_data.gLat) || std::isnan(temp_data.gLon))
return false;
905 if (EvalPriority(n0183_msg, active_priority_position,
906 priority_map_position)) {
908 gLat = temp_data.gLat;
909 gLon = temp_data.gLon;
910 valid_flag += POS_VALID;
911 m_watchdogs.position_watchdog = gps_watchdog_timeout_ticks;
912 m_n_log_watchdog_period = N_ACTIVE_LOG_WATCHDOG;
914 valid_flag += POS_UPDATE;
917 if (EvalPriority(n0183_msg, active_priority_satellites,
918 priority_map_satellites)) {
920 if (temp_data.n_satellites >= 0) {
921 g_SatsInView = temp_data.n_satellites;
924 m_watchdogs.satellite_watchdog = sat_watchdog_timeout_ticks;
929 SendBasicNavdata(valid_flag, m_log_callbacks);
933bool CommBridge::HandleN0183_GLL(
const N0183MsgPtr& n0183_msg) {
934 string str = n0183_msg->payload;
936 ClearNavData(temp_data);
939 if (!m_decoder.DecodeGLL(str, temp_data)) bvalid =
false;
941 if (std::isnan(temp_data.gLat) || std::isnan(temp_data.gLon))
return false;
944 if (EvalPriority(n0183_msg, active_priority_position,
945 priority_map_position)) {
947 gLat = temp_data.gLat;
948 gLon = temp_data.gLon;
949 valid_flag += POS_VALID;
950 m_watchdogs.position_watchdog = gps_watchdog_timeout_ticks;
951 m_n_log_watchdog_period = N_ACTIVE_LOG_WATCHDOG;
953 valid_flag += POS_UPDATE;
956 SendBasicNavdata(valid_flag, m_log_callbacks);
961 string str = n0183_msg->payload;
964 wxString sentence(str.c_str());
966 AisError ais_error = AIS_GENERIC_ERROR;
967 ais_error = DecodeSingleVDO(sentence, &gpd);
969 if (ais_error == AIS_NoError) {
971 if (!std::isnan(gpd.
kLat) && !std::isnan(gpd.
kLon)) {
972 if (EvalPriority(n0183_msg, active_priority_position,
973 priority_map_position)) {
976 valid_flag += POS_UPDATE;
977 valid_flag += POS_VALID;
978 m_watchdogs.position_watchdog = gps_watchdog_timeout_ticks;
979 m_n_log_watchdog_period =
980 N_ACTIVE_LOG_WATCHDOG;
984 if (!std::isnan(gpd.
kCog) && !std::isnan(gpd.
kSog)) {
985 if (EvalPriority(n0183_msg, active_priority_velocity,
986 priority_map_velocity)) {
988 valid_flag += SOG_UPDATE;
990 valid_flag += COG_UPDATE;
991 m_watchdogs.velocity_watchdog = gps_watchdog_timeout_ticks;
995 if (!std::isnan(gpd.
kHdt)) {
996 if (EvalPriority(n0183_msg, active_priority_heading,
997 priority_map_heading)) {
999 valid_flag += HDT_UPDATE;
1000 m_watchdogs.heading_watchdog = gps_watchdog_timeout_ticks;
1004 SendBasicNavdata(valid_flag, m_log_callbacks);
1009bool CommBridge::HandleSignalK(
const SignalKMsgPtr& sK_msg) {
1010 string str = sK_msg->raw_message;
1013 if (sK_msg->context_self != sK_msg->context)
return false;
1015 g_ownshipMMSI_SK = sK_msg->context_self;
1018 ClearNavData(temp_data);
1020 if (!m_decoder.DecodeSignalK(str, temp_data))
return false;
1024 if (!std::isnan(temp_data.gLat) && !std::isnan(temp_data.gLon)) {
1025 if (EvalPriority(sK_msg, active_priority_position, priority_map_position)) {
1026 gLat = temp_data.gLat;
1027 gLon = temp_data.gLon;
1028 valid_flag += POS_UPDATE;
1029 valid_flag += POS_VALID;
1030 m_watchdogs.position_watchdog = gps_watchdog_timeout_ticks;
1031 m_n_log_watchdog_period = N_ACTIVE_LOG_WATCHDOG;
1035 if (!std::isnan(temp_data.gSog)) {
1036 if (EvalPriority(sK_msg, active_priority_velocity, priority_map_velocity)) {
1037 gSog = temp_data.gSog;
1038 valid_flag += SOG_UPDATE;
1039 if ((
gSog > 0.05) && !std::isnan(temp_data.gCog)) {
1040 gCog = temp_data.gCog;
1041 valid_flag += COG_UPDATE;
1043 m_watchdogs.velocity_watchdog = gps_watchdog_timeout_ticks;
1047 if (!std::isnan(temp_data.gHdt)) {
1048 if (EvalPriority(sK_msg, active_priority_heading, priority_map_heading)) {
1049 gHdt = temp_data.gHdt;
1050 valid_flag += HDT_UPDATE;
1051 m_watchdogs.heading_watchdog = gps_watchdog_timeout_ticks;
1055 if (!std::isnan(temp_data.gHdm)) {
1056 if (EvalPriority(sK_msg, active_priority_heading, priority_map_heading)) {
1057 gHdm = temp_data.gHdm;
1059 valid_flag += HDT_UPDATE;
1060 m_watchdogs.heading_watchdog = gps_watchdog_timeout_ticks;
1064 if (!std::isnan(temp_data.gVar)) {
1065 if (EvalPriority(sK_msg, active_priority_variation,
1066 priority_map_variation)) {
1067 gVar = temp_data.gVar;
1068 valid_flag += VAR_UPDATE;
1069 m_watchdogs.variation_watchdog = gps_watchdog_timeout_ticks;
1073 if (temp_data.n_satellites > 0) {
1074 if (EvalPriority(sK_msg, active_priority_satellites,
1075 priority_map_satellites)) {
1076 g_SatsInView = temp_data.n_satellites;
1078 m_watchdogs.satellite_watchdog = sat_watchdog_timeout_ticks;
1082 if (g_pMUX && g_pMUX->IsLogActive())
1085 SendBasicNavdata(valid_flag, m_log_callbacks);
1089void CommBridge::ClearPriorityMaps() {
1090 priority_map_position.clear();
1091 priority_map_velocity.clear();
1092 priority_map_heading.clear();
1093 priority_map_variation.clear();
1094 priority_map_satellites.clear();
1098 if (category ==
"position")
1099 return active_priority_position;
1100 else if (category ==
"velocity")
1101 return active_priority_velocity;
1102 else if (category ==
"heading")
1103 return active_priority_heading;
1104 else if (category ==
"variation")
1105 return active_priority_variation;
1106 else if (category ==
"satellites")
1107 return active_priority_satellites;
1109 return active_priority_void;
1112void CommBridge::UpdateAndApplyMaps(
const std::vector<string>& new_maps) {
1113 ApplyPriorityMaps(new_maps);
1115 PresetPriorityContainers();
1118bool CommBridge::LoadConfig() {
1119 if (TheBaseConfig()) {
1120 TheBaseConfig()->SetPath(
"/Settings/CommPriority");
1122 std::vector<string> new_maps;
1123 wxString pri_string;
1125 TheBaseConfig()->Read(
"PriorityPosition", &pri_string);
1126 string s_prio = string(pri_string.c_str());
1127 new_maps.push_back(s_prio);
1129 TheBaseConfig()->Read(
"PriorityVelocity", &pri_string);
1130 s_prio = string(pri_string.c_str());
1131 new_maps.push_back(s_prio);
1133 TheBaseConfig()->Read(
"PriorityHeading", &pri_string);
1134 s_prio = string(pri_string.c_str());
1135 new_maps.push_back(s_prio);
1137 TheBaseConfig()->Read(
"PriorityVariation", &pri_string);
1138 s_prio = string(pri_string.c_str());
1139 new_maps.push_back(s_prio);
1141 TheBaseConfig()->Read(
"PrioritySatellites", &pri_string);
1142 s_prio = string(pri_string.c_str());
1143 new_maps.push_back(s_prio);
1145 ApplyPriorityMaps(new_maps);
1150bool CommBridge::SaveConfig()
const {
1151 if (TheBaseConfig()) {
1152 TheBaseConfig()->SetPath(
"/Settings/CommPriority");
1154 wxString pri_string =
1155 wxString(GetPriorityMap(priority_map_position).c_str());
1156 TheBaseConfig()->Write(
"PriorityPosition", pri_string);
1158 pri_string = wxString(GetPriorityMap(priority_map_velocity).c_str());
1159 TheBaseConfig()->Write(
"PriorityVelocity", pri_string);
1161 pri_string = wxString(GetPriorityMap(priority_map_heading).c_str());
1162 TheBaseConfig()->Write(
"PriorityHeading", pri_string);
1164 pri_string = wxString(GetPriorityMap(priority_map_variation).c_str());
1165 TheBaseConfig()->Write(
"PriorityVariation", pri_string);
1167 pri_string = wxString(GetPriorityMap(priority_map_satellites).c_str());
1168 TheBaseConfig()->Write(
"PrioritySatellites", pri_string);
1173bool CommBridge::EvalPriority(
const NavMsgPtr& msg,
1175 PriorityMap& priority_map) {
1176 string this_key = GetPriorityKey(msg);
1177 if (debug_priority) printf(
"This Key: %s\n", this_key.c_str());
1180 wxStringTokenizer tkz(this_key,
";");
1181 wxString wxs_this_source = tkz.GetNextToken();
1182 string source = wxs_this_source.ToStdString();
1183 wxString wxs_this_identifier = tkz.GetNextToken();
1184 string this_identifier = wxs_this_identifier.ToStdString();
1186 wxStringTokenizer tka(wxs_this_source,
":");
1188 std::stringstream ss;
1189 ss << tka.GetNextToken();
1191 ss >> source_address;
1199 if (msg->bus == NavAddr::Bus::N0183) {
1200 if (!strncmp(active_priority.prio_class.c_str(),
"velocity", 8)) {
1201 bool pos_ok =
false;
1202 if (!strcmp(active_priority_position.active_source.c_str(),
1204 if (active_priority_position.recent_active_time != -1) {
1208 if (!pos_ok)
return false;
1215 auto it = priority_map.find(this_key);
1216 if (it == priority_map.end()) {
1218 size_t n = priority_map.size();
1219 priority_map[this_key] =
static_cast<int>(n);
1222 this_priority = priority_map[this_key];
1224 if (debug_priority) {
1225 for (
const auto& jt : priority_map) {
1226 printf(
" priority_map: %s %d\n", jt.first.c_str(),
1233 if (this_priority > active_priority.active_priority) {
1235 printf(
" Drop low priority: %s %d %d \n", source.c_str(),
1236 this_priority, active_priority.active_priority);
1241 if (this_priority < active_priority.active_priority) {
1242 active_priority.active_priority = this_priority;
1243 active_priority.active_source = source;
1244 active_priority.active_identifier = this_identifier;
1245 active_priority.active_source_address = source_address;
1246 wxDateTime now = wxDateTime::Now();
1247 active_priority.recent_active_time = now.GetTicks();
1250 printf(
" Restoring high priority: %s %d\n", source.c_str(),
1258 if (!active_priority.active_source.empty()) {
1259 if (debug_priority) printf(
"source: %s\n", source.c_str());
1261 printf(
"active_source: %s\n", active_priority.active_source.c_str());
1263 if (source != active_priority.active_source) {
1266 int lowest_priority = -10;
1267 for (
const auto& jt : priority_map) {
1268 if (jt.second > lowest_priority) lowest_priority = jt.second;
1271 priority_map[this_key] = lowest_priority + 1;
1273 printf(
" Lowering priority A: %s :%d\n", source.c_str(),
1274 priority_map[this_key]);
1282 if (msg->bus == NavAddr::Bus::N0183) {
1283 auto msg_0183 = std::dynamic_pointer_cast<const Nmea0183Msg>(msg);
1285 if (!active_priority.active_identifier.empty()) {
1287 printf(
"this_identifier: %s\n", this_identifier.c_str());
1289 printf(
"active_priority.active_identifier: %s\n",
1290 active_priority.active_identifier.c_str());
1292 if (this_identifier != active_priority.active_identifier) {
1295 if (priority_map[this_key] == active_priority.active_priority) {
1296 int lowest_priority = -10;
1297 for (
const auto& jt : priority_map) {
1298 if (jt.second > lowest_priority) lowest_priority = jt.second;
1301 priority_map[this_key] = lowest_priority + 1;
1303 printf(
" Lowering priority B: %s :%d\n", source.c_str(),
1304 priority_map[this_key]);
1315 else if (msg->bus == NavAddr::Bus::N2000) {
1316 auto msg_n2k = std::dynamic_pointer_cast<const Nmea2000Msg>(msg);
1318 if (!active_priority.active_identifier.empty()) {
1319 if (this_identifier != active_priority.active_identifier) {
1322 if (priority_map[this_key] == active_priority.active_priority) {
1323 int lowest_priority = -10;
1324 for (
const auto& jt : priority_map) {
1325 if (jt.second > lowest_priority) lowest_priority = jt.second;
1328 priority_map[this_key] = lowest_priority + 1;
1330 printf(
" Lowering priority: %s :%d\n", source.c_str(),
1331 priority_map[this_key]);
1341 active_priority.active_source = source;
1342 active_priority.active_identifier = this_identifier;
1343 active_priority.active_source_address = source_address;
1344 wxDateTime now = wxDateTime::Now();
1345 active_priority.recent_active_time = now.GetTicks();
1347 printf(
" Accepting high priority: %s %d\n", source.c_str(), this_priority);
1349 if (active_priority.prio_class ==
"position") {
1350 if (this_priority != m_last_position_priority) {
1351 m_last_position_priority = this_priority;
1354 msg_.Printf(_(
"GNSS position fix priority shift:") +
" %s\n %s \n -> %s",
1355 this_identifier.c_str(), m_last_position_source.c_str(),
1357 auto& noteman = NotificationManager::GetInstance();
1358 noteman.AddNotification(NotificationSeverity::kInformational,
1359 msg_.ToStdString());
1361 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.