Allows for a GPS module to be connected to a serial port and exposes an easy to use API to get the GPS data. New feature, added Mbed/LPC17xx RTC synchronisation

Dependents:   SatGPS AntiTheftGPS FLIGHT_CONTROL_AND_COMMUNICATIONS_SYSTEM GPS-Lora ... more

Committer:
AjK
Date:
Wed Apr 20 09:15:07 2011 +0000
Revision:
5:7f130f85d5a4
Parent:
2:8aa059e7d8b1
1.15 See ChangeLog.c

Who changed what in which revision?

UserRevisionLine numberNew contents of line
AjK 0:db98027c0bbb 1 /*
AjK 0:db98027c0bbb 2 Copyright (c) 2010 Andy Kirkham
AjK 0:db98027c0bbb 3
AjK 0:db98027c0bbb 4 Permission is hereby granted, free of charge, to any person obtaining a copy
AjK 0:db98027c0bbb 5 of this software and associated documentation files (the "Software"), to deal
AjK 0:db98027c0bbb 6 in the Software without restriction, including without limitation the rights
AjK 0:db98027c0bbb 7 to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
AjK 0:db98027c0bbb 8 copies of the Software, and to permit persons to whom the Software is
AjK 0:db98027c0bbb 9 furnished to do so, subject to the following conditions:
AjK 0:db98027c0bbb 10
AjK 0:db98027c0bbb 11 The above copyright notice and this permission notice shall be included in
AjK 0:db98027c0bbb 12 all copies or substantial portions of the Software.
AjK 0:db98027c0bbb 13
AjK 0:db98027c0bbb 14 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
AjK 0:db98027c0bbb 15 IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
AjK 0:db98027c0bbb 16 FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AjK 0:db98027c0bbb 17 AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
AjK 0:db98027c0bbb 18 LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
AjK 0:db98027c0bbb 19 OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
AjK 0:db98027c0bbb 20 THE SOFTWARE.
AjK 0:db98027c0bbb 21 */
AjK 0:db98027c0bbb 22
AjK 0:db98027c0bbb 23 #include "GPS_Time.h"
AjK 0:db98027c0bbb 24
AjK 0:db98027c0bbb 25 GPS_Time::GPS_Time()
AjK 0:db98027c0bbb 26 {
AjK 0:db98027c0bbb 27 year = 2000;
AjK 0:db98027c0bbb 28 month = 1;
AjK 0:db98027c0bbb 29 day = 1;
AjK 0:db98027c0bbb 30 hour = 0;
AjK 0:db98027c0bbb 31 minute = 0;
AjK 0:db98027c0bbb 32 second = 0;
AjK 0:db98027c0bbb 33 tenths = 0;
AjK 0:db98027c0bbb 34 hundreths = 0;
AjK 0:db98027c0bbb 35 status = 'V';
AjK 2:8aa059e7d8b1 36 velocity = 0;
AjK 2:8aa059e7d8b1 37 track = 0;
AjK 2:8aa059e7d8b1 38 magvar_dir = 'W';
AjK 2:8aa059e7d8b1 39 magvar = 0;
AjK 0:db98027c0bbb 40 }
AjK 0:db98027c0bbb 41
AjK 5:7f130f85d5a4 42 time_t
AjK 5:7f130f85d5a4 43 GPS_Time::to_C_tm(bool set)
AjK 5:7f130f85d5a4 44 {
AjK 5:7f130f85d5a4 45 GPS_Time t;
AjK 5:7f130f85d5a4 46 tm ct;
AjK 5:7f130f85d5a4 47 time_t q;
AjK 5:7f130f85d5a4 48
AjK 5:7f130f85d5a4 49 timeNow(&t);
AjK 5:7f130f85d5a4 50 ct.tm_sec = t.second;
AjK 5:7f130f85d5a4 51 ct.tm_min = t.minute;
AjK 5:7f130f85d5a4 52 ct.tm_hour = t.hour;
AjK 5:7f130f85d5a4 53 ct.tm_mday = t.day;
AjK 5:7f130f85d5a4 54 ct.tm_mon = t.month - 1;
AjK 5:7f130f85d5a4 55 ct.tm_year = t.year - 1900;
AjK 5:7f130f85d5a4 56 ct.tm_isdst = 0; // GPS has no understanding of DST.
AjK 5:7f130f85d5a4 57
AjK 5:7f130f85d5a4 58 q = mktime(&ct);
AjK 5:7f130f85d5a4 59 if (set) {
AjK 5:7f130f85d5a4 60 set_time(q);
AjK 5:7f130f85d5a4 61 }
AjK 5:7f130f85d5a4 62 return q;
AjK 5:7f130f85d5a4 63 }
AjK 5:7f130f85d5a4 64
AjK 0:db98027c0bbb 65 GPS_Time *
AjK 0:db98027c0bbb 66 GPS_Time::timeNow(GPS_Time *n)
AjK 0:db98027c0bbb 67 {
AjK 0:db98027c0bbb 68 if (n == NULL) n = new GPS_Time;
AjK 0:db98027c0bbb 69
AjK 0:db98027c0bbb 70 do {
AjK 0:db98027c0bbb 71 memcpy(n, this, sizeof(GPS_Time));
AjK 0:db98027c0bbb 72 }
AjK 0:db98027c0bbb 73 while (memcmp(n, this, sizeof(GPS_Time)));
AjK 0:db98027c0bbb 74 return n;
AjK 0:db98027c0bbb 75 }
AjK 0:db98027c0bbb 76
AjK 0:db98027c0bbb 77 void
AjK 0:db98027c0bbb 78 GPS_Time::operator++()
AjK 0:db98027c0bbb 79 {
AjK 0:db98027c0bbb 80 hundreths++;
AjK 0:db98027c0bbb 81 if (hundreths == 10) {
AjK 0:db98027c0bbb 82 hundreths = 0;
AjK 0:db98027c0bbb 83 tenths++;
AjK 0:db98027c0bbb 84 if (tenths == 10) {
AjK 0:db98027c0bbb 85 tenths = hundreths = 0;
AjK 0:db98027c0bbb 86 }
AjK 0:db98027c0bbb 87 }
AjK 0:db98027c0bbb 88 }
AjK 0:db98027c0bbb 89
AjK 0:db98027c0bbb 90 void
AjK 0:db98027c0bbb 91 GPS_Time::operator++(int)
AjK 0:db98027c0bbb 92 {
AjK 0:db98027c0bbb 93 const int days[12] = { 31,28,31,30,31,30,31,31,30,31,30,31 };
AjK 0:db98027c0bbb 94 bool dateInc = false;
AjK 0:db98027c0bbb 95
AjK 0:db98027c0bbb 96 tenths = hundreths = 0;
AjK 0:db98027c0bbb 97 second++;
AjK 0:db98027c0bbb 98
AjK 0:db98027c0bbb 99 if (second == 60) {
AjK 0:db98027c0bbb 100 second = 0;
AjK 0:db98027c0bbb 101 minute++;
AjK 0:db98027c0bbb 102 if (minute == 60) {
AjK 0:db98027c0bbb 103 minute = 0;
AjK 0:db98027c0bbb 104 hour++;
AjK 0:db98027c0bbb 105 if (hour == 24) {
AjK 0:db98027c0bbb 106 hour = 0;
AjK 0:db98027c0bbb 107 dateInc = true;
AjK 0:db98027c0bbb 108 }
AjK 0:db98027c0bbb 109 }
AjK 0:db98027c0bbb 110 }
AjK 0:db98027c0bbb 111
AjK 0:db98027c0bbb 112 if (dateInc) {
AjK 0:db98027c0bbb 113 /* Handle February leap year. */
AjK 0:db98027c0bbb 114 int leap_year = ((year % 4 == 0 && year % 100 != 0) || year % 400 == 0) ? 1 : 0;
AjK 0:db98027c0bbb 115 int days_this_month = days[month - 1];
AjK 0:db98027c0bbb 116 if (month == 2 && leap_year) days_this_month++;
AjK 0:db98027c0bbb 117 day++;
AjK 0:db98027c0bbb 118 if (day > days_this_month) {
AjK 0:db98027c0bbb 119 day = 1;
AjK 0:db98027c0bbb 120 month++;
AjK 0:db98027c0bbb 121 if (month == 13) {
AjK 0:db98027c0bbb 122 year++;
AjK 0:db98027c0bbb 123 }
AjK 0:db98027c0bbb 124 }
AjK 0:db98027c0bbb 125 }
AjK 0:db98027c0bbb 126 }
AjK 0:db98027c0bbb 127
AjK 2:8aa059e7d8b1 128 // $GPRMC,112709.735,A,5611.5340,N,00302.0306,W,000.0,307.0,150411,,,A*70
AjK 0:db98027c0bbb 129 void
AjK 0:db98027c0bbb 130 GPS_Time::nmea_rmc(char *s)
AjK 0:db98027c0bbb 131 {
AjK 0:db98027c0bbb 132 char *token;
AjK 0:db98027c0bbb 133 int token_counter = 0;
AjK 0:db98027c0bbb 134 char *time = (char *)NULL;
AjK 0:db98027c0bbb 135 char *date = (char *)NULL;
AjK 0:db98027c0bbb 136 char *stat = (char *)NULL;
AjK 2:8aa059e7d8b1 137 char *vel = (char *)NULL;
AjK 2:8aa059e7d8b1 138 char *trk = (char *)NULL;
AjK 2:8aa059e7d8b1 139 char *magv = (char *)NULL;
AjK 2:8aa059e7d8b1 140 char *magd = (char *)NULL;
AjK 2:8aa059e7d8b1 141
AjK 0:db98027c0bbb 142 token = strtok(s, ",");
AjK 0:db98027c0bbb 143 while (token) {
AjK 0:db98027c0bbb 144 switch (token_counter) {
AjK 2:8aa059e7d8b1 145 case 9: date = token; break;
AjK 2:8aa059e7d8b1 146 case 1: time = token; break;
AjK 2:8aa059e7d8b1 147 case 2: stat = token; break;
AjK 2:8aa059e7d8b1 148 case 7: vel = token; break;
AjK 2:8aa059e7d8b1 149 case 8: trk = token; break;
AjK 2:8aa059e7d8b1 150 case 10: magv = token; break;
AjK 2:8aa059e7d8b1 151 case 11: magd = token; break;
AjK 0:db98027c0bbb 152 }
AjK 0:db98027c0bbb 153 token = strtok((char *)NULL, ",");
AjK 0:db98027c0bbb 154 token_counter++;
AjK 0:db98027c0bbb 155 }
AjK 0:db98027c0bbb 156
AjK 0:db98027c0bbb 157 if (stat && date && time) {
AjK 0:db98027c0bbb 158 hour = (char)((time[0] - '0') * 10) + (time[1] - '0');
AjK 0:db98027c0bbb 159 minute = (char)((time[2] - '0') * 10) + (time[3] - '0');
AjK 0:db98027c0bbb 160 second = (char)((time[4] - '0') * 10) + (time[5] - '0');
AjK 0:db98027c0bbb 161 day = (char)((date[0] - '0') * 10) + (date[1] - '0');
AjK 0:db98027c0bbb 162 month = (char)((date[2] - '0') * 10) + (date[3] - '0');
AjK 0:db98027c0bbb 163 year = (int)((date[4] - '0') * 10) + (date[5] - '0') + 2000;
AjK 0:db98027c0bbb 164 status = stat[0];
AjK 2:8aa059e7d8b1 165 velocity = atof(vel);
AjK 2:8aa059e7d8b1 166 track = atof(trk);
AjK 2:8aa059e7d8b1 167 magvar = atof(magv);
AjK 2:8aa059e7d8b1 168 magvar_dir = magd[0];
AjK 0:db98027c0bbb 169 }
AjK 0:db98027c0bbb 170 }
AjK 0:db98027c0bbb 171
AjK 0:db98027c0bbb 172 double
AjK 0:db98027c0bbb 173 GPS_Time::julian_day_number(GPS_Time *t) {
AjK 0:db98027c0bbb 174 double wikipedia_jdn = (double)(1461 * ((int)t->year + 4800 + ((int)t->month - 14) / 12)) / 4 + (367 * ((int)t->month - 2 - 12 * (((int)t->month - 14) / 12))) / 12 - (3 * (((int)t->year + 4900 + ((int)t->month - 14) / 12 ) / 100)) / 4 + (int)t->day - 32075;
AjK 0:db98027c0bbb 175 return wikipedia_jdn;
AjK 0:db98027c0bbb 176 }
AjK 0:db98027c0bbb 177
AjK 0:db98027c0bbb 178 double
AjK 0:db98027c0bbb 179 GPS_Time::julian_date(GPS_Time *t) {
AjK 0:db98027c0bbb 180 double hour, minute, second, jd;
AjK 0:db98027c0bbb 181 hour = (double)t->hour;
AjK 0:db98027c0bbb 182 minute = (double)t->minute;
AjK 0:db98027c0bbb 183 second = (double)t->second + ((double)t->tenths / 10.) + ((double)t->hundreths / 100.);
AjK 0:db98027c0bbb 184
AjK 0:db98027c0bbb 185 jd = julian_day_number(t) - 0.5 +
AjK 0:db98027c0bbb 186 ((hour - 12.) / 24.) +
AjK 0:db98027c0bbb 187 (minute / 1440.) +
AjK 0:db98027c0bbb 188 (second / 86400.);
AjK 0:db98027c0bbb 189
AjK 0:db98027c0bbb 190 return jd;
AjK 0:db98027c0bbb 191 }
AjK 0:db98027c0bbb 192
AjK 0:db98027c0bbb 193 double
AjK 0:db98027c0bbb 194 GPS_Time::siderealDegrees(double jd, double longitude) {
AjK 0:db98027c0bbb 195 double sidereal, gmst, lmst;
AjK 0:db98027c0bbb 196 double T = jd - 2451545.0;
AjK 0:db98027c0bbb 197 double T1 = T / 36525.0;
AjK 0:db98027c0bbb 198 double T2 = T1 * T1;
AjK 0:db98027c0bbb 199 double T3 = T2 * T1;
AjK 0:db98027c0bbb 200
AjK 0:db98027c0bbb 201 /* Calculate gmst angle. */
AjK 0:db98027c0bbb 202 sidereal = 280.46061837 + (360.98564736629 * T) + (0.000387933 * T2) - (T3 / 38710000.0);
AjK 0:db98027c0bbb 203
AjK 0:db98027c0bbb 204 /* Convert to degrees. */
AjK 0:db98027c0bbb 205 sidereal = fmod(sidereal, 360.0);
AjK 0:db98027c0bbb 206 if (sidereal < 0.0) sidereal += 360.0;
AjK 0:db98027c0bbb 207
AjK 0:db98027c0bbb 208 gmst = sidereal;
AjK 0:db98027c0bbb 209 lmst = gmst + longitude;
AjK 0:db98027c0bbb 210 return lmst;
AjK 0:db98027c0bbb 211 }
AjK 0:db98027c0bbb 212
AjK 0:db98027c0bbb 213 double
AjK 0:db98027c0bbb 214 GPS_Time::siderealDegrees(GPS_Time *t, double longitude) {
AjK 0:db98027c0bbb 215 if (t == NULL) t = new GPS_Time;
AjK 0:db98027c0bbb 216 return siderealDegrees(julian_date(t), longitude);
AjK 0:db98027c0bbb 217 }
AjK 0:db98027c0bbb 218
AjK 0:db98027c0bbb 219 double
AjK 0:db98027c0bbb 220 GPS_Time::siderealHA(double jd, double longitude) {
AjK 0:db98027c0bbb 221 double lmst = siderealDegrees(jd, longitude);
AjK 0:db98027c0bbb 222 return lmst / 360.0 * 24.0;
AjK 0:db98027c0bbb 223 }
AjK 0:db98027c0bbb 224
AjK 0:db98027c0bbb 225 double
AjK 0:db98027c0bbb 226 GPS_Time::siderealHA(GPS_Time *t, double longitude) {
AjK 0:db98027c0bbb 227 double lmst = siderealDegrees(t, longitude);
AjK 0:db98027c0bbb 228 return lmst / 360.0 * 24.0;
AjK 0:db98027c0bbb 229 }
AjK 0:db98027c0bbb 230