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"
69wxDEFINE_EVENT(EVT_DRIVER_CHANGE, wxCommandEvent);
73#define N_ACTIVE_LOG_WATCHDOG 300
77bool debug_priority = 0;
90static NmeaLog* GetDataMonitor() {
91 auto w = wxWindow::FindWindowByName(kDataMonitorWindowName);
92 return dynamic_cast<NmeaLog*
>(w);
96 log_callbacks.log_is_active = [&]() {
97 auto log = GetDataMonitor();
98 return log && log->IsActive();
100 log_callbacks.log_message = [&](
Logline ll) {
101 NmeaLog* monitor = GetDataMonitor();
102 if (monitor && monitor->
IsActive()) monitor->
Add(ll);
104 return log_callbacks;
109 AppNavMsg(
const std::shared_ptr<const AppMsg>& msg,
const std::string& name)
110 :
NavMsg(NavAddr::Bus::AppMsg,
111 std::make_shared<const NavAddrPlugin>(
"AppMsg")),
112 m_to_string(msg->to_string()),
115 std::string
to_string()
const override {
return m_to_string; }
117 std::string
key()
const override {
return "appmsg::" + m_name; }
119 const std::string m_to_string;
120 const std::string m_name;
123static void LogAppMsg(
const std::shared_ptr<const AppMsg>& msg,
124 const std::string& name,
126 if (!log_cb.log_is_active())
return;
127 auto navmsg = std::make_shared<AppNavMsg>(msg,
"basic-navdata");
130 log_cb.log_message(ll);
138 auto msg = std::make_shared<BasicNavDataMsg>(
139 gLat, gLon, gSog, gCog, gVar, gHdt, vflag, wxDateTime::Now().GetTicks());
140 clock_gettime(CLOCK_MONOTONIC, &msg->set_time);
141 LogAppMsg(msg,
"basic-navdata", log_callbacks);
142 AppMsgBus::GetInstance().
Notify(std::move(msg));
145static inline double GeodesicRadToDeg(
double rads) {
146 return rads * 180.0 / M_PI;
149static inline double MS2KNOTS(
double ms) {
return ms * 1.9438444924406; }
154EVT_TIMER(WATCHDOG_TIMER, CommBridge::OnWatchdogTimer)
159CommBridge::~CommBridge() {}
161bool CommBridge::Initialize() {
162 m_log_callbacks = GetLogCallbacks();
163 InitializePriorityContainers();
167 PresetPriorityContainers();
172 m_watchdog_timer.SetOwner(
this, WATCHDOG_TIMER);
173 m_watchdog_timer.Start(1000, wxTIMER_CONTINUOUS);
174 n_LogWatchdogPeriod = 3600;
181 driver_change_listener.
Listen(
182 CommDriverRegistry::GetInstance().evt_driverlist_change.key,
this,
184 Bind(EVT_DRIVER_CHANGE, [&](wxCommandEvent ev) { OnDriverStateChange(); });
189void CommBridge::PresetWatchdogs() {
190 m_watchdogs.position_watchdog =
192 m_watchdogs.velocity_watchdog = 20;
193 m_watchdogs.variation_watchdog = 20;
194 m_watchdogs.heading_watchdog = 20;
195 m_watchdogs.satellite_watchdog = 20;
198void CommBridge::SelectNextLowerPriority(
201 for (
auto it = map.begin(); it != map.end(); it++) {
202 if (it->second > pc.active_priority) {
203 best_prio = wxMin(best_prio, it->second);
207 pc.active_priority = best_prio;
208 pc.active_source.clear();
209 pc.active_identifier.clear();
212void CommBridge::OnWatchdogTimer(wxTimerEvent& event) {
214 m_watchdogs.position_watchdog--;
215 if (m_watchdogs.position_watchdog <= 0) {
216 if (m_watchdogs.position_watchdog % 5 == 0) {
218 auto msg = std::make_shared<GPSWatchdogMsg>(
219 GPSWatchdogMsg::WDSource::position, m_watchdogs.position_watchdog);
220 auto& msgbus = AppMsgBus::GetInstance();
221 msgbus.Notify(std::move(msg));
222 LogAppMsg(msg,
"watchdog", m_log_callbacks);
224 if (m_watchdogs.position_watchdog % n_LogWatchdogPeriod == 0) {
226 logmsg.Printf(_T(
" ***GPS Watchdog timeout at Lat:%g Lon: %g"),
228 wxLogMessage(logmsg);
236 active_priority_position.recent_active_time = -1;
240 SelectNextLowerPriority(priority_map_position, active_priority_position);
244 m_watchdogs.velocity_watchdog--;
245 if (m_watchdogs.velocity_watchdog <= 0) {
248 active_priority_velocity.recent_active_time = -1;
250 if (g_nNMEADebug && (m_watchdogs.velocity_watchdog == 0))
251 wxLogMessage(_T(
" ***Velocity Watchdog timeout..."));
252 if (m_watchdogs.velocity_watchdog % 5 == 0) {
254 auto msg = std::make_shared<GPSWatchdogMsg>(
255 GPSWatchdogMsg::WDSource::velocity, m_watchdogs.velocity_watchdog);
256 auto& msgbus = AppMsgBus::GetInstance();
257 msgbus.Notify(std::move(msg));
261 SelectNextLowerPriority(priority_map_velocity, active_priority_velocity);
265 m_watchdogs.heading_watchdog--;
266 if (m_watchdogs.heading_watchdog <= 0) {
268 active_priority_heading.recent_active_time = -1;
269 if (g_nNMEADebug && (m_watchdogs.heading_watchdog == 0))
270 wxLogMessage(_T(
" ***HDT Watchdog timeout..."));
274 SelectNextLowerPriority(priority_map_heading, active_priority_heading);
278 m_watchdogs.variation_watchdog--;
279 if (m_watchdogs.variation_watchdog <= 0) {
281 active_priority_variation.recent_active_time = -1;
283 if (g_nNMEADebug && (m_watchdogs.variation_watchdog == 0))
284 wxLogMessage(_T(
" ***VAR Watchdog timeout..."));
288 SelectNextLowerPriority(priority_map_variation, active_priority_variation);
292 m_watchdogs.satellite_watchdog--;
293 if (m_watchdogs.satellite_watchdog <= 0) {
297 active_priority_satellites.recent_active_time = -1;
299 if (g_nNMEADebug && (m_watchdogs.satellite_watchdog == 0))
300 wxLogMessage(_T(
" ***SAT Watchdog timeout..."));
304 SelectNextLowerPriority(priority_map_satellites,
305 active_priority_satellites);
309void CommBridge::MakeHDTFromHDM() {
312 if (!std::isnan(gHdm)) {
315 if (std::isnan(gVar) && (g_UserVar != 0.0)) gVar = g_UserVar;
317 if (!std::isnan(gHdt)) {
320 else if (gHdt >= 360)
323 m_watchdogs.heading_watchdog = gps_watchdog_timeout_ticks;
328void CommBridge::InitCommListeners() {
330 auto& msgbus = NavMsgBus::GetInstance();
334 Nmea2000Msg n2k_msg_129029(
static_cast<uint64_t
>(129029));
335 listener_N2K_129029.
Listen(n2k_msg_129029,
this, EVT_N2K_129029);
338 HandleN2K_129029(UnpackEvtPointer<Nmea2000Msg>(ev));
343 Nmea2000Msg n2k_msg_129025(
static_cast<uint64_t
>(129025));
344 listener_N2K_129025.
Listen(n2k_msg_129025,
this, EVT_N2K_129025);
346 HandleN2K_129025(UnpackEvtPointer<Nmea2000Msg>(ev));
351 Nmea2000Msg n2k_msg_129026(
static_cast<uint64_t
>(129026));
352 listener_N2K_129026.
Listen(n2k_msg_129026,
this, EVT_N2K_129026);
354 HandleN2K_129026(UnpackEvtPointer<Nmea2000Msg>(ev));
359 Nmea2000Msg n2k_msg_127250(
static_cast<uint64_t
>(127250));
360 listener_N2K_127250.
Listen(n2k_msg_127250,
this, EVT_N2K_127250);
362 HandleN2K_127250(UnpackEvtPointer<Nmea2000Msg>(ev));
367 Nmea2000Msg n2k_msg_129540(
static_cast<uint64_t
>(129540));
368 listener_N2K_129540.
Listen(n2k_msg_129540,
this, EVT_N2K_129540);
370 HandleN2K_129540(UnpackEvtPointer<Nmea2000Msg>(ev));
376 listener_N0183_RMC.
Listen(n0183_msg_RMC,
this, EVT_N0183_RMC);
379 HandleN0183_RMC(UnpackEvtPointer<Nmea0183Msg>(ev));
384 listener_N0183_HDT.
Listen(n0183_msg_HDT,
this, EVT_N0183_HDT);
387 HandleN0183_HDT(UnpackEvtPointer<Nmea0183Msg>(ev));
392 listener_N0183_HDG.
Listen(n0183_msg_HDG,
this, EVT_N0183_HDG);
395 HandleN0183_HDG(UnpackEvtPointer<Nmea0183Msg>(ev));
400 listener_N0183_HDM.
Listen(n0183_msg_HDM,
this, EVT_N0183_HDM);
403 HandleN0183_HDM(UnpackEvtPointer<Nmea0183Msg>(ev));
408 listener_N0183_VTG.
Listen(n0183_msg_VTG,
this, EVT_N0183_VTG);
411 HandleN0183_VTG(UnpackEvtPointer<Nmea0183Msg>(ev));
416 listener_N0183_GSV.
Listen(n0183_msg_GSV,
this, EVT_N0183_GSV);
419 HandleN0183_GSV(UnpackEvtPointer<Nmea0183Msg>(ev));
424 listener_N0183_GGA.
Listen(n0183_msg_GGA,
this, EVT_N0183_GGA);
427 HandleN0183_GGA(UnpackEvtPointer<Nmea0183Msg>(ev));
432 listener_N0183_GLL.
Listen(n0183_msg_GLL,
this, EVT_N0183_GLL);
435 HandleN0183_GLL(UnpackEvtPointer<Nmea0183Msg>(ev));
440 listener_N0183_AIVDO.
Listen(n0183_msg_AIVDO,
this, EVT_N0183_AIVDO);
448 listener_SignalK.
Listen(sk_msg,
this, EVT_SIGNALK);
451 HandleSignalK(UnpackEvtPointer<SignalkMsg>(ev));
455void CommBridge::OnDriverStateChange() {
457 PresetPriorityContainers();
460std::string CommBridge::GetPriorityMap(
461 std::unordered_map<std::string, int>& map) {
462#define MAX_SOURCES 10
463 std::string sa[MAX_SOURCES];
466 for (
auto& it : map) {
467 if ((it.second >= 0) && (it.second < MAX_SOURCES)) sa[it.second] = it.first;
471 for (
int i = 0; i < MAX_SOURCES; i++) {
481std::vector<std::string> CommBridge::GetPriorityMaps() {
482 std::vector<std::string> result;
484 result.push_back(GetPriorityMap(priority_map_position));
485 result.push_back(GetPriorityMap(priority_map_velocity));
486 result.push_back(GetPriorityMap(priority_map_heading));
487 result.push_back(GetPriorityMap(priority_map_variation));
488 result.push_back(GetPriorityMap(priority_map_satellites));
493void CommBridge::ApplyPriorityMap(
494 std::unordered_map<std::string, int>& priority_map, wxString& new_prio,
496 priority_map.clear();
497 wxStringTokenizer tk(new_prio,
"|");
499 while (tk.HasMoreTokens()) {
500 wxString entry = tk.GetNextToken();
501 std::string s_entry(entry.c_str());
502 priority_map[s_entry] = index;
507void CommBridge::ApplyPriorityMaps(std::vector<std::string> new_maps) {
508 wxString new_prio_string;
510 new_prio_string = wxString(new_maps[0].c_str());
511 ApplyPriorityMap(priority_map_position, new_prio_string, 0);
513 new_prio_string = wxString(new_maps[1].c_str());
514 ApplyPriorityMap(priority_map_velocity, new_prio_string, 1);
516 new_prio_string = wxString(new_maps[2].c_str());
517 ApplyPriorityMap(priority_map_heading, new_prio_string, 2);
519 new_prio_string = wxString(new_maps[3].c_str());
520 ApplyPriorityMap(priority_map_variation, new_prio_string, 3);
522 new_prio_string = wxString(new_maps[4].c_str());
523 ApplyPriorityMap(priority_map_satellites, new_prio_string, 4);
526void CommBridge::PresetPriorityContainer(
528 const std::unordered_map<std::string, int>& priority_map) {
532 for (
auto& it : priority_map) {
533 if (it.second == 0) key0 = it.first;
536 wxString this_key(key0.c_str());
537 wxStringTokenizer tkz(this_key, _T(
";"));
538 wxString wxs_this_source = tkz.GetNextToken();
539 std::string source = wxs_this_source.ToStdString();
540 wxString wxs_this_identifier = tkz.GetNextToken();
541 std::string this_identifier = wxs_this_identifier.ToStdString();
543 wxStringTokenizer tka(wxs_this_source, _T(
":"));
545 int source_address = atoi(tka.GetNextToken().ToStdString().c_str());
547 pc.active_priority = 0;
548 pc.active_source = source;
549 pc.active_identifier = this_identifier;
550 pc.active_source_address = source_address;
551 pc.recent_active_time = -1;
554void CommBridge::PresetPriorityContainers() {
555 PresetPriorityContainer(active_priority_position, priority_map_position);
556 PresetPriorityContainer(active_priority_velocity, priority_map_velocity);
557 PresetPriorityContainer(active_priority_heading, priority_map_heading);
558 PresetPriorityContainer(active_priority_variation, priority_map_variation);
559 PresetPriorityContainer(active_priority_satellites, priority_map_satellites);
562bool CommBridge::HandleN2K_129029(std::shared_ptr<const Nmea2000Msg> n2k_msg) {
563 std::vector<unsigned char> v = n2k_msg->payload;
567 unsigned char* c = (
unsigned char*)&pgn;
573 ClearNavData(temp_data);
575 if (!m_decoder.DecodePGN129029(v, temp_data))
return false;
578 if (!N2kIsNA(temp_data.gLat) && !N2kIsNA(temp_data.gLon)) {
579 if (EvalPriority(n2k_msg, active_priority_position,
580 priority_map_position)) {
581 gLat = temp_data.gLat;
582 gLon = temp_data.gLon;
583 valid_flag += POS_UPDATE;
584 valid_flag += POS_VALID;
585 m_watchdogs.position_watchdog = gps_watchdog_timeout_ticks;
586 n_LogWatchdogPeriod = N_ACTIVE_LOG_WATCHDOG;
590 if (temp_data.n_satellites >= 0) {
591 if (EvalPriority(n2k_msg, active_priority_satellites,
592 priority_map_satellites)) {
593 g_SatsInView = temp_data.n_satellites;
595 m_watchdogs.satellite_watchdog = sat_watchdog_timeout_ticks;
599 SendBasicNavdata(valid_flag, m_log_callbacks);
603bool CommBridge::HandleN2K_129025(std::shared_ptr<const Nmea2000Msg> n2k_msg) {
604 std::vector<unsigned char> v = n2k_msg->payload;
607 ClearNavData(temp_data);
609 if (!m_decoder.DecodePGN129025(v, temp_data))
return false;
612 if (!N2kIsNA(temp_data.gLat) && !N2kIsNA(temp_data.gLon)) {
613 if (EvalPriority(n2k_msg, active_priority_position,
614 priority_map_position)) {
615 gLat = temp_data.gLat;
616 gLon = temp_data.gLon;
617 valid_flag += POS_UPDATE;
618 valid_flag += POS_VALID;
619 m_watchdogs.position_watchdog = gps_watchdog_timeout_ticks;
620 n_LogWatchdogPeriod = N_ACTIVE_LOG_WATCHDOG;
627 SendBasicNavdata(valid_flag, m_log_callbacks);
631bool CommBridge::HandleN2K_129026(std::shared_ptr<const Nmea2000Msg> n2k_msg) {
632 std::vector<unsigned char> v = n2k_msg->payload;
635 ClearNavData(temp_data);
637 if (!m_decoder.DecodePGN129026(v, temp_data))
return false;
640 if (!N2kIsNA(temp_data.gSog)) {
641 if (EvalPriority(n2k_msg, active_priority_velocity,
642 priority_map_velocity)) {
643 gSog = MS2KNOTS(temp_data.gSog);
644 valid_flag += SOG_UPDATE;
646 if (N2kIsNA(temp_data.gCog))
649 gCog = GeodesicRadToDeg(temp_data.gCog);
650 valid_flag += COG_UPDATE;
651 m_watchdogs.velocity_watchdog = gps_watchdog_timeout_ticks;
656 SendBasicNavdata(valid_flag, m_log_callbacks);
660bool CommBridge::HandleN2K_127250(std::shared_ptr<const Nmea2000Msg> n2k_msg) {
661 std::vector<unsigned char> v = n2k_msg->payload;
664 ClearNavData(temp_data);
666 if (!m_decoder.DecodePGN127250(v, temp_data))
return false;
669 if (!N2kIsNA(temp_data.gVar)) {
670 if (EvalPriority(n2k_msg, active_priority_variation,
671 priority_map_variation)) {
672 gVar = GeodesicRadToDeg(temp_data.gVar);
673 valid_flag += VAR_UPDATE;
674 m_watchdogs.variation_watchdog = gps_watchdog_timeout_ticks;
678 if (!N2kIsNA(temp_data.gHdt)) {
679 if (EvalPriority(n2k_msg, active_priority_heading, priority_map_heading)) {
680 gHdt = GeodesicRadToDeg(temp_data.gHdt);
681 valid_flag += HDT_UPDATE;
682 m_watchdogs.heading_watchdog = gps_watchdog_timeout_ticks;
686 if (!N2kIsNA(temp_data.gHdm)) {
687 gHdm = GeodesicRadToDeg(temp_data.gHdm);
688 if (EvalPriority(n2k_msg, active_priority_heading, priority_map_heading)) {
690 valid_flag += HDT_UPDATE;
691 if (!std::isnan(gHdt))
692 m_watchdogs.heading_watchdog = gps_watchdog_timeout_ticks;
696 SendBasicNavdata(valid_flag, m_log_callbacks);
700bool CommBridge::HandleN2K_129540(std::shared_ptr<const Nmea2000Msg> n2k_msg) {
701 std::vector<unsigned char> v = n2k_msg->payload;
704 ClearNavData(temp_data);
706 if (!m_decoder.DecodePGN129540(v, temp_data))
return false;
709 if (temp_data.n_satellites >= 0) {
710 if (EvalPriority(n2k_msg, active_priority_satellites,
711 priority_map_satellites)) {
712 g_SatsInView = temp_data.n_satellites;
714 m_watchdogs.satellite_watchdog = sat_watchdog_timeout_ticks;
721bool CommBridge::HandleN0183_RMC(std::shared_ptr<const Nmea0183Msg> n0183_msg) {
722 std::string str = n0183_msg->payload;
725 ClearNavData(temp_data);
728 if (!m_decoder.DecodeRMC(str, temp_data)) bvalid =
false;
730 if (std::isnan(temp_data.gLat) || std::isnan(temp_data.gLon))
return false;
733 if (EvalPriority(n0183_msg, active_priority_position,
734 priority_map_position)) {
736 gLat = temp_data.gLat;
737 gLon = temp_data.gLon;
738 valid_flag += POS_VALID;
739 m_watchdogs.position_watchdog = gps_watchdog_timeout_ticks;
740 n_LogWatchdogPeriod = N_ACTIVE_LOG_WATCHDOG;
742 valid_flag += POS_UPDATE;
745 if (EvalPriority(n0183_msg, active_priority_velocity,
746 priority_map_velocity)) {
748 gSog = temp_data.gSog;
749 valid_flag += SOG_UPDATE;
750 gCog = temp_data.gCog;
751 valid_flag += COG_UPDATE;
752 m_watchdogs.velocity_watchdog = gps_watchdog_timeout_ticks;
756 if (!std::isnan(temp_data.gVar)) {
757 if (EvalPriority(n0183_msg, active_priority_variation,
758 priority_map_variation)) {
760 gVar = temp_data.gVar;
761 valid_flag += VAR_UPDATE;
762 m_watchdogs.variation_watchdog = gps_watchdog_timeout_ticks;
767 SendBasicNavdata(valid_flag, m_log_callbacks);
771bool CommBridge::HandleN0183_HDT(std::shared_ptr<const Nmea0183Msg> n0183_msg) {
772 std::string str = n0183_msg->payload;
774 ClearNavData(temp_data);
776 if (!m_decoder.DecodeHDT(str, temp_data))
return false;
779 if (EvalPriority(n0183_msg, active_priority_heading, priority_map_heading)) {
780 gHdt = temp_data.gHdt;
781 valid_flag += HDT_UPDATE;
782 m_watchdogs.heading_watchdog = gps_watchdog_timeout_ticks;
785 SendBasicNavdata(valid_flag, m_log_callbacks);
789bool CommBridge::HandleN0183_HDG(std::shared_ptr<const Nmea0183Msg> n0183_msg) {
790 std::string str = n0183_msg->payload;
792 ClearNavData(temp_data);
794 if (!m_decoder.DecodeHDG(str, temp_data))
return false;
799 if (EvalPriority(n0183_msg, active_priority_heading, priority_map_heading)) {
800 gHdm = temp_data.gHdm;
801 m_watchdogs.heading_watchdog = gps_watchdog_timeout_ticks;
805 if (!std::isnan(temp_data.gVar)) {
806 if (EvalPriority(n0183_msg, active_priority_variation,
807 priority_map_variation)) {
808 gVar = temp_data.gVar;
809 valid_flag += VAR_UPDATE;
810 m_watchdogs.variation_watchdog = gps_watchdog_timeout_ticks;
814 if (bHDM) MakeHDTFromHDM();
816 SendBasicNavdata(valid_flag, m_log_callbacks);
820bool CommBridge::HandleN0183_HDM(std::shared_ptr<const Nmea0183Msg> n0183_msg) {
821 std::string str = n0183_msg->payload;
823 ClearNavData(temp_data);
825 if (!m_decoder.DecodeHDM(str, temp_data))
return false;
828 if (EvalPriority(n0183_msg, active_priority_heading, priority_map_heading)) {
829 gHdm = temp_data.gHdm;
831 valid_flag += HDT_UPDATE;
832 m_watchdogs.heading_watchdog = gps_watchdog_timeout_ticks;
835 SendBasicNavdata(valid_flag, m_log_callbacks);
839bool CommBridge::HandleN0183_VTG(std::shared_ptr<const Nmea0183Msg> n0183_msg) {
840 std::string str = n0183_msg->payload;
842 ClearNavData(temp_data);
844 if (!m_decoder.DecodeVTG(str, temp_data))
return false;
847 if (EvalPriority(n0183_msg, active_priority_velocity,
848 priority_map_velocity)) {
849 gSog = temp_data.gSog;
850 valid_flag += SOG_UPDATE;
851 gCog = temp_data.gCog;
852 valid_flag += COG_UPDATE;
853 m_watchdogs.velocity_watchdog = gps_watchdog_timeout_ticks;
856 SendBasicNavdata(valid_flag, m_log_callbacks);
860bool CommBridge::HandleN0183_GSV(std::shared_ptr<const Nmea0183Msg> n0183_msg) {
861 std::string str = n0183_msg->payload;
863 ClearNavData(temp_data);
865 if (!m_decoder.DecodeGSV(str, temp_data))
return false;
868 if (EvalPriority(n0183_msg, active_priority_satellites,
869 priority_map_satellites)) {
870 if (temp_data.n_satellites >= 0) {
871 g_SatsInView = temp_data.n_satellites;
874 m_watchdogs.satellite_watchdog = sat_watchdog_timeout_ticks;
878 SendBasicNavdata(valid_flag, m_log_callbacks);
882bool CommBridge::HandleN0183_GGA(std::shared_ptr<const Nmea0183Msg> n0183_msg) {
883 std::string str = n0183_msg->payload;
885 ClearNavData(temp_data);
888 if (!m_decoder.DecodeGGA(str, temp_data)) bvalid =
false;
890 if (std::isnan(temp_data.gLat) || std::isnan(temp_data.gLon))
return false;
893 if (EvalPriority(n0183_msg, active_priority_position,
894 priority_map_position)) {
896 gLat = temp_data.gLat;
897 gLon = temp_data.gLon;
898 valid_flag += POS_VALID;
899 m_watchdogs.position_watchdog = gps_watchdog_timeout_ticks;
900 n_LogWatchdogPeriod = N_ACTIVE_LOG_WATCHDOG;
902 valid_flag += POS_UPDATE;
905 if (EvalPriority(n0183_msg, active_priority_satellites,
906 priority_map_satellites)) {
908 if (temp_data.n_satellites >= 0) {
909 g_SatsInView = temp_data.n_satellites;
912 m_watchdogs.satellite_watchdog = sat_watchdog_timeout_ticks;
917 SendBasicNavdata(valid_flag, m_log_callbacks);
921bool CommBridge::HandleN0183_GLL(std::shared_ptr<const Nmea0183Msg> n0183_msg) {
922 std::string str = n0183_msg->payload;
924 ClearNavData(temp_data);
927 if (!m_decoder.DecodeGLL(str, temp_data)) bvalid =
false;
929 if (std::isnan(temp_data.gLat) || std::isnan(temp_data.gLon))
return false;
932 if (EvalPriority(n0183_msg, active_priority_position,
933 priority_map_position)) {
935 gLat = temp_data.gLat;
936 gLon = temp_data.gLon;
937 valid_flag += POS_VALID;
938 m_watchdogs.position_watchdog = gps_watchdog_timeout_ticks;
939 n_LogWatchdogPeriod = N_ACTIVE_LOG_WATCHDOG;
941 valid_flag += POS_UPDATE;
944 SendBasicNavdata(valid_flag, m_log_callbacks);
949 std::shared_ptr<const Nmea0183Msg> n0183_msg) {
950 std::string str = n0183_msg->payload;
953 wxString sentence(str.c_str());
957 AisError nerr = AIS_GENERIC_ERROR;
958 nerr = DecodeSingleVDO(sentence, &gpd);
960 if (nerr == AIS_NoError) {
961 if (!std::isnan(gpd.
kLat) && !std::isnan(gpd.
kLon)) {
962 if (EvalPriority(n0183_msg, active_priority_position,
963 priority_map_position)) {
966 valid_flag += POS_UPDATE;
967 valid_flag += POS_VALID;
968 m_watchdogs.position_watchdog = gps_watchdog_timeout_ticks;
969 n_LogWatchdogPeriod = N_ACTIVE_LOG_WATCHDOG;
973 if (!std::isnan(gpd.
kCog) && !std::isnan(gpd.
kSog)) {
974 if (EvalPriority(n0183_msg, active_priority_velocity,
975 priority_map_velocity)) {
977 valid_flag += SOG_UPDATE;
979 valid_flag += COG_UPDATE;
980 m_watchdogs.velocity_watchdog = gps_watchdog_timeout_ticks;
984 if (!std::isnan(gpd.
kHdt)) {
985 if (EvalPriority(n0183_msg, active_priority_heading,
986 priority_map_heading)) {
988 valid_flag += HDT_UPDATE;
989 m_watchdogs.heading_watchdog = gps_watchdog_timeout_ticks;
993 SendBasicNavdata(valid_flag, m_log_callbacks);
998bool CommBridge::HandleSignalK(std::shared_ptr<const SignalkMsg> sK_msg) {
999 std::string str = sK_msg->raw_message;
1002 if (sK_msg->context_self != sK_msg->context)
return false;
1004 g_ownshipMMSI_SK = sK_msg->context_self;
1007 ClearNavData(temp_data);
1009 if (!m_decoder.DecodeSignalK(str, temp_data))
return false;
1013 if (!std::isnan(temp_data.gLat) && !std::isnan(temp_data.gLon)) {
1014 if (EvalPriority(sK_msg, active_priority_position, priority_map_position)) {
1015 gLat = temp_data.gLat;
1016 gLon = temp_data.gLon;
1017 valid_flag += POS_UPDATE;
1018 valid_flag += POS_VALID;
1019 m_watchdogs.position_watchdog = gps_watchdog_timeout_ticks;
1020 n_LogWatchdogPeriod = N_ACTIVE_LOG_WATCHDOG;
1024 if (!std::isnan(temp_data.gSog)) {
1025 if (EvalPriority(sK_msg, active_priority_velocity, priority_map_velocity)) {
1026 gSog = temp_data.gSog;
1027 valid_flag += SOG_UPDATE;
1028 if ((gSog > 0.05) && !std::isnan(temp_data.gCog)) {
1029 gCog = temp_data.gCog;
1030 valid_flag += COG_UPDATE;
1032 m_watchdogs.velocity_watchdog = gps_watchdog_timeout_ticks;
1036 if (!std::isnan(temp_data.gHdt)) {
1037 if (EvalPriority(sK_msg, active_priority_heading, priority_map_heading)) {
1038 gHdt = temp_data.gHdt;
1039 valid_flag += HDT_UPDATE;
1040 m_watchdogs.heading_watchdog = gps_watchdog_timeout_ticks;
1044 if (!std::isnan(temp_data.gHdm)) {
1045 if (EvalPriority(sK_msg, active_priority_heading, priority_map_heading)) {
1046 gHdm = temp_data.gHdm;
1048 valid_flag += HDT_UPDATE;
1049 m_watchdogs.heading_watchdog = gps_watchdog_timeout_ticks;
1053 if (!std::isnan(temp_data.gVar)) {
1054 if (EvalPriority(sK_msg, active_priority_variation,
1055 priority_map_variation)) {
1056 gVar = temp_data.gVar;
1057 valid_flag += VAR_UPDATE;
1058 m_watchdogs.variation_watchdog = gps_watchdog_timeout_ticks;
1062 bool sat_update =
false;
1063 if (temp_data.n_satellites > 0) {
1064 if (EvalPriority(sK_msg, active_priority_satellites,
1065 priority_map_satellites)) {
1066 g_SatsInView = temp_data.n_satellites;
1069 m_watchdogs.satellite_watchdog = sat_watchdog_timeout_ticks;
1073 if (g_pMUX && g_pMUX->IsLogActive()) {
1074 std::string logmsg =
"Self: ";
1075 std::string content;
1076 if (valid_flag & POS_UPDATE) content +=
"POS;";
1077 if (valid_flag & POS_VALID) content +=
"POS_Valid;";
1078 if (valid_flag & SOG_UPDATE) content +=
"SOG;";
1079 if (valid_flag & COG_UPDATE) content +=
"COG;";
1080 if (valid_flag & HDT_UPDATE) content +=
"HDT;";
1081 if (valid_flag & VAR_UPDATE) content +=
"VAR;";
1082 if (sat_update) content +=
"SAT;";
1084 if (content.empty()) content =
"Not used by OCPN, maybe passed to plugins";
1090 SendBasicNavdata(valid_flag, m_log_callbacks);
1094void CommBridge::InitializePriorityContainers() {
1095 active_priority_position.active_priority = 0;
1096 active_priority_velocity.active_priority = 0;
1097 active_priority_heading.active_priority = 0;
1098 active_priority_variation.active_priority = 0;
1099 active_priority_satellites.active_priority = 0;
1101 active_priority_position.active_source.clear();
1102 active_priority_velocity.active_source.clear();
1103 active_priority_heading.active_source.clear();
1104 active_priority_variation.active_source.clear();
1105 active_priority_satellites.active_source.clear();
1107 active_priority_position.active_identifier.clear();
1108 active_priority_velocity.active_identifier.clear();
1109 active_priority_heading.active_identifier.clear();
1110 active_priority_variation.active_identifier.clear();
1111 active_priority_satellites.active_identifier.clear();
1113 active_priority_position.pcclass =
"position";
1114 active_priority_velocity.pcclass =
"velocity";
1115 active_priority_heading.pcclass =
"heading";
1116 active_priority_variation.pcclass =
"variation";
1117 active_priority_satellites.pcclass =
"satellites";
1119 active_priority_position.active_source_address = -1;
1120 active_priority_velocity.active_source_address = -1;
1121 active_priority_heading.active_source_address = -1;
1122 active_priority_variation.active_source_address = -1;
1123 active_priority_satellites.active_source_address = -1;
1125 active_priority_void.active_priority = -1;
1128void CommBridge::ClearPriorityMaps() {
1129 priority_map_position.clear();
1130 priority_map_velocity.clear();
1131 priority_map_heading.clear();
1132 priority_map_variation.clear();
1133 priority_map_satellites.clear();
1137 const std::string category) {
1138 if (!category.compare(
"position"))
1139 return active_priority_position;
1140 else if (!category.compare(
"velocity"))
1141 return active_priority_velocity;
1142 else if (!category.compare(
"heading"))
1143 return active_priority_heading;
1144 else if (!category.compare(
"variation"))
1145 return active_priority_variation;
1146 else if (!category.compare(
"satellites"))
1147 return active_priority_satellites;
1149 return active_priority_void;
1152void CommBridge::UpdateAndApplyMaps(std::vector<std::string> new_maps) {
1153 ApplyPriorityMaps(new_maps);
1155 PresetPriorityContainers();
1158bool CommBridge::LoadConfig(
void) {
1159 if (TheBaseConfig()) {
1160 TheBaseConfig()->SetPath(
"/Settings/CommPriority");
1162 std::vector<std::string> new_maps;
1164 wxString pri_string;
1166 TheBaseConfig()->Read(
"PriorityPosition", &pri_string);
1167 s_prio = std::string(pri_string.c_str());
1168 new_maps.push_back(s_prio);
1170 TheBaseConfig()->Read(
"PriorityVelocity", &pri_string);
1171 s_prio = std::string(pri_string.c_str());
1172 new_maps.push_back(s_prio);
1174 TheBaseConfig()->Read(
"PriorityHeading", &pri_string);
1175 s_prio = std::string(pri_string.c_str());
1176 new_maps.push_back(s_prio);
1178 TheBaseConfig()->Read(
"PriorityVariation", &pri_string);
1179 s_prio = std::string(pri_string.c_str());
1180 new_maps.push_back(s_prio);
1182 TheBaseConfig()->Read(
"PrioritySatellites", &pri_string);
1183 s_prio = std::string(pri_string.c_str());
1184 new_maps.push_back(s_prio);
1186 ApplyPriorityMaps(new_maps);
1191bool CommBridge::SaveConfig(
void) {
1192 if (TheBaseConfig()) {
1193 TheBaseConfig()->SetPath(
"/Settings/CommPriority");
1195 wxString pri_string;
1196 pri_string = wxString(GetPriorityMap(priority_map_position).c_str());
1197 TheBaseConfig()->Write(
"PriorityPosition", pri_string);
1199 pri_string = wxString(GetPriorityMap(priority_map_velocity).c_str());
1200 TheBaseConfig()->Write(
"PriorityVelocity", pri_string);
1202 pri_string = wxString(GetPriorityMap(priority_map_heading).c_str());
1203 TheBaseConfig()->Write(
"PriorityHeading", pri_string);
1205 pri_string = wxString(GetPriorityMap(priority_map_variation).c_str());
1206 TheBaseConfig()->Write(
"PriorityVariation", pri_string);
1208 pri_string = wxString(GetPriorityMap(priority_map_satellites).c_str());
1209 TheBaseConfig()->Write(
"PrioritySatellites", pri_string);
1215std::string CommBridge::GetPriorityKey(std::shared_ptr<const NavMsg> msg) {
1216 std::string source = msg->source->to_string();
1217 std::string listener_key = msg->key();
1219 std::string this_identifier;
1220 std::string this_address(
"0");
1221 if (msg->bus == NavAddr::Bus::N0183) {
1222 auto msg_0183 = std::dynamic_pointer_cast<const Nmea0183Msg>(msg);
1224 this_identifier = msg_0183->talker;
1225 this_identifier += msg_0183->type;
1227 }
else if (msg->bus == NavAddr::Bus::N2000) {
1228 auto msg_n2k = std::dynamic_pointer_cast<const Nmea2000Msg>(msg);
1230 this_identifier = msg_n2k->PGN.to_string();
1231 unsigned char n_source = msg_n2k->payload.at(7);
1233 sprintf(ss,
"%d", n_source);
1234 this_address = std::string(ss);
1236 }
else if (msg->bus == NavAddr::Bus::Signalk) {
1237 auto msg_sk = std::dynamic_pointer_cast<const SignalkMsg>(msg);
1240 std::static_pointer_cast<const NavAddrSignalK>(msg->source);
1241 source = addr_sk->to_string();
1242 this_identifier =
"signalK";
1243 this_address = msg->source->iface;
1247 return source +
":" + this_address +
";" + this_identifier;
1250bool CommBridge::EvalPriority(
1252 std::unordered_map<std::string, int>& priority_map) {
1253 std::string this_key = GetPriorityKey(msg);
1254 if (debug_priority) printf(
"This Key: %s\n", this_key.c_str());
1257 wxStringTokenizer tkz(this_key, _T(
";"));
1258 wxString wxs_this_source = tkz.GetNextToken();
1259 std::string source = wxs_this_source.ToStdString();
1260 wxString wxs_this_identifier = tkz.GetNextToken();
1261 std::string this_identifier = wxs_this_identifier.ToStdString();
1263 wxStringTokenizer tka(wxs_this_source, _T(
":"));
1265 int source_address = atoi(tka.GetNextToken().ToStdString().c_str());
1273 if (!strncmp(active_priority.pcclass.c_str(),
"velocity", 8)) {
1274 bool pos_ok =
false;
1275 if (!strcmp(active_priority_position.active_source.c_str(),
1277 if (active_priority_position.recent_active_time != -1) {
1281 if (!pos_ok)
return false;
1287 auto it = priority_map.find(this_key);
1288 if (it == priority_map.end()) {
1290 size_t n = priority_map.size();
1291 priority_map[this_key] = n;
1294 this_priority = priority_map[this_key];
1296 if (debug_priority) {
1297 for (
auto it = priority_map.begin(); it != priority_map.end(); it++)
1298 printf(
" priority_map: %s %d\n", it->first.c_str(),
1304 if (this_priority > active_priority.active_priority) {
1306 printf(
" Drop low priority: %s %d %d \n", source.c_str(),
1307 this_priority, active_priority.active_priority);
1312 if (this_priority < active_priority.active_priority) {
1313 active_priority.active_priority = this_priority;
1314 active_priority.active_source = source;
1315 active_priority.active_identifier = this_identifier;
1316 active_priority.active_source_address = source_address;
1317 wxDateTime now = wxDateTime::Now();
1318 active_priority.recent_active_time = now.GetTicks();
1321 printf(
" Restoring high priority: %s %d\n", source.c_str(),
1329 if (active_priority.active_source.size()) {
1330 if (debug_priority) printf(
"source: %s\n", source.c_str());
1332 printf(
"active_source: %s\n", active_priority.active_source.c_str());
1334 if (source.compare(active_priority.active_source) != 0) {
1337 int lowest_priority = -10;
1338 for (
auto it = priority_map.begin(); it != priority_map.end(); it++) {
1339 if (it->second > lowest_priority) lowest_priority = it->second;
1342 priority_map[this_key] = lowest_priority + 1;
1344 printf(
" Lowering priority A: %s :%d\n", source.c_str(),
1345 priority_map[this_key]);
1353 if (msg->bus == NavAddr::Bus::N0183) {
1354 auto msg_0183 = std::dynamic_pointer_cast<const Nmea0183Msg>(msg);
1356 if (active_priority.active_identifier.size()) {
1358 printf(
"this_identifier: %s\n", this_identifier.c_str());
1360 printf(
"active_priority.active_identifier: %s\n",
1361 active_priority.active_identifier.c_str());
1363 if (this_identifier.compare(active_priority.active_identifier) != 0) {
1366 if (priority_map[this_key] == active_priority.active_priority) {
1367 int lowest_priority = -10;
1368 for (
auto it = priority_map.begin(); it != priority_map.end();
1370 if (it->second > lowest_priority) lowest_priority = it->second;
1373 priority_map[this_key] = lowest_priority + 1;
1375 printf(
" Lowering priority B: %s :%d\n", source.c_str(),
1376 priority_map[this_key]);
1387 else if (msg->bus == NavAddr::Bus::N2000) {
1388 auto msg_n2k = std::dynamic_pointer_cast<const Nmea2000Msg>(msg);
1390 if (active_priority.active_identifier.size()) {
1391 if (this_identifier.compare(active_priority.active_identifier) != 0) {
1394 if (priority_map[this_key] == active_priority.active_priority) {
1395 int lowest_priority = -10;
1396 for (
auto it = priority_map.begin(); it != priority_map.end();
1398 if (it->second > lowest_priority) lowest_priority = it->second;
1401 priority_map[this_key] = lowest_priority + 1;
1403 printf(
" Lowering priority: %s :%d\n", source.c_str(),
1404 priority_map[this_key]);
1414 active_priority.active_source = source;
1415 active_priority.active_identifier = this_identifier;
1416 active_priority.active_source_address = source_address;
1417 wxDateTime now = wxDateTime::Now();
1418 active_priority.recent_active_time = now.GetTicks();
1420 printf(
" Accepting high priority: %s %d\n", source.c_str(), this_priority);
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 IsActive() 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.
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.