driver/gps/gps.c
| Line | Branch | Exec | Source |
|---|---|---|---|
| 1 | /******************************************************************************* | ||
| 2 | * | ||
| 3 | * FILE: | ||
| 4 | * gps.c | ||
| 5 | * | ||
| 6 | * DESCRIPTION: | ||
| 7 | * Contains API functions for GPS | ||
| 8 | * | ||
| 9 | * COPYRIGHT: | ||
| 10 | * Copyright (c) 2025 Sun Devil Rocketry. | ||
| 11 | * All rights reserved. | ||
| 12 | * | ||
| 13 | * This software is licensed under terms that can be found in the LICENSE | ||
| 14 | * file in the root directory of this software component. | ||
| 15 | * If no LICENSE file comes with this software, it is covered under the | ||
| 16 | * BSD-3-Clause. | ||
| 17 | * | ||
| 18 | * https://opensource.org/license/bsd-3-clause | ||
| 19 | * | ||
| 20 | *******************************************************************************/ | ||
| 21 | |||
| 22 | |||
| 23 | /*------------------------------------------------------------------------------ | ||
| 24 | Standard Includes | ||
| 25 | ------------------------------------------------------------------------------*/ | ||
| 26 | |||
| 27 | |||
| 28 | /*------------------------------------------------------------------------------ | ||
| 29 | MCU Pins | ||
| 30 | ------------------------------------------------------------------------------*/ | ||
| 31 | #if defined( FLIGHT_COMPUTER ) | ||
| 32 | #include "sdr_pin_defines_A0002.h" | ||
| 33 | #include "stm32h7xx_hal.h" | ||
| 34 | #elif defined( ENGINE_CONTROLLER ) | ||
| 35 | #include "sdr_pin_defines_L0002.h" | ||
| 36 | #elif defined( VALVE_CONTROLLER ) | ||
| 37 | #include "sdr_pin_defines_L0005.h" | ||
| 38 | #elif defined( GROUND_STATION ) | ||
| 39 | #include "sdr_pin_defines_A0005.h" | ||
| 40 | #elif defined( FLIGHT_COMPUTER_LITE ) | ||
| 41 | #include "sdr_pin_defines_A0007.h" | ||
| 42 | #elif defined( A0010 ) | ||
| 43 | #include "sdr_pin_defines_A0010.h" | ||
| 44 | #endif | ||
| 45 | |||
| 46 | |||
| 47 | /*------------------------------------------------------------------------------ | ||
| 48 | Project Includes | ||
| 49 | ------------------------------------------------------------------------------*/ | ||
| 50 | #include "main.h" | ||
| 51 | #include "gps.h" | ||
| 52 | #include <string.h> | ||
| 53 | #include <stdlib.h> | ||
| 54 | #include <stdio.h> | ||
| 55 | #include <stdint.h> | ||
| 56 | |||
| 57 | /*------------------------------------------------------------------------------ | ||
| 58 | Preprocesor Directives | ||
| 59 | ------------------------------------------------------------------------------*/ | ||
| 60 | |||
| 61 | /*------------------------------------------------------------------------------ | ||
| 62 | Internal function prototypes | ||
| 63 | ------------------------------------------------------------------------------*/ | ||
| 64 | static GPS_NMEA_MSG_TYPE parse_token | ||
| 65 | ( | ||
| 66 | char* nmea_token | ||
| 67 | ); | ||
| 68 | |||
| 69 | /*------------------------------------------------------------------------------ | ||
| 70 | Local Variables | ||
| 71 | ------------------------------------------------------------------------------*/ | ||
| 72 | static GPS_DATA gps_last_valid_rmc_data; | ||
| 73 | static GPS_DATA gps_last_valid_gll_data; | ||
| 74 | |||
| 75 | /*------------------------------------------------------------------------------ | ||
| 76 | Procedures | ||
| 77 | ------------------------------------------------------------------------------*/ | ||
| 78 | |||
| 79 | |||
| 80 | /******************************************************************************* | ||
| 81 | * * | ||
| 82 | * PROCEDURE: * | ||
| 83 | * gps_transmit * | ||
| 84 | * * | ||
| 85 | * DESCRIPTION: * | ||
| 86 | * transmits a specified number of bytes over USB * | ||
| 87 | * * | ||
| 88 | *******************************************************************************/ | ||
| 89 | 4 | GPS_STATUS gps_transmit | |
| 90 | ( | ||
| 91 | void* tx_data_ptr , /* Data to be sent */ | ||
| 92 | size_t tx_data_size, /* Size of transmit data */ | ||
| 93 | uint32_t timeout /* UART timeout */ | ||
| 94 | ) | ||
| 95 | { | ||
| 96 | /*------------------------------------------------------------------------------ | ||
| 97 | Local Variables | ||
| 98 | ------------------------------------------------------------------------------*/ | ||
| 99 | 4 | HAL_StatusTypeDef gps_status; | |
| 100 | |||
| 101 | |||
| 102 | /*------------------------------------------------------------------------------ | ||
| 103 | API Function Implementation | ||
| 104 | ------------------------------------------------------------------------------*/ | ||
| 105 | |||
| 106 | /* Transmit byte */ | ||
| 107 | 4 | gps_status = HAL_UART_Transmit( &( GPS_HUART ), | |
| 108 | tx_data_ptr , | ||
| 109 | tx_data_size , | ||
| 110 | timeout ); | ||
| 111 | |||
| 112 | /* Return HAL status */ | ||
| 113 | 4 | if ( gps_status != HAL_OK ) | |
| 114 | { | ||
| 115 | return gps_status; | ||
| 116 | } | ||
| 117 | else | ||
| 118 | { | ||
| 119 | 4 | return GPS_OK; | |
| 120 | } | ||
| 121 | |||
| 122 | } /* usb_transmit */ | ||
| 123 | |||
| 124 | |||
| 125 | /******************************************************************************* | ||
| 126 | * * | ||
| 127 | * PROCEDURE: * | ||
| 128 | * usb_recieve * | ||
| 129 | * * | ||
| 130 | * DESCRIPTION: * | ||
| 131 | * Receives bytes from the USB port * | ||
| 132 | * * | ||
| 133 | *******************************************************************************/ | ||
| 134 | 4 | GPS_STATUS gps_receive | |
| 135 | ( | ||
| 136 | void* rx_data_ptr , /* Buffer to export data to */ | ||
| 137 | size_t rx_data_size, /* Size of the data to be received */ | ||
| 138 | uint32_t timeout /* UART timeout */ | ||
| 139 | ) | ||
| 140 | { | ||
| 141 | /*------------------------------------------------------------------------------ | ||
| 142 | Local Variables | ||
| 143 | ------------------------------------------------------------------------------*/ | ||
| 144 | 4 | HAL_StatusTypeDef gps_status; | |
| 145 | |||
| 146 | |||
| 147 | /*------------------------------------------------------------------------------ | ||
| 148 | API Function Implementation | ||
| 149 | ------------------------------------------------------------------------------*/ | ||
| 150 | |||
| 151 | /* Transmit byte */ | ||
| 152 | 4 | gps_status = HAL_UART_Receive( &( GPS_HUART ), | |
| 153 | rx_data_ptr , | ||
| 154 | rx_data_size , | ||
| 155 | timeout ); | ||
| 156 | /* Return HAL status */ | ||
| 157 |
3/3✓ Branch 0 taken 1 time.
✓ Branch 1 taken 2 times.
✓ Branch 2 taken 1 time.
|
4 | switch ( gps_status ) |
| 158 | { | ||
| 159 | case HAL_TIMEOUT: | ||
| 160 | { | ||
| 161 | return GPS_TIMEOUT; | ||
| 162 | 1 | break; | |
| 163 | } | ||
| 164 | 1 | case HAL_OK: | |
| 165 | { | ||
| 166 | 1 | return GPS_OK; | |
| 167 | 2 | break; | |
| 168 | } | ||
| 169 | 2 | default: | |
| 170 | { | ||
| 171 | 2 | return GPS_FAIL; | |
| 172 | 4 | break; | |
| 173 | } | ||
| 174 | } | ||
| 175 | |||
| 176 | } /* usb_receive */ | ||
| 177 | |||
| 178 | |||
| 179 | /******************************************************************************* | ||
| 180 | * * | ||
| 181 | * PROCEDURE: * | ||
| 182 | * usb_recieve_IT * | ||
| 183 | * * | ||
| 184 | * DESCRIPTION: * | ||
| 185 | * Receives bytes from the USB port * | ||
| 186 | * * | ||
| 187 | *******************************************************************************/ | ||
| 188 | 126 | GPS_STATUS gps_receive_IT | |
| 189 | ( | ||
| 190 | uint8_t* rx_data_ptr , /* Buffer to export data to */ | ||
| 191 | size_t rx_data_size /* Size of the data to be received */ | ||
| 192 | ) | ||
| 193 | { | ||
| 194 | /*------------------------------------------------------------------------------ | ||
| 195 | Local Variables | ||
| 196 | ------------------------------------------------------------------------------*/ | ||
| 197 | 126 | HAL_StatusTypeDef gps_status; | |
| 198 | |||
| 199 | |||
| 200 | /*------------------------------------------------------------------------------ | ||
| 201 | API Function Implementation | ||
| 202 | ------------------------------------------------------------------------------*/ | ||
| 203 | |||
| 204 | /* Transmit byte */ | ||
| 205 | 126 | gps_status = HAL_UART_Receive_IT( &( GPS_HUART ), | |
| 206 | rx_data_ptr , | ||
| 207 | rx_data_size ); | ||
| 208 | |||
| 209 | /* Return HAL status */ | ||
| 210 |
3/3✓ Branch 0 taken 123 times.
✓ Branch 1 taken 2 times.
✓ Branch 2 taken 1 time.
|
126 | switch ( gps_status ) |
| 211 | { | ||
| 212 | case HAL_TIMEOUT: | ||
| 213 | { | ||
| 214 | return GPS_TIMEOUT; | ||
| 215 | 123 | break; | |
| 216 | } | ||
| 217 | 123 | case HAL_OK: | |
| 218 | { | ||
| 219 | 123 | return GPS_OK; | |
| 220 | 2 | break; | |
| 221 | } | ||
| 222 | 2 | default: | |
| 223 | { | ||
| 224 | 2 | return GPS_FAIL; | |
| 225 | 126 | break; | |
| 226 | } | ||
| 227 | } | ||
| 228 | |||
| 229 | } /* usb_receive_IT */ | ||
| 230 | |||
| 231 | /******************************************************************************* | ||
| 232 | * * | ||
| 233 | * PROCEDURE: * | ||
| 234 | * gps_mesg_validate * | ||
| 235 | * * | ||
| 236 | * DESCRIPTION: * | ||
| 237 | * Validate message returned from GPS * | ||
| 238 | * * | ||
| 239 | * TEST: * | ||
| 240 | * test_gps_mesg_validate provides coverage. If this function * | ||
| 241 | * is updated, make sure the test cases are updated to match. * | ||
| 242 | * * | ||
| 243 | *******************************************************************************/ | ||
| 244 | 127 | int gps_mesg_validate(char *nmeastr){ | |
| 245 | 127 | char check[3]; | |
| 246 | 127 | char checkcalcstr[3]; | |
| 247 | 127 | int i; | |
| 248 | 127 | int calculated_check; | |
| 249 | |||
| 250 | 127 | i=0; | |
| 251 | 127 | calculated_check=0; | |
| 252 | |||
| 253 | // check to ensure that the string starts with a $ | ||
| 254 |
2/2✓ Branch 0 taken 126 times.
✓ Branch 1 taken 1 time.
|
127 | if(nmeastr[i] == '$') |
| 255 | i++; | ||
| 256 | else | ||
| 257 | return 0; | ||
| 258 | |||
| 259 | //No NULL reached, 75 char largest possible NMEA message, no '*' reached | ||
| 260 |
4/4✓ Branch 0 taken 7165 times.
✓ Branch 1 taken 125 times.
✓ Branch 2 taken 7164 times.
✓ Branch 3 taken 1 time.
|
7290 | while((nmeastr[i] != 0) && (nmeastr[i] != '*') && (i < 75)){ |
| 261 | 7164 | calculated_check ^= nmeastr[i];// calculate the checksum | |
| 262 | 7164 | i++; | |
| 263 | } | ||
| 264 | |||
| 265 |
2/2✓ Branch 0 taken 125 times.
✓ Branch 1 taken 1 time.
|
126 | if(i >= 75){ |
| 266 | return 0;// the string was too long so return an error | ||
| 267 | } | ||
| 268 | |||
| 269 |
2/2✓ Branch 0 taken 124 times.
✓ Branch 1 taken 1 time.
|
125 | if (nmeastr[i] == '*'){ |
| 270 | 124 | check[0] = nmeastr[i+1]; //put hex chars in check string | |
| 271 | 124 | check[1] = nmeastr[i+2]; | |
| 272 | 124 | check[2] = 0; | |
| 273 | } | ||
| 274 | else | ||
| 275 | return 0;// no checksum separator found there for invalid | ||
| 276 | |||
| 277 |
1/2✓ Branch 0 taken 124 times.
✗ Branch 1 not taken.
|
124 | sprintf(checkcalcstr,"%02X",calculated_check); |
| 278 | 124 | return((checkcalcstr[0] == check[0]) | |
| 279 |
2/4✓ Branch 0 taken 124 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 124 times.
|
124 | && (checkcalcstr[1] == check[1])) ? 1 : 0 ; |
| 280 | } /*gps_mesg_validate*/ | ||
| 281 | |||
| 282 | /******************************************************************************* | ||
| 283 | * * | ||
| 284 | * PROCEDURE: * | ||
| 285 | * GPS_parse * | ||
| 286 | * * | ||
| 287 | * DESCRIPTION: * | ||
| 288 | * Convert raw NMEA string to usable data * | ||
| 289 | * * | ||
| 290 | * TEST: * | ||
| 291 | * test_GPS_parse provides coverage. If this function or its * | ||
| 292 | * helpers are updated, make sure the test cases are updated to match. * | ||
| 293 | * * | ||
| 294 | *******************************************************************************/ | ||
| 295 | 140 | void GPS_parse | |
| 296 | ( | ||
| 297 | GPS_DATA* gps_ptr, | ||
| 298 | char *GPSstrParse | ||
| 299 | ) | ||
| 300 | { | ||
| 301 | /* Get message type */ | ||
| 302 | 140 | char token[8]; // Needs to be 8 chars for memory alignment | |
| 303 |
5/5✓ Branch 0 taken 24 times.
✓ Branch 1 taken 58 times.
✓ Branch 2 taken 25 times.
✓ Branch 3 taken 22 times.
✓ Branch 4 taken 11 times.
|
140 | strncpy(token, GPSstrParse, 6); |
| 304 | 140 | token[6] = '\0'; | |
| 305 | 140 | int idx = 7; /* Skips "$GPXXX,"*/ | |
| 306 | |||
| 307 | 140 | GPS_NMEA_MSG_TYPE message_type = parse_token(token); | |
| 308 | |||
| 309 | /* Parse by message type */ | ||
| 310 |
5/5✓ Branch 0 taken 24 times.
✓ Branch 1 taken 58 times.
✓ Branch 2 taken 25 times.
✓ Branch 3 taken 22 times.
✓ Branch 4 taken 11 times.
|
140 | switch ( message_type ) |
| 311 | { | ||
| 312 | 24 | case NMEA_MSG_GGA: | |
| 313 | 24 | gps_ptr->utc_time = gps_string_to_float(GPSstrParse, &idx); | |
| 314 | 24 | gps_ptr->nmea_latitude = gps_string_to_float(GPSstrParse, &idx); | |
| 315 | 24 | gps_ptr->ns = gps_string_to_char(GPSstrParse, &idx); | |
| 316 | 24 | gps_ptr->nmea_longitude = gps_string_to_float(GPSstrParse, &idx); | |
| 317 | 24 | gps_ptr->ew = gps_string_to_char(GPSstrParse, &idx); | |
| 318 | 24 | gps_ptr->lock = (int)gps_string_to_float(GPSstrParse, &idx) + 0.5; | |
| 319 | 24 | gps_ptr->satelites = (int)(gps_string_to_float(GPSstrParse, &idx) + 0.5); // This is a decimal number. | |
| 320 | 24 | gps_ptr->hdop = gps_string_to_float(GPSstrParse, &idx); | |
| 321 | 24 | gps_ptr->msl_altitude = gps_string_to_float(GPSstrParse, &idx); | |
| 322 | 24 | gps_ptr->msl_units = gps_string_to_char(GPSstrParse, &idx); | |
| 323 | 24 | gps_conv_latitude_longitude( gps_ptr ); | |
| 324 | 24 | break; | |
| 325 | 58 | case NMEA_MSG_RMC: | |
| 326 | /* Parse data */ | ||
| 327 | { | ||
| 328 | 58 | float utc_time = gps_string_to_float(GPSstrParse, &idx); | |
| 329 | 58 | char rmc_status = gps_string_to_char(GPSstrParse, &idx); | |
| 330 | 58 | float nmea_latitude = gps_string_to_float(GPSstrParse, &idx); | |
| 331 | 58 | char ns = gps_string_to_char(GPSstrParse, &idx); | |
| 332 | 58 | float nmea_longitude = gps_string_to_float(GPSstrParse, &idx); | |
| 333 | 58 | char ew = gps_string_to_char(GPSstrParse, &idx); | |
| 334 | 58 | float speed_k = gps_string_to_float(GPSstrParse, &idx); | |
| 335 | 58 | float course_d = gps_string_to_float(GPSstrParse, &idx); | |
| 336 | 58 | int date = (int)(0.5 + gps_string_to_float(GPSstrParse, &idx)); | |
| 337 | |||
| 338 | /* Save status */ | ||
| 339 | 58 | gps_ptr->rmc_status = rmc_status; | |
| 340 | |||
| 341 | /* Save rest of data only if status is A: Active */ | ||
| 342 |
2/2✓ Branch 0 taken 56 times.
✓ Branch 1 taken 2 times.
|
58 | if ( rmc_status == 'A' ) |
| 343 | { | ||
| 344 | 56 | gps_ptr->utc_time = utc_time; | |
| 345 | 56 | gps_ptr->nmea_latitude = nmea_latitude; | |
| 346 | 56 | gps_ptr->ns = ns; | |
| 347 | 56 | gps_ptr->nmea_longitude = nmea_longitude; | |
| 348 | 56 | gps_ptr->ew = ew; | |
| 349 | 56 | gps_ptr->speed_k = speed_k; | |
| 350 | 56 | gps_ptr->course_d = course_d; | |
| 351 | 56 | gps_ptr->date = date; | |
| 352 | 56 | gps_conv_latitude_longitude( gps_ptr ); | |
| 353 | |||
| 354 | /* Update last valid data */ | ||
| 355 | 56 | gps_last_valid_rmc_data = *gps_ptr; | |
| 356 | } | ||
| 357 | /* Discard new data, use last valid data instead if the status is V: Void */ | ||
| 358 |
1/2✓ Branch 0 taken 2 times.
✗ Branch 1 not taken.
|
2 | else if ( rmc_status == 'V' ) |
| 359 | { | ||
| 360 | 2 | *gps_ptr = gps_last_valid_rmc_data; | |
| 361 | |||
| 362 | /* Re-save rmc_status since the previous statement may override it */ | ||
| 363 | 2 | gps_ptr->rmc_status = rmc_status; | |
| 364 | } | ||
| 365 | } | ||
| 366 | break; | ||
| 367 | 25 | case NMEA_MSG_GLL: | |
| 368 | { | ||
| 369 | /* Parse data */ | ||
| 370 | 25 | float nmea_latitude = gps_string_to_float(GPSstrParse, &idx); | |
| 371 | 25 | char ns = gps_string_to_char(GPSstrParse, &idx); | |
| 372 | 25 | float nmea_longitude = gps_string_to_float(GPSstrParse, &idx); | |
| 373 | 25 | char ew = gps_string_to_char(GPSstrParse, &idx); | |
| 374 | 25 | float utc_time = gps_string_to_float(GPSstrParse, &idx); | |
| 375 | 25 | char gll_status = gps_string_to_char(GPSstrParse, &idx); | |
| 376 | |||
| 377 | /* Store status */ | ||
| 378 | 25 | gps_ptr->gll_status = gll_status; | |
| 379 | |||
| 380 | /* Save rest of data only if status is A: Data Valid */ | ||
| 381 |
2/2✓ Branch 0 taken 22 times.
✓ Branch 1 taken 3 times.
|
25 | if (gll_status == 'A') |
| 382 | { | ||
| 383 | 22 | gps_ptr->nmea_latitude = nmea_latitude; | |
| 384 | 22 | gps_ptr->ns = ns; | |
| 385 | 22 | gps_ptr->nmea_longitude = nmea_longitude; | |
| 386 | 22 | gps_ptr->ew = ew; | |
| 387 | 22 | gps_ptr->utc_time = utc_time; | |
| 388 | 22 | gps_conv_latitude_longitude( gps_ptr ); | |
| 389 | |||
| 390 | 22 | gps_last_valid_gll_data = *gps_ptr; | |
| 391 | } | ||
| 392 |
2/2✓ Branch 0 taken 2 times.
✓ Branch 1 taken 1 time.
|
3 | else if (gll_status == 'V') |
| 393 | { | ||
| 394 | 2 | *gps_ptr = gps_last_valid_gll_data; | |
| 395 | |||
| 396 | /* Resave gll status since the previous statement may override it */ | ||
| 397 | 2 | gps_ptr->gll_status = gll_status; | |
| 398 | } | ||
| 399 | } | ||
| 400 | break; | ||
| 401 | 22 | case NMEA_MSG_VTG: | |
| 402 | 22 | gps_ptr->course_t = gps_string_to_float(GPSstrParse, &idx); | |
| 403 | 22 | gps_ptr->course_t_unit = gps_string_to_char(GPSstrParse, &idx); | |
| 404 | 22 | gps_ptr->course_m = gps_string_to_float(GPSstrParse, &idx); | |
| 405 | 22 | gps_ptr->course_m_unit = gps_string_to_char(GPSstrParse, &idx); | |
| 406 | 22 | gps_ptr->speed_k = gps_string_to_float(GPSstrParse, &idx); | |
| 407 | 22 | gps_ptr->speed_k_unit = gps_string_to_char(GPSstrParse, &idx); | |
| 408 | 22 | gps_ptr->speed_km = gps_string_to_float(GPSstrParse, &idx); | |
| 409 | 22 | gps_ptr->speed_km_unit = gps_string_to_char(GPSstrParse, &idx); | |
| 410 | 22 | break; | |
| 411 | default: | ||
| 412 | break; /* Ignore */ | ||
| 413 | } | ||
| 414 | 140 | } /* GPS_parse */ | |
| 415 | |||
| 416 | /******************************************************************************* | ||
| 417 | * * | ||
| 418 | * PROCEDURE: * | ||
| 419 | * gps_string_to_float * | ||
| 420 | * * | ||
| 421 | * DESCRIPTION: * | ||
| 422 | * Convert part of an NMEA string to a float * | ||
| 423 | * * | ||
| 424 | * TEST: * | ||
| 425 | * test_GPS_parse provides coverage. If this function is * | ||
| 426 | * updated, please re-run the test and update if necessary * | ||
| 427 | * * | ||
| 428 | *******************************************************************************/ | ||
| 429 | 679 | float gps_string_to_float(char *GPSstrParse, int* inputIdx) | |
| 430 | { | ||
| 431 | 679 | int idx = *inputIdx; | |
| 432 | 679 | char currChar = GPSstrParse[idx]; | |
| 433 | 679 | char tempstr[16]; | |
| 434 | 679 | int tempidx = 0; | |
| 435 |
2/2✓ Branch 0 taken 25 times.
✓ Branch 1 taken 654 times.
|
679 | if (GPSstrParse[idx] == ',') /* Checks if subsequent comma */ |
| 436 | { | ||
| 437 | 25 | *inputIdx = *inputIdx + 1; | |
| 438 | 25 | return 0.0f; /* null return */ | |
| 439 | } | ||
| 440 |
2/2✓ Branch 0 taken 4614 times.
✓ Branch 1 taken 654 times.
|
5268 | while (currChar != ',') |
| 441 | { | ||
| 442 |
1/2✓ Branch 0 taken 4614 times.
✗ Branch 1 not taken.
|
4614 | if (tempidx > 15) |
| 443 | { | ||
| 444 | /* ERROR HANDLING */ | ||
| 445 | // maybe just exit loop? and deal with bad data? or make it null. | ||
| 446 | return 0.0f; | ||
| 447 | } | ||
| 448 | 4614 | tempstr[tempidx] = GPSstrParse[idx]; | |
| 449 | 4614 | tempidx++; | |
| 450 | 4614 | idx++; | |
| 451 | 4614 | currChar = GPSstrParse[idx]; | |
| 452 | } | ||
| 453 | 654 | *inputIdx = idx + 1; | |
| 454 | 654 | tempstr[tempidx] = '\0'; | |
| 455 | 654 | return strtof(tempstr, NULL); | |
| 456 | } /* gps_string_to_float */ | ||
| 457 | |||
| 458 | /******************************************************************************* | ||
| 459 | * * | ||
| 460 | * PROCEDURE: * | ||
| 461 | * gps_string_to_char * | ||
| 462 | * * | ||
| 463 | * DESCRIPTION: * | ||
| 464 | * Get a char from an NMEA string if it exists * | ||
| 465 | * * | ||
| 466 | * TEST: * | ||
| 467 | * test_GPS_parse provides coverage. If this function is * | ||
| 468 | * updated, please re-run the test and update if necessary * | ||
| 469 | * * | ||
| 470 | *******************************************************************************/ | ||
| 471 | 409 | char gps_string_to_char(char *GPSstrParse, int* inputIdx) | |
| 472 | { | ||
| 473 | 409 | int idx = *inputIdx; | |
| 474 |
2/2✓ Branch 0 taken 3 times.
✓ Branch 1 taken 406 times.
|
409 | if (GPSstrParse[idx] == ',') /* Checks if subsequent comma */ |
| 475 | { | ||
| 476 | 3 | *inputIdx = *inputIdx + 1; | |
| 477 | 3 | return 0; /* null return */ | |
| 478 | } | ||
| 479 | else | ||
| 480 | { | ||
| 481 | 406 | *inputIdx = *inputIdx + 2; | |
| 482 | 406 | return GPSstrParse[idx]; | |
| 483 | } | ||
| 484 | } /* gps_string_to_char */ | ||
| 485 | |||
| 486 | /******************************************************************************* | ||
| 487 | * * | ||
| 488 | * PROCEDURE: * | ||
| 489 | * gps_conv_latitude_longitude * | ||
| 490 | * * | ||
| 491 | * DESCRIPTION: * | ||
| 492 | * Convert latitude and longitude from NMEA strings to the standard * | ||
| 493 | * format. * | ||
| 494 | * * | ||
| 495 | * TEST: * | ||
| 496 | * test_GPS_parse provides coverage. If this function is * | ||
| 497 | * updated, please re-run the test and update if necessary * | ||
| 498 | * * | ||
| 499 | *******************************************************************************/ | ||
| 500 | 102 | void gps_conv_latitude_longitude( GPS_DATA* data ) | |
| 501 | { | ||
| 502 | /* Initialize variables */ | ||
| 503 | 102 | uint8_t latitude_deg; /* Range: 0 to 90 */ | |
| 504 | 102 | uint8_t longitude_deg; /* Range: 0 to 180 */ | |
| 505 | 102 | float latitude; | |
| 506 | 102 | float longitude; | |
| 507 | |||
| 508 | /* Compute the degrees. Dividing by 100 drops the last two digits before the decimal. | ||
| 509 | Truncate -- do not round */ | ||
| 510 | 102 | latitude_deg = (uint8_t)(data->nmea_latitude / 100); | |
| 511 | 102 | longitude_deg = (uint8_t)(data->nmea_longitude / 100); | |
| 512 | |||
| 513 | /* Compute the minutes, divide by 100 to move after the decimal */ | ||
| 514 | 102 | latitude = (data->nmea_latitude - (100 * latitude_deg)) / 60; | |
| 515 | 102 | longitude = (data->nmea_longitude - (100 * longitude_deg)) / 60; | |
| 516 | |||
| 517 | /* Add the degrees */ | ||
| 518 | 102 | latitude += (float)latitude_deg; | |
| 519 | 102 | longitude += (float)longitude_deg; | |
| 520 | |||
| 521 | /* Compute the sign */ | ||
| 522 |
2/2✓ Branch 0 taken 1 time.
✓ Branch 1 taken 101 times.
|
102 | if (data->ns == 'S') { |
| 523 | 1 | latitude = -latitude; | |
| 524 | } | ||
| 525 |
2/2✓ Branch 0 taken 24 times.
✓ Branch 1 taken 78 times.
|
102 | if (data->ew == 'W') { |
| 526 | 24 | longitude = -longitude; | |
| 527 | } | ||
| 528 | |||
| 529 | /* Set the values in the struct */ | ||
| 530 | 102 | data->dec_latitude = latitude; | |
| 531 | 102 | data->dec_longitude = longitude; | |
| 532 | 102 | } /* gps_conv_latitude_longitude */ | |
| 533 | |||
| 534 | |||
| 535 | /*------------------------------------------------------------------------------ | ||
| 536 | Internal procedures | ||
| 537 | ------------------------------------------------------------------------------*/ | ||
| 538 | |||
| 539 | 140 | static GPS_NMEA_MSG_TYPE parse_token | |
| 540 | ( | ||
| 541 | char* nmea_token | ||
| 542 | ) | ||
| 543 | { | ||
| 544 | 140 | GPS_NMEA_MSG_TYPE message_type; | |
| 545 | |||
| 546 | /* Skip '$' and talker ID */ | ||
| 547 | 140 | char* sentence_id = nmea_token + 3; | |
| 548 |
2/2✓ Branch 0 taken 116 times.
✓ Branch 1 taken 24 times.
|
140 | if ( !strncmp(sentence_id, "GGA", 3) ) message_type = NMEA_MSG_GGA; |
| 549 |
2/2✓ Branch 0 taken 91 times.
✓ Branch 1 taken 25 times.
|
116 | else if ( !strncmp(sentence_id, "GLL", 3) ) message_type = NMEA_MSG_GLL; |
| 550 |
2/2✓ Branch 0 taken 80 times.
✓ Branch 1 taken 11 times.
|
91 | else if ( !strncmp(sentence_id, "GSA", 3) ) message_type = NMEA_MSG_GSA; |
| 551 |
1/2✓ Branch 0 taken 80 times.
✗ Branch 1 not taken.
|
80 | else if ( !strncmp(sentence_id, "GSV", 3) ) message_type = NMEA_MSG_GSV; |
| 552 |
2/2✓ Branch 0 taken 22 times.
✓ Branch 1 taken 58 times.
|
80 | else if ( !strncmp(sentence_id, "RMC", 3) ) message_type = NMEA_MSG_RMC; |
| 553 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 22 times.
|
22 | else if ( !strncmp(sentence_id, "VTG", 3) ) message_type = NMEA_MSG_VTG; |
| 554 | ✗ | else message_type = NMEA_MSG_UNSUPPORTED; | |
| 555 | |||
| 556 | 140 | return message_type; | |
| 557 | |||
| 558 | } | ||
| 559 | |||
| 560 | /******************************************************************************* | ||
| 561 | * END OF FILE * | ||
| 562 | *******************************************************************************/ | ||
| 563 |