40#include <wx/tokenzr.h>
41#include <wx/fileconf.h>
43#include "model/comm_ais.h"
44#include "model/comm_appmsg_bus.h"
48#include "model/comm_vars.h"
49#include "model/config_vars.h"
50#include "model/cutil.h"
52#include "model/idents.h"
53#include "model/ocpn_types.h"
54#include "model/own_ship.h"
58#define N_ACTIVE_LOG_WATCHDOG 300
62bool debug_priority =
false;
75static NmeaLog* GetDataMonitor() {
76 auto w = wxWindow::FindWindowByName(kDataMonitorWindowName);
77 return dynamic_cast<NmeaLog*
>(w);
81 log_callbacks.log_is_active = [&]() {
82 auto log = GetDataMonitor();
83 return log && log->IsVisible();
85 log_callbacks.log_message = [&](
const Logline& ll) {
86 NmeaLog* monitor = GetDataMonitor();
94 AppNavMsg(
const std::shared_ptr<const AppMsg>& msg,
const string& name)
95 :
NavMsg(NavAddr::Bus::AppMsg,
96 std::make_shared<const NavAddrPlugin>(
"AppMsg")),
97 m_to_string(msg->to_string()),
100 [[nodiscard]]
string to_string()
const override {
return m_to_string; }
102 [[nodiscard]]
string key()
const override {
return "appmsg::" + m_name; }
104 const string m_to_string;
108static void LogAppMsg(
const std::shared_ptr<const AppMsg>& msg,
110 if (!log_cb.log_is_active())
return;
111 auto navmsg = std::make_shared<AppNavMsg>(msg,
"basic-navdata");
114 log_cb.log_message(ll);
121static void SendBasicNavdata(
int vflag,
123 auto msg = std::make_shared<BasicNavDataMsg>(
124 gLat, gLon, gSog, gCog, gVar, gHdt, vflag, wxDateTime::Now().GetTicks());
125 clock_gettime(CLOCK_MONOTONIC, &msg->set_time);
126 LogAppMsg(msg,
"basic-navdata", log_callbacks);
127 AppMsgBus::GetInstance().
Notify(std::move(msg));
130static inline double GeodesicRadToDeg(
double rads) {
131 return rads * 180.0 / M_PI;
134static inline double MS2KNOTS(
double ms) {
return ms * 1.9438444924406; }
136static string GetPriorityKey(
const NavMsgPtr& msg) {
139 string this_identifier;
140 string this_address(
"0");
141 if (msg->bus == NavAddr::Bus::N0183) {
142 auto msg_0183 = std::dynamic_pointer_cast<const Nmea0183Msg>(msg);
144 string source = msg->source->to_string();
145 this_identifier = msg_0183->talker;
146 this_identifier += msg_0183->type;
147 key = source +
":" + this_address +
";" + this_identifier;
149 }
else if (msg->bus == NavAddr::Bus::N2000) {
150 auto msg_n2k = std::dynamic_pointer_cast<const Nmea2000Msg>(msg);
152 this_identifier = msg_n2k->PGN.to_string();
153 unsigned char n_source = msg_n2k->payload.at(7);
154 wxString km = wxString::Format(
"N2k device address: %d", n_source);
155 key = km.ToStdString() +
" ; " +
"PGN: " + this_identifier;
157 }
else if (msg->bus == NavAddr::Bus::Signalk) {
158 auto msg_sk = std::dynamic_pointer_cast<const SignalkMsg>(msg);
161 std::static_pointer_cast<const NavAddrSignalK>(msg->source);
162 string source = addr_sk->to_string();
171 const PriorityMap& priority_map) {
175 for (
const auto& it : priority_map) {
176 if (it.second == 0) key0 = it.first;
179 wxString this_key(key0.c_str());
180 wxStringTokenizer tkz(this_key, _T(
";"));
181 string source = tkz.GetNextToken().ToStdString();
182 string this_identifier = tkz.GetNextToken().ToStdString();
184 wxStringTokenizer tka(source,
":");
186 std::stringstream ss;
187 ss << tka.GetNextToken();
188 ss >> pc.active_source_address;
189 pc.active_priority = 0;
190 pc.active_source = source;
191 pc.active_identifier = this_identifier;
192 pc.recent_active_time = -1;
195static void ApplyPriorityMap(PriorityMap& priority_map,
196 const wxString& new_prio,
int category) {
197 priority_map.clear();
198 wxStringTokenizer tk(new_prio,
"|");
200 while (tk.HasMoreTokens()) {
201 wxString entry = tk.GetNextToken();
202 string s_entry(entry.c_str());
203 priority_map[s_entry] = index;
208static string GetPriorityMap(
const PriorityMap& map) {
209#define MAX_SOURCES 10
210 string sa[MAX_SOURCES];
213 for (
auto& it : map) {
214 if ((it.second >= 0) && (it.second < MAX_SOURCES)) sa[it.second] = it.first;
218 for (
int i = 0; i < MAX_SOURCES; i++) {
219 if (!sa[i].empty()) {
228static bool IsNextLowerPriorityAvailable(
const PriorityMap& map,
231 for (
auto& it : map) {
232 if (it.second > pc.active_priority) {
233 best_prio = wxMin(best_prio, it.second);
236 return best_prio != pc.active_priority;
239static void SelectNextLowerPriority(
const PriorityMap& map,
242 for (
const auto& it : map) {
243 if (it.second > pc.active_priority) {
244 best_prio = wxMin(best_prio, it.second);
247 pc.active_priority = best_prio;
248 pc.active_source.clear();
249 pc.active_identifier.clear();
254CommBridge::CommBridge()
257 active_priority_position(
"position"),
258 active_priority_velocity(
"velocity"),
259 active_priority_heading(
"heading"),
260 active_priority_variation(
"variation"),
261 active_priority_satellites(
"satellites"),
262 active_priority_void(
"", -1),
263 m_n_log_watchdog_period(3600),
264 m_last_position_priority(0) {
265 Bind(wxEVT_TIMER, [&](wxTimerEvent&) { OnWatchdogTimer(); });
267CommBridge::~CommBridge() =
default;
269bool CommBridge::Initialize() {
270 m_log_callbacks = GetLogCallbacks();
274 PresetPriorityContainers();
279 m_watchdog_timer.SetOwner(
this, WATCHDOG_TIMER);
280 m_watchdog_timer.Start(1000, wxTIMER_CONTINUOUS);
285 m_driver_change_lstnr.
Init(
286 CommDriverRegistry::GetInstance().evt_driverlist_change,
287 [&](
const wxCommandEvent& ev) { OnDriverStateChange(); });
292void CommBridge::PresetWatchdogs() {
293 m_watchdogs.position_watchdog =
295 m_watchdogs.velocity_watchdog = 20;
296 m_watchdogs.variation_watchdog = 20;
297 m_watchdogs.heading_watchdog = 20;
298 m_watchdogs.satellite_watchdog = 20;
301void CommBridge::OnWatchdogTimer() {
303 m_watchdogs.position_watchdog--;
304 if (m_watchdogs.position_watchdog <= 0) {
305 if (m_watchdogs.position_watchdog % 5 == 0) {
307 auto msg = std::make_shared<GPSWatchdogMsg>(
308 GPSWatchdogMsg::WDSource::position, m_watchdogs.position_watchdog);
309 auto& msgbus = AppMsgBus::GetInstance();
310 LogAppMsg(msg,
"watchdog", m_log_callbacks);
311 msgbus.Notify(std::move(msg));
313 if (m_watchdogs.position_watchdog % m_n_log_watchdog_period == 0) {
315 logmsg.Printf(_T(
" ***GPS Watchdog timeout at Lat:%g Lon: %g"),
317 wxLogMessage(logmsg);
325 active_priority_position.recent_active_time = -1;
329 if (IsNextLowerPriorityAvailable(priority_map_position,
330 active_priority_position)) {
331 SelectNextLowerPriority(priority_map_position, active_priority_position);
336 m_watchdogs.velocity_watchdog--;
337 if (m_watchdogs.velocity_watchdog <= 0) {
340 active_priority_velocity.recent_active_time = -1;
342 if (g_nNMEADebug && (m_watchdogs.velocity_watchdog == 0))
343 wxLogMessage(_T(
" ***Velocity Watchdog timeout..."));
344 if (m_watchdogs.velocity_watchdog % 5 == 0) {
346 auto msg = std::make_shared<GPSWatchdogMsg>(
347 GPSWatchdogMsg::WDSource::velocity, m_watchdogs.velocity_watchdog);
348 auto& msgbus = AppMsgBus::GetInstance();
349 msgbus.Notify(std::move(msg));
353 SelectNextLowerPriority(priority_map_velocity, active_priority_velocity);
357 m_watchdogs.heading_watchdog--;
358 if (m_watchdogs.heading_watchdog <= 0) {
360 active_priority_heading.recent_active_time = -1;
361 if (g_nNMEADebug && (m_watchdogs.heading_watchdog == 0))
362 wxLogMessage(_T(
" ***HDT Watchdog timeout..."));
366 SelectNextLowerPriority(priority_map_heading, active_priority_heading);
370 m_watchdogs.variation_watchdog--;
371 if (m_watchdogs.variation_watchdog <= 0) {
373 active_priority_variation.recent_active_time = -1;
375 if (g_nNMEADebug && (m_watchdogs.variation_watchdog == 0))
376 wxLogMessage(_T(
" ***VAR Watchdog timeout..."));
380 SelectNextLowerPriority(priority_map_variation, active_priority_variation);
384 m_watchdogs.satellite_watchdog--;
385 if (m_watchdogs.satellite_watchdog <= 0) {
389 active_priority_satellites.recent_active_time = -1;
391 if (g_nNMEADebug && (m_watchdogs.satellite_watchdog == 0))
392 wxLogMessage(_T(
" ***SAT Watchdog timeout..."));
396 SelectNextLowerPriority(priority_map_satellites,
397 active_priority_satellites);
401void CommBridge::MakeHDTFromHDM() {
404 if (!std::isnan(gHdm)) {
407 if (std::isnan(gVar) && (g_UserVar != 0.0)) gVar = g_UserVar;
409 if (!std::isnan(gHdt)) {
412 else if (gHdt >= 360)
415 m_watchdogs.heading_watchdog = gps_watchdog_timeout_ticks;
420void CommBridge::InitCommListeners() {
426 HandleN2K_129029(UnpackEvtPointer<Nmea2000Msg>(ev));
432 HandleN2K_129025(UnpackEvtPointer<Nmea2000Msg>(ev));
438 HandleN2K_129026(UnpackEvtPointer<Nmea2000Msg>(ev));
444 HandleN2K_127250(UnpackEvtPointer<Nmea2000Msg>(ev));
450 HandleN2K_129540(UnpackEvtPointer<Nmea2000Msg>(ev));
457 HandleN0183_RMC(UnpackEvtPointer<Nmea0183Msg>(ev));
462 HandleN0183_HDT(UnpackEvtPointer<Nmea0183Msg>(ev));
467 HandleN0183_HDG(UnpackEvtPointer<Nmea0183Msg>(ev));
472 HandleN0183_HDM(UnpackEvtPointer<Nmea0183Msg>(ev));
477 HandleN0183_VTG(UnpackEvtPointer<Nmea0183Msg>(ev));
482 HandleN0183_GSV(UnpackEvtPointer<Nmea0183Msg>(ev));
487 HandleN0183_GGA(UnpackEvtPointer<Nmea0183Msg>(ev));
493 HandleN0183_GLL(UnpackEvtPointer<Nmea0183Msg>(ev));
503 HandleSignalK(UnpackEvtPointer<SignalkMsg>(ev));
507void CommBridge::OnDriverStateChange() {
509 PresetPriorityContainers();
512std::vector<string> CommBridge::GetPriorityMaps()
const {
513 std::vector<string> result;
514 result.push_back(GetPriorityMap(priority_map_position));
515 result.push_back(GetPriorityMap(priority_map_velocity));
516 result.push_back(GetPriorityMap(priority_map_heading));
517 result.push_back(GetPriorityMap(priority_map_variation));
518 result.push_back(GetPriorityMap(priority_map_satellites));
522void CommBridge::ApplyPriorityMaps(
const std::vector<string>& new_maps) {
523 wxString new_prio_string = wxString(new_maps[0].c_str());
524 ApplyPriorityMap(priority_map_position, new_prio_string, 0);
526 new_prio_string = wxString(new_maps[1].c_str());
527 ApplyPriorityMap(priority_map_velocity, new_prio_string, 1);
529 new_prio_string = wxString(new_maps[2].c_str());
530 ApplyPriorityMap(priority_map_heading, new_prio_string, 2);
532 new_prio_string = wxString(new_maps[3].c_str());
533 ApplyPriorityMap(priority_map_variation, new_prio_string, 3);
535 new_prio_string = wxString(new_maps[4].c_str());
536 ApplyPriorityMap(priority_map_satellites, new_prio_string, 4);
539void CommBridge::PresetPriorityContainers() {
540 PresetPriorityContainer(active_priority_position, priority_map_position);
541 PresetPriorityContainer(active_priority_velocity, priority_map_velocity);
542 PresetPriorityContainer(active_priority_heading, priority_map_heading);
543 PresetPriorityContainer(active_priority_variation, priority_map_variation);
544 PresetPriorityContainer(active_priority_satellites, priority_map_satellites);
547bool CommBridge::HandleN2K_129029(
const N2000MsgPtr& n2k_msg) {
548 std::vector<unsigned char> v = n2k_msg->payload;
552 ClearNavData(temp_data);
554 if (!m_decoder.DecodePGN129029(v, temp_data))
return false;
557 if (!N2kIsNA(temp_data.gLat) && !N2kIsNA(temp_data.gLon)) {
558 if (EvalPriority(n2k_msg, active_priority_position,
559 priority_map_position)) {
560 gLat = temp_data.gLat;
561 gLon = temp_data.gLon;
562 valid_flag += POS_UPDATE;
563 valid_flag += POS_VALID;
564 m_watchdogs.position_watchdog = gps_watchdog_timeout_ticks;
565 m_n_log_watchdog_period = N_ACTIVE_LOG_WATCHDOG;
569 if (temp_data.n_satellites >= 0) {
570 if (EvalPriority(n2k_msg, active_priority_satellites,
571 priority_map_satellites)) {
572 g_SatsInView = temp_data.n_satellites;
574 m_watchdogs.satellite_watchdog = sat_watchdog_timeout_ticks;
578 SendBasicNavdata(valid_flag, m_log_callbacks);
582bool CommBridge::HandleN2K_129025(
const N2000MsgPtr& n2k_msg) {
583 std::vector<unsigned char> v = n2k_msg->payload;
586 ClearNavData(temp_data);
588 if (!m_decoder.DecodePGN129025(v, temp_data))
return false;
591 if (!N2kIsNA(temp_data.gLat) && !N2kIsNA(temp_data.gLon)) {
592 if (EvalPriority(n2k_msg, active_priority_position,
593 priority_map_position)) {
594 gLat = temp_data.gLat;
595 gLon = temp_data.gLon;
596 valid_flag += POS_UPDATE;
597 valid_flag += POS_VALID;
598 m_watchdogs.position_watchdog = gps_watchdog_timeout_ticks;
599 m_n_log_watchdog_period = N_ACTIVE_LOG_WATCHDOG;
606 SendBasicNavdata(valid_flag, m_log_callbacks);
610bool CommBridge::HandleN2K_129026(
const N2000MsgPtr& n2k_msg) {
611 std::vector<unsigned char> v = n2k_msg->payload;
614 ClearNavData(temp_data);
616 if (!m_decoder.DecodePGN129026(v, temp_data))
return false;
619 if (!N2kIsNA(temp_data.gSog)) {
620 if (EvalPriority(n2k_msg, active_priority_velocity,
621 priority_map_velocity)) {
622 gSog = MS2KNOTS(temp_data.gSog);
623 valid_flag += SOG_UPDATE;
625 if (N2kIsNA(temp_data.gCog))
628 gCog = GeodesicRadToDeg(temp_data.gCog);
629 valid_flag += COG_UPDATE;
630 m_watchdogs.velocity_watchdog = gps_watchdog_timeout_ticks;
635 SendBasicNavdata(valid_flag, m_log_callbacks);
639bool CommBridge::HandleN2K_127250(
const N2000MsgPtr& n2k_msg) {
640 std::vector<unsigned char> v = n2k_msg->payload;
643 ClearNavData(temp_data);
645 if (!m_decoder.DecodePGN127250(v, temp_data))
return false;
648 if (!N2kIsNA(temp_data.gVar)) {
649 if (EvalPriority(n2k_msg, active_priority_variation,
650 priority_map_variation)) {
651 gVar = GeodesicRadToDeg(temp_data.gVar);
652 valid_flag += VAR_UPDATE;
653 m_watchdogs.variation_watchdog = gps_watchdog_timeout_ticks;
657 if (!N2kIsNA(temp_data.gHdt)) {
658 if (EvalPriority(n2k_msg, active_priority_heading, priority_map_heading)) {
659 gHdt = GeodesicRadToDeg(temp_data.gHdt);
660 valid_flag += HDT_UPDATE;
661 m_watchdogs.heading_watchdog = gps_watchdog_timeout_ticks;
665 if (!N2kIsNA(temp_data.gHdm)) {
666 gHdm = GeodesicRadToDeg(temp_data.gHdm);
667 if (EvalPriority(n2k_msg, active_priority_heading, priority_map_heading)) {
669 valid_flag += HDT_UPDATE;
670 if (!std::isnan(gHdt))
671 m_watchdogs.heading_watchdog = gps_watchdog_timeout_ticks;
675 SendBasicNavdata(valid_flag, m_log_callbacks);
679bool CommBridge::HandleN2K_129540(
const N2000MsgPtr& n2k_msg) {
680 std::vector<unsigned char> v = n2k_msg->payload;
683 ClearNavData(temp_data);
685 if (!m_decoder.DecodePGN129540(v, temp_data))
return false;
687 if (temp_data.n_satellites >= 0) {
688 if (EvalPriority(n2k_msg, active_priority_satellites,
689 priority_map_satellites)) {
690 g_SatsInView = temp_data.n_satellites;
692 m_watchdogs.satellite_watchdog = sat_watchdog_timeout_ticks;
699bool CommBridge::HandleN0183_RMC(
const N0183MsgPtr& n0183_msg) {
700 string str = n0183_msg->payload;
703 ClearNavData(temp_data);
705 bool is_valid =
true;
706 if (!m_decoder.DecodeRMC(str, temp_data)) is_valid =
false;
708 if (std::isnan(temp_data.gLat) || std::isnan(temp_data.gLon))
return false;
711 if (EvalPriority(n0183_msg, active_priority_position,
712 priority_map_position)) {
714 gLat = temp_data.gLat;
715 gLon = temp_data.gLon;
716 valid_flag += POS_VALID;
717 m_watchdogs.position_watchdog = gps_watchdog_timeout_ticks;
718 m_n_log_watchdog_period = N_ACTIVE_LOG_WATCHDOG;
720 valid_flag += POS_UPDATE;
723 if (EvalPriority(n0183_msg, active_priority_velocity,
724 priority_map_velocity)) {
726 gSog = temp_data.gSog;
727 valid_flag += SOG_UPDATE;
728 gCog = temp_data.gCog;
729 valid_flag += COG_UPDATE;
730 m_watchdogs.velocity_watchdog = gps_watchdog_timeout_ticks;
734 if (!std::isnan(temp_data.gVar)) {
735 if (EvalPriority(n0183_msg, active_priority_variation,
736 priority_map_variation)) {
738 gVar = temp_data.gVar;
739 valid_flag += VAR_UPDATE;
740 m_watchdogs.variation_watchdog = gps_watchdog_timeout_ticks;
750 if ((valid_flag & POS_VALID) == POS_VALID) {
752 if (g_SatsInView < 4) {
754 m_watchdogs.satellite_watchdog = sat_watchdog_timeout_ticks;
759 SendBasicNavdata(valid_flag, m_log_callbacks);
763bool CommBridge::HandleN0183_HDT(
const N0183MsgPtr& n0183_msg) {
764 string str = n0183_msg->payload;
766 ClearNavData(temp_data);
768 if (!m_decoder.DecodeHDT(str, temp_data))
return false;
771 if (EvalPriority(n0183_msg, active_priority_heading, priority_map_heading)) {
772 gHdt = temp_data.gHdt;
773 valid_flag += HDT_UPDATE;
774 m_watchdogs.heading_watchdog = gps_watchdog_timeout_ticks;
777 SendBasicNavdata(valid_flag, m_log_callbacks);
781bool CommBridge::HandleN0183_HDG(
const N0183MsgPtr& n0183_msg) {
782 string str = n0183_msg->payload;
784 ClearNavData(temp_data);
786 if (!m_decoder.DecodeHDG(str, temp_data))
return false;
791 if (EvalPriority(n0183_msg, active_priority_heading, priority_map_heading)) {
792 gHdm = temp_data.gHdm;
793 m_watchdogs.heading_watchdog = gps_watchdog_timeout_ticks;
797 if (!std::isnan(temp_data.gVar)) {
798 if (EvalPriority(n0183_msg, active_priority_variation,
799 priority_map_variation)) {
800 gVar = temp_data.gVar;
801 valid_flag += VAR_UPDATE;
802 m_watchdogs.variation_watchdog = gps_watchdog_timeout_ticks;
806 if (bHDM) MakeHDTFromHDM();
808 SendBasicNavdata(valid_flag, m_log_callbacks);
812bool CommBridge::HandleN0183_HDM(
const N0183MsgPtr& n0183_msg) {
813 string str = n0183_msg->payload;
815 ClearNavData(temp_data);
817 if (!m_decoder.DecodeHDM(str, temp_data))
return false;
820 if (EvalPriority(n0183_msg, active_priority_heading, priority_map_heading)) {
821 gHdm = temp_data.gHdm;
823 valid_flag += HDT_UPDATE;
824 m_watchdogs.heading_watchdog = gps_watchdog_timeout_ticks;
827 SendBasicNavdata(valid_flag, m_log_callbacks);
831bool CommBridge::HandleN0183_VTG(
const N0183MsgPtr& n0183_msg) {
832 string str = n0183_msg->payload;
834 ClearNavData(temp_data);
836 if (!m_decoder.DecodeVTG(str, temp_data))
return false;
839 if (EvalPriority(n0183_msg, active_priority_velocity,
840 priority_map_velocity)) {
841 gSog = temp_data.gSog;
842 valid_flag += SOG_UPDATE;
843 gCog = temp_data.gCog;
844 valid_flag += COG_UPDATE;
845 m_watchdogs.velocity_watchdog = gps_watchdog_timeout_ticks;
848 SendBasicNavdata(valid_flag, m_log_callbacks);
852bool CommBridge::HandleN0183_GSV(
const N0183MsgPtr& n0183_msg) {
853 string str = n0183_msg->payload;
855 ClearNavData(temp_data);
857 if (!m_decoder.DecodeGSV(str, temp_data))
return false;
860 if (EvalPriority(n0183_msg, active_priority_satellites,
861 priority_map_satellites)) {
862 if (temp_data.n_satellites >= 0) {
863 g_SatsInView = temp_data.n_satellites;
866 m_watchdogs.satellite_watchdog = sat_watchdog_timeout_ticks;
870 SendBasicNavdata(valid_flag, m_log_callbacks);
874bool CommBridge::HandleN0183_GGA(
const N0183MsgPtr& n0183_msg) {
875 string str = n0183_msg->payload;
877 ClearNavData(temp_data);
879 bool is_valid =
true;
880 if (!m_decoder.DecodeGGA(str, temp_data)) is_valid =
false;
882 if (std::isnan(temp_data.gLat) || std::isnan(temp_data.gLon))
return false;
885 if (EvalPriority(n0183_msg, active_priority_position,
886 priority_map_position)) {
888 gLat = temp_data.gLat;
889 gLon = temp_data.gLon;
890 valid_flag += POS_VALID;
891 m_watchdogs.position_watchdog = gps_watchdog_timeout_ticks;
892 m_n_log_watchdog_period = N_ACTIVE_LOG_WATCHDOG;
894 valid_flag += POS_UPDATE;
897 if (EvalPriority(n0183_msg, active_priority_satellites,
898 priority_map_satellites)) {
900 if (temp_data.n_satellites >= 0) {
901 g_SatsInView = temp_data.n_satellites;
904 m_watchdogs.satellite_watchdog = sat_watchdog_timeout_ticks;
909 SendBasicNavdata(valid_flag, m_log_callbacks);
913bool CommBridge::HandleN0183_GLL(
const N0183MsgPtr& n0183_msg) {
914 string str = n0183_msg->payload;
916 ClearNavData(temp_data);
919 if (!m_decoder.DecodeGLL(str, temp_data)) bvalid =
false;
921 if (std::isnan(temp_data.gLat) || std::isnan(temp_data.gLon))
return false;
924 if (EvalPriority(n0183_msg, active_priority_position,
925 priority_map_position)) {
927 gLat = temp_data.gLat;
928 gLon = temp_data.gLon;
929 valid_flag += POS_VALID;
930 m_watchdogs.position_watchdog = gps_watchdog_timeout_ticks;
931 m_n_log_watchdog_period = N_ACTIVE_LOG_WATCHDOG;
933 valid_flag += POS_UPDATE;
936 SendBasicNavdata(valid_flag, m_log_callbacks);
941 string str = n0183_msg->payload;
944 wxString sentence(str.c_str());
946 AisError ais_error = AIS_GENERIC_ERROR;
947 ais_error = DecodeSingleVDO(sentence, &gpd);
949 if (ais_error == AIS_NoError) {
951 if (!std::isnan(gpd.
kLat) && !std::isnan(gpd.
kLon)) {
952 if (EvalPriority(n0183_msg, active_priority_position,
953 priority_map_position)) {
956 valid_flag += POS_UPDATE;
957 valid_flag += POS_VALID;
958 m_watchdogs.position_watchdog = gps_watchdog_timeout_ticks;
959 m_n_log_watchdog_period =
960 N_ACTIVE_LOG_WATCHDOG;
964 if (!std::isnan(gpd.
kCog) && !std::isnan(gpd.
kSog)) {
965 if (EvalPriority(n0183_msg, active_priority_velocity,
966 priority_map_velocity)) {
968 valid_flag += SOG_UPDATE;
970 valid_flag += COG_UPDATE;
971 m_watchdogs.velocity_watchdog = gps_watchdog_timeout_ticks;
975 if (!std::isnan(gpd.
kHdt)) {
976 if (EvalPriority(n0183_msg, active_priority_heading,
977 priority_map_heading)) {
979 valid_flag += HDT_UPDATE;
980 m_watchdogs.heading_watchdog = gps_watchdog_timeout_ticks;
984 SendBasicNavdata(valid_flag, m_log_callbacks);
989bool CommBridge::HandleSignalK(
const SignalKMsgPtr& sK_msg) {
990 string str = sK_msg->raw_message;
993 if (sK_msg->context_self != sK_msg->context)
return false;
995 g_ownshipMMSI_SK = sK_msg->context_self;
998 ClearNavData(temp_data);
1000 if (!m_decoder.DecodeSignalK(str, temp_data))
return false;
1004 if (!std::isnan(temp_data.gLat) && !std::isnan(temp_data.gLon)) {
1005 if (EvalPriority(sK_msg, active_priority_position, priority_map_position)) {
1006 gLat = temp_data.gLat;
1007 gLon = temp_data.gLon;
1008 valid_flag += POS_UPDATE;
1009 valid_flag += POS_VALID;
1010 m_watchdogs.position_watchdog = gps_watchdog_timeout_ticks;
1011 m_n_log_watchdog_period = N_ACTIVE_LOG_WATCHDOG;
1015 if (!std::isnan(temp_data.gSog)) {
1016 if (EvalPriority(sK_msg, active_priority_velocity, priority_map_velocity)) {
1017 gSog = temp_data.gSog;
1018 valid_flag += SOG_UPDATE;
1019 if ((gSog > 0.05) && !std::isnan(temp_data.gCog)) {
1020 gCog = temp_data.gCog;
1021 valid_flag += COG_UPDATE;
1023 m_watchdogs.velocity_watchdog = gps_watchdog_timeout_ticks;
1027 if (!std::isnan(temp_data.gHdt)) {
1028 if (EvalPriority(sK_msg, active_priority_heading, priority_map_heading)) {
1029 gHdt = temp_data.gHdt;
1030 valid_flag += HDT_UPDATE;
1031 m_watchdogs.heading_watchdog = gps_watchdog_timeout_ticks;
1035 if (!std::isnan(temp_data.gHdm)) {
1036 if (EvalPriority(sK_msg, active_priority_heading, priority_map_heading)) {
1037 gHdm = temp_data.gHdm;
1039 valid_flag += HDT_UPDATE;
1040 m_watchdogs.heading_watchdog = gps_watchdog_timeout_ticks;
1044 if (!std::isnan(temp_data.gVar)) {
1045 if (EvalPriority(sK_msg, active_priority_variation,
1046 priority_map_variation)) {
1047 gVar = temp_data.gVar;
1048 valid_flag += VAR_UPDATE;
1049 m_watchdogs.variation_watchdog = gps_watchdog_timeout_ticks;
1053 if (temp_data.n_satellites > 0) {
1054 if (EvalPriority(sK_msg, active_priority_satellites,
1055 priority_map_satellites)) {
1056 g_SatsInView = temp_data.n_satellites;
1058 m_watchdogs.satellite_watchdog = sat_watchdog_timeout_ticks;
1062 if (g_pMUX && g_pMUX->IsLogActive())
1065 SendBasicNavdata(valid_flag, m_log_callbacks);
1069void CommBridge::ClearPriorityMaps() {
1070 priority_map_position.clear();
1071 priority_map_velocity.clear();
1072 priority_map_heading.clear();
1073 priority_map_variation.clear();
1074 priority_map_satellites.clear();
1078 if (category ==
"position")
1079 return active_priority_position;
1080 else if (category ==
"velocity")
1081 return active_priority_velocity;
1082 else if (category ==
"heading")
1083 return active_priority_heading;
1084 else if (category ==
"variation")
1085 return active_priority_variation;
1086 else if (category ==
"satellites")
1087 return active_priority_satellites;
1089 return active_priority_void;
1092void CommBridge::UpdateAndApplyMaps(
const std::vector<string>& new_maps) {
1093 ApplyPriorityMaps(new_maps);
1095 PresetPriorityContainers();
1098bool CommBridge::LoadConfig() {
1099 if (TheBaseConfig()) {
1100 TheBaseConfig()->SetPath(
"/Settings/CommPriority");
1102 std::vector<string> new_maps;
1103 wxString pri_string;
1105 TheBaseConfig()->Read(
"PriorityPosition", &pri_string);
1106 string s_prio = string(pri_string.c_str());
1107 new_maps.push_back(s_prio);
1109 TheBaseConfig()->Read(
"PriorityVelocity", &pri_string);
1110 s_prio = string(pri_string.c_str());
1111 new_maps.push_back(s_prio);
1113 TheBaseConfig()->Read(
"PriorityHeading", &pri_string);
1114 s_prio = string(pri_string.c_str());
1115 new_maps.push_back(s_prio);
1117 TheBaseConfig()->Read(
"PriorityVariation", &pri_string);
1118 s_prio = string(pri_string.c_str());
1119 new_maps.push_back(s_prio);
1121 TheBaseConfig()->Read(
"PrioritySatellites", &pri_string);
1122 s_prio = string(pri_string.c_str());
1123 new_maps.push_back(s_prio);
1125 ApplyPriorityMaps(new_maps);
1130bool CommBridge::SaveConfig()
const {
1131 if (TheBaseConfig()) {
1132 TheBaseConfig()->SetPath(
"/Settings/CommPriority");
1134 wxString pri_string =
1135 wxString(GetPriorityMap(priority_map_position).c_str());
1136 TheBaseConfig()->Write(
"PriorityPosition", pri_string);
1138 pri_string = wxString(GetPriorityMap(priority_map_velocity).c_str());
1139 TheBaseConfig()->Write(
"PriorityVelocity", pri_string);
1141 pri_string = wxString(GetPriorityMap(priority_map_heading).c_str());
1142 TheBaseConfig()->Write(
"PriorityHeading", pri_string);
1144 pri_string = wxString(GetPriorityMap(priority_map_variation).c_str());
1145 TheBaseConfig()->Write(
"PriorityVariation", pri_string);
1147 pri_string = wxString(GetPriorityMap(priority_map_satellites).c_str());
1148 TheBaseConfig()->Write(
"PrioritySatellites", pri_string);
1153bool CommBridge::EvalPriority(
const NavMsgPtr& msg,
1155 PriorityMap& priority_map) {
1156 string this_key = GetPriorityKey(msg);
1157 if (debug_priority) printf(
"This Key: %s\n", this_key.c_str());
1160 wxStringTokenizer tkz(this_key, _T(
";"));
1161 wxString wxs_this_source = tkz.GetNextToken();
1162 string source = wxs_this_source.ToStdString();
1163 wxString wxs_this_identifier = tkz.GetNextToken();
1164 string this_identifier = wxs_this_identifier.ToStdString();
1166 wxStringTokenizer tka(wxs_this_source, _T(
":"));
1168 std::stringstream ss;
1169 ss << tka.GetNextToken();
1171 ss >> source_address;
1179 if (msg->bus == NavAddr::Bus::N0183) {
1180 if (!strncmp(active_priority.prio_class.c_str(),
"velocity", 8)) {
1181 bool pos_ok =
false;
1182 if (!strcmp(active_priority_position.active_source.c_str(),
1184 if (active_priority_position.recent_active_time != -1) {
1188 if (!pos_ok)
return false;
1195 auto it = priority_map.find(this_key);
1196 if (it == priority_map.end()) {
1198 size_t n = priority_map.size();
1199 priority_map[this_key] =
static_cast<int>(n);
1202 this_priority = priority_map[this_key];
1204 if (debug_priority) {
1205 for (
const auto& jt : priority_map) {
1206 printf(
" priority_map: %s %d\n", jt.first.c_str(),
1213 if (this_priority > active_priority.active_priority) {
1215 printf(
" Drop low priority: %s %d %d \n", source.c_str(),
1216 this_priority, active_priority.active_priority);
1221 if (this_priority < active_priority.active_priority) {
1222 active_priority.active_priority = this_priority;
1223 active_priority.active_source = source;
1224 active_priority.active_identifier = this_identifier;
1225 active_priority.active_source_address = source_address;
1226 wxDateTime now = wxDateTime::Now();
1227 active_priority.recent_active_time = now.GetTicks();
1230 printf(
" Restoring high priority: %s %d\n", source.c_str(),
1238 if (!active_priority.active_source.empty()) {
1239 if (debug_priority) printf(
"source: %s\n", source.c_str());
1241 printf(
"active_source: %s\n", active_priority.active_source.c_str());
1243 if (source != active_priority.active_source) {
1246 int lowest_priority = -10;
1247 for (
const auto& jt : priority_map) {
1248 if (jt.second > lowest_priority) lowest_priority = jt.second;
1251 priority_map[this_key] = lowest_priority + 1;
1253 printf(
" Lowering priority A: %s :%d\n", source.c_str(),
1254 priority_map[this_key]);
1262 if (msg->bus == NavAddr::Bus::N0183) {
1263 auto msg_0183 = std::dynamic_pointer_cast<const Nmea0183Msg>(msg);
1265 if (!active_priority.active_identifier.empty()) {
1267 printf(
"this_identifier: %s\n", this_identifier.c_str());
1269 printf(
"active_priority.active_identifier: %s\n",
1270 active_priority.active_identifier.c_str());
1272 if (this_identifier != active_priority.active_identifier) {
1275 if (priority_map[this_key] == active_priority.active_priority) {
1276 int lowest_priority = -10;
1277 for (
const auto& jt : priority_map) {
1278 if (jt.second > lowest_priority) lowest_priority = jt.second;
1281 priority_map[this_key] = lowest_priority + 1;
1283 printf(
" Lowering priority B: %s :%d\n", source.c_str(),
1284 priority_map[this_key]);
1295 else if (msg->bus == NavAddr::Bus::N2000) {
1296 auto msg_n2k = std::dynamic_pointer_cast<const Nmea2000Msg>(msg);
1298 if (!active_priority.active_identifier.empty()) {
1299 if (this_identifier != active_priority.active_identifier) {
1302 if (priority_map[this_key] == active_priority.active_priority) {
1303 int lowest_priority = -10;
1304 for (
const auto& jt : priority_map) {
1305 if (jt.second > lowest_priority) lowest_priority = jt.second;
1308 priority_map[this_key] = lowest_priority + 1;
1310 printf(
" Lowering priority: %s :%d\n", source.c_str(),
1311 priority_map[this_key]);
1321 active_priority.active_source = source;
1322 active_priority.active_identifier = this_identifier;
1323 active_priority.active_source_address = source_address;
1324 wxDateTime now = wxDateTime::Now();
1325 active_priority.recent_active_time = now.GetTicks();
1327 printf(
" Accepting high priority: %s %d\n", source.c_str(), this_priority);
1329 if (active_priority.prio_class ==
"position") {
1330 if (this_priority != m_last_position_priority) {
1331 m_last_position_priority = this_priority;
1334 msg_.Printf(_(
"GNSS position fix priority shift:") +
" %s\n %s \n -> %s",
1335 this_identifier.c_str(), m_last_position_source.c_str(),
1337 auto& noteman = NotificationManager::GetInstance();
1338 noteman.AddNotification(NotificationSeverity::kInformational,
1339 msg_.ToStdString());
1341 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.
The CommBridge class and helpers.
Driver registration container, a singleton.
Raw messages layer, supports sending and recieving navmsg messages.
Hooks into gui available in model.
Multiplexer class and helpers.
Class NotificationManager.
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.