Rev 101 | Go to most recent revision | Blame | Compare with Previous | Last modification | View Log | RSS feed
#include "config.h"
#include <stdio.h>
#include <string.h>
#include <ctype.h>
#include <usb.h>
#include "garmin.h"
#define INTR_TIMEOUT 3000
#define BULK_TIMEOUT 3000
/* Close the USB connection with the Garmin device. */
int
garmin_close ( garmin_unit * garmin )
{
if ( garmin->usb.handle != NULL ) {
usb_release_interface(garmin->usb.handle,0);
usb_close(garmin->usb.handle);
garmin->usb.handle = NULL;
}
return 0;
}
/*
Open the USB connection with the first Garmin device we find. Eventually,
I'd like to add the ability to select a particular device.
*/
int
garmin_open ( garmin_unit * garmin )
{
struct usb_bus * bi;
struct usb_device * di;
int i;
if ( garmin->usb.handle == NULL ) {
usb_init();
usb_find_busses();
usb_find_devices();
for ( bi = usb_busses; bi != NULL; bi = bi->next ) {
for ( di = bi->devices; di != NULL; di = di->next ) {
if ( di->descriptor.idVendor == GARMIN_USB_VID &&
di->descriptor.idProduct == GARMIN_USB_PID ) {
if ( garmin->verbose != 0 ) {
printf("[garmin] found VID %04x, PID %04x on %s/%s\n",
di->descriptor.idVendor,
di->descriptor.idProduct,
bi->dirname,
di->filename);
}
garmin->usb.handle = usb_open(di);
garmin->usb.read_bulk = 0;
if ( garmin->usb.handle == NULL ) {
printf("usb_open failed: %s\n",usb_strerror());
exit(1);
}
if ( usb_set_configuration(garmin->usb.handle,1) < 0 ) {
printf("usb_set_configuration failed: %s\n",usb_strerror());
exit(1);
}
if ( usb_claim_interface(garmin->usb.handle,0) < 0 ) {
printf("usb_claim_interface failed: %s\n",usb_strerror());
exit(1);
}
for ( i = 0;
i < di->config->interface->altsetting->bNumEndpoints;
i++ ) {
struct usb_endpoint_descriptor * ep;
ep = &di->config->interface->altsetting->endpoint[i];
switch ( ep->bmAttributes & USB_ENDPOINT_TYPE_MASK ) {
case USB_ENDPOINT_TYPE_BULK:
if ( ep->bEndpointAddress & USB_ENDPOINT_DIR_MASK ) {
garmin->usb.bulk_in =
ep->bEndpointAddress & USB_ENDPOINT_ADDRESS_MASK;
} else {
garmin->usb.bulk_out =
ep->bEndpointAddress & USB_ENDPOINT_ADDRESS_MASK;
}
break;
case USB_ENDPOINT_TYPE_INTERRUPT:
if ( ep->bEndpointAddress & USB_ENDPOINT_DIR_MASK ) {
garmin->usb.intr_in =
ep->bEndpointAddress & USB_ENDPOINT_ADDRESS_MASK;
}
break;
default:
break;
}
}
break;
}
}
if ( garmin->usb.handle != NULL ) break;
}
}
return (garmin->usb.handle != NULL);
}
uint8
garmin_packet_type ( garmin_packet * p )
{
return p->packet.type;
}
uint16
garmin_packet_id ( garmin_packet * p )
{
return get_uint16(p->packet.id);
}
uint32
garmin_packet_size ( garmin_packet * p )
{
return get_uint32(p->packet.size);
}
uint8 *
garmin_packet_data ( garmin_packet * p )
{
return p->packet.data;
}
int
garmin_packetize ( garmin_packet * p,
uint16 id,
uint32 size,
uint8 * data )
{
int ok = 0;
if ( size + PACKET_HEADER_SIZE < sizeof(garmin_packet) ) {
p->packet.type = GARMIN_PROTOCOL_APP;
p->packet.reserved1 = 0;
p->packet.reserved2 = 0;
p->packet.reserved3 = 0;
p->packet.id[0] = id;
p->packet.id[1] = id >> 8;
p->packet.reserved4 = 0;
p->packet.reserved5 = 0;
p->packet.size[0] = size;
p->packet.size[1] = size >> 8;
p->packet.size[2] = size >> 16;
p->packet.size[3] = size >> 24;
if ( size > 0 && data != NULL ) {
memcpy(p->packet.data,data,size);
}
ok = 1;
}
return ok;
}
int
garmin_read ( garmin_unit * garmin, garmin_packet * p )
{
int r = -1;
garmin_open(garmin);
if ( garmin->usb.handle != NULL ) {
if ( garmin->usb.read_bulk == 0 ) {
r = usb_interrupt_read(garmin->usb.handle,
garmin->usb.intr_in,
p->data,
sizeof(garmin_packet),
INTR_TIMEOUT);
/*
If the packet is a "Pid_Data_Available" packet, we need to read
from the bulk endpoint until we get an empty packet.
*/
if ( garmin_packet_type(p) == GARMIN_PROTOCOL_USB &&
garmin_packet_id(p) == Pid_Data_Available ) {
/* FIXME!!! */
printf("Received a Pid_Data_Available from the unit!\n");
}
} else {
r = usb_bulk_read(garmin->usb.handle,
garmin->usb.bulk_in,
p->data,
sizeof(garmin_packet),
BULK_TIMEOUT);
}
}
if ( garmin->verbose != 0 && r >= 0 ) {
garmin_print_packet(p,GARMIN_DIR_READ,stdout);
}
return r;
}
int
garmin_write ( garmin_unit * garmin, garmin_packet * p )
{
int r = -1;
int s = garmin_packet_size(p) + PACKET_HEADER_SIZE;
garmin_open(garmin);
if ( garmin->usb.handle != NULL ) {
if ( garmin->verbose != 0 ) {
garmin_print_packet(p,GARMIN_DIR_WRITE,stdout);
}
r = usb_bulk_write(garmin->usb.handle,
garmin->usb.bulk_out,
p->data,
s,
BULK_TIMEOUT);
if ( r != s ) {
printf("usb_bulk_write failed: %s\n",usb_strerror());
exit(1);
}
}
return r;
}
uint32
garmin_start_session ( garmin_unit * garmin )
{
garmin_packet p;
garmin_packetize(&p,Pid_Start_Session,0,NULL);
p.packet.type = GARMIN_PROTOCOL_USB;
garmin_write(garmin,&p);
garmin_write(garmin,&p);
garmin_write(garmin,&p);
if ( garmin_read(garmin,&p) == 16 ) {
garmin->id = get_uint32(p.packet.data);
} else {
garmin->id = 0;
}
return garmin->id;
}
void
garmin_print_packet ( garmin_packet * p, int dir, FILE * fp )
{
int i;
int j;
uint32 s;
char hex[128];
char dec[128];
s = garmin_packet_size(p);
switch ( dir ) {
case GARMIN_DIR_READ: fprintf(fp,"<read"); break;
case GARMIN_DIR_WRITE: fprintf(fp,"<write"); break;
default: fprintf(fp,"<packet"); break;
}
fprintf(fp," type=\"0x%02x\" id=\"0x%04x\" size=\"%u\"",
garmin_packet_type(p),garmin_packet_id(p),s);
if ( s > 0 ) {
fprintf(fp,">\n");
for ( i = 0, j = 0; i < s; i++ ) {
sprintf(&hex[(3*(i&0x0f))]," %02x",p->packet.data[i]);
sprintf(&dec[(i&0x0f)],"%c",
(isalnum(p->packet.data[i]) ||
ispunct(p->packet.data[i]) ||
p->packet.data[i] == ' ') ?
p->packet.data[i] : '_');
if ( (i & 0x0f) == 0x0f ) {
j = 0;
fprintf(fp,"[%04x] %-54s %s\n",i-15,hex,dec);
} else {
j++;
}
}
if ( j > 0 ) {
fprintf(fp,"[%04x] %-54s %s\n",s-(s & 0x0f),hex,dec);
}
switch ( dir ) {
case GARMIN_DIR_READ: fprintf(fp,"</read>\n"); break;
case GARMIN_DIR_WRITE: fprintf(fp,"</write>\n"); break;
default: fprintf(fp,"</packet>\n"); break;
}
} else {
fprintf(fp,"/>\n");
}
}