34#include <wx/datetime.h>
38#include "o_sound/o_sound.h"
48#include "ais_info_gui.h"
57wxDEFINE_EVENT(EVT_AIS_DEL_TRACK, wxCommandEvent);
59wxDEFINE_EVENT(EVT_AIS_NEW_TRACK, wxCommandEvent);
60wxDEFINE_EVENT(EVT_AIS_TOUCH, wxCommandEvent);
61wxDEFINE_EVENT(EVT_AIS_WP, wxCommandEvent);
62wxDEFINE_EVENT(SOUND_PLAYED_EVTYPE, wxCommandEvent);
66static void onSoundFinished(
void *ptr) {
68 wxCommandEvent ev(SOUND_PLAYED_EVTYPE);
74 NavObj_dB::GetInstance().InsertRoutePoint(pWP);
78 if (gFrame->GetPrimaryCanvas()) {
79 gFrame->GetPrimaryCanvas()->undo->BeforeUndoableAction(
80 Undo_CreateWaypoint, pWP, Undo_HasParent, NULL);
81 gFrame->GetPrimaryCanvas()->undo->AfterUndoableAction(NULL);
82 gFrame->RefreshAllCanvas(
false);
83 gFrame->InvalidateAllGL();
87const static char *
const kDeleteTrackPrompt = _(R
"(
88This AIS target has Persistent Tracking selected by MMSI properties
89A Persistent track recording will therefore be restarted for this target.
91Do you instead want to stop Persistent Tracking for this target?
95 if (wxID_NO == OCPNMessageBox(NULL, kDeleteTrackPrompt, _(
"OpenCPN Info"),
96 wxYES_NO | wxCENTER, 60)) {
97 props->m_bPersistentTrack =
true;
101AisInfoGui::AisInfoGui() {
106 auto palert_target = std::static_pointer_cast<const AisTargetData>(ptr);
107 ShowAisInfo(palert_target);
111 Bind(EVT_AIS_TOUCH, [&](wxCommandEvent ev) { gFrame->TouchAISActive(); });
114 Bind(EVT_AIS_WP, [&](wxCommandEvent ev) {
115 auto pWP =
static_cast<RoutePoint *
>(ev.GetClientData());
116 OnNewAisWaypoint(pWP);
120 Bind(EVT_AIS_NEW_TRACK, [&](wxCommandEvent ev) {
121 auto t =
static_cast<Track *
>(ev.GetClientData());
122 NavObj_dB::GetInstance().InsertTrack(t);
126 Bind(EVT_AIS_DEL_TRACK, [&](wxCommandEvent ev) {
131 Bind(SOUND_PLAYED_EVTYPE,
132 [&](wxCommandEvent ev) { OnSoundFinishedAISAudio(ev); });
135 m_bAIS_Audio_Alert_On =
false;
136 m_bAIS_AlertPlaying =
false;
137 m_alarm_defer_count = -1;
138 m_lastMMSItime = wxDateTime::Now();
141void AisInfoGui::OnSoundFinishedAISAudio(wxCommandEvent &event) {
146 m_AIS_Sound->UnLoad();
148 m_bAIS_AlertPlaying =
false;
151void AisInfoGui::ShowAisInfo(
152 std::shared_ptr<const AisTargetData> palert_target) {
153 if (!palert_target)
return;
155 int audioType = AISAUDIO_NONE;
157 switch (palert_target->Class) {
159 audioType = AISAUDIO_DSC;
162 audioType = AISAUDIO_SART;
165 audioType = AISAUDIO_CPA;
171 int last_alert_MMSI = m_lastMMSI;
172 wxDateTime last_alert_time = m_lastMMSItime;
174 if (palert_target->MMSI != last_alert_MMSI) {
175 wxTimeSpan dt = wxDateTime::Now() - last_alert_time;
176 if (dt.GetSeconds() > 5) {
177 m_alarm_defer_count = -1;
181 m_lastMMSI = palert_target->MMSI;
182 m_lastMMSItime = wxDateTime::Now();
187 if (!g_pais_alert_dialog_active) {
189 if (m_alarm_defer_count < 0) {
190 m_alarm_defer_count = g_AIS_alert_delay;
192 if (m_alarm_defer_count >= 1) {
193 m_alarm_defer_count--;
196 if (m_alarm_defer_count == 0) {
197 bool b_jumpto = (palert_target->Class == AIS_SART) ||
198 (palert_target->Class == AIS_DSC);
199 bool b_createWP = palert_target->Class == AIS_DSC;
200 bool b_ack = palert_target->Class != AIS_DSC;
217 if (!gFrame->IsIconized()) {
219 pAISAlertDialog->Create(palert_target->MMSI, gFrame,
g_pAIS, b_jumpto,
220 b_createWP, b_ack, -1, _(
"AIS Alert"));
222 g_pais_alert_dialog_active = pAISAlertDialog;
224 wxTimeSpan alertLifeTime(0, 1, 0,
226 auto alert_dlg_active =
228 alert_dlg_active->dtAlertExpireTime = wxDateTime::Now() + alertLifeTime;
229 g_Platform->PositionAISAlert(pAISAlertDialog);
231 pAISAlertDialog->Show();
235 m_bAIS_Audio_Alert_On =
true;
243 double tcpa_min = 1e6;
245 const auto ¤t_targets =
g_pAIS->GetTargetList();
246 for (
auto &it : current_targets) {
249 if ((td->Class != AIS_SART) && (td->Class != AIS_DSC)) {
250 if (g_bAIS_CPA_Alert && td->b_active) {
251 if ((AIS_ALERT_SET == td->n_alert_state) && !td->b_in_ack_timeout) {
252 if (td->TCPA < tcpa_min) {
254 palert_target_lowestcpa = td.get();
263 auto alert_dlg_active =
266 g_pAIS->Get_Target_Data_From_MMSI(alert_dlg_active->Get_Dialog_MMSI());
272 if (AIS_NO_ALERT == palert_target->n_alert_state) {
273 if (palert_target_lowestcpa) {
274 palert_target = NULL;
276 m_alarm_defer_count = -1;
281 wxDateTime now = wxDateTime::Now();
282 if (((AIS_ALERT_SET == palert_target->n_alert_state) &&
283 !palert_target->b_in_ack_timeout) ||
284 (palert_target->Class == AIS_SART)) {
285 alert_dlg_active->UpdateText();
287 wxTimeSpan alertLifeTime(0, 1, 0,
289 alert_dlg_active->dtAlertExpireTime = wxDateTime::Now() + alertLifeTime;
292 else if (!palert_target->b_in_ack_timeout &&
293 (now.IsEarlierThan(alert_dlg_active->dtAlertExpireTime))) {
294 alert_dlg_active->UpdateText();
296 alert_dlg_active->Close();
297 m_bAIS_Audio_Alert_On =
false;
298 m_alarm_defer_count = -1;
301 if (
true == palert_target->b_suppress_audio)
302 m_bAIS_Audio_Alert_On =
false;
304 m_bAIS_Audio_Alert_On =
true;
306 alert_dlg_active->Close();
307 m_bAIS_Audio_Alert_On =
false;
308 m_alarm_defer_count = -1;
314 if (!g_bAIS_CPA_Alert_Audio) m_bAIS_Audio_Alert_On =
false;
317 auto alert_dlg_active_audio_check =
319 if (alert_dlg_active_audio_check && alert_dlg_active_audio_check->IsShown()) {
320 if (m_bAIS_Audio_Alert_On) {
322 m_AIS_Sound = o_sound::Factory();
324 if (!AIS_AlertPlaying()) {
325 m_bAIS_AlertPlaying =
true;
329 if (g_bAIS_DSC_Alert_Audio) soundFile = g_DSC_sound_file;
332 if (g_bAIS_SART_Alert_Audio) soundFile = g_SART_sound_file;
336 if (g_bAIS_GCPA_Alert_Audio) soundFile = g_AIS_sound_file;
340 m_AIS_Sound->Load(soundFile, g_iSoundDeviceIndex);
341 if (m_AIS_Sound->IsOk()) {
342 m_AIS_Sound->SetFinishedCallback(onSoundFinished,
this);
343 if (!m_AIS_Sound->Play()) {
346 m_bAIS_AlertPlaying =
false;
351 m_bAIS_AlertPlaying =
false;
359 if (palert_target && (palert_target->Class == AIS_SART)) {
363 gFrame->UpdateAISMOBRoute(palert_target.get());
365 gFrame->ActivateAISMOBRoute(palert_target.get());
ArrayOfMmsiProperties g_MMSI_Props_Array
Global instance.
AisDecoder * g_pAIS
Global instance.
Class AisDecoder and helpers.
AisInfoGui * g_pAISGUI
Global instance.
Global state for AIS decoder.
Class AISTargetAlertDialog and helpers.
Generic Chart canvas base.
Dialog for displaying AIS target alerts.
EventVar new_ais_wp
Notified when new AIS wp is created.
EventVar info_update
Notified when AIS user dialogs should update.
EventVar touch_state
Notified when gFrame->TouchAISActive() should be invoked.
Handles the AIS information GUI and sound alerts.
Process incoming AIS messages.
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.
std::shared_ptr< const void > GetSharedPtr() const
Gets the event's payload data.
Represents a waypoint or mark within the navigation system.
Represents a track, which is a series of connected track points.
Miscellaneous globals primarely used by gui layer, not persisted in configuration file.
MySQL based storage for routes, tracks, etc.
Waypoint or mark abstraction.
Route * pAISMOBRoute
Global instance.
RouteManagerDialog * pRouteManagerDialog
Global instance.
Framework for Undo features.