OpenCPN Partial API docs
Loading...
Searching...
No Matches
garmin_protocol_mgr.cpp
1/***************************************************************************
2 *
3 * Project: OpenCPN
4 * Purpose: Garmin NMEA Data Stream 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 ***************************************************************************
27 * Parts of this file were adapted from source code found in *
28 * John F. Waers (jfwaers@csn.net) public domain program MacGPS45 *
29 ***************************************************************************
30 *
31 */
32
33#include <stdlib.h>
34#include <math.h>
35#include <time.h>
36
37#include <vector>
38
39#ifndef _MSC_VER
40#include <arpa/inet.h>
41#include <netinet/tcp.h>
42#endif
43
44#include <wx/wxprec.h>
45
46#ifndef WX_PRECOMP
47#include <wx/wx.h>
48#endif // precompiled headers
49
50#include <wx/datetime.h>
51#include <wx/event.h>
52#include <wx/log.h>
53#include <wx/string.h>
54#include <wx/tokenzr.h>
55#include <wx/utils.h>
56
57#ifdef __WXMSW__
58#include <windows.h>
59#include <winioctl.h>
60#include <initguid.h>
61#include <setupapi.h>
62#endif
63
65#include "model/config_vars.h"
66#include "config.h"
67#include "model/garmin_wrapper.h"
68#include "model/garmin_protocol_mgr.h"
69#include "model/nmea_ctx_factory.h"
70#include "nmea0183.h"
71
72#ifdef __ANDROID__
73#include "androidUTIL.h"
74#endif
75
76#if !defined(NAN)
77static const long long lNaN = 0xfff8000000000000;
78#define NAN (*(double *)&lNaN)
79#endif
80
81#define N_DOG_TIMEOUT 5
82
83#ifdef __WXMSW__
84// {2C9C45C2-8E7D-4C08-A12D-816BBAE722C0}
85DEFINE_GUID(GARMIN_GUID1, 0x2c9c45c2L, 0x8e7d, 0x4c08, 0xa1, 0x2d, 0x81, 0x6b,
86 0xba, 0xe7, 0x22, 0xc0);
87#endif
88
89//----------------------------------------------------------------------------
90// Garmin Device Management
91// Handle USB and Serial Port Garmin PVT protocol data interface.
92//----------------------------------------------------------------------------
93
94#ifdef __WXMSW__
95BOOL IsUserAdmin(VOID)
96/*++
97 * Routine Description: This routine returns TRUE if the caller's
98 * process is a member of the Administrators local group. Caller is
99 * NOT expected to be impersonating anyone and is expected to be able to open
100 * its own process and process token. Arguments: None. Return Value: TRUE -
101 * Caller has Administrators local group. FALSE - Caller does not have
102 * Administrators local group. --
103 */
104{
105 BOOL b;
106 SID_IDENTIFIER_AUTHORITY NtAuthority = SECURITY_NT_AUTHORITY;
107 PSID AdministratorsGroup;
108 b = AllocateAndInitializeSid(&NtAuthority, 2, SECURITY_BUILTIN_DOMAIN_RID,
109 DOMAIN_ALIAS_RID_ADMINS, 0, 0, 0, 0, 0, 0,
110 &AdministratorsGroup);
111 if (b) {
112 if (!CheckTokenMembership(NULL, AdministratorsGroup, &b)) {
113 b = FALSE;
114 }
115 FreeSid(AdministratorsGroup);
116 }
117
118 return (b);
119}
120
121#endif
122
123BEGIN_EVENT_TABLE(GarminProtocolHandler, wxEvtHandler)
124EVT_TIMER(TIMER_GARMIN1, GarminProtocolHandler::OnTimerGarmin1)
125END_EVENT_TABLE()
126
128 SendMsgFunc send_msg_func,
129 bool bsel_usb) {
130 // m_pparent = parent;
131 m_send_msg_func = send_msg_func;
132 m_garmin_serial_thread = NULL;
133 m_garmin_usb_thread = NULL;
134 m_bOK = false;
135 m_busb = bsel_usb;
136
137 // Connect(wxEVT_OCPN_GARMIN,
138 // (wxObjectEventFunction)(wxEventFunction)&GarminProtocolHandler::OnEvtGarmin);
139
140 char pvt_on[14] = {20, 0, 0, 0, 10, 0, 0, 0, 2, 0, 0, 0, 49, 0};
141
142 char pvt_off[14] = {20, 0, 0, 0, 10, 0, 0, 0, 2, 0, 0, 0, 50, 0};
143
144#ifdef __WXMSW__
145 if (m_busb) {
146 m_usb_handle = INVALID_HANDLE_VALUE;
147
148 m_bneed_int_reset = true;
149 m_receive_state = rs_fromintr;
150 m_ndelay = 0;
151
152 wxLogMessage(_T("Searching for Garmin DeviceInterface and Device..."));
153
154 if (!FindGarminDeviceInterface()) {
155 wxLogMessage(_T(" Find:Is the Garmin USB driver installed?"));
156 } else {
157 if (!ResetGarminUSBDriver())
158 wxLogMessage(_T(" Reset:Is the Garmin USB Device plugged in?"));
159 }
160 }
161#endif
162
163 // Not using USB, so try a Garmin port open and device ident
164 if (!m_busb) {
165 m_port = port;
166
167 // Start handler thread
168 m_garmin_serial_thread =
169 new GARMIN_Serial_Thread(this, m_send_msg_func, m_port);
170
171 m_Thread_run_flag = 1;
172 m_garmin_serial_thread->Run();
173 }
174
175 TimerGarmin1.SetOwner(this, TIMER_GARMIN1);
176 TimerGarmin1.Start(100);
177}
178
179GarminProtocolHandler::~GarminProtocolHandler() {}
180
181void GarminProtocolHandler::Close(void) {
182 TimerGarmin1.Stop();
183
184 StopIOThread(true);
185 StopSerialThread();
186}
187
188void GarminProtocolHandler::StopSerialThread(void) {
189 if (m_garmin_serial_thread) {
190 wxLogMessage(_T("Stopping Garmin Serial thread"));
191 m_Thread_run_flag = 0;
192
193 int tsec = 5;
194 while ((m_Thread_run_flag >= 0) && (tsec--)) {
195 wxSleep(1);
196 }
197
198 wxString msg;
199 if (m_Thread_run_flag < 0)
200 msg.Printf(_T("Stopped in %d sec."), 5 - tsec);
201 else
202 msg.Printf(_T("Not Stopped after 5 sec."));
203 wxLogMessage(msg);
204 }
205
206 m_garmin_serial_thread = NULL;
207}
208
209void GarminProtocolHandler::StopIOThread(bool b_pause) {
210 if (b_pause) TimerGarmin1.Stop();
211
212 if (m_garmin_usb_thread) {
213 wxLogMessage(_T("Stopping Garmin USB thread"));
214 m_Thread_run_flag = 0;
215
216 int tsec = 5;
217 while ((m_Thread_run_flag >= 0) && (tsec--)) {
218 wxSleep(1);
219 }
220
221 wxString msg;
222 if (m_Thread_run_flag < 0)
223 msg.Printf(_T("Stopped in %d sec."), 5 - tsec);
224 else
225 msg.Printf(_T("Not Stopped after 5 sec."));
226 wxLogMessage(msg);
227 }
228
229 m_garmin_usb_thread = NULL;
230
231#ifdef __WXMSW__
232 if (m_busb && (m_usb_handle != INVALID_HANDLE_VALUE))
233 CloseHandle(m_usb_handle);
234 m_usb_handle = INVALID_HANDLE_VALUE;
235#endif
236
237 m_ndelay = 30; // Fix delay for next restart
238}
239
240void GarminProtocolHandler::RestartIOThread(void) {
241 wxLogMessage(_T("Restarting Garmin I/O thread"));
242 TimerGarmin1.Start(1000);
243}
244
245void GarminProtocolHandler::OnTimerGarmin1(wxTimerEvent &event) {
246 char pvt_on[14] = {20, 0, 0, 0, 10, 0, 0, 0, 2, 0, 0, 0, 49, 0};
247
248 TimerGarmin1.Stop();
249
250 if (m_busb) {
251#ifdef __WXMSW__
252 // Try to open the Garmin USB device
253 if (INVALID_HANDLE_VALUE == m_usb_handle) {
254 if (INVALID_HANDLE_VALUE != garmin_usb_start()) {
255 // Send out a request for Garmin PVT data
256 m_receive_state = rs_fromintr;
257 gusb_cmd_send((const garmin_usb_packet *)pvt_on, sizeof(pvt_on));
258
259 // Start the pump
260 m_garmin_usb_thread = new GARMIN_USB_Thread(
261 this, m_send_msg_func, (wxIntPtr)m_usb_handle, m_max_tx_size);
262 m_Thread_run_flag = 1;
263 m_garmin_usb_thread->Run();
264 }
265 }
266#endif
267 }
268
269 TimerGarmin1.Start(1000);
270}
271
272#ifdef __WXMSW__
273bool GarminProtocolHandler::ResetGarminUSBDriver() {
274 OSVERSIONINFO version_info;
275 version_info.dwOSVersionInfoSize = sizeof(OSVERSIONINFO);
276
277 if (GetVersionEx(&version_info)) {
278 if (version_info.dwMajorVersion > 5) {
279 if (!IsUserAdmin()) {
280 wxLogMessage(
281 _T(" GarminUSBDriver Reset skipped, requires elevated ")
282 _T("privileges on Vista and later...."));
283 return true;
284 }
285 }
286 }
287
288 HDEVINFO devs;
289 SP_DEVINFO_DATA devInfo;
290 SP_PROPCHANGE_PARAMS pchange;
291
292 devs = SetupDiGetClassDevs((GUID *)&GARMIN_GUID1, NULL, NULL,
293 DIGCF_PRESENT | DIGCF_INTERFACEDEVICE);
294 if (devs == INVALID_HANDLE_VALUE) return false;
295
296 devInfo.cbSize = sizeof(devInfo);
297 if (!SetupDiEnumDeviceInfo(devs, 0, &devInfo)) {
298 wxLogMessage(_T(" GarminUSBDriver Reset0 failed..."));
299 return false;
300 }
301
302 pchange.ClassInstallHeader.cbSize = sizeof(SP_CLASSINSTALL_HEADER);
303 pchange.ClassInstallHeader.InstallFunction = DIF_PROPERTYCHANGE;
304 pchange.StateChange = DICS_PROPCHANGE;
305 pchange.Scope = DICS_FLAG_CONFIGSPECIFIC;
306 pchange.HwProfile = 0;
307
308 if (!SetupDiSetClassInstallParams(devs, &devInfo, &pchange.ClassInstallHeader,
309 sizeof(pchange))) {
310 wxLogMessage(_T(" GarminUSBDriver Reset1 failed..."));
311 return false;
312 }
313
314 if (!SetupDiCallClassInstaller(DIF_PROPERTYCHANGE, devs, &devInfo)) {
315 wxLogMessage(_T(" GarminUSBDriver Reset2 failed..."));
316 return false;
317 }
318
319 wxLogMessage(_T("GarminUSBDriver Reset succeeded."));
320
321 return true;
322}
323
324bool GarminProtocolHandler::
325 FindGarminDeviceInterface() { // Search for a useable Garmin Device
326 // Interface Class
327
328 HDEVINFO hdevinfo;
329 SP_DEVINFO_DATA devInfo;
330
331 hdevinfo = SetupDiGetClassDevs((GUID *)&GARMIN_GUID1, NULL, NULL,
332 DIGCF_PRESENT | DIGCF_INTERFACEDEVICE);
333
334 if (hdevinfo != INVALID_HANDLE_VALUE) {
335 devInfo.cbSize = sizeof(devInfo);
336 if (!SetupDiEnumDeviceInfo(hdevinfo, 0, &devInfo)) {
337 return false;
338 }
339 }
340
341 return true;
342}
343
344bool GarminProtocolHandler::IsGarminPlugged() {
345 DWORD size = 0;
346
347 HDEVINFO hdevinfo;
348 SP_DEVICE_INTERFACE_DATA infodata;
349
350 // Search for the Garmin Device Interface Class
351 hdevinfo = SetupDiGetClassDevs((GUID *)&GARMIN_GUID1, NULL, NULL,
352 DIGCF_PRESENT | DIGCF_INTERFACEDEVICE);
353
354 if (hdevinfo == INVALID_HANDLE_VALUE) return INVALID_HANDLE_VALUE;
355
356 infodata.cbSize = sizeof(infodata);
357
358 bool bgarmin_unit_found =
359 (SetupDiEnumDeviceInterfaces(hdevinfo, NULL, (GUID *)&GARMIN_GUID1, 0,
360 &infodata) != 0);
361
362 if (!bgarmin_unit_found) return false;
363
364 PSP_INTERFACE_DEVICE_DETAIL_DATA pdd = NULL;
365 SP_DEVINFO_DATA devinfo;
366
367 SetupDiGetDeviceInterfaceDetail(hdevinfo, &infodata, NULL, 0, &size, NULL);
368
369 pdd = (PSP_INTERFACE_DEVICE_DETAIL_DATA)malloc(size);
370 pdd->cbSize = sizeof(SP_INTERFACE_DEVICE_DETAIL_DATA);
371
372 devinfo.cbSize = sizeof(SP_DEVINFO_DATA);
373 if (!SetupDiGetDeviceInterfaceDetail(hdevinfo, &infodata, pdd, size, NULL,
374 &devinfo)) {
375 free(pdd);
376 return false;
377 }
378
379 free(pdd);
380
381 return true;
382}
383
384HANDLE GarminProtocolHandler::garmin_usb_start() {
385 DWORD size = 0;
386
387 HDEVINFO hdevinfo;
388 SP_DEVICE_INTERFACE_DATA infodata;
389
390 // Search for the Garmin Device Interface Class
391 hdevinfo = SetupDiGetClassDevs((GUID *)&GARMIN_GUID1, NULL, NULL,
392 DIGCF_PRESENT | DIGCF_INTERFACEDEVICE);
393
394 if (hdevinfo == INVALID_HANDLE_VALUE) return INVALID_HANDLE_VALUE;
395
396 infodata.cbSize = sizeof(infodata);
397
398 bool bgarmin_unit_found =
399 (SetupDiEnumDeviceInterfaces(hdevinfo, NULL, (GUID *)&GARMIN_GUID1, 0,
400 &infodata) != 0);
401
402 if (!bgarmin_unit_found) return INVALID_HANDLE_VALUE;
403
404 wxLogMessage(_T("Garmin USB Device Found"));
405
406 if ((m_usb_handle == INVALID_HANDLE_VALUE) || (m_usb_handle == 0)) {
407 PSP_INTERFACE_DEVICE_DETAIL_DATA pdd = NULL;
408 SP_DEVINFO_DATA devinfo;
409
410 SetupDiGetDeviceInterfaceDetail(hdevinfo, &infodata, NULL, 0, &size, NULL);
411
412 pdd = (PSP_INTERFACE_DEVICE_DETAIL_DATA)malloc(size);
413 pdd->cbSize = sizeof(SP_INTERFACE_DEVICE_DETAIL_DATA);
414
415 devinfo.cbSize = sizeof(SP_DEVINFO_DATA);
416 if (!SetupDiGetDeviceInterfaceDetail(hdevinfo, &infodata, pdd, size, NULL,
417 &devinfo)) {
418 wxLogMessage(
419 _T(" SetupDiGetDeviceInterfaceDetail failed for Garmin Device..."));
420 free(pdd);
421 return INVALID_HANDLE_VALUE;
422 }
423
424 /* Whew. All that just to get something we can open... */
425 // wxString msg;
426 // msg.Printf(_T("Windows GUID for interface is
427 // %s"),pdd->DevicePath); wxLogMessage(msg);
428
429 if (m_bneed_int_reset) {
430 ResetGarminUSBDriver();
431 m_bneed_int_reset = false;
432 }
433
434 m_usb_handle = CreateFile(pdd->DevicePath, GENERIC_READ | GENERIC_WRITE, 0,
435 NULL, OPEN_EXISTING, 0, NULL);
436
437 if (m_usb_handle == INVALID_HANDLE_VALUE) {
438 wxString msg;
439 msg.Printf(_T(" (usb) CreateFile on '%s' failed"), pdd->DevicePath);
440 wxLogMessage(msg);
441 }
442
443 /*
444 DEV_BROADCAST_HANDLE filterData;
445 filterData.dbch_size = sizeof(DEV_BROADCAST_HANDLE);
446 filterData.dbch_devicetype = DBT_DEVTYP_HANDLE;
447 filterData.dbch_reserved = 0;
448 filterData.dbch_handle = m_usb_handle; // file handle used in
449 call to RegisterDeviceNotification filterData.dbch_hdevnotify = 0; //
450 returned from RegisterDeviceNotification
451
452 HDEVNOTIFY m_hDevNotify = RegisterDeviceNotification( GetHWND(),
453 &filterData, DEVICE_NOTIFY_WINDOW_HANDLE);
454 */
455
456 free(pdd);
457 }
458
459 m_max_tx_size = 0;
460
461 if (!DeviceIoControl(m_usb_handle, IOCTL_GARMIN_USB_BULK_OUT_PACKET_SIZE,
462 NULL, 0, &m_max_tx_size, GARMIN_USB_INTERRUPT_DATA_SIZE,
463 &size, NULL)) {
464 wxLogMessage(_T(" Couldn't get Garmin USB packet size."));
465 CloseHandle(m_usb_handle);
466 m_usb_handle = INVALID_HANDLE_VALUE;
467 return INVALID_HANDLE_VALUE;
468 }
469
470 if (!gusb_syncup()) {
471 CloseHandle(m_usb_handle);
472 m_usb_handle = INVALID_HANDLE_VALUE;
473 }
474
475 return m_usb_handle;
476}
477
478bool GarminProtocolHandler::gusb_syncup(void) {
479 static int unit_number;
480 static const char oinit[12] = {0, 0, 0, 0, GUSB_SESSION_START, 0, 0, 0,
481 0, 0, 0, 0};
482 garmin_usb_packet iresp;
483 int i;
484
485 /*
486 * This is our first communication with the unit.
487 */
488
489 m_receive_state = rs_fromintr;
490
491 for (i = 0; i < 25; i++) {
492 le_write16(&iresp.gusb_pkt.pkt_id[0], 0);
493 le_write32(&iresp.gusb_pkt.datasz[0], 0);
494 le_write32(&iresp.gusb_pkt.databuf[0], 0);
495
496 if (gusb_cmd_send((const garmin_usb_packet *)oinit, sizeof(oinit))) {
497 gusb_cmd_get(&iresp, sizeof(iresp));
498
499 if ((le_read16(iresp.gusb_pkt.pkt_id) == GUSB_SESSION_ACK) &&
500 (le_read32(iresp.gusb_pkt.datasz) == 4)) {
501 // unsigned serial_number =
502 // le_read32(iresp.gusb_pkt.databuf);
503 // garmin_unit_info[unit_number].serial_number =
504 // serial_number;
505 // gusb_id_unit(&garmin_unit_info[unit_number]);
506
507 unit_number++;
508
509 wxLogMessage(_T("Successful Garmin USB syncup."));
510 return true;
511 ;
512 }
513 }
514 }
515 wxLogMessage(_T(" Unable to establish Garmin USB syncup."));
516 return false;
517}
518
519int GarminProtocolHandler::gusb_cmd_send(const garmin_usb_packet *opkt,
520 size_t sz) {
521 unsigned int rv;
522
523 unsigned char *obuf = (unsigned char *)&opkt->dbuf[0];
524
525 rv = gusb_win_send(opkt, sz);
526
527 /*
528 * Recursion, when used in a disciplined way, can be our friend.
529 *
530 * The Garmin protocol requires that packets that are exactly
531 * a multiple of the max tx size be followed by a zero length
532 * packet. Do that here so we can see it in debugging traces.
533 */
534
535 if (sz && !(sz % m_max_tx_size)) {
536 wxLogMessage(_T("win_send_call1"));
537 gusb_win_send(opkt, 0);
538 wxLogMessage(_T("win_send_ret1"));
539 }
540
541 return (rv);
542}
543
544int GarminProtocolHandler::gusb_cmd_get(garmin_usb_packet *ibuf, size_t sz) {
545 int rv = 0;
546 unsigned char *buf = (unsigned char *)&ibuf->dbuf[0];
547 int orig_receive_state;
548top:
549 orig_receive_state = m_receive_state;
550 switch (m_receive_state) {
551 case rs_fromintr:
552 rv = gusb_win_get(ibuf, sz);
553 break;
554 case rs_frombulk:
555 rv = gusb_win_get_bulk(ibuf, sz);
556 break;
557 }
558
559 /* Adjust internal state and retry the read */
560 if ((rv > 0) && (ibuf->gusb_pkt.pkt_id[0] == GUSB_REQUEST_BULK)) {
561 m_receive_state = rs_frombulk;
562 goto top;
563 }
564 /*
565 * If we were reading from the bulk pipe and we just got
566 * a zero request, adjust our internal state.
567 * It's tempting to retry the read here to hide this "stray"
568 * packet from our callers, but that only works when you know
569 * there's another packet coming. That works in every case
570 * except the A000 discovery sequence.
571 */
572 if ((m_receive_state == rs_frombulk) && (rv <= 0)) {
573 m_receive_state = rs_fromintr;
574 }
575
576 return rv;
577}
578
579int GarminProtocolHandler::gusb_win_get(garmin_usb_packet *ibuf, size_t sz) {
580 DWORD rxed = GARMIN_USB_INTERRUPT_DATA_SIZE;
581 unsigned char *buf = (unsigned char *)&ibuf->dbuf[0];
582 int tsz = 0;
583
584 while (sz) {
585 /* The driver wrongly (IMO) rejects reads smaller than
586 * GARMIN_USB_INTERRUPT_DATA_SIZE
587 */
588 if (!DeviceIoControl(m_usb_handle, IOCTL_GARMIN_USB_INTERRUPT_IN, NULL, 0,
589 buf, GARMIN_USB_INTERRUPT_DATA_SIZE, &rxed, NULL)) {
590 // GPS_Serial_Error("Ioctl");
591 // fatal("ioctl\n");
592 }
593
594 buf += rxed;
595 sz -= rxed;
596 tsz += rxed;
597 if (rxed < GARMIN_USB_INTERRUPT_DATA_SIZE) break;
598 }
599 return tsz;
600}
601
602int GarminProtocolHandler::gusb_win_get_bulk(garmin_usb_packet *ibuf,
603 size_t sz) {
604 int n;
605 DWORD rsz;
606 unsigned char *buf = (unsigned char *)&ibuf->dbuf[0];
607
608 n = ReadFile(m_usb_handle, buf, sz, &rsz, NULL);
609
610 return rsz;
611}
612
613int GarminProtocolHandler::gusb_win_send(const garmin_usb_packet *opkt,
614 size_t sz) {
615 DWORD rsz;
616 unsigned char *obuf = (unsigned char *)&opkt->dbuf[0];
617
618 /* The spec warns us about making writes an exact multiple
619 * of the packet size, but isn't clear whether we can issue
620 * data in a single call to WriteFile if it spans buffers.
621 */
622 WriteFile(m_usb_handle, obuf, sz, &rsz, NULL);
623 int err = GetLastError();
624
625 // if (rsz != sz)
626 // fatal ("Error sending %d bytes. Successfully sent %ld\n", sz,
627 // rsz);
628
629 return rsz;
630}
631
632/*
633WXLRESULT GarminProtocolHandler::MSWWindowProc(WXUINT message, WXWPARAM wParam,
634WXLPARAM lParam)
635{
636 // did we process the message?
637 bool processed = false;
638
639 // the return value
640 bool rc;
641 PDEV_BROADCAST_HDR pDBHdr;
642 PDEV_BROADCAST_HANDLE pDBHandle;
643
644 // for most messages we should return 0 when we do process the message
645 rc = 0;
646
647 switch ( message )
648 {
649 case WM_DEVICECHANGE:
650 switch (wParam)
651 {
652 case DBT_DEVICEREMOVEPENDING:
653 case DBT_DEVICEREMOVECOMPLETE:
654 pDBHdr = (PDEV_BROADCAST_HDR) lParam;
655 switch (pDBHdr->dbch_devicetype)
656 case DBT_DEVTYP_HANDLE:
657 // A Device has been removed
658 // Stop the IO thread and close open handle to
659device
660
661 pDBHandle = (PDEV_BROADCAST_HANDLE) pDBHdr;
662 HANDLE target_handle = pDBHandle->dbch_handle;
663
664 wxLogMessage(_T("Garmin USB Device Removed"));
665 StopIOThread(false);
666 m_bneed_int_reset = true;
667 processed = true;
668 break;
669 }
670
671 break;
672
673 }
674
675 if ( !processed )
676 {
677 rc = (MSWDefWindowProc(message, wParam, lParam) != 0);
678 }
679
680 return rc;
681}
682*/
683#endif
684
686
687//-------------------------------------------------------------------------------------------------------------
688//
689// Garmin Serial Port Worker Thread
690//
691// This thread manages reading the positioning data stream from the declared
692// Garmin GRMN Mode serial device
693//
694//-------------------------------------------------------------------------------------------------------------
695GARMIN_Serial_Thread::GARMIN_Serial_Thread(GarminProtocolHandler *parent,
696 SendMsgFunc send_msg_func,
697 wxString port) {
698 m_parent = parent; // This thread's immediate "parent"
699 m_send_msg_func = send_msg_func;
700 m_port = port;
701
702 Create();
703}
704
705GARMIN_Serial_Thread::~GARMIN_Serial_Thread(void) {}
706
707// Entry Point
708void *GARMIN_Serial_Thread::Entry() {
709 // m_parent->SetSecThreadActive(); // I am alive
710 m_bdetected = false;
711 m_bconnected = false;
712
713 bool not_done = true;
714 wxDateTime last_rx_time;
715
716#ifdef USE_GARMINHOST
717 // The main loop
718
719 while ((not_done) && (m_parent->m_Thread_run_flag > 0)) {
720 if (TestDestroy()) {
721 not_done = false; // smooth exit
722 goto thread_exit_2;
723 }
724
725 while (!m_bdetected) {
726 // Try to init the port once
727 int v_init = Garmin_GPS_Init(m_port);
728 if (v_init < 0) { // Open failed, so sleep and try again
729 for (int i = 0; i < 4; i++) {
730 wxSleep(1);
731 if (TestDestroy()) goto thread_exit;
732 if (!m_parent->m_Thread_run_flag) goto thread_exit;
733 }
734 } else
735 m_bdetected = true;
736 } // while not detected
737
738 // Detected OK
739
740 // Start PVT packet transmission
741 if (!m_bconnected) {
742 if (!Garmin_GPS_PVT_On(m_port)) {
743 m_bdetected = false; // error, would not accept PVT On
744 m_bconnected = false;
745 } else
746 m_bconnected = true;
747 }
748
749 if (m_bconnected) {
750 D800_Pvt_Data_Type_Aligned *ppvt = &mypvt;
751 int ret = Garmin_GPS_GetPVT(&ppvt);
752 if (ret > 0) {
753 if ((mypvt.fix) >= 2 && (mypvt.fix <= 5)) {
754 // Synthesize an NMEA GMRMC message
755 SENTENCE snt;
756 NMEA0183 oNMEA0183(NmeaCtxFactory());
757 oNMEA0183.TalkerID = _T ( "GM" );
758
759 if (mypvt.lat < 0.)
760 oNMEA0183.Rmc.Position.Latitude.Set(-mypvt.lat, _T ( "S" ));
761 else
762 oNMEA0183.Rmc.Position.Latitude.Set(mypvt.lat, _T ( "N" ));
763
764 if (mypvt.lon < 0.)
765 oNMEA0183.Rmc.Position.Longitude.Set(-mypvt.lon, _T ( "W" ));
766 else
767 oNMEA0183.Rmc.Position.Longitude.Set(mypvt.lon, _T ( "E" ));
768
769 /* speed over ground */
770 double sog =
771 sqrt(mypvt.east * mypvt.east + mypvt.north * mypvt.north) * 3.6 /
772 1.852;
773 oNMEA0183.Rmc.SpeedOverGroundKnots = sog;
774
775 /* course over ground */
776 double course = atan2(mypvt.east, mypvt.north);
777 if (course < 0) course += 2 * PI;
778 double cog = course * 180 / PI;
779 oNMEA0183.Rmc.TrackMadeGoodDegreesTrue = cog;
780
781 oNMEA0183.Rmc.IsDataValid = NTrue;
782
783 oNMEA0183.Rmc.Write(snt);
784
785 // Send message...
786 auto msg = snt.Sentence.ToStdString();
787 m_send_msg_func(std::vector<unsigned char>(msg.begin(), msg.end()));
788
789 last_rx_time = wxDateTime::Now();
790 }
791 } else {
792 wxDateTime now = wxDateTime::Now();
793 if (last_rx_time.IsValid()) {
794 wxTimeSpan delta_time = now - last_rx_time;
795 if (delta_time.GetSeconds() > 5) {
796 m_bdetected = false;
797 m_bconnected = false;
798 Garmin_GPS_ClosePortVerify();
799 }
800 }
801 }
802 }
803 } // the big while...
804
805thread_exit_2:
806
807 Garmin_GPS_PVT_Off(m_port);
808 Garmin_GPS_ClosePortVerify();
809
810 while ((not_done) && (m_parent->m_Thread_run_flag > 0)) {
811 wxSleep(1);
812 if (TestDestroy()) {
813 not_done = false; // smooth exit
814 goto thread_exit;
815 }
816 }
817
818thread_exit:
819
820#endif // #ifdef USE_GARMINHOST
821
822 m_parent->m_Thread_run_flag = -1; // in GarminProtocolHandler
823 return 0;
824}
825
826//-------------------------------------------------------------------------------------------------------------
827// GARMIN_USB_Thread Implementation
828//-------------------------------------------------------------------------------------------------------------
829#if 1
830GARMIN_USB_Thread::GARMIN_USB_Thread(GarminProtocolHandler *parent,
831 SendMsgFunc send_msg_func,
832 unsigned int device_handle,
833 size_t max_tx_size) {
834 m_parent = parent; // This thread's immediate "parent"
835 m_send_msg_func = send_msg_func;
836 m_max_tx_size = max_tx_size;
837
838#ifdef __WXMSW__
839 m_usb_handle = (HANDLE)(device_handle & 0xffff);
840#endif
841
842 Create();
843}
844
845GARMIN_USB_Thread::~GARMIN_USB_Thread() {}
846
847void *GARMIN_USB_Thread::Entry() {
848 garmin_usb_packet iresp = {{0}};
849 int n_short_read = 0;
850 m_receive_state = rs_fromintr;
851
852 // Here comes the big while loop
853 while (m_parent->m_Thread_run_flag > 0) {
854 if (TestDestroy()) goto thread_prexit; // smooth exit
855
856 // Get one packet
857
858 int nr = gusb_cmd_get(&iresp, sizeof(iresp));
859
860 if (iresp.gusb_pkt.pkt_id[0] == GUSB_RESPONSE_SDR) // Satellite Data Record
861 {
862 unsigned char *t = (unsigned char *)&(iresp.gusb_pkt.databuf[0]);
863 for (int i = 0; i < 12; i++) {
864 m_sat_data[i].svid = *t++;
865 m_sat_data[i].snr = ((*t) << 8) + *(t + 1);
866 t += 2;
867 m_sat_data[i].elev = *t++;
868 m_sat_data[i].azmth = ((*t) << 8) + *(t + 1);
869 t += 2;
870 m_sat_data[i].status = *t++;
871 }
872
873 m_nSats = 0;
874 for (int i = 0; i < 12; i++) {
875 if (m_sat_data[i].svid != 255) m_nSats++;
876 }
877
878 // Synthesize an NMEA GMGSV message
879 SENTENCE snt;
880 NMEA0183 oNMEA0183(NmeaCtxFactory());
881 oNMEA0183.TalkerID = _T ( "GM" );
882 oNMEA0183.Gsv.SatsInView = m_nSats;
883
884 oNMEA0183.Gsv.Write(snt);
885 wxString msg = snt.Sentence;
886
887 // and send message.
888 m_send_msg_func(std::vector<unsigned char>(msg.begin(), msg.end()));
889 }
890
891 if (iresp.gusb_pkt.pkt_id[0] == GUSB_RESPONSE_PVT) // PVT Data Record
892 {
893 D800_Pvt_Data_Type *ppvt =
894 (D800_Pvt_Data_Type *)&(iresp.gusb_pkt.databuf[0]);
895
896 if ((ppvt->fix) >= 2 && (ppvt->fix <= 5)) {
897 // Synthesize an NMEA GMRMC message
898 SENTENCE snt;
899 NMEA0183 oNMEA0183(NmeaCtxFactory());
900 oNMEA0183.TalkerID = _T ( "GM" );
901
902 if (ppvt->lat < 0.)
903 oNMEA0183.Rmc.Position.Latitude.Set(-ppvt->lat * 180. / PI,
904 _T ( "S" ));
905 else
906 oNMEA0183.Rmc.Position.Latitude.Set(ppvt->lat * 180. / PI,
907 _T ( "N" ));
908
909 if (ppvt->lon < 0.)
910 oNMEA0183.Rmc.Position.Longitude.Set(-ppvt->lon * 180. / PI,
911 _T ( "W" ));
912 else
913 oNMEA0183.Rmc.Position.Longitude.Set(ppvt->lon * 180. / PI,
914 _T ( "E" ));
915
916 /* speed over ground */
917 double sog = sqrt(ppvt->east * ppvt->east + ppvt->north * ppvt->north) *
918 3.6 / 1.852;
919 oNMEA0183.Rmc.SpeedOverGroundKnots = sog;
920
921 /* course over ground */
922 double course = atan2(ppvt->east, ppvt->north);
923 if (course < 0) course += 2 * PI;
924 double cog = course * 180 / PI;
925 oNMEA0183.Rmc.TrackMadeGoodDegreesTrue = cog;
926
927 oNMEA0183.Rmc.IsDataValid = NTrue;
928
929 oNMEA0183.Rmc.Write(snt);
930 wxString msg = snt.Sentence;
931 m_send_msg_func(std::vector<unsigned char>(msg.begin(), msg.end()));
932 }
933 }
934 }
935thread_prexit:
936 m_parent->m_Thread_run_flag = -1;
937 return 0;
938}
939
940int GARMIN_USB_Thread::gusb_cmd_get(garmin_usb_packet *ibuf, size_t sz) {
941 int rv = 0;
942 unsigned char *buf = (unsigned char *)&ibuf->dbuf[0];
943 int orig_receive_state;
944top:
945 orig_receive_state = m_receive_state;
946 switch (m_receive_state) {
947 case rs_fromintr:
948 rv = gusb_win_get(ibuf, sz);
949 break;
950 case rs_frombulk:
951 rv = gusb_win_get_bulk(ibuf, sz);
952 break;
953 }
954
955 /* Adjust internal state and retry the read */
956 if ((rv > 0) && (ibuf->gusb_pkt.pkt_id[0] == GUSB_REQUEST_BULK)) {
957 m_receive_state = rs_frombulk;
958 goto top;
959 }
960 /*
961 * If we were reading from the bulk pipe and we just got
962 * a zero request, adjust our internal state.
963 * It's tempting to retry the read here to hide this "stray"
964 * packet from our callers, but that only works when you know
965 * there's another packet coming. That works in every case
966 * except the A000 discovery sequence.
967 */
968 if ((m_receive_state == rs_frombulk) && (rv <= 0)) {
969 m_receive_state = rs_fromintr;
970 }
971
972 return rv;
973}
974
975int GARMIN_USB_Thread::gusb_win_get(garmin_usb_packet *ibuf, size_t sz) {
976 int tsz = 0;
977#ifdef __WXMSW__
978 DWORD rxed = GARMIN_USB_INTERRUPT_DATA_SIZE;
979 unsigned char *buf = (unsigned char *)&ibuf->dbuf[0];
980
981 while (sz) {
982 /* The driver wrongly (IMO) rejects reads smaller than
983 * GARMIN_USB_INTERRUPT_DATA_SIZE
984 */
985 if (!DeviceIoControl(m_usb_handle, IOCTL_GARMIN_USB_INTERRUPT_IN, NULL, 0,
986 buf, GARMIN_USB_INTERRUPT_DATA_SIZE, &rxed, NULL)) {
987 // GPS_Serial_Error("Ioctl");
988 // fatal("ioctl\n");
989 }
990
991 buf += rxed;
992 sz -= rxed;
993 tsz += rxed;
994 if (rxed < GARMIN_USB_INTERRUPT_DATA_SIZE) break;
995 }
996
997#endif
998 return tsz;
999}
1000
1001int GARMIN_USB_Thread::gusb_win_get_bulk(garmin_usb_packet *ibuf, size_t sz) {
1002 int n;
1003 int ret_val = 0;
1004#ifdef __WXMSW__
1005 DWORD rsz;
1006 unsigned char *buf = (unsigned char *)&ibuf->dbuf[0];
1007
1008 n = ReadFile(m_usb_handle, buf, sz, &rsz, NULL);
1009 ret_val = rsz;
1010#endif
1011
1012 return ret_val;
1013}
1014#endif
NMEA0183 serial driver.