~ubuntu-branches/ubuntu/saucy/merkaartor/saucy

« back to all changes in this revision

Viewing changes to GPS/qgpsdevice.cpp

  • Committer: Bazaar Package Importer
  • Author(s): Bernd Zeimetz
  • Date: 2009-09-13 00:52:12 UTC
  • mto: (1.2.7 upstream) (0.1.3 upstream) (3.1.7 sid)
  • mto: This revision was merged to the branch mainline in revision 10.
  • Revision ID: james.westby@ubuntu.com-20090913005212-pjecal8zxm07x0fj
ImportĀ upstreamĀ versionĀ 0.14+svnfixes~20090912

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
 
/***************************************************************************
2
 
 *   Copyright (C) 2005 by Robin Gingras                                   *
3
 
 *   neozenkai@cox.net                                                     *
4
 
 *                                                                         *
5
 
 *   This program is free software; you can redistribute it and/or modify  *
6
 
 *   it under the terms of the GNU General Public License as published by  *
7
 
 *   the Free Software Foundation; either version 2 of the License, or     *
8
 
 *   (at your option) any later version.                                   *
9
 
 *                                                                         *
10
 
 *   This program is distributed in the hope that it will be useful,       *
11
 
 *   but WITHOUT ANY WARRANTY; without even the implied warranty of        *
12
 
 *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the         *
13
 
 *   GNU General Public License for more details.                          *
14
 
 *                                                                         *
15
 
 *   You should have received a copy of the GNU General Public License     *
16
 
 *   along with this program; if not, write to the                         *
17
 
 *   Free Software Foundation, Inc.,                                       *
18
 
 *   59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.             *
19
 
 ***************************************************************************/
20
 
 
21
 
#include <QThread>
22
 
#include <QObject>
23
 
#include <QString>
24
 
#include <QMutex>
25
 
#include <QFile>
26
 
#include <QStringList>
27
 
#include <QMessageBox>
28
 
#include <QTcpSocket>
29
 
#include <QTimer>
30
 
#include <QHostAddress>
31
 
 
32
 
#include <cstdlib>
33
 
 
34
 
#include "qgpsdevice.h"
35
 
#include "qextserialport.h"
36
 
 
37
 
#include "Preferences/MerkaartorPreferences.h"
38
 
 
39
 
#include <iostream>
40
 
 
41
 
/* GPSSLOTFORWARDER */
42
 
 
43
 
GPSSlotForwarder::GPSSlotForwarder(QGPSDevice* aTarget)
44
 
: Target(aTarget)
45
 
{
46
 
}
47
 
 
48
 
void GPSSlotForwarder::onLinkReady()
49
 
{
50
 
        Target->onLinkReady();
51
 
}
52
 
 
53
 
void GPSSlotForwarder::onDataAvailable()
54
 
{
55
 
        Target->onDataAvailable();
56
 
}
57
 
 
58
 
void GPSSlotForwarder::onStop()
59
 
{
60
 
        Target->onStop();
61
 
}
62
 
 
63
 
void GPSSlotForwarder::checkDataAvailable()
64
 
{
65
 
        Target->checkDataAvailable();
66
 
}
67
 
 
68
 
/**
69
 
 * QGPSDevice::QGPSDevice()
70
 
 *
71
 
 * Takes in an optional serialPort string and sets the serialPort property
72
 
 * accordingly.
73
 
 *
74
 
 * @param char serialPort   Serial port to listen to for GPS dat
75
 
 */
76
 
 
77
 
QGPSDevice::QGPSDevice()
78
 
{
79
 
    mutex = new QMutex(QMutex::Recursive);
80
 
 
81
 
    setLatitude(0);
82
 
    setLongitude(0);
83
 
    setAltitude(0);
84
 
    setHeading(0);
85
 
    setSpeed(0);
86
 
    setVariation(0);
87
 
 
88
 
        setFixMode(QGPSDevice::FixAuto);
89
 
        setFixType(QGPSDevice::FixUnavailable);
90
 
        setFixStatus(QGPSDevice::StatusVoid);
91
 
 
92
 
    stopLoop = false;
93
 
 
94
 
        cur_numSatellites = 0;
95
 
    for(int i = 0; i < 50; i ++)
96
 
    {
97
 
        satArray[i][0] = satArray[i][1] = satArray[i][2] = 0;
98
 
    }
99
 
}
100
 
 
101
 
/**
102
 
 * Accessor functions
103
 
 */
104
 
 
105
 
int QGPSDevice::latDegrees()    { return (int) (fabs(latitude()));                                                                                                      }
106
 
int QGPSDevice::latMinutes()
107
 
{
108
 
        double m = fabs(latitude()) - latDegrees();
109
 
        return int(m * 60);
110
 
}
111
 
int QGPSDevice::latSeconds()
112
 
{
113
 
        double m = fabs(latitude()) - latDegrees();
114
 
        double s = (m * 60) - int(m * 60);
115
 
        return int(s * 60);
116
 
}
117
 
int QGPSDevice::longDegrees()    { return (int) (fabs(longitude()));                                                                                                    }
118
 
int QGPSDevice::longMinutes()
119
 
{
120
 
        double m = fabs(longitude()) - longDegrees();
121
 
        return int(m * 60);
122
 
}
123
 
int QGPSDevice::longSeconds()
124
 
{
125
 
        double m = fabs(longitude()) - longDegrees();
126
 
        double s = (m * 60) - int(m * 60);
127
 
        return int(s * 60);
128
 
}
129
 
 
130
 
bool QGPSDevice::isActiveSat(unsigned int prn)
131
 
{
132
 
        for (int i=0; i<12; i++) {
133
 
                if (activeSats[i] == prn)
134
 
                        return true;
135
 
        }
136
 
        return false;
137
 
}
138
 
 
139
 
void QGPSDevice::satInfo(int index, int &elev, int &azim, int &snr)
140
 
{
141
 
    mutex->lock();
142
 
 
143
 
    elev = satArray[index][0];
144
 
    azim = satArray[index][1];
145
 
    snr  = satArray[index][2];
146
 
 
147
 
    mutex->unlock();
148
 
}
149
 
 
150
 
/**
151
 
 * QGPSDevice::run()
152
 
 *
153
 
 * Begins the thread loop, reading data from the GPS and parsing
154
 
 * full strings.
155
 
 */
156
 
 
157
 
/**
158
 
 * QGPSDevice::parseGGA()
159
 
 *
160
 
 * Parses a GPGGA string that contains fix information, such as
161
 
 * latitude, longitude, etc.
162
 
 *
163
 
 * The format of the GPGGA String is as follows:
164
 
 *
165
 
 *  $GPGGA,123519,4807.038,N,01131.000,E,1,08,0.9,545.4,M,46.9,M,,*47
166
 
 *  |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
167
 
 *  01234567890123456789012345678901234567890123456789012345678901234
168
 
 *  |         |         |         |         |         |         |
169
 
 *  0         10        20        30        40        50        60
170
 
 *
171
 
 *  GPGGA       -   Global Positioning System Fix Data
172
 
 *  123519      -   Fix taken at 12:35:19 UTC
173
 
 *  4807.038,N  -   Latitude 48 deg 07.038' N
174
 
 *  01131.000,E -   Longitude 11 deg 31.000' E
175
 
 *  1           -   Fix quality:
176
 
 *                      0 = Invalid
177
 
 *                      1 = GPS fix (SPS)
178
 
 *                      2 = DGPS fix
179
 
 *                      3 = PPS fix
180
 
 *                      4 = Real time kinematic
181
 
 *                      5 = Float RTK
182
 
 *                      6 = Estimated (dead reckoning)
183
 
 *                      7 = Manual input mode
184
 
 *                      8 = Simulation mode
185
 
 *  08          -   Number of satellites being tracked
186
 
 *  0.9         -   Horizontal dissolution of precision
187
 
 *  545.4,M     -   Altitude (meters) above sea level
188
 
 *  46.9,M      -   Height of geoid (sea level) above WGS84 ellipsoid
189
 
 *  (empty)     -   Seconds since last DGPS update
190
 
 *  (empty)     -   DGPS station ID number
191
 
 *  *47         -   Checksum, begins with *
192
 
 *
193
 
 * @param char ggaString    The full NMEA GPGGA string, starting with
194
 
 *                          the $ and ending with the checksum
195
 
 */
196
 
 
197
 
bool QGPSDevice::parseGGA(const char *ggaString)
198
 
{
199
 
    mutex->lock();
200
 
 
201
 
        QString line(ggaString);
202
 
        if (line.count('$') > 1)
203
 
                return false;
204
 
 
205
 
        QStringList tokens = line.split(",");
206
 
 
207
 
        double lat = tokens[2].left(2).toDouble();
208
 
        double latmin = tokens[2].mid(2).toDouble();
209
 
        lat += latmin / 60.0;
210
 
        if (tokens[3] != "N")
211
 
                lat = -lat;
212
 
    //cur_latitude = lat;
213
 
 
214
 
        if (!tokens[3].isEmpty())
215
 
        {
216
 
                if (tokens[3].at(0) == 'N')
217
 
                        setLatCardinal(CardinalNorth);
218
 
                else if (tokens[3].at(0) == 'S')
219
 
                        setLatCardinal(CardinalSouth);
220
 
                else
221
 
                        setLatCardinal(CardinalNone);
222
 
        }
223
 
 
224
 
 
225
 
        double lon = tokens[4].left(3).toDouble();
226
 
        double lonmin = tokens[4].mid(3).toDouble();
227
 
        lon += lonmin / 60.0;
228
 
        if (tokens[5] != "E")
229
 
                lon = -lon;
230
 
    //cur_longitude = lon;
231
 
 
232
 
        if (!tokens[5].isEmpty())
233
 
        {
234
 
                if (tokens[5].at(0) == 'E')
235
 
                        setLatCardinal(CardinalEast);
236
 
                else if (tokens[5].at(0) == 'W')
237
 
                        setLatCardinal(CardinalWest);
238
 
                else
239
 
                        setLatCardinal(CardinalNone);
240
 
        }
241
 
 
242
 
        int fix = tokens[6].toInt();
243
 
        setFixQuality(fix);
244
 
 
245
 
        int numSat = tokens[7].toInt();
246
 
        setNumSatellites(numSat);
247
 
 
248
 
        float dilut = tokens[8].toFloat();
249
 
    setDillution(dilut);
250
 
 
251
 
        float altitude = tokens[9].toFloat();
252
 
        setAltitude(altitude);
253
 
 
254
 
    mutex->unlock();
255
 
 
256
 
        return true;
257
 
} // parseGGA()
258
 
 
259
 
bool QGPSDevice::parseGLL(const char *ggaString)
260
 
{
261
 
    mutex->lock();
262
 
 
263
 
        QString line(ggaString);
264
 
        if (line.count('$') > 1)
265
 
                return false;
266
 
 
267
 
        QStringList tokens = line.split(",");
268
 
 
269
 
        double lat = tokens[1].left(2).toDouble();
270
 
        double latmin = tokens[1].mid(2).toDouble();
271
 
        lat += latmin / 60.0;
272
 
        if (tokens[2] != "N")
273
 
                lat = -lat;
274
 
    //cur_latitude = lat;
275
 
 
276
 
        if (!tokens[2].isEmpty())
277
 
        {
278
 
                if (tokens[2].at(0) == 'N')
279
 
                        setLatCardinal(CardinalNorth);
280
 
                else if (tokens[2].at(0) == 'S')
281
 
                        setLatCardinal(CardinalSouth);
282
 
                else
283
 
                        setLatCardinal(CardinalNone);
284
 
        }
285
 
 
286
 
        double lon = tokens[3].left(3).toDouble();
287
 
        double lonmin = tokens[3].mid(3).toDouble();
288
 
        lon += lonmin / 60.0;
289
 
        if (tokens[4] != "E")
290
 
                lon = -lon;
291
 
    //cur_longitude = lon;
292
 
 
293
 
        if (!tokens[4].isEmpty())
294
 
        {
295
 
                if (tokens[4].at(0) == 'E')
296
 
                        setLatCardinal(CardinalEast);
297
 
                else if (tokens[4].at(0) == 'W')
298
 
                        setLatCardinal(CardinalWest);
299
 
                else
300
 
                        setLatCardinal(CardinalNone);
301
 
        }
302
 
 
303
 
 
304
 
        if (tokens[6] == "A")
305
 
    {
306
 
        setFixStatus(StatusActive);
307
 
    }
308
 
    else
309
 
    {
310
 
        setFixStatus(StatusVoid);
311
 
    }
312
 
 
313
 
    mutex->unlock();
314
 
 
315
 
        return true;
316
 
} // parseGGA()
317
 
 
318
 
/**
319
 
 * QGPSDevice::parseGSA()
320
 
 *
321
 
 * Parses a GPGSA string that contains information about the nature
322
 
 * of the fix, such as DOP (dillution of precision) and active satellites
323
 
 * based on the viewing mask and almanac data of the reciever.
324
 
 *
325
 
 * The format of the GPGSA String is as follows:
326
 
 *
327
 
 *  $GPGSA,A,3,04,05,,09,12,,,24,,,,,2.5,1.3,2.1*39
328
 
 *  |||||||||||||||||||||||||||||||||||||||||||||||
329
 
 *  01234567890123456789012345678901234567890123456
330
 
 *  |         |         |         |         |
331
 
 *  0         10        20        30        40
332
 
 *
333
 
 *  GPGSA       -   Information about satellite status
334
 
 *  A           -   Fix mode, (A)utomatic or (M)anual
335
 
 *  3           -   Fix type:
336
 
 *                      1 = Invalid
337
 
 *                      2 = 2D
338
 
 *                      3 = 3D (4 or more satellites)
339
 
 *  04,05,...   -   Satellites used in the solution (up to 12)
340
 
 *  2.5         -   DOP (dillution of precision)
341
 
 *  1.3         -   Horizontal DOP
342
 
 *  2.1         -   Vertical DOP
343
 
 *  *39         -   Checksum
344
 
 *
345
 
 * @param char  The full NMEA GPGSA string, from $ to checksum
346
 
 */
347
 
 
348
 
bool QGPSDevice::parseGSA(const char *gsaString)
349
 
{
350
 
    mutex->lock();
351
 
 
352
 
        QString line(gsaString);
353
 
        if (line.count('$') > 1)
354
 
                return false;
355
 
 
356
 
        QStringList tokens = line.split(",");
357
 
 
358
 
        QString autoSelectFix = tokens[1];
359
 
    if(autoSelectFix == "A")
360
 
        setFixMode(FixAuto);
361
 
    else
362
 
        setFixMode(FixManual);
363
 
 
364
 
        int fix = tokens[2].toInt();
365
 
    if(fix == 1)
366
 
        setFixType(FixInvalid);
367
 
    else if(fix == 2)
368
 
        setFixType(Fix2D);
369
 
    else
370
 
        setFixType(Fix3D);
371
 
 
372
 
        for(int index = 0; index < 12; index ++) {
373
 
                activeSats[index] = tokens[index+3].toInt();
374
 
        }
375
 
 
376
 
    mutex->unlock();
377
 
 
378
 
        return true;
379
 
} // parseGSA()
380
 
 
381
 
/**
382
 
 * QGPSDevice::parseRMC()
383
 
 *
384
 
 * Parses an RMC string, which contains the recommended minimum fix
385
 
 * data, such as latitude, longitude, altitude, speed, track angle,
386
 
 * date, and magnetic variation. Saves us some calculating :)
387
 
 *
388
 
 * The format of the GPRMC string is as follows:
389
 
 *
390
 
 *  $GPRMC,123519,A,4807.038,N,01131.000,E,022.4,084.4,230394,003.1,W*6A
391
 
 *  ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
392
 
 *  01234567890123456789012345678901234567890123456789012345678901234567
393
 
 *  |         |         |         |         |         |         |
394
 
 *  0         10        20        30        40        50        60
395
 
 *
396
 
 *  GPRMC       -   Recommended minimum fix data
397
 
 *  123519      -   Fix taken at 12:35:19 UTC
398
 
 *  A           -   Fix status, (A)ctive or (V)oid
399
 
 *  4807.038,N  -   Latitude 48 degrees 07.038' N
400
 
 *  01131.000,E -   Longitude 11 degrees, 31.000' E
401
 
 *  022.4       -   Ground speed in knots
402
 
 *  084.4       -   Track angle in degrees (true north)
403
 
 *  230394      -   Date: 23 March 1994
404
 
 *  003.1,W     -   Magnetic Variation
405
 
 *  *6A         -   Checksum
406
 
 *
407
 
 * @param char  Full RMC string, from $ to checksum
408
 
 */
409
 
 
410
 
bool QGPSDevice::parseRMC(const char *rmcString)
411
 
{
412
 
        mutex->lock();
413
 
 
414
 
        // Fix time
415
 
 
416
 
        QString line(rmcString);
417
 
        if (line.count('$') > 1)
418
 
                return false;
419
 
 
420
 
        QStringList tokens = line.split(",");
421
 
 
422
 
        QString strDate = tokens[9] + tokens[1];
423
 
        cur_datetime = QDateTime::fromString(strDate, "ddMMyyHHmmss.zzz");
424
 
 
425
 
        if (cur_datetime.date().year() < 1970)
426
 
                cur_datetime = cur_datetime.addYears(100);
427
 
 
428
 
        // Fix status
429
 
 
430
 
        if (tokens[2] == "A")
431
 
        {
432
 
                setFixStatus(StatusActive);
433
 
        }
434
 
        else
435
 
        {
436
 
                setFixStatus(StatusVoid);
437
 
        }
438
 
 
439
 
        // Latitude
440
 
 
441
 
        double lat = tokens[3].left(2).toDouble();
442
 
        double latmin = tokens[3].mid(2).toDouble();
443
 
        lat += latmin / 60.0;
444
 
        if (tokens[4] != "N")
445
 
                lat = -lat;
446
 
        cur_latitude = lat;
447
 
 
448
 
        if (!tokens[4].isEmpty())
449
 
        {
450
 
                if (tokens[4].at(0) == 'N')
451
 
                        setLatCardinal(CardinalNorth);
452
 
                else if (tokens[4].at(0) == 'S')
453
 
                        setLatCardinal(CardinalSouth);
454
 
                else
455
 
                        setLatCardinal(CardinalNone);
456
 
        }
457
 
 
458
 
        double lon = tokens[5].left(3).toDouble();
459
 
        double lonmin = tokens[5].mid(3).toDouble();
460
 
        lon += lonmin / 60.0;
461
 
        if (tokens[6] != "E")
462
 
                lon = -lon;
463
 
        cur_longitude = lon;
464
 
 
465
 
        if (!tokens[6].isEmpty())
466
 
        {
467
 
                if (tokens[6].at(0) == 'E')
468
 
                        setLatCardinal(CardinalEast);
469
 
                else if (tokens[6].at(0) == 'W')
470
 
                        setLatCardinal(CardinalWest);
471
 
                else
472
 
                        setLatCardinal(CardinalNone);
473
 
        }
474
 
 
475
 
        // Ground speed in km/h
476
 
 
477
 
        double speed = QString::number(tokens[7].toDouble() * 1.852, 'f', 1).toDouble();
478
 
        setSpeed(speed);
479
 
 
480
 
        // Heading
481
 
 
482
 
        double heading = tokens[8].toDouble();
483
 
        setHeading(heading);
484
 
 
485
 
        // Magnetic variation
486
 
 
487
 
        double magvar = tokens[10].toDouble();
488
 
        setVariation(magvar);
489
 
 
490
 
        if (!tokens[11].isEmpty())
491
 
        {
492
 
                if (tokens[11].at(0) == 'E')
493
 
                        setVarCardinal(CardinalEast);
494
 
                else if (tokens[11].at(0) == 'W')
495
 
                        setVarCardinal(CardinalWest);
496
 
                else
497
 
                        setVarCardinal(CardinalNone);
498
 
        }
499
 
 
500
 
        mutex->unlock();
501
 
 
502
 
        return true;
503
 
} // parseRMC()
504
 
 
505
 
/**
506
 
 * QGPSDevice::parseGSV()
507
 
 *
508
 
 * Parses a GPGSV string, which contains satellite position and signal
509
 
 * strenght information. parseGSV() fills the satArray array with the
510
 
 * PRNs, elevations, azimuths, and SNRs of the visible satellites. This
511
 
 * array is based on the position of the satellite in the strings, not
512
 
 * the order of the PRNs! (see README for info)
513
 
 *
514
 
 * The format of the GPGSV string is as follows:
515
 
 *
516
 
 *  $GPGSV,2,1,08,01,40,083,46,02,17,308,41,12,07,344,39,14,22,228,45*75
517
 
 *  ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
518
 
 *  01234567890123456789012345678901234567890123456789012345678901234567
519
 
 *  |         |         |         |         |         |         |
520
 
 *  0         10        20        30        40        50        60
521
 
 *
522
 
 *  GPGSV       -   Satellite status
523
 
 *  2           -   Number of GPGSV sentences for full data
524
 
 *  1           -   Current sentence (1 of 2, etc)
525
 
 *  08          -   Number of satellites in view
526
 
 *
527
 
 *  01          -   Satellite PRN
528
 
 *  40          -   Elevation, degrees
529
 
 *  083         -   Azimuth, degrees
530
 
 *  46          -   SNR (signal to noise ratio)
531
 
 *      (for up to four satellites per sentence)
532
 
 *  *75         -   Checksum
533
 
 */
534
 
 
535
 
bool QGPSDevice::parseGSV(const char *gsvString)
536
 
{
537
 
    mutex->lock();
538
 
 
539
 
    int totalSentences;
540
 
    int currentSentence;
541
 
    int totalSatellites;
542
 
        int prn, elev, azim, snr;
543
 
 
544
 
        QString line(gsvString);
545
 
        if (line.count('$') > 1)
546
 
                return false;
547
 
 
548
 
        QStringList tokens = line.split(",");
549
 
 
550
 
        totalSentences = tokens[1].toInt();
551
 
        currentSentence = tokens[2].toInt();
552
 
        totalSatellites = tokens[3].toInt();
553
 
 
554
 
        for(int i = 0; (i < 4) && ((i*4)+4+3 < tokens.size()); i ++) {
555
 
                prn = tokens[(i*4)+4].toInt();
556
 
                elev = tokens[(i*4)+4+1].toInt();
557
 
                azim = tokens[(i*4)+4+2].toInt();
558
 
                if (tokens[(i*4)+4+3].contains('*')) {
559
 
                        QStringList tok2 = tokens[(i*4)+4+3].split("*");
560
 
                        snr = tok2[0].toInt();
561
 
                } else
562
 
                        snr = tokens[(i*4)+4+3].toInt();
563
 
                satArray[prn][0] = elev;
564
 
                satArray[prn][1] = azim;
565
 
                satArray[prn][2] = snr;
566
 
        }
567
 
 
568
 
    mutex->unlock();
569
 
 
570
 
        return true;
571
 
}
572
 
 
573
 
/**
574
 
 * QGPSDevice::startDevice()
575
 
 *
576
 
 * Calls start() to begin thread execution
577
 
 */
578
 
 
579
 
void QGPSDevice::startDevice()
580
 
{
581
 
    mutex->lock();
582
 
    stopLoop = false;
583
 
    mutex->unlock();
584
 
 
585
 
    printf("We're starting...\n");
586
 
 
587
 
    start();
588
 
}
589
 
 
590
 
/**
591
 
 * QGPSDevice::stopDevice()
592
 
 *
593
 
 * Stops execution of run() and ends thread execution
594
 
 * This function will be called outside this thread
595
 
 */
596
 
 
597
 
void QGPSDevice::stopDevice()
598
 
{
599
 
    // this is through a queued connection
600
 
    emit doStopDevice();
601
 
}
602
 
 
603
 
/*** QGPSComDevice  ***/
604
 
 
605
 
QGPSComDevice::QGPSComDevice(const QString &device)
606
 
        : QGPSDevice(), LogFile(0)
607
 
{
608
 
        if(!device.isNull())
609
 
        {
610
 
                setDevice(device);
611
 
        }
612
 
}
613
 
 
614
 
QGPSComDevice::~QGPSComDevice()
615
 
{
616
 
        if (LogFile) {
617
 
                if (LogFile->isOpen())
618
 
                        LogFile->close();
619
 
                delete LogFile;
620
 
        }
621
 
}
622
 
 
623
 
/**
624
 
 * QGPSComDevice::openDevice()
625
 
 *
626
 
 * Opens the serial port and sets the parameters for data transfer: parity,
627
 
 * stop bits, blocking, etc.
628
 
 */
629
 
 
630
 
bool QGPSComDevice::openDevice()
631
 
{
632
 
        port = new QextSerialPort(device());
633
 
        port->setBaudRate(BAUD4800);
634
 
        port->setFlowControl(FLOW_OFF);
635
 
        port->setParity(PAR_NONE);
636
 
        port->setDataBits(DATA_8);
637
 
        port->setStopBits(STOP_2);
638
 
 
639
 
        if (port->open(QIODevice::ReadOnly)) {
640
 
                if (M_PREFS->getGpsSaveLog()) {
641
 
                        QString fn = "log-" + QDateTime::currentDateTime().toString(Qt::ISODate) + ".nmea";
642
 
                        fn.replace(':', '-');
643
 
                        LogFile = new QFile(M_PREFS->getGpsLogDir() + "/"+fn);
644
 
                        if (!LogFile->open(QIODevice::WriteOnly)) {
645
 
                                QMessageBox::critical(NULL, tr("GPS log error"),
646
 
                                        tr("Unable to create GPS log file: %1.").arg(M_PREFS->getGpsLogDir() + "/"+fn), QMessageBox::Ok);
647
 
                                delete LogFile;
648
 
                                LogFile = NULL;
649
 
                        }
650
 
                }
651
 
                return true;
652
 
        }
653
 
        return false;
654
 
}
655
 
 
656
 
/**
657
 
 * QGPSComDevice::closeDevice()
658
 
 *
659
 
 * Closes the serial port
660
 
 */
661
 
 
662
 
bool QGPSComDevice::closeDevice()
663
 
{
664
 
        port->close();
665
 
        if (LogFile && LogFile->isOpen()) {
666
 
                LogFile->close();
667
 
                delete LogFile;
668
 
        }
669
 
        LogFile = NULL;
670
 
 
671
 
        return true;
672
 
}
673
 
 
674
 
void QGPSComDevice::onLinkReady()
675
 
{
676
 
}
677
 
 
678
 
void QGPSComDevice::onStop()
679
 
{
680
 
        quit();
681
 
}
682
 
 
683
 
 
684
 
void QGPSComDevice::run()
685
 
{
686
 
        GPSSlotForwarder Forward(this);
687
 
 
688
 
        QTimer *timer = new QTimer(this);
689
 
        connect(timer, SIGNAL(timeout()), &Forward, SLOT(checkDataAvailable()));
690
 
        timer->start(150);
691
 
 
692
 
//      connect(port,SIGNAL(readyRead()),&Forward,SLOT(onDataAvailable()));
693
 
        connect(this,SIGNAL(doStopDevice()),&Forward,SLOT(onStop()));
694
 
        exec();
695
 
        closeDevice();
696
 
}
697
 
 
698
 
void QGPSComDevice::checkDataAvailable() {
699
 
        if (port->bytesAvailable() > 0)
700
 
                onDataAvailable();
701
 
}
702
 
 
703
 
void QGPSComDevice::onDataAvailable()
704
 
{
705
 
        QByteArray ba(port->readAll());
706
 
        // filter out unwanted characters
707
 
        for (unsigned int i=ba.count(); i; --i)
708
 
                if(ba[i-1] == '\0' || 
709
 
                        (!isalnum((quint8)ba[i-1]) && 
710
 
                         !isspace((quint8)ba[i-1]) && 
711
 
                         !ispunct((quint8)ba[i-1])))
712
 
                {
713
 
                        ba.remove(i-1,1);
714
 
                }
715
 
        if (LogFile)
716
 
                LogFile->write(ba);
717
 
        Buffer.append(ba);
718
 
        if (Buffer.length() > 4096)
719
 
                // safety valve
720
 
                Buffer.remove(0,Buffer.length()-4096);
721
 
        while (Buffer.count())
722
 
        {
723
 
                // look for begin of sentence marker
724
 
                int i = Buffer.indexOf('$');
725
 
                if (i<0)
726
 
                {
727
 
                        Buffer.clear();
728
 
                        return;
729
 
                }
730
 
                Buffer.remove(0,i);
731
 
                // look for end of sentence marker
732
 
                for (i=0; i<Buffer.count(); ++i)
733
 
                        if ( (Buffer[i] == (char)(0x0a)) || (Buffer[i] == (char)(0x0d)) )
734
 
                                break;
735
 
                if (i == Buffer.count())
736
 
                        return;
737
 
                parse(Buffer.mid(0,i-2));
738
 
                Buffer.remove(0,i);
739
 
        }
740
 
}
741
 
 
742
 
 
743
 
void QGPSComDevice::parse(const QByteArray& bufferString)
744
 
{
745
 
        if (bufferString.length() < 6) return;
746
 
        if(bufferString[3] == 'G' && bufferString[4] == 'G' && bufferString[5] == 'A')
747
 
        {
748
 
        //strcpy(nmeastr_gga, bufferString);
749
 
        parseGGA(bufferString.data());
750
 
        }
751
 
        else if(bufferString[3] == 'G' && bufferString[4] == 'L' && bufferString[5] == 'L')
752
 
        {
753
 
        //strcpy(nmeastr_gga, bufferString);
754
 
        parseGLL(bufferString.data());
755
 
        }
756
 
    else if(bufferString[3] == 'G' && bufferString[4] == 'S' && bufferString[5] == 'V')
757
 
    {
758
 
        //strcpy(nmeastr_gsv, bufferString);
759
 
        parseGSV(bufferString.data());
760
 
    }
761
 
    else if(bufferString[3] == 'G' && bufferString[4] == 'S' && bufferString[5] == 'A')
762
 
    {
763
 
        //strcpy(nmeastr_gsa, bufferString);
764
 
        parseGSA(bufferString.data());
765
 
    }
766
 
    else if(bufferString[3] == 'R' && bufferString[4] == 'M' && bufferString[5] == 'C')
767
 
    {
768
 
        //strcpy(nmeastr_rmc, bufferString);
769
 
        if (parseRMC(bufferString.data()))
770
 
                        if (fixStatus() == QGPSDevice::StatusActive && (fixType() == QGPSDevice::Fix3D || fixType() == QGPSDevice::FixUnavailable))
771
 
                                emit updatePosition(latitude(), longitude(), dateTime(), altitude(), speed(), heading());
772
 
        }
773
 
        emit updateStatus();
774
 
}
775
 
 
776
 
/*** QGPSFileDevice  ***/
777
 
 
778
 
QGPSFileDevice::QGPSFileDevice(const QString &device)
779
 
        : QGPSDevice()
780
 
{
781
 
        if(!device.isNull())
782
 
        {
783
 
                setDevice(device);
784
 
        }
785
 
}
786
 
 
787
 
/**
788
 
 * QGPSFileDevice::openDevice()
789
 
 *
790
 
 * Opens the serial port and sets the parameters for data transfer: parity,
791
 
 * stop bits, blocking, etc.
792
 
 */
793
 
 
794
 
bool QGPSFileDevice::openDevice()
795
 
{
796
 
        theFile = new QFile(device());
797
 
 
798
 
        if (!theFile->open(QIODevice::ReadOnly | QIODevice::Text)) {
799
 
                delete theFile;
800
 
                theFile = NULL;
801
 
        return false;
802
 
        }
803
 
 
804
 
        return true;
805
 
}
806
 
 
807
 
void QGPSFileDevice::onLinkReady()
808
 
{
809
 
}
810
 
 
811
 
void QGPSFileDevice::onStop()
812
 
{
813
 
        quit();
814
 
}
815
 
 
816
 
/**
817
 
 * QGPSFileDevice::closeDevice()
818
 
 *
819
 
 * Closes the serial port
820
 
 */
821
 
 
822
 
bool QGPSFileDevice::closeDevice()
823
 
{
824
 
        if (theFile)
825
 
                theFile->close();
826
 
 
827
 
        return true;
828
 
}
829
 
 
830
 
void QGPSFileDevice::run()
831
 
{
832
 
        GPSSlotForwarder Forward(this);
833
 
        QTimer* t = new QTimer;
834
 
        connect(t,SIGNAL(timeout()),&Forward,SLOT(onDataAvailable()));
835
 
        connect(this,SIGNAL(doStopDevice()),&Forward,SLOT(onStop()));
836
 
        t->start(100);
837
 
        exec();
838
 
        closeDevice();
839
 
}
840
 
 
841
 
void QGPSFileDevice::onDataAvailable()
842
 
{
843
 
 
844
 
    int  index = 0;
845
 
    char bufferChar;
846
 
    char bufferString[100];
847
 
 
848
 
            theFile->read(&bufferChar, 1);
849
 
        if(bufferChar == '$')
850
 
        {
851
 
            index = 0;
852
 
            bufferString[index] = bufferChar;
853
 
 
854
 
            do
855
 
            {
856
 
                            theFile->read(&bufferChar, 1);
857
 
                if(bufferChar != '\0' && (isalnum(bufferChar) || isspace(bufferChar) || ispunct(bufferChar)))
858
 
                {
859
 
                    index ++;
860
 
                    bufferString[index] = bufferChar;
861
 
                }
862
 
            } while(bufferChar != 0x0a && bufferChar != 0x0d);
863
 
 
864
 
            bufferString[index + 1] = '\0';
865
 
 
866
 
            mutex->lock();
867
 
 
868
 
            if(bufferString[3] == 'G' && bufferString[4] == 'G' && bufferString[5] == 'A')
869
 
            {
870
 
                //strcpy(nmeastr_gga, bufferString);
871
 
                parseGGA(bufferString);
872
 
            }
873
 
                        else if(bufferString[3] == 'G' && bufferString[4] == 'L' && bufferString[5] == 'L')
874
 
                        {
875
 
                                //strcpy(nmeastr_gga, bufferString);
876
 
                                parseGLL(bufferString);
877
 
                        }
878
 
            else if(bufferString[3] == 'G' && bufferString[4] == 'S' && bufferString[5] == 'V')
879
 
            {
880
 
                //strcpy(nmeastr_gsv, bufferString);
881
 
                parseGSV(bufferString);
882
 
            }
883
 
            else if(bufferString[3] == 'G' && bufferString[4] == 'S' && bufferString[5] == 'A')
884
 
            {
885
 
                //strcpy(nmeastr_gsa, bufferString);
886
 
                parseGSA(bufferString);
887
 
            }
888
 
            else if(bufferString[3] == 'R' && bufferString[4] == 'M' && bufferString[5] == 'C')
889
 
            {
890
 
                //strcpy(nmeastr_rmc, bufferString);
891
 
                if (parseRMC(bufferString))
892
 
                                        if (fixStatus() == QGPSDevice::StatusActive && (fixType() == QGPSDevice::Fix3D || fixType() == QGPSDevice::FixUnavailable))
893
 
                                                emit updatePosition(latitude(), longitude(), dateTime(), altitude(), speed(), heading());
894
 
           }
895
 
 
896
 
            mutex->unlock();
897
 
 
898
 
            emit updateStatus(); 
899
 
        }
900
 
}
901
 
 
902
 
/* GPSSDEVICE */
903
 
 
904
 
QGPSDDevice::QGPSDDevice(const QString& device)
905
 
{
906
 
        setDevice(device);
907
 
}
908
 
 
909
 
bool QGPSDDevice::openDevice()
910
 
{
911
 
        return true;
912
 
}
913
 
 
914
 
bool QGPSDDevice::closeDevice()
915
 
{
916
 
        return true;
917
 
}
918
 
 
919
 
 
920
 
// this function will be called within this thread
921
 
void QGPSDDevice::onStop()
922
 
{
923
 
        quit();
924
 
}
925
 
 
926
 
void QGPSDDevice::run()
927
 
{
928
 
        GPSSlotForwarder Forward(this);
929
 
        QTcpSocket Link;
930
 
        Server = &Link;
931
 
        Link.connectToHost(QHostAddress("127.0.0.1"),2947);
932
 
        connect(Server,SIGNAL(connected()),&Forward,SLOT(onLinkReady()));
933
 
        connect(Server,SIGNAL(readyRead()),&Forward,SLOT(onDataAvailable()));
934
 
        connect(this,SIGNAL(doStopDevice()),&Forward,SLOT(onStop()));
935
 
        exec();
936
 
}
937
 
 
938
 
void QGPSDDevice::onDataAvailable()
939
 
{
940
 
        QByteArray ba(Server->readAll());
941
 
        Buffer.append(ba);
942
 
        if (Buffer.length() > 4096)
943
 
                // safety valve
944
 
                Buffer.remove(0,Buffer.length()-4096);
945
 
        int i = Buffer.indexOf("GPSD");
946
 
        if (i < 0)
947
 
                return;
948
 
        int j = Buffer.indexOf(10,i);
949
 
        if (j < 0)
950
 
                return;
951
 
        parse(QString::fromAscii(Buffer.data()+(i+5),(j-i-6)));
952
 
        Buffer.remove(0,j+1);
953
 
}
954
 
 
955
 
void QGPSDDevice::parse(const QString& s)
956
 
{
957
 
        std::cout << "parsing " << s.toUtf8().data() << "*" << std::endl;
958
 
        QStringList Args(s.split(',',QString::SkipEmptyParts));
959
 
        for (int i=0; i<Args.count(); ++i)
960
 
        {
961
 
                QString Left(Args[i].left(2));
962
 
                if (Left == "O=")
963
 
                        parseO(Args[i].right(Args[i].length()-2));
964
 
                if (Left == "Y=")
965
 
                        parseY(Args[i].right(Args[i].length()-2));
966
 
        }
967
 
}
968
 
 
969
 
void QGPSDDevice::parseY(const QString& s)
970
 
{
971
 
        for(int i = 0; i < 50; i ++)
972
 
                satArray[i][0] = satArray[i][1] = satArray[i][2] = 0;
973
 
        QStringList Sats(s.split(':',QString::SkipEmptyParts));
974
 
        for (int i=1; i<Sats.size(); ++i)
975
 
        {
976
 
                QStringList Items(Sats[i].split(' ',QString::SkipEmptyParts));
977
 
                if (Items.count() < 5)
978
 
                        continue;
979
 
                int id = Items[0].toInt();
980
 
                if ( (id >= 0) && (id<50) )
981
 
                {
982
 
                        satArray[id][0] = int(Items[1].toDouble());
983
 
                        satArray[id][1] = int(Items[2].toDouble());
984
 
                        satArray[id][2] = int(Items[3].toDouble());
985
 
                }
986
 
        }
987
 
        setNumSatellites(Sats.size());
988
 
        emit updateStatus();
989
 
}
990
 
 
991
 
void QGPSDDevice::parseO(const QString& s)
992
 
{
993
 
        if (s.isEmpty()) return;
994
 
        setFixType(FixInvalid);
995
 
        if (s[0] == '?') return;
996
 
        QStringList Args(s.split(' ',QString::SkipEmptyParts));
997
 
        if (Args.count() < 5) return;
998
 
        setFixType(Fix2D);
999
 
        setLatitude(Args[3].toDouble());
1000
 
        setLongitude(Args[4].toDouble());
1001
 
        double Alt = 0;
1002
 
        if (Args.count() > 5)
1003
 
                Alt = Args[5].toDouble();
1004
 
        double Speed = 0;
1005
 
        if (Args.count() > 9)
1006
 
                Speed = Args[9].toDouble();
1007
 
        double Heading = 0;
1008
 
        if (Args.count() > 7)
1009
 
                Heading = Args[7].toDouble();
1010
 
        emit updatePosition(Args[3].toDouble(),
1011
 
                Args[4].toDouble(),
1012
 
                QDateTime::currentDateTime(),
1013
 
                Alt, Speed, Heading);
1014
 
        setHeading(Heading);
1015
 
        setAltitude(Alt);
1016
 
        setSpeed(Speed);
1017
 
        emit updateStatus();
1018
 
 
1019
 
}
1020
 
 
1021
 
void QGPSDDevice::onLinkReady()
1022
 
{
1023
 
        if (!Server) return;
1024
 
        Server->write("w+");
1025
 
        Server->write("j=1");
1026
 
}