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