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"
46#include "model/idents.h"
47#include "model/ocpn_types.h"
48#include "model/own_ship.h"
49#include "model/multiplexer.h"
68wxDEFINE_EVENT(EVT_DRIVER_CHANGE, wxCommandEvent);
72#define N_ACTIVE_LOG_WATCHDOG 300
76bool debug_priority = 0;
94static void SendBasicNavdata(
int vflag) {
95 auto msg = std::make_shared<BasicNavDataMsg>(
96 gLat, gLon, gSog, gCog, gVar, gHdt, vflag, wxDateTime::Now().GetTicks());
97 clock_gettime(CLOCK_MONOTONIC, &msg->set_time);
98 AppMsgBus::GetInstance().
Notify(std::move(msg));
101static inline double GeodesicRadToDeg(
double rads) {
102 return rads * 180.0 / M_PI;
105static inline double MS2KNOTS(
double ms) {
return ms * 1.9438444924406; }
110EVT_TIMER(WATCHDOG_TIMER, CommBridge::OnWatchdogTimer)
115CommBridge::~CommBridge() {}
117bool CommBridge::Initialize() {
118 InitializePriorityContainers();
122 PresetPriorityContainers();
127 m_watchdog_timer.SetOwner(
this, WATCHDOG_TIMER);
128 m_watchdog_timer.Start(1000, wxTIMER_CONTINUOUS);
129 n_LogWatchdogPeriod = 3600;
136 driver_change_listener.
Listen(
137 CommDriverRegistry::GetInstance().evt_driverlist_change.key,
this,
139 Bind(EVT_DRIVER_CHANGE, [&](wxCommandEvent ev) { OnDriverStateChange(); });
144void CommBridge::PresetWatchdogs() {
145 m_watchdogs.position_watchdog =
147 m_watchdogs.velocity_watchdog = 20;
148 m_watchdogs.variation_watchdog = 20;
149 m_watchdogs.heading_watchdog = 20;
150 m_watchdogs.satellite_watchdog = 20;
153void CommBridge::SelectNextLowerPriority(
156 for (
auto it = map.begin(); it != map.end(); it++) {
157 if (it->second > pc.active_priority) {
158 best_prio = wxMin(best_prio, it->second);
162 pc.active_priority = best_prio;
163 pc.active_source.clear();
164 pc.active_identifier.clear();
167void CommBridge::OnWatchdogTimer(wxTimerEvent& event) {
169 m_watchdogs.position_watchdog--;
170 if (m_watchdogs.position_watchdog <= 0) {
171 if (m_watchdogs.position_watchdog % 5 == 0) {
173 auto msg = std::make_shared<GPSWatchdogMsg>(
174 GPSWatchdogMsg::WDSource::position, m_watchdogs.position_watchdog);
175 auto& msgbus = AppMsgBus::GetInstance();
176 msgbus.Notify(std::move(msg));
178 if (m_watchdogs.position_watchdog % n_LogWatchdogPeriod == 0) {
180 logmsg.Printf(_T(
" ***GPS Watchdog timeout at Lat:%g Lon: %g"),
182 wxLogMessage(logmsg);
190 active_priority_position.recent_active_time = -1;
194 SelectNextLowerPriority(priority_map_position, active_priority_position);
198 m_watchdogs.velocity_watchdog--;
199 if (m_watchdogs.velocity_watchdog <= 0) {
202 active_priority_velocity.recent_active_time = -1;
204 if (g_nNMEADebug && (m_watchdogs.velocity_watchdog == 0))
205 wxLogMessage(_T(
" ***Velocity Watchdog timeout..."));
206 if (m_watchdogs.velocity_watchdog % 5 == 0) {
208 auto msg = std::make_shared<GPSWatchdogMsg>(
209 GPSWatchdogMsg::WDSource::velocity, m_watchdogs.velocity_watchdog);
210 auto& msgbus = AppMsgBus::GetInstance();
211 msgbus.Notify(std::move(msg));
215 SelectNextLowerPriority(priority_map_velocity, active_priority_velocity);
219 m_watchdogs.heading_watchdog--;
220 if (m_watchdogs.heading_watchdog <= 0) {
222 active_priority_heading.recent_active_time = -1;
223 if (g_nNMEADebug && (m_watchdogs.heading_watchdog == 0))
224 wxLogMessage(_T(
" ***HDT Watchdog timeout..."));
228 SelectNextLowerPriority(priority_map_heading, active_priority_heading);
232 m_watchdogs.variation_watchdog--;
233 if (m_watchdogs.variation_watchdog <= 0) {
235 active_priority_variation.recent_active_time = -1;
237 if (g_nNMEADebug && (m_watchdogs.variation_watchdog == 0))
238 wxLogMessage(_T(
" ***VAR Watchdog timeout..."));
242 SelectNextLowerPriority(priority_map_variation, active_priority_variation);
246 m_watchdogs.satellite_watchdog--;
247 if (m_watchdogs.satellite_watchdog <= 0) {
251 active_priority_satellites.recent_active_time = -1;
253 if (g_nNMEADebug && (m_watchdogs.satellite_watchdog == 0))
254 wxLogMessage(_T(
" ***SAT Watchdog timeout..."));
258 SelectNextLowerPriority(priority_map_satellites,
259 active_priority_satellites);
263void CommBridge::MakeHDTFromHDM() {
266 if (!std::isnan(gHdm)) {
269 if (std::isnan(gVar) && (g_UserVar != 0.0)) gVar = g_UserVar;
271 if (!std::isnan(gHdt)) {
274 else if (gHdt >= 360)
277 m_watchdogs.heading_watchdog = gps_watchdog_timeout_ticks;
282void CommBridge::InitCommListeners() {
284 auto& msgbus = NavMsgBus::GetInstance();
288 Nmea2000Msg n2k_msg_129029(
static_cast<uint64_t
>(129029));
289 listener_N2K_129029.
Listen(n2k_msg_129029,
this, EVT_N2K_129029);
292 HandleN2K_129029(UnpackEvtPointer<Nmea2000Msg>(ev));
297 Nmea2000Msg n2k_msg_129025(
static_cast<uint64_t
>(129025));
298 listener_N2K_129025.
Listen(n2k_msg_129025,
this, EVT_N2K_129025);
300 HandleN2K_129025(UnpackEvtPointer<Nmea2000Msg>(ev));
305 Nmea2000Msg n2k_msg_129026(
static_cast<uint64_t
>(129026));
306 listener_N2K_129026.
Listen(n2k_msg_129026,
this, EVT_N2K_129026);
308 HandleN2K_129026(UnpackEvtPointer<Nmea2000Msg>(ev));
313 Nmea2000Msg n2k_msg_127250(
static_cast<uint64_t
>(127250));
314 listener_N2K_127250.
Listen(n2k_msg_127250,
this, EVT_N2K_127250);
316 HandleN2K_127250(UnpackEvtPointer<Nmea2000Msg>(ev));
321 Nmea2000Msg n2k_msg_129540(
static_cast<uint64_t
>(129540));
322 listener_N2K_129540.
Listen(n2k_msg_129540,
this, EVT_N2K_129540);
324 HandleN2K_129540(UnpackEvtPointer<Nmea2000Msg>(ev));
330 listener_N0183_RMC.
Listen(n0183_msg_RMC,
this, EVT_N0183_RMC);
333 HandleN0183_RMC(UnpackEvtPointer<Nmea0183Msg>(ev));
338 listener_N0183_HDT.
Listen(n0183_msg_HDT,
this, EVT_N0183_HDT);
341 HandleN0183_HDT(UnpackEvtPointer<Nmea0183Msg>(ev));
346 listener_N0183_HDG.
Listen(n0183_msg_HDG,
this, EVT_N0183_HDG);
349 HandleN0183_HDG(UnpackEvtPointer<Nmea0183Msg>(ev));
354 listener_N0183_HDM.
Listen(n0183_msg_HDM,
this, EVT_N0183_HDM);
357 HandleN0183_HDM(UnpackEvtPointer<Nmea0183Msg>(ev));
362 listener_N0183_VTG.
Listen(n0183_msg_VTG,
this, EVT_N0183_VTG);
365 HandleN0183_VTG(UnpackEvtPointer<Nmea0183Msg>(ev));
370 listener_N0183_GSV.
Listen(n0183_msg_GSV,
this, EVT_N0183_GSV);
373 HandleN0183_GSV(UnpackEvtPointer<Nmea0183Msg>(ev));
378 listener_N0183_GGA.
Listen(n0183_msg_GGA,
this, EVT_N0183_GGA);
381 HandleN0183_GGA(UnpackEvtPointer<Nmea0183Msg>(ev));
386 listener_N0183_GLL.
Listen(n0183_msg_GLL,
this, EVT_N0183_GLL);
389 HandleN0183_GLL(UnpackEvtPointer<Nmea0183Msg>(ev));
394 listener_N0183_AIVDO.
Listen(n0183_msg_AIVDO,
this, EVT_N0183_AIVDO);
397 HandleN0183_AIVDO(UnpackEvtPointer<Nmea0183Msg>(ev));
402 listener_SignalK.
Listen(sk_msg,
this, EVT_SIGNALK);
405 HandleSignalK(UnpackEvtPointer<SignalkMsg>(ev));
409void CommBridge::OnDriverStateChange() {
411 PresetPriorityContainers();
414std::string CommBridge::GetPriorityMap(
415 std::unordered_map<std::string, int>& map) {
416#define MAX_SOURCES 10
417 std::string sa[MAX_SOURCES];
420 for (
auto& it : map) {
421 if ((it.second >= 0) && (it.second < MAX_SOURCES)) sa[it.second] = it.first;
425 for (
int i = 0; i < MAX_SOURCES; i++) {
435std::vector<std::string> CommBridge::GetPriorityMaps() {
436 std::vector<std::string> result;
438 result.push_back(GetPriorityMap(priority_map_position));
439 result.push_back(GetPriorityMap(priority_map_velocity));
440 result.push_back(GetPriorityMap(priority_map_heading));
441 result.push_back(GetPriorityMap(priority_map_variation));
442 result.push_back(GetPriorityMap(priority_map_satellites));
447void CommBridge::ApplyPriorityMap(
448 std::unordered_map<std::string, int>& priority_map, wxString& new_prio,
450 priority_map.clear();
451 wxStringTokenizer tk(new_prio,
"|");
453 while (tk.HasMoreTokens()) {
454 wxString entry = tk.GetNextToken();
455 std::string s_entry(entry.c_str());
456 priority_map[s_entry] = index;
461void CommBridge::ApplyPriorityMaps(std::vector<std::string> new_maps) {
462 wxString new_prio_string;
464 new_prio_string = wxString(new_maps[0].c_str());
465 ApplyPriorityMap(priority_map_position, new_prio_string, 0);
467 new_prio_string = wxString(new_maps[1].c_str());
468 ApplyPriorityMap(priority_map_velocity, new_prio_string, 1);
470 new_prio_string = wxString(new_maps[2].c_str());
471 ApplyPriorityMap(priority_map_heading, new_prio_string, 2);
473 new_prio_string = wxString(new_maps[3].c_str());
474 ApplyPriorityMap(priority_map_variation, new_prio_string, 3);
476 new_prio_string = wxString(new_maps[4].c_str());
477 ApplyPriorityMap(priority_map_satellites, new_prio_string, 4);
480void CommBridge::PresetPriorityContainer(
482 const std::unordered_map<std::string, int>& priority_map) {
486 for (
auto& it : priority_map) {
487 if (it.second == 0) key0 = it.first;
490 wxString this_key(key0.c_str());
491 wxStringTokenizer tkz(this_key, _T(
";"));
492 wxString wxs_this_source = tkz.GetNextToken();
493 std::string source = wxs_this_source.ToStdString();
494 wxString wxs_this_identifier = tkz.GetNextToken();
495 std::string this_identifier = wxs_this_identifier.ToStdString();
497 wxStringTokenizer tka(wxs_this_source, _T(
":"));
499 int source_address = atoi(tka.GetNextToken().ToStdString().c_str());
501 pc.active_priority = 0;
502 pc.active_source = source;
503 pc.active_identifier = this_identifier;
504 pc.active_source_address = source_address;
505 pc.recent_active_time = -1;
508void CommBridge::PresetPriorityContainers() {
509 PresetPriorityContainer(active_priority_position, priority_map_position);
510 PresetPriorityContainer(active_priority_velocity, priority_map_velocity);
511 PresetPriorityContainer(active_priority_heading, priority_map_heading);
512 PresetPriorityContainer(active_priority_variation, priority_map_variation);
513 PresetPriorityContainer(active_priority_satellites, priority_map_satellites);
516bool CommBridge::HandleN2K_129029(std::shared_ptr<const Nmea2000Msg> n2k_msg) {
517 std::vector<unsigned char> v = n2k_msg->payload;
521 unsigned char* c = (
unsigned char*)&pgn;
527 ClearNavData(temp_data);
529 if (!m_decoder.DecodePGN129029(v, temp_data))
return false;
532 if (!N2kIsNA(temp_data.gLat) && !N2kIsNA(temp_data.gLon)) {
533 if (EvalPriority(n2k_msg, active_priority_position,
534 priority_map_position)) {
535 gLat = temp_data.gLat;
536 gLon = temp_data.gLon;
537 valid_flag += POS_UPDATE;
538 valid_flag += POS_VALID;
539 m_watchdogs.position_watchdog = gps_watchdog_timeout_ticks;
540 n_LogWatchdogPeriod = N_ACTIVE_LOG_WATCHDOG;
544 if (temp_data.n_satellites >= 0) {
545 if (EvalPriority(n2k_msg, active_priority_satellites,
546 priority_map_satellites)) {
547 g_SatsInView = temp_data.n_satellites;
549 m_watchdogs.satellite_watchdog = sat_watchdog_timeout_ticks;
553 SendBasicNavdata(valid_flag);
557bool CommBridge::HandleN2K_129025(std::shared_ptr<const Nmea2000Msg> n2k_msg) {
558 std::vector<unsigned char> v = n2k_msg->payload;
561 ClearNavData(temp_data);
563 if (!m_decoder.DecodePGN129025(v, temp_data))
return false;
566 if (!N2kIsNA(temp_data.gLat) && !N2kIsNA(temp_data.gLon)) {
567 if (EvalPriority(n2k_msg, active_priority_position,
568 priority_map_position)) {
569 gLat = temp_data.gLat;
570 gLon = temp_data.gLon;
571 valid_flag += POS_UPDATE;
572 valid_flag += POS_VALID;
573 m_watchdogs.position_watchdog = gps_watchdog_timeout_ticks;
574 n_LogWatchdogPeriod = N_ACTIVE_LOG_WATCHDOG;
581 SendBasicNavdata(valid_flag);
585bool CommBridge::HandleN2K_129026(std::shared_ptr<const Nmea2000Msg> n2k_msg) {
586 std::vector<unsigned char> v = n2k_msg->payload;
589 ClearNavData(temp_data);
591 if (!m_decoder.DecodePGN129026(v, temp_data))
return false;
594 if (!N2kIsNA(temp_data.gSog)) {
595 if (EvalPriority(n2k_msg, active_priority_velocity,
596 priority_map_velocity)) {
597 gSog = MS2KNOTS(temp_data.gSog);
598 valid_flag += SOG_UPDATE;
600 if (N2kIsNA(temp_data.gCog))
603 gCog = GeodesicRadToDeg(temp_data.gCog);
604 valid_flag += COG_UPDATE;
605 m_watchdogs.velocity_watchdog = gps_watchdog_timeout_ticks;
610 SendBasicNavdata(valid_flag);
614bool CommBridge::HandleN2K_127250(std::shared_ptr<const Nmea2000Msg> n2k_msg) {
615 std::vector<unsigned char> v = n2k_msg->payload;
618 ClearNavData(temp_data);
620 if (!m_decoder.DecodePGN127250(v, temp_data))
return false;
623 if (!N2kIsNA(temp_data.gVar)) {
624 if (EvalPriority(n2k_msg, active_priority_variation,
625 priority_map_variation)) {
626 gVar = GeodesicRadToDeg(temp_data.gVar);
627 valid_flag += VAR_UPDATE;
628 m_watchdogs.variation_watchdog = gps_watchdog_timeout_ticks;
632 if (!N2kIsNA(temp_data.gHdt)) {
633 if (EvalPriority(n2k_msg, active_priority_heading, priority_map_heading)) {
634 gHdt = GeodesicRadToDeg(temp_data.gHdt);
635 valid_flag += HDT_UPDATE;
636 m_watchdogs.heading_watchdog = gps_watchdog_timeout_ticks;
640 if (!N2kIsNA(temp_data.gHdm)) {
641 gHdm = GeodesicRadToDeg(temp_data.gHdm);
642 if (EvalPriority(n2k_msg, active_priority_heading, priority_map_heading)) {
644 valid_flag += HDT_UPDATE;
645 if (!std::isnan(gHdt))
646 m_watchdogs.heading_watchdog = gps_watchdog_timeout_ticks;
650 SendBasicNavdata(valid_flag);
654bool CommBridge::HandleN2K_129540(std::shared_ptr<const Nmea2000Msg> n2k_msg) {
655 std::vector<unsigned char> v = n2k_msg->payload;
658 ClearNavData(temp_data);
660 if (!m_decoder.DecodePGN129540(v, temp_data))
return false;
663 if (temp_data.n_satellites >= 0) {
664 if (EvalPriority(n2k_msg, active_priority_satellites,
665 priority_map_satellites)) {
666 g_SatsInView = temp_data.n_satellites;
668 m_watchdogs.satellite_watchdog = sat_watchdog_timeout_ticks;
675bool CommBridge::HandleN0183_RMC(std::shared_ptr<const Nmea0183Msg> n0183_msg) {
676 std::string str = n0183_msg->payload;
679 ClearNavData(temp_data);
682 if (!m_decoder.DecodeRMC(str, temp_data)) bvalid =
false;
684 if (std::isnan(temp_data.gLat) || std::isnan(temp_data.gLon))
return false;
687 if (EvalPriority(n0183_msg, active_priority_position,
688 priority_map_position)) {
690 gLat = temp_data.gLat;
691 gLon = temp_data.gLon;
692 valid_flag += POS_VALID;
693 m_watchdogs.position_watchdog = gps_watchdog_timeout_ticks;
694 n_LogWatchdogPeriod = N_ACTIVE_LOG_WATCHDOG;
696 valid_flag += POS_UPDATE;
699 if (EvalPriority(n0183_msg, active_priority_velocity,
700 priority_map_velocity)) {
702 gSog = temp_data.gSog;
703 valid_flag += SOG_UPDATE;
704 gCog = temp_data.gCog;
705 valid_flag += COG_UPDATE;
706 m_watchdogs.velocity_watchdog = gps_watchdog_timeout_ticks;
710 if (!std::isnan(temp_data.gVar)) {
711 if (EvalPriority(n0183_msg, active_priority_variation,
712 priority_map_variation)) {
714 gVar = temp_data.gVar;
715 valid_flag += VAR_UPDATE;
716 m_watchdogs.variation_watchdog = gps_watchdog_timeout_ticks;
721 SendBasicNavdata(valid_flag);
725bool CommBridge::HandleN0183_HDT(std::shared_ptr<const Nmea0183Msg> n0183_msg) {
726 std::string str = n0183_msg->payload;
728 ClearNavData(temp_data);
730 if (!m_decoder.DecodeHDT(str, temp_data))
return false;
733 if (EvalPriority(n0183_msg, active_priority_heading, priority_map_heading)) {
734 gHdt = temp_data.gHdt;
735 valid_flag += HDT_UPDATE;
736 m_watchdogs.heading_watchdog = gps_watchdog_timeout_ticks;
739 SendBasicNavdata(valid_flag);
743bool CommBridge::HandleN0183_HDG(std::shared_ptr<const Nmea0183Msg> n0183_msg) {
744 std::string str = n0183_msg->payload;
746 ClearNavData(temp_data);
748 if (!m_decoder.DecodeHDG(str, temp_data))
return false;
753 if (EvalPriority(n0183_msg, active_priority_heading, priority_map_heading)) {
754 gHdm = temp_data.gHdm;
755 m_watchdogs.heading_watchdog = gps_watchdog_timeout_ticks;
759 if (!std::isnan(temp_data.gVar)) {
760 if (EvalPriority(n0183_msg, active_priority_variation,
761 priority_map_variation)) {
762 gVar = temp_data.gVar;
763 valid_flag += VAR_UPDATE;
764 m_watchdogs.variation_watchdog = gps_watchdog_timeout_ticks;
768 if (bHDM) MakeHDTFromHDM();
770 SendBasicNavdata(valid_flag);
774bool CommBridge::HandleN0183_HDM(std::shared_ptr<const Nmea0183Msg> n0183_msg) {
775 std::string str = n0183_msg->payload;
777 ClearNavData(temp_data);
779 if (!m_decoder.DecodeHDM(str, temp_data))
return false;
782 if (EvalPriority(n0183_msg, active_priority_heading, priority_map_heading)) {
783 gHdm = temp_data.gHdm;
785 valid_flag += HDT_UPDATE;
786 m_watchdogs.heading_watchdog = gps_watchdog_timeout_ticks;
789 SendBasicNavdata(valid_flag);
793bool CommBridge::HandleN0183_VTG(std::shared_ptr<const Nmea0183Msg> n0183_msg) {
794 std::string str = n0183_msg->payload;
796 ClearNavData(temp_data);
798 if (!m_decoder.DecodeVTG(str, temp_data))
return false;
801 if (EvalPriority(n0183_msg, active_priority_velocity,
802 priority_map_velocity)) {
803 gSog = temp_data.gSog;
804 valid_flag += SOG_UPDATE;
805 gCog = temp_data.gCog;
806 valid_flag += COG_UPDATE;
807 m_watchdogs.velocity_watchdog = gps_watchdog_timeout_ticks;
810 SendBasicNavdata(valid_flag);
814bool CommBridge::HandleN0183_GSV(std::shared_ptr<const Nmea0183Msg> n0183_msg) {
815 std::string str = n0183_msg->payload;
817 ClearNavData(temp_data);
819 if (!m_decoder.DecodeGSV(str, temp_data))
return false;
822 if (EvalPriority(n0183_msg, active_priority_satellites,
823 priority_map_satellites)) {
824 if (temp_data.n_satellites >= 0) {
825 g_SatsInView = temp_data.n_satellites;
828 m_watchdogs.satellite_watchdog = sat_watchdog_timeout_ticks;
832 SendBasicNavdata(valid_flag);
836bool CommBridge::HandleN0183_GGA(std::shared_ptr<const Nmea0183Msg> n0183_msg) {
837 std::string str = n0183_msg->payload;
839 ClearNavData(temp_data);
842 if (!m_decoder.DecodeGGA(str, temp_data)) bvalid =
false;
844 if (std::isnan(temp_data.gLat) || std::isnan(temp_data.gLon))
return false;
847 if (EvalPriority(n0183_msg, active_priority_position,
848 priority_map_position)) {
850 gLat = temp_data.gLat;
851 gLon = temp_data.gLon;
852 valid_flag += POS_VALID;
853 m_watchdogs.position_watchdog = gps_watchdog_timeout_ticks;
854 n_LogWatchdogPeriod = N_ACTIVE_LOG_WATCHDOG;
856 valid_flag += POS_UPDATE;
859 if (EvalPriority(n0183_msg, active_priority_satellites,
860 priority_map_satellites)) {
862 if (temp_data.n_satellites >= 0) {
863 g_SatsInView = temp_data.n_satellites;
866 m_watchdogs.satellite_watchdog = sat_watchdog_timeout_ticks;
871 SendBasicNavdata(valid_flag);
875bool CommBridge::HandleN0183_GLL(std::shared_ptr<const Nmea0183Msg> n0183_msg) {
876 std::string str = n0183_msg->payload;
878 ClearNavData(temp_data);
881 if (!m_decoder.DecodeGLL(str, temp_data)) bvalid =
false;
883 if (std::isnan(temp_data.gLat) || std::isnan(temp_data.gLon))
return false;
886 if (EvalPriority(n0183_msg, active_priority_position,
887 priority_map_position)) {
889 gLat = temp_data.gLat;
890 gLon = temp_data.gLon;
891 valid_flag += POS_VALID;
892 m_watchdogs.position_watchdog = gps_watchdog_timeout_ticks;
893 n_LogWatchdogPeriod = N_ACTIVE_LOG_WATCHDOG;
895 valid_flag += POS_UPDATE;
898 SendBasicNavdata(valid_flag);
902bool CommBridge::HandleN0183_AIVDO(
903 std::shared_ptr<const Nmea0183Msg> n0183_msg) {
904 std::string str = n0183_msg->payload;
907 wxString sentence(str.c_str());
911 AisError nerr = AIS_GENERIC_ERROR;
912 nerr = DecodeSingleVDO(sentence, &gpd);
914 if (nerr == AIS_NoError) {
915 if (!std::isnan(gpd.kLat) && !std::isnan(gpd.kLon)) {
916 if (EvalPriority(n0183_msg, active_priority_position,
917 priority_map_position)) {
920 valid_flag += POS_UPDATE;
921 valid_flag += POS_VALID;
922 m_watchdogs.position_watchdog = gps_watchdog_timeout_ticks;
923 n_LogWatchdogPeriod = N_ACTIVE_LOG_WATCHDOG;
927 if (!std::isnan(gpd.kCog) && !std::isnan(gpd.kSog)) {
928 if (EvalPriority(n0183_msg, active_priority_velocity,
929 priority_map_velocity)) {
931 valid_flag += SOG_UPDATE;
933 valid_flag += COG_UPDATE;
934 m_watchdogs.velocity_watchdog = gps_watchdog_timeout_ticks;
938 if (!std::isnan(gpd.kHdt)) {
939 if (EvalPriority(n0183_msg, active_priority_heading,
940 priority_map_heading)) {
942 valid_flag += HDT_UPDATE;
943 m_watchdogs.heading_watchdog = gps_watchdog_timeout_ticks;
947 SendBasicNavdata(valid_flag);
952bool CommBridge::HandleSignalK(std::shared_ptr<const SignalkMsg> sK_msg) {
953 std::string str = sK_msg->raw_message;
956 if (sK_msg->context_self != sK_msg->context)
return false;
958 g_ownshipMMSI_SK = sK_msg->context_self;
961 ClearNavData(temp_data);
963 if (!m_decoder.DecodeSignalK(str, temp_data))
return false;
967 if (!std::isnan(temp_data.gLat) && !std::isnan(temp_data.gLon)) {
968 if (EvalPriority(sK_msg, active_priority_position, priority_map_position)) {
969 gLat = temp_data.gLat;
970 gLon = temp_data.gLon;
971 valid_flag += POS_UPDATE;
972 valid_flag += POS_VALID;
973 m_watchdogs.position_watchdog = gps_watchdog_timeout_ticks;
974 n_LogWatchdogPeriod = N_ACTIVE_LOG_WATCHDOG;
978 if (!std::isnan(temp_data.gSog)) {
979 if (EvalPriority(sK_msg, active_priority_velocity, priority_map_velocity)) {
980 gSog = temp_data.gSog;
981 valid_flag += SOG_UPDATE;
982 if ((gSog > 0.05) && !std::isnan(temp_data.gCog)) {
983 gCog = temp_data.gCog;
984 valid_flag += COG_UPDATE;
986 m_watchdogs.velocity_watchdog = gps_watchdog_timeout_ticks;
990 if (!std::isnan(temp_data.gHdt)) {
991 if (EvalPriority(sK_msg, active_priority_heading, priority_map_heading)) {
992 gHdt = temp_data.gHdt;
993 valid_flag += HDT_UPDATE;
994 m_watchdogs.heading_watchdog = gps_watchdog_timeout_ticks;
998 if (!std::isnan(temp_data.gHdm)) {
999 if (EvalPriority(sK_msg, active_priority_heading, priority_map_heading)) {
1000 gHdm = temp_data.gHdm;
1002 valid_flag += HDT_UPDATE;
1003 m_watchdogs.heading_watchdog = gps_watchdog_timeout_ticks;
1007 if (!std::isnan(temp_data.gVar)) {
1008 if (EvalPriority(sK_msg, active_priority_variation,
1009 priority_map_variation)) {
1010 gVar = temp_data.gVar;
1011 valid_flag += VAR_UPDATE;
1012 m_watchdogs.variation_watchdog = gps_watchdog_timeout_ticks;
1016 bool sat_update =
false;
1017 if (temp_data.n_satellites > 0) {
1018 if (EvalPriority(sK_msg, active_priority_satellites,
1019 priority_map_satellites)) {
1020 g_SatsInView = temp_data.n_satellites;
1023 m_watchdogs.satellite_watchdog = sat_watchdog_timeout_ticks;
1027 if (g_pMUX && g_pMUX->IsLogActive()) {
1028 std::string logmsg =
"Self: ";
1029 std::string content;
1030 if (valid_flag & POS_UPDATE) content +=
"POS;";
1031 if (valid_flag & POS_VALID) content +=
"POS_Valid;";
1032 if (valid_flag & SOG_UPDATE) content +=
"SOG;";
1033 if (valid_flag & COG_UPDATE) content +=
"COG;";
1034 if (valid_flag & HDT_UPDATE) content +=
"HDT;";
1035 if (valid_flag & VAR_UPDATE) content +=
"VAR;";
1036 if (sat_update) content +=
"SAT;";
1038 if (content.empty()) content =
"Not used by OCPN, maybe passed to plugins";
1041 std::string source = sK_msg->source->to_string();
1045 SendBasicNavdata(valid_flag);
1049void CommBridge::InitializePriorityContainers() {
1050 active_priority_position.active_priority = 0;
1051 active_priority_velocity.active_priority = 0;
1052 active_priority_heading.active_priority = 0;
1053 active_priority_variation.active_priority = 0;
1054 active_priority_satellites.active_priority = 0;
1056 active_priority_position.active_source.clear();
1057 active_priority_velocity.active_source.clear();
1058 active_priority_heading.active_source.clear();
1059 active_priority_variation.active_source.clear();
1060 active_priority_satellites.active_source.clear();
1062 active_priority_position.active_identifier.clear();
1063 active_priority_velocity.active_identifier.clear();
1064 active_priority_heading.active_identifier.clear();
1065 active_priority_variation.active_identifier.clear();
1066 active_priority_satellites.active_identifier.clear();
1068 active_priority_position.pcclass =
"position";
1069 active_priority_velocity.pcclass =
"velocity";
1070 active_priority_heading.pcclass =
"heading";
1071 active_priority_variation.pcclass =
"variation";
1072 active_priority_satellites.pcclass =
"satellites";
1074 active_priority_position.active_source_address = -1;
1075 active_priority_velocity.active_source_address = -1;
1076 active_priority_heading.active_source_address = -1;
1077 active_priority_variation.active_source_address = -1;
1078 active_priority_satellites.active_source_address = -1;
1080 active_priority_void.active_priority = -1;
1083void CommBridge::ClearPriorityMaps() {
1084 priority_map_position.clear();
1085 priority_map_velocity.clear();
1086 priority_map_heading.clear();
1087 priority_map_variation.clear();
1088 priority_map_satellites.clear();
1092 const std::string category) {
1093 if (!category.compare(
"position"))
1094 return active_priority_position;
1095 else if (!category.compare(
"velocity"))
1096 return active_priority_velocity;
1097 else if (!category.compare(
"heading"))
1098 return active_priority_heading;
1099 else if (!category.compare(
"variation"))
1100 return active_priority_variation;
1101 else if (!category.compare(
"satellites"))
1102 return active_priority_satellites;
1104 return active_priority_void;
1107void CommBridge::UpdateAndApplyMaps(std::vector<std::string> new_maps) {
1108 ApplyPriorityMaps(new_maps);
1110 PresetPriorityContainers();
1113bool CommBridge::LoadConfig(
void) {
1114 if (TheBaseConfig()) {
1115 TheBaseConfig()->SetPath(
"/Settings/CommPriority");
1117 std::vector<std::string> new_maps;
1119 wxString pri_string;
1121 TheBaseConfig()->Read(
"PriorityPosition", &pri_string);
1122 s_prio = std::string(pri_string.c_str());
1123 new_maps.push_back(s_prio);
1125 TheBaseConfig()->Read(
"PriorityVelocity", &pri_string);
1126 s_prio = std::string(pri_string.c_str());
1127 new_maps.push_back(s_prio);
1129 TheBaseConfig()->Read(
"PriorityHeading", &pri_string);
1130 s_prio = std::string(pri_string.c_str());
1131 new_maps.push_back(s_prio);
1133 TheBaseConfig()->Read(
"PriorityVariation", &pri_string);
1134 s_prio = std::string(pri_string.c_str());
1135 new_maps.push_back(s_prio);
1137 TheBaseConfig()->Read(
"PrioritySatellites", &pri_string);
1138 s_prio = std::string(pri_string.c_str());
1139 new_maps.push_back(s_prio);
1141 ApplyPriorityMaps(new_maps);
1146bool CommBridge::SaveConfig(
void) {
1147 if (TheBaseConfig()) {
1148 TheBaseConfig()->SetPath(
"/Settings/CommPriority");
1150 wxString pri_string;
1151 pri_string = wxString(GetPriorityMap(priority_map_position).c_str());
1152 TheBaseConfig()->Write(
"PriorityPosition", pri_string);
1154 pri_string = wxString(GetPriorityMap(priority_map_velocity).c_str());
1155 TheBaseConfig()->Write(
"PriorityVelocity", pri_string);
1157 pri_string = wxString(GetPriorityMap(priority_map_heading).c_str());
1158 TheBaseConfig()->Write(
"PriorityHeading", pri_string);
1160 pri_string = wxString(GetPriorityMap(priority_map_variation).c_str());
1161 TheBaseConfig()->Write(
"PriorityVariation", pri_string);
1163 pri_string = wxString(GetPriorityMap(priority_map_satellites).c_str());
1164 TheBaseConfig()->Write(
"PrioritySatellites", pri_string);
1170std::string CommBridge::GetPriorityKey(std::shared_ptr<const NavMsg> msg) {
1171 std::string source = msg->source->to_string();
1172 std::string listener_key = msg->key();
1174 std::string this_identifier;
1175 std::string this_address(
"0");
1176 if (msg->bus == NavAddr::Bus::N0183) {
1177 auto msg_0183 = std::dynamic_pointer_cast<const Nmea0183Msg>(msg);
1179 this_identifier = msg_0183->talker;
1180 this_identifier += msg_0183->type;
1182 }
else if (msg->bus == NavAddr::Bus::N2000) {
1183 auto msg_n2k = std::dynamic_pointer_cast<const Nmea2000Msg>(msg);
1185 this_identifier = msg_n2k->PGN.to_string();
1186 unsigned char n_source = msg_n2k->payload.at(7);
1188 sprintf(ss,
"%d", n_source);
1189 this_address = std::string(ss);
1191 }
else if (msg->bus == NavAddr::Bus::Signalk) {
1192 auto msg_sk = std::dynamic_pointer_cast<const SignalkMsg>(msg);
1195 std::static_pointer_cast<const NavAddrSignalK>(msg->source);
1196 source = addr_sk->to_string();
1197 this_identifier =
"signalK";
1198 this_address = msg->source->iface;
1202 return source +
":" + this_address +
";" + this_identifier;
1205bool CommBridge::EvalPriority(
1207 std::unordered_map<std::string, int>& priority_map) {
1208 std::string this_key = GetPriorityKey(msg);
1209 if (debug_priority) printf(
"This Key: %s\n", this_key.c_str());
1212 wxStringTokenizer tkz(this_key, _T(
";"));
1213 wxString wxs_this_source = tkz.GetNextToken();
1214 std::string source = wxs_this_source.ToStdString();
1215 wxString wxs_this_identifier = tkz.GetNextToken();
1216 std::string this_identifier = wxs_this_identifier.ToStdString();
1218 wxStringTokenizer tka(wxs_this_source, _T(
":"));
1220 int source_address = atoi(tka.GetNextToken().ToStdString().c_str());
1228 if (!strncmp(active_priority.pcclass.c_str(),
"velocity", 8)) {
1229 bool pos_ok =
false;
1230 if (!strcmp(active_priority_position.active_source.c_str(),
1232 if (active_priority_position.recent_active_time != -1) {
1236 if (!pos_ok)
return false;
1242 auto it = priority_map.find(this_key);
1243 if (it == priority_map.end()) {
1245 size_t n = priority_map.size();
1246 priority_map[this_key] = n;
1249 this_priority = priority_map[this_key];
1251 if (debug_priority) {
1252 for (
auto it = priority_map.begin(); it != priority_map.end(); it++)
1253 printf(
" priority_map: %s %d\n", it->first.c_str(),
1259 if (this_priority > active_priority.active_priority) {
1261 printf(
" Drop low priority: %s %d %d \n", source.c_str(),
1262 this_priority, active_priority.active_priority);
1267 if (this_priority < active_priority.active_priority) {
1268 active_priority.active_priority = this_priority;
1269 active_priority.active_source = source;
1270 active_priority.active_identifier = this_identifier;
1271 active_priority.active_source_address = source_address;
1272 wxDateTime now = wxDateTime::Now();
1273 active_priority.recent_active_time = now.GetTicks();
1276 printf(
" Restoring high priority: %s %d\n", source.c_str(),
1284 if (active_priority.active_source.size()) {
1285 if (debug_priority) printf(
"source: %s\n", source.c_str());
1287 printf(
"active_source: %s\n", active_priority.active_source.c_str());
1289 if (source.compare(active_priority.active_source) != 0) {
1292 int lowest_priority = -10;
1293 for (
auto it = priority_map.begin(); it != priority_map.end(); it++) {
1294 if (it->second > lowest_priority) lowest_priority = it->second;
1297 priority_map[this_key] = lowest_priority + 1;
1299 printf(
" Lowering priority A: %s :%d\n", source.c_str(),
1300 priority_map[this_key]);
1308 if (msg->bus == NavAddr::Bus::N0183) {
1309 auto msg_0183 = std::dynamic_pointer_cast<const Nmea0183Msg>(msg);
1311 if (active_priority.active_identifier.size()) {
1313 printf(
"this_identifier: %s\n", this_identifier.c_str());
1315 printf(
"active_priority.active_identifier: %s\n",
1316 active_priority.active_identifier.c_str());
1318 if (this_identifier.compare(active_priority.active_identifier) != 0) {
1321 if (priority_map[this_key] == active_priority.active_priority) {
1322 int lowest_priority = -10;
1323 for (
auto it = priority_map.begin(); it != priority_map.end();
1325 if (it->second > lowest_priority) lowest_priority = it->second;
1328 priority_map[this_key] = lowest_priority + 1;
1330 printf(
" Lowering priority B: %s :%d\n", source.c_str(),
1331 priority_map[this_key]);
1342 else if (msg->bus == NavAddr::Bus::N2000) {
1343 auto msg_n2k = std::dynamic_pointer_cast<const Nmea2000Msg>(msg);
1345 if (active_priority.active_identifier.size()) {
1346 if (this_identifier.compare(active_priority.active_identifier) != 0) {
1349 if (priority_map[this_key] == active_priority.active_priority) {
1350 int lowest_priority = -10;
1351 for (
auto it = priority_map.begin(); it != priority_map.end();
1353 if (it->second > lowest_priority) lowest_priority = it->second;
1356 priority_map[this_key] = lowest_priority + 1;
1358 printf(
" Lowering priority: %s :%d\n", source.c_str(),
1359 priority_map[this_key]);
1369 active_priority.active_source = source;
1370 active_priority.active_identifier = this_identifier;
1371 active_priority.active_source_address = source_address;
1372 wxDateTime now = wxDateTime::Now();
1373 active_priority.recent_active_time = now.GetTicks();
1375 printf(
" Accepting high priority: %s %d\n", source.c_str(), this_priority);
void Notify(std::shared_ptr< const AppMsg > msg)
Send message to everyone listening to given message type.
void LogInputMessage(const wxString &msg, const wxString &stream_name, bool b_filter, bool b_error=false, const wxString error_msg=wxEmptyString)
Logs an input message with context information.
A regular Nmea0183 message.
See: https://github.com/OpenCPN/OpenCPN/issues/2729#issuecomment-1179506343.
void Listen(const std::string &key, wxEvtHandler *listener, wxEventType evt)
Set object to send wxEventType ev to listener on changes in key.
Adds a std::shared<void> element to wxCommandEvent.
A parsed SignalK message over ipv4.
Driver registration container, a singleton.
Raw messages layer, supports sending and recieving navmsg messages.