OpenCPN Partial API docs
Loading...
Searching...
No Matches
plugin_comm.cpp
Go to the documentation of this file.
1/**************************************************************************
2 * Copyright (C) 2022 by David Register *
3 * Copyright (C) 2022 Alec Leamas *
4 * *
5 * This program is free software; you can redistribute it and/or modify *
6 * it under the terms of the GNU General Public License as published by *
7 * the Free Software Foundation; either version 2 of the License, or *
8 * (at your option) any later version. *
9 * *
10 * This program is distributed in the hope that it will be useful, *
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of *
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
13 * GNU General Public License for more details. *
14 * *
15 * You should have received a copy of the GNU General Public License *
16 * along with this program; if not, write to the *
17 * Free Software Foundation, Inc., *
18 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. *
19 **************************************************************************/
20
26#include <setjmp.h>
27
28#include <wx/event.h>
29#include <wx/jsonval.h>
30#include <wx/jsonreader.h>
31#include <wx/jsonwriter.h>
32
33#include "model/comm_appmsg.h"
35#include "model/plugin_loader.h"
36
37#include "model/plugin_comm.h"
38
39#include "ocpn_plugin.h"
40
41#ifndef _WIN32
42
43static struct sigaction sa_all_PIM_previous;
44static sigjmp_buf env_PIM;
45
46static void catch_signals_PIM(int signo) {
47 switch (signo) {
48 case SIGSEGV:
49 siglongjmp(env_PIM, 1); // jump back to the setjmp() point
50 break;
51
52 default:
53 break;
54 }
55}
56
57#endif
58
59void SendMessageToAllPlugins(const wxString& message_id,
60 const wxString& message_body) {
61 auto msg = std::make_shared<PluginMsg>(
62 PluginMsg(message_id.ToStdString(), message_body.ToStdString()));
63 NavMsgBus::GetInstance().Notify(msg);
64
65 // decouple 'const wxString &' and 'wxString &' to keep bin
66 wxString decouple_message_id(message_id);
67 wxString decouple_message_body(message_body);
68
69 auto plugin_array = PluginLoader::getInstance()->GetPlugInArray();
70 for (unsigned int i = 0; i < plugin_array->GetCount(); i++) {
71 PlugInContainer* pic = plugin_array->Item(i);
72 if (pic->m_enabled && pic->m_init_state) {
74 switch (pic->m_api_version) {
75 case 106: {
76 auto* ppi = dynamic_cast<opencpn_plugin_16*>(pic->m_pplugin);
77 if (ppi)
78 ppi->SetPluginMessage(decouple_message_id, decouple_message_body);
79 break;
80 }
81 case 107: {
82 auto* ppi = dynamic_cast<opencpn_plugin_17*>(pic->m_pplugin);
83 if (ppi)
84 ppi->SetPluginMessage(decouple_message_id, decouple_message_body);
85 break;
86 }
87 case 108:
88 case 109:
89 case 110:
90 case 111:
91 case 112:
92 case 113:
93 case 114:
94 case 115:
95 case 116:
96 case 117:
97 case 118:
98 case 119: {
99 auto* ppi = dynamic_cast<opencpn_plugin_18*>(pic->m_pplugin);
100 if (ppi)
101 ppi->SetPluginMessage(decouple_message_id, decouple_message_body);
102 break;
103 }
104 default:
105 break;
106 }
107 }
108 }
109 }
110}
111
112void SendJSONMessageToAllPlugins(const wxString& message_id, wxJSONValue v) {
113 wxJSONWriter w;
114 wxString out;
115 w.Write(v, out);
116 SendMessageToAllPlugins(message_id, out);
117 wxLogDebug(message_id);
118 wxLogDebug(out);
119}
120
121void SendAISSentenceToAllPlugIns(const wxString& sentence) {
122 // decouple 'const wxString &' to keep interface.
123 wxString decouple_sentence(sentence);
124 auto plugin_array = PluginLoader::getInstance()->GetPlugInArray();
125 for (unsigned int i = 0; i < plugin_array->GetCount(); i++) {
126 PlugInContainer* pic = plugin_array->Item(i);
127 if (pic->m_enabled && pic->m_init_state) {
129 pic->m_pplugin->SetAISSentence(decouple_sentence);
130 }
131 }
132}
133
134void SendPositionFixToAllPlugIns(GenericPosDatEx* ppos) {
135 // Send basic position fix
137 pfix.Lat = ppos->kLat;
138 pfix.Lon = ppos->kLon;
139 pfix.Cog = ppos->kCog;
140 pfix.Sog = ppos->kSog;
141 pfix.Var = ppos->kVar;
142 pfix.FixTime = ppos->FixTime;
143 pfix.nSats = ppos->nSats;
144
145 auto plugin_array = PluginLoader::getInstance()->GetPlugInArray();
146 for (unsigned int i = 0; i < plugin_array->GetCount(); i++) {
147 PlugInContainer* pic = plugin_array->Item(i);
148 if (pic->m_enabled && pic->m_init_state) {
149 if (pic->m_cap_flag & WANTS_NMEA_EVENTS)
150 if (pic->m_pplugin) pic->m_pplugin->SetPositionFix(pfix);
151 }
152 }
153
154 // Send extended position fix to PlugIns at API 108 and later
156 pfix_ex.Lat = ppos->kLat;
157 pfix_ex.Lon = ppos->kLon;
158 pfix_ex.Cog = ppos->kCog;
159 pfix_ex.Sog = ppos->kSog;
160 pfix_ex.Var = ppos->kVar;
161 pfix_ex.FixTime = ppos->FixTime;
162 pfix_ex.nSats = ppos->nSats;
163 pfix_ex.Hdt = ppos->kHdt;
164 pfix_ex.Hdm = ppos->kHdm;
165
166 for (unsigned int i = 0; i < plugin_array->GetCount(); i++) {
167 PlugInContainer* pic = plugin_array->Item(i);
168 if (pic->m_enabled && pic->m_init_state) {
169 if (pic->m_cap_flag & WANTS_NMEA_EVENTS) {
170 switch (pic->m_api_version) {
171 case 108:
172 case 109:
173 case 110:
174 case 111:
175 case 112:
176 case 113:
177 case 114:
178 case 115:
179 case 116:
180 case 117:
181 case 118:
182 case 119: {
183 auto* ppi = dynamic_cast<opencpn_plugin_18*>(pic->m_pplugin);
184 if (ppi) ppi->SetPositionFixEx(pfix_ex);
185 break;
186 }
187 default:
188 break;
189 }
190 }
191 }
192 }
193}
194
195void SendActiveLegInfoToAllPlugIns(const ActiveLegDat* leg_info) {
197 leg.Btw = leg_info->Btw;
198 leg.Dtw = leg_info->Dtw;
199 leg.wp_name = leg_info->wp_name;
200 leg.Xte = leg_info->Xte;
201 leg.arrival = leg_info->arrival;
202 auto plugin_array = PluginLoader::getInstance()->GetPlugInArray();
203 for (unsigned int i = 0; i < plugin_array->GetCount(); i++) {
204 PlugInContainer* pic = plugin_array->Item(i);
205 if (pic->m_enabled && pic->m_init_state) {
206 if (pic->m_cap_flag & WANTS_NMEA_EVENTS) {
207 switch (pic->m_api_version) {
208 case 108:
209 case 109:
210 case 110:
211 case 111:
212 case 112:
213 case 113:
214 case 114:
215 case 115:
216 case 116:
217 break;
218 case 117:
219 case 118:
220 case 119: {
221 auto* ppi = dynamic_cast<opencpn_plugin_117*>(pic->m_pplugin);
222 if (ppi) ppi->SetActiveLegInfo(leg);
223 break;
224 }
225 default:
226 break;
227 }
228 }
229 }
230 }
231}
232
233bool SendMouseEventToPlugins(wxMouseEvent& event) {
234 bool bret = false;
235 auto plugin_array = PluginLoader::getInstance()->GetPlugInArray();
236 for (unsigned int i = 0; i < plugin_array->GetCount(); i++) {
237 PlugInContainer* pic = plugin_array->Item(i);
238 if (pic->m_enabled && pic->m_init_state) {
239 if (pic->m_cap_flag & WANTS_MOUSE_EVENTS) {
240 switch (pic->m_api_version) {
241 case 112:
242 case 113:
243 case 114:
244 case 115:
245 case 116:
246 case 117:
247 case 118:
248 case 119: {
249 auto* ppi = dynamic_cast<opencpn_plugin_112*>(pic->m_pplugin);
250 if (ppi && ppi->MouseEventHook(event)) bret = true;
251 break;
252 }
253 default:
254 break;
255 }
256 }
257 }
258 }
259 return bret;
260}
261
262bool SendKeyEventToPlugins(wxKeyEvent& event) {
263 bool bret = false;
264 auto plugin_array = PluginLoader::getInstance()->GetPlugInArray();
265 for (unsigned int i = 0; i < plugin_array->GetCount(); i++) {
266 PlugInContainer* pic = plugin_array->Item(i);
267 if (pic->m_enabled && pic->m_init_state) {
269 {
270 switch (pic->m_api_version) {
271 case 113:
272 case 114:
273 case 115:
274 case 116:
275 case 117:
276 case 118:
277 case 119: {
278 auto* ppi = dynamic_cast<opencpn_plugin_113*>(pic->m_pplugin);
279 if (ppi && ppi->KeyboardEventHook(event)) bret = true;
280 break;
281 }
282 default:
283 break;
284 }
285 }
286 }
287 }
288 }
289
290 return bret;
291}
292
293void SendPreShutdownHookToPlugins() {
294 auto plugin_array = PluginLoader::getInstance()->GetPlugInArray();
295 for (unsigned int i = 0; i < plugin_array->GetCount(); i++) {
296 PlugInContainer* pic = plugin_array->Item(i);
297 if (pic->m_enabled && pic->m_init_state) {
299 switch (pic->m_api_version) {
300 case 119: {
301 auto* ppi = dynamic_cast<opencpn_plugin_119*>(pic->m_pplugin);
302 if (ppi) ppi->PreShutdownHook();
303 break;
304 }
305 default:
306 break;
307 }
308 }
309 }
310 }
311}
312
313void SendCursorLatLonToAllPlugIns(double lat, double lon) {
314 auto plugin_array = PluginLoader::getInstance()->GetPlugInArray();
315 for (unsigned int i = 0; i < plugin_array->GetCount(); i++) {
316 PlugInContainer* pic = plugin_array->Item(i);
317 if (pic->m_enabled && pic->m_init_state) {
319 if (pic->m_pplugin) pic->m_pplugin->SetCursorLatLon(lat, lon);
320 }
321 }
322}
323
324void SendNMEASentenceToAllPlugIns(const wxString& sentence) {
325 // decouple 'const wxString &' to keep plugin interface.
326 wxString decouple_sentence(sentence);
327#ifndef __WXMSW__
328 // Set up a framework to catch (some) sigsegv faults from plugins.
329 sigaction(SIGSEGV, NULL, &sa_all_PIM_previous); // save existing
330 // action for this signal
331 struct sigaction temp;
332 sigaction(SIGSEGV, NULL, &temp); // inspect existing action for this signal
333
334 temp.sa_handler = catch_signals_PIM; // point to my handler
335 sigemptyset(&temp.sa_mask); // make the blocking set
336 // empty, so that all
337 // other signals will be
338 // unblocked during my handler
339 temp.sa_flags = 0;
340 sigaction(SIGSEGV, &temp, NULL);
341#endif
342 auto plugin_array = PluginLoader::getInstance()->GetPlugInArray();
343 for (unsigned int i = 0; i < plugin_array->GetCount(); i++) {
344 PlugInContainer* pic = plugin_array->Item(i);
345 if (pic->m_enabled && pic->m_init_state) {
346 if (pic->m_cap_flag & WANTS_NMEA_SENTENCES) {
347#ifndef __WXMSW__
348 if (sigsetjmp(env_PIM, 1)) {
349 // Something in the "else" code block faulted.
350 // Probably safest to assume that all variables in this method are
351 // trash... So, simply clean up and return.
352 sigaction(SIGSEGV, &sa_all_PIM_previous, NULL);
353 // reset signal handler
354 return;
355 } else
356#endif
357 {
358 // volatile int *x = 0;
359 //*x = 0;
360 if (pic->m_pplugin)
361 pic->m_pplugin->SetNMEASentence(decouple_sentence);
362 }
363 }
364 }
365 }
366#ifndef __WXMSW__
367 sigaction(SIGSEGV, &sa_all_PIM_previous, NULL); // reset signal handler
368#endif
369}
370
371int GetJSONMessageTargetCount() {
372 int rv = 0;
373 auto plugin_array = PluginLoader::getInstance()->GetPlugInArray();
374 for (unsigned int i = 0; i < plugin_array->GetCount(); i++) {
375 PlugInContainer* pic = plugin_array->Item(i);
376 if (pic->m_enabled && pic->m_init_state &&
378 rv++;
379 }
380 return rv;
381}
382
383void SendVectorChartObjectInfo(const wxString& chart, const wxString& feature,
384 const wxString& objname, double& lat,
385 double& lon, double& scale, int& nativescale) {
386 wxString decouple_chart(chart);
387 wxString decouple_feature(feature);
388 wxString decouple_objname(objname);
389 auto plugin_array = PluginLoader::getInstance()->GetPlugInArray();
390 for (unsigned int i = 0; i < plugin_array->GetCount(); i++) {
391 PlugInContainer* pic = (*plugin_array)[i];
392 if (pic->m_enabled && pic->m_init_state) {
394 switch (pic->m_api_version) {
395 case 112:
396 case 113:
397 case 114:
398 case 115:
399 case 116:
400 case 117:
401 case 118:
402 case 119: {
403 auto* ppi = dynamic_cast<opencpn_plugin_112*>(pic->m_pplugin);
404 if (ppi)
405 ppi->SendVectorChartObjectInfo(decouple_chart, decouple_feature,
406 decouple_objname, lat, lon, scale,
407 nativescale);
408 break;
409 }
410 default:
411 break;
412 }
413 }
414 }
415 }
416}
void Notify(std::shared_ptr< const NavMsg > message)
Accept message received by driver, make it available for upper layers.
Data for a loaded plugin, including dl-loaded library.
int m_cap_flag
PlugIn Capabilities descriptor.
Extended position fix information.
int nSats
Number of satellites used in the fix.
double Var
Magnetic variation in degrees, typically from RMC message.
double Cog
Course over ground in degrees.
double Lat
Latitude in decimal degrees.
double Hdm
Heading magnetic in degrees.
time_t FixTime
UTC time of fix.
double Lon
Longitude in decimal degrees.
double Sog
Speed over ground in knots.
double Hdt
Heading true in degrees.
Basic position fix information.
double Cog
Course over ground in degrees.
double Sog
Speed over ground in knots.
time_t FixTime
UTC time of fix as time_t value.
double Lat
Latitude in decimal degrees.
int nSats
Number of satellites used in the fix.
double Var
Magnetic variation in degrees, typically from RMC message.
double Lon
Longitude in decimal degrees.
A plugin to plugin json message over the REST interface.
Information about the currently active route leg.
double Dtw
Distance to waypoint in nautical miles.
wxString wp_name
Name of destination waypoint for the active leg.
double Xte
Cross track error in nautical miles, negative values indicate left side of track.
double Btw
Bearing to waypoint in degrees true.
bool arrival
True when vessel is within the arrival circle of the destination waypoint.
virtual void SendVectorChartObjectInfo(wxString &chart, wxString &feature, wxString &objname, double lat, double lon, double scale, int nativescale)
Receives vector chart object information.
virtual void PreShutdownHook()
Called just before OpenCPN begins shutdown sequence.
virtual void SetPluginMessage(wxString &message_id, wxString &message_body)
Receives plugin-to-plugin messages.
virtual void SetPositionFixEx(PlugIn_Position_Fix_Ex &pfix)
Updates plugin with extended position fix data.
virtual void SetPositionFix(PlugIn_Position_Fix &pfix)
Updates plugin with current position fix data.
virtual void SetNMEASentence(wxString &sentence)
Receive all NMEA 0183 sentences from OpenCPN.
virtual void SetAISSentence(wxString &sentence)
Receive all AIS sentences from OpenCPN.
virtual void SetCursorLatLon(double lat, double lon)
Receives cursor lat/lon position updates.
The JSON value class implementation.
Definition jsonval.h:84
The JSON document writer.
Definition jsonwriter.h:50
void Write(const wxJSONValue &value, wxString &str)
Write the JSONvalue object to a JSON text.
Raw messages layer, supports sending and recieving navmsg messages.
PlugIn Object Definition/API.
#define WANTS_NMEA_EVENTS
Receive decoded NMEA events with parsed data.
#define WANTS_VECTOR_CHART_OBJECT_INFO
Receive information about vector chart objects.
#define WANTS_AIS_SENTENCES
Receive AIS target information and updates.
#define WANTS_KEYBOARD_EVENTS
Receive keyboard events from main window.
#define WANTS_NMEA_SENTENCES
Receive raw NMEA 0183 sentences from all active ports.
#define WANTS_MOUSE_EVENTS
Receive mouse events (clicks, movement, etc).
#define WANTS_PRESHUTDOWN_HOOK
Receive notification just before OpenCPN shutdown.
#define WANTS_PLUGIN_MESSAGING
Enable message passing between plugins.
#define WANTS_CURSOR_LATLON
Receive updates when cursor moves over chart.
Definition ocpn_plugin.h:90
void SendNMEASentenceToAllPlugIns(const wxString &sentence)
Distribute a NMEA 0183 sentence to all plugins that have registered interest by setting the WANTS_NME...
Tools to send data to plugins.
A generic position and navigation data structure.
Definition ocpn_types.h:74
double kCog
Course over ground in degrees.
Definition ocpn_types.h:92
double kHdt
True heading in degrees.
Definition ocpn_types.h:117
int nSats
Number of satellites used in the fix.
Definition ocpn_types.h:132
double kHdm
Magnetic heading in degrees.
Definition ocpn_types.h:110
time_t FixTime
UTC time of fix.
Definition ocpn_types.h:124
double kLat
Latitude in decimal degrees.
Definition ocpn_types.h:81
double kSog
Speed over ground in knots.
Definition ocpn_types.h:98
double kVar
Magnetic variation in degrees.
Definition ocpn_types.h:104
double kLon
Longitude in decimal degrees.
Definition ocpn_types.h:89