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.
A plugin to plugin json message over the REST interface.
virtual void SetNMEASentence(wxString &sentence)
Receive all NMEA 0183 sentences from OpenCPN.
virtual void SetAISSentence(wxString &sentence)
Receive all AIS sentences from OpenCPN.
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.