Subversion Repositories public

Rev

Go to most recent revision | Details | Last modification | View Log | RSS feed

Rev Author Line No. Line
93 andreas 1
#include "config.h"
2
#include <stdio.h>
101 andreas 3
#include <stdlib.h>
4
#include <errno.h>
93 andreas 5
#include <string.h>
6
#include <ctype.h>
101 andreas 7
#include <unistd.h>
8
#include <sys/stat.h>
9
#include <fcntl.h>
10
#include <sys/select.h>
11
#include <sys/signal.h>
12
#include <time.h>
93 andreas 13
#include <usb.h>
14
#include "garmin.h"
15
 
101 andreas 16
/* #if defined (HAVE_SYS_TERMIOS_H)
17
   #include <sys/termios.h>
18
#else
19
   #if defined (HAVE_TERMIOS_H) */
20
      #include <termios.h>
21
/*   #endif
22
#endif
23
*/
93 andreas 24
#define INTR_TIMEOUT  3000
25
#define BULK_TIMEOUT  3000
26
 
101 andreas 27
#ifndef TRUE
28
   #define TRUE 1
29
#endif
93 andreas 30
 
101 andreas 31
#ifndef FALSE
32
   #define FALSE 0
33
#endif
34
 
35
/* something magic about 64, garmin driver will not return more than
36
 * 64 at a time. If you read less than 64 bytes the next read will
37
 * just get the last of the 64 byte buffer.
38
 */
39
#define ASYNC_DATA_SIZE 64
40
#define PRIV_PKTID_SET_MODE     2
41
#define PRIV_PKTID_INFO_RESP    4
42
#define PRIV_PKTID_INFO_REQ     3
43
#define GARMIN_LAYERID_PRIVATE  0x01106E4B
44
 
45
const char *USBdevice = NULL;
46
int method = 0;		/* 0 = Read directly from USB-Device, 1 = read from special device */
47
struct termios ttyset, ttyset_old;
48
static fd_set all_fds;
49
void signal_handler_IO (int status);   /* definition of signal handler */
50
int wait_flag = TRUE;                    /* TRUE while no signal received */
51
 
52
int garmin_set_speed(garmin_unit *garmin, unsigned int speed, unsigned int stopbits);
53
 
54
void garmin_set_device(const char *device)
55
{
56
	USBdevice = device;
57
}
58
 
59
void garmin_set_method(int mth)
60
{
61
	method = (mth != 0) ? 1 : 0;
62
}
63
 
93 andreas 64
/* Close the USB connection with the Garmin device. */
65
 
101 andreas 66
int garmin_close(garmin_unit *garmin)
93 andreas 67
{
101 andreas 68
	if (method && garmin->usb.fd != -1)
69
	{
70
	   if (isatty(garmin->usb.fd))
71
	   {
72
	      /* force hangup on close on systems that don't do HUPCL properly */
73
	      cfsetispeed(&ttyset, (speed_t)B0);
74
	      cfsetospeed(&ttyset, (speed_t)B0);
75
	      tcsetattr(garmin->usb.fd, TCSANOW, &ttyset);
76
	   }
93 andreas 77
 
101 andreas 78
	   /* this is the clean way to do it */
79
	   ttyset_old.c_cflag |= HUPCL;
80
	   tcsetattr(garmin->usb.fd, TCSANOW, &ttyset_old);
81
	   close(garmin->usb.fd);
82
	   garmin->usb.fd = -1;
83
	   USBdevice = NULL;
84
	}
85
	else if (garmin->usb.handle != NULL )
86
	{
87
	   usb_release_interface(garmin->usb.handle,0);
88
	   usb_close(garmin->usb.handle);
89
	   garmin->usb.handle = NULL;
90
	}
91
 
92
	return 0;
93 andreas 93
}
94
 
95
/* 
96
   Open the USB connection with the first Garmin device we find.  Eventually,
97
   I'd like to add the ability to select a particular device.
98
*/
99
 
101 andreas 100
int garmin_open(garmin_unit *garmin)
93 andreas 101
{
101 andreas 102
struct usb_bus *     bi;
103
struct usb_device *  di;
104
int                  i;
105
static unsigned int rates[] = {0, 4800, 9600, 19200, 38400, 57600};
106
garmin_packet p;
107
struct sigaction saio;
93 andreas 108
 
101 andreas 109
	if (method && garmin->usb.fd == -1)
110
	{
111
	   /* check for USB serial drivers -- very Linux-specific */
112
	   if (access("/sys/module/garmin_gps", R_OK) != 0)
113
	   {
114
	      fprintf(stderr, "garmin_gps not active.\n");
115
	      return 0;
116
	   }
93 andreas 117
 
101 andreas 118
	   if ((garmin->usb.fd = open(USBdevice, O_RDWR | O_NOCTTY | O_NONBLOCK)) == -1)
119
	      return 0;
93 andreas 120
 
101 andreas 121
	   if (isatty(garmin->usb.fd))
122
	   {
123
	      /* install the signal handler before making the device asynchronous */
124
	      memset (&saio, 0, sizeof(struct sigaction));
125
	      saio.sa_handler = signal_handler_IO;
126
/*	      saio.sa_mask = 0;
127
	      saio.sa_flags = 0;
128
	      saio.sa_restorer = NULL; */
129
	      sigaction(SIGIO, &saio, NULL);
93 andreas 130
 
101 andreas 131
	      /* allow the process to receive SIGIO */
132
	      fcntl(garmin->usb.fd, F_SETOWN, getpid());
133
	      /* Make the file descriptor asynchronous (the manual page says only
134
		 O_APPEND and O_NONBLOCK, will work with F_SETFL...) */
135
	      fcntl(garmin->usb.fd, F_SETFL, FASYNC);
136
	      tcgetattr(garmin->usb.fd, &ttyset_old);	/* save current port settings */
137
	      ttyset.c_cflag &= ~(PARENB | CRTSCTS);
138
	      ttyset.c_cflag |= CREAD | CLOCAL | B9600;
139
	      ttyset.c_iflag = ttyset.c_oflag = ttyset.c_lflag = (tcflag_t) 0;
140
	      ttyset.c_oflag = (ONLCR);
93 andreas 141
 
101 andreas 142
	      tcflush(garmin->usb.fd, TCIFLUSH);
143
	      tcsetattr(garmin->usb.fd, TCSANOW, &ttyset);
144
	   }
145
	   else
146
	   {
147
	      close(garmin->usb.fd);
148
	      garmin->usb.fd = -1;
149
	      return 0;
150
	   }
93 andreas 151
 
101 andreas 152
	   return 1;
153
	}
154
	else if (!method && garmin->usb.handle == NULL)
155
	{
156
	   usb_init();
157
	   usb_find_busses();
158
	   usb_find_devices();
159
 
160
	   for ( bi = usb_busses; bi != NULL; bi = bi->next )
161
	   {
162
	      for ( di = bi->devices; di != NULL; di = di->next )
163
	      {
164
	         if ( di->descriptor.idVendor  == GARMIN_USB_VID &&
165
			di->descriptor.idProduct == GARMIN_USB_PID )
166
		 {
167
 
168
		    if ( garmin->verbose != 0 )
169
		    {
170
		       fprintf(stderr, "[garmin] found VID %04x, PID %04x on %s/%s\n",
171
			di->descriptor.idVendor,
172
			di->descriptor.idProduct,
173
			bi->dirname,
174
			di->filename);
175
		    }
176
 
177
		    garmin->usb.handle = usb_open(di);
178
		    garmin->usb.read_bulk = 0;
179
 
180
		    if ( garmin->usb.handle == NULL )
181
		    {
182
		       fprintf(stderr, "usb_open failed: %s\n",usb_strerror());
183
		       return 0;
184
		    }
185
 
186
		    if ( usb_set_configuration(garmin->usb.handle,1) < 0 )
187
		    {
188
		       fprintf(stderr, "usb_set_configuration failed: %s\n",usb_strerror());
189
		       return 0;
190
		    }
191
 
192
		    if ( usb_claim_interface(garmin->usb.handle,0) < 0 )
193
		    {
194
		       fprintf(stderr, "usb_claim_interface failed: %s\n",usb_strerror());
195
		       return 0;
196
		    }
197
 
198
		    for ( i = 0; i < di->config->interface->altsetting->bNumEndpoints; i++ )
199
		    {
200
		     struct usb_endpoint_descriptor * ep;
201
 
202
		       ep = &di->config->interface->altsetting->endpoint[i];
203
 
204
		       switch ( ep->bmAttributes & USB_ENDPOINT_TYPE_MASK )
205
		       {
206
			  case USB_ENDPOINT_TYPE_BULK:
207
			     if ( ep->bEndpointAddress & USB_ENDPOINT_DIR_MASK )
208
			     {
209
			        garmin->usb.bulk_in = ep->bEndpointAddress & USB_ENDPOINT_ADDRESS_MASK;
210
			     }
211
			     else
212
			     {
213
			        garmin->usb.bulk_out = ep->bEndpointAddress & USB_ENDPOINT_ADDRESS_MASK;
214
			     }
215
			  break;
216
 
217
			  case USB_ENDPOINT_TYPE_INTERRUPT:
218
			     if ( ep->bEndpointAddress & USB_ENDPOINT_DIR_MASK )
219
			     {
220
			        garmin->usb.intr_in = ep->bEndpointAddress & USB_ENDPOINT_ADDRESS_MASK;
221
			     }
222
			  break;
223
 
224
			  default:
225
			     break;
226
		       }
227
		    }
228
 
229
		    break;
230
	         }
93 andreas 231
	      }
232
 
101 andreas 233
	      if ( garmin->usb.handle != NULL )
234
		 break;
235
	   }
93 andreas 236
	}
237
 
101 andreas 238
	return (garmin->usb.handle != NULL);
93 andreas 239
}
240
 
101 andreas 241
void signal_handler_IO (int status)
242
{
243
	wait_flag = FALSE;
244
}
93 andreas 245
 
101 andreas 246
int garmin_set_speed(garmin_unit *garmin, unsigned int speed, unsigned int stopbits)
93 andreas 247
{
101 andreas 248
unsigned int rate;
249
 
250
	if (speed < 300)
251
	   rate = B0;
252
	else if (speed < 1200)
253
	   rate = B300;
254
	else if (speed < 2400)
255
	   rate = B1200;
256
	else if (speed < 4800)
257
	   rate = B2400;
258
	else if (speed < 9600)
259
	   rate = B4800;
260
	else if (speed < 19200)
261
	   rate = B9600;
262
	else if (speed < 38400)
263
	   rate = B19200;
264
	else if (speed < 57600)
265
	   rate = B38400;
266
	else if (speed < 115200)
267
	   rate = B57600;
268
	else
269
	   rate = B115200;
270
 
271
	tcflush(garmin->usb.fd, TCIOFLUSH); /* toss stale data */
272
 
273
	if (rate != cfgetispeed(&ttyset) || stopbits != 1)
274
	{
275
	   cfsetispeed(&ttyset, (speed_t)rate);
276
	   cfsetospeed(&ttyset, (speed_t)rate);
277
	   ttyset.c_cflag &=~ CSIZE;
278
	   ttyset.c_cflag |= (CSIZE & (stopbits == 2 ? CS7 : CS8));
279
 
280
	   if (tcsetattr(garmin->usb.fd, TCSANOW, &ttyset) != 0)
281
	      return 0;
282
 
283
	   tcflush(garmin->usb.fd, TCIOFLUSH);
284
	}
285
 
286
/*	if ((session->packet_type = packet_sniff(session)) == BAD_PACKET)
287
	   return 0;
288
*/
289
	return 1;
93 andreas 290
}
291
 
101 andreas 292
uint8 garmin_packet_type(garmin_packet *p)
293
{
294
	return p->packet.type;
295
}
93 andreas 296
 
101 andreas 297
 
298
uint16 garmin_packet_id(garmin_packet *p)
93 andreas 299
{
101 andreas 300
	return get_uint16(p->packet.id);
93 andreas 301
}
302
 
303
 
101 andreas 304
uint32 garmin_packet_size(garmin_packet *p)
93 andreas 305
{
101 andreas 306
	return get_uint32(p->packet.size);
93 andreas 307
}
308
 
309
 
101 andreas 310
uint8 *garmin_packet_data(garmin_packet *p)
93 andreas 311
{
101 andreas 312
	return p->packet.data;
93 andreas 313
}
314
 
315
 
101 andreas 316
int garmin_packetize(garmin_packet *p, uint16 id, uint32 size, uint8 *data)
93 andreas 317
{
101 andreas 318
int ok = 0;
93 andreas 319
 
101 andreas 320
	if (size + PACKET_HEADER_SIZE < sizeof(garmin_packet))
321
	{
322
	   p->packet.type       = GARMIN_PROTOCOL_APP;
323
	   p->packet.reserved1  = 0;
324
	   p->packet.reserved2  = 0;
325
	   p->packet.reserved3  = 0;
326
	   p->packet.id[0]      = id;
327
	   p->packet.id[1]      = id >> 8;
328
	   p->packet.reserved4  = 0;
329
	   p->packet.reserved5  = 0;
330
	   p->packet.size[0]    = size;
331
	   p->packet.size[1]    = size >> 8;
332
	   p->packet.size[2]    = size >> 16;
333
	   p->packet.size[3]    = size >> 24;
93 andreas 334
 
101 andreas 335
	   if ( size > 0 && data != NULL )
336
	   {
337
	      memcpy(p->packet.data,data,size);
338
	   }
339
 
340
	   ok = 1;
341
	}
342
 
343
	return ok;
93 andreas 344
}
345
 
346
 
101 andreas 347
int garmin_read(garmin_unit *garmin, garmin_packet *p)
93 andreas 348
{
101 andreas 349
int r = -1;
350
int cnt = 0;
351
int bLen = 0;
352
struct timespec delay, rem;
353
fd_set fds, rfds;
354
struct timeval tv;
355
int sel_ret = 0;
356
int ok = 0;
93 andreas 357
 
101 andreas 358
	if (garmin->usb.fd == -1 && garmin->usb.handle == NULL)
359
	   garmin_open(garmin);
93 andreas 360
 
101 andreas 361
	if (method && garmin->usb.fd != -1)
362
	{
363
	   long theBytesReturned = 0;
364
	   char *buf = (char *)p->data;
365
 
366
	   for(cnt = 0 ; cnt < 10 ; cnt++)
367
	   {
368
	      if (wait_flag != FALSE)
369
	      {
370
		 cnt--;
371
		 usleep (100000);
372
		 continue;
373
	      }
374
 
375
	      /* Read async data until the driver returns less than the
376
	       * max async data size, which signifies the end of a packet
377
	       * not optimal, but given the speed and packet nature of
378
	       * the USB not too bad for a start
379
	       */
380
	      wait_flag = TRUE;
381
 
382
	      theBytesReturned = read(garmin->usb.fd, buf + bLen, ASYNC_DATA_SIZE);
383
 
384
	      if (0 > theBytesReturned)
385
	      {
386
		 /* read error...
387
		  * or EAGAIN, but O_NONBLOCK is never set
388
		  */
389
		 fprintf(stderr, "Read error=%ld, errno=%d\n", theBytesReturned, errno);
390
		 continue;
391
	      }
392
 
393
	      fprintf(stderr, "got %ld bytes\n", theBytesReturned);
394
	      bLen += theBytesReturned;
395
 
396
	      if (theBytesReturned < ASYNC_DATA_SIZE)
397
	      {
398
		 /* zero length, or short, read is a flag for got the whole packet */
399
		 break;
400
	      }
401
 
402
	      if (256 <= bLen)
403
	      {
404
		 /* really bad read error... */
405
		 bLen = 0;
406
		 fprintf(stderr, "Packet too long!\n");
407
		 break;
408
	      }
409
 
410
	      delay.tv_sec = 0;
411
	      delay.tv_nsec = 3330000L;
412
 
413
	      while (nanosleep(&delay, &rem) < 0)
414
	         continue;
415
	   }
416
	}
417
	else if (garmin->usb.handle != NULL)
418
	{
419
	   if (garmin->usb.read_bulk == 0)
420
	   {
421
	      r = usb_interrupt_read(garmin->usb.handle,
93 andreas 422
			     garmin->usb.intr_in,
423
			     p->data,
424
			     sizeof(garmin_packet),
425
			     INTR_TIMEOUT);
101 andreas 426
	      /* 
427
	       * If the packet is a "Pid_Data_Available" packet, we need to read
428
	       * from the bulk endpoint until we get an empty packet.
429
	       */
430
 
431
	      if (garmin_packet_type(p) == GARMIN_PROTOCOL_USB &&
432
			garmin_packet_id(p) == Pid_Data_Available)
433
	      {
434
		 /* FIXME!!! */
435
		 fprintf(stderr, "Received a Pid_Data_Available from the unit!\n");
436
	      }
437
	   }
438
	   else
439
	   {
440
	      r = usb_bulk_read(garmin->usb.handle,
93 andreas 441
			garmin->usb.bulk_in,
442
			p->data,
443
			sizeof(garmin_packet),
444
			BULK_TIMEOUT);
101 andreas 445
	   }
446
	}
93 andreas 447
 
101 andreas 448
	if (garmin->verbose != 0 && r >= 0)
449
	{
450
	   garmin_print_packet(p, GARMIN_DIR_READ, stdout);
451
	}
93 andreas 452
 
101 andreas 453
	return r;
93 andreas 454
}
455
 
456
 
101 andreas 457
int garmin_write(garmin_unit *garmin, garmin_packet *p)
93 andreas 458
{
101 andreas 459
int r = -1;
460
int s = garmin_packet_size(p) + PACKET_HEADER_SIZE;
93 andreas 461
 
101 andreas 462
	if (garmin->usb.fd == -1 && garmin->usb.handle == NULL)
463
	   garmin_open(garmin);
93 andreas 464
 
101 andreas 465
	if (garmin->usb.handle != NULL || garmin->usb.fd != -1)
466
	{
467
	   if (garmin->verbose != 0)
468
	   {
469
	      garmin_print_packet(p, GARMIN_DIR_WRITE, stdout);
470
	   }
93 andreas 471
 
101 andreas 472
	   if (method)
473
	      r = write(garmin->usb.fd, p->data, s);
474
	   else
475
	      r = usb_bulk_write(garmin->usb.handle,
93 andreas 476
		       garmin->usb.bulk_out,
477
		       p->data,
478
		       s,
479
		       BULK_TIMEOUT);
101 andreas 480
 
481
	   if (r != s)
482
	   {
483
	      if (method)
484
		 fprintf(stderr, "Write to device failed!\n");
485
	      else
486
		 fprintf(stderr, "usb_bulk_write failed: %s\n", usb_strerror());
487
 
488
	      return 0;
489
	   }
490
	}
491
 
492
	return r;
93 andreas 493
}
494
 
495
 
101 andreas 496
uint32 garmin_start_session(garmin_unit *garmin)
93 andreas 497
{
101 andreas 498
garmin_packet p;
499
int i;
500
fd_set fds, rfds;
501
struct timeval tv;
502
int sel_ret = 0;
503
int ok = 0;
93 andreas 504
 
101 andreas 505
	garmin_packetize(&p, Pid_Start_Session, 0, NULL);
506
	p.packet.type = GARMIN_PROTOCOL_USB;
93 andreas 507
 
101 andreas 508
	if (method && garmin->usb.fd != -1)
509
	{
510
	   FD_ZERO(&fds);
511
	   FD_SET(garmin->usb.fd, &fds);
512
	}
93 andreas 513
 
101 andreas 514
	garmin_write(garmin, &p);
515
	garmin_write(garmin, &p);
516
	garmin_write(garmin, &p);
517
 
518
	if (garmin_read(garmin, &p) == 16)
519
	{
520
	   garmin->id = get_uint32(p.packet.data);
521
	}
522
	else
523
	{
524
	   garmin->id = 0;
525
	}
526
 
527
	return garmin->id;
93 andreas 528
}
529
 
530
 
101 andreas 531
void garmin_print_packet(garmin_packet *p, int dir, FILE *fp)
93 andreas 532
{
101 andreas 533
int    i;
534
int    j;
535
uint32 s;
536
char   hex[128];
537
char   dec[128];
93 andreas 538
 
101 andreas 539
	s = garmin_packet_size(p);
93 andreas 540
 
101 andreas 541
	switch ( dir )
542
	{
543
	   case GARMIN_DIR_READ:   fprintf(fp,"<read");   break;
544
	   case GARMIN_DIR_WRITE:  fprintf(fp,"<write");  break;
545
	   default:                fprintf(fp,"<packet");        break;
546
	}
93 andreas 547
 
101 andreas 548
	fprintf(fp," type=\"0x%02x\" id=\"0x%04x\" size=\"%u\"",
93 andreas 549
	  garmin_packet_type(p),garmin_packet_id(p),s);
101 andreas 550
 
551
	if (s > 0)
552
	{
553
	   fprintf(fp,">\n");
554
 
555
	   for ( i = 0, j = 0; i < s; i++ )
556
	   {
557
	      sprintf(&hex[(3*(i&0x0f))]," %02x",p->packet.data[i]);
558
	      sprintf(&dec[(i&0x0f)],"%c",
559
		(isalnum(p->packet.data[i]) ||
560
		ispunct(p->packet.data[i]) ||
561
		p->packet.data[i] == ' ') ?
562
		p->packet.data[i] : '_');
563
 
564
	      if ( (i & 0x0f) == 0x0f )
565
	      {
566
		 j = 0;
567
		 fprintf(fp,"[%04x] %-54s %s\n",i-15,hex,dec);
568
	      }
569
	      else
570
	      {
571
		 j++;
572
	      }
573
	   }
574
 
575
	   if (j > 0)
576
	   {
577
	      fprintf(fp,"[%04x] %-54s %s\n",s-(s & 0x0f),hex,dec);
578
	   }
579
 
580
	   switch (dir)
581
	   {
582
	      case GARMIN_DIR_READ:   fprintf(fp,"</read>\n");   break;
583
	      case GARMIN_DIR_WRITE:  fprintf(fp,"</write>\n");  break;
584
	      default:                fprintf(fp,"</packet>\n"); break;
585
	   }
586
	}
587
	else
588
	{
589
	   fprintf(fp,"/>\n");
590
	}
93 andreas 591
}