~bilalakhtar/ubuntu/maverick/gpsdrive/gpsdrive-fix-325288

« back to all changes in this revision

Viewing changes to src/garmin_application.cpp

  • Committer: Bazaar Package Importer
  • Author(s): Frank Kirschner
  • Date: 2004-05-25 11:44:03 UTC
  • Revision ID: james.westby@ubuntu.com-20040525114403-j3rsu57cavfax6z8
Tags: upstream-2.09
ImportĀ upstreamĀ versionĀ 2.09

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
// -*- mode: c++; c-basic-offset: 8; -*-
 
2
// $Id: garmin_application.cpp,v 1.4 2003/04/28 15:42:38 ganter Exp $
 
3
// garmin_application.cp
 
4
// Douglas S. J. De Couto
 
5
// September 9, 1998
 
6
 
 
7
// Copyright (C) 1998 Douglas S. J. De Couto
 
8
// <decouto@lcs.mit.edu>
 
9
//
 
10
// This program is free software; you can redistribute it and/or
 
11
// modify it under the terms of the GNU General Public License
 
12
// as published by the Free Software Foundation; either version 2
 
13
// of the License, or (at your option) any later version.
 
14
//
 
15
// This program is distributed in the hope that it will be useful,
 
16
// but WITHOUT ANY WARRANTY; without even the implied warranty of
 
17
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 
18
// GNU General Public License for more details.
 
19
 
 
20
 
 
21
#include "garmin_application.h"
 
22
#include "garmin_command.h"
 
23
#include "garmin_util.h"
 
24
#include "garmin_data.h"
 
25
#include "garmin_legacy.h"
 
26
 
 
27
#include <iostream>
 
28
 
 
29
#include <cctype>
 
30
#include <algorithm>
 
31
#include <stdio.h>
 
32
#include <assert.h>
 
33
 
 
34
namespace garmin 
 
35
{
 
36
using namespace std;
 
37
 
 
38
#define check_init() if (!m_init) throw not_possible("The garmin application layer is not initialized")
 
39
 
 
40
 
 
41
/////
 
42
// Aborts any pending transfer
 
43
////
 
44
void
 
45
application_layer::abort_transfer(void) throw (timeout)
 
46
{
 
47
        check_init();
 
48
 
 
49
        //      uint8 sz;
 
50
        sint16 *buf16 = (sint16 *) m_buf;
 
51
        //packet_id pid;
 
52
 
 
53
        buf16[0] = host2garmin16((sint16) cmnd_abort_transfer);
 
54
        m_ll->put_packet(pid_command_data, m_buf, 2);
 
55
        
 
56
}
 
57
 
 
58
//////////////////
 
59
 
 
60
product_data_type
 
61
application_layer::get_product_data(void) throw (not_possible, timeout)
 
62
{
 
63
        check_init();
 
64
        
 
65
        uint8 sz;
 
66
        packet_id pid;
 
67
 
 
68
 
 
69
        // First, abort any pending transfer:
 
70
        abort_transfer();
 
71
        
 
72
        m_ll->put_packet(pid_product_rqst, m_buf, 0);
 
73
        pid = m_ll->get_packet(m_buf, sz);
 
74
        
 
75
        if (pid != pid_product_data) {
 
76
                throw not_possible("GPS did not reply with product data packet");
 
77
        }
 
78
        
 
79
        if (sz < 5) {
 
80
                throw not_possible("Product data packet is too small");
 
81
        }
 
82
 
 
83
        product_data_type pd;   
 
84
        sint16 *buf16 = (sint16 *) m_buf;
 
85
        pd.product_id = garmin2host16(buf16[0]);
 
86
        pd.software_version = garmin2host16(buf16[1]);
 
87
        pd.product_description = &((char *) m_buf)[4];
 
88
        
 
89
        // get capability protocol info... (A001),
 
90
        // but not supported on all units!
 
91
        try {
 
92
                pid = m_ll->get_packet(m_buf, sz);
 
93
        }
 
94
        catch (timeout &ex) {
 
95
                // timeout indicates gps is not sending capability protocol info
 
96
                m_got_protocol_info = false;
 
97
 
 
98
                // we should compose our own capability info from the device id 
 
99
                for (int i = 0; legacy_devices[i].id; i++)
 
100
                {
 
101
                        legacy_device *ldp = &legacy_devices[i];
 
102
 
 
103
                        if (    ldp->id == pd.product_id && 
 
104
                                ldp->version_min <= pd.software_version &&
 
105
                                ldp->version_max >= pd.software_version)
 
106
                        {
 
107
                                // found it, creating capability info
 
108
                                for (int j = 0; ldp->protocols[j].tag ; j++)
 
109
                                {
 
110
                                        protocol_datatypes_t x;
 
111
                                        for (int k = 0; ldp->protocols[j].types[k] != type_end; k++)
 
112
                                        {
 
113
                                                x.push_back(ldp->protocols[j].types[k]);
 
114
                                        }
 
115
                                        pd.protocol_info[(ldp->protocols[j].id << 8) | ((unsigned char)ldp->protocols[j].tag)] =  x;                       
 
116
                                }
 
117
 
 
118
                        
 
119
                                break;  
 
120
                        }
 
121
                }
 
122
                return pd;
 
123
        }
 
124
        m_got_protocol_info = true;
 
125
        if (pid != pid_protocol_array) {
 
126
                throw not_possible("Product data packet followed by some packet besides capability protocol");
 
127
        }
 
128
        if ((sz % 3) != 0) {
 
129
                throw not_possible("Capability protocol packet is strange size");
 
130
        }
 
131
 
 
132
 
 
133
        // we store now the protocols support by the device and the
 
134
        // associated data types 
 
135
 
 
136
        int lastdata(-1);
 
137
        // contains the last found protocol id
 
138
        // used to known where to store the datatype infos
 
139
 
 
140
        for (sint16 i = 0; i < sz; i +=3) {
 
141
                char tag = (char) m_buf[i];
 
142
                uint16 data = garmin2host16(*(uint16 *) (m_buf + i + 1));
 
143
                
 
144
                if ( tag != 'D' )
 
145
                {
 
146
                        // is a protocol info
 
147
                        protocol_datatypes_t x;
 
148
                        lastdata = (data << 8) | ((unsigned char)tag);
 
149
                        pd.protocol_info[lastdata] =  x;
 
150
                }
 
151
                else
 
152
                {
 
153
                        // is a protocol data type
 
154
                        assert(lastdata != -1);
 
155
                        pd.protocol_info[lastdata].push_back(data);
 
156
                }
 
157
                
 
158
                                
 
159
        }
 
160
        return pd;
 
161
}
 
162
 
 
163
 
 
164
//////
 
165
// This reads the display bitmap on GPS models that support this.
 
166
// Saves the bitmap into a BMP file
 
167
//
 
168
//
 
169
// Screen data is stored as unsigned long format, each long (32 bits)
 
170
// contains 16 pixels, with 2 bits per pixel.
 
171
//
 
172
//  0= white, 1=Light grey, 2=dark grey, 3=black
 
173
//
 
174
// Please note that display is actually mirrored! We would need to put everything
 
175
// into a table in memory before flushing it to disk if we wanted to have the right
 
176
// display.
 
177
/////
 
178
void
 
179
application_layer::get_display_bitmap(void) throw (not_possible, timeout)
 
180
{
 
181
        check_init();
 
182
        product_data_type pd = get_product_data();
 
183
 
 
184
        uint8 sz;
 
185
        uint16 width, height;
 
186
        sint16 *buf16 = (sint16 *) m_buf;
 
187
        uint32 tlong,q,ptr;
 
188
        FILE *outfile;
 
189
        // I'm using the BMP format because it's the one used by g7to and I don't
 
190
        // have enough time to create PNG or something fancy like this.
 
191
        // This is a standard BMP header adapted to our purpose:
 
192
        unsigned char bmh[118] = {
 
193
                66,  77, 182,  31,   0,   0,   0,   0,   0,   0, 118,   0,   0, 
 
194
                0,  40,   0,   0,   0, 160,   0,   0,   0, 100,   0,   0,   0, 
 
195
                1,   0,   4,   0,   0,   0,   0,   0,  64,  31,   0,   0,   0, 
 
196
                0,   0,   0,   0,   0,   0,   0,  16,   0,   0,   0,  16,   0, 
 
197
                0,   0,   0,   0,   0,   0,  99,  99,  99,   0, 181, 181, 181, 
 
198
                0, 255, 255, 255,   0, 255, 255, 255,   0, 255, 255, 255,   0, 
 
199
                255, 255, 255,   0, 255, 255, 255,   0, 255, 255, 255,   0, 255, 
 
200
                255, 255,   0, 255, 255, 255,   0, 255, 255, 255,   0, 255, 255, 
 
201
                255,   0, 255, 255, 255,   0, 255, 255, 255,   0, 255, 255, 255,   0 
 
202
        }; // bmh[118]
 
203
 
 
204
        // Abort any pending/failed transfer:
 
205
        abort_transfer();
 
206
 
 
207
        buf16[0] = host2garmin16((sint16) cmnd_transfer_screenbitmap);
 
208
        m_ll->put_packet(pid_command_data, m_buf, 2);
 
209
        
 
210
        packet_id pid = m_ll->get_packet(m_buf, sz);
 
211
        
 
212
        if (pid != pid_display_data) {
 
213
                throw not_possible("GPS did not reply with start of screen bitmap data packet");
 
214
        }
 
215
 
 
216
        // First packet contains screen width and lenght at the following offsets:
 
217
        // 16: width
 
218
        // 20: height (number of lines)
 
219
        width = *(uint16 *) (m_buf + 16);
 
220
        height =*(uint16 *) (m_buf + 20);
 
221
        cout << "Screen size: " << width << "x" << height << endl;
 
222
        
 
223
        // Open the screen.bmp file and write the header
 
224
        bmh[18]= width;
 
225
        bmh[22]= height;
 
226
        outfile = fopen("screenshot.bmp","w");
 
227
        tlong=width*height/2;
 
228
        memcpy(&bmh[34],&tlong,4);
 
229
        tlong+=118;
 
230
        memcpy(&bmh[2],&tlong,4);
 
231
        fwrite(bmh,118,1,outfile);
 
232
 
 
233
        // Then parse each subsequent packet and
 
234
        // write the data into the BMP file after parsing.
 
235
        int pixnum = 0;
 
236
        for (int i=0; i< height; i++) {
 
237
                // Get next packet with screen line
 
238
                pid = m_ll->get_packet(m_buf, sz);
 
239
                if (pid != pid_display_data) throw not_possible("GPS did not reply with screen bitmap data packet");                   
 
240
                q = 8;
 
241
                ptr = *(uint32*) (m_buf+q);
 
242
                // Offset 4 is the pixel number starting the line
 
243
                pixnum = *(uint32*) (m_buf + 4);
 
244
                cout << "Line number " << i << "\r" << flush;
 
245
                // Add the pixels to the new pixel bitmap:
 
246
                uint32 mask = 0x3;
 
247
                uint32 ptr;
 
248
                uint16 bit_shift;
 
249
                uint8 a,b,c;
 
250
                for (int j=0; j< width / 16; j++) {
 
251
                        mask=0x3L;
 
252
                        bit_shift=0;
 
253
                        for(int j=1;j<5;j++) {              // for each byte in long
 
254
                                for(int k=1;k<3;k++) {      // for each pixel in the byte
 
255
                                        //
 
256
                                        // Our bmp output file has one nibble per pixel
 
257
                                        // first nibble of byte
 
258
                                        //
 
259
                                        ptr = *(uint32*)(m_buf+q);
 
260
                                        a = (~(uint8)(((ptr) & mask) >> bit_shift)) & 3;
 
261
                                        bit_shift += 2;
 
262
                                        mask=mask << 2;
 
263
                                        //
 
264
                                        // second nibble of byte
 
265
                                        //
 
266
                                        b= (~(uint8)(((ptr)&mask)>>bit_shift))&3;
 
267
                                        bit_shift += 2;
 
268
                                        mask=mask << 2;
 
269
                                        //
 
270
                                        // Write line into file:
 
271
                                        //
 
272
                                        c = (a<<4)|b;
 
273
                                        fwrite(&c,1,1,outfile);
 
274
                                }
 
275
                        }
 
276
                        q +=4;  // index pointer to next 4 bytes (unsigned long)
 
277
                }
 
278
        }
 
279
        fclose(outfile);
 
280
}
 
281
 
 
282
/////////////////
 
283
 
 
284
radian_type
 
285
application_layer::get_pvt(void) throw (not_possible, timeout)
 
286
{
 
287
        check_init();
 
288
                                                                                                                      
 
289
        sint16 *sbuf16 = (sint16 *) m_buf;
 
290
                                                                                                                      
 
291
        sbuf16[0] = host2garmin16((sint16) cmnd_start_pvt_data);
 
292
        m_ll->put_packet(pid_command_data, m_buf, 2);
 
293
                                                                                                                      
 
294
        uint8 sz;
 
295
        packet_id pid = m_ll->get_packet(m_buf, sz);
 
296
                                                                                                                      
 
297
        if (pid != pid_pvt_data) {
 
298
                throw not_possible("GPS did not respond with position packet");
 
299
        }
 
300
        if (sz != 16) {
 
301
                throw not_possible("Position packet is the wrong size");
 
302
        }
 
303
                                                                                                                      
 
304
        double64 *dbuf = (double64 *) m_buf;
 
305
        radian_type retval;
 
306
        retval.lat = garmin2host64(dbuf[0]);
 
307
        retval.lon = garmin2host64(dbuf[1]);
 
308
 
 
309
        return retval;
 
310
}
 
311
 
 
312
///////////////////
 
313
 
 
314
 
 
315
 
 
316
 
 
317
 
 
318
waypt_vec_t *
 
319
application_layer::get_waypoints(void) throw (not_possible, timeout, unsupported_protocol)
 
320
{
 
321
        check_init();
 
322
 
 
323
        product_data_type pd = get_product_data();
 
324
 
 
325
        if (!pd.protocol_info.empty() && !pd.has_protocol('A',100))
 
326
        {
 
327
                throw unsupported_protocol("GPS does not support selected protocol");
 
328
        }
 
329
        
 
330
        uint8 sz;
 
331
        sint16 *buf16 = (sint16 *) m_buf;
 
332
        char ident[7];
 
333
        char cmnt[41];
 
334
        ident[6] = cmnt[40] = 0;
 
335
        
 
336
        buf16[0] = host2garmin16((sint16) cmnd_transfer_wpt);
 
337
        m_ll->put_packet(pid_command_data, m_buf, 2);
 
338
        
 
339
        packet_id pid = m_ll->get_packet(m_buf, sz);
 
340
        
 
341
        if (pid != pid_records) {
 
342
                throw not_possible("GPS did not reply with start of records data packet for waypoint data");
 
343
        }
 
344
        if (sz != 2) {
 
345
                throw not_possible("Waypoint data start of records packet is wrong size");
 
346
        }
 
347
        
 
348
        sint16 num_recs = garmin2host16(buf16[0]);
 
349
        waypt_vec_t *waypts = new waypt_vec_t(num_recs);
 
350
        bool unsupp = false;
 
351
                
 
352
        for (sint16 i = 0; i < num_recs; i++) {
 
353
                basic_waypt_type &waypt = (*waypts)[i];
 
354
                
 
355
                pid = m_ll->get_packet(m_buf, sz);
 
356
                
 
357
                if (pid != pid_wpt_data) {
 
358
                        delete waypts;
 
359
                        throw not_possible("GPS did not send waypoint data packet");
 
360
                }
 
361
                /*
 
362
                if (sz < (6 + 8 + 4 + 40)) {
 
363
                        delete waypts;
 
364
                        throw not_possible("Waypoint data packet is too small");
 
365
                }
 
366
                */
 
367
                switch (pd.protocol_datatype('A',100,0))
 
368
                {
 
369
                        case 108:
 
370
                        case 109:
 
371
                        {
 
372
                                D108 my_d108(m_buf);
 
373
                                waypt << my_d108;
 
374
                                break;
 
375
                        }
 
376
                                
 
377
                        case 103:
 
378
                        {
 
379
                                uint32 *buf32 = (uint32 *) (m_buf + 6);
 
380
                                waypt.pos.lat = garmin2host32(buf32[0]);
 
381
                                waypt.pos.lon = garmin2host32(buf32[1]);
 
382
 
 
383
                                strncpy(ident, (char *) m_buf, 6);
 
384
                                waypt.id = string(ident);
 
385
        
 
386
                                strncpy(cmnt, (char *) (m_buf + 18), 40);
 
387
                                waypt.comment = string(cmnt);
 
388
                                break;
 
389
                        }
 
390
                        default:
 
391
                                unsupp = true; // Cannot just bail out, otherwise the GPS is confused
 
392
                }
 
393
        }
 
394
        if (unsupp)  throw unsupported_protocol("Waypoint Datatype of GPS not supported");
 
395
 
 
396
        pid = m_ll->get_packet(m_buf, sz);
 
397
        if (pid != pid_xfer_cmplt) {
 
398
                delete waypts;
 
399
                throw not_possible("GPS did not terminate waypoint data with end of records packet");
 
400
        }
 
401
        if (garmin2host16(buf16[0]) != cmnd_transfer_wpt) {
 
402
                delete waypts;
 
403
                throw not_possible("End of records packet does not match original waypoint transfer command");
 
404
        }
 
405
                
 
406
        return waypts;
 
407
                
 
408
}
 
409
 
 
410
/////////////////////
 
411
 
 
412
void 
 
413
application_layer::send_waypoints(waypt_vec_t *waypts) throw (not_possible, timeout)
 
414
{
 
415
        check_init();
 
416
        
 
417
        const   int d103_sz = 6 + 8 + 4 + 40 + 2;
 
418
 
 
419
        product_data_type pd = get_product_data();
 
420
 
 
421
        if (!(pd.has_protocol('A',100) && pd.protocol_datatype('A',100,0) == 103))
 
422
                {
 
423
                throw not_possible("Waypoint download not supported for this GPS");
 
424
        }
 
425
 
 
426
        sint16 *buf16 = (sint16 *) m_buf;
 
427
        buf16[0] = host2garmin16(waypts->size());
 
428
        
 
429
        m_ll->put_packet(pid_records, m_buf, 2);
 
430
        
 
431
        for (unsigned int i = 0; i < waypts->size(); i++) {
 
432
                basic_waypt_type &w = (*waypts)[i];
 
433
                
 
434
                // clear all fields
 
435
                memset(m_buf, 0, d103_sz);
 
436
                // set all waypt strings to blank spaces
 
437
                memset(m_buf, ' ', 6);
 
438
                memset(m_buf + 18, ' ', 40);
 
439
                
 
440
                // copy in strings, fixing up for GPS; leave bad characters as spaces
 
441
                for (size_t j = 0; j < min<size_t>(6, w.id.size()); j++) {
 
442
                        char c = w.id[j];
 
443
                        if (isalnum(c)) {
 
444
                                m_buf[j] = toupper(c);
 
445
                        }
 
446
                }
 
447
                for (size_t j = 0; j < min<size_t>(40, w.comment.length()); j++) {
 
448
                        char c = w.comment[j];
 
449
                        if (isalnum(c) || c == '-') {
 
450
                                m_buf[j + 18] = toupper(c);
 
451
                        }
 
452
                }
 
453
                
 
454
                // copy in position data
 
455
                uint32 *buf32 = (uint32 *) (m_buf + 6);
 
456
                buf32[0] = host2garmin32(w.pos.lat);
 
457
                buf32[1] = host2garmin32(w.pos.lon);
 
458
                
 
459
                m_ll->put_packet(pid_wpt_data, m_buf, d103_sz);
 
460
        }
 
461
        
 
462
        buf16[0] = host2garmin16(cmnd_transfer_wpt);
 
463
        m_ll->put_packet(pid_xfer_cmplt, m_buf, 2);
 
464
}
 
465
 
 
466
/////////////////////
 
467
 
 
468
route_list_t *
 
469
application_layer::get_routes() throw (not_possible, timeout)
 
470
{
 
471
        check_init();
 
472
        pd = get_product_data();
 
473
 
 
474
        if (!pd.protocol_info.empty() && pd.has_protocol('A',201))
 
475
        {
 
476
                return get_routes_201();        
 
477
        }
 
478
 
 
479
        if (!pd.protocol_info.empty() && pd.has_protocol('A',200))
 
480
        {
 
481
                return get_routes_200();        
 
482
        }
 
483
 
 
484
        return get_routes_200();
 
485
        // give it a try
 
486
}
 
487
                
 
488
 
 
489
 
 
490
route_list_t *
 
491
application_layer::get_routes_201() throw (not_possible, timeout, unsupported_protocol)
 
492
{
 
493
        check_init();
 
494
 
 
495
        if (!pd.protocol_info.empty() && !pd.has_protocol('A',201))
 
496
        {
 
497
                throw unsupported_protocol("GPS does not support selected protocol");
 
498
        }
 
499
                
 
500
 
 
501
        uint16 *buf16 = (uint16 *) m_buf;
 
502
        buf16[0] = host2garmin16((sint16) cmnd_transfer_rte);
 
503
        m_ll->put_packet(pid_command_data, m_buf, 2);
 
504
        uint8 sz;
 
505
 
 
506
        packet_id pid = m_ll->get_packet(m_buf, sz);
 
507
        if (pid != pid_records) {
 
508
                throw not_possible("GPS did not reply with start of records data packet for route data");
 
509
        }
 
510
        if (sz != 2) {
 
511
                throw not_possible("Route data start of records packet is wrong size");
 
512
        }
 
513
        sint16 num_packets = garmin2host16(buf16[0]);
 
514
 
 
515
        // create route list with no routes
 
516
        route_list_t *retval = new route_list_t(0);
 
517
        
 
518
        bool curr_rt_exists = false;
 
519
        for (sint16 i = 0; i < num_packets; i++) {
 
520
                pid = m_ll->get_packet(m_buf, sz);
 
521
                if (pid == pid_rte_hdr) {
 
522
                        // start new route
 
523
                        retval->push_back(list<basic_waypt_type>());
 
524
                        curr_rt_exists = true;
 
525
                        continue;
 
526
                }
 
527
                if (pid == pid_rte_link_data) {
 
528
                        curr_rt_exists = true;
 
529
                        continue;
 
530
                }
 
531
                
 
532
                if (pid != pid_rte_wpt_data) {
 
533
                        delete retval;
 
534
                        throw not_possible("Packet is not route waypoint data or route header");
 
535
                }
 
536
                if (!curr_rt_exists) {
 
537
                        delete retval;
 
538
                        throw not_possible("Route waypoint data packet was not preceded by a route header packet");
 
539
                }
 
540
                if (sz < (6 + 8 + 2 + 40)) {
 
541
                        delete retval;
 
542
                        throw not_possible("Route waypoint data packet is too small");
 
543
                }
 
544
 
 
545
                basic_waypt_type waypt;
 
546
 
 
547
                D108 my_d108(m_buf);
 
548
                waypt << my_d108;
 
549
                
 
550
                // add this waypoint to end of last route in route list.
 
551
                retval->back().push_back(waypt);
 
552
                
 
553
        }
 
554
        
 
555
        pid = m_ll->get_packet(m_buf, sz);
 
556
        if (pid != pid_xfer_cmplt) {
 
557
                delete retval;
 
558
                throw not_possible("GPS did not terminate route data with end of records packet");
 
559
        }
 
560
        if (garmin2host16(buf16[0]) != cmnd_transfer_rte) {
 
561
                delete retval;
 
562
                throw not_possible("End of records packet does not match original route transfer command");
 
563
        }
 
564
                
 
565
        return retval;
 
566
                
 
567
}
 
568
/////////////////////
 
569
 
 
570
route_list_t *
 
571
application_layer::get_routes_200(void) throw (not_possible, timeout, unsupported_protocol)
 
572
{
 
573
        check_init();
 
574
 
 
575
        product_data_type pd = get_product_data();
 
576
 
 
577
        if (!pd.protocol_info.empty() && !pd.has_protocol('A',200))
 
578
        {
 
579
                throw unsupported_protocol("GPS does not support selected protocol");
 
580
        }
 
581
 
 
582
        uint16 *buf16 = (uint16 *) m_buf;
 
583
        buf16[0] = host2garmin16((sint16) cmnd_transfer_rte);
 
584
        m_ll->put_packet(pid_command_data, m_buf, 2);
 
585
        uint8 sz;
 
586
 
 
587
        packet_id pid = m_ll->get_packet(m_buf, sz);
 
588
        if (pid != pid_records) {
 
589
                throw not_possible("GPS did not reply with start of records data packet for route data");
 
590
        }
 
591
        if (sz != 2) {
 
592
                throw not_possible("Route data start of records packet is wrong size");
 
593
        }
 
594
        sint16 num_packets = garmin2host16(buf16[0]);
 
595
 
 
596
        // create route list with no routes
 
597
        route_list_t *retval = new route_list_t(0);
 
598
        
 
599
        bool curr_rt_exists = false;
 
600
        for (sint16 i = 0; i < num_packets; i++) {
 
601
                pid = m_ll->get_packet(m_buf, sz);
 
602
                if (pid == pid_rte_hdr) {
 
603
                        // start new route
 
604
                        retval->push_back(list<basic_waypt_type>());
 
605
                        curr_rt_exists = true;
 
606
                        continue;
 
607
                }
 
608
                
 
609
                if (pid != pid_rte_wpt_data) {
 
610
                        delete retval;
 
611
                        throw not_possible("Packet is not route waypoint data or route header");
 
612
                }
 
613
                if (!curr_rt_exists) {
 
614
                        delete retval;
 
615
                        throw not_possible("Route waypoint data packet was not preceded by a route header packet");
 
616
                }
 
617
                if (sz < (6 + 8 + 2 + 40)) {
 
618
                        delete retval;
 
619
                        throw not_possible("Route waypoint data packet is too small");
 
620
                }
 
621
                
 
622
                semicircle_type *sp = (semicircle_type *) (m_buf + 6);
 
623
                sp->lat = garmin2host32(sp->lat);
 
624
                sp->lon = garmin2host32(sp->lon);
 
625
 
 
626
                basic_waypt_type waypt;
 
627
 
 
628
                char ident[7], cmnt[41];
 
629
                ident[6] = cmnt[40] = 0;
 
630
                strncpy(ident, (char *) m_buf, 6);
 
631
                waypt.id = string(ident);
 
632
 
 
633
                waypt.pos = *sp;
 
634
                
 
635
                strncpy(cmnt, (char *) m_buf + 14, 40);
 
636
                waypt.comment = string(cmnt);
 
637
                
 
638
                // add this waypoint to end of last route in route list.
 
639
                retval->back().push_back(waypt);
 
640
                
 
641
        }
 
642
        
 
643
        pid = m_ll->get_packet(m_buf, sz);
 
644
        if (pid != pid_xfer_cmplt) {
 
645
                delete retval;
 
646
                throw not_possible("GPS did not terminate route data with end of records packet");
 
647
        }
 
648
        if (garmin2host16(buf16[0]) != cmnd_transfer_rte) {
 
649
                delete retval;
 
650
                throw not_possible("End of records packet does not match original route transfer command");
 
651
        }
 
652
                
 
653
        return retval;
 
654
                
 
655
}
 
656
 
 
657
/////////////////////
 
658
 
 
659
void 
 
660
application_layer::send_routes(route_list_t *routes) throw (not_possible, timeout)
 
661
{
 
662
        check_init();
 
663
                
 
664
        product_data_type pd = get_product_data();
 
665
 
 
666
        if (!(pd.has_protocol('A',200) && pd.protocol_datatype('A',200,1) == 103))
 
667
        {
 
668
                throw not_possible("Waypoint download not supported for this GPS");
 
669
        }
 
670
 
 
671
        const   int d103_sz = 6 + 8 + 4 + 40 + 2;
 
672
        
 
673
        // how many data packets?
 
674
        sint16 num_recs = 0;
 
675
        route_list_t::const_iterator llw;
 
676
        for (llw = routes->begin(); llw != routes->end(); llw++) {
 
677
                num_recs += llw->size();
 
678
        }
 
679
        num_recs += routes->size(); // plus 1 header packet for each route
 
680
        
 
681
        sint16 *buf16 = (sint16 *) m_buf;
 
682
        buf16[0] = host2garmin16(num_recs);
 
683
        
 
684
        m_ll->put_packet(pid_records, m_buf, 2);
 
685
        
 
686
        for (llw = routes->begin(); llw != routes->end(); llw++) {
 
687
                
 
688
                // put route header
 
689
                m_buf[0] = 10;
 
690
                char *test = "TESTING COMMENT     "; 
 
691
                for (int k = 0; k < 20; k++) {
 
692
                        m_buf[k + 1] = test[k];
 
693
                }
 
694
                m_ll->put_packet(pid_rte_hdr, m_buf, 21);
 
695
                
 
696
                // put route waypoints
 
697
                route_t::const_iterator lw;
 
698
                for (lw = llw->begin(); lw != llw->end(); lw++) {
 
699
                        memset(m_buf, 0, d103_sz);
 
700
                        // set all waypt strings to blank spaces
 
701
                        memset(m_buf, ' ', 6);
 
702
                        memset(m_buf + 18, ' ', 40);
 
703
                
 
704
                        // copy in strings, fixing up for GPS; leave bad characters as spaces
 
705
                        for (size_t j = 0; j < min<size_t>(6, lw->id.size()); j++) {
 
706
                                char c = lw->id[j];
 
707
                                if (isalnum(c)) {
 
708
                                        m_buf[j] = toupper(c);
 
709
                                }
 
710
                        }
 
711
                        for (size_t j = 0; j < min<size_t>(40, lw->comment.length()); j++) {
 
712
                                char c = lw->comment[j];
 
713
                                if (isalnum(c) || c == '-') {
 
714
                                        m_buf[j + 18] = toupper(c);
 
715
                                }
 
716
                        }
 
717
                
 
718
                        // copy in position data
 
719
                        uint32 *buf32 = (uint32 *) (m_buf + 6);
 
720
                        buf32[0] = host2garmin32(lw->pos.lat);
 
721
                        buf32[1] = host2garmin32(lw->pos.lon);
 
722
                
 
723
                        m_ll->put_packet(pid_rte_wpt_data, m_buf, d103_sz);
 
724
                }
 
725
        }
 
726
        buf16[0] = host2garmin16(cmnd_transfer_rte);
 
727
        m_ll->put_packet(pid_xfer_cmplt, m_buf, 2);
 
728
}
 
729
        
 
730
/////////////////////
 
731
 
 
732
void
 
733
application_layer::send_track_logs(track_list_t *tracks) throw (not_possible, timeout)
 
734
{
 
735
        check_init();
 
736
 
 
737
        // how many track points?
 
738
        sint16 num_recs = 0;
 
739
        track_list_t::const_iterator llti;
 
740
        for (llti = tracks->begin(); llti != tracks->end(); llti++) {
 
741
                num_recs += llti->size();
 
742
        }
 
743
        
 
744
        sint16 *sbuf16 = (sint16 *) m_buf;
 
745
        sbuf16[0] = host2garmin16(num_recs);
 
746
                
 
747
        m_ll->put_packet(pid_records, m_buf, 2);
 
748
        
 
749
        for (llti = tracks->begin(); llti != tracks->end(); llti++) {
 
750
                track_t::const_iterator lti;
 
751
                bool first = true;
 
752
                m_buf[8 + 4] = 1;
 
753
                for (lti = llti->begin(); lti != llti->end(); lti++, first = false) {
 
754
                
 
755
                        uint32 *buf32 = (uint32 *) m_buf;
 
756
                        buf32[0] = host2garmin32(lti->pos.lat);
 
757
                        buf32[1] = host2garmin32(lti->pos.lon);
 
758
                        
 
759
                        // GPS ignores time field, leave it as 0 
 
760
                        
 
761
                        m_ll->put_packet(pid_trk_data, m_buf, 16);
 
762
                        
 
763
                        // set new_track element at first point of each segment, but not for other
 
764
                        // points in track segment
 
765
                        if (first) {
 
766
                                m_buf[8 + 4] = 0;
 
767
                        }
 
768
                }
 
769
        }
 
770
        
 
771
        sbuf16[0] = host2garmin16(cmnd_transfer_trk);
 
772
        m_ll->put_packet(pid_xfer_cmplt, m_buf, 2);
 
773
}
 
774
 
 
775
/////////////////////
 
776
 
 
777
track_list_t *
 
778
application_layer::get_track_logs(void) throw (not_possible, timeout, unsupported_protocol)
 
779
{
 
780
        check_init();
 
781
        product_data_type pd = get_product_data();
 
782
 
 
783
        if (!pd.protocol_info.empty() && pd.has_protocol('A',301))
 
784
        {
 
785
                return get_track_logs_301();    
 
786
        }
 
787
 
 
788
        if (!pd.protocol_info.empty() && pd.has_protocol('A',300))
 
789
        {
 
790
                return get_track_logs_300();    
 
791
        }
 
792
 
 
793
        return get_track_logs_300();    
 
794
        // give it a try
 
795
}
 
796
 
 
797
track_list_t *
 
798
application_layer::get_track_logs_300(void) throw (not_possible, timeout, unsupported_protocol)
 
799
{
 
800
        check_init();
 
801
 
 
802
        product_data_type pd = get_product_data();
 
803
 
 
804
        if (!pd.protocol_info.empty() && !pd.has_protocol('A',300))
 
805
        {
 
806
                throw unsupported_protocol("GPS does not support selected protocol");
 
807
        }
 
808
        
 
809
        uint8 sz;
 
810
        sint16 *buf16 = (sint16 *) m_buf;
 
811
        
 
812
        buf16[0] = host2garmin16((sint16) cmnd_transfer_trk);
 
813
        m_ll->put_packet(pid_command_data, m_buf, 2);
 
814
        
 
815
        packet_id pid = m_ll->get_packet(m_buf, sz);
 
816
        
 
817
        if (pid != pid_records) {
 
818
                throw not_possible("GPS did not reply with start of records data packet for track log data");
 
819
        }
 
820
        if (sz != 2) {
 
821
                throw not_possible("Track log data start of records packet is wrong size");
 
822
        }
 
823
        
 
824
        sint16 num_recs = garmin2host16(buf16[0]);
 
825
        track_list_t *tracks = new track_list_t(0);
 
826
                
 
827
        for (sint16 i = 0; i < num_recs; i++) {
 
828
                pid = m_ll->get_packet(m_buf, sz);
 
829
                
 
830
                if (pid != pid_trk_data) {
 
831
                        delete tracks;
 
832
                        throw not_possible("GPS did not send track point data packet");
 
833
                }
 
834
 
 
835
                if (sz < (8 + 4 + 1)) {
 
836
                        delete tracks;
 
837
                        throw not_possible("Track point data packet is too small");
 
838
                }
 
839
                
 
840
                bool new_trk = m_buf[8 + 4];
 
841
                if (new_trk || i == 0) {
 
842
                        tracks->push_back(list<track_point_type>());
 
843
                }               
 
844
                
 
845
                semicircle_type *sp = (semicircle_type *) m_buf;
 
846
                sp->lat = garmin2host32(sp->lat);
 
847
                sp->lon = garmin2host32(sp->lon);
 
848
 
 
849
                track_point_type track_point;
 
850
                track_point.pos = *sp;
 
851
                track_point.new_track = new_trk;
 
852
                uint32 *buf32 = (uint32 *) m_buf;
 
853
                
 
854
                struct tm my_tm;
 
855
                memset(&my_tm, 0, sizeof(struct tm));
 
856
                my_tm.tm_sec = garmin2host32(buf32[2]);
 
857
                my_tm.tm_year = 89;
 
858
                my_tm.tm_mday = 31; // 1 based counting
 
859
                my_tm.tm_mon  = 11; // 0 based counting
 
860
                my_tm.tm_isdst = -1; // unknown
 
861
                
 
862
                track_point.time = mktime(&my_tm);
 
863
                
 
864
                tracks->back().push_back(track_point);
 
865
        }
 
866
        
 
867
        pid = m_ll->get_packet(m_buf, sz);
 
868
        if (pid != pid_xfer_cmplt) {
 
869
                delete tracks;
 
870
                throw not_possible("GPS did not terminate track log data with end of records packet");
 
871
        }
 
872
        if (garmin2host16(buf16[0]) != cmnd_transfer_trk) {
 
873
                delete tracks;
 
874
                throw not_possible("End of records packet does not match original track log transfer command");
 
875
        }
 
876
                
 
877
        return tracks;
 
878
}
 
879
 
 
880
track_list_t *
 
881
application_layer::get_track_logs_301(void) throw (not_possible, timeout, unsupported_protocol)
 
882
{
 
883
        check_init();
 
884
 
 
885
        product_data_type pd = get_product_data();
 
886
 
 
887
        if (!pd.protocol_info.empty() && !pd.has_protocol('A',301))
 
888
        {
 
889
                throw unsupported_protocol("GPS does not support selected protocol");
 
890
        }
 
891
        
 
892
        uint8 sz;
 
893
        sint16 *buf16 = (sint16 *) m_buf;
 
894
        
 
895
        buf16[0] = host2garmin16((sint16) cmnd_transfer_trk);
 
896
        m_ll->put_packet(pid_command_data, m_buf, 2);
 
897
        
 
898
        packet_id pid = m_ll->get_packet(m_buf, sz);
 
899
        
 
900
        if (pid != pid_records) {
 
901
                throw not_possible("GPS did not reply with start of records data packet for track log data");
 
902
        }
 
903
        if (sz != 2) {
 
904
                throw not_possible("Track log data start of records packet is wrong size");
 
905
        }
 
906
        
 
907
        sint16 num_recs = garmin2host16(buf16[0]);
 
908
        track_list_t *tracks = new track_list_t(0);
 
909
 
 
910
                
 
911
        for (sint16 i = 0; i < num_recs; i++) {
 
912
                pid = m_ll->get_packet(m_buf, sz);
 
913
 
 
914
                
 
915
                if (pid == pid_trk_hdr) {
 
916
                        cout << "New track: " << m_buf + 2 << endl;
 
917
                        continue;
 
918
                }
 
919
 
 
920
                if (pid != pid_trk_data) {
 
921
                        delete tracks;
 
922
                        throw not_possible("GPS did not send track point data packet");
 
923
                }
 
924
 
 
925
                if (sz < (8 + 4 + 1)) {
 
926
                        delete tracks;
 
927
                        throw not_possible("Track point data packet is too small");
 
928
                }
 
929
                
 
930
                bool new_trk = m_buf[8 + 4 + 8];
 
931
                if (new_trk || i == 0) {
 
932
                        tracks->push_back(list<track_point_type>());
 
933
                }               
 
934
        
 
935
                track_point_type track_point;
 
936
                D301 my_d301(m_buf);    
 
937
 
 
938
                track_point << my_d301;
 
939
                tracks->back().push_back(track_point);
 
940
        }
 
941
        
 
942
        pid = m_ll->get_packet(m_buf, sz);
 
943
        if (pid != pid_xfer_cmplt) {
 
944
                delete tracks;
 
945
                throw not_possible("GPS did not terminate track log data with end of records packet");
 
946
        }
 
947
        if (garmin2host16(buf16[0]) != cmnd_transfer_trk) {
 
948
                delete tracks;
 
949
                throw not_possible("End of records packet does not match original track log transfer command");
 
950
        }
 
951
                
 
952
        return tracks;
 
953
}
 
954
 
 
955
/////////////////
 
956
 
 
957
prox_waypt_vec_t *
 
958
application_layer::get_proximity_waypoints(void) throw (not_possible, timeout, unsupported_protocol)
 
959
{
 
960
        check_init();
 
961
 
 
962
        product_data_type pd = get_product_data();
 
963
 
 
964
        if (!pd.protocol_info.empty() && !pd.has_protocol('A',400))
 
965
        {
 
966
                throw unsupported_protocol("GPS does not support selected protocol");
 
967
        }
 
968
        
 
969
        uint8 sz;
 
970
        sint16 *buf16 = (sint16 *) m_buf;
 
971
        
 
972
        char ident[7];
 
973
        char cmnt[41];
 
974
        ident[6] = cmnt[40] = 0;
 
975
        
 
976
        buf16[0] = host2garmin16((sint16) cmnd_transfer_prx);
 
977
        m_ll->put_packet(pid_command_data, m_buf, 2);
 
978
        
 
979
        packet_id pid = m_ll->get_packet(m_buf, sz);
 
980
        
 
981
        if (pid != pid_records) {
 
982
                throw not_possible("GPS did not reply with start of records data packet for proximity waypoint data");
 
983
        }
 
984
        if (sz != 2) {
 
985
                throw not_possible("Proximity waypoint data start of records packet is wrong size");
 
986
        }
 
987
        
 
988
        sint16 num_recs = garmin2host16(buf16[0]);
 
989
        prox_waypt_vec_t *waypts = new prox_waypt_vec_t(num_recs);
 
990
                
 
991
        for (sint16 i = 0; i < num_recs; i++) {
 
992
                proximity_waypt_type &waypt = (*waypts)[i];
 
993
                
 
994
                pid = m_ll->get_packet(m_buf, sz);
 
995
                
 
996
                if (pid != pid_prx_wpt_data) {
 
997
                        delete waypts;
 
998
                        throw not_possible("GPS did not send proximity waypoint data packet");
 
999
                }
 
1000
                if (sz < (6 + 8 + 4 + 40 + 2 + 4)) {
 
1001
                        delete waypts;
 
1002
                        throw not_possible("Proximity waypoint data packet is too small");
 
1003
                }
 
1004
                
 
1005
                uint32 *buf32 = (uint32 *) (m_buf + 6);
 
1006
                waypt.waypt.pos.lat = garmin2host32(buf32[0]);
 
1007
                waypt.waypt.pos.lon = garmin2host32(buf32[1]);
 
1008
 
 
1009
                strncpy(ident, (char *) m_buf, 6);
 
1010
                waypt.waypt.id = string(ident);
 
1011
                
 
1012
                strncpy(cmnt, (char *) m_buf + 18, 40);
 
1013
                waypt.waypt.comment = string(cmnt);
 
1014
                
 
1015
                buf32 = (uint32 *) (m_buf + sz - 4);
 
1016
                *buf32 = garmin2host32(buf32[0]);
 
1017
                float32 *dist = (float32 *) buf32;
 
1018
                waypt.dist = *dist;
 
1019
        }
 
1020
        
 
1021
        pid = m_ll->get_packet(m_buf, sz);
 
1022
        if (pid != pid_xfer_cmplt) {
 
1023
                delete waypts;
 
1024
                throw not_possible("GPS did not terminate proximity waypoint data with end of records packet");
 
1025
        }
 
1026
        if (garmin2host16(buf16[0]) != cmnd_transfer_prx) {
 
1027
                delete waypts;
 
1028
                throw not_possible("End of records packet does not match original proximity waypoint transfer command");
 
1029
        }
 
1030
                
 
1031
        return waypts;
 
1032
                
 
1033
}
 
1034
 
 
1035
/////////////////////
 
1036
 
 
1037
void
 
1038
application_layer::send_proximity_waypoints(prox_waypt_vec_t *prx_waypts) throw (not_possible, timeout)
 
1039
{
 
1040
        check_init();
 
1041
        
 
1042
        product_data_type pd = get_product_data();
 
1043
 
 
1044
        if (!(pd.has_protocol('A',400) && pd.protocol_datatype('A',400,0) == 403))
 
1045
        {
 
1046
                throw not_possible("Waypoint download not supported for this GPS");
 
1047
        }
 
1048
        const   int d103_sz = 6 + 8 + 4 + 40 + 2;
 
1049
        
 
1050
        sint16 *buf16 = (sint16 *) m_buf;
 
1051
        buf16[0] = host2garmin16(prx_waypts->size());
 
1052
        
 
1053
        m_ll->put_packet(pid_records, m_buf, 2);
 
1054
        
 
1055
        for (unsigned int i = 0; i < prx_waypts->size(); i++) {
 
1056
                basic_waypt_type &w = (*prx_waypts)[i].waypt;
 
1057
                
 
1058
                // clear all fields
 
1059
                memset(m_buf, 0, d103_sz + 4);
 
1060
                // set all waypt strings to blank spaces
 
1061
                memset(m_buf, ' ', 6);
 
1062
                memset(m_buf + 18, ' ', 40);
 
1063
                
 
1064
                // copy in strings, fixing up for GPS; leave bad characters as spaces
 
1065
                for (size_t j = 0; j < min<size_t>(6, w.id.size()); j++) {
 
1066
                        char c = w.id[j];
 
1067
                        if (isalnum(c)) {
 
1068
                                m_buf[j] = toupper(c);
 
1069
                        }
 
1070
                }
 
1071
                for (size_t j = 0; j < min<size_t>(40, w.comment.length()); j++) {
 
1072
                        char c = w.comment[j];
 
1073
                        if (isalnum(c) || c == '-') {
 
1074
                                m_buf[j + 18] = toupper(c);
 
1075
                        }
 
1076
                }
 
1077
                
 
1078
                // copy in position data
 
1079
                uint32 *buf32 = (uint32 *) (m_buf + 6);
 
1080
                buf32[0] = host2garmin32(w.pos.lat);
 
1081
                buf32[1] = host2garmin32(w.pos.lon);
 
1082
                
 
1083
                // copy in proximity distance
 
1084
                buf32 = (uint32 *) (m_buf + d103_sz);
 
1085
                float32 d = (*prx_waypts)[i].dist;
 
1086
                uint32 *t32 = (uint32 *) &d;
 
1087
                *buf32 = host2garmin32(*t32);
 
1088
                
 
1089
                m_ll->put_packet(pid_prx_wpt_data, m_buf, d103_sz + 4);
 
1090
        }
 
1091
        
 
1092
        buf16[0] = host2garmin16(cmnd_transfer_prx);
 
1093
        m_ll->put_packet(pid_xfer_cmplt, m_buf, 2);
 
1094
 
 
1095
}
 
1096
 
 
1097
 
 
1098
/////////////////////
 
1099
 
 
1100
void
 
1101
application_layer::turn_off_gps(void) throw (not_possible, timeout)
 
1102
{
 
1103
        check_init();
 
1104
        
 
1105
        sint16 *buf16 = (sint16 *) m_buf;
 
1106
        
 
1107
        buf16[0] = host2garmin16((sint16) cmnd_turn_off_pwr);
 
1108
        m_ll->put_packet(pid_command_data, m_buf, 2);
 
1109
        
 
1110
}
 
1111
 
 
1112
/////////////////
 
1113
 
 
1114
time_t 
 
1115
application_layer::get_date_time(void) throw (not_possible, timeout)
 
1116
{
 
1117
        check_init();
 
1118
 
 
1119
        sint16 *sbuf16 = (sint16 *) m_buf;
 
1120
        
 
1121
        sbuf16[0] = host2garmin16((sint16) cmnd_transfer_time);
 
1122
        m_ll->put_packet(pid_command_data, m_buf, 2);
 
1123
        
 
1124
        uint8 sz;
 
1125
        packet_id pid = m_ll->get_packet(m_buf, sz);
 
1126
        
 
1127
        if (pid != pid_date_time_data) {
 
1128
                throw not_possible("GPS did not respond with date and time packet");
 
1129
        }
 
1130
        if (sz != 8) {
 
1131
                throw not_possible("Date and time packet is the wrong size");
 
1132
        }
 
1133
        
 
1134
        struct tm my_tm;
 
1135
        memset(&my_tm, 0, sizeof(struct tm));
 
1136
        
 
1137
        my_tm.tm_mon = m_buf[0] - 1;
 
1138
        my_tm.tm_mday = m_buf[1];
 
1139
        uint16 *ubuf16 = (uint16 *) m_buf;
 
1140
        my_tm.tm_year = garmin2host16(ubuf16[1]) - 1900;
 
1141
        my_tm.tm_hour = garmin2host16(sbuf16[2]);
 
1142
        my_tm.tm_min = m_buf[6];
 
1143
        my_tm.tm_sec = m_buf[7];
 
1144
        
 
1145
        my_tm.tm_isdst = -1;
 
1146
        
 
1147
        return mktime(&my_tm);
 
1148
}
 
1149
 
 
1150
/////////////////////
 
1151
 
 
1152
void 
 
1153
application_layer::send_date_time(time_t t) throw (bad_time, not_possible, timeout)
 
1154
{
 
1155
        check_init();
 
1156
 
 
1157
        struct tm my_tm = *gmtime(&t);
 
1158
        if (my_tm.tm_year < 90) {
 
1159
                throw bad_time();
 
1160
        }
 
1161
        
 
1162
        m_buf[0] = my_tm.tm_mon + 1;
 
1163
        m_buf[1] = my_tm.tm_mday;
 
1164
        uint16 *buf16 = (uint16 *) m_buf;;
 
1165
        buf16[1] = host2garmin16(my_tm.tm_year + 1900);
 
1166
        sint16 *sbuf16 = (sint16 *) buf16;
 
1167
        sbuf16[2] = host2garmin16(my_tm.tm_hour);
 
1168
        m_buf[6] = my_tm.tm_min;
 
1169
        m_buf[8] = my_tm.tm_sec;
 
1170
        
 
1171
        m_ll->put_packet(pid_date_time_data, m_buf, 8);
 
1172
}
 
1173
 
 
1174
//////////////////
 
1175
 
 
1176
radian_type
 
1177
application_layer::get_position(void) throw (not_possible, timeout)
 
1178
{
 
1179
        check_init();
 
1180
 
 
1181
        sint16 *sbuf16 = (sint16 *) m_buf;
 
1182
        
 
1183
        sbuf16[0] = host2garmin16((sint16) cmnd_transfer_posn);
 
1184
        m_ll->put_packet(pid_command_data, m_buf, 2);
 
1185
        
 
1186
        uint8 sz;
 
1187
        packet_id pid = m_ll->get_packet(m_buf, sz);
 
1188
        
 
1189
        if (pid != pid_position_data) {
 
1190
                throw not_possible("GPS did not respond with position packet");
 
1191
        }
 
1192
        if (sz != 16) {
 
1193
                throw not_possible("Position packet is the wrong size");
 
1194
        }
 
1195
        
 
1196
        double64 *dbuf = (double64 *) m_buf;
 
1197
        radian_type retval;
 
1198
        retval.lat = garmin2host64(dbuf[0]);
 
1199
        retval.lon = garmin2host64(dbuf[1]);
 
1200
        
 
1201
        return retval;
 
1202
}
 
1203
 
 
1204
/////////////////////
 
1205
 
 
1206
void 
 
1207
application_layer::send_position(radian_type pos) throw (not_possible, timeout)
 
1208
{
 
1209
        check_init();
 
1210
 
 
1211
        double64 *dbuf = (double64 *) m_buf;
 
1212
        dbuf[0] = host2garmin64(pos.lat);
 
1213
        dbuf[1] = host2garmin64(pos.lon);
 
1214
        
 
1215
        m_ll->put_packet(pid_position_data, m_buf, 16);
 
1216
}
 
1217
 
 
1218
//////////////////
 
1219
 
 
1220
} // namespace