Docjar: A Java Source and Docuemnt Enginecom.*    java.*    javax.*    org.*    all    new    plug-in

Quick Search    Search Deep

Source code: jflight/gps/garmin/GarminGps.java


1   /*
2   Project name:   JFlight
3   Hosted at:     www.sourceforge.net
4   Homepage:    jflight.sourceforge.net
5   Licence:    GNU public licence (GPL)
6   Filename:    GarminGps.java
7   Package:    jflight
8    */
9   
10  package jflight.gps.garmin;
11  import jflight.gps.*;
12  import jflight.model.*;
13  
14  import java.io.*;
15  import java.util.*;
16  import java.text.*;
17  import java.awt.*;
18  import java.awt.event.*;
19  import java.lang.System;
20  
21  /**
22   * Support for the Garmin GPS-devices.
23   *
24   *
25   *
26   * @since       JDK1.1.x
27   * @author      R?diger Bien
28   *
29   * CVS-section:
30   * @file_version  $Revision: 1.38 $
31   *
32   */
33  public class GarminGps
34  extends Gps {
35      
36      
37      
38      private int pid;
39      private int bufSize;
40      private byte dataBuf[];
41      //private byte varioBuf[];
42      //private int varioCnt;
43      private Caps GpsCaps;
44      private byte msg[];
45      
46      
47      // L001 - link protocol 1
48      private final int PID_ACK =   6;
49      private final int PID_NACK =  21;
50      private final int PID_CMD_DATA = 10;
51      private final int PID_XFER_CMPLT = 12;
52      private final int PID_RECORDS = 27;
53      private final int PID_WPT_DATA = 35;
54      private final int PID_TRK_DATA = 34;
55      private final int PID_RTE_WPT_DATA = 30;
56      private final int PID_RTE_HDR = 29;
57      private final int PID_RTE_LNK = 98;
58      private final int PID_TRK_HDR = 99;
59      private final int PID_PROD_REQ = 254;
60      private final int PID_PROD_DATA = 255;
61      
62      // A010 - device command protocol 1
63      private final int CMD_START_PVT_DATA = 49;
64      private final int CMD_STOP_PVT_DATA = 50;
65      private final int CMD_TRANSFER_WPT = 7;
66      private final int CMD_TRANSFER_TRK = 6;
67      private final int CMD_TRANSFER_TIME = 5;
68      private final int CMD_TRANSFER_RTE = 4;
69      private final int CMD_TRANSFER_PRX = 3;
70      private final int CMD_TRANSFER_POS = 2;
71      
72      private final int DLE = 16;
73      private final int ETX = 3;
74      private final int RX_TIMEOUT = 500; // # of ms
75      private final int TX_RETRY = 10;
76      private final String Delim = ",|";
77      private final int WPT_MODE = 0;
78      private final int RTE_MODE = 1;
79      
80      
81      private final int BUG_WORKAROUND = 60*60*1000;
82      private final int MAX_INT = 2147483647;
83      
84      /** Capabilities of selected Garmin GPS
85       *
86       * Some Garmin devices behave different depending on the version. The interval
87       * can be set in sw_version_beg / _end.
88       *
89       */
90      
91      // id, sw-version beg, sw-version end, data-formats for wpt, rte, trk, prx
92      // 0 means not supported
93      private final int GpsCapsList[][]= {
94          // GPS 12-types:
95          { 0, 1, 0xFFFF, 100, 201, 300, 0 }, // default-dummy
96          { 77, 1, 301, 100, 201, 300, 400 },
97          { 77, 301, 350, 103, 201, 300, 403 },
98          { 77, 350, 361, 103, 201, 300, 0 },
99          { 77, 361, 0xFFFF, 103, 201, 300, 403 },
100         { 87, 1, 0xFFFF, 103, 201, 300, 403 },
101         { 96, 1, 0xFFFF, 103, 201, 300, 403 },
102         { 105, 1, 0xFFFF, 103, 201, 300, 403 },
103         { 106, 1, 0xFFFF, 103, 201, 300, 403 },
104         { 138, 1, 0xFFFF, 103, 201, 300, 403 },
105         // GPS II:
106         { 59, 1, 0xFFFF, 100, 201, 300, 0 },
107         // GPS 45:
108         { 31, 1, 0xFFFF, 100, 201, 300, 0 },
109         { 41, 1, 0xFFFF, 100, 201, 300, 0 },
110         // GPS III:
111         //{ 72, 1, 0xFFFF, 104, 201, 300, 0 },
112         // GPS II+:
113         { 73, 1, 0xFFFF, 103, 201, 300, 0 },
114         { 97, 1, 0xFFFF, 103, 201, 300, 0 },
115         // ETREX-Family: (ID & formats to be checked!)
116         { 0/*?*/, 1, 0xFFFF, 109, 201, 301/*the only one with altitude*/, 0 },
117     };
118     private final int NUM_GPS = 16;  // update this number with every new GPS !!!
119     private final int DEFAULT_GPS = 0;
120     
121     
122     /**
123      * Constructor GarminGps
124      *
125      */
126     public GarminGps() {
127         
128         super();
129         
130         msg = new byte[300];
131         dataBuf = new byte[400]; // here a single packet will be stored for later evaluation
132         GpsCaps = new Caps();
133         //varioCnt = 0;
134         ioInit = false;
135         
136         if ((debug&0x01)!=0) printDebug("Init GarminGps");
137         
138         this.gpsID = "GARXXX";
139         
140     }
141     
142     
143     public String getManufactoringID() {
144         return "4";
145     }
146     
147     
148     /**
149      * Send a packet with a variable size to the GPS
150      * If an IOException occurs, it retries some time, then rethrows the Exception
151      * Wait for (n)ack, if required
152      * Resends packet on NACK until too much retries
153      * Uses class-variable "msg"
154      *
155      * @return SUCCESS     implies ACK has been received <br>
156      * TX_RETRY_ERROR   if too much NACKs have been received and packet sent <br>
157      * was no ACK/NACK <br>
158      * IO_NOT_INITIALIZED
159      *
160      * @exception  GpsTimeoutException ...
161      * @exception  IOException ...
162      */
163     private int sendVarPacket( byte packetId, byte data[], byte num)
164     throws GpsTimeoutException, IOException {
165         int i=0;
166         int j = 0;
167         int crc = 0;
168         int ret = SUCCESS;
169         long t1;
170         boolean err = true;
171         int retry = 0;
172         
173         if( !ioInit ) return IO_NOT_INITIALIZED;
174         if((debug&0x01)!=0) printDebug("GarminGPS::sendPacket():");
175         // assemble packet:
176         msg[i++] = DLE;
177         msg[i++] = packetId;
178         msg[i++] = num;
179         if( num == DLE ) {
180             msg[i++] = DLE;
181         }
182         crc = absByte(packetId) + absByte(num);
183         if( num > 0 ) {
184             if((debug&0x01)!=0) printDebug(" data 0,1 (i)= " + data[0] + " " + data[1] + " " + i + "---\n");
185             for( j=0; j<num; j++ ) {
186                 msg[i++] = data[j];
187                 crc += absByte(data[j]);
188                 if( data[j] == DLE ) {
189                     msg[i++] = DLE;
190                 }
191             }
192         }
193         if((debug&0x01)!=0) printDebug(" crc = " + crc + "---");
194         crc = (~crc)+1;
195         msg[i++] = (byte) (crc&0x00ff);
196         if((debug&0x01)!=0) printDebug(" crc k2 = " + (crc&0x00ff) + "---");
197         if( (crc&0x00ff) == DLE ) {
198             msg[i++] = DLE;
199         }
200         msg[i++] = DLE;
201         msg[i++] = ETX;
202         if((debug&0x01)!=0) {
203             printDebug("num bytes: " + i + " ---");
204             for( j=0; j<(i); j++) printDebug("#" + ((int)msg[j]) + ",");
205         }
206         
207         // packet is assembled, now send it:
208         t1 = System.currentTimeMillis();
209         do {
210             try {
211                 err = false;
212                 os.write(msg, 0, i );
213                 os.flush();
214             } catch (IOException e) {
215                 // data may have been sent or not, don't know
216                 // if sent, resend should't disturb
217                 // if not, retry is required
218                 if( (System.currentTimeMillis() - t1) > RX_TIMEOUT ) {
219                     if((debug&0x01)!=0)  printDebug("OutputStream write error: " + e);
220                     throw new IOException(e.getMessage()); // rethrow Exception
221                 }
222                 else {
223                     err = true;
224                 }
225             }
226             if(!err) {
227                 if( (packetId != PID_ACK) && (packetId != PID_NACK) ) {
228                     // data have been sent, but maybe not received by the GPS -> wait for (N)ACK:
229                     t1 = System.currentTimeMillis(); // restart timer
230                     do {
231                         getPacket(false); // timeout? tbd
232                     }
233                     while( (pid != PID_ACK) && (pid != PID_NACK) );
234                     if( pid != PID_ACK ) {
235                         if( retry++ > TX_RETRY ) ret = TX_RETRY_ERROR;
236                         else err = true; // retry
237                     }
238                     
239                 } // (packetId != PID_ACK) && (packetId != PID_NACK)
240             } // if(!err)
241         }
242         while( err );
243         if((debug&0x01)!=0) printDebug(" end send var packet ---");
244         return ret;
245     }
246     
247     
248     
249     /**
250      * Get packet
251      * Shall be able to deal with an unstable or lost connection. What may happen:
252      * - There is no connection at all: E.g. wrong interface setup -> timeout detection
253      * - The connection gets lost: No more chars come in -> timeout detection
254      * - The connection is unstable: Some chars are missing -> the sequence 0x10 - 0x03
255      * occurs out-of-order, timeout detection
256      * In any case only a single packet (or two, if the devices switch their
257      * client-server releationship) can get lost.
258      * Detecting a wrong byte-sequence is quite difficult and not implemented so far,
259      * just timeout detection.
260      * If a timout occurs, the missing bytes will not be resent. In case of (N)ACK, some
261      * GPS will resend it after 2-5s, but this cannot be relied on. To be sure
262      * a NAVCK should be assumed an the last transfer should be done again.
263      * In case of an interrupted data-transfer a NACK should be sent by the PC to request
264      * retransmission.
265      *
266      * changes: pid, dataBuf, bufSize
267      * @param  idMode: Packet A001 during ID-reading may come or not, no exception shall be thrown here
268      * @return SUCCESS or
269      * BAD_CRC: CRC-error <br>
270      * IO_NOT_INITIALIZED <br>
271      * data in buffer dataBuf <br>
272      *
273      * @exception  GpsTimeoutException ...
274      * @exception  IOException ...
275      */
276     private int getPacket(boolean idMode) throws IOException, GpsTimeoutException {
277         int state = 0;
278         int  b; // in byte
279         int stuffCnt = 0; // count DLE stuffing
280         int crc = -1;
281         int sum = 0; // for crc calculation
282         int ret = 0;
283         boolean stuff = false;
284         int userDataCnt = 0;
285         long t1;
286         
287         if( !ioInit ) return IO_NOT_INITIALIZED;
288         if((debug&0x01)!=0) printDebug("GarminGPS::getPacket(): waiting for one packet from GPS ...");
289         
290         t1 = System.currentTimeMillis();
291         while( state != 99 ) {
292             if((debug&0x01)!=0) printDebug(" [" + state + "] " );
293             b = is.read();
294             if (b == -1 ) {
295                 if ((System.currentTimeMillis() - t1) > RX_TIMEOUT ) {
296                     if( idMode ) {
297                         return GPS_TIMEOUT;
298                     }
299                     else if ((debug&0x01)!=0)  printDebug("GarminGPS::getPacket(): timeout!");
300                     throw new GpsTimeoutException("Timeout: GPS doesn't reply");
301                 } else {
302                     delay(1);
303                     continue;
304                 }
305             }
306             if((debug&0x01)!=0) printDebug(" *" + b);
307             switch (state) {
308                 /* DLE */
309                 case 0:
310                     if( b != 0x10 ) {
311                         state = 9; // sequence error
312                     }
313                     else {
314                         state++;
315                     }
316                     break;
317                     /* type */
318                 case 1:
319                     pid = absByte((byte)b);
320                     sum += pid;
321                     state++;
322                     break;
323                     /* size */
324                 case 2:
325                     bufSize = b;
326                     sum += absByte((byte)bufSize);
327                     if( bufSize == 0x10 ) {
328                         state++;
329                     } else {
330                         state+=2;
331                     }
332                     break;
333                     // read stuff byte
334                 case 3:
335                     state++;
336                     break;
337                     /* user data */
338                 case 4:
339                     dataBuf[userDataCnt-stuffCnt] = (byte) b;
340                     if( b == 0x10 ) {
341                         if( stuff == false ) {
342                             stuff = true;
343                             stuffCnt++;
344                             sum += absByte((byte)b);
345                         } else stuff = false;
346                     } else sum += absByte((byte)b);
347                     userDataCnt++;
348                     if( userDataCnt >= (bufSize+stuffCnt)) {
349                         state++;
350                     }
351                     break;
352                     /* crc */
353                 case 5:
354                     crc = b;
355                     if( crc == 0x10 ) {
356                         state++;
357                     } else {
358                         state += 2;
359                     }
360                     // crc ok ?
361                     if( (((sum&0x00FF) + absByte((byte)crc))&0x00FF) == 0 ) {
362                         ret = SUCCESS;
363                         if((debug&0x01)!=0) printDebug(" crc ok " + crc);
364                     } else {
365                         ret = BAD_CRC;
366                         if((debug&0x01)!=0) printDebug(" crc bad " + sum + " " + crc);
367                     }
368                     break;
369                     // read stuff byte
370                 case 6:
371                     state++;
372                     break;
373                     /* DLE */
374                 case 7:
375                     state++;
376                     break;
377                     /* ETX */
378                 case 8:
379                     state=99; // end
380                     break;
381                     // simple escape from sequence error: wait for DLE-ETX sequence
382                 case 9:
383                     if( b == 0x10 ) state = 10;
384                     break;
385                 case 10:
386                     if( b == 0x03 ) {
387                         throw new GpsTimeoutException("Fatal data sequence error! May require power off/on on GPS to escape");
388                     }
389                     break;
390             } // switch
391         } // while
392         
393         //System.out.println("Pid: " + pid );
394         
395         if((debug&0x01)!=0) printDebug("- packet end -");
396         if((debug&0x01)!=0) printDebug("GarminGPS::getPacket() Finished normally with ret = " + ret);
397         return ret;
398     }
399     
400     /**
401      * Identify the GPS connected and return some descriptive information.
402      * For the main class this function is for GPS-type detection (in case
403      * other devices are supported too) and informative use. <br>
404      * Modifies <a href="jflight.gps.Gps.html#gpsId">gpsId</a>,
405      * <a href="jflight.gps.Gps.html#swVersion">swVersion</a>,
406      * <a href="jflight.gps.Gps.html#prodDescr">prodDescr</a>
407      *
408      * @return SUCCESS <br>
409      * BAD_CRC: CRC-error <br>
410      * TX_RETRY_ERROR if too much NACKs have been received; <br>
411      * IO_NOT_INITIALIZED
412      *
413      *
414      * @exception  GpsTimeoutException ...
415      * @exception  IOException ...
416      */
417     public int getGpsId() throws GpsTimeoutException, IOException {
418         int ret;
419         int i;
420         byte tag;
421         short data;
422         
423         if((debug&0x01)!=0) System.err.println("getGpsId():");
424         if( !ioInit ) return IO_NOT_INITIALIZED;
425         
426         ret = sendVarPacket( (byte) 254, msg, (byte) 0 );
427         if( ret != SUCCESS ) return ret;
428         // must have been ACK
429         
430         // A000-type data
431         ret = getPacket(false);
432         if((debug&0x01)!=0) printDebug("data pid: " + pid + " ---");
433         if( ret != SUCCESS ) return ret;
434         
435         // setup input stream to read data from buffer:
436         DataInputStream in =
437         new DataInputStream(
438         new BufferedInputStream(
439         new ByteArrayInputStream(dataBuf)));
440         
441         gpsId = in.readShort();
442         gpsId = swap16(gpsId);
443         swVersion = in.readShort();
444         swVersion = swap16(swVersion);
445         
446         if( bufSize > 4 ) {
447             prodDescr = new String( dataBuf, 4, bufSize-5 );
448             prodDescr.trim();
449         } else {
450             prodDescr = new String("Garmin GPS");
451         }
452         byte[] locbuf = new byte[2];
453         locbuf[0] = (byte)PID_PROD_DATA;
454         locbuf[1] = (byte)0;
455         ret = sendVarPacket( (byte) PID_ACK, locbuf, (byte)2); // ACK
456         
457         // A001 packet ? Check, if a packet is sent by the GPS
458         if( getPacket(true) == SUCCESS ) {
459             ret = sendVarPacket( (byte) PID_ACK, msg, (byte) 0 ); // ACK
460             //if((debug&0x01)!=0) printDebug("A001 packet received ---");
461             //System.out.println("A001 packet received ---");
462             // setup input stream to read data from buffer:
463             in =
464             new DataInputStream(
465             new BufferedInputStream(
466             new ByteArrayInputStream(dataBuf)));
467             
468             int aValue = 0;
469             for(int a=0, d=0;;) {
470                 tag = in.readByte();
471                 switch (tag) {
472                     case 'P':
473                         data = in.readShort(); // ignore
474                         data = swap16(data);
475                         //System.out.println("P " + data);
476                         break;
477                     case 'L':
478                         data = in.readShort(); // ignore
479                         data = swap16(data);
480                         //System.out.println("L " + data);
481                         break;
482                     case 'A':
483                         a++;
484                         data = in.readShort();
485                         data = swap16(data);
486                         aValue = data;
487                         //System.out.println("A " + data);
488                         switch(a) {
489                             case 1:
490                                 break; // ignore the first one
491                             case 2:
492                                 GpsCaps.wpt_a = data;
493                                 break;
494                             case 3:
495                                 GpsCaps.rte_a = data;
496                                 break;
497                             case 4:
498                                 GpsCaps.trk_a = data;
499                                 break;
500                             default:
501                                 break;
502                         }
503                         break;
504                     case 'D':
505                         data = in.readShort();
506                         data = swap16(data);
507                         //System.out.println("D " + data);
508                         switch(a) {
509                             // ignore the first one
510                             case 2:
511                                 GpsCaps.wpt_d = data;
512                                 break;
513                             case 3:
514                                 GpsCaps.rte_d[d++] = data;
515                                 break;
516                             case 4:
517                                 GpsCaps.trk_d = data;
518                                 break;
519                             default:
520                                 break;
521                         }
522                         break;
523                 }
524                 if( aValue > 300 ) break; // other protocols are not handled anyway
525             } // for-loop
526         }
527         else {
528             for( i=0; i<NUM_GPS; i++ ) {
529                 if( GpsCapsList[i][0] == gpsId ) {
530                     if( (swVersion >= GpsCapsList[i][1]) && (swVersion < GpsCapsList[i][2]) ) {
531                         if((debug&0x01)!=0) printDebug("Device supported!");
532                         break;
533                     }
534                 }
535             }
536             if( i == NUM_GPS ) {
537                 if((debug&0x01)!=0) printDebug("Device with ID " + gpsId + " not supported!");
538                 if((debug&0x01)!=0) printDebug("Using default-device (GPS-12)");
539                 i = DEFAULT_GPS; // default-device
540             }
541             
542             GpsCaps.wpt_d = GpsCapsList[i][3];
543             GpsCaps.rte_d[0] = GpsCapsList[i][4];
544             GpsCaps.rte_d[1] = 103; // fixed
545             GpsCaps.trk_d = GpsCapsList[i][5];
546             GpsCaps.prx_d = GpsCapsList[i][6];
547             GpsCaps.wpt_a = 100; // fixed
548             GpsCaps.rte_a = 200; // fixed
549             GpsCaps.trk_a = 300; // fixed
550         }
551         
552         if((debug&0x01)!=0) {
553             printDebug("GPS ID: " + gpsId );
554             printDebug("SW Version: " + swVersion );
555             printDebug("GPS description: " + prodDescr );
556         }
557         
558         System.out.println( GpsCaps );
559         return ret;
560     }
561     
562     
563 /*
564 D109 Waypoint Type handling by JFlight: Simplified, mapped to the D103-capabilities
565  
566     typedef struct                      //                                 size // JFlight:
567         {
568         byte            dtyp;           // data packet type (0x01 for D109)1    //
569         byte            wpt_class;      // class                           1    // 0: user-wpt
570         byte            dspl_color;     // display & color (see below)     1    // 0: black
571         byte            attr;           // attributes (0x70 for D109)      1    //
572         Symbol_Type     smbl;           // waypoint symbol                 2    // -1: dot
573         byte            subclass[18];   // subclass                        18   // 6*0x00, 12*0xFF
574         Semicircle_Type posn;           // 32 bit semicircle               8    // D103
575         float           alt;            // altitude in meters              4    // 0.0
576         float           dpth;           // depth in meters                 4    // 0.0
577         float           dist;           // proximity distance in meters    4    // 0.0
578         char            state[2];       // state                           2    // "  "
579         char            cc[2];          // country code                    2    // "  "
580        longword        ete;            // outbound link ete in seconds    4    // -1
581 (52 bytes so far)
582     //  char            ident[];           variable length string          1-51 // D103, first 6 letters
583     //  char            comment[];         waypoint user comment           1-51 // D103 comment
584     //  char            facility[];        facility name                   1-31 // empty (0-terminated)
585     //  char            city[];            city name                       1-25 // empty (0-terminated)
586     //  char            addr[];            address number                  1-51 // empty (0-terminated)
587     //  char            cross_road[];      intersecting road label         1-51 // empty (0-terminated)
588         } D109_Wpt_Type;
589  
590  */
591     /**
592      * Read a single waypoint from the input stream and save it in curWpt
593      * Data types D108/109 are required for devices passing altitude too
594      *
595      * @return curWpt (module local variable)
596      *
597      * @exception  IOException ...
598      */
599     private void getWpt(DataInputStream in, int rteWptMode) throws IOException {
600         int i,
601         lat,
602         lon,
603         identOffset;
604         int accum = 0;
605         int len=0, len_tmp, offs;
606         float height;
607         int caps;
608         
609         if( rteWptMode == WPT_MODE ) {
610             caps = GpsCaps.wpt_d;
611         }
612         else {
613             caps = GpsCaps.rte_d[1];
614         }
615 
616         curWpt = new Wpt();
617         switch( caps ) {
618             case 100:
619             case 101:
620             case 102:
621             case 103:
622             case 104:
623             case 107:
624                 curWpt.name = new String( dataBuf, 0, 6 );
625                 // eleminate the string-terminating 0-char:
626                 for( i=18; i<58; i++ ) {
627                     if( dataBuf[i] == 0 ) dataBuf[i] = 0x20;
628                 }
629                 curWpt.comment = new String( dataBuf, 18, 40 );
630                 curWpt.comment = curWpt.comment.trim();
631                 in.skipBytes(6);
632                 lat = in.readInt();
633                 lat = swap32(lat);
634                 lon = in.readInt();
635                 lon = swap32(lon);
636                 curWpt.dlat = ((double)lat*180)/MAX_INT;
637                 curWpt.dlon = ((double)lon*180)/MAX_INT;
638                 if( GpsCaps.wpt_d == 103 ) {
639                     in.skipBytes(44);
640                     curWpt.iconId = in.readByte();
641                     curWpt.displayOption = in.readByte();
642                 }
643                 break;
644             case 108:
645             case 109:
646                 // default-values:
647                 curWpt.iconId = Wpt.SYM_DOT;
648                 // values from the GPS:
649                 in.skipBytes(24);
650                 lat = in.readInt();
651                 lat = swap32(lat);
652                 lon = in.readInt();
653                 lon = swap32(lon);
654                 curWpt.dlat = ((double)lat*180)/MAX_INT;
655                 curWpt.dlon = ((double)lon*180)/MAX_INT;
656                 
657                 // height:
658                 accum = in.readInt();
659                 accum = swap32(accum);
660                 height = Float.intBitsToFloat(accum);
661                 if( height == 1.0e25 ) { // not supported by device or unknown
662                     curWpt.height = 0;
663                 } else {
664                     curWpt.height = (int) height;
665                 }
666                 
667                 if( GpsCaps.wpt_d == 108 ) identOffset = 48;
668                 else identOffset = 52;
669                 
670                 // ident string:
671                 if( dataBuf[identOffset] != 0 ) {
672                     for( i=0, len=0; i<identOffset; i++ ) {
673                         if( dataBuf[identOffset+i] != 0 ) len++;
674                         else break;
675                     }
676                     if( len > 6 ) len_tmp = 6;
677                     else len_tmp = len;
678                     curWpt.name = new String( dataBuf, identOffset, len_tmp );
679                 }
680                 len++; // 0-byte
681                 
682                 // comment string:
683                 offs = len;
684                 if( dataBuf[identOffset+offs] != 0 ) {
685                     for( i=0, len=0; i<identOffset; i++ ) {
686                         if( dataBuf[identOffset+offs+i] != 0 ) len++;
687                         else break;
688                     }
689                 }
690                 if( len > 40 ) len_tmp = 40;
691                 else len_tmp = len;
692                 curWpt.comment = new String( dataBuf, identOffset+offs, len_tmp );
693                 curWpt.comment = curWpt.comment.trim();
694                 System.out.println(GpsCaps.wpt_d + ": " + curWpt );
695                 // done d108/109 ;-)
696                 break;
697             default:
698                 throw new IOException("Waypoint data type" + GpsCaps.wpt_d +" not supported");
699                 
700         }
701         
702         if((debug&0x01)!=0) {
703             if((debug&0x01)!=0) printDebug("\nWPT name: " + curWpt.name);
704             if((debug&0x01)!=0) printDebug("WPT comment: " + curWpt.comment);
705             if((debug&0x01)!=0) printDebug("WPT dlat/dlon: " + curWpt.dlat + " - " +
706             curWpt.dlon);
707             if((debug&0x01)!=0) printDebug("WPT opt/sym: " + curWpt.displayOption + " - " +
708             curWpt.iconId);
709         }
710     }
711     
712     /**
713      * Read all waypoints from the GPS and store them locally.
714      *
715      * @return SUCCESS <br>
716      * BAD_CRC: CRC-error <br>
717      * TX_RETRY_ERROR if too much NACKs have been received; <br>
718      * IO_NOT_INITIALIZED
719      *
720      * @param  mode: Gps.REPLACE or Gps.APPEND  waypoints to the list
721      *
722      * @exception  GpsTimeoutException ...
723      * @exception  IOException ...
724      */
725     public int getWpts(int mode) throws GpsTimeoutException, IOException {
726         int ret;
727         int i;
728         int numPacks;
729         byte locBuf[] = new byte[2];
730         int pidTmp = PID_WPT_DATA;
731         int size;
732         
733         if( !ioInit ) return IO_NOT_INITIALIZED;
734         if( gpsId == 0 ) {
735             // make sure Gps has been detetced:
736             ret = getGpsId();
737             if( ret != SUCCESS ) return ret;
738         } else {
739             // send NACK; may help to recover from interrupted transmissions:
740             sendVarPacket( (byte) PID_NACK, msg, (byte) 0 );
741         }
742         
743         
744         
745         // send request to GPS: send wpts
746         locBuf[0] = CMD_TRANSFER_WPT;
747         ret = sendVarPacket( (byte) PID_CMD_DATA, locBuf, (byte) 2 );
748         if((debug&0x01)!=0) printDebug("ret: " + ret + " ---");
749         if( ret != SUCCESS ) return ret;
750         
751         // GPS sends PID_RECORDS and num packets to come:
752         ret = getPacket(false);
753         if( ret != SUCCESS ) return ret;
754         if((debug&0x01)!=0) {
755             printDebug("data pid (expected: 27): " + pid + " ---");
756             printDebug("num packets: " + absByte(dataBuf[0]) + " " + absByte(dataBuf[1]));
757         }
758         numPacks = absByte(dataBuf[0]) + (absByte(dataBuf[1])<<8);
759         if((debug&0x01)!=0) printDebug("num packets to come: " + numPacks + " ---");
760         // confirm data:
761         sendVarPacket( (byte) PID_ACK, msg, (byte) 0 ); // ACK
762         
763         // read wpts:
764         if( mode == Gps.REPLACE ) {
765             wptCont.removeAllWpts();
766         }
767         if( numPacks > 0 )
768             while( pidTmp == PID_WPT_DATA ) {
769                 i = 0;
770                 ret = getPacket(false);
771                 pidTmp = pid;
772                 if( ret == SUCCESS ) {
773                     // confirm data:
774                     sendVarPacket( (byte) PID_ACK, msg, (byte) 0 ); // ACK
775                 }
776                 else {
777                     sendVarPacket( (byte) PID_NACK, msg, (byte) 0 ); // NACK
778                     continue;
779                 }
780                 
781                 // analyze the data:
782                 if( pidTmp != PID_XFER_CMPLT ) {
783                     // setup input stream to read data from buffer:
784                     DataInputStream in =
785                     new DataInputStream(
786                     new BufferedInputStream(
787                     new ByteArrayInputStream(dataBuf)));
788                     getWpt(in, WPT_MODE);
789                     if( mode == Gps.APPEND ) {
790                         // insertNewWpt( curWpt );
791                         // now check, if waypoint (checked by name) already exists:
792                         String newWptName = curWpt.getName();
793                         size = wptCont.size();
794                         for( i=0; i<size; i++) {
795                             Wpt aWpt = wptCont.wptAt(i);
796                             if( aWpt.getName().compareTo(newWptName) == 0 ) {
797                                 if( aWpt.getComment().compareTo(curWpt.getComment()) == 0 ) {
798                                     break;
799                                 }
800                             }
801                         }
802                         if( i == size ) {
803                             // it's a new Wpt; now insert it at the right position:
804                             for( i=0; i<size; i++) {
805                                 Wpt aWpt = wptCont.wptAt(i);
806                                 if( aWpt.getName().compareTo(newWptName) < 0 ) continue;
807                                 else {
808                                     wptCont.insertWptAt(curWpt,i);
809                                     break;
810                                 }
811                             }
812                             // insert at the end?
813                             if( i == size ) {
814                                 wptCont.addWpt(curWpt);
815                             }
816                         }
817                     } else { // REPLACE mode
818                         // Wpts already sorted by the GPS: just append it
819                         wptCont.addWpt( curWpt );
820                     }
821                 }
822             }
823         else {
824             if((debug&0x01)!=0) printDebug("no waypoints on GPS ---");
825         }
826         
827         return ret;
828     }
829     
830     
831     /** send a single waypoint, without any header- or end-package:
832      * @exception  GpsTimeoutException ...
833      * @exception  IOException ...
834      */
835     private int sendASingleWpt(int index, byte packetId, int rteWptMode)
836     throws IOException, GpsTimeoutException {
837         int i, l, ret,
838         lat,
839         lon;
840         double   dlat,
841         dlon;
842         float height;
843         Wpt wpt;
844         byte length=0;
845         byte[] locBuf2 = new byte[300];
846         int caps;
847         
848         wpt = wptCont.wptAt(index);
849         
850         // setup input stream to write data to buffer:
851         ByteArrayOutputStream locBuf = new ByteArrayOutputStream(300);
852         DataOutputStream out = new DataOutputStream( locBuf );
853         
854         if( rteWptMode == WPT_MODE ) {
855             caps = GpsCaps.wpt_d;
856         }
857         else {
858             caps = GpsCaps.rte_d[1];
859         }
860         
861         // build buffer:
862         switch( caps ) {
863             case 100:
864             case 103:
865                 out.writeBytes(wpt.name);
866                 if( (l=wpt.getName().length()) < 6 ) {
867                     for( i=0; i<(6-l); i++ ) out.writeByte(32);
868                 }
869                 dlat = (wpt.dlat/180)*MAX_INT;
870                 dlon = (wpt.dlon/180)*MAX_INT;
871                 lat = (int) dlat;
872                 lon = (int) dlon;
873                 out.writeInt(swap32(lat));
874                 out.writeInt(swap32(lon));
875                 out.writeInt(0); // dummy
876                 out.writeBytes(wpt.comment);
877                 if( (l=wpt.getComment().length()) < 40 ) {
878                     for( i=0; i<(40-l); i++ ) out.writeByte(32);
879                 }
880                 length = 58;
881                 if( GpsCaps.wpt_d == 103 ) {
882                     out.writeByte(wpt.iconId);
883                     out.writeByte(wpt.displayOption);
884                     length += 2;
885                 }
886                 locBuf2[57] = 0;
887                 break;
888             case 108:
889                 out.writeByte(0x00);
890                 out.writeByte(0xFF);    // def. color
891                 out.writeByte(0x00);
892                 out.writeByte(0x60);    // attr
893                 out.writeShort(0xFFFF); // symbol; will be set to "dot" (default) by GPS
894                 out.writeShort(0x0000); // subclass
895                 out.writeShort(0x0000);
896                 out.writeShort(0x0000);
897                 out.writeShort(0xFFFF);
898                 out.writeShort(0xFFFF);
899                 out.writeShort(0xFFFF);
900                 out.writeShort(0xFFFF);
901                 out.writeShort(0xFFFF);
902                 out.writeShort(0xFFFF);
903                 dlat = (wpt.dlat/180)*MAX_INT;
904                 dlon = (wpt.dlon/180)*MAX_INT;
905                 lat = (int) dlat;
906                 lon = (int) dlon;
907                 out.writeInt(swap32(lat));
908                 out.writeInt(swap32(lon));
909                 height = wpt.height;
910                 out.writeInt(swap32(Float.floatToIntBits(height)));
911                 height = 1.0F+25;
912                 out.writeInt(swap32(Float.floatToIntBits(height)));
913                 height = 0;
914                 out.writeInt(swap32(Float.floatToIntBits(height)));
915                 for(int loop = 0;loop<4;loop++) out.writeByte((byte)'X'); // state, country code
916                 
917                 out.writeBytes(wpt.name);out.writeByte(0x00);
918                 out.writeBytes(wpt.comment);out.writeByte(0x00);
919                 
920                 out.writeByte(0x00);
921                 out.writeByte(0x00);
922                 out.writeByte(0x00);
923                 out.writeByte(0x00);
924                 
925                 length = (byte)out.size();
926                 break;
927             case 109:
928                 out.writeByte(0x01);
929                 out.writeByte(0x00); // user wpt
930                 out.writeByte(0x1F); // color
931                 out.writeShort(0xFFFF); // will be set to "dot" (default) by GPS
932                 out.writeShort(0x0000); // subclass
933                 out.writeShort(0x0000);
934                 out.writeShort(0x0000);
935                 out.writeShort(0xFFFF);
936                 out.writeShort(0xFFFF);
937                 out.writeShort(0xFFFF);
938                 out.writeShort(0xFFFF);
939                 out.writeShort(0xFFFF);
940                 out.writeShort(0xFFFF);
941                 dlat = (wpt.dlat/180)*MAX_INT;
942                 dlon = (wpt.dlon/180)*MAX_INT;
943                 lat = (int) dlat;
944                 lon = (int) dlon;
945                 out.writeInt(swap32(lat));
946                 out.writeInt(swap32(lon));
947                 height = wpt.height;
948                 out.writeInt(swap32(Float.floatToIntBits(height)));
949                 height = 1.0F+25;
950                 out.writeInt(swap32(Float.floatToIntBits(height)));
951                 height = 0;
952                 out.writeInt(swap32(Float.floatToIntBits(height)));
953                 for(int loop = 0;loop<4;loop++) out.writeByte((byte)'X'); // state, country code
954                 out.writeInt(-1);
955                 
956                 out.writeBytes(wpt.name);
957                 out.writeByte(0x00);
958                 
959                 out.writeBytes(wpt.comment);
960                 out.writeByte(0x00);
961                 
962                 out.writeByte(0x00);
963                 out.writeByte(0x00);
964                 out.writeByte(0x00);
965                 out.writeByte(0x00);
966                 length = (byte)out.size();
967                 break;
968                 // send waypoint:
969             default:
970                 throw new IOException("Error: Waypoint data type " + GpsCaps.wpt_d+ " not yet supported!"); // rethrow Exception
971         }
972         locBuf2 = locBuf.toByteArray(); // get buffer
973         ret = sendVarPacket( packetId, locBuf2, length );
974         
975         return ret;
976     }
977     
978     /**
979      * Sends one or all waypoint(s) to the GPS. Uses the waypoint with the specified index
980      * in the Vector of all waypoints. If index is equalt to -1, then all wpts are sent. <br>
981      * Note: It's important that the comment is null-terminated
982      * (doesn't match the garmin description).
983      *
984      * @param  index   Index of the waypoint in the list
985      * @return SUCCESS <br>
986      * BAD_CRC: CRC-error <br>
987      * TX_RETRY_ERROR if too much NACKs have been received <br>
988      * WRONG_INDEX_ERROR if waypoint doesn't exist <br>
989      * IO_NOT_INITIALIZED
990      *
991      * @exception  GpsTimeoutException ...
992      * @exception  IOException ...
993      */
994     public int sendWpt(int index) throws GpsTimeoutException, IOException {
995         int ret;
996         int i;
997         
998         byte[] packs = new byte[2];
999         int numWpts;
1000        
1001        if( !ioInit ) return IO_NOT_INITIALIZED;
1002        if( gpsId == 0 ) {
1003            // make sure Gps has been detetced:
1004            ret = getGpsId();
1005            if( ret != SUCCESS ) return ret;
1006        } else {
1007            // send NACK; may help to recover from interrupted transmissions:
1008            // makes problems when sending single waypoints repeatedly:
1009            //sendVarPacket( (byte) PID_NACK, msg, (byte) 0 );
1010        }
1011        
1012        // get wpt from the list:
1013        numWpts = wptCont.size();
1014        if( (index > numWpts) || (numWpts == 0) ) return WRONG_INDEX_ERROR;
1015        
1016        if( index >= 0 ) {
1017            // send number of records to follow to the GPS
1018            packs[0] = 1; // data packet(s) to follows
1019            packs[1] = 0;
1020            ret = sendVarPacket( (byte) PID_RECORDS, packs, (byte) 2 );
1021            if( ret != SUCCESS ) return ret;
1022            
1023            sendASingleWpt( index, (byte)PID_WPT_DATA, WPT_MODE );
1024            
1025        } else {
1026            // send number of records to follow to the GPS
1027            packs[0] = (byte) (numWpts&0xFF); // data packet(s) to follows
1028            packs[1] = (byte) ((numWpts&0xFF00)>>8);
1029            ret = sendVarPacket( (byte) PID_RECORDS, packs, (byte) 2 );
1030            if( ret != SUCCESS ) return ret;
1031            
1032            if( numWpts > 500 ) numWpts = 500; // limit  Garmin12
1033            for( i=0; i<numWpts; i++ ) {
1034                sendASingleWpt(i, (byte) PID_WPT_DATA, WPT_MODE );
1035            }
1036        }
1037        
1038        // terminate wpt-transfer
1039        ret = sendVarPacket( (byte) PID_XFER_CMPLT, packs, (byte) 0 );
1040        
1041        return ret;
1042    }
1043    
1044    /**
1045     * Get the track (may consist of multiple segments) from the Gps.
1046     * Adds only trackpoints from the date specified.<br>
1047     * It also removes any segments that are considered not to be a track because
1048     * the distance moved is too small (tbd: add parameter!).<br>
1049     * This function is prepared to manage multiple
1050     * tracks for displaying / analysis (param: trackNumber).<br>
1051     * New: Supports A301 transfer protocol
1052     *
1053     * @param  date<br>
1054     * 0  :  any date (load complete track)<br>
1055     * any  :  specified date (time should be set to 00:00 in UTC[ms]; to be improved) <br>
1056     * @param  trackNumber: number (buffer) of the track to use (ignored, for later enhancements)<br>
1057     * @param  readMode: Gps.REPLACE or Gps.APPEND  track
1058     *
1059     * @return SUCCESS <br>
1060     * BAD_CRC: CRC-error <br>
1061     * TX_RETRY_ERROR if too much NACKs have been received; <br>
1062     * IO_NOT_INITIALIZED
1063     *
1064     * @exception  GpsTimeoutException ...
1065     * @exception  IOException ...
1066     */
1067    public int getTrack( long date, int trackNumber, int mode ) throws GpsTimeoutException, IOException {
1068        int ret;
1069        
1070        int lat,
1071        lon;
1072        int numPacks;
1073        
1074        byte locBuf[] = new byte[2];
1075        int pidTmp = PID_TRK_DATA;
1076        Date date1 = new Date();
1077        boolean firstOne = true;
1078        float   height;
1079        
1080        if( !ioInit ) return IO_NOT_INITIALIZED;
1081        if( gpsId == 0 ) {
1082            // make sure Gps has been detetced:
1083            ret = getGpsId();
1084            if( ret != SUCCESS ) return ret;
1085        }
1086        
1087        // send request to GPS: send wpts
1088        locBuf[0] = CMD_TRANSFER_TRK;
1089        ret = sendVarPacket( (byte) PID_CMD_DATA, locBuf, (byte) 2 );
1090        if((debug&0x01)!=0) printDebug("ret: " + ret + " ---");
1091        if( ret != SUCCESS ) return ret;
1092        // printDebug("(n)ack pid: " + pid + " ---");
1093        //if( pid != PID_ACK ) return 0;
1094        
1095        // GPS sends PID_RECORDS and num packets to come:
1096        ret = getPacket(false);
1097        if( ret != SUCCESS ) return ret;
1098        if((debug&0x01)!=0) printDebug("data pid (expected: 27): " + pid + " ---");
1099        if((debug&0x01)!=0) printDebug("num packets: " + absByte(dataBuf[0]) + " " + absByte(dataBuf[1]));
1100        numPacks = absByte(dataBuf[0]) + (absByte(dataBuf[1])<<8);
1101        if((debug&0x01)!=0) printDebug("num packets to come: " + numPacks + " ---\nPlease wait ...");
1102        // confirm data:
1103        sendVarPacket( (byte) PID_ACK, msg, (byte) 0 ); // ACK
1104        
1105        // read track coordinates
1106        if( mode == Gps.REPLACE ) trkCont.removeTracksFromTrack(0);
1107        if( numPacks > 0 ) {
1108            
1109            while( (pidTmp == PID_TRK_DATA) || (pidTmp == PID_TRK_HDR) ) {
1110                ret = getPacket(false);
1111                pidTmp = pid;
1112                if( ret == SUCCESS ) {
1113                    // confirm data:
1114                    sendVarPacket( (byte) PID_ACK, msg, (byte) 0 ); // ACK
1115                }
1116                else {
1117                    // doesn't work as expected sometimes :-(
1118                    sendVarPacket( (byte) PID_NACK, msg, (byte) 0 ); // NACK
1119                    continue;
1120                }
1121                
1122                // ignore track header data
1123                if( (pidTmp != PID_XFER_CMPLT) && (pidTmp != PID_TRK_HDR) ) {
1124                    Trk curTrk = new Trk();
1125                    // setup input stream to read data from buffer:
1126                    DataInputStream in =
1127                    new DataInputStream(
1128                    new BufferedInputStream(
1129                    new ByteArrayInputStream(dataBuf)));
1130                    curTrk = new Trk();
1131                    
1132                    lat = in.readInt();
1133                    lat = swap32(lat);
1134                    lon = in.readInt();
1135                    lon = swap32(lon);
1136                    curTrk.timeStamp = swap32(in.readInt());
1137                    // Convert Garmin-time to UTC [ms]:
1138                    curTrk.timeStamp += DIFF_UTC_GPS_TIME;
1139                    curTrk.timeStamp *= 1000;
1140                    
1141                    if( GpsCaps.trk_a == 301 ) {
1142                        // is of ETREX-type or Geko 201
1143                        int accum = 0;
1144                        accum = in.readInt();
1145                        accum = swap32(accum);
1146                        height = Float.intBitsToFloat(accum);
1147                        if( height == 1.0e25 ) { // not supported by device or unknown
1148                            curTrk.height = 0;
1149                        } else {
1150                            curTrk.height = (int) height;
1151                        }
1152                        // dummy-read -> drop depth-value:
1153                        in.readFloat();
1154                    }
1155                    
1156                    curTrk.newTrkSeg = in.readByte();
1157                    if( (curTrk.newTrkSeg == 1) || (firstOne == true) ) {
1158                        firstOne = false;
1159                        date1.setTime(curTrk.timeStamp);
1160                        printMessage("New track starts at (UTC) " + date1.toString() );
1161                    }
1162                    curTrk.dlat = ((double)lat*180)/MAX_INT;
1163                    curTrk.dlon = ((double)lon*180)/MAX_INT;
1164                    curTrk.rlat = curTrk.dlat * Math.PI * 2 / 360;
1165                    curTrk.rlon = curTrk.dlon * Math.PI * 2 / 360;
1166                    
1167                    // check date of waypoint:
1168                    if((debug&0x01)!=0) printDebug("UTC-timestamp [s]: " + curTrk.timeStamp);
1169                    if( ((curTrk.timeStamp >= date) && (curTrk.timeStamp < (date+86400000))) || (date == 0 ) ) {
1170                        trkCont.addTrk(0,curTrk);
1171                    }
1172                    curTrk.calcSignature();
1173                }
1174                
1175            } // while( pidTmp == PID_TRK_DATA )
1176            
1177            trkCont.removeNonFlights(0, 0.1);
1178        } else {
1179            if((debug&0x01)!=0) printDebug("no track on GPS ---");
1180        }
1181        
1182        return ret;
1183    }
1184    
1185    
1186    /**
1187     * Sends one route to the GPS.
1188     * Route null is the active route.
1189     * If a waypoint isn't found in the list, remaining waypoints are not transmitted any more.
1190     * New: Transfer protocol 201 is supportted, fixed to "line mode"; experimental
1191     *
1192     * @param  index  index of the route to send in the List
1193     *
1194     * @return SUCCESS <br>
1195     * BAD_CRC: CRC-error <br>
1196     * TX_RETRY_ERROR if too much NACKs have been received; <br>
1197     * WRONG_INDEX_ERROR if route-index too high <br>
1198     * RTE_NOT_FOUND_ERROR if route-index doesn't exist <br>
1199     * WPT_NOT_FOUND_ERROR if waypoint in route is not in the waypoint list <br>
1200     * IO_NOT_INITIALIZED
1201     *
1202     * @exception  GpsTimeoutException ...
1203     * @exception  IOException ...
1204     */
1205    public int sendRte(int rteNr, int index) throws GpsTimeoutException, IOException {
1206        int ret;
1207        int i,j;
1208        
1209        byte[] packs = new byte[2];
1210        byte[] locBuf2 = new byte[41];
1211        byte[] rteLnk = {0,3, /*class = direct, swapped word (!)*/
1212        0,0,
1213        0,0,0,0,
1214        -1,-1,-1,-1,
1215        -1,-1,-1,-1,
1216        -1,-1,-1,-1,
1217        0 // no ident
1218        };
1219        int size;
1220        
1221        String rteWpt;
1222        
1223        if( !ioInit ) return IO_NOT_INITIALIZED;
1224        if( index < 0 ) return WRONG_INDEX_ERROR;
1225        // if( GpsCaps.rte_a == 201 ) return PROTOCOL_NOT_SUPPORTED;
1226        if( gpsId == 0 ) {
1227            // make sure Gps has been detetced:
1228            ret = getGpsId();
1229            if( ret != SUCCESS ) return ret;
1230        } else {
1231            // send NACK; may help to recover from interrupted transmissions:
1232            //sendVarPacket( (byte) PID_NACK, msg, (byte) 0 );
1233        }
1234        
1235        // check index:
1236        size = rteCont.size();
1237        if((debug&0x01)!=0) printDebug("--- send route " + index + " " + size + " ---");
1238        if(size == 0) return RTE_NOT_FOUND_ERROR;
1239        
1240        // setup input stream to write data to buffer:
1241        ByteArrayOutputStream locBuf = new ByteArrayOutputStream(60);
1242        DataOutputStream out = new DataOutputStream( locBuf );
1243        
1244        // select route in the list:
1245        curRte = rteCont.routeAt(index);
1246        
1247        // send number of records to follow to the GPS
1248        if((debug&0x01)!=0) printDebug("route " + curRte.rteNumber + " " + curRte.comment);
1249        if( GpsCaps.rte_a == 201 ) {
1250            packs[0] = (byte)(2*curRte.wptName.size()); // data packet(s) to follows
1251        } else {
1252            packs[0] = (byte)(1+curRte.wptName.size()); // data packet(s) to follows
1253        }
1254        packs[1] = 0;
1255        ret = sendVarPacket( (byte) PID_RECORDS, packs, (byte) 2 );
1256        if( ret != SUCCESS ) return ret;
1257        
1258        // create and send route header:
1259        if( GpsCaps.rte_d[0] == 200 ) {
1260            out.writeByte((byte) rteNr); // route number
1261        }
1262        else if( GpsCaps.rte_d[0] == 201 ) {
1263            out.writeByte((byte) rteNr); // route number
1264            curRte.comment = curRte.comment.toUpperCase();
1265            out.writeBytes(curRte.comment + "                    "); // append bytes to get 20 bytes
1266        }
1267        else if( GpsCaps.rte_d[0] == 202 ) {
1268            curRte.comment = curRte.comment.toUpperCase();
1269            out.writeBytes(curRte.comment);
1270      out.writeByte(0);
1271        }
1272
1273        locBuf2 = locBuf.toByteArray(); // get buffer
1274        // send header:
1275        if((debug&0x01)!=0) printDebug("route header ...");
1276        ret = sendVarPacket( (byte) PID_RTE_HDR, locBuf2, (byte) out.size() );
1277        if( ret != SUCCESS ) return ret;
1278        
1279        // now search the waypoints in the list and send them to the GPS:
1280        size = curRte.wptName.size();
1281        for( i=0; i<size; i++) {
1282            // get name of next wpt:
1283            rteWpt = (String) curRte.wptName.elementAt(i);
1284            // search it in the list of all wpts:
1285            for( j=0; j<wptCont.size(); j++ ) {
1286                curWpt = wptCont.wptAt(j);
1287                if( curWpt.name.compareTo(rteWpt) == 0 ) break; // wpt found in list
1288            }
1289            
1290            if( j == wptCont.size() ) {
1291                if((debug&0x01)!=0) printDebug("rte-wpt not found: " + rteWpt);
1292                ret = WPT_NOT_FOUND_ERROR;
1293                break; // fatal error
1294            }
1295            
1296            if((debug&0x01)!=0) printDebug("rte-wpt found: " + curWpt.name);
1297            ret = sendASingleWpt( j, (byte)PID_RTE_WPT_DATA, RTE_MODE );
1298            if( ret != SUCCESS ) break;
1299            if( (GpsCaps.rte_a == 201) && (i != (size-1)) ) {
1300                sendVarPacket( (byte) PID_RTE_LNK, rteLnk, (byte) 20 );
1301            }
1302        }
1303        
1304        // terminate wpt-transfer
1305        sendVarPacket( (byte) PID_XFER_CMPLT, packs, (byte) 0 );
1306        
1307        return ret;
1308    }
1309    
1310    
1311    /**
1312     * Read all storted routes from the GPS and store it locally.
1313     * The waypoints that make up a specific route are read in. If they don't already exist,
1314     * they will be added to the list of existing waypoints. This is checked by the name.
1315     * Existing routes will be
1316     * The route's waypoints are defined by the list of names of waypoints only to avoid ambiguities.
1317     * New: Transfer protocl A201 is partly supported (link data will be ignored)
1318     *
1319     * @param  mode: Gps.REPLACE or Gps.APPEND  route(s) to the list
1320     *
1321     * @return SUCCESS <br>
1322     * BAD_CRC: CRC-error  <br>
1323     * TX_RETRY_ERROR if too much NACKs have been received; <br>
1324     * IO_NOT_INITIALIZED
1325     *
1326     * @exception  GpsTimeoutException ...
1327     * @exception  IOException ...
1328     */
1329    public int getRte(int mode) throws GpsTimeoutException, IOException {
1330        int ret;
1331        int i;
1332        int numPacks;
1333        byte locBuf[] = new byte[2];
1334        int pidTmp = PID_RTE_HDR;
1335        boolean addRoute = false; // no route read so far
1336        
1337        if( !ioInit ) return IO_NOT_INITIALIZED;
1338        if( gpsId == 0 ) {
1339            // make sure Gps has been detetced:
1340            ret = getGpsId();
1341            if( ret != SUCCESS ) return ret;
1342        } else {
1343            // send NACK; may help to recover from interrupted transmissions:
1344            sendVarPacket( (byte) PID_NACK, msg, (byte) 0 );
1345        }
1346        
1347        
1348        
1349        if((debug&0x01)!=0) printDebug("--- get route ---");
1350        // send request to GPS: send route
1351        locBuf[0] = CMD_TRANSFER_RTE;
1352        ret = sendVarPacket( (byte) PID_CMD_DATA, locBuf, (byte) 2 );
1353        if((debug&0x01)!=0) printDebug("ret: " + ret + " ---");
1354        if( ret != SUCCESS ) return ret;
1355        
1356        // GPS sends PID_RECORDS and num packets to come:
1357        ret = getPacket(false);
1358        if( ret != SUCCESS ) return ret;
1359        if((debug&0x01)!=0) {
1360            printDebug("data pid (expected pid: 27): " + pid + " ---");
1361            printDebug("num packets: " + absByte(dataBuf[0]) + " " + absByte(dataBuf[1]));
1362        }
1363        numPacks = absByte(dataBuf[0]) + (absByte(dataBuf[1])<<8);
1364        if((debug&0x01)!=0) printDebug("num packets to come: " + numPacks + " ---");
1365        // confirm data:
1366        sendVarPacket( (byte) PID_ACK, msg, (byte) 0 ); // ACK
1367        
1368        // read wpts:
1369        pid