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"
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_THS(UnpackEvtPointer<Nmea0183Msg>(ev));
467 HandleN0183_HDT(UnpackEvtPointer<Nmea0183Msg>(ev));
472 HandleN0183_HDG(UnpackEvtPointer<Nmea0183Msg>(ev));
477 HandleN0183_HDM(UnpackEvtPointer<Nmea0183Msg>(ev));
482 HandleN0183_VTG(UnpackEvtPointer<Nmea0183Msg>(ev));
487 HandleN0183_GSV(UnpackEvtPointer<Nmea0183Msg>(ev));
492 HandleN0183_GGA(UnpackEvtPointer<Nmea0183Msg>(ev));
498 HandleN0183_GLL(UnpackEvtPointer<Nmea0183Msg>(ev));
508 HandleSignalK(UnpackEvtPointer<SignalkMsg>(ev));
512void CommBridge::OnDriverStateChange() {
514 PresetPriorityContainers();
517std::vector<string> CommBridge::GetPriorityMaps()
const {
518 std::vector<string> result;
519 result.push_back(GetPriorityMap(priority_map_position));
520 result.push_back(GetPriorityMap(priority_map_velocity));
521 result.push_back(GetPriorityMap(priority_map_heading));
522 result.push_back(GetPriorityMap(priority_map_variation));
523 result.push_back(GetPriorityMap(priority_map_satellites));
527void CommBridge::ApplyPriorityMaps(
const std::vector<string>& new_maps) {
528 wxString new_prio_string = wxString(new_maps[0].c_str());
529 ApplyPriorityMap(priority_map_position, new_prio_string, 0);
531 new_prio_string = wxString(new_maps[1].c_str());
532 ApplyPriorityMap(priority_map_velocity, new_prio_string, 1);
534 new_prio_string = wxString(new_maps[2].c_str());
535 ApplyPriorityMap(priority_map_heading, new_prio_string, 2);
537 new_prio_string = wxString(new_maps[3].c_str());
538 ApplyPriorityMap(priority_map_variation, new_prio_string, 3);
540 new_prio_string = wxString(new_maps[4].c_str());
541 ApplyPriorityMap(priority_map_satellites, new_prio_string, 4);
544void CommBridge::PresetPriorityContainers() {
545 PresetPriorityContainer(active_priority_position, priority_map_position);
546 PresetPriorityContainer(active_priority_velocity, priority_map_velocity);
547 PresetPriorityContainer(active_priority_heading, priority_map_heading);
548 PresetPriorityContainer(active_priority_variation, priority_map_variation);
549 PresetPriorityContainer(active_priority_satellites, priority_map_satellites);
552bool CommBridge::HandleN2K_129029(
const N2000MsgPtr& n2k_msg) {
553 std::vector<unsigned char> v = n2k_msg->payload;
557 ClearNavData(temp_data);
559 if (!m_decoder.DecodePGN129029(v, temp_data))
return false;
562 if (!N2kIsNA(temp_data.gLat) && !N2kIsNA(temp_data.gLon)) {
563 if (EvalPriority(n2k_msg, active_priority_position,
564 priority_map_position)) {
565 gLat = temp_data.gLat;
566 gLon = temp_data.gLon;
567 valid_flag += POS_UPDATE;
568 valid_flag += POS_VALID;
569 m_watchdogs.position_watchdog = gps_watchdog_timeout_ticks;
570 m_n_log_watchdog_period = N_ACTIVE_LOG_WATCHDOG;
574 if (temp_data.n_satellites >= 0) {
575 if (EvalPriority(n2k_msg, active_priority_satellites,
576 priority_map_satellites)) {
577 g_SatsInView = temp_data.n_satellites;
579 m_watchdogs.satellite_watchdog = sat_watchdog_timeout_ticks;
583 SendBasicNavdata(valid_flag, m_log_callbacks);
587bool CommBridge::HandleN2K_129025(
const N2000MsgPtr& n2k_msg) {
588 std::vector<unsigned char> v = n2k_msg->payload;
591 ClearNavData(temp_data);
593 if (!m_decoder.DecodePGN129025(v, temp_data))
return false;
596 if (!N2kIsNA(temp_data.gLat) && !N2kIsNA(temp_data.gLon)) {
597 if (EvalPriority(n2k_msg, active_priority_position,
598 priority_map_position)) {
599 gLat = temp_data.gLat;
600 gLon = temp_data.gLon;
601 valid_flag += POS_UPDATE;
602 valid_flag += POS_VALID;
603 m_watchdogs.position_watchdog = gps_watchdog_timeout_ticks;
604 m_n_log_watchdog_period = N_ACTIVE_LOG_WATCHDOG;
611 SendBasicNavdata(valid_flag, m_log_callbacks);
615bool CommBridge::HandleN2K_129026(
const N2000MsgPtr& n2k_msg) {
616 std::vector<unsigned char> v = n2k_msg->payload;
619 ClearNavData(temp_data);
621 if (!m_decoder.DecodePGN129026(v, temp_data))
return false;
624 if (!N2kIsNA(temp_data.gSog)) {
625 if (EvalPriority(n2k_msg, active_priority_velocity,
626 priority_map_velocity)) {
627 gSog = MS2KNOTS(temp_data.gSog);
628 valid_flag += SOG_UPDATE;
630 if (N2kIsNA(temp_data.gCog))
633 gCog = GeodesicRadToDeg(temp_data.gCog);
634 valid_flag += COG_UPDATE;
635 m_watchdogs.velocity_watchdog = gps_watchdog_timeout_ticks;
640 SendBasicNavdata(valid_flag, m_log_callbacks);
644bool CommBridge::HandleN2K_127250(
const N2000MsgPtr& n2k_msg) {
645 std::vector<unsigned char> v = n2k_msg->payload;
648 ClearNavData(temp_data);
650 if (!m_decoder.DecodePGN127250(v, temp_data))
return false;
653 if (!N2kIsNA(temp_data.gVar)) {
654 if (EvalPriority(n2k_msg, active_priority_variation,
655 priority_map_variation)) {
656 gVar = GeodesicRadToDeg(temp_data.gVar);
657 valid_flag += VAR_UPDATE;
658 m_watchdogs.variation_watchdog = gps_watchdog_timeout_ticks;
662 if (!N2kIsNA(temp_data.gHdt)) {
663 if (EvalPriority(n2k_msg, active_priority_heading, priority_map_heading)) {
664 gHdt = GeodesicRadToDeg(temp_data.gHdt);
665 valid_flag += HDT_UPDATE;
666 m_watchdogs.heading_watchdog = gps_watchdog_timeout_ticks;
670 if (!N2kIsNA(temp_data.gHdm)) {
671 gHdm = GeodesicRadToDeg(temp_data.gHdm);
672 if (EvalPriority(n2k_msg, active_priority_heading, priority_map_heading)) {
674 valid_flag += HDT_UPDATE;
675 if (!std::isnan(gHdt))
676 m_watchdogs.heading_watchdog = gps_watchdog_timeout_ticks;
680 SendBasicNavdata(valid_flag, m_log_callbacks);
684bool CommBridge::HandleN2K_129540(
const N2000MsgPtr& n2k_msg) {
685 std::vector<unsigned char> v = n2k_msg->payload;
688 ClearNavData(temp_data);
690 if (!m_decoder.DecodePGN129540(v, temp_data))
return false;
692 if (temp_data.n_satellites >= 0) {
693 if (EvalPriority(n2k_msg, active_priority_satellites,
694 priority_map_satellites)) {
695 g_SatsInView = temp_data.n_satellites;
697 m_watchdogs.satellite_watchdog = sat_watchdog_timeout_ticks;
704bool CommBridge::HandleN0183_RMC(
const N0183MsgPtr& n0183_msg) {
705 string str = n0183_msg->payload;
708 ClearNavData(temp_data);
710 bool is_valid =
true;
711 if (!m_decoder.DecodeRMC(str, temp_data)) is_valid =
false;
713 if (std::isnan(temp_data.gLat) || std::isnan(temp_data.gLon))
return false;
716 if (EvalPriority(n0183_msg, active_priority_position,
717 priority_map_position)) {
719 gLat = temp_data.gLat;
720 gLon = temp_data.gLon;
721 valid_flag += POS_VALID;
722 m_watchdogs.position_watchdog = gps_watchdog_timeout_ticks;
723 m_n_log_watchdog_period = N_ACTIVE_LOG_WATCHDOG;
725 valid_flag += POS_UPDATE;
728 if (EvalPriority(n0183_msg, active_priority_velocity,
729 priority_map_velocity)) {
731 gSog = temp_data.gSog;
732 valid_flag += SOG_UPDATE;
733 gCog = temp_data.gCog;
734 valid_flag += COG_UPDATE;
735 m_watchdogs.velocity_watchdog = gps_watchdog_timeout_ticks;
739 if (!std::isnan(temp_data.gVar)) {
740 if (EvalPriority(n0183_msg, active_priority_variation,
741 priority_map_variation)) {
743 gVar = temp_data.gVar;
744 valid_flag += VAR_UPDATE;
745 m_watchdogs.variation_watchdog = gps_watchdog_timeout_ticks;
755 if ((valid_flag & POS_VALID) == POS_VALID) {
757 if (g_SatsInView < 4) {
759 m_watchdogs.satellite_watchdog = sat_watchdog_timeout_ticks;
764 SendBasicNavdata(valid_flag, m_log_callbacks);
768bool CommBridge::HandleN0183_THS(
const N0183MsgPtr& n0183_msg) {
769 string str = n0183_msg->payload;
771 ClearNavData(temp_data);
773 if (!m_decoder.DecodeTHS(str, temp_data))
return false;
776 if (EvalPriority(n0183_msg, active_priority_heading, priority_map_heading)) {
777 gHdt = temp_data.gHdt;
778 valid_flag += HDT_UPDATE;
779 m_watchdogs.heading_watchdog = gps_watchdog_timeout_ticks;
782 SendBasicNavdata(valid_flag, m_log_callbacks);
786bool CommBridge::HandleN0183_HDT(
const N0183MsgPtr& n0183_msg) {
787 string str = n0183_msg->payload;
789 ClearNavData(temp_data);
791 if (!m_decoder.DecodeHDT(str, temp_data))
return false;
794 if (EvalPriority(n0183_msg, active_priority_heading, priority_map_heading)) {
795 gHdt = temp_data.gHdt;
796 valid_flag += HDT_UPDATE;
797 m_watchdogs.heading_watchdog = gps_watchdog_timeout_ticks;
800 SendBasicNavdata(valid_flag, m_log_callbacks);
804bool CommBridge::HandleN0183_HDG(
const N0183MsgPtr& n0183_msg) {
805 string str = n0183_msg->payload;
807 ClearNavData(temp_data);
809 if (!m_decoder.DecodeHDG(str, temp_data))
return false;
814 if (EvalPriority(n0183_msg, active_priority_heading, priority_map_heading)) {
815 gHdm = temp_data.gHdm;
816 m_watchdogs.heading_watchdog = gps_watchdog_timeout_ticks;
820 if (!std::isnan(temp_data.gVar)) {
821 if (EvalPriority(n0183_msg, active_priority_variation,
822 priority_map_variation)) {
823 gVar = temp_data.gVar;
824 valid_flag += VAR_UPDATE;
825 m_watchdogs.variation_watchdog = gps_watchdog_timeout_ticks;
829 if (bHDM) MakeHDTFromHDM();
831 SendBasicNavdata(valid_flag, m_log_callbacks);
835bool CommBridge::HandleN0183_HDM(
const N0183MsgPtr& n0183_msg) {
836 string str = n0183_msg->payload;
838 ClearNavData(temp_data);
840 if (!m_decoder.DecodeHDM(str, temp_data))
return false;
843 if (EvalPriority(n0183_msg, active_priority_heading, priority_map_heading)) {
844 gHdm = temp_data.gHdm;
846 valid_flag += HDT_UPDATE;
847 m_watchdogs.heading_watchdog = gps_watchdog_timeout_ticks;
850 SendBasicNavdata(valid_flag, m_log_callbacks);
854bool CommBridge::HandleN0183_VTG(
const N0183MsgPtr& n0183_msg) {
855 string str = n0183_msg->payload;
857 ClearNavData(temp_data);
859 if (!m_decoder.DecodeVTG(str, temp_data))
return false;
862 if (EvalPriority(n0183_msg, active_priority_velocity,
863 priority_map_velocity)) {
864 gSog = temp_data.gSog;
865 valid_flag += SOG_UPDATE;
866 gCog = temp_data.gCog;
867 valid_flag += COG_UPDATE;
868 m_watchdogs.velocity_watchdog = gps_watchdog_timeout_ticks;
871 SendBasicNavdata(valid_flag, m_log_callbacks);
875bool CommBridge::HandleN0183_GSV(
const N0183MsgPtr& n0183_msg) {
876 string str = n0183_msg->payload;
878 ClearNavData(temp_data);
880 if (!m_decoder.DecodeGSV(str, temp_data))
return false;
883 if (EvalPriority(n0183_msg, active_priority_satellites,
884 priority_map_satellites)) {
885 if (temp_data.n_satellites >= 0) {
886 g_SatsInView = temp_data.n_satellites;
889 m_watchdogs.satellite_watchdog = sat_watchdog_timeout_ticks;
893 SendBasicNavdata(valid_flag, m_log_callbacks);
897bool CommBridge::HandleN0183_GGA(
const N0183MsgPtr& n0183_msg) {
898 string str = n0183_msg->payload;
900 ClearNavData(temp_data);
902 bool is_valid =
true;
903 if (!m_decoder.DecodeGGA(str, temp_data)) is_valid =
false;
905 if (std::isnan(temp_data.gLat) || std::isnan(temp_data.gLon))
return false;
908 if (EvalPriority(n0183_msg, active_priority_position,
909 priority_map_position)) {
911 gLat = temp_data.gLat;
912 gLon = temp_data.gLon;
913 valid_flag += POS_VALID;
914 m_watchdogs.position_watchdog = gps_watchdog_timeout_ticks;
915 m_n_log_watchdog_period = N_ACTIVE_LOG_WATCHDOG;
917 valid_flag += POS_UPDATE;
920 if (EvalPriority(n0183_msg, active_priority_satellites,
921 priority_map_satellites)) {
923 if (temp_data.n_satellites >= 0) {
924 g_SatsInView = temp_data.n_satellites;
927 m_watchdogs.satellite_watchdog = sat_watchdog_timeout_ticks;
932 SendBasicNavdata(valid_flag, m_log_callbacks);
936bool CommBridge::HandleN0183_GLL(
const N0183MsgPtr& n0183_msg) {
937 string str = n0183_msg->payload;
939 ClearNavData(temp_data);
942 if (!m_decoder.DecodeGLL(str, temp_data)) bvalid =
false;
944 if (std::isnan(temp_data.gLat) || std::isnan(temp_data.gLon))
return false;
947 if (EvalPriority(n0183_msg, active_priority_position,
948 priority_map_position)) {
950 gLat = temp_data.gLat;
951 gLon = temp_data.gLon;
952 valid_flag += POS_VALID;
953 m_watchdogs.position_watchdog = gps_watchdog_timeout_ticks;
954 m_n_log_watchdog_period = N_ACTIVE_LOG_WATCHDOG;
956 valid_flag += POS_UPDATE;
959 SendBasicNavdata(valid_flag, m_log_callbacks);
964 string str = n0183_msg->payload;
967 wxString sentence(str.c_str());
969 AisError ais_error = AIS_GENERIC_ERROR;
970 ais_error = DecodeSingleVDO(sentence, &gpd);
972 if (ais_error == AIS_NoError) {
974 if (!std::isnan(gpd.
kLat) && !std::isnan(gpd.
kLon)) {
975 if (EvalPriority(n0183_msg, active_priority_position,
976 priority_map_position)) {
979 valid_flag += POS_UPDATE;
980 valid_flag += POS_VALID;
981 m_watchdogs.position_watchdog = gps_watchdog_timeout_ticks;
982 m_n_log_watchdog_period =
983 N_ACTIVE_LOG_WATCHDOG;
987 if (!std::isnan(gpd.
kCog) && !std::isnan(gpd.
kSog)) {
988 if (EvalPriority(n0183_msg, active_priority_velocity,
989 priority_map_velocity)) {
991 valid_flag += SOG_UPDATE;
993 valid_flag += COG_UPDATE;
994 m_watchdogs.velocity_watchdog = gps_watchdog_timeout_ticks;
998 if (!std::isnan(gpd.
kHdt)) {
999 if (EvalPriority(n0183_msg, active_priority_heading,
1000 priority_map_heading)) {
1002 valid_flag += HDT_UPDATE;
1003 m_watchdogs.heading_watchdog = gps_watchdog_timeout_ticks;
1007 SendBasicNavdata(valid_flag, m_log_callbacks);
1012bool CommBridge::HandleSignalK(
const SignalKMsgPtr& sK_msg) {
1013 string str = sK_msg->raw_message;
1016 if (sK_msg->context_self != sK_msg->context)
return false;
1018 g_ownshipMMSI_SK = sK_msg->context_self;
1021 ClearNavData(temp_data);
1023 if (!m_decoder.DecodeSignalK(str, temp_data))
return false;
1027 if (!std::isnan(temp_data.gLat) && !std::isnan(temp_data.gLon)) {
1028 if (EvalPriority(sK_msg, active_priority_position, priority_map_position)) {
1029 gLat = temp_data.gLat;
1030 gLon = temp_data.gLon;
1031 valid_flag += POS_UPDATE;
1032 valid_flag += POS_VALID;
1033 m_watchdogs.position_watchdog = gps_watchdog_timeout_ticks;
1034 m_n_log_watchdog_period = N_ACTIVE_LOG_WATCHDOG;
1038 if (!std::isnan(temp_data.gSog)) {
1039 if (EvalPriority(sK_msg, active_priority_velocity, priority_map_velocity)) {
1040 gSog = temp_data.gSog;
1041 valid_flag += SOG_UPDATE;
1042 if ((gSog > 0.05) && !std::isnan(temp_data.gCog)) {
1043 gCog = temp_data.gCog;
1044 valid_flag += COG_UPDATE;
1046 m_watchdogs.velocity_watchdog = gps_watchdog_timeout_ticks;
1050 if (!std::isnan(temp_data.gHdt)) {
1051 if (EvalPriority(sK_msg, active_priority_heading, priority_map_heading)) {
1052 gHdt = temp_data.gHdt;
1053 valid_flag += HDT_UPDATE;
1054 m_watchdogs.heading_watchdog = gps_watchdog_timeout_ticks;
1058 if (!std::isnan(temp_data.gHdm)) {
1059 if (EvalPriority(sK_msg, active_priority_heading, priority_map_heading)) {
1060 gHdm = temp_data.gHdm;
1062 valid_flag += HDT_UPDATE;
1063 m_watchdogs.heading_watchdog = gps_watchdog_timeout_ticks;
1067 if (!std::isnan(temp_data.gVar)) {
1068 if (EvalPriority(sK_msg, active_priority_variation,
1069 priority_map_variation)) {
1070 gVar = temp_data.gVar;
1071 valid_flag += VAR_UPDATE;
1072 m_watchdogs.variation_watchdog = gps_watchdog_timeout_ticks;
1076 if (temp_data.n_satellites > 0) {
1077 if (EvalPriority(sK_msg, active_priority_satellites,
1078 priority_map_satellites)) {
1079 g_SatsInView = temp_data.n_satellites;
1081 m_watchdogs.satellite_watchdog = sat_watchdog_timeout_ticks;
1085 if (g_pMUX && g_pMUX->IsLogActive())
1088 SendBasicNavdata(valid_flag, m_log_callbacks);
1092void CommBridge::ClearPriorityMaps() {
1093 priority_map_position.clear();
1094 priority_map_velocity.clear();
1095 priority_map_heading.clear();
1096 priority_map_variation.clear();
1097 priority_map_satellites.clear();
1101 if (category ==
"position")
1102 return active_priority_position;
1103 else if (category ==
"velocity")
1104 return active_priority_velocity;
1105 else if (category ==
"heading")
1106 return active_priority_heading;
1107 else if (category ==
"variation")
1108 return active_priority_variation;
1109 else if (category ==
"satellites")
1110 return active_priority_satellites;
1112 return active_priority_void;
1115void CommBridge::UpdateAndApplyMaps(
const std::vector<string>& new_maps) {
1116 ApplyPriorityMaps(new_maps);
1118 PresetPriorityContainers();
1121bool CommBridge::LoadConfig() {
1122 if (TheBaseConfig()) {
1123 TheBaseConfig()->SetPath(
"/Settings/CommPriority");
1125 std::vector<string> new_maps;
1126 wxString pri_string;
1128 TheBaseConfig()->Read(
"PriorityPosition", &pri_string);
1129 string s_prio = string(pri_string.c_str());
1130 new_maps.push_back(s_prio);
1132 TheBaseConfig()->Read(
"PriorityVelocity", &pri_string);
1133 s_prio = string(pri_string.c_str());
1134 new_maps.push_back(s_prio);
1136 TheBaseConfig()->Read(
"PriorityHeading", &pri_string);
1137 s_prio = string(pri_string.c_str());
1138 new_maps.push_back(s_prio);
1140 TheBaseConfig()->Read(
"PriorityVariation", &pri_string);
1141 s_prio = string(pri_string.c_str());
1142 new_maps.push_back(s_prio);
1144 TheBaseConfig()->Read(
"PrioritySatellites", &pri_string);
1145 s_prio = string(pri_string.c_str());
1146 new_maps.push_back(s_prio);
1148 ApplyPriorityMaps(new_maps);
1153bool CommBridge::SaveConfig()
const {
1154 if (TheBaseConfig()) {
1155 TheBaseConfig()->SetPath(
"/Settings/CommPriority");
1157 wxString pri_string =
1158 wxString(GetPriorityMap(priority_map_position).c_str());
1159 TheBaseConfig()->Write(
"PriorityPosition", pri_string);
1161 pri_string = wxString(GetPriorityMap(priority_map_velocity).c_str());
1162 TheBaseConfig()->Write(
"PriorityVelocity", pri_string);
1164 pri_string = wxString(GetPriorityMap(priority_map_heading).c_str());
1165 TheBaseConfig()->Write(
"PriorityHeading", pri_string);
1167 pri_string = wxString(GetPriorityMap(priority_map_variation).c_str());
1168 TheBaseConfig()->Write(
"PriorityVariation", pri_string);
1170 pri_string = wxString(GetPriorityMap(priority_map_satellites).c_str());
1171 TheBaseConfig()->Write(
"PrioritySatellites", pri_string);
1176bool CommBridge::EvalPriority(
const NavMsgPtr& msg,
1178 PriorityMap& priority_map) {
1179 string this_key = GetPriorityKey(msg);
1180 if (debug_priority) printf(
"This Key: %s\n", this_key.c_str());
1183 wxStringTokenizer tkz(this_key, _T(
";"));
1184 wxString wxs_this_source = tkz.GetNextToken();
1185 string source = wxs_this_source.ToStdString();
1186 wxString wxs_this_identifier = tkz.GetNextToken();
1187 string this_identifier = wxs_this_identifier.ToStdString();
1189 wxStringTokenizer tka(wxs_this_source, _T(
":"));
1191 std::stringstream ss;
1192 ss << tka.GetNextToken();
1194 ss >> source_address;
1202 if (msg->bus == NavAddr::Bus::N0183) {
1203 if (!strncmp(active_priority.prio_class.c_str(),
"velocity", 8)) {
1204 bool pos_ok =
false;
1205 if (!strcmp(active_priority_position.active_source.c_str(),
1207 if (active_priority_position.recent_active_time != -1) {
1211 if (!pos_ok)
return false;
1218 auto it = priority_map.find(this_key);
1219 if (it == priority_map.end()) {
1221 size_t n = priority_map.size();
1222 priority_map[this_key] =
static_cast<int>(n);
1225 this_priority = priority_map[this_key];
1227 if (debug_priority) {
1228 for (
const auto& jt : priority_map) {
1229 printf(
" priority_map: %s %d\n", jt.first.c_str(),
1236 if (this_priority > active_priority.active_priority) {
1238 printf(
" Drop low priority: %s %d %d \n", source.c_str(),
1239 this_priority, active_priority.active_priority);
1244 if (this_priority < active_priority.active_priority) {
1245 active_priority.active_priority = this_priority;
1246 active_priority.active_source = source;
1247 active_priority.active_identifier = this_identifier;
1248 active_priority.active_source_address = source_address;
1249 wxDateTime now = wxDateTime::Now();
1250 active_priority.recent_active_time = now.GetTicks();
1253 printf(
" Restoring high priority: %s %d\n", source.c_str(),
1261 if (!active_priority.active_source.empty()) {
1262 if (debug_priority) printf(
"source: %s\n", source.c_str());
1264 printf(
"active_source: %s\n", active_priority.active_source.c_str());
1266 if (source != active_priority.active_source) {
1269 int lowest_priority = -10;
1270 for (
const auto& jt : priority_map) {
1271 if (jt.second > lowest_priority) lowest_priority = jt.second;
1274 priority_map[this_key] = lowest_priority + 1;
1276 printf(
" Lowering priority A: %s :%d\n", source.c_str(),
1277 priority_map[this_key]);
1285 if (msg->bus == NavAddr::Bus::N0183) {
1286 auto msg_0183 = std::dynamic_pointer_cast<const Nmea0183Msg>(msg);
1288 if (!active_priority.active_identifier.empty()) {
1290 printf(
"this_identifier: %s\n", this_identifier.c_str());
1292 printf(
"active_priority.active_identifier: %s\n",
1293 active_priority.active_identifier.c_str());
1295 if (this_identifier != active_priority.active_identifier) {
1298 if (priority_map[this_key] == active_priority.active_priority) {
1299 int lowest_priority = -10;
1300 for (
const auto& jt : priority_map) {
1301 if (jt.second > lowest_priority) lowest_priority = jt.second;
1304 priority_map[this_key] = lowest_priority + 1;
1306 printf(
" Lowering priority B: %s :%d\n", source.c_str(),
1307 priority_map[this_key]);
1318 else if (msg->bus == NavAddr::Bus::N2000) {
1319 auto msg_n2k = std::dynamic_pointer_cast<const Nmea2000Msg>(msg);
1321 if (!active_priority.active_identifier.empty()) {
1322 if (this_identifier != active_priority.active_identifier) {
1325 if (priority_map[this_key] == active_priority.active_priority) {
1326 int lowest_priority = -10;
1327 for (
const auto& jt : priority_map) {
1328 if (jt.second > lowest_priority) lowest_priority = jt.second;
1331 priority_map[this_key] = lowest_priority + 1;
1333 printf(
" Lowering priority: %s :%d\n", source.c_str(),
1334 priority_map[this_key]);
1344 active_priority.active_source = source;
1345 active_priority.active_identifier = this_identifier;
1346 active_priority.active_source_address = source_address;
1347 wxDateTime now = wxDateTime::Now();
1348 active_priority.recent_active_time = now.GetTicks();
1350 printf(
" Accepting high priority: %s %d\n", source.c_str(), this_priority);
1352 if (active_priority.prio_class ==
"position") {
1353 if (this_priority != m_last_position_priority) {
1354 m_last_position_priority = this_priority;
1357 msg_.Printf(_(
"GNSS position fix priority shift:") +
" %s\n %s \n -> %s",
1358 this_identifier.c_str(), m_last_position_source.c_str(),
1360 auto& noteman = NotificationManager::GetInstance();
1361 noteman.AddNotification(NotificationSeverity::kInformational,
1362 msg_.ToStdString());
1364 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.
Global variables stored in configuration file.
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.