OpenCPN Partial API docs
Loading...
Searching...
No Matches
wmm_pi.cpp
Go to the documentation of this file.
1/**************************************************************************
2 * Copyright (C) 2011-2019 by Pavel Kalian *
3 * *
4 * This program is free software; you can redistribute it and/or modify *
5 * it under the terms of the GNU General Public License as published by *
6 * the Free Software Foundation; either version 2 of the License, or *
7 * (at your option) any later version. *
8 * *
9 * This program is distributed in the hope that it will be useful, *
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of *
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
12 * GNU General Public License for more details. *
13 * *
14 * You should have received a copy of the GNU General Public License *
15 * along with this program; if not, see <https://www.gnu.org/licenses/>. *
16 **************************************************************************/
17
24#include "wmm_pi.h"
25
26#include <wx/wxprec.h>
27
28#ifndef WX_PRECOMP
29#include <wx/wx.h>
30#endif // precompiled headers
31
32#ifndef __ANDROID__
33#include <GL/gl.h>
34#include <GL/glu.h>
35#else
36#include "qopengl.h" // this gives us the qt runtime gles2.h
37#include "GL/gl_private.h"
38#include "qdebug.h"
39#endif
40
41#include "version.h"
42
43float g_piGLMinSymbolLineWidth = 0.9;
44
45void WMMLogMessage1(wxString s) { wxLogMessage("WMM: " + s); }
46extern "C" void WMMLogMessage(const char *s) {
47 WMMLogMessage1(wxString::FromAscii(s));
48}
49
50// the class factories, used to create and destroy instances of the PlugIn
51
52extern "C" DECL_EXP opencpn_plugin *create_pi(void *ppimgr) {
53 return new WmmPi(ppimgr);
54}
55
56extern "C" DECL_EXP void destroy_pi(opencpn_plugin *p) { delete p; }
57
58WmmPi *g_pi;
59
60bool g_compact;
61
62//---------------------------------------------------------------------------------------------------------
63//
64// WMM PlugIn Implementation
65//
66//---------------------------------------------------------------------------------------------------------
67
68#include "icons.h"
69#include <N2kMsg.h>
70#include <N2kTypes.h>
71#include <N2kMessages.h>
72
73void WmmUIDialog::EnablePlotChanged(wxCommandEvent &event) {
74 if (m_cbEnablePlot->GetValue()) m_wmm_pi.RecomputePlot();
75 m_wmm_pi.SetShowPlot(m_cbEnablePlot->GetValue());
76 RequestRefresh(m_wmm_pi.m_parent_window);
77}
78
79void WmmUIDialog::PlotSettings(wxCommandEvent &event) {
80 m_wmm_pi.ShowPlotSettings();
81}
82
83void WmmPlotSettingsDialog::About(wxCommandEvent &event) {
84 wxString msg0(
85 _("\n\
86World Magnetic Model Plotting allows users to cross reference the\
87 magnetic variation values printed on many raster charts.\n\n\
88Variation is the angle between true and magnetic north.\n\
89Inclination or dip, is the vertical angle of the magnetic field.\n\
90\t(+- 90 at the magnetic poles)\n\
91Field Strength is the magnetic field in nano tesla from\n\
92\t20000 to 66000\n\n\
93The plotted lines are similar to a topographic map. The \
94space between them can be adjusted; more space takes \
95less time to calculate.\n\n\
96The Step size and Pole accuracy sliders allow a trade off \
97for speed vs computation time.\n\n\
98The World Magnetic Model Plugin was written by Pavel Kalian \
99and extended by Sean D'Epagnier to support plotting."));
100
101 wxMessageDialog dlg(this, msg0, _("WMM Plugin"), wxOK);
102
103 dlg.ShowModal();
104}
105
106//---------------------------------------------------------------------------------------------------------
107//
108// PlugIn initialization and de-init
109//
110//---------------------------------------------------------------------------------------------------------
111
112WmmPi::WmmPi(void *ppimgr)
113 : opencpn_plugin_118(ppimgr),
114 m_bShowPlot(false),
115 m_DeclinationMap(DECLINATION_PLOT, MagneticModel, TimedMagneticModel,
116 &Ellip),
117 m_InclinationMap(INCLINATION_PLOT, MagneticModel, TimedMagneticModel,
118 &Ellip),
119 m_FieldStrengthMap(FIELD_STRENGTH_PLOT, MagneticModel, TimedMagneticModel,
120 &Ellip),
121 m_bComputingPlot(false) {
122 // Create the PlugIn icons
123 initialize_images();
124
125 g_pi = this;
126}
127
128int WmmPi::Init(void) {
129 AddLocaleCatalog(PLUGIN_CATALOG_NAME);
130
131 // Set some default private member parameters
132 m_wmm_dialog_x = 0;
133 m_wmm_dialog_y = 0;
134
135 MagneticModel = NULL;
136 TimedMagneticModel = NULL;
137
138 ::wxDisplaySize(&m_display_width, &m_display_height);
139
140 // Get a pointer to the opencpn display canvas, to use as a parent for the
141 // POI Manager dialog
142 m_parent_window = GetOCPNCanvasWindow();
143
144 // Get a pointer to the opencpn configuration object
145 m_pconfig = GetOCPNConfigObject();
146
147 // And load the configuration items
148 LoadConfig();
149
150#ifdef __ANDROID__
151 g_compact = true;
152 m_bShowPlotOptions = false;
153 m_iViewType = 1;
154#endif
155
156 m_buseable = true;
157
158 m_LastVal = wxEmptyString;
159
160 // pFontSmall = new wxFont( 10, wxFONTFAMILY_SWISS, wxFONTSTYLE_NORMAL,
161 // wxFONTWEIGHT_BOLD );
162 pFontSmall = OCPNGetFont(_("WMM_Live_Overlay"));
163
164 m_shareLocn = *GetpSharedDataLocation() + "plugins" +
165 wxFileName::GetPathSeparator() + "wmm_pi" +
166 wxFileName::GetPathSeparator() + "data" +
167 wxFileName::GetPathSeparator();
168
169 // WMM initialization
170
171 /* Memory allocation */
172 int NumTerms, epochs = 1, nMax = 0;
173 wxString cof_filename = m_shareLocn + "WMM.COF";
174
175 if (!MAG_robustReadMagModels(
176 const_cast<char *>((const char *)cof_filename.mb_str()),
177 (MAGtype_MagneticModel * (*)[]) & MagneticModels[0], 1)) {
178 WMMLogMessage1("initialization error");
179 m_buseable = false;
180 } else {
181 WMMLogMessage1(wxString::Format("WMM model data loaded from file %s.",
182 cof_filename.c_str()));
183 for (int i = 0; i < epochs; i++) {
184 if (MagneticModels[i]->nMax > nMax) {
185 nMax = MagneticModels[i]->nMax;
186 }
187 }
188 NumTerms = ((nMax + 1) * (nMax + 2) / 2);
189
190 TimedMagneticModel = MAG_AllocateModelMemory(
191 NumTerms); /* For storing the time modified WMM Model parameters */
192
193 for (int i = 0; i < epochs; i++) {
194 if (MagneticModels[i] == NULL || TimedMagneticModel == NULL) {
195 WMMLogMessage1("initialization error MAG_Error(2)");
196 m_buseable = false;
197 }
198 }
199
200 MagneticModel = MagneticModels[0];
201
202 MAG_SetDefaults(&Ellip, &Geoid); /* Set default values and constants */
203 /* Check for Geographic Poles */
204
205 /* Set EGM96 Geoid parameters */
206 Geoid.GeoidHeightBuffer = GeoidHeightBuffer;
207 Geoid.Geoid_Initialized = 1;
208 /* Set EGM96 Geoid parameters END */
209 }
210
211 bool found_handle = false;
212 for (const auto &handle : GetActiveDrivers()) {
213 const auto &attributes = GetAttributes(handle);
214 if (attributes.find("protocol") == attributes.end()) continue;
215 WMMLogMessage1(
216 wxString::Format("handle proto %s", attributes.at("protocol")));
217 if (attributes.at("protocol") == "nmea2000") {
218 m_handleN2k = handle;
219 found_handle = true;
220 break;
221 }
222 }
223 if (!found_handle) {
224 WMMLogMessage1("nmea2000 handle not found");
225 }
226 std::vector<int> pgn_list = {127258};
227 CommDriverResult xx = RegisterTXPGNs(m_handleN2k, pgn_list);
228
229 int ret_flag =
230 (WANTS_OVERLAY_CALLBACK | WANTS_OPENGL_OVERLAY_CALLBACK |
233
234 if (m_bShowIcon) {
235 // This PlugIn needs a toolbar icon, so request its insertion
236 m_leftclick_tool_id =
237 InsertPlugInTool("", _img_wmm, _img_wmm, wxITEM_NORMAL, _("WMM"), "",
238 NULL, WMM_TOOL_POSITION, 0, this);
239
240 SetIconType(); // SVGs allowed if not showing live icon
241
242 ret_flag |= INSTALLS_TOOLBAR_TOOL;
243 }
244
245 m_pWmmDialog = NULL;
246 m_oDC = NULL;
247
248 return ret_flag;
249}
250
251bool WmmPi::DeInit(void) {
252 // Record the dialog position
253 if (NULL != m_pWmmDialog) {
254 wxPoint p = m_pWmmDialog->GetPosition();
255 SetWmmDialogX(p.x);
256 SetWmmDialogY(p.y);
257
258 m_pWmmDialog->Close();
259 delete m_pWmmDialog;
260 m_pWmmDialog = NULL;
261 }
262 SaveConfig();
263 if (MagneticModel) {
264 MAG_FreeMagneticModelMemory(MagneticModel);
265 }
266 if (TimedMagneticModel) {
267 MAG_FreeMagneticModelMemory(TimedMagneticModel);
268 }
269
270 RemovePlugInTool(m_leftclick_tool_id);
271
272 /*if (Geoid.GeoidHeightBuffer)
273 {
274 free(Geoid.GeoidHeightBuffer);
275 Geoid.GeoidHeightBuffer = NULL;
276 }*/
277
278 // delete pFontSmall;
279
280 if (m_oDC) delete m_oDC;
281
282 return true;
283}
284
285int WmmPi::GetAPIVersionMajor() { return MY_API_VERSION_MAJOR; }
286
287int WmmPi::GetAPIVersionMinor() { return MY_API_VERSION_MINOR; }
288
289int WmmPi::GetPlugInVersionMajor() { return PLUGIN_VERSION_MAJOR; }
290
291int WmmPi::GetPlugInVersionMinor() { return PLUGIN_VERSION_MINOR; }
292
293wxBitmap *WmmPi::GetPlugInBitmap() { return _img_wmm_pi; }
294
295wxString WmmPi::GetCommonName() { return _("WMM"); }
296
298 return _("World Magnetic Model PlugIn for OpenCPN");
299}
300
302 return _(
303 "World Magnetic Model PlugIn for OpenCPN\n\
304Implements the NOAA World Magnetic Model\n\
305More information:\n\
306https://www.ngdc.noaa.gov/geomag/WMM/DoDWMM.shtml\n\
307The bundled WMM2025 model is valid until late 2029.\n\
308After then, if new version of the plugin will not be released\n\
309in time, get a new WMM.COF from NOAA and place it to the\n\
310location you can find in the OpenCPN logfile.");
311}
312
313int WmmPi::GetToolbarToolCount(void) { return 1; }
314
316 if (NULL == m_pWmmDialog) return;
317 DimeWindow(m_pWmmDialog);
318}
319
320void WmmPi::SetIconType() {
321 if (m_bShowLiveIcon) {
322 SetToolbarToolBitmaps(m_leftclick_tool_id, _img_wmm, _img_wmm);
323 SetToolbarToolBitmapsSVG(m_leftclick_tool_id, "", "", "");
324 m_LastVal.Empty();
325 } else {
326 wxString normalIcon = m_shareLocn + "wmm_pi.svg";
327 wxString toggledIcon = m_shareLocn + "wmm_pi.svg";
328 wxString rolloverIcon = m_shareLocn + "wmm_pi.svg";
329
330 SetToolbarToolBitmapsSVG(m_leftclick_tool_id, normalIcon, rolloverIcon,
331 toggledIcon);
332 }
333}
334
335void WmmPi::RearrangeWindow() {
336 if (NULL == m_pWmmDialog) return;
337 if (m_iViewType == 1) {
338 m_pWmmDialog->sbScursor->Hide(m_pWmmDialog->gScursor, true);
339 m_pWmmDialog->sbSboat->Hide(m_pWmmDialog->gSboat, true);
340 } else {
341 m_pWmmDialog->sbScursor->Show(m_pWmmDialog->gScursor, true, true);
342 m_pWmmDialog->sbSboat->Show(m_pWmmDialog->gSboat, true, true);
343 }
344
345 m_pWmmDialog->m_cbEnablePlot->Show(m_bShowPlotOptions);
346 m_pWmmDialog->m_bPlotSettings->Show(m_bShowPlotOptions);
347
348 if (!m_bShowAtCursor) {
349 m_pWmmDialog->bSframe->Hide(m_pWmmDialog->sbScursor, true);
350 } else {
351 m_pWmmDialog->bSframe->Show(m_pWmmDialog->sbScursor, true, true);
352 if (m_iViewType == 1)
353 m_pWmmDialog->sbScursor->Hide(m_pWmmDialog->gScursor, true);
354 }
355
357
358 m_pWmmDialog->Fit();
359
360#ifdef __WXMSW__
361 // UGLY!!!!!!! On Windows XP the transparent window is not refreshed properly
362 // in OpenGL mode at least on the Atom powered netbooks, so we have to disable
363 // transparency.
364 wxFileConfig *pConf = (wxFileConfig *)m_pconfig;
365 bool gl = true;
366 if (pConf) {
367 pConf->SetPath("/Settings");
368 pConf->Read("OpenGL", &gl, false);
369 pConf = NULL;
370 }
371 if (!(gl && wxPlatformInfo::Get().GetOSMajorVersion() == 5 &&
372 wxPlatformInfo::Get().GetOSMinorVersion() == 1))
373#endif
374 if (m_pWmmDialog->CanSetTransparent())
375 m_pWmmDialog->SetTransparent(m_iOpacity);
376}
377
379 if (!m_buseable) return;
380 if (NULL == m_pWmmDialog) {
381 m_pWmmDialog = new WmmUIDialog(*this, m_parent_window);
382 wxFont *pFont = OCPNGetFont(_("Dialog"));
383 m_pWmmDialog->SetFont(*pFont);
384
385 m_pWmmDialog->Move(wxPoint(m_wmm_dialog_x, m_wmm_dialog_y));
386 }
387
388 RearrangeWindow();
389 /*m_pWmmDialog->SetMaxSize(m_pWmmDialog->GetSize());
390 m_pWmmDialog->SetMinSize(m_pWmmDialog->GetSize());*/
391 m_pWmmDialog->Show(!m_pWmmDialog->IsShown());
392 m_pWmmDialog->Layout(); // Some platforms need a re-Layout at this point
393 // (gtk, at least)
394 if (m_pWmmDialog->IsShown())
395 SendPluginMessage("WMM_WINDOW_SHOWN", wxEmptyString);
396 else
397 SendPluginMessage("WMM_WINDOW_HIDDEN", wxEmptyString);
398
399 wxPoint p = m_pWmmDialog->GetPosition();
400 m_pWmmDialog->Move(0, 0); // workaround for gtk autocentre dialog behavior
401 m_pWmmDialog->Move(p);
402
403#ifdef __ANDROID__
404 m_pWmmDialog->CentreOnScreen();
405 m_pWmmDialog->Move(-1, 0);
406#endif
407}
408
409void WmmPi::RenderOverlayBoth(pi_ocpnDC *dc, PlugIn_ViewPort *vp) {
410 if (!m_bShowPlot) return;
411
412 m_DeclinationMap.Plot(dc, vp, wxColour(255, 0, 90, 220));
413 m_InclinationMap.Plot(dc, vp, wxColour(60, 255, 30, 220));
414 m_FieldStrengthMap.Plot(dc, vp, wxColour(0, 60, 255, 220));
415}
416
417bool WmmPi::RenderOverlay(wxDC &dc, PlugIn_ViewPort *vp) {
418 if (!m_bShowPlot) return true;
419
420 if (!m_oDC) m_oDC = new pi_ocpnDC();
421
422 m_oDC->SetVP(vp);
423 m_oDC->SetDC(&dc);
424
425 RenderOverlayBoth(m_oDC, vp);
426
427 return true;
428}
429
430bool WmmPi::RenderGLOverlay(wxGLContext *pcontext, PlugIn_ViewPort *vp) {
431 if (!m_bShowPlot) return true;
432
433 if (!m_oDC) {
434#ifdef ocpnUSE_GL
435 // Set the minimum line width
436 GLint parms[2];
437#ifndef USE_ANDROID_GLES2
438 glGetIntegerv(GL_SMOOTH_LINE_WIDTH_RANGE, &parms[0]);
439#else
440 glGetIntegerv(GL_ALIASED_LINE_WIDTH_RANGE, &parms[0]);
441#endif
442 g_piGLMinSymbolLineWidth = wxMax(parms[0], 1);
443#endif
444 m_oDC = new pi_ocpnDC();
445 }
446
447 m_oDC->SetVP(vp);
448 m_oDC->SetDC(NULL);
449
450#ifndef USE_ANDROID_GLES2
451 glPushAttrib(GL_COLOR_BUFFER_BIT | GL_LINE_BIT | GL_ENABLE_BIT |
452 GL_POLYGON_BIT | GL_HINT_BIT);
453
454 glEnable(GL_LINE_SMOOTH);
455 glEnable(GL_BLEND);
456 glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
457 glHint(GL_LINE_SMOOTH_HINT, GL_NICEST);
458#endif
459
460 RenderOverlayBoth(m_oDC, vp);
461
462#ifndef USE_ANDROID_GLES2
463 glPopAttrib();
464#endif
465
466 return true;
467}
468
469void WmmPi::RecomputePlot() {
470 if (m_bCachedPlotOk) return;
471
472 if (m_bComputingPlot) return;
473 m_bComputingPlot = true;
474
475 if (!m_DeclinationMap.Recompute(m_MapDate) ||
476 !m_InclinationMap.Recompute(m_MapDate) ||
477 !m_FieldStrengthMap.Recompute(m_MapDate)) {
478 m_bShowPlot = false;
479 if (m_pWmmDialog) m_pWmmDialog->m_cbEnablePlot->SetValue(false);
480 } else
481 m_bCachedPlotOk = true;
482
483 m_bComputingPlot = false;
484}
485
486void WmmPi::SetCursorLatLon(double lat, double lon) {
487 if (!m_pWmmDialog) return;
488
489 if (!m_bShowAtCursor)
490 return; // We don't want to waste CPU cycles that much...
491 if (lat < -90 || lat > 90 || lon < -180 || lon > 180 ||
492 NULL == m_pWmmDialog || !m_pWmmDialog->IsShown())
493 return;
494 if (!m_buseable) {
495 m_pWmmDialog->m_tbD->SetValue(_("Error, see log."));
496 return;
497 }
498 CoordGeodetic.lambda = lon;
499 CoordGeodetic.phi = lat;
500 CoordGeodetic.HeightAboveEllipsoid = 0;
501 CoordGeodetic.HeightAboveGeoid = 0;
502 CoordGeodetic.UseGeoid = 0;
503 UserDate.Year = wxDateTime::GetCurrentYear();
504 UserDate.Month =
505 wxDateTime::GetCurrentMonth() + 1; // WHY is it 0 based????????
506 UserDate.Day = wxDateTime::Now().GetDay();
507 char err[255];
508 MAG_DateToYear(&UserDate, err);
509 MAG_GeodeticToSpherical(
510 Ellip, CoordGeodetic,
511 &CoordSpherical); /*Convert from geodeitic to Spherical Equations: 17-18,
512 WMM Technical report*/
513 MAG_TimelyModifyMagneticModel(
514 UserDate, MagneticModel,
515 TimedMagneticModel); /* Time adjust the coefficients, Equation 19, WMM
516 Technical report */
517 MAG_Geomag(Ellip, CoordSpherical, CoordGeodetic, TimedMagneticModel,
518 &GeoMagneticElements); /* Computes the geoMagnetic field elements
519 and their time change*/
520 MAG_CalculateGridVariation(CoordGeodetic, &GeoMagneticElements);
521 // WMM_PrintUserData(GeoMagneticElements,CoordGeodetic, UserDate,
522 // TimedMagneticModel, &Geoid); /* Print the results */
523 m_pWmmDialog->m_tcF->SetValue(
524 wxString::Format("%-9.1lf nT", GeoMagneticElements.F));
525 m_pWmmDialog->m_tcH->SetValue(
526 wxString::Format("%-9.1lf nT", GeoMagneticElements.H));
527 m_pWmmDialog->m_tcX->SetValue(
528 wxString::Format("%-9.1lf nT", GeoMagneticElements.X));
529 m_pWmmDialog->m_tcY->SetValue(
530 wxString::Format("%-9.1lf nT", GeoMagneticElements.Y));
531 m_pWmmDialog->m_tcZ->SetValue(
532 wxString::Format("%-9.1lf nT", GeoMagneticElements.Z));
533 m_pWmmDialog->m_tcD->SetValue(
534 wxString::Format("%-5.1lf%c (%s)", GeoMagneticElements.Decl, 0x00B0,
535 AngleToText(GeoMagneticElements.Decl).c_str()));
536 m_pWmmDialog->m_tcI->SetValue(
537 wxString::Format("%-5.1lf%c", GeoMagneticElements.Incl, 0x00B0));
538
539 m_cursorVariation = GeoMagneticElements;
540 SendCursorVariation();
541}
542
544 if (!m_buseable) {
545 return;
546 }
547 CoordGeodetic.lambda = pfix.Lon;
548 CoordGeodetic.phi = pfix.Lat;
549 CoordGeodetic.HeightAboveEllipsoid = 0;
550 CoordGeodetic.UseGeoid = 0;
551 UserDate.Year = wxDateTime::GetCurrentYear();
552 UserDate.Month =
553 wxDateTime::GetCurrentMonth() + 1; // WHY is it 0 based????????
554 UserDate.Day = wxDateTime::Now().GetDay();
555 char err[255];
556 MAG_DateToYear(&UserDate, err);
557 MAG_GeodeticToSpherical(
558 Ellip, CoordGeodetic,
559 &CoordSpherical); /*Convert from geodeitic to Spherical Equations: 17-18,
560 WMM Technical report*/
561 MAG_TimelyModifyMagneticModel(
562 UserDate, MagneticModel,
563 TimedMagneticModel); /* Time adjust the coefficients, Equation 19, WMM
564 Technical report */
565 MAG_Geomag(Ellip, CoordSpherical, CoordGeodetic, TimedMagneticModel,
566 &GeoMagneticElements); /* Computes the geoMagnetic field elements
567 and their time change*/
568 MAG_CalculateGridVariation(CoordGeodetic, &GeoMagneticElements);
569 // WMM_PrintUserData(GeoMagneticElements,CoordGeodetic, UserDate,
570 // TimedMagneticModel, &Geoid); /* Print the results */
571
572 m_boatVariation = GeoMagneticElements;
573 SendBoatVariation();
574
575 wxString NewVal = wxString::Format("%.1f", GeoMagneticElements.Decl);
577 scale = wxRound(scale * 4.0) / 4.0;
579
580 // scale =
581 // wxMax(1.0, scale); // Let the upstream processing handle minification.
582
583 if (m_bShowIcon && m_bShowLiveIcon &&
584 ((m_LastVal != NewVal) || (scale != m_scale))) {
585 m_scale = scale;
586 m_LastVal = NewVal;
587 int w = _img_wmm_live->GetWidth() * scale;
588 int h = _img_wmm_live->GetHeight() * scale;
589 wxMemoryDC dc;
590 wxBitmap icon;
591
592 // Is SVG available?
593 wxBitmap live = GetBitmapFromSVGFile(m_shareLocn + "wmm_live.svg", w, h);
594 if (!live.IsOk()) {
595 icon = wxBitmap(_img_wmm_live->GetWidth(), _img_wmm_live->GetHeight());
596 dc.SelectObject(icon);
597 dc.DrawBitmap(*_img_wmm_live, 0, 0, true);
598 } else {
599 icon = wxBitmap(w, h);
600 dc.SelectObject(icon);
601 wxColour col;
602 dc.SetBackground(*wxTRANSPARENT_BRUSH);
603 dc.Clear();
604
605 dc.DrawBitmap(live, 0, 0, true);
606 }
607
608 wxColour cf;
609 GetGlobalColor("CHWHT", &cf);
610 dc.SetTextForeground(cf);
611 if (pFontSmall->IsOk()) {
612 if (live.IsOk()) {
613 int point_size = wxMax(10, 10 * scale);
614 pFontSmall->SetPointSize(point_size);
615
616 // Validate and adjust the font size...
617 // No smaller than 8 pt.
618 int w;
619 wxScreenDC sdc;
620 sdc.GetTextExtent(NewVal, &w, NULL, NULL, NULL, pFontSmall);
621
622 while ((w > (icon.GetWidth() * 8 / 10)) && (point_size >= 8)) {
623 point_size--;
624 pFontSmall->SetPointSize(point_size);
625 sdc.GetTextExtent(NewVal, &w, NULL, NULL, NULL, pFontSmall);
626 }
627 }
628 dc.SetFont(*pFontSmall);
629 }
630 wxSize s = dc.GetTextExtent(NewVal);
631 dc.DrawText(NewVal, (icon.GetWidth() - s.GetWidth()) / 2,
632 (icon.GetHeight() - s.GetHeight()) / 2);
633 dc.SelectObject(wxNullBitmap);
634
635 if (live.IsOk()) {
636 // By using a DC to modify the bitmap, we have lost the original bitmap's
637 // alpha channel Recover it by copying from the original to the target,
638 // bit by bit
639 wxImage imo = live.ConvertToImage();
640 wxImage im = icon.ConvertToImage();
641
642 if (!imo.HasAlpha()) imo.InitAlpha();
643 if (!im.HasAlpha()) im.InitAlpha();
644
645 unsigned char *alive = imo.GetAlpha();
646 unsigned char *target = im.GetAlpha();
647
648 for (int i = 0; i < h; i++) {
649 for (int j = 0; j < w; j++) {
650 int index = (i * w) + j;
651 target[index] = alive[index];
652 }
653 }
654 icon = wxBitmap(im);
655 }
656
657 SetToolbarToolBitmaps(m_leftclick_tool_id, &icon, &icon);
658 }
659
660 if (NULL == m_pWmmDialog || !m_pWmmDialog->IsShown()) return;
661 if (!m_buseable) {
662 m_pWmmDialog->m_tbD->SetValue(_("Error, see log."));
663 return;
664 }
665 m_pWmmDialog->m_tbF->SetValue(
666 wxString::Format("%-9.1lf nT", GeoMagneticElements.F));
667 m_pWmmDialog->m_tbH->SetValue(
668 wxString::Format("%-9.1lf nT", GeoMagneticElements.H));
669 m_pWmmDialog->m_tbX->SetValue(
670 wxString::Format("%-9.1lf nT", GeoMagneticElements.X));
671 m_pWmmDialog->m_tbY->SetValue(
672 wxString::Format("%-9.1lf nT", GeoMagneticElements.Y));
673 m_pWmmDialog->m_tbZ->SetValue(
674 wxString::Format("%-9.1lf nT", GeoMagneticElements.Z));
675 m_pWmmDialog->m_tbD->SetValue(
676 wxString::Format("%-5.1lf%c (%s)", GeoMagneticElements.Decl, 0x00B0,
677 AngleToText(GeoMagneticElements.Decl).c_str()));
678 m_pWmmDialog->m_tbI->SetValue(
679 wxString::Format("%-5.1lf%c", GeoMagneticElements.Incl, 0x00B0));
680}
681
682// Demo implementation of response mechanism
683void WmmPi::SetPluginMessage(wxString &message_id, wxString &message_body) {
684 if (message_id == "WMM_VARIATION_REQUEST") {
685 wxJSONReader r;
686 wxJSONValue v;
687 r.Parse(message_body, &v);
688 double lat = v["Lat"].AsDouble();
689 double lon = v["Lon"].AsDouble();
690 int year = v["Year"].AsInt();
691 int month = v["Month"].AsInt();
692 int day = v["Day"].AsInt();
693 SendVariationAt(lat, lon, year, month, day);
694 } else if (message_id == "WMM_VARIATION_BOAT_REQUEST") {
695 SendBoatVariation();
696 } else if (message_id == "WMM_VARIATION_CURSOR_REQUEST") {
697 SendCursorVariation();
698 }
699}
700
701void WmmPi::SendVariationAt(double lat, double lon, int year, int month,
702 int day) {
703 wxJSONValue v;
704 v["Lat"] = lat;
705 v["Lon"] = lon;
706 v["Year"] = year;
707 v["Month"] = month;
708 v["Day"] = day;
709 CoordGeodetic.lambda = lon;
710 CoordGeodetic.phi = lat;
711 CoordGeodetic.HeightAboveEllipsoid = 0;
712 CoordGeodetic.UseGeoid = 0;
713 UserDate.Year = year;
714 UserDate.Month = month;
715 UserDate.Day = day;
716 char err[255];
717 MAG_DateToYear(&UserDate, err);
718 MAG_GeodeticToSpherical(
719 Ellip, CoordGeodetic,
720 &CoordSpherical); /*Convert from geodeitic to Spherical Equations: 17-18,
721 WMM Technical report*/
722 MAG_TimelyModifyMagneticModel(
723 UserDate, MagneticModel,
724 TimedMagneticModel); /* Time adjust the coefficients, Equation 19, WMM
725 Technical report */
726 MAG_Geomag(Ellip, CoordSpherical, CoordGeodetic, TimedMagneticModel,
727 &GeoMagneticElements); /* Computes the geoMagnetic field elements
728 and their time change*/
729 MAG_CalculateGridVariation(CoordGeodetic, &GeoMagneticElements);
730 v["Decl"] = GeoMagneticElements.Decl;
731 v["Decldot"] = GeoMagneticElements.Decldot;
732 v["F"] = GeoMagneticElements.F;
733 v["Fdot"] = GeoMagneticElements.Fdot;
734 v["GV"] = GeoMagneticElements.GV;
735 v["GVdot"] = GeoMagneticElements.GVdot;
736 v["H"] = GeoMagneticElements.H;
737 v["Hdot"] = GeoMagneticElements.Hdot;
738 v["Incl"] = GeoMagneticElements.Incl;
739 v["Incldot"] = GeoMagneticElements.Incldot;
740 v["X"] = GeoMagneticElements.X;
741 v["Xdot"] = GeoMagneticElements.Xdot;
742 v["Y"] = GeoMagneticElements.Y;
743 v["Ydot"] = GeoMagneticElements.Ydot;
744 v["Z"] = GeoMagneticElements.Z;
745 v["Zdot"] = GeoMagneticElements.Zdot;
746 wxJSONWriter w;
747 wxString out;
748 w.Write(v, out);
749 SendPluginMessage(wxString("WMM_VARIATION"), out);
750}
751
752void WmmPi::SendBoatVariation() {
753 wxJSONValue v;
754 v["Decl"] = m_boatVariation.Decl;
755 v["Decldot"] = m_boatVariation.Decldot;
756 v["F"] = m_boatVariation.F;
757 v["Fdot"] = m_boatVariation.Fdot;
758 v["GV"] = m_boatVariation.GV;
759 v["GVdot"] = m_boatVariation.GVdot;
760 v["H"] = m_boatVariation.H;
761 v["Hdot"] = m_boatVariation.Hdot;
762 v["Incl"] = m_boatVariation.Incl;
763 v["Incldot"] = m_boatVariation.Incldot;
764 v["X"] = m_boatVariation.X;
765 v["Xdot"] = m_boatVariation.Xdot;
766 v["Y"] = m_boatVariation.Y;
767 v["Ydot"] = m_boatVariation.Ydot;
768 v["Z"] = m_boatVariation.Z;
769 v["Zdot"] = m_boatVariation.Zdot;
770 wxJSONWriter w;
771 wxString out;
772 w.Write(v, out);
773 SendPluginMessage(wxString("WMM_VARIATION_BOAT"), out);
774 // Send boat variation as NMEA HVD for the Priority List.
775 SendBoatVarHVD(m_boatVariation.Decl);
776 SendPGN127258(m_boatVariation.Decl);
777}
778
779void WmmPi::SendCursorVariation() {
780 wxJSONValue v;
781 v["Decl"] = m_cursorVariation.Decl;
782 v["Decldot"] = m_cursorVariation.Decldot;
783 v["F"] = m_cursorVariation.F;
784 v["Fdot"] = m_cursorVariation.Fdot;
785 v["GV"] = m_cursorVariation.GV;
786 v["GVdot"] = m_cursorVariation.GVdot;
787 v["H"] = m_cursorVariation.H;
788 v["Hdot"] = m_cursorVariation.Hdot;
789 v["Incl"] = m_cursorVariation.Incl;
790 v["Incldot"] = m_cursorVariation.Incldot;
791 v["X"] = m_cursorVariation.X;
792 v["Xdot"] = m_cursorVariation.Xdot;
793 v["Y"] = m_cursorVariation.Y;
794 v["Ydot"] = m_cursorVariation.Ydot;
795 v["Z"] = m_cursorVariation.Z;
796 v["Zdot"] = m_cursorVariation.Zdot;
797 wxJSONWriter w;
798 wxString out;
799 w.Write(v, out);
800 SendPluginMessage(wxString("WMM_VARIATION_CURSOR"), out);
801}
802
803wxString WmmPi::AngleToText(double angle) {
804 int deg = (int)fabs(angle);
805 int min = (fabs(angle) - deg) * 60;
806 if (angle < 0)
807 return wxString::Format("%u%c%u' W", deg, 0x00B0, min);
808 else
809 return wxString::Format("%u%c%u' E", deg, 0x00B0, min);
810}
811
812bool WmmPi::LoadConfig(void) {
813 wxFileConfig *pConf = (wxFileConfig *)m_pconfig;
814
815 if (pConf) {
816 pConf->SetPath("/Settings/WMM");
817 pConf->Read("ViewType", &m_iViewType, 1);
818 pConf->Read("ShowPlotOptions", &m_bShowPlotOptions, 1);
819 pConf->Read("ShowAtCursor", &m_bShowAtCursor, 1);
820 pConf->Read("ShowLiveIcon", &m_bShowLiveIcon, 1);
821 pConf->Read("ShowIcon", &m_bShowIcon, 1);
822 pConf->Read("Opacity", &m_iOpacity, 255);
823
824 m_wmm_dialog_x = pConf->Read("DialogPosX", 20L);
825 m_wmm_dialog_y = pConf->Read("DialogPosY", 20L);
826
827 if ((m_wmm_dialog_x < 0) || (m_wmm_dialog_x > m_display_width))
828 m_wmm_dialog_x = 5;
829 if ((m_wmm_dialog_y < 0) || (m_wmm_dialog_y > m_display_height))
830 m_wmm_dialog_y = 5;
831
832 pConf->SetPath("/Settings/WMM/Plot");
833 pConf->Read("Declination", &m_DeclinationMap.m_bEnabled, 1);
834 pConf->Read("DeclinationSpacing", &m_DeclinationMap.m_Spacing, 10);
835 pConf->Read("Inclination", &m_InclinationMap.m_bEnabled, 0);
836 pConf->Read("InclinationSpacing", &m_InclinationMap.m_Spacing, 10);
837 pConf->Read("FieldStrength", &m_FieldStrengthMap.m_bEnabled, 0);
838 pConf->Read("FieldStrengthSpacing", &m_FieldStrengthMap.m_Spacing, 10000);
839
840 pConf->Read("StepSize", &m_MapStep, 6);
841 pConf->Read("PoleAccuracy", &m_MapPoleAccuracy, 2);
842 m_DeclinationMap.ConfigureAccuracy(m_MapStep, m_MapPoleAccuracy);
843 m_InclinationMap.ConfigureAccuracy(m_MapStep, m_MapPoleAccuracy);
844 m_FieldStrengthMap.ConfigureAccuracy(m_MapStep, m_MapPoleAccuracy);
845
846 m_MapDate = wxDateTime::Now(); /* always reset to current date */
847
848 m_bCachedPlotOk = false;
849
850 pConf->SetPath("/Directories");
851 wxString s = wxFileName::GetPathSeparator();
852 wxString def =
853 *GetpSharedDataLocation() + "plugins" + s + "wmm_pi" + s + "data" + s;
854 // pConf->Read ( "WMMDataLocation", &m_wmm_dir, def);
855 m_wmm_dir = def;
856 return true;
857 } else
858 return false;
859}
860
861bool WmmPi::SaveConfig(void) {
862 wxFileConfig *pConf = (wxFileConfig *)m_pconfig;
863
864 if (pConf) {
865 pConf->SetPath("/Settings/WMM");
866 pConf->Write("ViewType", m_iViewType);
867 pConf->Write("ShowPlotOptions", m_bShowPlotOptions);
868 pConf->Write("ShowAtCursor", m_bShowAtCursor);
869 pConf->Write("ShowLiveIcon", m_bShowLiveIcon);
870 pConf->Write("ShowIcon", m_bShowIcon);
871 pConf->Write("Opacity", m_iOpacity);
872
873 pConf->Write("DialogPosX", m_wmm_dialog_x);
874 pConf->Write("DialogPosY", m_wmm_dialog_y);
875
876 pConf->SetPath("/Settings/WMM/Plot");
877 pConf->Write("Declination", m_DeclinationMap.m_bEnabled);
878 pConf->Write("DeclinationSpacing", m_DeclinationMap.m_Spacing);
879 pConf->Write("Inclination", m_InclinationMap.m_bEnabled);
880 pConf->Write("InclinationSpacing", m_InclinationMap.m_Spacing);
881 pConf->Write("FieldStrength", m_FieldStrengthMap.m_bEnabled);
882 pConf->Write("FieldStrengthSpacing", m_FieldStrengthMap.m_Spacing);
883 pConf->Write("StepSize", m_MapStep);
884 pConf->Write("PoleAccuracy", m_MapPoleAccuracy);
885
886 pConf->SetPath("/Directories");
887 pConf->Write("WMMDataLocation", m_wmm_dir);
888
889 return true;
890 } else
891 return false;
892}
893
894void WmmPi::ShowPreferencesDialog(wxWindow *parent) {
895 WmmPrefsDialog *dialog =
896 new WmmPrefsDialog(parent, wxID_ANY, _("WMM Preferences"),
897 wxPoint(m_wmm_dialog_x, m_wmm_dialog_y), wxDefaultSize,
898 wxDEFAULT_DIALOG_STYLE);
899 dialog->Fit();
900
901 dialog->m_rbViewType->SetSelection(m_iViewType);
902 dialog->m_cbShowPlotOptions->SetValue(m_bShowPlotOptions);
903 dialog->m_cbShowAtCursor->SetValue(m_bShowAtCursor);
904 dialog->m_cbShowIcon->SetValue(m_bShowIcon);
905 dialog->m_cbLiveIcon->SetValue(m_bShowLiveIcon);
906 dialog->m_sOpacity->SetValue(m_iOpacity);
907
908 if (dialog->ShowModal() == wxID_OK) {
909 m_iViewType = dialog->m_rbViewType->GetSelection();
910 m_bShowPlotOptions = dialog->m_cbShowPlotOptions->GetValue();
911 m_bShowAtCursor = dialog->m_cbShowAtCursor->GetValue();
912 m_bShowLiveIcon = dialog->m_cbLiveIcon->GetValue();
913 m_bShowIcon = dialog->m_cbShowIcon->GetValue();
914 m_iOpacity = dialog->m_sOpacity->GetValue();
915
916 RearrangeWindow();
917 SetIconType();
918
919 SaveConfig();
920 }
921 delete dialog;
922}
923
925 WmmPlotSettingsDialog *dialog = new WmmPlotSettingsDialog(m_parent_window);
926 wxFont *pFont = OCPNGetFont(_("Dialog"));
927 dialog->SetFont(*pFont);
928
929 dialog->Fit();
930
931 dialog->m_cbDeclination->SetValue(m_DeclinationMap.m_bEnabled);
932 dialog->m_scDeclinationSpacing->SetValue(m_DeclinationMap.m_Spacing);
933 dialog->m_cbInclination->SetValue(m_InclinationMap.m_bEnabled);
934 dialog->m_scInclinationSpacing->SetValue(m_InclinationMap.m_Spacing);
935 dialog->m_cbFieldStrength->SetValue(m_FieldStrengthMap.m_bEnabled);
936 dialog->m_scFieldStrengthSpacing->SetValue(m_FieldStrengthMap.m_Spacing);
938 dialog->m_sStep->SetValue(m_MapStep);
939 dialog->m_sPoleAccuracy->SetValue(m_MapPoleAccuracy);
940
941 if (dialog->ShowModal() == wxID_OK) {
942 m_DeclinationMap.m_bEnabled = dialog->m_cbDeclination->GetValue();
943 m_DeclinationMap.m_Spacing = dialog->m_scDeclinationSpacing->GetValue();
944 m_InclinationMap.m_bEnabled = dialog->m_cbInclination->GetValue();
945 m_InclinationMap.m_Spacing = dialog->m_scInclinationSpacing->GetValue();
946 m_FieldStrengthMap.m_bEnabled = dialog->m_cbFieldStrength->GetValue();
947 m_FieldStrengthMap.m_Spacing = dialog->m_scFieldStrengthSpacing->GetValue();
949 m_MapStep = dialog->m_sStep->GetValue();
950 m_MapPoleAccuracy = dialog->m_sPoleAccuracy->GetValue();
951 m_DeclinationMap.ConfigureAccuracy(m_MapStep, m_MapPoleAccuracy);
952 m_InclinationMap.ConfigureAccuracy(m_MapStep, m_MapPoleAccuracy);
953 m_FieldStrengthMap.ConfigureAccuracy(m_MapStep, m_MapPoleAccuracy);
954
955 m_bCachedPlotOk = false;
956 if (m_pWmmDialog->m_cbEnablePlot->GetValue()) RecomputePlot();
957
958 RequestRefresh(m_parent_window);
959 RearrangeWindow();
960
961 SaveConfig();
962 }
963 delete dialog;
964}
965
966void WmmPi::SendBoatVarHVD(double d_var) {
967 // We use the HVD NMEA sentence to send magnetic variation.
968 // The user can then select the desired variation
969 // via the priority of the source code. The not official Talker: WM
970 // is used to print source: WMM plugin in the Priority list.
971 wxString s_dir = d_var >= 0 ? "E" : "W";
972 d_var = fabs(d_var); // Make it positive for NMEA sentence
973 wxString S = "$WMHVD";
974 S.Append(","); // 1 Var degrees
975 S.Append(wxString::Format("%.1f", d_var));
976 S.Append(","); // 2 Var Dir
977 S.Append(s_dir); // E/W
978 S.Append("*");
979 S.Append(wxString::Format("%02X", ComputeChecksum(S)));
980 S += "\r\n";
981
983}
984
985void WmmPi::SendPGN127258(double d_var) {
986 // Send Magnetic Variation as PGN 127258 Magnetic Variation
987 double var_rad = d_var * (M_PI / 180.0);
988 // Calculate the number of days since the Unix epoch
989 time_t now = time(nullptr);
990 int days_since_epoch = now / (60 * 60 * 24);
991 tN2kMsg msg127285;
992 SetN2kPGN127258(msg127285, 0xFF, tN2kMagneticVariation::N2kmagvar_WMM2025,
993 days_since_epoch, var_rad);
994 std::shared_ptr<std::vector<uint8_t>> payload(new std::vector<uint8_t>(
995 msg127285.Data, msg127285.Data + msg127285.DataLen));
996 WriteCommDriverN2K(m_handleN2k, 127258, 0xFF, 7, payload);
997}
998
999unsigned char WmmPi::ComputeChecksum(wxString sentence) const {
1000 unsigned char calculated_checksum = 0;
1001 for (wxString::const_iterator i = sentence.begin() + 1;
1002 i != sentence.end() && *i != '*'; ++i)
1003 calculated_checksum ^= static_cast<unsigned char>(*i);
1004
1005 return (calculated_checksum);
1006}
Basic position fix information.
double Lat
Latitude in decimal degrees.
double Lon
Longitude in decimal degrees.
Contains view parameters and status information for a chart display viewport.
Definition wmm_pi.h:91
int GetAPIVersionMinor() override
Returns the minor version number of the plugin API that this plugin supports.
Definition wmm_pi.cpp:287
wxString GetShortDescription() override
Get a brief description of the plugin.
Definition wmm_pi.cpp:297
int GetPlugInVersionMajor() override
Returns the major version number of the plugin itself.
Definition wmm_pi.cpp:289
void ShowPlotSettings()
Definition wmm_pi.cpp:924
wxString GetLongDescription() override
Get detailed plugin information.
Definition wmm_pi.cpp:301
bool RenderGLOverlay(wxGLContext *pcontext, PlugIn_ViewPort *vp) override
Renders plugin overlay graphics in OpenGL mode for single canvas.
Definition wmm_pi.cpp:430
int Init() override
Initialize the plugin and declare its capabilities.
Definition wmm_pi.cpp:128
void ShowPreferencesDialog(wxWindow *parent) override
Shows the plugin preferences dialog.
Definition wmm_pi.cpp:894
void SetCursorLatLon(double lat, double lon) override
Receives cursor lat/lon position updates.
Definition wmm_pi.cpp:486
int GetAPIVersionMajor() override
Returns the major version number of the plugin API that this plugin supports.
Definition wmm_pi.cpp:285
bool DeInit() override
Clean up plugin resources.
Definition wmm_pi.cpp:251
void OnToolbarToolCallback(int id) override
Handles toolbar tool clicks.
Definition wmm_pi.cpp:378
void SetColorScheme(PI_ColorScheme cs) override
Updates plugin color scheme.
Definition wmm_pi.cpp:315
wxBitmap * GetPlugInBitmap() override
Get the plugin's icon bitmap.
Definition wmm_pi.cpp:293
int GetPlugInVersionMinor() override
Returns the minor version number of the plugin itself.
Definition wmm_pi.cpp:291
wxString GetCommonName() override
Get the plugin's common (short) name.
Definition wmm_pi.cpp:295
void SetPositionFix(PlugIn_Position_Fix &pfix) override
Updates plugin with current position fix data at regular intervals.
Definition wmm_pi.cpp:543
int GetToolbarToolCount() override
Returns the number of toolbar tools this plugin provides.
Definition wmm_pi.cpp:313
Class WmmPrefsDialog.
Base class for OpenCPN plugins.
The JSON parser.
Definition jsonreader.h:45
int Parse(const wxString &doc, wxJSONValue *val)
Parse the JSON document.
The JSON value class implementation.
Definition jsonval.h:79
double AsDouble() const
Return the stored value as a double.
Definition jsonval.cpp:830
int AsInt() const
Return the stored value as an integer.
Definition jsonval.cpp:792
The JSON document writer.
Definition jsonwriter.h:45
void Write(const wxJSONValue &value, wxString &str)
Write the JSONvalue object to a JSON text.
CommDriverResult
Error return values
#define WANTS_NMEA_EVENTS
Receive decoded NMEA events with parsed data.
PI_ColorScheme
Color schemes for different lighting conditions.
#define WANTS_PREFERENCES
Plugin will add page(s) to global preferences dialog.
#define WANTS_CONFIG
Plugin requires persistent configuration storage.
#define WANTS_PLUGIN_MESSAGING
Enable message passing between plugins.
#define INSTALLS_TOOLBAR_TOOL
Plugin will add one or more toolbar buttons.
#define WANTS_CURSOR_LATLON
Receive updates when cursor moves over chart.
Definition ocpn_plugin.h:95
#define WANTS_TOOLBAR_CALLBACK
Receive notification when user left-clicks plugin's toolbar buttons.
#define WANTS_OVERLAY_CALLBACK
Receive callbacks to render custom overlay graphics on the chart.
Definition ocpn_plugin.h:91
void RemovePlugInTool(int tool_id)
Removes a tool from OpenCPN's toolbar.
wxWindow * GetOCPNCanvasWindow()
Gets OpenCPN's main canvas window.
wxFont * OCPNGetFont(wxString TextElement, int default_size)
Gets a font for UI elements.
wxFileConfig * GetOCPNConfigObject()
Gets OpenCPN's configuration object.
wxBitmap GetBitmapFromSVGFile(wxString filename, unsigned int width, unsigned int height)
Creates bitmap from SVG file.
int InsertPlugInTool(wxString label, wxBitmap *bitmap, wxBitmap *bmpRollover, wxItemKind kind, wxString shortHelp, wxString longHelp, wxObject *clientData, int position, int tool_sel, opencpn_plugin *pplugin)
Adds a tool to OpenCPN's toolbar.
void SetToolbarToolBitmaps(int item, wxBitmap *bitmap, wxBitmap *bmpRollover)
Updates toolbar tool bitmaps.
wxString * GetpSharedDataLocation()
Gets shared application data location.
void DimeWindow(wxWindow *win)
Applies system color scheme to window.
double GetOCPNGUIToolScaleFactor_PlugIn()
Gets current global GUI scaling factor.
void SetToolbarToolBitmapsSVG(int item, wxString SVGfile, wxString SVGfileRollover, wxString SVGfileToggled)
Updates SVG graphics for toolbar tool.
double OCPN_GetWinDIPScaleFactor()
Gets Windows-specific DPI scaling factor.
void PushNMEABuffer(wxString buf)
Pushes NMEA sentence to the system.
void SendPluginMessage(wxString message_id, wxString message_body)
Sends message to other plugins.
void RequestRefresh(wxWindow *win)
Requests window refresh.
bool AddLocaleCatalog(wxString catalog)
Adds a locale catalog for translations.
CommDriverResult WriteCommDriverN2K(DriverHandle handle, int PGN, int destinationCANAddress, int priority, const std::shared_ptr< std::vector< uint8_t > > &payload)
Send a PGN message to an NMEA2000 address.
std::vector< DriverHandle > GetActiveDrivers()
Comm port plugin TX support methods
const std::unordered_map< std::string, std::string > GetAttributes(DriverHandle handle)
Query a specific driver for attributes.
CommDriverResult RegisterTXPGNs(DriverHandle handle, std::vector< int > &pgn_list)
Register PGNs that this application intends to transmit for some NMEA 2000 adapters like Actisense NG...
WMM plugin.