diff options
author | Maximilien Cuony <maximilien@theglu.org> | 2016-06-02 22:00:22 +0200 |
---|---|---|
committer | Maximilien Cuony <maximilien@theglu.org> | 2016-06-02 22:00:22 +0200 |
commit | bbe4080e94308149b74dd9ccefddf95878eec5d0 (patch) | |
tree | db97785a48ff7267e263b9a55bed27b354e65925 /src/fsm | |
parent | 9069fc127e4f73041fbd1f66e4506fcf12418315 (diff) | |
download | glutte-o-matic-bbe4080e94308149b74dd9ccefddf95878eec5d0.tar.gz glutte-o-matic-bbe4080e94308149b74dd9ccefddf95878eec5d0.tar.bz2 glutte-o-matic-bbe4080e94308149b74dd9ccefddf95878eec5d0.zip |
Simulator: UART, Leds, begining of GPS
Diffstat (limited to 'src/fsm')
-rw-r--r-- | src/fsm/gps.c | 138 | ||||
-rw-r--r-- | src/fsm/gps.h | 46 | ||||
-rw-r--r-- | src/fsm/minmea.c | 572 | ||||
-rw-r--r-- | src/fsm/minmea.h | 234 |
4 files changed, 0 insertions, 990 deletions
diff --git a/src/fsm/gps.c b/src/fsm/gps.c deleted file mode 100644 index ea3e597..0000000 --- a/src/fsm/gps.c +++ /dev/null @@ -1,138 +0,0 @@ -/* - * The MIT License (MIT) - * - * Copyright (c) 2015 Matthias P. Braendli - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. -*/ - -#include "stm32f4xx_conf.h" -#include "stm32f4xx.h" -#include "FreeRTOS.h" -#include "FreeRTOSConfig.h" -#include "task.h" -#include "semphr.h" -#include "common.h" -#include "gps.h" -#include "usart.h" -#include "minmea.h" - - -TickType_t gps_timeutc_last_updated = 0; -static struct tm gps_timeutc; -static int gps_timeutc_valid; - -const TickType_t gps_data_validity_timeout = 10000ul / portTICK_PERIOD_MS; - -static void gps_task(void *pvParameters); - -SemaphoreHandle_t timeutc_semaphore; - -// Get current time from GPS -int gps_utctime(struct tm *timeutc) -{ - int valid = 0; - - xSemaphoreTake(timeutc_semaphore, portMAX_DELAY); - if (xTaskGetTickCount() - gps_timeutc_last_updated < gps_data_validity_timeout) { - timeutc->tm_year = gps_timeutc.tm_year; - timeutc->tm_mon = gps_timeutc.tm_mon; - timeutc->tm_mday = gps_timeutc.tm_mday; - timeutc->tm_hour = gps_timeutc.tm_hour; - timeutc->tm_min = gps_timeutc.tm_min; - timeutc->tm_sec = gps_timeutc.tm_sec; - valid = gps_timeutc_valid; - } - xSemaphoreGive(timeutc_semaphore); - - return valid; -} - -#define RXBUF_LEN MAX_NMEA_SENTENCE_LEN -static char rxbuf[RXBUF_LEN]; - -static void gps_task(void *pvParameters) -{ - // Periodically reinit the GPS - while (1) { - taskYIELD(); - - int success = usart_get_nmea_sentence(rxbuf); - - if (success) { - const int strict = 1; - switch (minmea_sentence_id(rxbuf, strict)) { - case MINMEA_SENTENCE_RMC: - { - struct minmea_sentence_rmc frame; - if (minmea_parse_rmc(&frame, rxbuf)) { - xSemaphoreTake(timeutc_semaphore, portMAX_DELAY); - gps_timeutc.tm_year = 2000 + frame.date.year; - gps_timeutc.tm_mon = frame.date.month; - gps_timeutc.tm_mday = frame.date.day; - gps_timeutc.tm_hour = frame.time.hours; - gps_timeutc.tm_min = frame.time.minutes; - gps_timeutc.tm_sec = frame.time.seconds; - gps_timeutc_valid = frame.valid; - gps_timeutc_last_updated = xTaskGetTickCount(); - xSemaphoreGive(timeutc_semaphore); - } - } break; - default: - break; - } - } - } -} - -void gps_init() -{ - gps_timeutc_valid = 0; - - usart_gps_init(); - - timeutc_semaphore = xSemaphoreCreateBinary(); - - if( timeutc_semaphore == NULL ) { - trigger_fault(FAULT_SOURCE_GPS); - } - else { - xSemaphoreGive(timeutc_semaphore); - } - - xTaskCreate( - gps_task, - "TaskGPS", - 4*configMINIMAL_STACK_SIZE, - (void*) NULL, - tskIDLE_PRIORITY + 2UL, - NULL); -} - -// Return 1 of the GPS is receiving time -int gps_locked() -{ - if (xTaskGetTickCount() - gps_timeutc_last_updated < gps_data_validity_timeout) { - return gps_timeutc_valid; - } - else { - return 0; - } -} - diff --git a/src/fsm/gps.h b/src/fsm/gps.h deleted file mode 100644 index 3472237..0000000 --- a/src/fsm/gps.h +++ /dev/null @@ -1,46 +0,0 @@ -/* - * The MIT License (MIT) - * - * Copyright (c) 2015 Matthias P. Braendli - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. -*/ - -#pragma once - -#include <stdint.h> -#include <time.h> - -/* Setup GPS receiver over USART and parse time */ - -/* USART connections: - * board TX to GPS RX on PD8 - * board RX to GPS TX on PD9 - */ - -// Setup communication and GPS receiver -void gps_init(); - -// Return 1 of the GPS is receiving time -int gps_locked(); - -// Get current time from GPS -// Returns 1 if time is valid, 0 otherwise -int gps_utctime(struct tm *timeutc); - diff --git a/src/fsm/minmea.c b/src/fsm/minmea.c deleted file mode 100644 index fc6aa43..0000000 --- a/src/fsm/minmea.c +++ /dev/null @@ -1,572 +0,0 @@ -/* - * Copyright © 2014 Kosma Moczek <kosma@cloudyourcar.com> - * This program is free software. It comes without any warranty, to the extent - * permitted by applicable law. You can redistribute it and/or modify it under - * the terms of the Do What The Fuck You Want To Public License, Version 2, as - * published by Sam Hocevar. See the COPYING file for more details. - */ - -// We are lacking timegm, but we only handle UTC and use mktime instead. See -// https://github.com/cloudyourcar/minmea-t/ README.md -#define timegm mktime - -#include "minmea.h" - -#include <stdlib.h> -#include <string.h> -#include <ctype.h> -#include <stdarg.h> - -#define boolstr(s) ((s) ? "true" : "false") - -static int hex2int(char c) -{ - if (c >= '0' && c <= '9') - return c - '0'; - if (c >= 'A' && c <= 'F') - return c - 'A' + 10; - if (c >= 'a' && c <= 'f') - return c - 'a' + 10; - return -1; -} - -uint8_t minmea_checksum(const char *sentence) -{ - // Support senteces with or without the starting dollar sign. - if (*sentence == '$') - sentence++; - - uint8_t checksum = 0x00; - - // The optional checksum is an XOR of all bytes between "$" and "*". - while (*sentence && *sentence != '*') - checksum ^= *sentence++; - - return checksum; -} - -bool minmea_check(const char *sentence, bool strict) -{ - uint8_t checksum = 0x00; - - // Sequence length is limited. - if (strlen(sentence) > MINMEA_MAX_LENGTH + 3) - return false; - - // A valid sentence starts with "$". - if (*sentence++ != '$') - return false; - - // The optional checksum is an XOR of all bytes between "$" and "*". - while (*sentence && *sentence != '*' && isprint((unsigned char) *sentence)) - checksum ^= *sentence++; - - // If checksum is present... - if (*sentence == '*') { - // Extract checksum. - sentence++; - int upper = hex2int(*sentence++); - if (upper == -1) - return false; - int lower = hex2int(*sentence++); - if (lower == -1) - return false; - int expected = upper << 4 | lower; - - // Check for checksum mismatch. - if (checksum != expected) - return false; - } else if (strict) { - // Discard non-checksummed frames in strict mode. - return false; - } - - // The only stuff allowed at this point is a newline. - if (*sentence && strcmp(sentence, "\n") && strcmp(sentence, "\r\n")) - return false; - - return true; -} - -static inline bool minmea_isfield(char c) { - return isprint((unsigned char) c) && c != ',' && c != '*'; -} - -bool minmea_scan(const char *sentence, const char *format, ...) -{ - bool result = false; - bool optional = false; - va_list ap; - va_start(ap, format); - - const char *field = sentence; -#define next_field() \ - do { \ - /* Progress to the next field. */ \ - while (minmea_isfield(*sentence)) \ - sentence++; \ - /* Make sure there is a field there. */ \ - if (*sentence == ',') { \ - sentence++; \ - field = sentence; \ - } else { \ - field = NULL; \ - } \ - } while (0) - - while (*format) { - char type = *format++; - - if (type == ';') { - // All further fields are optional. - optional = true; - continue; - } - - if (!field && !optional) { - // Field requested but we ran out if input. Bail out. - goto parse_error; - } - - switch (type) { - case 'c': { // Single character field (char). - char value = '\0'; - - if (field && minmea_isfield(*field)) - value = *field; - - *va_arg(ap, char *) = value; - } break; - - case 'd': { // Single character direction field (int). - int value = 0; - - if (field && minmea_isfield(*field)) { - switch (*field) { - case 'N': - case 'E': - value = 1; - break; - case 'S': - case 'W': - value = -1; - break; - default: - goto parse_error; - } - } - - *va_arg(ap, int *) = value; - } break; - - case 'f': { // Fractional value with scale (struct minmea_float). - int sign = 0; - int_least32_t value = -1; - int_least32_t scale = 0; - - if (field) { - while (minmea_isfield(*field)) { - if (*field == '+' && !sign && value == -1) { - sign = 1; - } else if (*field == '-' && !sign && value == -1) { - sign = -1; - } else if (isdigit((unsigned char) *field)) { - int digit = *field - '0'; - if (value == -1) - value = 0; - if (value > (INT_LEAST32_MAX-digit) / 10) { - /* we ran out of bits, what do we do? */ - if (scale) { - /* truncate extra precision */ - break; - } else { - /* integer overflow. bail out. */ - goto parse_error; - } - } - value = (10 * value) + digit; - if (scale) - scale *= 10; - } else if (*field == '.' && scale == 0) { - scale = 1; - } else if (*field == ' ') { - /* Allow spaces at the start of the field. Not NMEA - * conformant, but some modules do this. */ - if (sign != 0 || value != -1 || scale != 0) - goto parse_error; - } else { - goto parse_error; - } - field++; - } - } - - if ((sign || scale) && value == -1) - goto parse_error; - - if (value == -1) { - /* No digits were scanned. */ - value = 0; - scale = 0; - } else if (scale == 0) { - /* No decimal point. */ - scale = 1; - } - if (sign) - value *= sign; - - *va_arg(ap, struct minmea_float *) = (struct minmea_float) {value, scale}; - } break; - - case 'i': { // Integer value, default 0 (int). - int value = 0; - - if (field) { - char *endptr; - value = strtol(field, &endptr, 10); - if (minmea_isfield(*endptr)) - goto parse_error; - } - - *va_arg(ap, int *) = value; - } break; - - case 's': { // String value (char *). - char *buf = va_arg(ap, char *); - - if (field) { - while (minmea_isfield(*field)) - *buf++ = *field++; - } - - *buf = '\0'; - } break; - - case 't': { // NMEA talker+sentence identifier (char *). - // This field is always mandatory. - if (!field) - goto parse_error; - - if (field[0] != '$') - goto parse_error; - for (int f=0; f<5; f++) - if (!minmea_isfield(field[1+f])) - goto parse_error; - - char *buf = va_arg(ap, char *); - memcpy(buf, field+1, 5); - buf[5] = '\0'; - } break; - - case 'D': { // Date (int, int, int), -1 if empty. - struct minmea_date *date = va_arg(ap, struct minmea_date *); - - int d = -1, m = -1, y = -1; - - if (field && minmea_isfield(*field)) { - // Always six digits. - for (int f=0; f<6; f++) - if (!isdigit((unsigned char) field[f])) - goto parse_error; - - d = strtol((char[]) {field[0], field[1], '\0'}, NULL, 10); - m = strtol((char[]) {field[2], field[3], '\0'}, NULL, 10); - y = strtol((char[]) {field[4], field[5], '\0'}, NULL, 10); - } - - date->day = d; - date->month = m; - date->year = y; - } break; - - case 'T': { // Time (int, int, int, int), -1 if empty. - struct minmea_time *time_ = va_arg(ap, struct minmea_time *); - - int h = -1, i = -1, s = -1, u = -1; - - if (field && minmea_isfield(*field)) { - // Minimum required: integer time. - for (int f=0; f<6; f++) - if (!isdigit((unsigned char) field[f])) - goto parse_error; - - h = strtol((char[]) {field[0], field[1], '\0'}, NULL, 10); - i = strtol((char[]) {field[2], field[3], '\0'}, NULL, 10); - s = strtol((char[]) {field[4], field[5], '\0'}, NULL, 10); - field += 6; - - // Extra: fractional time. Saved as microseconds. - if (*field++ == '.') { - int value = 0; - int scale = 1000000; - while (isdigit((unsigned char) *field) && scale > 1) { - value = (value * 10) + (*field++ - '0'); - scale /= 10; - } - u = value * scale; - } else { - u = 0; - } - } - - time_->hours = h; - time_->minutes = i; - time_->seconds = s; - time_->microseconds = u; - } break; - - case '_': { // Ignore the field. - } break; - - default: { // Unknown. - goto parse_error; - } break; - } - - next_field(); - } - - result = true; - -parse_error: - va_end(ap); - return result; -} - -bool minmea_talker_id(char talker[3], const char *sentence) -{ - char type[6]; - if (!minmea_scan(sentence, "t", type)) - return false; - - talker[0] = type[0]; - talker[1] = type[1]; - talker[2] = '\0'; - - return true; -} - -enum minmea_sentence_id minmea_sentence_id(const char *sentence, bool strict) -{ - if (!minmea_check(sentence, strict)) - return MINMEA_INVALID; - - char type[6]; - if (!minmea_scan(sentence, "t", type)) - return MINMEA_INVALID; - - if (!strcmp(type+2, "RMC")) - return MINMEA_SENTENCE_RMC; - if (!strcmp(type+2, "GGA")) - return MINMEA_SENTENCE_GGA; - if (!strcmp(type+2, "GSA")) - return MINMEA_SENTENCE_GSA; - if (!strcmp(type+2, "GLL")) - return MINMEA_SENTENCE_GLL; - if (!strcmp(type+2, "GST")) - return MINMEA_SENTENCE_GST; - if (!strcmp(type+2, "GSV")) - return MINMEA_SENTENCE_GSV; - - return MINMEA_UNKNOWN; -} - -bool minmea_parse_rmc(struct minmea_sentence_rmc *frame, const char *sentence) -{ - // $GPRMC,081836,A,3751.65,S,14507.36,E,000.0,360.0,130998,011.3,E*62 - char type[6]; - char validity; - int latitude_direction; - int longitude_direction; - int variation_direction; - if (!minmea_scan(sentence, "tTcfdfdffDfd", - type, - &frame->time, - &validity, - &frame->latitude, &latitude_direction, - &frame->longitude, &longitude_direction, - &frame->speed, - &frame->course, - &frame->date, - &frame->variation, &variation_direction)) - return false; - if (strcmp(type+2, "RMC")) - return false; - - frame->valid = (validity == 'A'); - frame->latitude.value *= latitude_direction; - frame->longitude.value *= longitude_direction; - frame->variation.value *= variation_direction; - - return true; -} - -bool minmea_parse_gga(struct minmea_sentence_gga *frame, const char *sentence) -{ - // $GPGGA,123519,4807.038,N,01131.000,E,1,08,0.9,545.4,M,46.9,M,,*47 - char type[6]; - int latitude_direction; - int longitude_direction; - - if (!minmea_scan(sentence, "tTfdfdiiffcfci_", - type, - &frame->time, - &frame->latitude, &latitude_direction, - &frame->longitude, &longitude_direction, - &frame->fix_quality, - &frame->satellites_tracked, - &frame->hdop, - &frame->altitude, &frame->altitude_units, - &frame->height, &frame->height_units, - &frame->dgps_age)) - return false; - if (strcmp(type+2, "GGA")) - return false; - - frame->latitude.value *= latitude_direction; - frame->longitude.value *= longitude_direction; - - return true; -} - -bool minmea_parse_gsa(struct minmea_sentence_gsa *frame, const char *sentence) -{ - // $GPGSA,A,3,04,05,,09,12,,,24,,,,,2.5,1.3,2.1*39 - char type[6]; - - if (!minmea_scan(sentence, "tciiiiiiiiiiiiifff", - type, - &frame->mode, - &frame->fix_type, - &frame->sats[0], - &frame->sats[1], - &frame->sats[2], - &frame->sats[3], - &frame->sats[4], - &frame->sats[5], - &frame->sats[6], - &frame->sats[7], - &frame->sats[8], - &frame->sats[9], - &frame->sats[10], - &frame->sats[11], - &frame->pdop, - &frame->hdop, - &frame->vdop)) - return false; - if (strcmp(type+2, "GSA")) - return false; - - return true; -} - -bool minmea_parse_gll(struct minmea_sentence_gll *frame, const char *sentence) -{ - // $GPGLL,3723.2475,N,12158.3416,W,161229.487,A,A*41$; - char type[6]; - int latitude_direction; - int longitude_direction; - - if (!minmea_scan(sentence, "tfdfdTc;c", - type, - &frame->latitude, &latitude_direction, - &frame->longitude, &longitude_direction, - &frame->time, - &frame->status, - &frame->mode)) - return false; - if (strcmp(type+2, "GLL")) - return false; - - frame->latitude.value *= latitude_direction; - frame->longitude.value *= longitude_direction; - - return true; -} - -bool minmea_parse_gst(struct minmea_sentence_gst *frame, const char *sentence) -{ - // $GPGST,024603.00,3.2,6.6,4.7,47.3,5.8,5.6,22.0*58 - char type[6]; - - if (!minmea_scan(sentence, "tTfffffff", - type, - &frame->time, - &frame->rms_deviation, - &frame->semi_major_deviation, - &frame->semi_minor_deviation, - &frame->semi_major_orientation, - &frame->latitude_error_deviation, - &frame->longitude_error_deviation, - &frame->altitude_error_deviation)) - return false; - if (strcmp(type+2, "GST")) - return false; - - return true; -} - -bool minmea_parse_gsv(struct minmea_sentence_gsv *frame, const char *sentence) -{ - // $GPGSV,3,1,11,03,03,111,00,04,15,270,00,06,01,010,00,13,06,292,00*74 - // $GPGSV,3,3,11,22,42,067,42,24,14,311,43,27,05,244,00,,,,*4D - // $GPGSV,4,2,11,08,51,203,30,09,45,215,28*75 - // $GPGSV,4,4,13,39,31,170,27*40 - // $GPGSV,4,4,13*7B - char type[6]; - - if (!minmea_scan(sentence, "tiii;iiiiiiiiiiiiiiii", - type, - &frame->total_msgs, - &frame->msg_nr, - &frame->total_sats, - &frame->sats[0].nr, - &frame->sats[0].elevation, - &frame->sats[0].azimuth, - &frame->sats[0].snr, - &frame->sats[1].nr, - &frame->sats[1].elevation, - &frame->sats[1].azimuth, - &frame->sats[1].snr, - &frame->sats[2].nr, - &frame->sats[2].elevation, - &frame->sats[2].azimuth, - &frame->sats[2].snr, - &frame->sats[3].nr, - &frame->sats[3].elevation, - &frame->sats[3].azimuth, - &frame->sats[3].snr - )) { - return false; - } - if (strcmp(type+2, "GSV")) - return false; - - return true; -} - -int minmea_gettime(struct timespec *ts, const struct minmea_date *date, const struct minmea_time *time_) -{ - if (date->year == -1 || time_->hours == -1) - return -1; - - struct tm tm; - memset(&tm, 0, sizeof(tm)); - tm.tm_year = 2000 + date->year - 1900; - tm.tm_mon = date->month - 1; - tm.tm_mday = date->day; - tm.tm_hour = time_->hours; - tm.tm_min = time_->minutes; - tm.tm_sec = time_->seconds; - - time_t timestamp = timegm(&tm); /* See README.md if your system lacks timegm(). */ - if (timestamp != -1) { - ts->tv_sec = timestamp; - ts->tv_nsec = time_->microseconds * 1000; - return 0; - } else { - return -1; - } -} - -/* vim: set ts=4 sw=4 et: */ diff --git a/src/fsm/minmea.h b/src/fsm/minmea.h deleted file mode 100644 index 6d7fe18..0000000 --- a/src/fsm/minmea.h +++ /dev/null @@ -1,234 +0,0 @@ -/* - * Copyright © 2014 Kosma Moczek <kosma@cloudyourcar.com> - * This program is free software. It comes without any warranty, to the extent - * permitted by applicable law. You can redistribute it and/or modify it under - * the terms of the Do What The Fuck You Want To Public License, Version 2, as - * published by Sam Hocevar. See the COPYING file for more details. - */ - -#ifndef MINMEA_H -#define MINMEA_H - -#ifdef __cplusplus -extern "C" { -#endif - -#include <stdio.h> -#include <stdint.h> -#include <stdbool.h> -#include <errno.h> -#include <time.h> -#include <math.h> - -#define MINMEA_MAX_LENGTH 80 - -enum minmea_sentence_id { - MINMEA_INVALID = -1, - MINMEA_UNKNOWN = 0, - MINMEA_SENTENCE_RMC, - MINMEA_SENTENCE_GGA, - MINMEA_SENTENCE_GSA, - MINMEA_SENTENCE_GLL, - MINMEA_SENTENCE_GST, - MINMEA_SENTENCE_GSV, -}; - -struct minmea_float { - int_least32_t value; - int_least32_t scale; -}; - -struct minmea_date { - int day; - int month; - int year; -}; - -struct minmea_time { - int hours; - int minutes; - int seconds; - int microseconds; -}; - -struct minmea_sentence_rmc { - struct minmea_time time; - bool valid; - struct minmea_float latitude; - struct minmea_float longitude; - struct minmea_float speed; - struct minmea_float course; - struct minmea_date date; - struct minmea_float variation; -}; - -struct minmea_sentence_gga { - struct minmea_time time; - struct minmea_float latitude; - struct minmea_float longitude; - int fix_quality; - int satellites_tracked; - struct minmea_float hdop; - struct minmea_float altitude; char altitude_units; - struct minmea_float height; char height_units; - int dgps_age; -}; - -enum minmea_gll_status { - MINMEA_GLL_STATUS_DATA_VALID = 'A', - MINMEA_GLL_STATUS_DATA_NOT_VALID = 'V', -}; - -enum minmea_gll_mode { - MINMEA_GLL_MODE_AUTONOMOUS = 'A', - MINMEA_GLL_MODE_DPGS = 'D', - MINMEA_GLL_MODE_DR = 'E', -}; - -struct minmea_sentence_gll { - struct minmea_float latitude; - struct minmea_float longitude; - struct minmea_time time; - char status; - char mode; -}; - -struct minmea_sentence_gst { - struct minmea_time time; - struct minmea_float rms_deviation; - struct minmea_float semi_major_deviation; - struct minmea_float semi_minor_deviation; - struct minmea_float semi_major_orientation; - struct minmea_float latitude_error_deviation; - struct minmea_float longitude_error_deviation; - struct minmea_float altitude_error_deviation; -}; - -enum minmea_gsa_mode { - MINMEA_GPGSA_MODE_AUTO = 'A', - MINMEA_GPGSA_MODE_FORCED = 'M', -}; - -enum minmea_gsa_fix_type { - MINMEA_GPGSA_FIX_NONE = 1, - MINMEA_GPGSA_FIX_2D = 2, - MINMEA_GPGSA_FIX_3D = 3, -}; - -struct minmea_sentence_gsa { - char mode; - int fix_type; - int sats[12]; - struct minmea_float pdop; - struct minmea_float hdop; - struct minmea_float vdop; -}; - -struct minmea_sat_info { - int nr; - int elevation; - int azimuth; - int snr; -}; - -struct minmea_sentence_gsv { - int total_msgs; - int msg_nr; - int total_sats; - struct minmea_sat_info sats[4]; -}; - -/** - * Calculate raw sentence checksum. Does not check sentence integrity. - */ -uint8_t minmea_checksum(const char *sentence); - -/** - * Check sentence validity and checksum. Returns true for valid sentences. - */ -bool minmea_check(const char *sentence, bool strict); - -/** - * Determine talker identifier. - */ -bool minmea_talker_id(char talker[3], const char *sentence); - -/** - * Determine sentence identifier. - */ -enum minmea_sentence_id minmea_sentence_id(const char *sentence, bool strict); - -/** - * Scanf-like processor for NMEA sentences. Supports the following formats: - * c - single character (char *) - * d - direction, returned as 1/-1, default 0 (int *) - * f - fractional, returned as value + scale (int *, int *) - * i - decimal, default zero (int *) - * s - string (char *) - * t - talker identifier and type (char *) - * T - date/time stamp (int *, int *, int *) - * Returns true on success. See library source code for details. - */ -bool minmea_scan(const char *sentence, const char *format, ...); - -/* - * Parse a specific type of sentence. Return true on success. - */ -bool minmea_parse_rmc(struct minmea_sentence_rmc *frame, const char *sentence); -bool minmea_parse_gga(struct minmea_sentence_gga *frame, const char *sentence); -bool minmea_parse_gsa(struct minmea_sentence_gsa *frame, const char *sentence); -bool minmea_parse_gll(struct minmea_sentence_gll *frame, const char *sentence); -bool minmea_parse_gst(struct minmea_sentence_gst *frame, const char *sentence); -bool minmea_parse_gsv(struct minmea_sentence_gsv *frame, const char *sentence); - -/** - * Convert GPS UTC date/time representation to a UNIX timestamp. - */ -int minmea_gettime(struct timespec *ts, const struct minmea_date *date, const struct minmea_time *time_); - -/** - * Rescale a fixed-point value to a different scale. Rounds towards zero. - */ -static inline int_least32_t minmea_rescale(struct minmea_float *f, int_least32_t new_scale) -{ - if (f->scale == 0) - return 0; - if (f->scale == new_scale) - return f->value; - if (f->scale > new_scale) - return (f->value + ((f->value > 0) - (f->value < 0)) * f->scale/new_scale/2) / (f->scale/new_scale); - else - return f->value * (new_scale/f->scale); -} - -/** - * Convert a fixed-point value to a floating-point value. - * Returns NaN for "unknown" values. - */ -static inline float minmea_tofloat(struct minmea_float *f) -{ - if (f->scale == 0) - return NAN; - return (float) f->value / (float) f->scale; -} - -/** - * Convert a raw coordinate to a floating point DD.DDD... value. - * Returns NaN for "unknown" values. - */ -static inline float minmea_tocoord(struct minmea_float *f) -{ - if (f->scale == 0) - return NAN; - int_least32_t degrees = f->value / (f->scale * 100); - int_least32_t minutes = f->value % (f->scale * 100); - return (float) degrees + (float) minutes / (60 * f->scale); -} - -#ifdef __cplusplus -} -#endif - -#endif /* MINMEA_H */ - -/* vim: set ts=4 sw=4 et: */ |