├── Makefile ├── README.md ├── testgps.c ├── tinygps.c └── tinygps.h /Makefile: -------------------------------------------------------------------------------- 1 | CC = gcc 2 | EXEC = testgps 3 | OBJS = tinygps.o testgps.o 4 | LDFLAGS = -lm 5 | 6 | all: $(EXEC) 7 | 8 | $(EXEC): $(OBJS) 9 | $(CC) $(LDFLAGS) -o $@ $(OBJS) 10 | 11 | %.$(o) : %.c 12 | $(CC) -c $< -o $@ 13 | 14 | clean: 15 | rm -rf *.o $(EXEC) 16 | 17 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | tinygps 2 | ======= 3 | 4 | tinygps - A fork of TinyGPS 5 | 6 | This is a convertion from C++ to C and replace Arduino function by POSIX/ANSI functions 7 | -------------------------------------------------------------------------------- /testgps.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include "tinygps.h" 9 | 10 | #define BAUDRATE B4800 11 | #define FALSE 0 12 | #define TRUE 1 13 | // 14 | volatile int STOP=FALSE; 15 | void signal_handler_IO (int status); 16 | int wait_flag=TRUE; 17 | char devicename[80] = "/dev/ttyUSB0", ch; 18 | int status; 19 | 20 | int newdata = 0; 21 | 22 | // 23 | int main(int argc, char *argv[]) 24 | { 25 | int fd, res, i; 26 | struct termios newtio; 27 | struct sigaction saio; 28 | char buf[255]; 29 | // 30 | //open the device in non-blocking way (read will return immediately) 31 | fd = open(devicename, O_RDWR | O_NOCTTY | O_NONBLOCK); 32 | if (fd < 0) 33 | { 34 | perror(devicename); 35 | exit(1); 36 | } 37 | // 38 | //install the serial handler before making the device asynchronous 39 | saio.sa_handler = signal_handler_IO; 40 | sigemptyset(&saio.sa_mask); //saio.sa_mask = 0; 41 | saio.sa_flags = 0; 42 | saio.sa_restorer = NULL; 43 | sigaction(SIGIO,&saio,NULL); 44 | // 45 | // allow the process to receive SIGIO 46 | fcntl(fd, F_SETOWN, getpid()); 47 | // 48 | // make the file descriptor asynchronous 49 | fcntl(fd, F_SETFL, FASYNC); 50 | // 51 | // set new port settings for canonical input processing 52 | newtio.c_cflag = BAUDRATE | CRTSCTS | CS8 | CLOCAL | CREAD; 53 | newtio.c_iflag = IGNPAR; 54 | newtio.c_oflag = 0; 55 | newtio.c_lflag = 0; 56 | newtio.c_cc[VMIN]=1; 57 | newtio.c_cc[VTIME]=0; 58 | tcflush(fd, TCIFLUSH); 59 | tcsetattr(fd,TCSANOW,&newtio); 60 | // 61 | // loop while waiting for input. normally we would do something useful here 62 | while (STOP == FALSE) 63 | { 64 | // 65 | // after receiving SIGIO, wait_flag = FALSE, input is available and can be read */ 66 | if (wait_flag == FALSE) //if input is available 67 | { 68 | res = read(fd,buf,255); 69 | if (res > 0) 70 | { 71 | for (i=0; i < res; i++) //for all chars in string 72 | { 73 | //printf("%c", buf[i]); 74 | if(gps_encode(buf[i])) 75 | newdata = 1; 76 | } 77 | 78 | if (newdata) 79 | { 80 | float flat, flon; 81 | unsigned long age; 82 | gps_f_get_position(&flat, &flon, &age); 83 | printf("LAT= %f LON= %f SAT=%d PREC=%d \n", 84 | flat, flon, gps_satellites(), gps_hdop()); 85 | newdata = 0; 86 | } 87 | 88 | 89 | } 90 | wait_flag = TRUE; /* wait for new input */ 91 | } 92 | } 93 | close(fd); 94 | } 95 | // 96 | /*************************************************************************** 97 | * signal handler. sets wait_flag to FALSE, to indicate above loop that * 98 | * characters have been received. * 99 | ***************************************************************************/ 100 | // 101 | void signal_handler_IO (int status) 102 | { 103 | //printf("received SIGIO signal.\n"); 104 | wait_flag = FALSE; 105 | } 106 | 107 | 108 | -------------------------------------------------------------------------------- /tinygps.c: -------------------------------------------------------------------------------- 1 | /* 2 | TinyGPS - a small GPS library for Arduino providing basic NMEA parsing 3 | Based on work by and "distance_to" and "course_to" courtesy of Maarten Lamers. 4 | Suggestion to add satellites(), course_to(), and cardinal(), by Matt Monson. 5 | Copyright (C) 2008-2012 Mikal Hart 6 | All rights reserved. 7 | 8 | This library is free software; you can redistribute it and/or 9 | modify it under the terms of the GNU Lesser General Public 10 | License as published by the Free Software Foundation; either 11 | version 2.1 of the License, or (at your option) any later version. 12 | 13 | This library is distributed in the hope that it will be useful, 14 | but WITHOUT ANY WARRANTY; without even the implied warranty of 15 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 16 | Lesser General Public License for more details. 17 | 18 | You should have received a copy of the GNU Lesser General Public 19 | License along with this library; if not, write to the Free Software 20 | Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA 21 | */ 22 | 23 | #include 24 | #include 25 | #include "tinygps.h" 26 | 27 | // properties 28 | unsigned long _time, _new_time; 29 | unsigned long _date, _new_date; 30 | long _latitude, _new_latitude; 31 | long _longitude, _new_longitude; 32 | long _altitude, _new_altitude; 33 | unsigned long _speed, _new_speed; 34 | unsigned long _course, _new_course; 35 | unsigned long _hdop, _new_hdop; 36 | unsigned short _numsats, _new_numsats; 37 | 38 | unsigned long _last_time_fix, _new_time_fix; 39 | unsigned long _last_position_fix, _new_position_fix; 40 | 41 | // parsing state variables 42 | byte _parity; 43 | bool _is_checksum_term; 44 | char _term[15]; 45 | byte _sentence_type; 46 | byte _term_number = 0; 47 | byte _term_offset = 0; 48 | bool _is_gps_data_good; 49 | 50 | #ifndef GPS_NO_STATS 51 | // statistics 52 | unsigned long _encoded_characters; 53 | unsigned short _good_sentences; 54 | unsigned short _failed_checksum; 55 | unsigned short _passed_checksum; 56 | #endif 57 | 58 | // 59 | // public methods 60 | // 61 | 62 | // verify is character is a digit 63 | bool gpsisdigit(char c) { return c >= '0' && c <= '9'; } 64 | 65 | // signed altitude in centimeters (from GPGGA sentence) 66 | inline long altitude() { return _altitude; } 67 | 68 | // course in last full GPRMC sentence in 100th of a degree 69 | inline unsigned long course() { return _course; } 70 | 71 | // speed in last full GPRMC sentence in 100ths of a knot 72 | inline unsigned long speed() { return _speed; } 73 | 74 | // satellites used in last full GPGGA sentence 75 | inline unsigned short gps_satellites() { return _numsats; } 76 | 77 | // horizontal dilution of precision in 100ths 78 | inline unsigned long gps_hdop() { return _hdop; } 79 | 80 | 81 | clock_t uptime() 82 | { 83 | return clock() / (CLOCKS_PER_SEC / 1000); 84 | } 85 | 86 | float radians(float deg) 87 | { 88 | return deg * (PI/180); 89 | } 90 | 91 | float degrees(float rad) 92 | { 93 | return rad * (180/PI); 94 | } 95 | 96 | bool gps_encode(char c) 97 | { 98 | bool valid_sentence = false; 99 | 100 | #ifndef GPS_NO_STATS 101 | _encoded_characters++; 102 | #endif 103 | switch(c) 104 | { 105 | case ',': // term terminators 106 | _parity ^= c; 107 | case '\r': 108 | case '\n': 109 | case '*': 110 | if (_term_offset < sizeof(_term)) 111 | { 112 | _term[_term_offset] = 0; 113 | valid_sentence = gps_term_complete(); 114 | } 115 | ++_term_number; 116 | _term_offset = 0; 117 | _is_checksum_term = c == '*'; 118 | return valid_sentence; 119 | 120 | case '$': // sentence begin 121 | _term_number = 0; 122 | _term_offset = 0; 123 | _parity = 0; 124 | _sentence_type = GPS_SENTENCE_OTHER; 125 | _is_checksum_term = false; 126 | _is_gps_data_good = false; 127 | return valid_sentence; 128 | } 129 | 130 | // ordinary characters 131 | if (_term_offset < sizeof(_term) - 1) 132 | _term[_term_offset++] = c; 133 | if (!_is_checksum_term) 134 | _parity ^= c; 135 | 136 | return valid_sentence; 137 | } 138 | 139 | #ifndef GPS_NO_STATS 140 | void gps_stats(unsigned long *chars, unsigned short *sentences, unsigned short *failed_cs) 141 | { 142 | if (chars) 143 | *chars = _encoded_characters; 144 | if (sentences) 145 | *sentences = _good_sentences; 146 | if (failed_cs) 147 | *failed_cs = _failed_checksum; 148 | } 149 | #endif 150 | 151 | /* 152 | * internal utilities 153 | */ 154 | 155 | int from_hex(char a) 156 | { 157 | if (a >= 'A' && a <= 'F') 158 | return a - 'A' + 10; 159 | else if (a >= 'a' && a <= 'f') 160 | return a - 'a' + 10; 161 | else 162 | return a - '0'; 163 | } 164 | 165 | unsigned long gps_parse_decimal() 166 | { 167 | char *p; 168 | bool isneg; 169 | unsigned long ret; 170 | 171 | p = _term; 172 | isneg = (*p == '-'); 173 | if (isneg) 174 | ++p; 175 | 176 | ret = 100UL * gpsatol(p); 177 | 178 | while (gpsisdigit(*p)) 179 | ++p; 180 | 181 | if (*p == '.') 182 | { 183 | if (gpsisdigit(p[1])) 184 | { 185 | ret += 10 * (p[1] - '0'); 186 | if (gpsisdigit(p[2])) 187 | ret += p[2] - '0'; 188 | } 189 | } 190 | return isneg ? -ret : ret; 191 | } 192 | 193 | unsigned long gps_parse_degrees() 194 | { 195 | char *p; 196 | unsigned long left; 197 | unsigned long tenk_minutes; 198 | 199 | left = gpsatol(_term); 200 | tenk_minutes = (left % 100UL) * 10000UL; 201 | 202 | for (p=_term; gpsisdigit(*p); ++p); 203 | 204 | if (*p == '.') 205 | { 206 | unsigned long mult = 1000; 207 | while (gpsisdigit(*++p)) 208 | { 209 | tenk_minutes += mult * (*p - '0'); 210 | mult /= 10; 211 | } 212 | } 213 | return (left / 100) * 100000 + tenk_minutes / 6; 214 | } 215 | 216 | #define COMBINE(sentence_type, term_number) (((unsigned)(sentence_type) << 5) | term_number) 217 | 218 | /* Processes a just-completed term 219 | * Returns true if new sentence has just passed checksum test and is validated 220 | */ 221 | bool gps_term_complete() 222 | { 223 | if (_is_checksum_term) 224 | { 225 | byte checksum; 226 | checksum = 16 * from_hex(_term[0]) + from_hex(_term[1]); 227 | if (checksum == _parity) 228 | { 229 | if (_is_gps_data_good) 230 | { 231 | #ifndef GPS_NO_STATS 232 | ++_good_sentences; 233 | #endif 234 | _last_time_fix = _new_time_fix; 235 | _last_position_fix = _new_position_fix; 236 | 237 | switch(_sentence_type) 238 | { 239 | case GPS_SENTENCE_GPRMC: 240 | _time = _new_time; 241 | _date = _new_date; 242 | _latitude = _new_latitude; 243 | _longitude = _new_longitude; 244 | _speed = _new_speed; 245 | _course = _new_course; 246 | break; 247 | case GPS_SENTENCE_GPGGA: 248 | _altitude = _new_altitude; 249 | _time = _new_time; 250 | _latitude = _new_latitude; 251 | _longitude = _new_longitude; 252 | _numsats = _new_numsats; 253 | _hdop = _new_hdop; 254 | break; 255 | } 256 | 257 | return true; 258 | } 259 | } 260 | 261 | #ifndef GPS_NO_STATS 262 | else 263 | ++_failed_checksum; 264 | #endif 265 | return false; 266 | } 267 | 268 | // the first term determines the sentence type 269 | if (_term_number == 0) 270 | { 271 | if (!gpsstrcmp(_term, GPRMC_TERM)) 272 | _sentence_type = GPS_SENTENCE_GPRMC; 273 | else if (!gpsstrcmp(_term, GPGGA_TERM)) 274 | _sentence_type = GPS_SENTENCE_GPGGA; 275 | else 276 | _sentence_type = GPS_SENTENCE_OTHER; 277 | return false; 278 | } 279 | 280 | if (_sentence_type != GPS_SENTENCE_OTHER && _term[0]) 281 | switch(COMBINE(_sentence_type, _term_number)) 282 | { 283 | case COMBINE(GPS_SENTENCE_GPRMC, 1): // Time in both sentences 284 | case COMBINE(GPS_SENTENCE_GPGGA, 1): 285 | _new_time = gps_parse_decimal(); 286 | _new_time_fix = uptime(); 287 | break; 288 | case COMBINE(GPS_SENTENCE_GPRMC, 2): // GPRMC validity 289 | _is_gps_data_good = (_term[0] == 'A'); 290 | break; 291 | case COMBINE(GPS_SENTENCE_GPRMC, 3): // Latitude 292 | case COMBINE(GPS_SENTENCE_GPGGA, 2): 293 | _new_latitude = gps_parse_degrees(); 294 | _new_position_fix = uptime(); 295 | break; 296 | case COMBINE(GPS_SENTENCE_GPRMC, 4): // N/S 297 | case COMBINE(GPS_SENTENCE_GPGGA, 3): 298 | if (_term[0] == 'S') 299 | _new_latitude = -_new_latitude; 300 | break; 301 | case COMBINE(GPS_SENTENCE_GPRMC, 5): // Longitude 302 | case COMBINE(GPS_SENTENCE_GPGGA, 4): 303 | _new_longitude = gps_parse_degrees(); 304 | break; 305 | case COMBINE(GPS_SENTENCE_GPRMC, 6): // E/W 306 | case COMBINE(GPS_SENTENCE_GPGGA, 5): 307 | if (_term[0] == 'W') 308 | _new_longitude = -_new_longitude; 309 | break; 310 | case COMBINE(GPS_SENTENCE_GPRMC, 7): // Speed (GPRMC) 311 | _new_speed = gps_parse_decimal(); 312 | break; 313 | case COMBINE(GPS_SENTENCE_GPRMC, 8): // Course (GPRMC) 314 | _new_course = gps_parse_decimal(); 315 | break; 316 | case COMBINE(GPS_SENTENCE_GPRMC, 9): // Date (GPRMC) 317 | _new_date = gpsatol(_term); 318 | break; 319 | case COMBINE(GPS_SENTENCE_GPGGA, 6): // Fix data (GPGGA) 320 | _is_gps_data_good = (_term[0] > '0'); 321 | break; 322 | case COMBINE(GPS_SENTENCE_GPGGA, 7): // Satellites used (GPGGA) 323 | _new_numsats = (unsigned char)atoi(_term); 324 | break; 325 | case COMBINE(GPS_SENTENCE_GPGGA, 8): // HDOP 326 | _new_hdop = gps_parse_decimal(); 327 | break; 328 | case COMBINE(GPS_SENTENCE_GPGGA, 9): // Altitude (GPGGA) 329 | _new_altitude = gps_parse_decimal(); 330 | break; 331 | } 332 | 333 | return false; 334 | } 335 | 336 | long gpsatol(const char *str) 337 | { 338 | long ret = 0; 339 | while (gpsisdigit(*str)) 340 | ret = 10 * ret + *str++ - '0'; 341 | return ret; 342 | } 343 | 344 | int gpsstrcmp(const char *str1, const char *str2) 345 | { 346 | while (*str1 && *str1 == *str2) 347 | ++str1, ++str2; 348 | return *str1; 349 | } 350 | 351 | /* static */ 352 | float gps_distance_between (float lat1, float long1, float lat2, float long2) 353 | { 354 | // returns distance in meters between two positions, both specified 355 | // as signed decimal-degrees latitude and longitude. Uses great-circle 356 | // distance computation for hypothetical sphere of radius 6372795 meters. 357 | // Because Earth is no exact sphere, rounding errors may be up to 0.5%. 358 | // Courtesy of Maarten Lamers 359 | float delta = radians(long1-long2); 360 | float sdlong = (float)sin(delta); 361 | float cdlong = (float)cos(delta); 362 | lat1 = radians(lat1); 363 | lat2 = radians(lat2); 364 | float slat1 = sin(lat1); 365 | float clat1 = cos(lat1); 366 | float slat2 = sin(lat2); 367 | float clat2 = cos(lat2); 368 | delta = (clat1 * slat2) - (slat1 * clat2 * cdlong); 369 | delta = sq(delta); 370 | delta += sq(clat2 * sdlong); 371 | delta = sqrt(delta); 372 | float denom = (slat1 * slat2) + (clat1 * clat2 * cdlong); 373 | delta = atan2(delta, denom); 374 | return delta * 6372795; 375 | } 376 | 377 | float gps_course_to (float lat1, float long1, float lat2, float long2) 378 | { 379 | // returns course in degrees (North=0, West=270) from position 1 to position 2, 380 | // both specified as signed decimal-degrees latitude and longitude. 381 | // Because Earth is no exact sphere, calculated course may be off by a tiny fraction. 382 | // Courtesy of Maarten Lamers 383 | float dlon = radians(long2-long1); 384 | lat1 = radians(lat1); 385 | lat2 = radians(lat2); 386 | float a1 = sin(dlon) * cos(lat2); 387 | float a2 = sin(lat1) * cos(lat2) * cos(dlon); 388 | a2 = cos(lat1) * sin(lat2) - a2; 389 | a2 = atan2(a1, a2); 390 | if (a2 < 0.0) 391 | { 392 | a2 += TWO_PI; 393 | } 394 | return degrees(a2); 395 | } 396 | 397 | const char *gps_cardinal (float course) 398 | { 399 | static const char* directions[] = {"N", "NNE", "NE", "ENE", "E", "ESE", "SE", "SSE", "S", "SSW", "SW", "WSW", "W", "WNW", "NW", "NNW"}; 400 | 401 | int direction = (int)((course + 11.25f) / 22.5f); 402 | return directions[direction % 16]; 403 | } 404 | 405 | // lat/long in hundred thousandths of a degree and age of fix in milliseconds 406 | void gps_get_position(long *latitude, long *longitude, unsigned long *fix_age) 407 | { 408 | if (latitude) 409 | *latitude = _latitude; 410 | if (longitude) 411 | *longitude = _longitude; 412 | if (fix_age) 413 | *fix_age = (_last_position_fix == GPS_INVALID_FIX_TIME) ? 414 | GPS_INVALID_AGE : uptime() - _last_position_fix; 415 | } 416 | 417 | // date as ddmmyy, time as hhmmsscc, and age in milliseconds 418 | void gps_get_datetime(unsigned long *date, unsigned long *time, unsigned long *age) 419 | { 420 | if (date) 421 | *date = _date; 422 | if (time) 423 | *time = _time; 424 | if (age) 425 | *age = _last_time_fix == GPS_INVALID_FIX_TIME ? 426 | GPS_INVALID_AGE : uptime() - _last_time_fix; 427 | } 428 | 429 | void gps_f_get_position(float *latitude, float *longitude, unsigned long *fix_age) 430 | { 431 | long lat, lon; 432 | gps_get_position(&lat, &lon, fix_age); 433 | *latitude = lat == GPS_INVALID_ANGLE ? GPS_INVALID_F_ANGLE : (lat / 100000.0); 434 | *longitude = lat == GPS_INVALID_ANGLE ? GPS_INVALID_F_ANGLE : (lon / 100000.0); 435 | } 436 | 437 | void gps_crack_datetime(int *year, byte *month, byte *day, 438 | byte *hour, byte *minute, byte *second, byte *hundredths, unsigned long *age) 439 | { 440 | unsigned long date, time; 441 | gps_get_datetime(&date, &time, age); 442 | if (year) 443 | { 444 | *year = date % 100; 445 | *year += *year > 80 ? 1900 : 2000; 446 | } 447 | if (month) *month = (date / 100) % 100; 448 | if (day) *day = date / 10000; 449 | if (hour) *hour = time / 1000000; 450 | if (minute) *minute = (time / 10000) % 100; 451 | if (second) *second = (time / 100) % 100; 452 | if (hundredths) *hundredths = time % 100; 453 | } 454 | 455 | float gps_f_altitude() 456 | { 457 | return _altitude == GPS_INVALID_ALTITUDE ? GPS_INVALID_F_ALTITUDE : _altitude / 100.0; 458 | } 459 | 460 | float gps_f_course() 461 | { 462 | return _course == GPS_INVALID_ANGLE ? GPS_INVALID_F_ANGLE : _course / 100.0; 463 | } 464 | 465 | float gps_f_speed_knots() 466 | { 467 | return _speed == GPS_INVALID_SPEED ? GPS_INVALID_F_SPEED : _speed / 100.0; 468 | } 469 | 470 | float gps_f_speed_mph() 471 | { 472 | float sk = gps_f_speed_knots(); 473 | return sk == GPS_INVALID_F_SPEED ? GPS_INVALID_F_SPEED : GPS_MPH_PER_KNOT * gps_f_speed_knots(); 474 | } 475 | 476 | float gps_f_speed_mps() 477 | { 478 | float sk = gps_f_speed_knots(); 479 | return sk == GPS_INVALID_F_SPEED ? GPS_INVALID_F_SPEED : GPS_MPS_PER_KNOT * gps_f_speed_knots(); 480 | } 481 | 482 | float gps_f_speed_kmph() 483 | { 484 | float sk = gps_f_speed_knots(); 485 | return sk == GPS_INVALID_F_SPEED ? GPS_INVALID_F_SPEED : GPS_KMPH_PER_KNOT * gps_f_speed_knots(); 486 | } 487 | 488 | -------------------------------------------------------------------------------- /tinygps.h: -------------------------------------------------------------------------------- 1 | /* 2 | TinyGPS - a small GPS library for Arduino providing basic NMEA parsing 3 | Based on work by and "distance_to" and "course_to" courtesy of Maarten Lamers. 4 | Suggestion to add satellites(), course_to(), and cardinal(), by Matt Monson. 5 | Copyright (C) 2008-2012 Mikal Hart 6 | All rights reserved. 7 | 8 | This library is free software; you can redistribute it and/or 9 | modify it under the terms of the GNU Lesser General Public 10 | License as published by the Free Software Foundation; either 11 | version 2.1 of the License, or (at your option) any later version. 12 | 13 | This library is distributed in the hope that it will be useful, 14 | but WITHOUT ANY WARRANTY; without even the implied warranty of 15 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 16 | Lesser General Public License for more details. 17 | 18 | You should have received a copy of the GNU Lesser General Public 19 | License along with this library; if not, write to the Free Software 20 | Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA 21 | */ 22 | 23 | #ifndef tinygps_h 24 | #define tinygps_h 25 | 26 | typedef char bool; 27 | typedef unsigned char byte; 28 | #define false 0 29 | #define true 1 30 | 31 | #define PI 3.14159265 32 | #define TWO_PI 2*PI 33 | 34 | #define sq(x) ((x)*(x)) 35 | 36 | #define GPRMC_TERM "GPRMC" 37 | #define GPGGA_TERM "GPGGA" 38 | 39 | #define GPS_INVALID_F_ANGLE 1000.0 40 | #define GPS_INVALID_F_ALTITUDE 1000000.0 41 | #define GPS_INVALID_F_SPEED -1.0 42 | 43 | 44 | #define GPS_VERSION 12 // software version of this library 45 | #define GPS_MPH_PER_KNOT 1.15077945 46 | #define GPS_MPS_PER_KNOT 0.51444444 47 | #define GPS_KMPH_PER_KNOT 1.852 48 | #define GPS_MILES_PER_METER 0.00062137112 49 | #define GPS_KM_PER_METER 0.001 50 | // #define GPS_NO_STATS 51 | 52 | enum { 53 | GPS_INVALID_AGE = 0xFFFFFFFF, 54 | GPS_INVALID_ANGLE = 999999999, 55 | GPS_INVALID_ALTITUDE = 999999999, 56 | GPS_INVALID_DATE = 0, 57 | GPS_INVALID_TIME = 0xFFFFFFFF, 58 | GPS_INVALID_SPEED = 999999999, 59 | GPS_INVALID_FIX_TIME = 0xFFFFFFFF, 60 | GPS_INVALID_SATELLITES = 0xFF, 61 | GPS_INVALID_HDOP = 0xFFFFFFFF 62 | }; 63 | 64 | // process one character received from GPS 65 | bool encode(char c); 66 | 67 | // lat/long in hundred thousandths of a degree and age of fix in milliseconds 68 | void gps_get_position(long *latitude, long *longitude, unsigned long *fix_age); 69 | 70 | // date as ddmmyy, time as hhmmsscc, and age in milliseconds 71 | void gps_get_datetime(unsigned long *date, unsigned long *time, unsigned long *age); 72 | 73 | void gps_f_get_position(float *latitude, float *longitude, unsigned long *fix_age); 74 | void gps_crack_datetime(int *year, byte *month, byte *day, 75 | byte *hour, byte *minute, byte *second, byte *hundredths, unsigned long *fix_age); 76 | float gps_f_altitude(); 77 | float gps_f_course(); 78 | float gps_f_speed_knots(); 79 | float gps_f_speed_mph(); 80 | float gps_f_speed_mps(); 81 | float gps_f_speed_kmph(); 82 | 83 | static int library_version() { return GPS_VERSION; } 84 | 85 | static float gps_distance_between (float lat1, float long1, float lat2, float long2); 86 | static float gps_course_to (float lat1, float long1, float lat2, float long2); 87 | static const char *gps_cardinal(float course); 88 | 89 | #ifndef GPS_NO_STATS 90 | void gps_stats(unsigned long *chars, unsigned short *good_sentences, unsigned short *failed_cs); 91 | #endif 92 | 93 | enum { 94 | GPS_SENTENCE_GPGGA, 95 | GPS_SENTENCE_GPRMC, 96 | GPS_SENTENCE_OTHER 97 | }; 98 | 99 | // internal utilities 100 | int from_hex(char a); 101 | unsigned long gps_parse_decimal(); 102 | unsigned long gps_parse_degrees(); 103 | bool gps_term_complete(); 104 | bool gpsisdigit(char c); 105 | long gpsatol(const char *str); 106 | int gpsstrcmp(const char *str1, const char *str2); 107 | 108 | #endif 109 | --------------------------------------------------------------------------------