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 <string.h>
3
#include <stdlib.h>
4
#include "garmin.h"
5
 
6
 
7
/* ------------------------------------------------------------------------- */
8
/* Assign an application protocol to the Garmin unit.                        */
9
/* ------------------------------------------------------------------------- */
10
 
11
static void
12
garmin_assign_protocol ( garmin_unit *  garmin, 
13
			 uint16         protocol,
14
			 uint16 *       datatypes )
15
{
16
  /* Unknown protocols and their data types are ignored. */
17
 
18
  switch ( protocol ) {
19
  case appl_A010:
20
  case appl_A011:
21
    garmin->protocol.command             = protocol;
22
    break;
23
 
24
  case appl_A100:
25
    garmin->protocol.waypoint.waypoint   = protocol;  
26
    garmin->datatype.waypoint.waypoint   = datatypes[0];
27
    break;
28
 
29
  case appl_A101:
30
    garmin->protocol.waypoint.category   = protocol;
31
    garmin->datatype.waypoint.category   = datatypes[0];
32
    break;
33
 
34
  case appl_A200:
35
    garmin->protocol.route               = protocol;
36
    garmin->datatype.route.header        = datatypes[0];
37
    garmin->datatype.route.waypoint      = datatypes[1];
38
 
39
  case appl_A201:
40
    garmin->protocol.route               = protocol;
41
    garmin->datatype.route.header        = datatypes[0];
42
    garmin->datatype.route.waypoint      = datatypes[1];
43
    garmin->datatype.route.link          = datatypes[2];
44
    break;
45
 
46
  case appl_A300:
47
    garmin->protocol.track               = protocol;
48
    garmin->datatype.track.data          = datatypes[0];
49
    break;
50
 
51
  case appl_A301:
52
  case appl_A302:
53
    garmin->protocol.track               = protocol;
54
    garmin->datatype.track.header        = datatypes[0];
55
    garmin->datatype.track.data          = datatypes[1];
56
    break;
57
 
58
  case appl_A400:
59
    garmin->protocol.waypoint.proximity  = protocol;
60
    garmin->datatype.waypoint.proximity  = datatypes[0];
61
    break;
62
 
63
  case appl_A500:
64
    garmin->protocol.almanac             = protocol;
65
    garmin->datatype.almanac             = datatypes[0];
66
    break;
67
 
68
  case appl_A600:
69
    garmin->protocol.date_time           = protocol;
70
    garmin->datatype.date_time           = datatypes[0];
71
    break;
72
 
73
  case appl_A601:
74
    /* --- UNDOCUMENTED --- */
75
    break;
76
 
77
  case appl_A650:
78
    garmin->protocol.flightbook          = protocol;
79
    garmin->datatype.flightbook          = datatypes[0];
80
    break;
81
 
82
  case appl_A700:
83
    garmin->protocol.position            = protocol;
84
    garmin->datatype.position            = datatypes[0];
85
    break;
86
 
87
  case appl_A800:
88
    garmin->protocol.pvt                 = protocol;
89
    garmin->datatype.pvt                 = datatypes[0];
90
    break;
91
 
92
  case appl_A801:
93
    /* --- UNDOCUMENTED --- */
94
    break;
95
 
96
  case appl_A902:
97
    /* --- UNDOCUMENTED --- */
98
    break;
99
 
100
  case appl_A903:
101
    /* --- UNDOCUMENTED --- */
102
    break;
103
 
104
  case appl_A906:
105
    garmin->protocol.lap                 = protocol;
106
    garmin->datatype.lap                 = datatypes[0];
107
    break;
108
 
109
  case appl_A907:
110
    /* --- UNDOCUMENTED --- */
111
    break;
112
 
113
  case appl_A1000:
114
    garmin->protocol.run                 = protocol;
115
    garmin->datatype.run                 = datatypes[0];
116
    break;
117
 
118
  case appl_A1002:
119
    garmin->protocol.workout.workout     = protocol;
120
    garmin->datatype.workout.workout     = datatypes[0];
121
    break;
122
 
123
  case appl_A1003:
124
    garmin->protocol.workout.occurrence  = protocol;
125
    garmin->datatype.workout.occurrence  = datatypes[0];
126
    break;
127
 
128
  case appl_A1004:
129
    garmin->protocol.fitness             = protocol;
130
    garmin->datatype.fitness             = datatypes[0];
131
    break;
132
 
133
  case appl_A1005:
134
    garmin->protocol.workout.limits      = protocol;
135
    garmin->datatype.workout.limits      = datatypes[0];
136
    break;
137
 
138
  case appl_A1006:
139
    garmin->protocol.course.course       = protocol;
140
    garmin->datatype.course.course       = datatypes[0];
141
    break;
142
 
143
  case appl_A1007:
144
    garmin->protocol.course.lap          = protocol;
145
    garmin->datatype.course.lap          = datatypes[0];
146
    break;
147
 
148
  case appl_A1008:
149
    garmin->protocol.course.point        = protocol;
150
    garmin->datatype.course.point        = datatypes[0];
151
 
152
  case appl_A1009:
153
    garmin->protocol.course.limits       = protocol;
154
    garmin->datatype.course.limits       = datatypes[0];
155
    break;
156
 
157
  case appl_A1012:
158
    garmin->protocol.course.track        = protocol;
159
    garmin->datatype.course.track.header = datatypes[0];
160
    garmin->datatype.course.track.data   = datatypes[1];
161
    break;
162
 
163
  default:
164
    break;
165
  }
166
}
167
 
168
 
169
static char **
170
merge_strings ( char ** one, char ** two )
171
{
172
  int     i;
173
  int     n1;
174
  int     n2;
175
  char ** pos;
176
  char ** ret = NULL;
177
 
178
  for ( pos = one, n1 = 0; pos && *pos; pos++, n1++ );
179
  for ( pos = two, n2 = 0; pos && *pos; pos++, n2++ );
180
 
181
  if ( n1 + n2 > 0 ) {
182
    ret = calloc(n1+n2+1,sizeof(char *));
183
    for ( i = 0; i < n1; i++ ) ret[i]    = one[i];
184
    for ( i = 0; i < n2; i++ ) ret[n1+i] = two[i];
185
    if ( one != NULL ) free(one);
186
    if ( two != NULL ) free(two);
187
  }
188
 
189
  return ret;
190
}
191
 
192
 
193
/* Read a single packet with an expected packet ID and data type. */
194
 
195
static garmin_data *
196
garmin_read_singleton ( garmin_unit *     garmin,
197
			garmin_pid        pid,
198
			garmin_datatype   type )
199
{
200
  garmin_data *     d = NULL;
201
  garmin_packet     p;
202
  link_protocol     link = garmin->protocol.link;
203
  garmin_pid        ppid;
204
 
205
  if ( garmin_read(garmin,&p) > 0 ) {
206
    ppid = garmin_gpid(link,garmin_packet_id(&p));
207
    if ( ppid == pid ) {
208
      d = garmin_unpack_packet(&p,type);
209
    } else {
210
      /* Expected pid but got something else. */
211
      printf("garmin_read_singleton: expected %d, got %d\n",pid,ppid);
212
    }
213
  } else {
214
    /* Failed to read the packet off the link. */
215
    printf("garmin_read_singleton: failed to read Pid_Records packet\n");
216
  }
217
 
218
  return d;
219
}
220
 
221
 
222
/* Read a Pid_Records, (pid)+, Pid_Xfer_Cmplt sequence. */
223
 
224
static garmin_data *
225
garmin_read_records ( garmin_unit *     garmin,
226
		      garmin_pid        pid,
227
		      garmin_datatype   type )
228
{
229
  garmin_data *     d         = NULL;
230
  garmin_list *     l         = NULL;
231
  garmin_packet     p;
232
  link_protocol     link      = garmin->protocol.link;
233
  int               done      = 0;
234
  int               expected  = 0;
235
  int               got       = 0;
236
  garmin_pid        ppid;
237
 
238
  if ( garmin_read(garmin,&p) > 0 ) {
239
    ppid = garmin_gpid(link,garmin_packet_id(&p));
240
    if ( ppid == Pid_Records ) {
241
      expected = get_uint16(p.packet.data);
242
 
243
      if ( garmin->verbose != 0 ) {
244
	printf("[garmin] Pid_Records indicates %d packets to follow\n",
245
	       expected);
246
      }
247
 
248
      /* Allocate a list for the records. */
249
 
250
      d = garmin_alloc_data(data_Dlist);
251
      l = (garmin_list *)d->data;
252
 
253
      /* 
254
	 Now we expect packets with the given packet_id and datatype, up
255
	 until the final packet, which is a Pid_Xfer_Cmplt.
256
      */
257
 
258
      while ( !done && garmin_read(garmin,&p) > 0 ) {
259
	ppid = garmin_gpid(link,garmin_packet_id(&p));
260
	if ( ppid == Pid_Xfer_Cmplt ) {
261
	  if ( got != expected ) {
262
	    /* Incorrect number of packets received. */
263
	    printf("garmin_read_records: expected %d packets, got %d\n",
264
		   expected,got);
265
	  } else if ( garmin->verbose != 0 ) {
266
	    printf("[garmin] all %d expected packets received\n",got);
267
	  }
268
	  done = 1;
269
	} else if ( ppid == pid ) {
270
	  garmin_list_append(l,garmin_unpack_packet(&p,type));
271
	  got++;
272
	} else {
273
	  /* Unexpected packet ID! */
274
	  done = 1;
275
	}
276
      }
277
    } else {
278
      /* Expected Pid_Records but got something else. */
279
      printf("garmin_read_records: expected Pid_Records, got %d\n",ppid);
280
    }
281
  } else {
282
    /* Failed to read the Pid_Records packet off the link. */
283
    printf("garmin_read_records: failed to read Pid_Records packet\n");
284
  }
285
 
286
  return d;
287
}
288
 
289
 
290
/* Read a Pid_Records, (pid1, (pid2)+)+, Pid_Xfer_Cmplt sequence. */
291
 
292
static garmin_data *
293
garmin_read_records2 ( garmin_unit *     garmin,
294
		       garmin_pid        pid1,
295
		       garmin_datatype   type1,
296
		       garmin_pid        pid2,
297
		       garmin_datatype   type2 )
298
{
299
  garmin_data *     d         = NULL;
300
  garmin_list *     l         = NULL;
301
  garmin_packet     p;
302
  link_protocol     link      = garmin->protocol.link;
303
  int               expected  = 0;
304
  int               got       = 0;
305
  int               state     = 0;
306
  garmin_pid        ppid;
307
 
308
  if ( garmin_read(garmin,&p) > 0 ) {
309
    ppid = garmin_gpid(link,garmin_packet_id(&p));
310
    if ( ppid == Pid_Records ) {
311
      expected = get_uint16(p.packet.data);
312
 
313
      if ( garmin->verbose != 0 ) {
314
	printf("[garmin] Pid_Records indicates %d packets to follow\n",
315
	       expected);
316
      }
317
 
318
      /* Allocate a list for the records. */
319
 
320
      d = garmin_alloc_data(data_Dlist);
321
      l = (garmin_list *)d->data;
322
 
323
      while ( state >= 0 && garmin_read(garmin,&p) > 0 ) {
324
	ppid = garmin_gpid(link,garmin_packet_id(&p));
325
	if ( ppid == Pid_Xfer_Cmplt ) {
326
	  /* transfer complete! */
327
	  if ( got != expected ) {
328
	    /* wrong number of packets received! */
329
	    printf("garmin_read_records2: expected %d packets, got %d\n",
330
		   expected,got);
331
	  } else if ( garmin->verbose != 0 ) {
332
	    printf("[garmin] all %d expected packets received\n",got);
333
	  }
334
	  break;
335
	}
336
	switch ( state ) {
337
	case 0:  /* want pid1 */
338
	  if ( ppid == pid1 ) {
339
	    garmin_list_append(l,garmin_unpack_packet(&p,type1));
340
	    state = 1;
341
	    got++;
342
	  } else {
343
	    state = -1;
344
	  }
345
	  break;
346
	case 1:  /* want pid2 */
347
	  if ( ppid == pid2 ) {
348
	    garmin_list_append(l,garmin_unpack_packet(&p,type2));
349
	    state = 2;
350
	    got++;
351
	  } else {
352
	    state = -1;
353
	  }
354
	  break;
355
	case 2: /* want pid2 or pid1 */
356
	  if ( ppid == pid1 ) {
357
	    garmin_list_append(l,garmin_unpack_packet(&p,type1));
358
	    state = 1;
359
	    got++;
360
	  } else if ( ppid == pid2 ) {
361
	    garmin_list_append(l,garmin_unpack_packet(&p,type2));
362
	    state = 2;
363
	    got++;
364
	  } else {
365
	    state = -1;
366
	  }
367
	  break;
368
	default:
369
	  state = -1;
370
	  break;
371
	}
372
      }
373
      if ( state < 0 ) {
374
	/* Unexpected packet received. */
375
	printf("garmin_read_records2: unexpected packet %d received\n",ppid);
376
      }
377
    } else {
378
      /* Expected Pid_Records but got something else. */
379
      printf("garmin_read_records2: expected Pid_Records, got %d\n",ppid);
380
    }
381
  } else {
382
    /* Failed to read the Pid_Records packet off the link. */
383
    printf("garmin_read_records2: failed to read Pid_Records packet\n");
384
  }
385
 
386
  return d;
387
}
388
 
389
 
390
/* Read a Pid_Records, (pid1, (pid2, pid3)+)+, Pid_Xfer_Cmplt sequence. */
391
 
392
static garmin_data *
393
garmin_read_records3 ( garmin_unit *     garmin,
394
		       garmin_pid        pid1,
395
		       garmin_datatype   type1,
396
		       garmin_pid        pid2,
397
		       garmin_datatype   type2,
398
		       garmin_pid        pid3,
399
		       garmin_datatype   type3 )
400
{
401
  garmin_data *     d         = NULL;
402
  garmin_list *     l         = NULL;
403
  garmin_packet     p;
404
  link_protocol     link      = garmin->protocol.link;
405
  int               expected  = 0;
406
  int               got       = 0;
407
  garmin_pid        ppid;
408
  int               state     = 0;
409
 
410
  if ( garmin_read(garmin,&p) > 0 ) {
411
    ppid = garmin_gpid(link,garmin_packet_id(&p));
412
    if ( ppid == Pid_Records ) {
413
      expected = get_uint16(p.packet.data);
414
 
415
      if ( garmin->verbose != 0 ) {
416
	printf("[garmin] Pid_Records indicates %d packets to follow\n",
417
	       expected);
418
      }
419
 
420
      /* Allocate a list for the records. */
421
 
422
      d = garmin_alloc_data(data_Dlist);
423
      l = (garmin_list *)d->data;
424
 
425
      while ( state >= 0 && garmin_read(garmin,&p) > 0 ) {
426
	ppid = garmin_gpid(link,garmin_packet_id(&p));
427
	if ( ppid == Pid_Xfer_Cmplt ) {
428
	  /* transfer complete! */
429
	  if ( got != expected ) {
430
	    /* wrong number of packets received! */
431
	    printf("garmin_read_records3: expected %d packets, got %d\n",
432
		   expected,got);
433
	  } else if ( garmin->verbose != 0 ) {
434
	    printf("[garmin] all %d expected packets received\n",got);
435
	  }
436
	  break;
437
	}
438
	switch ( state ) {
439
	case 0:  /* want pid1 */
440
	  if ( ppid == pid1 ) {
441
	    garmin_list_append(l,garmin_unpack_packet(&p,type1));
442
	    state = 1;
443
	    got++;
444
	  } else {
445
	    state = -1;
446
	  }
447
	  break;
448
	case 1:  /* want pid2 */
449
	  if ( ppid == pid2 ) {
450
	    garmin_list_append(l,garmin_unpack_packet(&p,type2));
451
	    state = 2;
452
	    got++;
453
	  } else {
454
	    state = -1;
455
	  }
456
	  break;
457
	case 2: /* want pid3 */
458
	  if ( ppid == pid3 ) {
459
	    garmin_list_append(l,garmin_unpack_packet(&p,type3));
460
	    state = 3;
461
	    got++;
462
	  } else {
463
	    state = -1;
464
	  }
465
	  break;
466
	case 3: /* want pid2 or pid1 */
467
	  if ( ppid == pid1 ) {
468
	    garmin_list_append(l,garmin_unpack_packet(&p,type1));
469
	    state = 1;
470
	    got++;
471
	  } else if ( ppid == pid2 ) {
472
	    garmin_list_append(l,garmin_unpack_packet(&p,type2));
473
	    state = 2;
474
	    got++;
475
	  } else {
476
	    state = -1;
477
	  }
478
	  break;
479
	default:
480
	  state = -1;
481
	  break;
482
	}
483
      }
484
      if ( state < 0 ) {
485
	/* Unexpected packet received. */
486
	printf("garmin_read_records3: unexpected packet %d received\n",ppid);
487
      }
488
    } else {
489
      /* Expected Pid_Records but got something else. */
490
      printf("garmin_read_records3: expected Pid_Records, got %d\n",ppid);
491
    }
492
  } else {
493
    /* Failed to read the Pid_Records packet off the link. */
494
    printf("garmin_read_records3: failed to read Pid_Records packet\n");
495
  }
496
 
497
  return d;
498
}
499
 
500
 
501
/* ------------------------------------------------------------------------- */
502
/* 6.1  A000 - Product Data Protocol                                         */
503
/* 6.2  A001 - Protocol Capability Protocol                                  */
504
/* ------------------------------------------------------------------------- */
505
 
506
void
507
garmin_read_a000_a001 ( garmin_unit * garmin )
508
{
509
  garmin_packet          p;
510
  garmin_product *       r;
511
  garmin_extended_data * e;
512
  int                    done = 0;
513
  int                    pos;
514
  int                    size;
515
  int                    i;
516
  int                    j;
517
  uint8                  tag;
518
  uint16                 data;
519
  uint16 *               datatypes;
520
 
521
  /* Send the product request */
522
 
523
  garmin_packetize(&p,L000_Pid_Product_Rqst,0,NULL);
524
  garmin_write(garmin,&p);
525
 
526
  /* Read the response. */
527
 
528
  while ( !done && garmin_read(garmin,&p) > 0 ) {
529
    switch ( garmin_packet_id(&p) ) {
530
    case L000_Pid_Product_Data:
531
      r = &garmin->product;
532
      /* product ID, software version, product description, additional data. */
533
      r->product_id = get_uint16(p.packet.data);
534
      r->software_version = get_sint16(p.packet.data+2);
535
      pos = 4;
536
      if ( r->product_description != NULL ) {
537
	free(r->product_description);
538
      }
539
      r->product_description = get_string(&p,&pos);      
540
      r->additional_data = merge_strings(r->additional_data,
541
					 get_strings(&p,&pos));
542
      break;
543
 
544
    case L000_Pid_Ext_Product_Data:
545
      e = &garmin->extended;
546
      /* These strings should be ignored, but we save them anyway. */
547
      pos = 0;
548
      e->ext_data = merge_strings(e->ext_data,get_strings(&p,&pos));
549
      break;
550
 
551
    case L000_Pid_Protocol_Array:
552
      /* This is the A001 protocol, initiated by the device. */
553
      size = garmin_packet_size(&p) / 3;
554
      datatypes = calloc(size,sizeof(uint16));
555
      for ( i = 0; i < size; i++ ) {
556
	tag  = p.packet.data[3*i];
557
	data = get_uint16(p.packet.data + 3*i + 1);	
558
	switch ( tag ) {
559
	case Tag_Phys_Prot_Id:  
560
	  garmin->protocol.physical = data;
561
	  break;
562
	case Tag_Link_Prot_Id:
563
	  garmin->protocol.link = data;
564
	  break;
565
	case Tag_Appl_Prot_Id:
566
	  memset(datatypes,0,size * sizeof(uint16));
567
	  for ( j = i+1; p.packet.data[3*j] == Tag_Data_Type_Id; j++ ) {
568
	    datatypes[j-i-1] = get_uint16(p.packet.data + 3*j + 1);
569
	  }
570
	  garmin_assign_protocol(garmin,data,datatypes);
571
	  break;
572
	case Tag_Data_Type_Id:
573
	  /* Skip, since we should already have handled them. */
574
	default:
575
	  break;
576
	}
577
      }
578
      free(datatypes);
579
      done = 1;
580
      break;
581
 
582
    default:
583
      /* Ignore any other packets sent from the device. */
584
      break;
585
    }
586
  }
587
}
588
 
589
 
590
/* ------------------------------------------------------------------------- */
591
/* 6.4  A100 - Waypoint Transfer Protocol                                    */
592
/* ------------------------------------------------------------------------- */
593
 
594
garmin_data *
595
garmin_read_a100 ( garmin_unit * garmin )
596
{
597
  garmin_data * d = NULL;
598
 
599
  if ( garmin_send_command(garmin,Cmnd_Transfer_Wpt) != 0 ) {
600
    d = garmin_read_records(garmin,
601
			    Pid_Wpt_Data,
602
			    garmin->datatype.waypoint.waypoint);
603
  }
604
 
605
  return d;
606
}
607
 
608
 
609
/* ------------------------------------------------------------------------- */
610
/* 6.5  A101 - Waypoint Category Transfer Protocol                           */
611
/* ------------------------------------------------------------------------- */
612
 
613
garmin_data *
614
garmin_read_a101 ( garmin_unit * garmin )
615
{
616
  garmin_data * d = NULL;
617
 
618
  if ( garmin_send_command(garmin,Cmnd_Transfer_Wpt_Cats) != 0 ) {
619
    d = garmin_read_records(garmin,
620
			    Pid_Wpt_Cat,
621
			    garmin->datatype.waypoint.category);
622
  }
623
 
624
  return d;
625
}
626
 
627
 
628
/* ------------------------------------------------------------------------- */
629
/* 6.6.2  A200 - Route Transfer Protocol                                     */
630
/* ------------------------------------------------------------------------- */
631
 
632
garmin_data *
633
garmin_read_a200 ( garmin_unit * garmin )
634
{
635
  garmin_data * d = NULL;
636
 
637
  if ( garmin_send_command(garmin,Cmnd_Transfer_Rte) != 0 ) {
638
    d = garmin_read_records2(garmin,
639
			     Pid_Rte_Hdr,
640
			     garmin->datatype.route.header,
641
			     Pid_Rte_Wpt_Data,
642
			     garmin->datatype.waypoint.waypoint);
643
  }
644
 
645
  return d;
646
}
647
 
648
 
649
/* ------------------------------------------------------------------------- */
650
/* 6.6.3  A201 - Route Transfer Protocol                                     */
651
/* ------------------------------------------------------------------------- */
652
 
653
garmin_data *
654
garmin_read_a201 ( garmin_unit * garmin )
655
{
656
  garmin_data * d = NULL;
657
 
658
  if ( garmin_send_command(garmin,Cmnd_Transfer_Rte) != 0 ) {
659
    d = garmin_read_records3(garmin,
660
			     Pid_Rte_Hdr,
661
			     garmin->datatype.route.header,
662
			     Pid_Rte_Wpt_Data,
663
			     garmin->datatype.route.waypoint,
664
			     Pid_Rte_Link_Data,
665
			     garmin->datatype.route.link);
666
  }
667
 
668
  return d;
669
}
670
 
671
 
672
/* ------------------------------------------------------------------------- */
673
/* 6.7.2  A300 - Track Log Transfer Protocol                                 */
674
/* ------------------------------------------------------------------------- */
675
 
676
garmin_data *
677
garmin_read_a300 ( garmin_unit * garmin )
678
{
679
  garmin_data * d = NULL;
680
 
681
  if ( garmin_send_command(garmin,Cmnd_Transfer_Trk) != 0 ) {
682
    d = garmin_read_records(garmin,
683
			    Pid_Trk_Data,
684
			    garmin->datatype.track.data);
685
  }
686
 
687
  return d;
688
}
689
 
690
 
691
/* ------------------------------------------------------------------------- */
692
/* 6.7.3  A301 - Track Log Transfer Protocol                                 */
693
/* ------------------------------------------------------------------------- */
694
 
695
garmin_data *
696
garmin_read_a301 ( garmin_unit * garmin )
697
{
698
  garmin_data * d = NULL;
699
 
700
  if ( garmin_send_command(garmin,Cmnd_Transfer_Trk) != 0 ) {
701
    d = garmin_read_records2(garmin,
702
			     Pid_Trk_Hdr,
703
			     garmin->datatype.track.header,
704
			     Pid_Trk_Data,
705
			     garmin->datatype.track.data);
706
  }
707
 
708
  return d;
709
}
710
 
711
 
712
/* ------------------------------------------------------------------------- */
713
/* 6.7.4  A302 - Track Log Transfer Protocol                                 */
714
/* ------------------------------------------------------------------------- */
715
 
716
garmin_data *
717
garmin_read_a302 ( garmin_unit * garmin )
718
{
719
  return garmin_read_a301(garmin);
720
}
721
 
722
 
723
/* ------------------------------------------------------------------------- */
724
/* 6.8  A400 - Proximity Waypoint Transfer Protocol                          */
725
/* ------------------------------------------------------------------------- */
726
 
727
garmin_data *
728
garmin_read_a400 ( garmin_unit * garmin )
729
{
730
  garmin_data * d = NULL;
731
 
732
  if ( garmin_send_command(garmin,Cmnd_Transfer_Prx) != 0 ) {
733
    d = garmin_read_records(garmin,
734
			    Pid_Prx_Wpt_Data,
735
			    garmin->datatype.waypoint.proximity);
736
  }
737
 
738
  return d;
739
}
740
 
741
 
742
/* ------------------------------------------------------------------------- */
743
/* 6.9  A500 - Almanac Transfer Protocol                                     */
744
/* ------------------------------------------------------------------------- */
745
 
746
garmin_data *
747
garmin_read_a500 ( garmin_unit * garmin )
748
{
749
  garmin_data * d = NULL;
750
 
751
  if ( garmin_send_command(garmin,Cmnd_Transfer_Alm) != 0 ) {
752
    d = garmin_read_records(garmin,
753
			    Pid_Almanac_Data,
754
			    garmin->datatype.almanac);
755
  }
756
 
757
  return d;
758
}
759
 
760
 
761
/* ------------------------------------------------------------------------- */
762
/* 6.10  A600 - Date and Time Initialization Protocol                        */
763
/* ------------------------------------------------------------------------- */
764
 
765
garmin_data *
766
garmin_read_a600 ( garmin_unit * garmin )
767
{
768
  garmin_data * d = NULL;
769
 
770
  d = garmin_read_singleton(garmin,
771
			    Pid_Date_Time_Data,
772
			    garmin->datatype.date_time);
773
 
774
  return d;
775
}
776
 
777
 
778
/* ------------------------------------------------------------------------- */
779
/* 6.11  A650 - FlightBook Transfer Protocol                                 */
780
/* ------------------------------------------------------------------------- */
781
 
782
garmin_data *
783
garmin_read_a650 ( garmin_unit * garmin )
784
{
785
  garmin_data * d = NULL;
786
 
787
  if ( garmin_send_command(garmin,Cmnd_FlightBook_Transfer) ) {
788
    d = garmin_read_records(garmin,
789
			    Pid_FlightBook_Record,
790
			    garmin->datatype.flightbook);
791
  }
792
 
793
  return d;
794
}
795
 
796
 
797
/* ------------------------------------------------------------------------- */
798
/* 6.12  A700 - Position Initialization Protocol                             */
799
/* ------------------------------------------------------------------------- */
800
 
801
garmin_data *
802
garmin_read_a700 ( garmin_unit * garmin )
803
{
804
  garmin_data * d;
805
 
806
  d = garmin_read_singleton(garmin,
807
			    Pid_Position_Data,
808
			    garmin->datatype.position);
809
 
810
  return d;
811
}
812
 
813
 
814
/* ------------------------------------------------------------------------- */
815
/* 6.13  A800 - PVT Protocol                                                 */
816
/* ------------------------------------------------------------------------- */
817
 
818
garmin_data *
819
garmin_read_a800 ( garmin_unit * garmin )
820
{
821
  garmin_data * d;
822
 
823
  d = garmin_read_singleton(garmin,
824
			    Pid_Pvt_Data,
825
			    garmin->datatype.pvt);
826
 
827
  return d;
828
}
829
 
830
 
831
/* ------------------------------------------------------------------------- */
832
/* 6.14  A906 - Lap Transfer Protocol                                        */
833
/* ------------------------------------------------------------------------- */
834
 
835
garmin_data *
836
garmin_read_a906 ( garmin_unit * garmin )
837
{
838
  garmin_data * d = NULL;
839
 
840
  if ( garmin_send_command(garmin,Cmnd_Transfer_Laps) != 0 ) {
841
    d = garmin_read_records(garmin,Pid_Lap,garmin->datatype.lap);
842
  }
843
 
844
  return d;
845
}
846
 
847
 
848
/* ------------------------------------------------------------------------- */
849
/* 6.15  A1000 - Run Transfer Protocol                                       */
850
/* ------------------------------------------------------------------------- */
851
 
852
garmin_data *
853
garmin_read_a1000 ( garmin_unit * garmin )
854
{
855
  garmin_data * d  = NULL;
856
  garmin_list * l  = NULL;
857
 
858
  /* Read the runs, then the laps, then the track log. */
859
 
860
  if ( garmin_send_command(garmin,Cmnd_Transfer_Runs) != 0 ) {
861
    d = garmin_alloc_data(data_Dlist);
862
    l = d->data;
863
    garmin_list_append(l,garmin_read_records(garmin,Pid_Run,
864
					     garmin->datatype.run));
865
    garmin_list_append(l,garmin_read_a906(garmin));
866
    garmin_list_append(l,garmin_read_a302(garmin));
867
  }
868
 
869
  return d;
870
}
871
 
872
 
873
/* ------------------------------------------------------------------------- */
874
/* 6.16  A1002 - Workout Transfer Protocol                                   */
875
/* ------------------------------------------------------------------------- */
876
 
877
garmin_data *
878
garmin_read_a1002 ( garmin_unit * garmin )
879
{
880
  garmin_data * d  = NULL;
881
  garmin_list * l  = NULL;
882
 
883
  /* Read the workouts, then the workout occurrences */
884
 
885
  if ( garmin_send_command(garmin,Cmnd_Transfer_Workouts) != 0 ) {
886
    d = garmin_alloc_data(data_Dlist);
887
    l = d->data;
888
    garmin_list_append(l,
889
		       garmin_read_records(garmin,
890
					   Pid_Workout,
891
					   garmin->datatype.workout.workout));
892
    garmin_list_append(l,garmin_read_a1003(garmin));
893
  }
894
 
895
  return d;
896
}
897
 
898
 
899
/* ------------------------------------------------------------------------- */
900
/* --- UNDOCUMENTED ---  A1003 - Workout Occurrence Transfer Protocol        */
901
/* ------------------------------------------------------------------------- */
902
 
903
garmin_data *
904
garmin_read_a1003 ( garmin_unit * garmin )
905
{
906
  garmin_data * d = NULL;
907
 
908
  /* Read the workouts, then the workout occurrences */
909
 
910
  if ( garmin_send_command(garmin,Cmnd_Transfer_Workout_Occurrences) != 0 ) {
911
    d = garmin_read_records(garmin,
912
			    Pid_Workout_Occurrence,
913
			    garmin->datatype.workout.occurrence);
914
  }
915
 
916
  return d;
917
}
918
 
919
 
920
/* ------------------------------------------------------------------------- */
921
/* 6.17  A1004 - Fitness User Profile Transfer Protocol                      */
922
/* ------------------------------------------------------------------------- */
923
 
924
garmin_data *
925
garmin_read_a1004 ( garmin_unit * garmin )
926
{
927
  garmin_data * d = NULL;
928
 
929
  if ( garmin_send_command(garmin,Cmnd_Transfer_Fitness_User_Profile) != 0 ) {
930
    d = garmin_read_singleton(garmin,
931
			      Pid_Fitness_User_Profile,
932
			      garmin->datatype.fitness);
933
  }
934
 
935
  return d;
936
}
937
 
938
 
939
/* ------------------------------------------------------------------------- */
940
/* 6.18  A1005 - Workout Limits Transfer Protocol                            */
941
/* ------------------------------------------------------------------------- */
942
 
943
garmin_data *
944
garmin_read_a1005 ( garmin_unit * garmin )
945
{
946
  garmin_data * d = NULL;
947
 
948
  if ( garmin_send_command(garmin,Cmnd_Transfer_Workout_Limits) != 0 ) {
949
    d = garmin_read_singleton(garmin,
950
			      Pid_Workout_Limits,
951
			      garmin->datatype.workout.limits);
952
  }
953
 
954
  return d;
955
}
956
 
957
 
958
/* ------------------------------------------------------------------------- */
959
/* 6.19  A1006 - Course Transfer Protocol                                    */
960
/* ------------------------------------------------------------------------- */
961
 
962
garmin_data *
963
garmin_read_a1006 ( garmin_unit * garmin )
964
{
965
  garmin_data * d  = NULL;
966
  garmin_list * l  = NULL;
967
 
968
  if ( garmin_send_command(garmin,Cmnd_Transfer_Courses) != 0 ) {
969
    d = garmin_alloc_data(data_Dlist);
970
    l = d->data;
971
    garmin_list_append(l,garmin_read_records(garmin,
972
					     Pid_Course,
973
					     garmin->datatype.course.course));
974
    garmin_list_append(l,garmin_read_a1007(garmin));
975
    garmin_list_append(l,garmin_read_a1012(garmin));
976
    garmin_list_append(l,garmin_read_a1008(garmin));
977
  }
978
 
979
  return d;
980
}
981
 
982
 
983
/* ------------------------------------------------------------------------- */
984
/* --- UNDOCUMENTED ---  A1007 - Course Lap Transfer Protocol                */
985
/* ------------------------------------------------------------------------- */
986
 
987
garmin_data *
988
garmin_read_a1007 ( garmin_unit * garmin )
989
{
990
  garmin_data * d = NULL;
991
 
992
  if ( garmin_send_command(garmin,Cmnd_Transfer_Course_Laps) != 0 ) {
993
    d = garmin_read_records(garmin,
994
			    Pid_Course_Lap,
995
			    (garmin->datatype.course.lap != data_Dnil) ?
996
			    garmin->datatype.course.lap :
997
			    garmin->datatype.lap);
998
  }
999
 
1000
  return d;
1001
}
1002
 
1003
 
1004
/* ------------------------------------------------------------------------- */
1005
/* --- UNDOCUMENTED ---  A1008 - Course Point Transfer Protocol              */
1006
/* ------------------------------------------------------------------------- */
1007
 
1008
garmin_data *
1009
garmin_read_a1008 ( garmin_unit * garmin )
1010
{
1011
  garmin_data * d = NULL;
1012
 
1013
  if ( garmin_send_command(garmin,Cmnd_Transfer_Course_Points) != 0 ) {
1014
    d = garmin_read_records(garmin,
1015
			    Pid_Course_Point,
1016
			    garmin->datatype.course.point);
1017
  }
1018
 
1019
  return d;
1020
}
1021
 
1022
 
1023
/* ------------------------------------------------------------------------- */
1024
/* 6.20  A1009 - Course Limits Transfer Protocol                             */
1025
/* ------------------------------------------------------------------------- */
1026
 
1027
garmin_data *
1028
garmin_read_a1009 ( garmin_unit * garmin )
1029
{
1030
  garmin_data * d = NULL;
1031
 
1032
  if ( garmin_send_command(garmin,Cmnd_Transfer_Course_Limits) != 0 ) {
1033
    d = garmin_read_singleton(garmin,
1034
			      Pid_Course_Limits,
1035
			      garmin->datatype.course.limits);
1036
  }
1037
 
1038
  return d;
1039
}
1040
 
1041
 
1042
/* ------------------------------------------------------------------------- */
1043
/* --- UNDOCUMENTED ---  A1012 - Course Track Transfer Protocol              */
1044
/* ------------------------------------------------------------------------- */
1045
 
1046
garmin_data *
1047
garmin_read_a1012 ( garmin_unit * garmin )
1048
{
1049
  garmin_datatype  header;
1050
  garmin_datatype  data;
1051
  garmin_data *    d = NULL;
1052
 
1053
  if ( garmin_send_command(garmin,Cmnd_Transfer_Course_Tracks) != 0 ) {
1054
 
1055
    if ( garmin->datatype.course.track.header != data_Dnil ) {
1056
      header = garmin->datatype.course.track.header;
1057
    } else {
1058
      header = garmin->datatype.track.header;
1059
    }
1060
 
1061
    if ( garmin->datatype.course.track.data != data_Dnil ) {
1062
      data = garmin->datatype.course.track.data;
1063
    } else {
1064
      data = garmin->datatype.track.data;
1065
    }
1066
 
1067
    d = garmin_read_records2(garmin,
1068
			     Pid_Course_Trk_Hdr,
1069
			     header,
1070
			     Pid_Course_Trk_Data,
1071
			     data);
1072
  }
1073
 
1074
  return d;
1075
}
1076
 
1077
 
1078
/* ------------------------------------------------------------------------- */
1079
/* Get data from the Garmin unit via a particular top-level protocol         */
1080
/* ------------------------------------------------------------------------- */
1081
 
1082
garmin_data *
1083
garmin_read_via ( garmin_unit * garmin, appl_protocol protocol )
1084
{
1085
  garmin_data * data = NULL;
1086
 
1087
#define CASE_PROTOCOL(x)                                                      \
1088
  case appl_A##x:                                                             \
1089
    if ( garmin->verbose != 0 ) {                                             \
1090
      printf("[garmin] -> garmin_read_a" #x "\n");                            \
1091
    }                                                                         \
1092
    data = garmin_read_a##x(garmin);                                          \
1093
    if ( garmin->verbose != 0 ) {                                             \
1094
      printf("[garmin] <- garmin_read_a" #x "\n");                            \
1095
    }                                                                         \
1096
    break
1097
 
1098
  switch ( protocol ) {
1099
  CASE_PROTOCOL(100);   /* waypoints */
1100
  CASE_PROTOCOL(101);   /* waypoint categories */
1101
  CASE_PROTOCOL(200);   /* routes */
1102
  CASE_PROTOCOL(201);   /* routes */
1103
  CASE_PROTOCOL(300);   /* track log */
1104
  CASE_PROTOCOL(301);   /* track log */
1105
  CASE_PROTOCOL(302);   /* track log */
1106
  CASE_PROTOCOL(400);   /* proximity waypoints */
1107
  CASE_PROTOCOL(500);   /* almanac */
1108
  CASE_PROTOCOL(650);   /* flightbook */
1109
  CASE_PROTOCOL(1000);  /* runs */
1110
  CASE_PROTOCOL(1002);  /* workouts */
1111
  CASE_PROTOCOL(1004);  /* fitness user profile */
1112
  CASE_PROTOCOL(1005);  /* workout limits */
1113
  CASE_PROTOCOL(1006);  /* courses */
1114
  CASE_PROTOCOL(1009);  /* course limits */
1115
  default:
1116
    /* invalid top-level read protocol */
1117
    break;
1118
  }
1119
 
1120
  return data;
1121
}
1122
 
1123
 
1124
/* ------------------------------------------------------------------------- */
1125
/* Get data from the Garmin unit                                             */
1126
/* ------------------------------------------------------------------------- */
1127
 
1128
garmin_data *
1129
garmin_get ( garmin_unit * garmin, garmin_get_type what )
1130
{
1131
  garmin_data * data = NULL;
1132
 
1133
#define CASE_WHAT(x,y) \
1134
  case GET_##x: data = garmin_read_via(garmin,garmin->protocol.y); break
1135
 
1136
  switch ( what ) {
1137
  CASE_WHAT(WAYPOINTS,waypoint.waypoint);
1138
  CASE_WHAT(WAYPOINT_CATEGORIES,waypoint.category);
1139
  CASE_WHAT(ROUTES,route);
1140
  CASE_WHAT(TRACKLOG,track);
1141
  CASE_WHAT(PROXIMITY_WAYPOINTS,waypoint.proximity);
1142
  CASE_WHAT(ALMANAC,almanac);
1143
  CASE_WHAT(FLIGHTBOOK,flightbook);
1144
  CASE_WHAT(RUNS,run);
1145
  CASE_WHAT(WORKOUTS,workout.workout);
1146
  CASE_WHAT(FITNESS_USER_PROFILE,fitness);
1147
  CASE_WHAT(WORKOUT_LIMITS,workout.limits);
1148
  CASE_WHAT(COURSES,course.course);
1149
  CASE_WHAT(COURSE_LIMITS,course.limits);
1150
  default:
1151
    /* invalid garmin_get_type */
1152
    break;
1153
  }
1154
 
1155
  return data;
1156
}
1157
 
1158
 
1159
/* Initialize a connection with a Garmin unit. */
1160
 
1161
int
1162
garmin_init ( garmin_unit * garmin, int verbose )
1163
{
1164
  memset(garmin,0,sizeof(garmin_unit));
1165
  garmin->verbose = verbose;
1166
 
1167
  if ( garmin_open(garmin) != 0 ) {
1168
    garmin_start_session(garmin);
1169
    garmin_read_a000_a001(garmin);
1170
    return 1;
1171
  } else {
1172
    return 0;
1173
  }
1174
}
1175