Subversion Repositories public

Rev

Rev 101 | 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>
3
#include <string.h>
4
#include <ctype.h>
5
#include <usb.h>
6
#include "garmin.h"
7
 
8
 
9
#define INTR_TIMEOUT  3000
10
#define BULK_TIMEOUT  3000
11
 
12
 
13
/* Close the USB connection with the Garmin device. */
14
 
15
int
16
garmin_close ( garmin_unit * garmin )
17
{
18
  if ( garmin->usb.handle != NULL ) {
19
    usb_release_interface(garmin->usb.handle,0);
20
    usb_close(garmin->usb.handle);
21
    garmin->usb.handle = NULL;
22
  }
23
 
24
  return 0;
25
}
26
 
27
 
28
/* 
29
   Open the USB connection with the first Garmin device we find.  Eventually,
30
   I'd like to add the ability to select a particular device.
31
*/
32
 
33
int
34
garmin_open ( garmin_unit * garmin )
35
{
36
  struct usb_bus *     bi;
37
  struct usb_device *  di;
38
  int                  i;
39
 
40
  if ( garmin->usb.handle == NULL ) {
41
    usb_init();
42
    usb_find_busses();
43
    usb_find_devices();
44
 
45
    for ( bi = usb_busses; bi != NULL; bi = bi->next ) {
46
      for ( di = bi->devices; di != NULL; di = di->next ) {
47
	if ( di->descriptor.idVendor  == GARMIN_USB_VID &&
48
	     di->descriptor.idProduct == GARMIN_USB_PID ) {
49
 
50
	  if ( garmin->verbose != 0 ) {
51
	    printf("[garmin] found VID %04x, PID %04x on %s/%s\n",
52
		   di->descriptor.idVendor,
53
		   di->descriptor.idProduct,
54
		   bi->dirname,
55
		   di->filename);
56
	  }
57
 
58
	  garmin->usb.handle = usb_open(di);
59
	  garmin->usb.read_bulk = 0;
60
	  if ( garmin->usb.handle == NULL ) {
61
	    printf("usb_open failed: %s\n",usb_strerror());
62
	    exit(1);
63
	  }
64
 
65
	  if ( usb_set_configuration(garmin->usb.handle,1) < 0 ) {
66
	    printf("usb_set_configuration failed: %s\n",usb_strerror());
67
	    exit(1);
68
	  }
69
 
70
	  if ( usb_claim_interface(garmin->usb.handle,0) < 0 ) {
71
	    printf("usb_claim_interface failed: %s\n",usb_strerror());
72
	    exit(1);
73
	  }
74
 
75
	  for ( i = 0; 
76
		i < di->config->interface->altsetting->bNumEndpoints; 
77
		i++ ) {
78
	    struct usb_endpoint_descriptor * ep;
79
 
80
	    ep = &di->config->interface->altsetting->endpoint[i];
81
	    switch ( ep->bmAttributes & USB_ENDPOINT_TYPE_MASK ) {
82
	    case USB_ENDPOINT_TYPE_BULK:
83
	      if ( ep->bEndpointAddress & USB_ENDPOINT_DIR_MASK ) {
84
		garmin->usb.bulk_in = 
85
		  ep->bEndpointAddress & USB_ENDPOINT_ADDRESS_MASK;
86
	      } else {
87
		garmin->usb.bulk_out = 
88
		  ep->bEndpointAddress & USB_ENDPOINT_ADDRESS_MASK;
89
	      }
90
	      break;
91
	    case USB_ENDPOINT_TYPE_INTERRUPT:
92
	      if ( ep->bEndpointAddress & USB_ENDPOINT_DIR_MASK ) {
93
		garmin->usb.intr_in = 
94
		  ep->bEndpointAddress & USB_ENDPOINT_ADDRESS_MASK;
95
	      }
96
	      break;
97
	    default:
98
	      break;
99
	    }
100
	  }
101
 
102
	  break;
103
	}
104
      }
105
      if ( garmin->usb.handle != NULL ) break;
106
    }
107
  }
108
 
109
  return (garmin->usb.handle != NULL);
110
}
111
 
112
 
113
uint8
114
garmin_packet_type ( garmin_packet * p )
115
{
116
  return p->packet.type;
117
}
118
 
119
 
120
uint16
121
garmin_packet_id ( garmin_packet * p )
122
{
123
  return get_uint16(p->packet.id);
124
}
125
 
126
 
127
uint32
128
garmin_packet_size ( garmin_packet * p )
129
{
130
  return get_uint32(p->packet.size);
131
}
132
 
133
 
134
uint8 *
135
garmin_packet_data ( garmin_packet * p )
136
{
137
  return p->packet.data;
138
}
139
 
140
 
141
int
142
garmin_packetize ( garmin_packet *  p,
143
		   uint16           id, 
144
		   uint32           size, 
145
		   uint8 *          data )
146
{
147
  int ok = 0;
148
 
149
  if ( size + PACKET_HEADER_SIZE < sizeof(garmin_packet) ) {
150
    p->packet.type       = GARMIN_PROTOCOL_APP;
151
    p->packet.reserved1  = 0;
152
    p->packet.reserved2  = 0;
153
    p->packet.reserved3  = 0;
154
    p->packet.id[0]      = id;
155
    p->packet.id[1]      = id >> 8;
156
    p->packet.reserved4  = 0;
157
    p->packet.reserved5  = 0;
158
    p->packet.size[0]    = size;
159
    p->packet.size[1]    = size >> 8;
160
    p->packet.size[2]    = size >> 16;
161
    p->packet.size[3]    = size >> 24;
162
    if ( size > 0 && data != NULL ) {
163
      memcpy(p->packet.data,data,size);
164
    }
165
    ok = 1;
166
  }
167
 
168
  return ok;
169
}
170
 
171
 
172
int
173
garmin_read ( garmin_unit * garmin, garmin_packet * p )
174
{
175
  int r = -1;
176
 
177
  garmin_open(garmin);
178
 
179
  if ( garmin->usb.handle != NULL ) {
180
    if ( garmin->usb.read_bulk == 0 ) {
181
      r = usb_interrupt_read(garmin->usb.handle,
182
			     garmin->usb.intr_in,
183
			     p->data,
184
			     sizeof(garmin_packet),
185
			     INTR_TIMEOUT);
186
      /* 
187
	 If the packet is a "Pid_Data_Available" packet, we need to read
188
	 from the bulk endpoint until we get an empty packet.
189
      */
190
 
191
      if ( garmin_packet_type(p) == GARMIN_PROTOCOL_USB &&
192
	   garmin_packet_id(p) == Pid_Data_Available ) {
193
 
194
	/* FIXME!!! */
195
 
196
	printf("Received a Pid_Data_Available from the unit!\n");
197
      }
198
 
199
    } else {
200
      r = usb_bulk_read(garmin->usb.handle,
201
			garmin->usb.bulk_in,
202
			p->data,
203
			sizeof(garmin_packet),
204
			BULK_TIMEOUT);
205
    }
206
  }
207
 
208
  if ( garmin->verbose != 0 && r >= 0 ) {
209
    garmin_print_packet(p,GARMIN_DIR_READ,stdout);
210
  }
211
 
212
  return r;
213
}
214
 
215
 
216
int
217
garmin_write ( garmin_unit * garmin, garmin_packet * p )
218
{
219
  int r = -1;
220
  int s = garmin_packet_size(p) + PACKET_HEADER_SIZE;
221
 
222
  garmin_open(garmin);
223
 
224
  if ( garmin->usb.handle != NULL ) {
225
 
226
    if ( garmin->verbose != 0 ) {
227
      garmin_print_packet(p,GARMIN_DIR_WRITE,stdout);
228
    }
229
 
230
    r = usb_bulk_write(garmin->usb.handle,
231
		       garmin->usb.bulk_out,
232
		       p->data,
233
		       s,
234
		       BULK_TIMEOUT);
235
    if ( r != s ) {
236
      printf("usb_bulk_write failed: %s\n",usb_strerror());
237
      exit(1);
238
    }
239
  }
240
 
241
  return r;
242
}
243
 
244
 
245
uint32
246
garmin_start_session ( garmin_unit * garmin )
247
{
248
  garmin_packet p;
249
 
250
  garmin_packetize(&p,Pid_Start_Session,0,NULL);
251
  p.packet.type = GARMIN_PROTOCOL_USB;
252
 
253
  garmin_write(garmin,&p);
254
  garmin_write(garmin,&p);
255
  garmin_write(garmin,&p);
256
 
257
  if ( garmin_read(garmin,&p) == 16 ) {
258
    garmin->id = get_uint32(p.packet.data);
259
  } else {
260
    garmin->id = 0;
261
  }
262
 
263
  return garmin->id;
264
}
265
 
266
 
267
void
268
garmin_print_packet ( garmin_packet * p, int dir, FILE * fp )
269
{
270
  int    i;
271
  int    j;
272
  uint32 s;
273
  char   hex[128];
274
  char   dec[128];
275
 
276
  s = garmin_packet_size(p);
277
 
278
  switch ( dir ) {
279
  case GARMIN_DIR_READ:   fprintf(fp,"<read");   break;
280
  case GARMIN_DIR_WRITE:  fprintf(fp,"<write");  break;
281
  default:                fprintf(fp,"<packet");        break;
282
  }
283
 
284
  fprintf(fp," type=\"0x%02x\" id=\"0x%04x\" size=\"%u\"",
285
	  garmin_packet_type(p),garmin_packet_id(p),s);
286
  if ( s > 0 ) {
287
    fprintf(fp,">\n");
288
    for ( i = 0, j = 0; i < s; i++ ) {
289
      sprintf(&hex[(3*(i&0x0f))]," %02x",p->packet.data[i]);
290
      sprintf(&dec[(i&0x0f)],"%c",
291
	      (isalnum(p->packet.data[i]) || 
292
	       ispunct(p->packet.data[i]) ||
293
	       p->packet.data[i] == ' ') ?
294
	      p->packet.data[i] : '_');
295
      if ( (i & 0x0f) == 0x0f ) {
296
	j = 0;
297
	fprintf(fp,"[%04x] %-54s %s\n",i-15,hex,dec);
298
      } else {
299
	j++;
300
      }
301
    }
302
    if ( j > 0 ) {
303
      fprintf(fp,"[%04x] %-54s %s\n",s-(s & 0x0f),hex,dec);
304
    }
305
    switch ( dir ) {
306
    case GARMIN_DIR_READ:   fprintf(fp,"</read>\n");   break;
307
    case GARMIN_DIR_WRITE:  fprintf(fp,"</write>\n");  break;
308
    default:                fprintf(fp,"</packet>\n"); break;
309
    }
310
  } else {
311
    fprintf(fp,"/>\n");
312
  }
313
}