Satellite Observers Workbench. NOT yet complete, just published for forum posters to \"cherry pick\" pieces of code as requiered as an example.

Dependencies:   mbed

Committer:
AjK
Date:
Mon Oct 11 10:34:55 2010 +0000
Revision:
0:0a841b89d614
Totally Alpha quality as this project isn\t completed. Just publishing it as it answers many questions asked in the forums

Who changed what in which revision?

UserRevisionLine numberNew contents of line
AjK 0:0a841b89d614 1 /****************************************************************************
AjK 0:0a841b89d614 2 * Copyright 2010 Andy Kirkham, Stellar Technologies Ltd
AjK 0:0a841b89d614 3 *
AjK 0:0a841b89d614 4 * This file is part of the Satellite Observers Workbench (SOWB).
AjK 0:0a841b89d614 5 *
AjK 0:0a841b89d614 6 * SOWB is free software: you can redistribute it and/or modify
AjK 0:0a841b89d614 7 * it under the terms of the GNU General Public License as published by
AjK 0:0a841b89d614 8 * the Free Software Foundation, either version 3 of the License, or
AjK 0:0a841b89d614 9 * (at your option) any later version.
AjK 0:0a841b89d614 10 *
AjK 0:0a841b89d614 11 * SOWB is distributed in the hope that it will be useful,
AjK 0:0a841b89d614 12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
AjK 0:0a841b89d614 13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
AjK 0:0a841b89d614 14 * GNU General Public License for more details.
AjK 0:0a841b89d614 15 *
AjK 0:0a841b89d614 16 * You should have received a copy of the GNU General Public License
AjK 0:0a841b89d614 17 * along with SOWB. If not, see <http://www.gnu.org/licenses/>.
AjK 0:0a841b89d614 18 *
AjK 0:0a841b89d614 19 * $Id: main.cpp 5 2010-07-12 20:51:11Z ajk $
AjK 0:0a841b89d614 20 *
AjK 0:0a841b89d614 21 ***************************************************************************/
AjK 0:0a841b89d614 22
AjK 0:0a841b89d614 23 /*
AjK 0:0a841b89d614 24 Implementation notes.
AjK 0:0a841b89d614 25 The SOWB reads GPS data in on RDX1. We don't use TDX1 as we use it as part
AjK 0:0a841b89d614 26 of the SSP/SPI for the MAX7456/Flash card reader. However, we are not really
AjK 0:0a841b89d614 27 interested in writing to the GPS module as the most crucial data is the time
AjK 0:0a841b89d614 28 rather than the location. We do use the location data but we don't need any
AjK 0:0a841b89d614 29 WAAS data correction, 10metres is enough accuracy. So we only use Uart1 Rx to
AjK 0:0a841b89d614 30 get data.
AjK 0:0a841b89d614 31
AjK 0:0a841b89d614 32 Additionally, the GPS 1 pulse per second signal is connected to a P29 (P0.5)
AjK 0:0a841b89d614 33 and the gpioirq.c module routes that interrupt back to us via the _gps_pps_irq()
AjK 0:0a841b89d614 34 callback function.
AjK 0:0a841b89d614 35 */
AjK 0:0a841b89d614 36
AjK 0:0a841b89d614 37 #include "sowb.h"
AjK 0:0a841b89d614 38 #include "rit.h"
AjK 0:0a841b89d614 39 #include "gpio.h"
AjK 0:0a841b89d614 40 #include "gps.h"
AjK 0:0a841b89d614 41 #include "math.h"
AjK 0:0a841b89d614 42 #include "debug.h"
AjK 0:0a841b89d614 43
AjK 0:0a841b89d614 44 /* Module global variables. */
AjK 0:0a841b89d614 45 double lat_average;
AjK 0:0a841b89d614 46 double lon_average;
AjK 0:0a841b89d614 47 double lat_history[GPS_HISTORY_SIZE];
AjK 0:0a841b89d614 48 double lon_history[GPS_HISTORY_SIZE];
AjK 0:0a841b89d614 49 int history_in_index;
AjK 0:0a841b89d614 50 int history_complete;
AjK 0:0a841b89d614 51 GPS_TIME the_time;
AjK 0:0a841b89d614 52 GPS_LOCATION_RAW the_location;
AjK 0:0a841b89d614 53
AjK 0:0a841b89d614 54 double lat_acc_average;
AjK 0:0a841b89d614 55 double lon_acc_average;
AjK 0:0a841b89d614 56 double cnt_acc_average;
AjK 0:0a841b89d614 57
AjK 0:0a841b89d614 58 /* We maintain two serial input buffers so that the
AjK 0:0a841b89d614 59 _process() function can be processing one buffer
AjK 0:0a841b89d614 60 while the serial interrupt system can be capturing
AjK 0:0a841b89d614 61 to the other. */
AjK 0:0a841b89d614 62 char uart1_buffer[2][GPS_BUFFER_SIZE];
AjK 0:0a841b89d614 63
AjK 0:0a841b89d614 64 #define UART1_BUFFER_A 0
AjK 0:0a841b89d614 65 #define UART1_BUFFER_B 1
AjK 0:0a841b89d614 66
AjK 0:0a841b89d614 67 char active_buffer, active_buffer_in;
AjK 0:0a841b89d614 68 char passive_buffer_ready;
AjK 0:0a841b89d614 69
AjK 0:0a841b89d614 70 /* Update flag to signal new data in the active buffer. */
AjK 0:0a841b89d614 71 char have_new_location;
AjK 0:0a841b89d614 72
AjK 0:0a841b89d614 73 /* Set to non-zero by the updater interrupts. */
AjK 0:0a841b89d614 74 char time_updated;
AjK 0:0a841b89d614 75 char location_updated;
AjK 0:0a841b89d614 76
AjK 0:0a841b89d614 77 /* Internal function prototypes. */
AjK 0:0a841b89d614 78 void _gps_process_rmc(char passive_buffer);
AjK 0:0a841b89d614 79 void _gps_process_gga(char passive_buffer);
AjK 0:0a841b89d614 80 void _gps_time_inc(GPS_TIME *q);
AjK 0:0a841b89d614 81 void _gps_date_inc(GPS_TIME *q);
AjK 0:0a841b89d614 82 void _gps_timer_tick_cb(int);
AjK 0:0a841b89d614 83 void _gps_pps_alive_cb(int);
AjK 0:0a841b89d614 84 void Uart1_init(void);
AjK 0:0a841b89d614 85
AjK 0:0a841b89d614 86 /** gps_process
AjK 0:0a841b89d614 87 */
AjK 0:0a841b89d614 88 void gps_process(void) {
AjK 0:0a841b89d614 89 int i, j;
AjK 0:0a841b89d614 90 uint32_t ier_copy;
AjK 0:0a841b89d614 91 char passive_buffer;
AjK 0:0a841b89d614 92 double lat_temp, lon_temp;
AjK 0:0a841b89d614 93
AjK 0:0a841b89d614 94 if (passive_buffer_ready == 1) {
AjK 0:0a841b89d614 95 /* Disable serial interrupts on UART1 */
AjK 0:0a841b89d614 96 ier_copy = LPC_UART1->IER;
AjK 0:0a841b89d614 97 LPC_UART1->IER = 0x0;
AjK 0:0a841b89d614 98
AjK 0:0a841b89d614 99 /* What index is the passive buffer, i.e., what is the opposite
AjK 0:0a841b89d614 100 of the current active buffer? */
AjK 0:0a841b89d614 101 passive_buffer = active_buffer == 0 ? 1 : 0;
AjK 0:0a841b89d614 102
AjK 0:0a841b89d614 103 if (!strncmp(uart1_buffer[passive_buffer], "$GPRMC", 6)) {
AjK 0:0a841b89d614 104 _gps_process_rmc(passive_buffer);
AjK 0:0a841b89d614 105 }
AjK 0:0a841b89d614 106 else if (!strncmp(uart1_buffer[passive_buffer], "$GPGGA", 6)) {
AjK 0:0a841b89d614 107 _gps_process_gga(passive_buffer);
AjK 0:0a841b89d614 108 }
AjK 0:0a841b89d614 109
AjK 0:0a841b89d614 110 /* Flag we have completed processing the passive buffer. */
AjK 0:0a841b89d614 111 passive_buffer_ready = 0;
AjK 0:0a841b89d614 112
AjK 0:0a841b89d614 113 /* Enable serial interrupts on UART1 */
AjK 0:0a841b89d614 114 LPC_UART1->IER = ier_copy;
AjK 0:0a841b89d614 115 }
AjK 0:0a841b89d614 116
AjK 0:0a841b89d614 117 /* Update the latitude/longitude moving average filter. */
AjK 0:0a841b89d614 118 if (the_location.is_valid && have_new_location != 0) {
AjK 0:0a841b89d614 119 have_new_location = 0;
AjK 0:0a841b89d614 120 lat_history[history_in_index] = gps_convert_coord(the_location.lat, GPS_LAT_STR);
AjK 0:0a841b89d614 121 lon_history[history_in_index] = gps_convert_coord(the_location.lon, GPS_LON_STR);
AjK 0:0a841b89d614 122 history_in_index++;
AjK 0:0a841b89d614 123 if (history_in_index >= GPS_HISTORY_SIZE) {
AjK 0:0a841b89d614 124 history_in_index = 0;
AjK 0:0a841b89d614 125 history_complete = 1;
AjK 0:0a841b89d614 126 }
AjK 0:0a841b89d614 127 j = history_complete == 1 ? GPS_HISTORY_SIZE+1 : history_in_index;
AjK 0:0a841b89d614 128 for(lat_temp = lon_temp = 0., i = 1; i < j; i++) {
AjK 0:0a841b89d614 129 lat_temp += lat_history[i - 1];
AjK 0:0a841b89d614 130 lon_temp += lon_history[i - 1];
AjK 0:0a841b89d614 131 }
AjK 0:0a841b89d614 132 if (i) {
AjK 0:0a841b89d614 133 lat_average = lat_temp / (double)(i - 1);
AjK 0:0a841b89d614 134 lon_average = lon_temp / (double)(i - 1);
AjK 0:0a841b89d614 135 location_updated = 1;
AjK 0:0a841b89d614 136 }
AjK 0:0a841b89d614 137 }
AjK 0:0a841b89d614 138 }
AjK 0:0a841b89d614 139
AjK 0:0a841b89d614 140 /** _gps_process_rmc
AjK 0:0a841b89d614 141 *
AjK 0:0a841b89d614 142 * Extract the NMEA data from an RMC packet.
AjK 0:0a841b89d614 143 * Sample:-
AjK 0:0a841b89d614 144 * $GPRMC,132555.639,A,5611.5374,N,00302.0325,W,000.0,129.3,020910,,,A*75
AjK 0:0a841b89d614 145 *
AjK 0:0a841b89d614 146 * @param char passive_buffer Which buffer holds the RMC packet data.
AjK 0:0a841b89d614 147 */
AjK 0:0a841b89d614 148 void _gps_process_rmc(char passive_buffer) {
AjK 0:0a841b89d614 149 char *token;
AjK 0:0a841b89d614 150 int token_counter = 0;
AjK 0:0a841b89d614 151 char *time = (char *)NULL;
AjK 0:0a841b89d614 152 char *date = (char *)NULL;
AjK 0:0a841b89d614 153 char *status = (char *)NULL;
AjK 0:0a841b89d614 154
AjK 0:0a841b89d614 155 token = strtok(uart1_buffer[passive_buffer], ",");
AjK 0:0a841b89d614 156 while (token) {
AjK 0:0a841b89d614 157 switch (token_counter) {
AjK 0:0a841b89d614 158 case 9: date = token; break;
AjK 0:0a841b89d614 159 case 1: time = token; break;
AjK 0:0a841b89d614 160 case 2: status = token; break;
AjK 0:0a841b89d614 161 }
AjK 0:0a841b89d614 162 token = strtok((char *)NULL, ",");
AjK 0:0a841b89d614 163 token_counter++;
AjK 0:0a841b89d614 164 }
AjK 0:0a841b89d614 165
AjK 0:0a841b89d614 166 if (status && date && time) {
AjK 0:0a841b89d614 167 the_time.hour = (char)((time[0] - '0') * 10) + (time[1] - '0');
AjK 0:0a841b89d614 168 the_time.minute = (char)((time[2] - '0') * 10) + (time[3] - '0');
AjK 0:0a841b89d614 169 the_time.second = (char)((time[4] - '0') * 10) + (time[5] - '0');
AjK 0:0a841b89d614 170 the_time.day = (char)((date[0] - '0') * 10) + (date[1] - '0');
AjK 0:0a841b89d614 171 the_time.month = (char)((date[2] - '0') * 10) + (date[3] - '0');
AjK 0:0a841b89d614 172 the_time.year = (int)((date[4] - '0') * 10) + (date[5] - '0') + 2000;
AjK 0:0a841b89d614 173 the_time.is_valid = status[0] == 'A' ? 1 : 0;
AjK 0:0a841b89d614 174 the_time.prev_valid = 1;
AjK 0:0a841b89d614 175 }
AjK 0:0a841b89d614 176 else {
AjK 0:0a841b89d614 177 the_time.is_valid = 0;
AjK 0:0a841b89d614 178 }
AjK 0:0a841b89d614 179 }
AjK 0:0a841b89d614 180
AjK 0:0a841b89d614 181 /** _gps_process_gga
AjK 0:0a841b89d614 182 *
AjK 0:0a841b89d614 183 * Extract the NMEA data from a GGA packet.
AjK 0:0a841b89d614 184 * Sample:-
AjK 0:0a841b89d614 185 * $GPGGA,132526.639,5611.5417,N,00302.0298,W,1,05,7.3,43.4,M,52.0,M,,0000*70
AjK 0:0a841b89d614 186 *
AjK 0:0a841b89d614 187 * @param char passive_buffer Which buffer holds the GGA packet data.
AjK 0:0a841b89d614 188 */
AjK 0:0a841b89d614 189 void _gps_process_gga(char passive_buffer) {
AjK 0:0a841b89d614 190 char *token;
AjK 0:0a841b89d614 191 int token_counter = 0;
AjK 0:0a841b89d614 192 char *latitude = (char *)NULL;
AjK 0:0a841b89d614 193 char *longitude = (char *)NULL;
AjK 0:0a841b89d614 194 char *lat_dir = (char *)NULL;
AjK 0:0a841b89d614 195 char *lon_dir = (char *)NULL;
AjK 0:0a841b89d614 196 char *qual = (char *)NULL;
AjK 0:0a841b89d614 197 char *altitude = (char *)NULL;
AjK 0:0a841b89d614 198 char *sats = (char *)NULL;
AjK 0:0a841b89d614 199
AjK 0:0a841b89d614 200 token = strtok(uart1_buffer[passive_buffer], ",");
AjK 0:0a841b89d614 201 while (token) {
AjK 0:0a841b89d614 202 switch (token_counter) {
AjK 0:0a841b89d614 203 case 2: latitude = token; break;
AjK 0:0a841b89d614 204 case 4: longitude = token; break;
AjK 0:0a841b89d614 205 case 3: lat_dir = token; break;
AjK 0:0a841b89d614 206 case 5: lon_dir = token; break;
AjK 0:0a841b89d614 207 case 6: qual = token; break;
AjK 0:0a841b89d614 208 case 7: sats = token; break;
AjK 0:0a841b89d614 209 case 9: altitude = token; break;
AjK 0:0a841b89d614 210 }
AjK 0:0a841b89d614 211 token = strtok((char *)NULL, ",");
AjK 0:0a841b89d614 212 token_counter++;
AjK 0:0a841b89d614 213 }
AjK 0:0a841b89d614 214
AjK 0:0a841b89d614 215 /* If the fix quality is valid set our location information. */
AjK 0:0a841b89d614 216 if (latitude && longitude && altitude && sats) {
AjK 0:0a841b89d614 217 memcpy(the_location.lat, latitude, 10); /* Fixed length string. */
AjK 0:0a841b89d614 218 memcpy(the_location.lon, longitude, 10); /* Fixed length string. */
AjK 0:0a841b89d614 219 memset(the_location.alt, 0, sizeof(the_location.alt)); /* Clean string out first. */
AjK 0:0a841b89d614 220 strncpy(the_location.alt, altitude, 10); /* Variable length string. */
AjK 0:0a841b89d614 221 strncpy(the_location.sats, sats, 3); /* Variable length string. */
AjK 0:0a841b89d614 222 the_location.north_south = lat_dir[0];
AjK 0:0a841b89d614 223 the_location.east_west = lon_dir[0];
AjK 0:0a841b89d614 224 the_location.is_valid = qual[0];
AjK 0:0a841b89d614 225 the_location.updated++;
AjK 0:0a841b89d614 226 have_new_location = 1;
AjK 0:0a841b89d614 227 }
AjK 0:0a841b89d614 228 else {
AjK 0:0a841b89d614 229 the_location.is_valid = qual[0];
AjK 0:0a841b89d614 230 }
AjK 0:0a841b89d614 231 }
AjK 0:0a841b89d614 232
AjK 0:0a841b89d614 233 /** gps_convert_coord
AjK 0:0a841b89d614 234 *
AjK 0:0a841b89d614 235 * Given a string and a type convert the string into a double.
AjK 0:0a841b89d614 236 *
AjK 0:0a841b89d614 237 * @param char *s A pointer to the string to convert.
AjK 0:0a841b89d614 238 * @param int type The conversion type required (lat or lon)
AjK 0:0a841b89d614 239 * @return double the converted string.
AjK 0:0a841b89d614 240 */
AjK 0:0a841b89d614 241 double gps_convert_coord(char *s, int type) {
AjK 0:0a841b89d614 242 int deg, min, sec;
AjK 0:0a841b89d614 243 double fsec, val;
AjK 0:0a841b89d614 244
AjK 0:0a841b89d614 245 if (type == GPS_LAT_STR) {
AjK 0:0a841b89d614 246 deg = ( (s[0] - '0') * 10) + s[1] - '0';
AjK 0:0a841b89d614 247 min = ( (s[2] - '0') * 10) + s[3] - '0';
AjK 0:0a841b89d614 248 sec = ( ((s[5] - '0') * 1000) + ((s[6] - '0') * 100) + ((s[7] - '0') * 10) + (s[8] - '0'));
AjK 0:0a841b89d614 249 fsec = (double)((double)sec /10000.0);
AjK 0:0a841b89d614 250 val = (double)deg + ((double)((double)min/60.0)) + (fsec/60.0);
AjK 0:0a841b89d614 251 return val;
AjK 0:0a841b89d614 252 }
AjK 0:0a841b89d614 253 else {
AjK 0:0a841b89d614 254 deg = ( (s[0] - '0') * 100) + ((s[1] - '0') * 10) + (s[2] - '0');
AjK 0:0a841b89d614 255 min = ( (s[3] - '0') * 10) + s[4] - '0';
AjK 0:0a841b89d614 256 sec = ( ((s[6] - '0') * 1000) + ((s[7] - '0') * 100) + ((s[8] - '0') * 10) + (s[9] - '0'));
AjK 0:0a841b89d614 257 fsec = (double)((double)sec /10000.0);
AjK 0:0a841b89d614 258 val = (double)deg + ((double)((double)min/60.0)) + (fsec/60.0);
AjK 0:0a841b89d614 259 return val;
AjK 0:0a841b89d614 260 }
AjK 0:0a841b89d614 261 }
AjK 0:0a841b89d614 262
AjK 0:0a841b89d614 263 /** gps_init
AjK 0:0a841b89d614 264 */
AjK 0:0a841b89d614 265 void gps_init(void) {
AjK 0:0a841b89d614 266 int i;
AjK 0:0a841b89d614 267
AjK 0:0a841b89d614 268 DEBUG_INIT_START;
AjK 0:0a841b89d614 269
AjK 0:0a841b89d614 270 /* Set the time to a known starting point in the past. */
AjK 0:0a841b89d614 271 the_time.year = 2000;
AjK 0:0a841b89d614 272 the_time.month = 1;
AjK 0:0a841b89d614 273 the_time.day = 1;
AjK 0:0a841b89d614 274 the_time.hour = 0;
AjK 0:0a841b89d614 275 the_time.minute = 0;
AjK 0:0a841b89d614 276 the_time.second = 0;
AjK 0:0a841b89d614 277 the_time.tenth = 0;
AjK 0:0a841b89d614 278 the_time.hundreth = 0;
AjK 0:0a841b89d614 279 the_time.is_valid = 0;
AjK 0:0a841b89d614 280 the_time.prev_valid = 0;
AjK 0:0a841b89d614 281
AjK 0:0a841b89d614 282 memset(&the_location, 0, sizeof(GPS_LOCATION_RAW));
AjK 0:0a841b89d614 283
AjK 0:0a841b89d614 284 /* Initial condition. */
AjK 0:0a841b89d614 285 time_updated = 0;
AjK 0:0a841b89d614 286
AjK 0:0a841b89d614 287 /* Zero out the moving average filter. */
AjK 0:0a841b89d614 288 lat_average = 0.;
AjK 0:0a841b89d614 289 lon_average = 0.;
AjK 0:0a841b89d614 290 history_in_index = 0;
AjK 0:0a841b89d614 291 history_complete = 0;
AjK 0:0a841b89d614 292 for(i = 0; i < GPS_HISTORY_SIZE; i++) {
AjK 0:0a841b89d614 293 lat_history[i] = 0.;
AjK 0:0a841b89d614 294 lon_history[i] = 0.;
AjK 0:0a841b89d614 295 }
AjK 0:0a841b89d614 296
AjK 0:0a841b89d614 297 lat_acc_average = 0.;
AjK 0:0a841b89d614 298 lon_acc_average = 0.;
AjK 0:0a841b89d614 299 cnt_acc_average = 0.;
AjK 0:0a841b89d614 300
AjK 0:0a841b89d614 301 /* Init the active buffer and the serial in pointer. */
AjK 0:0a841b89d614 302 active_buffer = active_buffer_in = 0;
AjK 0:0a841b89d614 303
AjK 0:0a841b89d614 304 /* Flag the passive buffer is not ready. The passive buffer
AjK 0:0a841b89d614 305 is the opposite of the active buffer. When the serial irq
AjK 0:0a841b89d614 306 system detects the end of a NEMA message it automatically
AjK 0:0a841b89d614 307 switches buffers and sets passive_buffer_ready non-zero to
AjK 0:0a841b89d614 308 indicate it's just finished dumping data into it. */
AjK 0:0a841b89d614 309 passive_buffer_ready = 0;
AjK 0:0a841b89d614 310
AjK 0:0a841b89d614 311 /* Updated to non-zero after a new location packet is received. */
AjK 0:0a841b89d614 312 have_new_location = 0;
AjK 0:0a841b89d614 313
AjK 0:0a841b89d614 314 /* Setup the 0.01second timer. */
AjK 0:0a841b89d614 315 rit_timer_set_reload(RIT_TIMER_CB_GPS, 10); /* Recurring reload. */
AjK 0:0a841b89d614 316 rit_timer_set_counter(RIT_TIMER_CB_GPS, 10); /* Start timer. */
AjK 0:0a841b89d614 317
AjK 0:0a841b89d614 318 DEBUG_INIT_END;
AjK 0:0a841b89d614 319
AjK 0:0a841b89d614 320 Uart1_init();
AjK 0:0a841b89d614 321 }
AjK 0:0a841b89d614 322
AjK 0:0a841b89d614 323 /** gps_get_time
AjK 0:0a841b89d614 324 *
AjK 0:0a841b89d614 325 * Copies our internal time data structure to a buffer supplied by the caller.
AjK 0:0a841b89d614 326 *
AjK 0:0a841b89d614 327 * Note, the update flag is set to non-zero by the interrupt routines when an
AjK 0:0a841b89d614 328 * update occurs. The loop is to test if an update occured while the copy was
AjK 0:0a841b89d614 329 * in progress. If it did, do the copy again as it's most likely corrupted the
AjK 0:0a841b89d614 330 * orginal copy operation.
AjK 0:0a841b89d614 331 *
AjK 0:0a841b89d614 332 * @param GPS_TIME *q A pointer to the GPS_TIME data structure to copy to.
AjK 0:0a841b89d614 333 * @return GPS_TIME * The supplied pointer.
AjK 0:0a841b89d614 334 */
AjK 0:0a841b89d614 335 GPS_TIME *gps_get_time(GPS_TIME *q) {
AjK 0:0a841b89d614 336
AjK 0:0a841b89d614 337 do {
AjK 0:0a841b89d614 338 time_updated = 0;
AjK 0:0a841b89d614 339 memcpy(q, &the_time, sizeof(GPS_TIME));
AjK 0:0a841b89d614 340 } while (time_updated != 0);
AjK 0:0a841b89d614 341
AjK 0:0a841b89d614 342 return q;
AjK 0:0a841b89d614 343 }
AjK 0:0a841b89d614 344
AjK 0:0a841b89d614 345 /** gps_get_location_raw
AjK 0:0a841b89d614 346 *
AjK 0:0a841b89d614 347 * Copies our internal location data structure to a buffer supplied by the caller.
AjK 0:0a841b89d614 348 *
AjK 0:0a841b89d614 349 * Note, the update flag is set to non-zero by the interrupt routines when an
AjK 0:0a841b89d614 350 * update occurs. The loop is to test if an update occured while the copy was
AjK 0:0a841b89d614 351 * in progress. If it did, do the copy again as it's most likely corrupted the
AjK 0:0a841b89d614 352 * orginal copy operation.
AjK 0:0a841b89d614 353 *
AjK 0:0a841b89d614 354 * @param GPS_LOCATION_RAW *q A pointer to the GPS_LOCATION_RAW data structure to copy to.
AjK 0:0a841b89d614 355 * @return GPS_LOCATION_RAW * The supplied pointer.
AjK 0:0a841b89d614 356 */
AjK 0:0a841b89d614 357 GPS_LOCATION_RAW *gps_get_location_raw(GPS_LOCATION_RAW *q) {
AjK 0:0a841b89d614 358
AjK 0:0a841b89d614 359 do {
AjK 0:0a841b89d614 360 location_updated = 0;
AjK 0:0a841b89d614 361 memcpy(q, &the_location, sizeof(GPS_LOCATION_RAW));
AjK 0:0a841b89d614 362 } while (location_updated != 0);
AjK 0:0a841b89d614 363
AjK 0:0a841b89d614 364 return q;
AjK 0:0a841b89d614 365 }
AjK 0:0a841b89d614 366
AjK 0:0a841b89d614 367 /** gps_get_location_average
AjK 0:0a841b89d614 368 *
AjK 0:0a841b89d614 369 * Places the current average location into the supplied struct buffer.
AjK 0:0a841b89d614 370 * The caller is responsible for allocating the buffer storage space.
AjK 0:0a841b89d614 371 *
AjK 0:0a841b89d614 372 * Note, the update flag is set to non-zero by the interrupt routines when an
AjK 0:0a841b89d614 373 * update occurs. The loop is to test if an update occured while the copy was
AjK 0:0a841b89d614 374 * in progress. If it did, do the copy again as it's most likely corrupted the
AjK 0:0a841b89d614 375 * orginal copy operation.
AjK 0:0a841b89d614 376 *
AjK 0:0a841b89d614 377 * @param GPS_LOCATION_AVERAGE *q A pointer to the struct buffer to write data to.
AjK 0:0a841b89d614 378 * @return GPS_LOCATION_AVERAGE * The supplied pointer returned.
AjK 0:0a841b89d614 379 */
AjK 0:0a841b89d614 380 GPS_LOCATION_AVERAGE *gps_get_location_average(GPS_LOCATION_AVERAGE *q) {
AjK 0:0a841b89d614 381 char **p = NULL;
AjK 0:0a841b89d614 382
AjK 0:0a841b89d614 383 do {
AjK 0:0a841b89d614 384 location_updated = 0;
AjK 0:0a841b89d614 385 q->north_south = the_location.north_south;
AjK 0:0a841b89d614 386 q->latitude = lat_average;
AjK 0:0a841b89d614 387 q->east_west = the_location.east_west;
AjK 0:0a841b89d614 388 q->longitude = lon_average;
AjK 0:0a841b89d614 389 q->height = strtod(the_location.alt, p);
AjK 0:0a841b89d614 390 q->sats = the_location.sats;
AjK 0:0a841b89d614 391 q->is_valid = the_location.is_valid;
AjK 0:0a841b89d614 392 } while (location_updated != 0);
AjK 0:0a841b89d614 393
AjK 0:0a841b89d614 394 /* Test the values to ensure the data is valid. */
AjK 0:0a841b89d614 395 if (isnan(q->latitude) || isnan(q->longitude) || isnan(q->height)) {
AjK 0:0a841b89d614 396 q->is_valid = 0;
AjK 0:0a841b89d614 397 }
AjK 0:0a841b89d614 398
AjK 0:0a841b89d614 399 return q;
AjK 0:0a841b89d614 400 }
AjK 0:0a841b89d614 401
AjK 0:0a841b89d614 402 /** gps_julian_day_number
AjK 0:0a841b89d614 403 *
AjK 0:0a841b89d614 404 * Gets the Julian Day Number from the supplied time reference passed.
AjK 0:0a841b89d614 405 * http://en.wikipedia.org/wiki/Julian_day#Converting_Gregorian_calendar_date_to_Julian_Day_Number
AjK 0:0a841b89d614 406 *
AjK 0:0a841b89d614 407 * @param GPS_TIME *t A pointer to a time data structure.
AjK 0:0a841b89d614 408 * @return double The Julian Day Number.
AjK 0:0a841b89d614 409 */
AjK 0:0a841b89d614 410 double gps_julian_day_number(GPS_TIME *t) {
AjK 0:0a841b89d614 411 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:0a841b89d614 412
AjK 0:0a841b89d614 413 /* Not sure why yet but the calculation on the Wikipedia site returns a value that
AjK 0:0a841b89d614 414 is 0.5 too big. */
AjK 0:0a841b89d614 415 return wikipedia_jdn;
AjK 0:0a841b89d614 416 }
AjK 0:0a841b89d614 417
AjK 0:0a841b89d614 418 /** gps_julian_date
AjK 0:0a841b89d614 419 *
AjK 0:0a841b89d614 420 * Find the Julian Date based on the supplied args.
AjK 0:0a841b89d614 421 *
AjK 0:0a841b89d614 422 * @param GPS_TIME *t A pointer to a time data structure.
AjK 0:0a841b89d614 423 * @return double The Julian Date.
AjK 0:0a841b89d614 424 */
AjK 0:0a841b89d614 425 double gps_julian_date(GPS_TIME *t) {
AjK 0:0a841b89d614 426 double hour, minute, second, jd;
AjK 0:0a841b89d614 427 hour = (double)t->hour;
AjK 0:0a841b89d614 428 minute = (double)t->minute;
AjK 0:0a841b89d614 429 second = (double)t->second + ((double)t->tenth / 10.) + ((double)t->hundreth / 100.);
AjK 0:0a841b89d614 430 /* Wiki fix, see above. */
AjK 0:0a841b89d614 431 jd = gps_julian_day_number(t) - 0.5 +
AjK 0:0a841b89d614 432 ((hour - 12.) / 24.) +
AjK 0:0a841b89d614 433 (minute / 1440.) +
AjK 0:0a841b89d614 434 (second / 86400.);
AjK 0:0a841b89d614 435
AjK 0:0a841b89d614 436 return jd;
AjK 0:0a841b89d614 437 }
AjK 0:0a841b89d614 438
AjK 0:0a841b89d614 439 /** gps_siderealDegrees_by_jd
AjK 0:0a841b89d614 440 *
AjK 0:0a841b89d614 441 * Calculate the sidereal degree angle based on the
AjK 0:0a841b89d614 442 * Julian Date supplied.
AjK 0:0a841b89d614 443 *
AjK 0:0a841b89d614 444 * @param double jd Julian Date.
AjK 0:0a841b89d614 445 * @return The sidereal angle in degrees.
AjK 0:0a841b89d614 446 */
AjK 0:0a841b89d614 447 double gps_siderealDegrees_by_jd(double jd) {
AjK 0:0a841b89d614 448 double sidereal, gmst, lmst, mul;
AjK 0:0a841b89d614 449 double T = jd - 2451545.0;
AjK 0:0a841b89d614 450 double T1 = T / 36525.0;
AjK 0:0a841b89d614 451 double T2 = T1 * T1;
AjK 0:0a841b89d614 452 double T3 = T2 * T1;
AjK 0:0a841b89d614 453
AjK 0:0a841b89d614 454 /* Calculate gmst angle. */
AjK 0:0a841b89d614 455 sidereal = 280.46061837 + (360.98564736629 * T) + (0.000387933 * T2) - (T3 / 38710000.0);
AjK 0:0a841b89d614 456
AjK 0:0a841b89d614 457 /* Convert to degrees. */
AjK 0:0a841b89d614 458 sidereal = fmod(sidereal, 360.0);
AjK 0:0a841b89d614 459 if (sidereal < 0.0) sidereal += 360.0;
AjK 0:0a841b89d614 460
AjK 0:0a841b89d614 461 mul = (the_location.east_west == 'W') ? -1.0 : 1.0;
AjK 0:0a841b89d614 462
AjK 0:0a841b89d614 463 gmst = sidereal;
AjK 0:0a841b89d614 464 lmst = gmst + (lon_average * mul);
AjK 0:0a841b89d614 465 return lmst;
AjK 0:0a841b89d614 466 }
AjK 0:0a841b89d614 467
AjK 0:0a841b89d614 468 /** gps_siderealDegrees_by_time
AjK 0:0a841b89d614 469 *
AjK 0:0a841b89d614 470 * Calculate the sidereal degree angle based on the
AjK 0:0a841b89d614 471 * time data structure supplied.
AjK 0:0a841b89d614 472 *
AjK 0:0a841b89d614 473 * @param GPS_TIME *t A pointer to the time structure.
AjK 0:0a841b89d614 474 * @return The sidereal angle in degrees.
AjK 0:0a841b89d614 475 */
AjK 0:0a841b89d614 476 double gps_siderealDegrees_by_time(GPS_TIME *t) {
AjK 0:0a841b89d614 477 GPS_TIME temp;
AjK 0:0a841b89d614 478 if (t == (GPS_TIME *)NULL) {
AjK 0:0a841b89d614 479 t = &temp;
AjK 0:0a841b89d614 480 gps_get_time(t);
AjK 0:0a841b89d614 481 }
AjK 0:0a841b89d614 482 return gps_siderealDegrees_by_jd(gps_julian_date(t));
AjK 0:0a841b89d614 483 }
AjK 0:0a841b89d614 484
AjK 0:0a841b89d614 485 /** gps_siderealHA_by_jd
AjK 0:0a841b89d614 486 *
AjK 0:0a841b89d614 487 * Calculate the HA (hour angle) based on the supplied Julian Date.
AjK 0:0a841b89d614 488 *
AjK 0:0a841b89d614 489 * @param double jd The Julian Date.
AjK 0:0a841b89d614 490 * @return double The Hour Angle.
AjK 0:0a841b89d614 491 */
AjK 0:0a841b89d614 492 double gps_siderealHA_by_jd(double jd) {
AjK 0:0a841b89d614 493 double lmst = gps_siderealDegrees_by_jd(jd);
AjK 0:0a841b89d614 494 return lmst / 360.0 * 24.0;
AjK 0:0a841b89d614 495 }
AjK 0:0a841b89d614 496
AjK 0:0a841b89d614 497 /** gps_siderealHA_by_time
AjK 0:0a841b89d614 498 *
AjK 0:0a841b89d614 499 * Calculate the HA (hour angle) based on the supplied time data structure.
AjK 0:0a841b89d614 500 *
AjK 0:0a841b89d614 501 * @param GPS_TIME *t The time data structure.
AjK 0:0a841b89d614 502 * @return double The Hour Angle.
AjK 0:0a841b89d614 503 */
AjK 0:0a841b89d614 504 double gps_siderealHA_by_time(GPS_TIME *t) {
AjK 0:0a841b89d614 505 double lmst = gps_siderealDegrees_by_time(t);
AjK 0:0a841b89d614 506 return lmst / 360.0 * 24.0;
AjK 0:0a841b89d614 507 }
AjK 0:0a841b89d614 508
AjK 0:0a841b89d614 509 /** _gps_inc_time
AjK 0:0a841b89d614 510 *
AjK 0:0a841b89d614 511 * Used to increment the time structure by 0.01sec.
AjK 0:0a841b89d614 512 * Called by the RIT timer callback.
AjK 0:0a841b89d614 513 *
AjK 0:0a841b89d614 514 * @see gpioirq.c
AjK 0:0a841b89d614 515 * @param int t_index The timer's index number (handle).
AjK 0:0a841b89d614 516 */
AjK 0:0a841b89d614 517 void _gps_timer_tick_cb(int t_index) {
AjK 0:0a841b89d614 518
AjK 0:0a841b89d614 519 /* We use x so that the_time.hundreth can never be 10 as I have noticed
AjK 0:0a841b89d614 520 occasionally between the ++ and the == 10 test an interrupt can occur
AjK 0:0a841b89d614 521 and then the_time.hundreth contains an invalid value. So using x to do
AjK 0:0a841b89d614 522 the ++ and ==10 test means the_time.hundreth can never itself be 10.
AjK 0:0a841b89d614 523 We reuse x on the tenths for a similar reason. */
AjK 0:0a841b89d614 524 char x = the_time.hundreth;
AjK 0:0a841b89d614 525 x++;
AjK 0:0a841b89d614 526
AjK 0:0a841b89d614 527 if (x == 10) {
AjK 0:0a841b89d614 528 the_time.hundreth = 0;
AjK 0:0a841b89d614 529 x = the_time.tenth + 1;
AjK 0:0a841b89d614 530 if (x < 10) {
AjK 0:0a841b89d614 531 the_time.tenth = x;
AjK 0:0a841b89d614 532 time_updated = 1;
AjK 0:0a841b89d614 533 }
AjK 0:0a841b89d614 534 }
AjK 0:0a841b89d614 535 else {
AjK 0:0a841b89d614 536 the_time.hundreth = x;
AjK 0:0a841b89d614 537 time_updated = 1;
AjK 0:0a841b89d614 538 }
AjK 0:0a841b89d614 539 }
AjK 0:0a841b89d614 540
AjK 0:0a841b89d614 541 /** _gps_pps_alive_cb
AjK 0:0a841b89d614 542 *
AjK 0:0a841b89d614 543 * Timeout that goes off if the GPS 1PPS signal doesn't
AjK 0:0a841b89d614 544 * fire within 1.5seconds telling us that the GPS isn't
AjK 0:0a841b89d614 545 * connected. Not currently used.
AjK 0:0a841b89d614 546 */
AjK 0:0a841b89d614 547 void _gps_pps_alive_cb(int index) {
AjK 0:0a841b89d614 548 the_time.is_valid = 0;
AjK 0:0a841b89d614 549 }
AjK 0:0a841b89d614 550
AjK 0:0a841b89d614 551 /** gps_pps_fall
AjK 0:0a841b89d614 552 *
AjK 0:0a841b89d614 553 * Increments the seconds. Called by the GPS 1PP callback interrupt.
AjK 0:0a841b89d614 554 *
AjK 0:0a841b89d614 555 * Note, some GPS modules, including the one used in this design,
AjK 0:0a841b89d614 556 * provide a 1PPS signal. However, it's almost always positive logic
AjK 0:0a841b89d614 557 * and it doesn't interface directly to an Mbed pin/interrupt. So we
AjK 0:0a841b89d614 558 * have a simple FET that buffers the signal and in so doing it becomes
AjK 0:0a841b89d614 559 * an active low signal. Hence why this is a falling edge interrupt.
AjK 0:0a841b89d614 560 *
AjK 0:0a841b89d614 561 * @see gpioirq.c
AjK 0:0a841b89d614 562 */
AjK 0:0a841b89d614 563 void gps_pps_fall(void) {
AjK 0:0a841b89d614 564 the_time.hundreth = 0;
AjK 0:0a841b89d614 565 the_time.tenth = 0;
AjK 0:0a841b89d614 566 _gps_time_inc(&the_time);
AjK 0:0a841b89d614 567 }
AjK 0:0a841b89d614 568
AjK 0:0a841b89d614 569 /** gps_date_inc
AjK 0:0a841b89d614 570 *
AjK 0:0a841b89d614 571 * Increment the time.
AjK 0:0a841b89d614 572 *
AjK 0:0a841b89d614 573 * @param GPS_TIME *q Pointer the data struct holding the time.
AjK 0:0a841b89d614 574 */
AjK 0:0a841b89d614 575 void _gps_time_inc(GPS_TIME *q) {
AjK 0:0a841b89d614 576
AjK 0:0a841b89d614 577 time_updated = 1;
AjK 0:0a841b89d614 578
AjK 0:0a841b89d614 579 q->second++;
AjK 0:0a841b89d614 580 if (q->second == 60) {
AjK 0:0a841b89d614 581 q->second = 0;
AjK 0:0a841b89d614 582 q->minute++;
AjK 0:0a841b89d614 583 if (q->minute == 60) {
AjK 0:0a841b89d614 584 q->minute = 0;
AjK 0:0a841b89d614 585 q->hour++;
AjK 0:0a841b89d614 586 if (q->hour == 24) {
AjK 0:0a841b89d614 587 q->hour = 0;
AjK 0:0a841b89d614 588 _gps_date_inc(q);
AjK 0:0a841b89d614 589 }
AjK 0:0a841b89d614 590 }
AjK 0:0a841b89d614 591 }
AjK 0:0a841b89d614 592 }
AjK 0:0a841b89d614 593
AjK 0:0a841b89d614 594 /** _gps_date_inc
AjK 0:0a841b89d614 595 *
AjK 0:0a841b89d614 596 * Increment the date.
AjK 0:0a841b89d614 597 *
AjK 0:0a841b89d614 598 * @param GPS_TIME *q Pointer the data struct holding the time.
AjK 0:0a841b89d614 599 */
AjK 0:0a841b89d614 600 void _gps_date_inc(GPS_TIME *q) {
AjK 0:0a841b89d614 601 const int days[12] = { 31,28,31,30,31,30,31,31,30,31,30,31 } ;
AjK 0:0a841b89d614 602
AjK 0:0a841b89d614 603 /* Handle February leap year. */
AjK 0:0a841b89d614 604 int leap_year = ((the_time.year % 4 == 0 && the_time.year % 100 != 0) || the_time.year % 400 == 0) ? 1 : 0;
AjK 0:0a841b89d614 605 int days_this_month = days[q->month - 1];
AjK 0:0a841b89d614 606 if (q->month == 2 && leap_year) days_this_month++;
AjK 0:0a841b89d614 607
AjK 0:0a841b89d614 608 q->day++;
AjK 0:0a841b89d614 609 if (q->day > days_this_month) {
AjK 0:0a841b89d614 610 q->day = 1;
AjK 0:0a841b89d614 611 q->month++;
AjK 0:0a841b89d614 612 if (q->month == 13) {
AjK 0:0a841b89d614 613 q->year++;
AjK 0:0a841b89d614 614 }
AjK 0:0a841b89d614 615 }
AjK 0:0a841b89d614 616 }
AjK 0:0a841b89d614 617
AjK 0:0a841b89d614 618 /* UART1 functions. */
AjK 0:0a841b89d614 619
AjK 0:0a841b89d614 620 extern "C" void UART1_IRQHandler(void) __irq {
AjK 0:0a841b89d614 621 volatile uint32_t iir;
AjK 0:0a841b89d614 622 volatile char c;
AjK 0:0a841b89d614 623
AjK 0:0a841b89d614 624 iir = LPC_UART1->IIR;
AjK 0:0a841b89d614 625
AjK 0:0a841b89d614 626 if (iir & 0x1) return;
AjK 0:0a841b89d614 627
AjK 0:0a841b89d614 628 /* Do we have a serial character(s) in the fifo? */
AjK 0:0a841b89d614 629 if (UART_RX_INTERRUPT) {
AjK 0:0a841b89d614 630 while (UART1_FIFO_NOT_EMPTY) {
AjK 0:0a841b89d614 631 c = UART1_GETC;
AjK 0:0a841b89d614 632 uart1_buffer[active_buffer][active_buffer_in++] = c;
AjK 0:0a841b89d614 633 active_buffer_in &= (GPS_BUFFER_SIZE - 1);
AjK 0:0a841b89d614 634 if (c == '\n') {
AjK 0:0a841b89d614 635 /* Swap buffers and clean it out. */
AjK 0:0a841b89d614 636 active_buffer = active_buffer == 0 ? 1 : 0;
AjK 0:0a841b89d614 637 memset(uart1_buffer[active_buffer], 0, GPS_BUFFER_SIZE);
AjK 0:0a841b89d614 638 active_buffer_in = 0;
AjK 0:0a841b89d614 639 passive_buffer_ready = 1;
AjK 0:0a841b89d614 640 }
AjK 0:0a841b89d614 641 }
AjK 0:0a841b89d614 642 }
AjK 0:0a841b89d614 643 }
AjK 0:0a841b89d614 644
AjK 0:0a841b89d614 645 /** Uart1_init
AjK 0:0a841b89d614 646 */
AjK 0:0a841b89d614 647 void Uart1_init(void) {
AjK 0:0a841b89d614 648
AjK 0:0a841b89d614 649 DEBUG_INIT_START;
AjK 0:0a841b89d614 650
AjK 0:0a841b89d614 651 LPC_SC->PCONP |= (1UL << 4);
AjK 0:0a841b89d614 652 LPC_SC->PCLKSEL0 &= ~(3UL << 8);
AjK 0:0a841b89d614 653 LPC_SC->PCLKSEL0 |= (1UL << 8);
AjK 0:0a841b89d614 654 LPC_PINCON->PINSEL4 &= ~(3UL << 2); /* TXD1 not used. See SSP0_init() in max7456.c */
AjK 0:0a841b89d614 655 LPC_PINCON->PINSEL4 |= (2UL << 2); /* TXD1 not used. See SSP0_init() in max7456.c */
AjK 0:0a841b89d614 656 LPC_UART1->LCR = 0x83;
AjK 0:0a841b89d614 657 LPC_UART1->DLL = 0x71;
AjK 0:0a841b89d614 658 LPC_UART1->DLM = 0x02;
AjK 0:0a841b89d614 659 LPC_UART1->LCR = 0x03;
AjK 0:0a841b89d614 660 LPC_UART1->FCR = 0x07;
AjK 0:0a841b89d614 661
AjK 0:0a841b89d614 662 NVIC_SetVector(UART1_IRQn, (uint32_t)UART1_IRQHandler);
AjK 0:0a841b89d614 663 NVIC_EnableIRQ(UART1_IRQn);
AjK 0:0a841b89d614 664
AjK 0:0a841b89d614 665 /* Enable the RDA interrupt. */
AjK 0:0a841b89d614 666 LPC_UART1->IER = 0x01;
AjK 0:0a841b89d614 667
AjK 0:0a841b89d614 668 DEBUG_INIT_END;
AjK 0:0a841b89d614 669 }
AjK 0:0a841b89d614 670