35#include <wx/tokenzr.h>
36#include <wx/fileconf.h>
38#include "model/comm_ais.h"
39#include "model/comm_appmsg_bus.h"
40#include "model/comm_bridge.h"
43#include "model/comm_vars.h"
44#include "model/config_vars.h"
45#include "model/cutil.h"
47#include "model/idents.h"
48#include "model/ocpn_types.h"
49#include "model/own_ship.h"
50#include "model/multiplexer.h"
70wxDEFINE_EVENT(EVT_DRIVER_CHANGE, wxCommandEvent);
74#define N_ACTIVE_LOG_WATCHDOG 300
78bool debug_priority = 0;
91static NmeaLog* GetDataMonitor() {
92 auto w = wxWindow::FindWindowByName(kDataMonitorWindowName);
93 return dynamic_cast<NmeaLog*
>(w);
97 log_callbacks.log_is_active = [&]() {
98 auto log = GetDataMonitor();
99 return log && log->IsVisible();
101 log_callbacks.log_message = [&](
Logline ll) {
102 NmeaLog* monitor = GetDataMonitor();
105 return log_callbacks;
110 AppNavMsg(
const std::shared_ptr<const AppMsg>& msg,
const std::string& name)
111 :
NavMsg(NavAddr::Bus::AppMsg,
112 std::make_shared<const NavAddrPlugin>(
"AppMsg")),
113 m_to_string(msg->to_string()),
116 std::string
to_string()
const override {
return m_to_string; }
118 std::string
key()
const override {
return "appmsg::" + m_name; }
120 const std::string m_to_string;
121 const std::string m_name;
124static void LogAppMsg(
const std::shared_ptr<const AppMsg>& msg,
125 const std::string& name,
127 if (!log_cb.log_is_active())
return;
128 auto navmsg = std::make_shared<AppNavMsg>(msg,
"basic-navdata");
131 log_cb.log_message(ll);
139 auto msg = std::make_shared<BasicNavDataMsg>(
140 gLat, gLon, gSog, gCog, gVar, gHdt, vflag, wxDateTime::Now().GetTicks());
141 clock_gettime(CLOCK_MONOTONIC, &msg->set_time);
142 LogAppMsg(msg,
"basic-navdata", log_callbacks);
143 AppMsgBus::GetInstance().
Notify(std::move(msg));
146static inline double GeodesicRadToDeg(
double rads) {
147 return rads * 180.0 / M_PI;
150static inline double MS2KNOTS(
double ms) {
return ms * 1.9438444924406; }
155EVT_TIMER(WATCHDOG_TIMER, CommBridge::OnWatchdogTimer)
160CommBridge::~CommBridge() {}
162bool CommBridge::Initialize() {
163 m_log_callbacks = GetLogCallbacks();
164 InitializePriorityContainers();
168 PresetPriorityContainers();
173 m_watchdog_timer.SetOwner(
this, WATCHDOG_TIMER);
174 m_watchdog_timer.Start(1000, wxTIMER_CONTINUOUS);
175 n_LogWatchdogPeriod = 3600;
182 driver_change_listener.
Listen(
183 CommDriverRegistry::GetInstance().evt_driverlist_change.key,
this,
185 Bind(EVT_DRIVER_CHANGE, [&](wxCommandEvent ev) { OnDriverStateChange(); });
190void CommBridge::PresetWatchdogs() {
191 m_watchdogs.position_watchdog =
193 m_watchdogs.velocity_watchdog = 20;
194 m_watchdogs.variation_watchdog = 20;
195 m_watchdogs.heading_watchdog = 20;
196 m_watchdogs.satellite_watchdog = 20;
199bool CommBridge::IsNextLowerPriorityAvailable(
202 for (
auto it = map.begin(); it != map.end(); it++) {
203 if (it->second > pc.active_priority) {
204 best_prio = wxMin(best_prio, it->second);
207 return best_prio != pc.active_priority;
210void CommBridge::SelectNextLowerPriority(
213 for (
auto it = map.begin(); it != map.end(); it++) {
214 if (it->second > pc.active_priority) {
215 best_prio = wxMin(best_prio, it->second);
219 pc.active_priority = best_prio;
220 pc.active_source.clear();
221 pc.active_identifier.clear();
224void CommBridge::OnWatchdogTimer(wxTimerEvent& event) {
226 m_watchdogs.position_watchdog--;
227 if (m_watchdogs.position_watchdog <= 0) {
228 if (m_watchdogs.position_watchdog % 5 == 0) {
230 auto msg = std::make_shared<GPSWatchdogMsg>(
231 GPSWatchdogMsg::WDSource::position, m_watchdogs.position_watchdog);
232 auto& msgbus = AppMsgBus::GetInstance();
233 LogAppMsg(msg,
"watchdog", m_log_callbacks);
234 msgbus.Notify(std::move(msg));
236 if (m_watchdogs.position_watchdog % n_LogWatchdogPeriod == 0) {
238 logmsg.Printf(_T(
" ***GPS Watchdog timeout at Lat:%g Lon: %g"),
240 wxLogMessage(logmsg);
248 active_priority_position.recent_active_time = -1;
252 if (IsNextLowerPriorityAvailable(priority_map_position,
253 active_priority_position)) {
254 SelectNextLowerPriority(priority_map_position, active_priority_position);
259 m_watchdogs.velocity_watchdog--;
260 if (m_watchdogs.velocity_watchdog <= 0) {
263 active_priority_velocity.recent_active_time = -1;
265 if (g_nNMEADebug && (m_watchdogs.velocity_watchdog == 0))
266 wxLogMessage(_T(
" ***Velocity Watchdog timeout..."));
267 if (m_watchdogs.velocity_watchdog % 5 == 0) {
269 auto msg = std::make_shared<GPSWatchdogMsg>(
270 GPSWatchdogMsg::WDSource::velocity, m_watchdogs.velocity_watchdog);
271 auto& msgbus = AppMsgBus::GetInstance();
272 msgbus.Notify(std::move(msg));
276 SelectNextLowerPriority(priority_map_velocity, active_priority_velocity);
280 m_watchdogs.heading_watchdog--;
281 if (m_watchdogs.heading_watchdog <= 0) {
283 active_priority_heading.recent_active_time = -1;
284 if (g_nNMEADebug && (m_watchdogs.heading_watchdog == 0))
285 wxLogMessage(_T(
" ***HDT Watchdog timeout..."));
289 SelectNextLowerPriority(priority_map_heading, active_priority_heading);
293 m_watchdogs.variation_watchdog--;
294 if (m_watchdogs.variation_watchdog <= 0) {
296 active_priority_variation.recent_active_time = -1;
298 if (g_nNMEADebug && (m_watchdogs.variation_watchdog == 0))
299 wxLogMessage(_T(
" ***VAR Watchdog timeout..."));
303 SelectNextLowerPriority(priority_map_variation, active_priority_variation);
307 m_watchdogs.satellite_watchdog--;
308 if (m_watchdogs.satellite_watchdog <= 0) {
312 active_priority_satellites.recent_active_time = -1;
314 if (g_nNMEADebug && (m_watchdogs.satellite_watchdog == 0))
315 wxLogMessage(_T(
" ***SAT Watchdog timeout..."));
319 SelectNextLowerPriority(priority_map_satellites,
320 active_priority_satellites);
324void CommBridge::MakeHDTFromHDM() {
327 if (!std::isnan(gHdm)) {
330 if (std::isnan(gVar) && (g_UserVar != 0.0)) gVar = g_UserVar;
332 if (!std::isnan(gHdt)) {
335 else if (gHdt >= 360)
338 m_watchdogs.heading_watchdog = gps_watchdog_timeout_ticks;
343void CommBridge::InitCommListeners() {
345 auto& msgbus = NavMsgBus::GetInstance();
349 Nmea2000Msg n2k_msg_129029(
static_cast<uint64_t
>(129029));
350 listener_N2K_129029.
Listen(n2k_msg_129029,
this, EVT_N2K_129029);
353 HandleN2K_129029(UnpackEvtPointer<Nmea2000Msg>(ev));
358 Nmea2000Msg n2k_msg_129025(
static_cast<uint64_t
>(129025));
359 listener_N2K_129025.
Listen(n2k_msg_129025,
this, EVT_N2K_129025);
361 HandleN2K_129025(UnpackEvtPointer<Nmea2000Msg>(ev));
366 Nmea2000Msg n2k_msg_129026(
static_cast<uint64_t
>(129026));
367 listener_N2K_129026.
Listen(n2k_msg_129026,
this, EVT_N2K_129026);
369 HandleN2K_129026(UnpackEvtPointer<Nmea2000Msg>(ev));
374 Nmea2000Msg n2k_msg_127250(
static_cast<uint64_t
>(127250));
375 listener_N2K_127250.
Listen(n2k_msg_127250,
this, EVT_N2K_127250);
377 HandleN2K_127250(UnpackEvtPointer<Nmea2000Msg>(ev));
382 Nmea2000Msg n2k_msg_129540(
static_cast<uint64_t
>(129540));
383 listener_N2K_129540.
Listen(n2k_msg_129540,
this, EVT_N2K_129540);
385 HandleN2K_129540(UnpackEvtPointer<Nmea2000Msg>(ev));
391 listener_N0183_RMC.
Listen(n0183_msg_RMC,
this, EVT_N0183_RMC);
394 HandleN0183_RMC(UnpackEvtPointer<Nmea0183Msg>(ev));
399 listener_N0183_HDT.
Listen(n0183_msg_HDT,
this, EVT_N0183_HDT);
402 HandleN0183_HDT(UnpackEvtPointer<Nmea0183Msg>(ev));
407 listener_N0183_HDG.
Listen(n0183_msg_HDG,
this, EVT_N0183_HDG);
410 HandleN0183_HDG(UnpackEvtPointer<Nmea0183Msg>(ev));
415 listener_N0183_HDM.
Listen(n0183_msg_HDM,
this, EVT_N0183_HDM);
418 HandleN0183_HDM(UnpackEvtPointer<Nmea0183Msg>(ev));
423 listener_N0183_VTG.
Listen(n0183_msg_VTG,
this, EVT_N0183_VTG);
426 HandleN0183_VTG(UnpackEvtPointer<Nmea0183Msg>(ev));
431 listener_N0183_GSV.
Listen(n0183_msg_GSV,
this, EVT_N0183_GSV);
434 HandleN0183_GSV(UnpackEvtPointer<Nmea0183Msg>(ev));
439 listener_N0183_GGA.
Listen(n0183_msg_GGA,
this, EVT_N0183_GGA);
442 HandleN0183_GGA(UnpackEvtPointer<Nmea0183Msg>(ev));
447 listener_N0183_GLL.
Listen(n0183_msg_GLL,
this, EVT_N0183_GLL);
450 HandleN0183_GLL(UnpackEvtPointer<Nmea0183Msg>(ev));
455 listener_N0183_AIVDO.
Listen(n0183_msg_AIVDO,
this, EVT_N0183_AIVDO);
463 listener_SignalK.
Listen(sk_msg,
this, EVT_SIGNALK);
466 HandleSignalK(UnpackEvtPointer<SignalkMsg>(ev));
470void CommBridge::OnDriverStateChange() {
472 PresetPriorityContainers();
475std::string CommBridge::GetPriorityMap(
476 std::unordered_map<std::string, int>& map) {
477#define MAX_SOURCES 10
478 std::string sa[MAX_SOURCES];
481 for (
auto& it : map) {
482 if ((it.second >= 0) && (it.second < MAX_SOURCES)) sa[it.second] = it.first;
486 for (
int i = 0; i < MAX_SOURCES; i++) {
496std::vector<std::string> CommBridge::GetPriorityMaps() {
497 std::vector<std::string> result;
499 result.push_back(GetPriorityMap(priority_map_position));
500 result.push_back(GetPriorityMap(priority_map_velocity));
501 result.push_back(GetPriorityMap(priority_map_heading));
502 result.push_back(GetPriorityMap(priority_map_variation));
503 result.push_back(GetPriorityMap(priority_map_satellites));
508void CommBridge::ApplyPriorityMap(
509 std::unordered_map<std::string, int>& priority_map, wxString& new_prio,
511 priority_map.clear();
512 wxStringTokenizer tk(new_prio,
"|");
514 while (tk.HasMoreTokens()) {
515 wxString entry = tk.GetNextToken();
516 std::string s_entry(entry.c_str());
517 priority_map[s_entry] = index;
522void CommBridge::ApplyPriorityMaps(std::vector<std::string> new_maps) {
523 wxString new_prio_string;
525 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::PresetPriorityContainer(
543 const std::unordered_map<std::string, int>& priority_map) {
547 for (
auto& it : priority_map) {
548 if (it.second == 0) key0 = it.first;
551 wxString this_key(key0.c_str());
552 wxStringTokenizer tkz(this_key, _T(
";"));
553 wxString wxs_this_source = tkz.GetNextToken();
554 std::string source = wxs_this_source.ToStdString();
555 wxString wxs_this_identifier = tkz.GetNextToken();
556 std::string this_identifier = wxs_this_identifier.ToStdString();
558 wxStringTokenizer tka(wxs_this_source, _T(
":"));
560 int source_address = atoi(tka.GetNextToken().ToStdString().c_str());
562 pc.active_priority = 0;
563 pc.active_source = source;
564 pc.active_identifier = this_identifier;
565 pc.active_source_address = source_address;
566 pc.recent_active_time = -1;
569void CommBridge::PresetPriorityContainers() {
570 PresetPriorityContainer(active_priority_position, priority_map_position);
571 PresetPriorityContainer(active_priority_velocity, priority_map_velocity);
572 PresetPriorityContainer(active_priority_heading, priority_map_heading);
573 PresetPriorityContainer(active_priority_variation, priority_map_variation);
574 PresetPriorityContainer(active_priority_satellites, priority_map_satellites);
577bool CommBridge::HandleN2K_129029(std::shared_ptr<const Nmea2000Msg> n2k_msg) {
578 std::vector<unsigned char> v = n2k_msg->payload;
582 unsigned char* c = (
unsigned char*)&pgn;
588 ClearNavData(temp_data);
590 if (!m_decoder.DecodePGN129029(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 n_LogWatchdogPeriod = N_ACTIVE_LOG_WATCHDOG;
605 if (temp_data.n_satellites >= 0) {
606 if (EvalPriority(n2k_msg, active_priority_satellites,
607 priority_map_satellites)) {
608 g_SatsInView = temp_data.n_satellites;
610 m_watchdogs.satellite_watchdog = sat_watchdog_timeout_ticks;
614 SendBasicNavdata(valid_flag, m_log_callbacks);
618bool CommBridge::HandleN2K_129025(std::shared_ptr<const Nmea2000Msg> n2k_msg) {
619 std::vector<unsigned char> v = n2k_msg->payload;
622 ClearNavData(temp_data);
624 if (!m_decoder.DecodePGN129025(v, temp_data))
return false;
627 if (!N2kIsNA(temp_data.gLat) && !N2kIsNA(temp_data.gLon)) {
628 if (EvalPriority(n2k_msg, active_priority_position,
629 priority_map_position)) {
630 gLat = temp_data.gLat;
631 gLon = temp_data.gLon;
632 valid_flag += POS_UPDATE;
633 valid_flag += POS_VALID;
634 m_watchdogs.position_watchdog = gps_watchdog_timeout_ticks;
635 n_LogWatchdogPeriod = N_ACTIVE_LOG_WATCHDOG;
642 SendBasicNavdata(valid_flag, m_log_callbacks);
646bool CommBridge::HandleN2K_129026(std::shared_ptr<const Nmea2000Msg> n2k_msg) {
647 std::vector<unsigned char> v = n2k_msg->payload;
650 ClearNavData(temp_data);
652 if (!m_decoder.DecodePGN129026(v, temp_data))
return false;
655 if (!N2kIsNA(temp_data.gSog)) {
656 if (EvalPriority(n2k_msg, active_priority_velocity,
657 priority_map_velocity)) {
658 gSog = MS2KNOTS(temp_data.gSog);
659 valid_flag += SOG_UPDATE;
661 if (N2kIsNA(temp_data.gCog))
664 gCog = GeodesicRadToDeg(temp_data.gCog);
665 valid_flag += COG_UPDATE;
666 m_watchdogs.velocity_watchdog = gps_watchdog_timeout_ticks;
671 SendBasicNavdata(valid_flag, m_log_callbacks);
675bool CommBridge::HandleN2K_127250(std::shared_ptr<const Nmea2000Msg> n2k_msg) {
676 std::vector<unsigned char> v = n2k_msg->payload;
679 ClearNavData(temp_data);
681 if (!m_decoder.DecodePGN127250(v, temp_data))
return false;
684 if (!N2kIsNA(temp_data.gVar)) {
685 if (EvalPriority(n2k_msg, active_priority_variation,
686 priority_map_variation)) {
687 gVar = GeodesicRadToDeg(temp_data.gVar);
688 valid_flag += VAR_UPDATE;
689 m_watchdogs.variation_watchdog = gps_watchdog_timeout_ticks;
693 if (!N2kIsNA(temp_data.gHdt)) {
694 if (EvalPriority(n2k_msg, active_priority_heading, priority_map_heading)) {
695 gHdt = GeodesicRadToDeg(temp_data.gHdt);
696 valid_flag += HDT_UPDATE;
697 m_watchdogs.heading_watchdog = gps_watchdog_timeout_ticks;
701 if (!N2kIsNA(temp_data.gHdm)) {
702 gHdm = GeodesicRadToDeg(temp_data.gHdm);
703 if (EvalPriority(n2k_msg, active_priority_heading, priority_map_heading)) {
705 valid_flag += HDT_UPDATE;
706 if (!std::isnan(gHdt))
707 m_watchdogs.heading_watchdog = gps_watchdog_timeout_ticks;
711 SendBasicNavdata(valid_flag, m_log_callbacks);
715bool CommBridge::HandleN2K_129540(std::shared_ptr<const Nmea2000Msg> n2k_msg) {
716 std::vector<unsigned char> v = n2k_msg->payload;
719 ClearNavData(temp_data);
721 if (!m_decoder.DecodePGN129540(v, temp_data))
return false;
724 if (temp_data.n_satellites >= 0) {
725 if (EvalPriority(n2k_msg, active_priority_satellites,
726 priority_map_satellites)) {
727 g_SatsInView = temp_data.n_satellites;
729 m_watchdogs.satellite_watchdog = sat_watchdog_timeout_ticks;
736bool CommBridge::HandleN0183_RMC(std::shared_ptr<const Nmea0183Msg> n0183_msg) {
737 std::string str = n0183_msg->payload;
740 ClearNavData(temp_data);
743 if (!m_decoder.DecodeRMC(str, temp_data)) bvalid =
false;
745 if (std::isnan(temp_data.gLat) || std::isnan(temp_data.gLon))
return false;
748 if (EvalPriority(n0183_msg, active_priority_position,
749 priority_map_position)) {
751 gLat = temp_data.gLat;
752 gLon = temp_data.gLon;
753 valid_flag += POS_VALID;
754 m_watchdogs.position_watchdog = gps_watchdog_timeout_ticks;
755 n_LogWatchdogPeriod = N_ACTIVE_LOG_WATCHDOG;
757 valid_flag += POS_UPDATE;
760 if (EvalPriority(n0183_msg, active_priority_velocity,
761 priority_map_velocity)) {
763 gSog = temp_data.gSog;
764 valid_flag += SOG_UPDATE;
765 gCog = temp_data.gCog;
766 valid_flag += COG_UPDATE;
767 m_watchdogs.velocity_watchdog = gps_watchdog_timeout_ticks;
771 if (!std::isnan(temp_data.gVar)) {
772 if (EvalPriority(n0183_msg, active_priority_variation,
773 priority_map_variation)) {
775 gVar = temp_data.gVar;
776 valid_flag += VAR_UPDATE;
777 m_watchdogs.variation_watchdog = gps_watchdog_timeout_ticks;
782 SendBasicNavdata(valid_flag, m_log_callbacks);
786bool CommBridge::HandleN0183_HDT(std::shared_ptr<const Nmea0183Msg> n0183_msg) {
787 std::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(std::shared_ptr<const Nmea0183Msg> n0183_msg) {
805 std::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(std::shared_ptr<const Nmea0183Msg> n0183_msg) {
836 std::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(std::shared_ptr<const Nmea0183Msg> n0183_msg) {
855 std::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(std::shared_ptr<const Nmea0183Msg> n0183_msg) {
876 std::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(std::shared_ptr<const Nmea0183Msg> n0183_msg) {
898 std::string str = n0183_msg->payload;
900 ClearNavData(temp_data);
903 if (!m_decoder.DecodeGGA(str, temp_data)) bvalid =
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 n_LogWatchdogPeriod = 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(std::shared_ptr<const Nmea0183Msg> n0183_msg) {
937 std::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 n_LogWatchdogPeriod = N_ACTIVE_LOG_WATCHDOG;
956 valid_flag += POS_UPDATE;
959 SendBasicNavdata(valid_flag, m_log_callbacks);
964 std::shared_ptr<const Nmea0183Msg> n0183_msg) {
965 std::string str = n0183_msg->payload;
968 wxString sentence(str.c_str());
972 AisError nerr = AIS_GENERIC_ERROR;
973 nerr = DecodeSingleVDO(sentence, &gpd);
975 if (nerr == AIS_NoError) {
976 if (!std::isnan(gpd.
kLat) && !std::isnan(gpd.
kLon)) {
977 if (EvalPriority(n0183_msg, active_priority_position,
978 priority_map_position)) {
981 valid_flag += POS_UPDATE;
982 valid_flag += POS_VALID;
983 m_watchdogs.position_watchdog = gps_watchdog_timeout_ticks;
984 n_LogWatchdogPeriod = N_ACTIVE_LOG_WATCHDOG;
988 if (!std::isnan(gpd.
kCog) && !std::isnan(gpd.
kSog)) {
989 if (EvalPriority(n0183_msg, active_priority_velocity,
990 priority_map_velocity)) {
992 valid_flag += SOG_UPDATE;
994 valid_flag += COG_UPDATE;
995 m_watchdogs.velocity_watchdog = gps_watchdog_timeout_ticks;
999 if (!std::isnan(gpd.
kHdt)) {
1000 if (EvalPriority(n0183_msg, active_priority_heading,
1001 priority_map_heading)) {
1003 valid_flag += HDT_UPDATE;
1004 m_watchdogs.heading_watchdog = gps_watchdog_timeout_ticks;
1008 SendBasicNavdata(valid_flag, m_log_callbacks);
1013bool CommBridge::HandleSignalK(std::shared_ptr<const SignalkMsg> sK_msg) {
1014 std::string str = sK_msg->raw_message;
1017 if (sK_msg->context_self != sK_msg->context)
return false;
1019 g_ownshipMMSI_SK = sK_msg->context_self;
1022 ClearNavData(temp_data);
1024 if (!m_decoder.DecodeSignalK(str, temp_data))
return false;
1028 if (!std::isnan(temp_data.gLat) && !std::isnan(temp_data.gLon)) {
1029 if (EvalPriority(sK_msg, active_priority_position, priority_map_position)) {
1030 gLat = temp_data.gLat;
1031 gLon = temp_data.gLon;
1032 valid_flag += POS_UPDATE;
1033 valid_flag += POS_VALID;
1034 m_watchdogs.position_watchdog = gps_watchdog_timeout_ticks;
1035 n_LogWatchdogPeriod = N_ACTIVE_LOG_WATCHDOG;
1039 if (!std::isnan(temp_data.gSog)) {
1040 if (EvalPriority(sK_msg, active_priority_velocity, priority_map_velocity)) {
1041 gSog = temp_data.gSog;
1042 valid_flag += SOG_UPDATE;
1043 if ((gSog > 0.05) && !std::isnan(temp_data.gCog)) {
1044 gCog = temp_data.gCog;
1045 valid_flag += COG_UPDATE;
1047 m_watchdogs.velocity_watchdog = gps_watchdog_timeout_ticks;
1051 if (!std::isnan(temp_data.gHdt)) {
1052 if (EvalPriority(sK_msg, active_priority_heading, priority_map_heading)) {
1053 gHdt = temp_data.gHdt;
1054 valid_flag += HDT_UPDATE;
1055 m_watchdogs.heading_watchdog = gps_watchdog_timeout_ticks;
1059 if (!std::isnan(temp_data.gHdm)) {
1060 if (EvalPriority(sK_msg, active_priority_heading, priority_map_heading)) {
1061 gHdm = temp_data.gHdm;
1063 valid_flag += HDT_UPDATE;
1064 m_watchdogs.heading_watchdog = gps_watchdog_timeout_ticks;
1068 if (!std::isnan(temp_data.gVar)) {
1069 if (EvalPriority(sK_msg, active_priority_variation,
1070 priority_map_variation)) {
1071 gVar = temp_data.gVar;
1072 valid_flag += VAR_UPDATE;
1073 m_watchdogs.variation_watchdog = gps_watchdog_timeout_ticks;
1077 bool sat_update =
false;
1078 if (temp_data.n_satellites > 0) {
1079 if (EvalPriority(sK_msg, active_priority_satellites,
1080 priority_map_satellites)) {
1081 g_SatsInView = temp_data.n_satellites;
1084 m_watchdogs.satellite_watchdog = sat_watchdog_timeout_ticks;
1088 if (g_pMUX && g_pMUX->IsLogActive()) {
1089 std::string logmsg =
"Self: ";
1090 std::string content;
1091 if (valid_flag & POS_UPDATE) content +=
"POS;";
1092 if (valid_flag & POS_VALID) content +=
"POS_Valid;";
1093 if (valid_flag & SOG_UPDATE) content +=
"SOG;";
1094 if (valid_flag & COG_UPDATE) content +=
"COG;";
1095 if (valid_flag & HDT_UPDATE) content +=
"HDT;";
1096 if (valid_flag & VAR_UPDATE) content +=
"VAR;";
1097 if (sat_update) content +=
"SAT;";
1099 if (content.empty()) content =
"Not used by OCPN, maybe passed to plugins";
1105 SendBasicNavdata(valid_flag, m_log_callbacks);
1109void CommBridge::InitializePriorityContainers() {
1110 active_priority_position.active_priority = 0;
1111 active_priority_velocity.active_priority = 0;
1112 active_priority_heading.active_priority = 0;
1113 active_priority_variation.active_priority = 0;
1114 active_priority_satellites.active_priority = 0;
1116 active_priority_position.active_source.clear();
1117 active_priority_velocity.active_source.clear();
1118 active_priority_heading.active_source.clear();
1119 active_priority_variation.active_source.clear();
1120 active_priority_satellites.active_source.clear();
1122 active_priority_position.active_identifier.clear();
1123 active_priority_velocity.active_identifier.clear();
1124 active_priority_heading.active_identifier.clear();
1125 active_priority_variation.active_identifier.clear();
1126 active_priority_satellites.active_identifier.clear();
1128 active_priority_position.pcclass =
"position";
1129 active_priority_velocity.pcclass =
"velocity";
1130 active_priority_heading.pcclass =
"heading";
1131 active_priority_variation.pcclass =
"variation";
1132 active_priority_satellites.pcclass =
"satellites";
1134 active_priority_position.active_source_address = -1;
1135 active_priority_velocity.active_source_address = -1;
1136 active_priority_heading.active_source_address = -1;
1137 active_priority_variation.active_source_address = -1;
1138 active_priority_satellites.active_source_address = -1;
1140 active_priority_void.active_priority = -1;
1143void CommBridge::ClearPriorityMaps() {
1144 priority_map_position.clear();
1145 priority_map_velocity.clear();
1146 priority_map_heading.clear();
1147 priority_map_variation.clear();
1148 priority_map_satellites.clear();
1152 const std::string category) {
1153 if (!category.compare(
"position"))
1154 return active_priority_position;
1155 else if (!category.compare(
"velocity"))
1156 return active_priority_velocity;
1157 else if (!category.compare(
"heading"))
1158 return active_priority_heading;
1159 else if (!category.compare(
"variation"))
1160 return active_priority_variation;
1161 else if (!category.compare(
"satellites"))
1162 return active_priority_satellites;
1164 return active_priority_void;
1167void CommBridge::UpdateAndApplyMaps(std::vector<std::string> new_maps) {
1168 ApplyPriorityMaps(new_maps);
1170 PresetPriorityContainers();
1173bool CommBridge::LoadConfig(
void) {
1174 if (TheBaseConfig()) {
1175 TheBaseConfig()->SetPath(
"/Settings/CommPriority");
1177 std::vector<std::string> new_maps;
1179 wxString pri_string;
1181 TheBaseConfig()->Read(
"PriorityPosition", &pri_string);
1182 s_prio = std::string(pri_string.c_str());
1183 new_maps.push_back(s_prio);
1185 TheBaseConfig()->Read(
"PriorityVelocity", &pri_string);
1186 s_prio = std::string(pri_string.c_str());
1187 new_maps.push_back(s_prio);
1189 TheBaseConfig()->Read(
"PriorityHeading", &pri_string);
1190 s_prio = std::string(pri_string.c_str());
1191 new_maps.push_back(s_prio);
1193 TheBaseConfig()->Read(
"PriorityVariation", &pri_string);
1194 s_prio = std::string(pri_string.c_str());
1195 new_maps.push_back(s_prio);
1197 TheBaseConfig()->Read(
"PrioritySatellites", &pri_string);
1198 s_prio = std::string(pri_string.c_str());
1199 new_maps.push_back(s_prio);
1201 ApplyPriorityMaps(new_maps);
1206bool CommBridge::SaveConfig(
void) {
1207 if (TheBaseConfig()) {
1208 TheBaseConfig()->SetPath(
"/Settings/CommPriority");
1210 wxString pri_string;
1211 pri_string = wxString(GetPriorityMap(priority_map_position).c_str());
1212 TheBaseConfig()->Write(
"PriorityPosition", pri_string);
1214 pri_string = wxString(GetPriorityMap(priority_map_velocity).c_str());
1215 TheBaseConfig()->Write(
"PriorityVelocity", pri_string);
1217 pri_string = wxString(GetPriorityMap(priority_map_heading).c_str());
1218 TheBaseConfig()->Write(
"PriorityHeading", pri_string);
1220 pri_string = wxString(GetPriorityMap(priority_map_variation).c_str());
1221 TheBaseConfig()->Write(
"PriorityVariation", pri_string);
1223 pri_string = wxString(GetPriorityMap(priority_map_satellites).c_str());
1224 TheBaseConfig()->Write(
"PrioritySatellites", pri_string);
1230std::string CommBridge::GetPriorityKey(std::shared_ptr<const NavMsg> msg) {
1231 std::string source = msg->source->to_string();
1232 std::string listener_key = msg->key();
1234 std::string this_identifier;
1235 std::string this_address(
"0");
1236 if (msg->bus == NavAddr::Bus::N0183) {
1237 auto msg_0183 = std::dynamic_pointer_cast<const Nmea0183Msg>(msg);
1239 this_identifier = msg_0183->talker;
1240 this_identifier += msg_0183->type;
1242 }
else if (msg->bus == NavAddr::Bus::N2000) {
1243 auto msg_n2k = std::dynamic_pointer_cast<const Nmea2000Msg>(msg);
1245 this_identifier = msg_n2k->PGN.to_string();
1246 unsigned char n_source = msg_n2k->payload.at(7);
1248 sprintf(ss,
"%d", n_source);
1249 this_address = std::string(ss);
1251 }
else if (msg->bus == NavAddr::Bus::Signalk) {
1252 auto msg_sk = std::dynamic_pointer_cast<const SignalkMsg>(msg);
1255 std::static_pointer_cast<const NavAddrSignalK>(msg->source);
1256 source = addr_sk->to_string();
1257 this_identifier =
"signalK";
1258 this_address = msg->source->iface;
1262 return source +
":" + this_address +
";" + this_identifier;
1265bool CommBridge::EvalPriority(
1267 std::unordered_map<std::string, int>& priority_map) {
1268 std::string this_key = GetPriorityKey(msg);
1269 if (debug_priority) printf(
"This Key: %s\n", this_key.c_str());
1272 wxStringTokenizer tkz(this_key, _T(
";"));
1273 wxString wxs_this_source = tkz.GetNextToken();
1274 std::string source = wxs_this_source.ToStdString();
1275 wxString wxs_this_identifier = tkz.GetNextToken();
1276 std::string this_identifier = wxs_this_identifier.ToStdString();
1278 wxStringTokenizer tka(wxs_this_source, _T(
":"));
1280 int source_address = atoi(tka.GetNextToken().ToStdString().c_str());
1288 if (msg->bus == NavAddr::Bus::N0183) {
1289 if (!strncmp(active_priority.pcclass.c_str(),
"velocity", 8)) {
1290 bool pos_ok =
false;
1291 if (!strcmp(active_priority_position.active_source.c_str(),
1293 if (active_priority_position.recent_active_time != -1) {
1297 if (!pos_ok)
return false;
1304 auto it = priority_map.find(this_key);
1305 if (it == priority_map.end()) {
1307 size_t n = priority_map.size();
1308 priority_map[this_key] = n;
1311 this_priority = priority_map[this_key];
1313 if (debug_priority) {
1314 for (
auto it = priority_map.begin(); it != priority_map.end(); it++)
1315 printf(
" priority_map: %s %d\n", it->first.c_str(),
1321 if (this_priority > active_priority.active_priority) {
1323 printf(
" Drop low priority: %s %d %d \n", source.c_str(),
1324 this_priority, active_priority.active_priority);
1329 if (this_priority < active_priority.active_priority) {
1330 active_priority.active_priority = this_priority;
1331 active_priority.active_source = source;
1332 active_priority.active_identifier = this_identifier;
1333 active_priority.active_source_address = source_address;
1334 wxDateTime now = wxDateTime::Now();
1335 active_priority.recent_active_time = now.GetTicks();
1338 printf(
" Restoring high priority: %s %d\n", source.c_str(),
1346 if (active_priority.active_source.size()) {
1347 if (debug_priority) printf(
"source: %s\n", source.c_str());
1349 printf(
"active_source: %s\n", active_priority.active_source.c_str());
1351 if (source.compare(active_priority.active_source) != 0) {
1354 int lowest_priority = -10;
1355 for (
auto it = priority_map.begin(); it != priority_map.end(); it++) {
1356 if (it->second > lowest_priority) lowest_priority = it->second;
1359 priority_map[this_key] = lowest_priority + 1;
1361 printf(
" Lowering priority A: %s :%d\n", source.c_str(),
1362 priority_map[this_key]);
1370 if (msg->bus == NavAddr::Bus::N0183) {
1371 auto msg_0183 = std::dynamic_pointer_cast<const Nmea0183Msg>(msg);
1373 if (active_priority.active_identifier.size()) {
1375 printf(
"this_identifier: %s\n", this_identifier.c_str());
1377 printf(
"active_priority.active_identifier: %s\n",
1378 active_priority.active_identifier.c_str());
1380 if (this_identifier.compare(active_priority.active_identifier) != 0) {
1383 if (priority_map[this_key] == active_priority.active_priority) {
1384 int lowest_priority = -10;
1385 for (
auto it = priority_map.begin(); it != priority_map.end();
1387 if (it->second > lowest_priority) lowest_priority = it->second;
1390 priority_map[this_key] = lowest_priority + 1;
1392 printf(
" Lowering priority B: %s :%d\n", source.c_str(),
1393 priority_map[this_key]);
1404 else if (msg->bus == NavAddr::Bus::N2000) {
1405 auto msg_n2k = std::dynamic_pointer_cast<const Nmea2000Msg>(msg);
1407 if (active_priority.active_identifier.size()) {
1408 if (this_identifier.compare(active_priority.active_identifier) != 0) {
1411 if (priority_map[this_key] == active_priority.active_priority) {
1412 int lowest_priority = -10;
1413 for (
auto it = priority_map.begin(); it != priority_map.end();
1415 if (it->second > lowest_priority) lowest_priority = it->second;
1418 priority_map[this_key] = lowest_priority + 1;
1420 printf(
" Lowering priority: %s :%d\n", source.c_str(),
1421 priority_map[this_key]);
1431 active_priority.active_source = source;
1432 active_priority.active_identifier = this_identifier;
1433 active_priority.active_source_address = source_address;
1434 wxDateTime now = wxDateTime::Now();
1435 active_priority.recent_active_time = now.GetTicks();
1437 printf(
" Accepting high priority: %s %d\n", source.c_str(), this_priority);
1439 if (active_priority.pcclass ==
"position") {
1440 if (this_priority != m_last_position_priority) {
1441 m_last_position_priority = this_priority;
1444 msg.Printf(
"GNSS position fix priority shift: %s\n %s \n -> %s",
1445 this_identifier.c_str(), m_last_position_source.c_str(),
1447 auto& noteman = NotificationManager::GetInstance();
1448 noteman.AddNotification(NotificationSeverity::kInformational,
1451 m_last_position_source = source;
void Notify(const std::shared_ptr< const AppMsg > &msg)
Send message to everyone listening to given message type.
std::string key() const override
Return unique key used by observable to notify/listen.
std::string to_string() const override
Return printable string for logging etc without trailing nl.
bool HandleN0183_AIVDO(std::shared_ptr< const Nmea0183Msg > 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="")
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.
virtual void Add(const Logline &l)=0
Add an formatted string to log output.
void Listen(const std::string &key, wxEvtHandler *listener, wxEventType evt)
Set object to send wxEventType ev to listener on changes in key.
Custom event class for OpenCPN's notification system.
A parsed SignalK message over ipv4.
Driver registration container, a singleton.
Raw messages layer, supports sending and recieving navmsg messages.
Hooks into gui available in model.
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.