OpenCPN Partial API docs
Loading...
Searching...
No Matches
comm_n0183_output.cpp
1/***************************************************************************
2 *
3 * Project: OpenCPN
4 * Purpose: NMEA Data Multiplexer Object
5 * Author: David Register
6 *
7 ***************************************************************************
8 * Copyright (C) 2010 by David S. Register *
9 * *
10 * This program is free software; you can redistribute it and/or modify *
11 * it under the terms of the GNU General Public License as published by *
12 * the Free Software Foundation; either version 2 of the License, or *
13 * (at your option) any later version. *
14 * *
15 * This program is distributed in the hope that it will be useful, *
16 * but WITHOUT ANY WARRANTY; without even the implied warranty of *
17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
18 * GNU General Public License for more details. *
19 * *
20 * You should have received a copy of the GNU General Public License *
21 * along with this program; if not, write to the *
22 * Free Software Foundation, Inc., *
23 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. *
24 **************************************************************************/
25
26// For compilers that support precompilation, includes "wx.h".
27#include <wx/wxprec.h>
28
29#ifndef WX_PRECOMP
30#include <wx/wx.h>
31#endif // precompiled headers
32
33#include "config.h"
34
35#include <wx/jsonreader.h>
36#include <wx/jsonval.h>
37#include <wx/jsonwriter.h>
38#include <wx/tokenzr.h>
39
40#include "comm_driver.h"
41#include "comm_drv_factory.h"
42#include "comm_drv_n0183_net.h"
43#include "comm_drv_n0183_serial.h"
44#include "comm_drv_registry.h"
45#include "comm_n0183_output.h"
46#include "config_vars.h"
47#include "conn_params.h"
48#include "gui_lib.h"
49#include "nmea0183.h"
50#include "route.h"
51#include "NMEALogWindow.h"
52
53#ifdef USE_GARMINHOST
54#include "garmin_wrapper.h"
55#endif
56
57//FIXME (dave) think about GUI feedback, disabled herein
58
59void LogBroadcastOutputMessageColor(const wxString &msg,
60 const wxString &stream_name,
61 const wxString &color) {
62#ifndef CLIAPP
63
64 if (NMEALogWindow::Get().Active()) {
65 wxDateTime now = wxDateTime::Now();
66 wxString ss;
67#ifndef __WXQT__ // Date/Time on Qt are broken, at least for android
68 ss = now.FormatISOTime();
69#endif
70 ss.Prepend(_T("--> "));
71 ss.Append(_T(" ("));
72 ss.Append(stream_name);
73 ss.Append(_T(") "));
74 ss.Append(msg);
75 ss.Prepend(color);
76
77 NMEALogWindow::Get().Add(ss.ToStdString());
78
79 }
80#endif
81}
82
83void BroadcastNMEA0183Message(const wxString &msg) {
84
85 auto& registry = CommDriverRegistry::GetInstance();
86 const std::vector<std::shared_ptr<AbstractCommDriver>>& drivers = registry.GetDrivers();
87
88 for (auto& driver : drivers) {
89 if (driver->bus == NavAddr::Bus::N0183) {
90 ConnectionParams params;
91 auto drv_serial =
92 std::dynamic_pointer_cast<CommDriverN0183Serial>(driver);
93 if (drv_serial) {
94 params = drv_serial->GetParams();
95 } else {
96 auto drv_net = std::dynamic_pointer_cast<CommDriverN0183Net>(driver);
97 if (drv_net) {
98 params = drv_net->GetParams();
99 }
100 }
101
102 if (params.IOSelect == DS_TYPE_INPUT_OUTPUT ||
103 params.IOSelect == DS_TYPE_OUTPUT) {
104 bool bout_filter = params.SentencePassesFilter(msg, FILTER_OUTPUT);
105 if (bout_filter) {
106 std::string id = msg.ToStdString().substr(1,5);
107 auto msg_out = std::make_shared<Nmea0183Msg>(id,
108 msg.ToStdString(),
109 std::make_shared<NavAddr0183>(driver->iface));
110
111 bool bxmit_ok = driver->SendMessage(msg_out, std::make_shared<NavAddr0183>(driver->iface));
112
113 if (bxmit_ok)
114 LogBroadcastOutputMessageColor(msg, params.GetDSPort(), _T("<BLUE>"));
115 else
116 LogBroadcastOutputMessageColor(msg, params.GetDSPort(), _T("<RED>"));
117 }
118 else
119 LogBroadcastOutputMessageColor(msg, params.GetDSPort(), _T("<CORAL>"));
120
121 }
122 }
123 }
124 // Send to plugins
125 //FIXME (dave)
126// if (g_pi_manager) g_pi_manager->SendNMEASentenceToAllPlugIns(msg);
127}
128
129
130std::shared_ptr<AbstractCommDriver> CreateOutputConnection(const wxString &com_name,
131 std::shared_ptr<AbstractCommDriver> &old_driver,
132 ConnectionParams &params_save,
133 bool &btempStream, bool &b_restoreStream){
134
135 std::shared_ptr<AbstractCommDriver> driver;
136 auto& registry = CommDriverRegistry::GetInstance();
137 const std::vector<std::shared_ptr<AbstractCommDriver>>& drivers = registry.GetDrivers();
138
139 if (com_name.Lower().StartsWith("serial")) {
140 wxString comx = com_name.AfterFirst(':'); // strip "Serial:"
141 comx = comx.BeforeFirst(' '); // strip off any description provided by Windows
142
143 old_driver = FindDriver(drivers, comx.ToStdString());
144 wxLogDebug("Looking for old stream %s", com_name);
145
146 if (old_driver) {
147 auto drv_serial_n0183 =
148 std::dynamic_pointer_cast<CommDriverN0183Serial>(old_driver);
149 if (drv_serial_n0183) {
150 params_save = drv_serial_n0183->GetParams();
151 }
152 registry.Deactivate(old_driver);
153
154 b_restoreStream = true;
155 }
156
157 } else {
158 driver = FindDriver(drivers, com_name.ToStdString());
159 }
160
161 if (com_name.Lower().StartsWith("serial")) {
162 // If the port was temporarily closed, reopen as I/O type
163 // Otherwise, open another port using default properties
164 int baud;
165
166 if (old_driver) {
167 baud = params_save.Baudrate;
168 } else {
169 baud = 4800;
170 }
171
173 cp.Type = SERIAL;
174 cp.SetPortStr(com_name);
175 cp.Baudrate = baud;
176 cp.IOSelect = DS_TYPE_INPUT_OUTPUT;
177
178 driver = MakeCommDriver(&cp);
179 btempStream = true;
180
181#ifdef __ANDROID__
182 wxMilliSleep(1000);
183#else
184 auto drv_serial_n0183 =
185 std::dynamic_pointer_cast<CommDriverN0183Serial>(driver);
186 if (drv_serial_n0183) {
187 // Wait up to 1 seconds for serial Driver secondary thread to come up
188 int timeout = 0;
189 while (!drv_serial_n0183->IsSecThreadActive() && (timeout < 50)) {
190 wxMilliSleep(100);
191 timeout++;
192 }
193
194 if (!drv_serial_n0183->IsSecThreadActive()) {
195 wxString msg(_T("-->GPS Port:"));
196 msg += com_name;
197 msg += _T(" ...Could not be opened for writing");
198 wxLogMessage(msg);
199 }
200
201 }
202#endif
203 }
204 else if (com_name.Find("Bluetooth") != wxNOT_FOUND) {
205 if (!driver) {
207 ConnectionParams.Type = INTERNAL_BT;
208 wxStringTokenizer tkz(com_name, _T(";"));
209 wxString name = tkz.GetNextToken();
210 wxString mac = tkz.GetNextToken();
211
212 ConnectionParams.NetworkAddress = name;
213 ConnectionParams.Port = mac;
214 ConnectionParams.NetworkPort = 0;
215 ConnectionParams.NetProtocol = PROTO_UNDEFINED;
216 ConnectionParams.Baudrate = 0;
217
218 driver = MakeCommDriver(&ConnectionParams);
219
220 btempStream = true;
221 }
222 }
223 else if (com_name.Lower().StartsWith("udp") ||
224 com_name.Lower().StartsWith("tcp")) {
225 std::shared_ptr<CommDriverN0183Net> drv_net_n0183;
226
227 if (!driver) {
228 NetworkProtocol protocol = UDP;
229 if (com_name.Lower().StartsWith("tcp")) protocol = TCP;
230 wxStringTokenizer tkz(com_name, _T(":"));
231 wxString token = tkz.GetNextToken();
232 wxString address = tkz.GetNextToken();
233 token = tkz.GetNextToken();
234 long port;
235 token.ToLong(&port);
236
238 cp.Type = NETWORK;
239 cp.NetProtocol = protocol;
240 cp.NetworkAddress = address;
241 cp.NetworkPort = port;
242 cp.IOSelect = DS_TYPE_INPUT_OUTPUT;
243
244 driver = MakeCommDriver(&cp);
245 btempStream = true;
246 }
247 drv_net_n0183 =
248 std::dynamic_pointer_cast<CommDriverN0183Net>(driver);
249
250 if (com_name.Lower().StartsWith("tcp")) {
251 // new tcp connections must wait for connect
252// wxString msg = _("Connecting to ");
253// msg += com_name;
254// dialog->SetMessage(msg);
255// dialog->GetProgressGauge()->Pulse();
256
257
258 if (drv_net_n0183) {
259 int loopCount = 10; // seconds
260 bool bconnected = false;
261 while (!bconnected && (loopCount > 0)) {
262 if (drv_net_n0183->GetSock()->IsConnected()) {
263 bconnected = true;
264 break;
265 }
266// dialog->GetProgressGauge()->Pulse();
267// wxYield();
268 wxSleep(1);
269 loopCount--;
270 }
271
272 if (bconnected) {
273// msg = _("Connected to ");
274// msg += com_name;
275// dialog->SetMessage(msg);
276 } else {
277 if (btempStream) {
278 registry.Deactivate(driver);
279 }
280 return 0;
281 }
282 }
283 }
284 }
285 return driver;
286}
287
288
289int SendRouteToGPS_N0183(Route *pr, const wxString &com_name,
290 bool bsend_waypoints/*, SendToGpsDlg *dialog*/) {
291 int ret_val = 0;
292
293 ConnectionParams params_save;
294 bool b_restoreStream = false;
295 bool btempStream = false;
296 std::shared_ptr<AbstractCommDriver> old_driver;
297 std::shared_ptr<AbstractCommDriver> driver;
298 auto& registry = CommDriverRegistry::GetInstance();
299
300 driver = CreateOutputConnection(com_name, old_driver,
301 params_save, btempStream, b_restoreStream);
302 if (!driver)
303 return 1;
304
305 auto drv_n0183 = std::dynamic_pointer_cast<CommDriverN0183>(driver);
306 auto address = std::make_shared<NavAddr0183>(drv_n0183->iface);
307
308
309#if 0
310
311 if (g_GPS_Ident == _T("FurunoGP3X")) {
312 if (pr->pRoutePointList->GetCount() > 30) {
313 long style = wxOK;
314 auto dlg = new OCPN_TimedHTMLMessageDialog(
315 0,
316 _T("Routes containing more than 30 waypoints must be split before ")
317 _T("uploading."),
318 _("Route Upload"), 10, style, false, wxDefaultPosition);
319 int reply = dlg->ShowModal();
320 return 1;
321 }
322 }
323
324#endif
325
326#ifdef USE_GARMINHOST
327#ifdef __WXMSW__
328 if (com_name.Upper().Matches(_T("*GARMIN*"))) // Garmin USB Mode
329 {
330 // if(m_pdevmon)
331 // m_pdevmon->StopIOThread(true);
332
333 int v_init = Garmin_GPS_Init(wxString(_T("usb:")));
334
335 if (v_init < 0) {
336 wxString msg(_T(" Garmin USB GPS could not be initialized"));
337 wxLogMessage(msg);
338 msg.Printf(_T(" Error Code is %d"), v_init);
339 wxLogMessage(msg);
340 msg = _T(" LastGarminError is: ");
341 msg += GetLastGarminError();
342 wxLogMessage(msg);
343
344 ret_val = ERR_GARMIN_INITIALIZE;
345 } else {
346 wxLogMessage(_T("Garmin USB Initialized"));
347
348 wxString msg = _T("USB Unit identifies as: ");
349 wxString GPS_Unit = Garmin_GPS_GetSaveString();
350 msg += GPS_Unit;
351 wxLogMessage(msg);
352
353 wxLogMessage(_T("Sending Routes..."));
354 int ret1 = Garmin_GPS_SendRoute(wxString(_T("usb:")), pr,
355 0/*dialog->GetProgressGauge()*/);
356
357 if (ret1 != 1) {
358 wxLogMessage(_T(" Error Sending Routes"));
359 wxString msg;
360 msg = _T(" LastGarminError is: ");
361 msg += GetLastGarminError();
362 wxLogMessage(msg);
363
364 ret_val = ERR_GARMIN_GENERAL;
365 } else
366 ret_val = 0;
367 }
368
369 // if(m_pdevmon)
370 // m_pdevmon->RestartIOThread();
371
372 goto ret_point_1;
373 }
374#endif
375
376 if (g_bGarminHostUpload) {
377 int lret_val;
378// if (dialog && dialog->GetProgressGauge()) {
379// dialog->GetProgressGauge()->SetValue(20);
380// dialog->GetProgressGauge()->Refresh();
381// dialog->GetProgressGauge()->Update();
382// }
383
384 wxString short_com = com_name.Mid(7);
385 // Initialize the Garmin receiver, build required Jeeps internal data
386 // structures
387 int v_init = Garmin_GPS_Init(short_com);
388 if (v_init < 0) {
389 wxString msg(_T("Garmin GPS could not be initialized on port: "));
390 msg += short_com;
391 wxString err;
392 err.Printf(_T(" Error Code is %d"), v_init);
393 msg += err;
394
395 msg += _T("\n LastGarminError is: ");
396 msg += GetLastGarminError();
397
398 wxLogMessage(msg);
399
400 ret_val = ERR_GARMIN_INITIALIZE;
401 goto ret_point;
402 } else {
403 wxString msg(_T("Sent Route to Garmin GPS on port: "));
404 msg += short_com;
405 msg += _T("\n Unit identifies as: ");
406 wxString GPS_Unit = Garmin_GPS_GetSaveString();
407 msg += GPS_Unit;
408
409 wxLogMessage(msg);
410 }
411
412// if (dialog && dialog->GetProgressGauge()) {
413// dialog->GetProgressGauge()->SetValue(40);
414// dialog->GetProgressGauge()->Refresh();
415// dialog->GetProgressGauge()->Update();
416// }
417
418 lret_val = Garmin_GPS_SendRoute(short_com, pr, 0/*dialog->GetProgressGauge()*/);
419 if (lret_val != 1) {
420 wxString msg(_T("Error Sending Route to Garmin GPS on port: "));
421 msg += short_com;
422 wxString err;
423 err.Printf(_T(" Error Code is %d"), ret_val);
424
425 msg += _T("\n LastGarminError is: ");
426 msg += GetLastGarminError();
427
428 msg += err;
429 wxLogMessage(msg);
430
431 ret_val = ERR_GARMIN_GENERAL;
432 goto ret_point;
433 } else
434 ret_val = 0;
435
436 ret_point:
437
438// if (dialog && dialog->GetProgressGauge()) {
439// dialog->GetProgressGauge()->SetValue(100);
440// dialog->GetProgressGauge()->Refresh();
441// dialog->GetProgressGauge()->Update();
442// }
443
444 wxMilliSleep(500);
445
446 goto ret_point_1;
447 } else
448#endif // USE_GARMINHOST
449
450#if 1
451 {
452 SENTENCE snt;
453 NMEA0183 oNMEA0183;
454 oNMEA0183.TalkerID = _T ( "EC" );
455
456 int nProg = pr->pRoutePointList->GetCount() + 1;
457// if (dialog && dialog->GetProgressGauge())
458// dialog->GetProgressGauge()->SetRange(100);
459
460 int progress_stall = 500;
461 if (pr->pRoutePointList->GetCount() > 10) progress_stall = 200;
462
463// if (!dialog) progress_stall = 200; // 80 chars at 4800 baud is ~160 msec
464
465 // Send out the waypoints, in order
466 if (bsend_waypoints) {
467 wxRoutePointListNode *node = pr->pRoutePointList->GetFirst();
468
469 int ip = 1;
470 while (node) {
471 RoutePoint *prp = node->GetData();
472
473 if (g_GPS_Ident == _T("Generic")) {
474 if (prp->m_lat < 0.)
475 oNMEA0183.Wpl.Position.Latitude.Set(-prp->m_lat, _T ( "S" ));
476 else
477 oNMEA0183.Wpl.Position.Latitude.Set(prp->m_lat, _T ( "N" ));
478
479 if (prp->m_lon < 0.)
480 oNMEA0183.Wpl.Position.Longitude.Set(-prp->m_lon, _T ( "W" ));
481 else
482 oNMEA0183.Wpl.Position.Longitude.Set(prp->m_lon, _T ( "E" ));
483
484 oNMEA0183.Wpl.To = prp->GetName().Truncate(g_maxWPNameLength);
485
486 oNMEA0183.Wpl.Write(snt);
487
488 } else if (g_GPS_Ident == _T("FurunoGP3X")) {
489 // Furuno has its own talker ID, so do not allow the global
490 // override
491 wxString talker_save = g_TalkerIdText;
492 g_TalkerIdText.Clear();
493
494 oNMEA0183.TalkerID = _T ( "PFEC," );
495
496 if (prp->m_lat < 0.)
497 oNMEA0183.GPwpl.Position.Latitude.Set(-prp->m_lat, _T ( "S" ));
498 else
499 oNMEA0183.GPwpl.Position.Latitude.Set(prp->m_lat, _T ( "N" ));
500
501 if (prp->m_lon < 0.)
502 oNMEA0183.GPwpl.Position.Longitude.Set(-prp->m_lon, _T ( "W" ));
503 else
504 oNMEA0183.GPwpl.Position.Longitude.Set(prp->m_lon, _T ( "E" ));
505
506 wxString name = prp->GetName();
507 name += _T("000000");
508 name.Truncate(g_maxWPNameLength);
509 oNMEA0183.GPwpl.To = name;
510
511 oNMEA0183.GPwpl.Write(snt);
512
513 g_TalkerIdText = talker_save;
514 }
515
516 wxString payload = snt.Sentence;
517
518 // for some gps, like some garmin models, they assume the first
519 // waypoint in the route is the boat location, therefore it is
520 // dropped. These gps also can only accept a maximum of up to 20
521 // waypoints at a time before a delay is needed and a new string of
522 // waypoints may be sent. To ensure all waypoints will arrive, we can
523 // simply send each one twice. This ensures that the gps will get the
524 // waypoint and also allows us to send as many as we like
525 //
526 // We need only send once for FurunoGP3X models
527
528 auto msg_out = std::make_shared<Nmea0183Msg>(std::string("ECWPL"),
529 snt.Sentence.ToStdString(),
530 address);
531
532 drv_n0183->SendMessage(msg_out, address);
533 if (g_GPS_Ident != _T("FurunoGP3X"))
534 drv_n0183->SendMessage(msg_out, address);
535
536// LogOutputMessage(snt.Sentence, dstr->GetPort(), false);
537
538 wxString msg(_T("-->GPS Port:"));
539 msg += com_name;
540 msg += _T(" Sentence: ");
541 msg += snt.Sentence;
542 msg.Trim();
543 wxLogMessage(msg);
544
545// if (dialog && dialog->GetProgressGauge()) {
546// dialog->GetProgressGauge()->SetValue((ip * 100) / nProg);
547// dialog->GetProgressGauge()->Refresh();
548// dialog->GetProgressGauge()->Update();
549// }
550
551 wxMilliSleep(progress_stall);
552
553 node = node->GetNext();
554
555 ip++;
556 }
557 }
558
559 // Create the NMEA Rte sentence
560 // Try to create a single sentence, and then check the length to see if
561 // too long
562 unsigned int max_length = 76;
563 unsigned int max_wp = 2; // seems to be required for garmin...
564
565 // Furuno GPS can only accept 5 (five) waypoint linkage sentences....
566 // So, we need to compact a few more points into each link sentence.
567 if (g_GPS_Ident == _T("FurunoGP3X")) {
568 max_wp = 8;
569 max_length = 80;
570 }
571
572 // Furuno has its own talker ID, so do not allow the global override
573 wxString talker_save = g_TalkerIdText;
574 if (g_GPS_Ident == _T("FurunoGP3X")) g_TalkerIdText.Clear();
575
576 oNMEA0183.Rte.Empty();
577 oNMEA0183.Rte.TypeOfRoute = CompleteRoute;
578
579 if (pr->m_RouteNameString.IsEmpty())
580 oNMEA0183.Rte.RouteName = _T ( "1" );
581 else
582 oNMEA0183.Rte.RouteName = pr->m_RouteNameString;
583
584 if (g_GPS_Ident == _T("FurunoGP3X")) {
585 oNMEA0183.Rte.RouteName = _T ( "01" );
586 oNMEA0183.TalkerID = _T ( "GP" );
587 oNMEA0183.Rte.m_complete_char = 'C'; // override the default "c"
588 oNMEA0183.Rte.m_skip_checksum = 1; // no checksum needed
589 }
590
591 oNMEA0183.Rte.total_number_of_messages = 1;
592 oNMEA0183.Rte.message_number = 1;
593
594 // add the waypoints
595 wxRoutePointListNode *node = pr->pRoutePointList->GetFirst();
596 while (node) {
597 RoutePoint *prp = node->GetData();
598 wxString name = prp->GetName().Truncate(g_maxWPNameLength);
599
600 if (g_GPS_Ident == _T("FurunoGP3X")) {
601 name = prp->GetName();
602 name += _T("000000");
603 name.Truncate(g_maxWPNameLength);
604 name.Prepend(_T(" ")); // What Furuno calls "Skip Code", space means
605 // use the WP
606 }
607
608 oNMEA0183.Rte.AddWaypoint(name);
609 node = node->GetNext();
610 }
611
612 oNMEA0183.Rte.Write(snt);
613
614 if ((snt.Sentence.Len() > max_length) ||
615 (pr->pRoutePointList->GetCount() >
616 max_wp)) // Do we need split sentences?
617 {
618 // Make a route with zero waypoints to get tare load.
619 NMEA0183 tNMEA0183;
620 SENTENCE tsnt;
621 tNMEA0183.TalkerID = _T ( "EC" );
622
623 tNMEA0183.Rte.Empty();
624 tNMEA0183.Rte.TypeOfRoute = CompleteRoute;
625
626 if (g_GPS_Ident != _T("FurunoGP3X")) {
627 if (pr->m_RouteNameString.IsEmpty())
628 tNMEA0183.Rte.RouteName = _T ( "1" );
629 else
630 tNMEA0183.Rte.RouteName = pr->m_RouteNameString;
631
632 } else {
633 tNMEA0183.Rte.RouteName = _T ( "01" );
634 }
635
636 tNMEA0183.Rte.Write(tsnt);
637
638 unsigned int tare_length = tsnt.Sentence.Len();
639 tare_length -= 3; // Drop the checksum, for length calculations
640
641 wxArrayString sentence_array;
642
643 // Trial balloon: add the waypoints, with length checking
644 int n_total = 1;
645 bool bnew_sentence = true;
646 int sent_len = 0;
647 unsigned int wp_count = 0;
648
649 wxRoutePointListNode *node = pr->pRoutePointList->GetFirst();
650 while (node) {
651 RoutePoint *prp = node->GetData();
652 unsigned int name_len =
653 prp->GetName().Truncate(g_maxWPNameLength).Len();
654 if (g_GPS_Ident == _T("FurunoGP3X"))
655 name_len = 7; // six chars, with leading space for "Skip Code"
656
657 if (bnew_sentence) {
658 sent_len = tare_length;
659 sent_len += name_len + 1; // with comma
660 bnew_sentence = false;
661 node = node->GetNext();
662 wp_count = 1;
663
664 } else {
665 if ((sent_len + name_len > max_length) || (wp_count >= max_wp)) {
666 n_total++;
667 bnew_sentence = true;
668 } else {
669 if (wp_count == max_wp)
670 sent_len += name_len; // with comma
671 else
672 sent_len += name_len + 1; // with comma
673 wp_count++;
674 node = node->GetNext();
675 }
676 }
677 }
678
679 // Now we have the sentence count, so make the real sentences using the
680 // same counting logic
681 int final_total = n_total;
682 int n_run = 1;
683 bnew_sentence = true;
684
685 node = pr->pRoutePointList->GetFirst();
686 while (node) {
687 RoutePoint *prp = node->GetData();
688 wxString name = prp->GetName().Truncate(g_maxWPNameLength);
689 if (g_GPS_Ident == _T("FurunoGP3X")) {
690 name = prp->GetName();
691 name += _T("000000");
692 name.Truncate(g_maxWPNameLength);
693 name.Prepend(_T(" ")); // What Furuno calls "Skip Code", space
694 // means use the WP
695 }
696
697 unsigned int name_len = name.Len();
698
699 if (bnew_sentence) {
700 sent_len = tare_length;
701 sent_len += name_len + 1; // comma
702 bnew_sentence = false;
703
704 oNMEA0183.Rte.Empty();
705 oNMEA0183.Rte.TypeOfRoute = CompleteRoute;
706
707 if (g_GPS_Ident != _T("FurunoGP3X")) {
708 if (pr->m_RouteNameString.IsEmpty())
709 oNMEA0183.Rte.RouteName = _T ( "1" );
710 else
711 oNMEA0183.Rte.RouteName = pr->m_RouteNameString;
712 } else {
713 oNMEA0183.Rte.RouteName = _T ( "01" );
714 }
715
716 oNMEA0183.Rte.total_number_of_messages = final_total;
717 oNMEA0183.Rte.message_number = n_run;
718 snt.Sentence.Clear();
719 wp_count = 1;
720
721 oNMEA0183.Rte.AddWaypoint(name);
722 node = node->GetNext();
723 } else {
724 if ((sent_len + name_len > max_length) || (wp_count >= max_wp)) {
725 n_run++;
726 bnew_sentence = true;
727
728 oNMEA0183.Rte.Write(snt);
729
730 sentence_array.Add(snt.Sentence);
731 } else {
732 sent_len += name_len + 1; // comma
733 oNMEA0183.Rte.AddWaypoint(name);
734 wp_count++;
735 node = node->GetNext();
736 }
737 }
738 }
739
740 oNMEA0183.Rte.Write(snt); // last one...
741 if (snt.Sentence.Len() > tare_length) sentence_array.Add(snt.Sentence);
742
743 for (unsigned int ii = 0; ii < sentence_array.GetCount(); ii++) {
744 wxString sentence = sentence_array[ii];
745
746 auto msg_out = std::make_shared<Nmea0183Msg>(std::string("ECRTE"),
747 sentence.ToStdString(),
748 address);
749 drv_n0183->SendMessage(msg_out, address);
750
751// LogOutputMessage(sentence, dstr->GetPort(), false);
752
753 wxString msg(_T("-->GPS Port:"));
754 msg += com_name;
755 msg += _T(" Sentence: ");
756 msg += sentence;
757 msg.Trim();
758 wxLogMessage(msg);
759
760 wxMilliSleep(progress_stall);
761 }
762
763 } else {
764 auto msg_out = std::make_shared<Nmea0183Msg>(std::string("ECRTE"),
765 snt.Sentence.ToStdString(),
766 address);
767 drv_n0183->SendMessage(msg_out, address);
768
769 //LogOutputMessage(snt.Sentence, dstr->GetPort(), false);
770
771 wxString msg(_T("-->GPS Port:"));
772 msg += com_name;
773 msg += _T(" Sentence: ");
774 msg += snt.Sentence;
775 msg.Trim();
776 wxLogMessage(msg);
777 }
778
779 if (g_GPS_Ident == _T("FurunoGP3X")) {
780 wxString name = pr->GetName();
781 if (name.IsEmpty()) name = _T("RTECOMMENT");
782 wxString rte;
783 rte.Printf(_T("$PFEC,GPrtc,01,"));
784 rte += name.Left(16);
785 wxString rtep;
786 rtep.Printf(_T(",%c%c"), 0x0d, 0x0a);
787 rte += rtep;
788
789 auto msg_out = std::make_shared<Nmea0183Msg>(std::string("GPRTC"),
790 rte.ToStdString(),
791 address);
792 drv_n0183->SendMessage(msg_out, address);
793
794// LogOutputMessage(rte, dstr->GetPort(), false);
795
796 wxString msg(_T("-->GPS Port:"));
797 msg += com_name;
798 msg += _T(" Sentence: ");
799 msg += rte;
800 msg.Trim();
801 wxLogMessage(msg);
802
803 wxString term;
804 term.Printf(_T("$PFEC,GPxfr,CTL,E%c%c"), 0x0d, 0x0a);
805
806 auto msg_outf = std::make_shared<Nmea0183Msg>(std::string("GPRTC"),
807 term.ToStdString(),
808 address);
809 drv_n0183->SendMessage(msg_outf, address);
810
811// LogOutputMessage(term, dstr->GetPort(), false);
812
813 msg = wxString(_T("-->GPS Port:"));
814 msg += com_name;
815 msg += _T(" Sentence: ");
816 msg += term;
817 msg.Trim();
818 wxLogMessage(msg);
819 }
820
821// if (dialog && dialog->GetProgressGauge()) {
822// dialog->GetProgressGauge()->SetValue(100);
823// dialog->GetProgressGauge()->Refresh();
824// dialog->GetProgressGauge()->Update();
825// }
826
827 wxMilliSleep(progress_stall);
828
829 ret_val = 0;
830
831 // All finished with the temp port
832 if (btempStream)
833 registry.Deactivate(driver);
834
835 if (g_GPS_Ident == _T("FurunoGP3X")) g_TalkerIdText = talker_save;
836 }
837#endif
838ret_point_1:
839
840 if (b_restoreStream && old_driver)
841 MakeCommDriver(&params_save);
842
843 return ret_val;
844}
845
846int SendWaypointToGPS_N0183(RoutePoint *prp, const wxString &com_name/*,SendToGpsDlg *dialog*/) {
847 int ret_val = 0;
848
849 ConnectionParams params_save;
850 bool b_restoreStream = false;
851 bool btempStream = false;
852 std::shared_ptr<AbstractCommDriver> old_driver;
853 std::shared_ptr<AbstractCommDriver> driver;
854 auto& registry = CommDriverRegistry::GetInstance();
855
856 driver = CreateOutputConnection(com_name, old_driver,
857 params_save, btempStream, b_restoreStream);
858 if (!driver)
859 return 1;
860
861 auto drv_n0183 = std::dynamic_pointer_cast<CommDriverN0183>(driver);
862 auto address = std::make_shared<NavAddr0183>(drv_n0183->iface);
863
864#ifdef USE_GARMINHOST
865 //FIXME (dave)
866#ifdef __WXMSW__
867 if (com_name.Upper().Matches(_T("*GARMIN*"))) // Garmin USB Mode
868 {
869 // if(m_pdevmon)
870 // m_pdevmon->StopIOThread(true);
871
872 int v_init = Garmin_GPS_Init(wxString(_T("usb:")));
873
874 if (v_init < 0) {
875 wxString msg(_T(" Garmin USB GPS could not be initialized"));
876 wxLogMessage(msg);
877 msg.Printf(_T(" Error Code is %d"), v_init);
878 wxLogMessage(msg);
879 msg = _T(" LastGarminError is: ");
880 msg += GetLastGarminError();
881 wxLogMessage(msg);
882
883 ret_val = ERR_GARMIN_INITIALIZE;
884 } else {
885 wxLogMessage(_T("Garmin USB Initialized"));
886
887 wxString msg = _T("USB Unit identifies as: ");
888 wxString GPS_Unit = Garmin_GPS_GetSaveString();
889 msg += GPS_Unit;
890 wxLogMessage(msg);
891
892 wxLogMessage(_T("Sending Waypoint..."));
893
894 // Create a RoutePointList with one item
895 RoutePointList rplist;
896 rplist.Append(prp);
897
898 int ret1 = Garmin_GPS_SendWaypoints(wxString(_T("usb:")), &rplist);
899
900 if (ret1 != 1) {
901 wxLogMessage(_T(" Error Sending Waypoint to Garmin USB"));
902 wxString msg;
903 msg = _T(" LastGarminError is: ");
904 msg += GetLastGarminError();
905 wxLogMessage(msg);
906
907 ret_val = ERR_GARMIN_GENERAL;
908 } else
909 ret_val = 0;
910 }
911
912 // if(m_pdevmon)
913 // m_pdevmon->RestartIOThread();
914
915 return ret_val;
916 }
917#endif
918
919 // Are we using Garmin Host mode for uploads?
920 if (g_bGarminHostUpload) {
921 RoutePointList rplist;
922 int ret_val;
923
924 wxString short_com = com_name.Mid(7);
925 // Initialize the Garmin receiver, build required Jeeps internal data
926 // structures
927 int v_init = Garmin_GPS_Init(short_com);
928 if (v_init < 0) {
929 wxString msg(_T("Garmin GPS could not be initialized on port: "));
930 msg += com_name;
931 wxString err;
932 err.Printf(_T(" Error Code is %d"), v_init);
933 msg += err;
934
935 msg += _T("\n LastGarminError is: ");
936 msg += GetLastGarminError();
937
938 wxLogMessage(msg);
939
940 ret_val = ERR_GARMIN_INITIALIZE;
941 goto ret_point;
942 } else {
943 wxString msg(_T("Sent waypoint(s) to Garmin GPS on port: "));
944 msg += com_name;
945 msg += _T("\n Unit identifies as: ");
946 wxString GPS_Unit = Garmin_GPS_GetSaveString();
947 msg += GPS_Unit;
948 wxLogMessage(msg);
949 }
950
951 // Create a RoutePointList with one item
952 rplist.Append(prp);
953
954 ret_val = Garmin_GPS_SendWaypoints(short_com, &rplist);
955 if (ret_val != 1) {
956 wxString msg(_T("Error Sending Waypoint(s) to Garmin GPS on port: "));
957 msg += com_name;
958 wxString err;
959 err.Printf(_T(" Error Code is %d"), ret_val);
960 msg += err;
961
962 msg += _T("\n LastGarminError is: ");
963 msg += GetLastGarminError();
964
965 wxLogMessage(msg);
966
967 ret_val = ERR_GARMIN_GENERAL;
968 goto ret_point;
969 } else
970 ret_val = 0;
971
972 goto ret_point;
973 } else
974#endif // USE_GARMINHOST
975
976 { // Standard NMEA mode
977
978 SENTENCE snt;
979 NMEA0183 oNMEA0183;
980 oNMEA0183.TalkerID = _T ( "EC" );
981
982//FIXME if (dialog && dialog->GetProgressGauge())
983// dialog->GetProgressGauge()->SetRange(100);
984
985 if (g_GPS_Ident == _T("Generic")) {
986 if (prp->m_lat < 0.)
987 oNMEA0183.Wpl.Position.Latitude.Set(-prp->m_lat, _T ( "S" ));
988 else
989 oNMEA0183.Wpl.Position.Latitude.Set(prp->m_lat, _T ( "N" ));
990
991 if (prp->m_lon < 0.)
992 oNMEA0183.Wpl.Position.Longitude.Set(-prp->m_lon, _T ( "W" ));
993 else
994 oNMEA0183.Wpl.Position.Longitude.Set(prp->m_lon, _T ( "E" ));
995
996 oNMEA0183.Wpl.To = prp->GetName().Truncate(g_maxWPNameLength);
997
998 oNMEA0183.Wpl.Write(snt);
999 } else if (g_GPS_Ident == _T("FurunoGP3X")) {
1000 oNMEA0183.TalkerID = _T ( "PFEC," );
1001
1002 if (prp->m_lat < 0.)
1003 oNMEA0183.GPwpl.Position.Latitude.Set(-prp->m_lat, _T ( "S" ));
1004 else
1005 oNMEA0183.GPwpl.Position.Latitude.Set(prp->m_lat, _T ( "N" ));
1006
1007 if (prp->m_lon < 0.)
1008 oNMEA0183.GPwpl.Position.Longitude.Set(-prp->m_lon, _T ( "W" ));
1009 else
1010 oNMEA0183.GPwpl.Position.Longitude.Set(prp->m_lon, _T ( "E" ));
1011
1012 wxString name = prp->GetName();
1013 name += _T("000000");
1014 name.Truncate(g_maxWPNameLength);
1015
1016 oNMEA0183.GPwpl.To = name;
1017
1018 oNMEA0183.GPwpl.Write(snt);
1019 }
1020
1021 auto msg_out = std::make_shared<Nmea0183Msg>(std::string("ECWPL"),
1022 snt.Sentence.ToStdString(),
1023 address);
1024 drv_n0183->SendMessage(msg_out, address);
1025
1026 //LogOutputMessage(snt.Sentence, com_name, false);
1027
1028 wxString msg(_T("-->GPS Port:"));
1029 msg += com_name;
1030 msg += _T(" Sentence: ");
1031 msg += snt.Sentence;
1032 msg.Trim();
1033 wxLogMessage(msg);
1034
1035 if (g_GPS_Ident == _T("FurunoGP3X")) {
1036 wxString term;
1037 term.Printf(_T("$PFEC,GPxfr,CTL,E%c%c"), 0x0d, 0x0a);
1038
1039 //driver->SendSentence(term);
1040 //LogOutputMessage(term, dstr->GetPort(), false);
1041
1042 wxString msg(_T("-->GPS Port:"));
1043 msg += com_name;
1044 msg += _T(" Sentence: ");
1045 msg += term;
1046 msg.Trim();
1047 wxLogMessage(msg);
1048 }
1049
1050// if (dialog && dialog->GetProgressGauge()) {
1051// dialog->GetProgressGauge()->SetValue(100);
1052// dialog->GetProgressGauge()->Refresh();
1053// dialog->GetProgressGauge()->Update();
1054// }
1055
1056 wxMilliSleep(500);
1057
1058 // All finished with the temp port
1059 if (btempStream)
1060 registry.Deactivate(driver);
1061
1062 ret_val = 0;
1063 }
1064
1065ret_point:
1066 if (b_restoreStream) {
1067 if (old_driver){
1068 MakeCommDriver(&params_save);
1069 }
1070 }
1071
1072 return ret_val;
1073}
Definition: route.h:70