OpenCPN Partial API docs
Loading...
Searching...
No Matches
plugin_api.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, see <https://www.gnu.org/licenses/>. *
17 **************************************************************************/
18
25#include <memory>
26#include <sstream>
27#include <vector>
28
29#include <wx/event.h>
30#include <wx/fileconf.h>
31#include <wx/jsonval.h>
32#include <wx/jsonreader.h>
33#include <wx/tokenzr.h>
34
35#include "model/base_platform.h"
36#include "model/comm_appmsg.h"
40#include "model/comm_drv_n2k.h"
44#include "ocpn_plugin.h"
48
49using namespace std;
50
51vector<uint8_t> GetN2000Payload(NMEA2000Id id, ObservedEvt ev) {
52 auto msg = UnpackEvtPointer<Nmea2000Msg>(ev);
53 return msg->payload;
54}
55
57 auto msg = UnpackEvtPointer<Nmea2000Msg>(ev);
58 return msg->source->to_string();
59}
60
62 auto msg = UnpackEvtPointer<Nmea0183Msg>(ev);
63 return msg->payload;
64}
65
67 auto msg = UnpackEvtPointer<PluginMsg>(ev);
68 return msg->message;
69}
70
71std::shared_ptr<void> GetSignalkPayload(ObservedEvt ev) {
72 auto msg = UnpackEvtPointer<SignalkMsg>(ev);
73 wxJSONReader reader;
74 wxJSONValue data;
75 reader.Parse(wxString(msg->raw_message), &data);
76
77 wxJSONValue root(wxJSONTYPE_OBJECT);
78 root["Data"] = data;
79 root["ErrorCount"] = reader.GetErrorCount();
80 root["WarningCount"] = reader.GetWarningCount();
81
82 root["Errors"] = wxJSONValue(wxJSONTYPE_ARRAY);
83 for (size_t i = 0; i < reader.GetErrors().GetCount(); i++)
84 root["Errors"].Append(reader.GetErrors().Item(i));
85
86 root["Warnings"] = wxJSONValue(wxJSONTYPE_ARRAY);
87 for (size_t i = 0; i < reader.GetWarnings().GetCount(); i++)
88 root["Warnings"].Append(reader.GetWarnings().Item(i));
89
90 root["Context"] = msg->context;
91 root["ContextSelf"] = msg->context_self;
92
93 return static_pointer_cast<void>(std::make_shared<wxJSONValue>(root));
94}
95
96std::shared_ptr<PI_Notification> GetNotificationMsgPayload(NotificationMsgId id,
97 ObservedEvt ev) {
98 auto msg = UnpackEvtPointer<NotificationMsg>(ev);
99 auto note = msg->notification;
100 auto rv = std::make_shared<PI_Notification>(
101 (PI_NotificationSeverity)note->GetSeverity(), note->GetMessage(),
102 note->GetTimeoutStart(), note->GetTimeoutLeft(), note->GetGuid());
103 rv->action_verb = msg->action_verb;
104 return rv;
105}
106
107shared_ptr<ObservableListener> GetListener(NMEA2000Id id, wxEventType et,
108 wxEvtHandler* eh) {
109 return make_shared<ObservableListener>(Nmea2000Msg(id.id), eh, et);
110}
111
112std::shared_ptr<ObservableListener> GetListener(NMEA0183Id id, wxEventType et,
113 wxEvtHandler* eh) {
114 return make_shared<ObservableListener>(Nmea0183Msg(id.id), eh, et);
115}
116
117shared_ptr<ObservableListener> GetListener(SignalkId id, wxEventType et,
118 wxEvtHandler* eh) {
119 return make_shared<ObservableListener>(SignalkMsg(), eh, et);
120}
121
122shared_ptr<ObservableListener> GetListener(NavDataId id, wxEventType et,
123 wxEvtHandler* eh) {
124 return make_shared<ObservableListener>(BasicNavDataMsg(), eh, et);
125}
126
127std::shared_ptr<ObservableListener> GetListener(PluginMsgId id, wxEventType et,
128 wxEvtHandler* eh) {
129 return make_shared<ObservableListener>(PluginMsg(id.id, ""), eh, et);
130}
131
132std::shared_ptr<ObservableListener> GetListener(NotificationMsgId id,
133 wxEventType et,
134 wxEvtHandler* eh) {
135 return make_shared<ObservableListener>(NotificationMsg(), eh, et);
136}
137
139 auto msg = UnpackEvtPointer<BasicNavDataMsg>(ev);
140 PluginNavdata data;
141
142 data.lat = msg->pos.lat;
143 data.lon = msg->pos.lon;
144 data.sog = msg->sog;
145 data.cog = msg->cog;
146 data.var = msg->var;
147 data.hdt = msg->hdt;
148 data.time = msg->time;
149 return data;
150}
151
154std::vector<DriverHandle> GetActiveDrivers() {
155 std::vector<DriverHandle> result;
156
157 auto& registry = CommDriverRegistry::GetInstance();
158 const std::vector<DriverPtr>& drivers = registry.GetDrivers();
159
160 for (auto& driver : drivers) result.push_back(driver->Key());
161
162 return result;
163}
164
165const std::unordered_map<std::string, std::string> GetAttributes(
166 DriverHandle handle) {
167 auto& registry = CommDriverRegistry::GetInstance();
168 auto& drivers = registry.GetDrivers();
169 auto func = [handle](const DriverPtr d) { return d->Key() == handle; };
170 AbstractCommDriver* found = nullptr;
171 for (auto& d : drivers)
172 if (d->Key() == handle) found = d.get();
173 if (found)
174 return found->GetAttributes();
175 else
176 return {};
177}
178
180 DriverHandle handle, const std::shared_ptr<std::vector<uint8_t>>& payload) {
181 // Find the driver from the handle
182 auto& registry = CommDriverRegistry::GetInstance();
183 auto& drivers = registry.GetDrivers();
184 AbstractCommDriver* found = nullptr;
185 for (auto& d : drivers)
186 if (d->Key() == handle) found = d.get();
187 if (!found) {
189 }
190
191 // Determine protocol
192 std::unordered_map<std::string, std::string> attributes =
193 GetAttributes(handle);
194 auto protocol_it = attributes.find("protocol");
195 if (protocol_it == attributes.end()) return RESULT_COMM_INVALID_PARMS;
196 std::string protocol = protocol_it->second;
197
198 // This whole thing is a design collapse. If things were as they should,
199 // all drivers should have the same interface and there should be no
200 // need to handle different protocols separately. Part of the problem
201 // is that there is no "internal" driver.
202 const std::string msg(payload->begin(), payload->end());
203 if (protocol == "nmea0183") {
204 std::string id = msg.substr(1, 5);
205 auto address = std::make_shared<NavAddr>();
206 auto msg_out = std::make_shared<Nmea0183Msg>(id, msg, address);
207 bool xmit_ok = found->SendMessage(msg_out, address);
209 } else if (protocol == "internal") {
210 size_t space_pos = msg.find(" ");
211 if (space_pos == std::string::npos) return RESULT_COMM_INVALID_PARMS;
212 auto plugin_msg = std::make_shared<PluginMsg>(msg.substr(0, space_pos),
213 msg.substr(space_pos + 1));
214 NavMsgBus::GetInstance().Notify(static_pointer_cast<NavMsg>(plugin_msg));
216 } else if (protocol == "loopback") {
217 auto navmsg = LoopbackDriver::ParsePluginMessage(msg);
218 if (!navmsg) return RESULT_COMM_INVALID_PARMS;
219 bool send_ok = found->SendMessage(navmsg, nullptr);
221 } else {
223 }
224}
225
227 DriverHandle handle, int PGN, int destinationCANAddress, int priority,
228 const std::shared_ptr<std::vector<uint8_t>>& payload) {
229 uint64_t _PGN;
230 _PGN = PGN;
231
232 wxString m1;
233 m1.Printf("WriteCommDriverN2K... PGN: 0x%0X, Destination Address: 0x%0X",
234 PGN, destinationCANAddress);
235 wxLogMessage(m1);
236 wxString m2 = "Payload: ";
237 for (uint8_t& d : *payload) {
238 wxString m3;
239 m3.Printf(" 0x%02X", d);
240 m2 += m3;
241 }
242 wxLogMessage(m2);
243
244 // Find the driver from the handle
245 auto& registry = CommDriverRegistry::GetInstance();
246 auto& drivers = registry.GetDrivers();
247
248 AbstractCommDriver* found(nullptr);
249 for (auto& d : drivers)
250 if (d->Key() == handle) found = d.get();
251 if (!found) {
253 }
254 auto dest_addr =
255 std::make_shared<const NavAddr2000>(found->iface, destinationCANAddress);
256 auto msg =
257 std::make_shared<const Nmea2000Msg>(_PGN, *payload, dest_addr, priority);
258 bool result = found->SendMessage(msg, dest_addr);
259
261}
262
264 std::vector<int>& pgn_list) {
265 if (!pgn_list.size()) return RESULT_COMM_INVALID_PARMS;
266
267 // Find the driver from the handle
268 auto& registry = CommDriverRegistry::GetInstance();
269 auto& drivers = registry.GetDrivers();
270 AbstractCommDriver* found(nullptr);
271 for (auto& d : drivers)
272 if (d->Key() == handle) found = d.get();
273
274 if (!found) {
276 }
277 auto dn2k = dynamic_cast<CommDriverN2K*>(found);
278
279 int nloop = 0;
280 for (size_t i = 0; i < pgn_list.size(); i++) {
281 int nTry = 5;
282 int iresult = -1;
283 nloop = 0;
284 while (nTry && iresult < 0) {
285 iresult = dn2k->SetTXPGN(pgn_list[i]);
286 nTry--;
287 nloop++;
288 }
289 if (iresult < 0) {
291 }
292 }
294}
295
299
300void ReloadConfigConnections() {
301 // Close and delete all active comm drivers
302 auto& registry = CommDriverRegistry::GetInstance();
303 registry.CloseAllDrivers();
304
305 // Reload config file connections parameters.
306 wxFileConfig* pConf = GetOCPNConfigObject();
307 if (pConf) {
308 TheConnectionParams().clear();
309 pConf->SetPath("/Settings/NMEADataSource");
310
311 wxString connectionconfigs;
312 pConf->Read("DataConnections", &connectionconfigs);
313 if (!connectionconfigs.IsEmpty()) {
314 wxArrayString confs = wxStringTokenize(connectionconfigs, "|");
315 for (size_t i = 0; i < confs.Count(); i++) {
316 ConnectionParams* prm = new ConnectionParams(confs[i]);
317 if (!prm->Valid) continue;
318 TheConnectionParams().push_back(prm);
319 }
320 }
321 }
322
323 // Reconnect enabled connections
324 for (auto* cp : TheConnectionParams()) {
325 if (cp->bEnabled) {
326 MakeCommDriver(cp);
327 cp->b_IsSetup = TRUE;
328 }
329 }
330}
331
337 const std::string& _message,
338 int _timeout_start, int _timeout_left,
339 std::string _guid) {
340 severity = _severity;
341 message = _message;
342 auto_timeout_start = _timeout_start;
343 auto_timeout_left = _timeout_left;
344 guid = _guid;
345}
346
347int GetActiveNotificationCount() {
348 auto& noteman = NotificationManager::GetInstance();
349 return noteman.GetNotificationCount();
350}
351
352PI_NotificationSeverity GetMaxActiveNotificationLevel() {
353 auto& noteman = NotificationManager::GetInstance();
354 if (noteman.GetNotificationCount())
355 return (PI_NotificationSeverity)noteman.GetMaxSeverity();
356 else
357 return (PI_NotificationSeverity)-1;
358}
359
360std::string RaiseNotification(const PI_NotificationSeverity _severity,
361 const std::string& _message, int timeout_secs) {
362 auto& noteman = NotificationManager::GetInstance();
363 auto notification = std::make_shared<Notification>(
364 (NotificationSeverity)_severity, _message, timeout_secs);
365 return noteman.AddNotification(notification);
366}
367
368bool AcknowledgeNotification(const std::string& guid) {
369 auto& noteman = NotificationManager::GetInstance();
370 return noteman.AcknowledgeNotification(guid);
371}
372
373std::vector<std::shared_ptr<PI_Notification>> GetActiveNotifications() {
374 auto& noteman = NotificationManager::GetInstance();
375 std::vector<std::shared_ptr<PI_Notification>> pi_notes;
376 for (auto note : noteman.GetNotifications()) {
377 auto pi_note = std::make_shared<PI_Notification>(
378 (PI_NotificationSeverity)note->GetSeverity(), note->GetMessage(),
379 note->GetTimeoutStart(), note->GetTimeoutLeft(), note->GetGuid());
380 pi_notes.push_back(pi_note);
381 }
382
383 return pi_notes;
384}
385
389PI_Comm_Status GetConnState(const std::string& iface, PI_Conn_Bus _bus) {
390 // Translate API bus to internal NavAddr::Bus
391 NavAddr::Bus ibus = NavAddr::Bus::Undef;
392 switch (_bus) {
393 case PI_Conn_Bus::N0183:
394 ibus = NavAddr::Bus::N0183;
395 break;
396
397 case PI_Conn_Bus::Signalk:
398 ibus = NavAddr::Bus::Signalk;
399 break;
400
401 case PI_Conn_Bus::N2000:
402 ibus = NavAddr::Bus::N2000;
403 break;
404
405 default:
406 break;
407 }
408
409 DriverStats stats;
410 if (ibus != NavAddr::Bus::Undef) {
411 auto& registry = CommDriverRegistry::GetInstance();
412 auto& drivers = registry.GetDrivers();
413 auto& found_driver = FindDriver(drivers, iface, ibus);
414 if (found_driver) {
415 auto stats_provider =
416 dynamic_cast<DriverStatsProvider*>(found_driver.get());
417 if (stats_provider) {
418 stats = stats_provider->GetDriverStats();
419 }
420 }
421 }
422
424 if (stats.available) {
425 if (stats.rx_count)
426 rv.state = PI_Comm_State::Ok;
427 else
428 rv.state = PI_Comm_State::NoData;
429 } else
430 rv.state = PI_Comm_State::Unavailable;
431
432 rv.rx_count = stats.rx_count;
433 rv.tx_count = stats.tx_count;
434 rv.error_count = stats.error_count;
435
436 return rv;
437}
BasePlatform * g_BasePlatform
points to g_platform, handles brain-dead MS linker.
Basic platform specific support utilities without GUI deps.
Common interface for all drivers.
Definition comm_driver.h:65
const std::string iface
Physical device for 0183, else a unique string.
Definition comm_driver.h:95
wxString * GetPrivateDataDirPtr()
Legacy compatibility syntactic sugar for GetPrivateDataDir().
Driver interface providing driver statistics.
static std::shared_ptr< const NavMsg > ParsePluginMessage(const std::string &msg)
Parse a string as provided by plugin and convert to a navmsg.
void Notify(std::shared_ptr< const NavMsg > message)
Accept message received by driver, make it available for upper layers.
A regular Nmea0183 message.
See: https://github.com/OpenCPN/OpenCPN/issues/2729#issuecomment-1179506343.
Custom event class for OpenCPN's notification system.
unsigned error_count
Number of detected errors since program start.
unsigned tx_count
Number of bytes sent since program start.
unsigned rx_count
Number of bytes received since program start.
PI_Notification(PI_NotificationSeverity _severity, const std::string &_message, int _timeout_start, int _timeout_left, std::string _guid)
Plugin Notification Framework support.
A plugin to plugin json message over the REST interface.
A parsed SignalK message over ipv4.
The JSON parser.
Definition jsonreader.h:50
const wxArrayString & GetWarnings() const
Return a reference to the warning message's array.
const wxArrayString & GetErrors() const
Return a reference to the error message's array.
int GetErrorCount() const
Return the size of the error message's array.
int GetWarningCount() const
Return the size of the warning message's array.
int Parse(const wxString &doc, wxJSONValue *val)
Parse the JSON document.
The JSON value class implementation.
Definition jsonval.h:84
Decoded messages definitions.
void MakeCommDriver(const ConnectionParams *params)
Create and register a driver for given connection.
Communication drivers factory and support.
Loopback driver, treat sent messages as received.
NMEA0183 over IP driver.
NMEA0183 serial driver.
Nmea2000 driver.
Nmea2000 IP network driver.
Nmea2000 serial driver.
DriverPtr & FindDriver(const std::vector< DriverPtr > &drivers, const std::string &iface, const NavAddr::Bus _bus)
Search list of drivers for a driver with given interface string.
Driver registration container, a singleton.
Raw messages layer, supports sending and recieving navmsg messages.
User notifications manager.
PlugIn Object Definition/API.
CommDriverResult
Error return values
@ RESULT_COMM_INVALID_PARMS
Invalid parameters provided to operation.
@ RESULT_COMM_TX_ERROR
Error occurred during transmission.
@ RESULT_COMM_REGISTER_PGN_ERROR
Failed to register PGN parameters.
@ RESULT_COMM_NO_ERROR
Operation completed successfully.
@ RESULT_COMM_INVALID_HANDLE
Invalid or unknown driver handle specified.
PI_NotificationSeverity
Plugin Notification Framework support.
std::string DriverHandle
Plugin API supporting direct access to comm drivers for output purposes.
wxFileConfig * GetOCPNConfigObject()
Gets OpenCPN's configuration object.
PI_Comm_Status GetConnState(const std::string &iface, PI_Conn_Bus _bus)
Plugin polled Comm Status support.
std::string GetPluginMsgPayload(PluginMsgId id, ObservedEvt ev)
Retrieve the string in a plugin message, internal or received on the REST insterface.
std::string GetN0183Payload(NMEA0183Id id, ObservedEvt ev)
Return payload in a received n0183 message of type id in ev.
PluginNavdata GetEventNavdata(ObservedEvt ev)
Return BasicNavDataMsg decoded data available in ev.
std::shared_ptr< PI_Notification > GetNotificationMsgPayload(NotificationMsgId id, ObservedEvt ev)
Retrieve the Notification Event in a Notification message.
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.
wxString * GetpPrivateApplicationDataLocation()
Gets private application data directory.
shared_ptr< ObservableListener > GetListener(NMEA2000Id id, wxEventType et, wxEvtHandler *eh)
Gets listener for NMEA 2000 messages.
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.
std::string GetN2000Source(NMEA2000Id id, ObservedEvt ev)
Return source identifier (iface) of a received n2000 message of type id in ev.
vector< uint8_t > GetN2000Payload(NMEA2000Id id, ObservedEvt ev)
Return N2K payload for a received n2000 message of type id in ev.
std::shared_ptr< void > GetSignalkPayload(ObservedEvt ev)
Get SignalK status payload after receiving a message.
CommDriverResult WriteCommDriver(DriverHandle handle, const std::shared_ptr< std::vector< uint8_t > > &payload)
Send a non-NMEA2000 message.
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...
Driver statistics report.
unsigned tx_count
Number of bytes sent since program start.
unsigned rx_count
Number of bytes received since program start.
unsigned error_count
Number of detected errors since program start.
Identifier for NMEA 0183 sentence types.
Identifier for NMEA 2000 message types.
Navigation data message identifier.
Facade for NotificationMsg.
Facade for NavAddrPluginMsg.
Basic navigation data structure.
double lat
Latitude in decimal degrees.
Identifier for Signal K paths.