Satellite Observers Workbench. NOT yet complete, just published for forum posters to \"cherry pick\" pieces of code as requiered as an example.
gps/gps.c@0:0a841b89d614, 2010-10-11 (annotated)
- 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?
User | Revision | Line number | New 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 |