| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794 |
- // Copyright 2015-2018 Espressif Systems (Shanghai) PTE LTD
- //
- // Licensed under the Apache License, Version 2.0 (the "License");
- // you may not use this file except in compliance with the License.
- // You may obtain a copy of the License at
- //
- // http://www.apache.org/licenses/LICENSE-2.0
- //
- // Unless required by applicable law or agreed to in writing, software
- // distributed under the License is distributed on an "AS IS" BASIS,
- // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- // See the License for the specific language governing permissions and
- // limitations under the License.
- #include <stdlib.h>
- #include <string.h>
- #include <ctype.h>
- #include <math.h>
- #include "freertos/FreeRTOS.h"
- #include "freertos/task.h"
- #include "esp_log.h"
- #include "nmea_parser.h"
- /**
- * @brief NMEA Parser runtime buffer size
- *
- */
- #define NMEA_PARSER_RUNTIME_BUFFER_SIZE (CONFIG_NMEA_PARSER_RING_BUFFER_SIZE / 2)
- #define NMEA_MAX_STATEMENT_ITEM_LENGTH (16)
- #define NMEA_EVENT_LOOP_QUEUE_SIZE (16)
- /**
- * @brief Define of NMEA Parser Event base
- *
- */
- ESP_EVENT_DEFINE_BASE(ESP_NMEA_EVENT);
- static const char *GPS_TAG = "nmea_parser";
- /**
- * @brief GPS parser library runtime structure
- *
- */
- typedef struct {
- uint8_t item_pos; /*!< Current position in item */
- uint8_t item_num; /*!< Current item number */
- uint8_t asterisk; /*!< Asterisk detected flag */
- uint8_t crc; /*!< Calculated CRC value */
- uint8_t parsed_statement; /*!< OR'd of statements that have been parsed */
- uint8_t sat_num; /*!< Satellite number */
- uint8_t sat_count; /*!< Satellite count */
- uint8_t cur_statement; /*!< Current statement ID */
- uint32_t all_statements; /*!< All statements mask */
- char item_str[NMEA_MAX_STATEMENT_ITEM_LENGTH]; /*!< Current item */
- gps_t parent; /*!< Parent class */
- uart_port_t uart_port; /*!< Uart port number */
- uint8_t *buffer; /*!< Runtime buffer */
- esp_event_loop_handle_t event_loop_hdl; /*!< Event loop handle */
- TaskHandle_t tsk_hdl; /*!< NMEA Parser task handle */
- QueueHandle_t event_queue; /*!< UART event queue handle */
- } esp_gps_t;
- /**
- * @brief parse latitude or longitude
- * format of latitude in NMEA is ddmm.sss and longitude is dddmm.sss
- * @param esp_gps esp_gps_t type object
- * @return float Latitude or Longitude value (unit: degree)
- */
- static float parse_lat_long(esp_gps_t *esp_gps)
- {
- float ll = strtof(esp_gps->item_str, NULL);
- int deg = ((int)ll) / 100;
- float min = ll - (deg * 100);
- ll = deg + min / 60.0f;
- return ll;
- }
- /**
- * @brief Converter two continuous numeric character into a uint8_t number
- *
- * @param digit_char numeric character
- * @return uint8_t result of converting
- */
- static inline uint8_t convert_two_digit2number(const char *digit_char)
- {
- return 10 * (digit_char[0] - '0') + (digit_char[1] - '0');
- }
- /**
- * @brief Parse UTC time in GPS statements
- *
- * @param esp_gps esp_gps_t type object
- */
- static void parse_utc_time(esp_gps_t *esp_gps)
- {
- esp_gps->parent.tim.hour = convert_two_digit2number(esp_gps->item_str + 0);
- esp_gps->parent.tim.minute = convert_two_digit2number(esp_gps->item_str + 2);
- esp_gps->parent.tim.second = convert_two_digit2number(esp_gps->item_str + 4);
- if (esp_gps->item_str[6] == '.') {
- uint16_t tmp = 0;
- uint8_t i = 7;
- while (esp_gps->item_str[i]) {
- tmp = 10 * tmp + esp_gps->item_str[i] - '0';
- i++;
- }
- esp_gps->parent.tim.thousand = tmp;
- }
- }
- #if CONFIG_NMEA_STATEMENT_GGA
- /**
- * @brief Parse GGA statements
- *
- * @param esp_gps esp_gps_t type object
- */
- static void parse_gga(esp_gps_t *esp_gps)
- {
- /* Process GGA statement */
- switch (esp_gps->item_num) {
- case 1: /* Process UTC time */
- parse_utc_time(esp_gps);
- break;
- case 2: /* Latitude */
- esp_gps->parent.latitude = parse_lat_long(esp_gps);
- break;
- case 3: /* Latitude north(1)/south(-1) information */
- if (esp_gps->item_str[0] == 'S' || esp_gps->item_str[0] == 's') {
- esp_gps->parent.latitude *= -1;
- }
- break;
- case 4: /* Longitude */
- esp_gps->parent.longitude = parse_lat_long(esp_gps);
- break;
- case 5: /* Longitude east(1)/west(-1) information */
- if (esp_gps->item_str[0] == 'W' || esp_gps->item_str[0] == 'w') {
- esp_gps->parent.longitude *= -1;
- }
- break;
- case 6: /* Fix status */
- esp_gps->parent.fix = (gps_fix_t)strtol(esp_gps->item_str, NULL, 10);
- break;
- case 7: /* Satellites in use */
- esp_gps->parent.sats_in_use = (uint8_t)strtol(esp_gps->item_str, NULL, 10);
- break;
- case 8: /* HDOP */
- esp_gps->parent.dop_h = strtof(esp_gps->item_str, NULL);
- break;
- case 9: /* Altitude */
- esp_gps->parent.altitude = strtof(esp_gps->item_str, NULL);
- break;
- case 11: /* Altitude above ellipsoid */
- esp_gps->parent.altitude += strtof(esp_gps->item_str, NULL);
- break;
- default:
- break;
- }
- }
- #endif
- #if CONFIG_NMEA_STATEMENT_GSA
- /**
- * @brief Parse GSA statements
- *
- * @param esp_gps esp_gps_t type object
- */
- static void parse_gsa(esp_gps_t *esp_gps)
- {
- /* Process GSA statement */
- switch (esp_gps->item_num) {
- case 2: /* Process fix mode */
- esp_gps->parent.fix_mode = (gps_fix_mode_t)strtol(esp_gps->item_str, NULL, 10);
- break;
- case 15: /* Process PDOP */
- esp_gps->parent.dop_p = strtof(esp_gps->item_str, NULL);
- break;
- case 16: /* Process HDOP */
- esp_gps->parent.dop_h = strtof(esp_gps->item_str, NULL);
- break;
- case 17: /* Process VDOP */
- esp_gps->parent.dop_v = strtof(esp_gps->item_str, NULL);
- break;
- default:
- /* Parse satellite IDs */
- if (esp_gps->item_num >= 3 && esp_gps->item_num <= 14) {
- esp_gps->parent.sats_id_in_use[esp_gps->item_num - 3] = (uint8_t)strtol(esp_gps->item_str, NULL, 10);
- }
- break;
- }
- }
- #endif
- #if CONFIG_NMEA_STATEMENT_GSV
- /**
- * @brief Parse GSV statements
- *
- * @param esp_gps esp_gps_t type object
- */
- static void parse_gsv(esp_gps_t *esp_gps)
- {
- /* Process GSV statement */
- switch (esp_gps->item_num) {
- case 1: /* total GSV numbers */
- esp_gps->sat_count = (uint8_t)strtol(esp_gps->item_str, NULL, 10);
- break;
- case 2: /* Current GSV statement number */
- esp_gps->sat_num = (uint8_t)strtol(esp_gps->item_str, NULL, 10);
- break;
- case 3: /* Process satellites in view */
- esp_gps->parent.sats_in_view = (uint8_t)strtol(esp_gps->item_str, NULL, 10);
- break;
- default:
- if (esp_gps->item_num >= 4 && esp_gps->item_num <= 19) {
- uint8_t item_num = esp_gps->item_num - 4; /* Normalize item number from 4-19 to 0-15 */
- uint8_t index;
- uint32_t value;
- index = 4 * (esp_gps->sat_num - 1) + item_num / 4; /* Get array index */
- if (index < GPS_MAX_SATELLITES_IN_VIEW) {
- value = strtol(esp_gps->item_str, NULL, 10);
- switch (item_num % 4) {
- case 0:
- esp_gps->parent.sats_desc_in_view[index].num = (uint8_t)value;
- break;
- case 1:
- esp_gps->parent.sats_desc_in_view[index].elevation = (uint8_t)value;
- break;
- case 2:
- esp_gps->parent.sats_desc_in_view[index].azimuth = (uint16_t)value;
- break;
- case 3:
- esp_gps->parent.sats_desc_in_view[index].snr = (uint8_t)value;
- break;
- default:
- break;
- }
- }
- }
- break;
- }
- }
- #endif
- #if CONFIG_NMEA_STATEMENT_RMC
- /**
- * @brief Parse RMC statements
- *
- * @param esp_gps esp_gps_t type object
- */
- static void parse_rmc(esp_gps_t *esp_gps)
- {
- /* Process GPRMC statement */
- switch (esp_gps->item_num) {
- case 1:/* Process UTC time */
- parse_utc_time(esp_gps);
- break;
- case 2: /* Process valid status */
- esp_gps->parent.valid = (esp_gps->item_str[0] == 'A');
- break;
- case 3:/* Latitude */
- esp_gps->parent.latitude = parse_lat_long(esp_gps);
- break;
- case 4: /* Latitude north(1)/south(-1) information */
- if (esp_gps->item_str[0] == 'S' || esp_gps->item_str[0] == 's') {
- esp_gps->parent.latitude *= -1;
- }
- break;
- case 5: /* Longitude */
- esp_gps->parent.longitude = parse_lat_long(esp_gps);
- break;
- case 6: /* Longitude east(1)/west(-1) information */
- if (esp_gps->item_str[0] == 'W' || esp_gps->item_str[0] == 'w') {
- esp_gps->parent.longitude *= -1;
- }
- break;
- case 7: /* Process ground speed in unit m/s */
- esp_gps->parent.speed = strtof(esp_gps->item_str, NULL) * 1.852;
- break;
- case 8: /* Process true course over ground */
- esp_gps->parent.cog = strtof(esp_gps->item_str, NULL);
- break;
- case 9: /* Process date */
- esp_gps->parent.date.day = convert_two_digit2number(esp_gps->item_str + 0);
- esp_gps->parent.date.month = convert_two_digit2number(esp_gps->item_str + 2);
- esp_gps->parent.date.year = convert_two_digit2number(esp_gps->item_str + 4);
- break;
- case 10: /* Process magnetic variation */
- esp_gps->parent.variation = strtof(esp_gps->item_str, NULL);
- break;
- default:
- break;
- }
- }
- #endif
- #if CONFIG_NMEA_STATEMENT_GLL
- /**
- * @brief Parse GLL statements
- *
- * @param esp_gps esp_gps_t type object
- */
- static void parse_gll(esp_gps_t *esp_gps)
- {
- /* Process GPGLL statement */
- switch (esp_gps->item_num) {
- case 1:/* Latitude */
- esp_gps->parent.latitude = parse_lat_long(esp_gps);
- break;
- case 2: /* Latitude north(1)/south(-1) information */
- if (esp_gps->item_str[0] == 'S' || esp_gps->item_str[0] == 's') {
- esp_gps->parent.latitude *= -1;
- }
- break;
- case 3: /* Longitude */
- esp_gps->parent.longitude = parse_lat_long(esp_gps);
- break;
- case 4: /* Longitude east(1)/west(-1) information */
- if (esp_gps->item_str[0] == 'W' || esp_gps->item_str[0] == 'w') {
- esp_gps->parent.longitude *= -1;
- }
- break;
- case 5:/* Process UTC time */
- parse_utc_time(esp_gps);
- break;
- case 6: /* Process valid status */
- esp_gps->parent.valid = (esp_gps->item_str[0] == 'A');
- break;
- default:
- break;
- }
- }
- #endif
- #if CONFIG_NMEA_STATEMENT_VTG
- /**
- * @brief Parse VTG statements
- *
- * @param esp_gps esp_gps_t type object
- */
- static void parse_vtg(esp_gps_t *esp_gps)
- {
- /* Process GPVGT statement */
- switch (esp_gps->item_num) {
- case 1: /* Process true course over ground */
- esp_gps->parent.cog = strtof(esp_gps->item_str, NULL);
- break;
- case 3:/* Process magnetic variation */
- esp_gps->parent.variation = strtof(esp_gps->item_str, NULL);
- break;
- case 5:/* Process ground speed in unit m/s */
- esp_gps->parent.speed = strtof(esp_gps->item_str, NULL) * 1.852;//knots to m/s
- break;
- case 7:/* Process ground speed in unit m/s */
- esp_gps->parent.speed = strtof(esp_gps->item_str, NULL) / 3.6;//km/h to m/s
- break;
- default:
- break;
- }
- }
- #endif
- /**
- * @brief Parse received item
- *
- * @param esp_gps esp_gps_t type object
- * @return esp_err_t ESP_OK on success, ESP_FAIL on error
- */
- static esp_err_t parse_item(esp_gps_t *esp_gps)
- {
- esp_err_t err = ESP_OK;
- /* start of a statement */
- if (esp_gps->item_num == 0 && esp_gps->item_str[0] == '$') {
- if (0) {
- }
- #if CONFIG_NMEA_STATEMENT_GGA
- else if (strstr(esp_gps->item_str, "GGA")) {
- esp_gps->cur_statement = STATEMENT_GGA;
- }
- #endif
- #if CONFIG_NMEA_STATEMENT_GSA
- else if (strstr(esp_gps->item_str, "GSA")) {
- esp_gps->cur_statement = STATEMENT_GSA;
- }
- #endif
- #if CONFIG_NMEA_STATEMENT_RMC
- else if (strstr(esp_gps->item_str, "RMC")) {
- esp_gps->cur_statement = STATEMENT_RMC;
- }
- #endif
- #if CONFIG_NMEA_STATEMENT_GSV
- else if (strstr(esp_gps->item_str, "GSV")) {
- esp_gps->cur_statement = STATEMENT_GSV;
- }
- #endif
- #if CONFIG_NMEA_STATEMENT_GLL
- else if (strstr(esp_gps->item_str, "GLL")) {
- esp_gps->cur_statement = STATEMENT_GLL;
- }
- #endif
- #if CONFIG_NMEA_STATEMENT_VTG
- else if (strstr(esp_gps->item_str, "VTG")) {
- esp_gps->cur_statement = STATEMENT_VTG;
- }
- #endif
- else {
- esp_gps->cur_statement = STATEMENT_UNKNOWN;
- }
- goto out;
- }
- /* Parse each item, depend on the type of the statement */
- if (esp_gps->cur_statement == STATEMENT_UNKNOWN) {
- goto out;
- }
- #if CONFIG_NMEA_STATEMENT_GGA
- else if (esp_gps->cur_statement == STATEMENT_GGA) {
- parse_gga(esp_gps);
- }
- #endif
- #if CONFIG_NMEA_STATEMENT_GSA
- else if (esp_gps->cur_statement == STATEMENT_GSA) {
- parse_gsa(esp_gps);
- }
- #endif
- #if CONFIG_NMEA_STATEMENT_GSV
- else if (esp_gps->cur_statement == STATEMENT_GSV) {
- parse_gsv(esp_gps);
- }
- #endif
- #if CONFIG_NMEA_STATEMENT_RMC
- else if (esp_gps->cur_statement == STATEMENT_RMC) {
- parse_rmc(esp_gps);
- }
- #endif
- #if CONFIG_NMEA_STATEMENT_GLL
- else if (esp_gps->cur_statement == STATEMENT_GLL) {
- parse_gll(esp_gps);
- }
- #endif
- #if CONFIG_NMEA_STATEMENT_VTG
- else if (esp_gps->cur_statement == STATEMENT_VTG) {
- parse_vtg(esp_gps);
- }
- #endif
- else {
- err = ESP_FAIL;
- }
- out:
- return err;
- }
- /**
- * @brief Parse NMEA statements from GPS receiver
- *
- * @param esp_gps esp_gps_t type object
- * @param len number of bytes to decode
- * @return esp_err_t ESP_OK on success, ESP_FAIL on error
- */
- static esp_err_t gps_decode(esp_gps_t *esp_gps, size_t len)
- {
- const uint8_t *d = esp_gps->buffer;
- while (*d) {
- /* Start of a statement */
- if (*d == '$') {
- /* Reset runtime information */
- esp_gps->asterisk = 0;
- esp_gps->item_num = 0;
- esp_gps->item_pos = 0;
- esp_gps->cur_statement = 0;
- esp_gps->crc = 0;
- esp_gps->sat_count = 0;
- esp_gps->sat_num = 0;
- /* Add character to item */
- esp_gps->item_str[esp_gps->item_pos++] = *d;
- esp_gps->item_str[esp_gps->item_pos] = '\0';
- }
- /* Detect item separator character */
- else if (*d == ',') {
- /* Parse current item */
- parse_item(esp_gps);
- /* Add character to CRC computation */
- esp_gps->crc ^= (uint8_t)(*d);
- /* Start with next item */
- esp_gps->item_pos = 0;
- esp_gps->item_str[0] = '\0';
- esp_gps->item_num++;
- }
- /* End of CRC computation */
- else if (*d == '*') {
- /* Parse current item */
- parse_item(esp_gps);
- /* Asterisk detected */
- esp_gps->asterisk = 1;
- /* Start with next item */
- esp_gps->item_pos = 0;
- esp_gps->item_str[0] = '\0';
- esp_gps->item_num++;
- }
- /* End of statement */
- else if (*d == '\r') {
- /* Convert received CRC from string (hex) to number */
- uint8_t crc = (uint8_t)strtol(esp_gps->item_str, NULL, 16);
- /* CRC passed */
- if (esp_gps->crc == crc) {
- switch (esp_gps->cur_statement) {
- #if CONFIG_NMEA_STATEMENT_GGA
- case STATEMENT_GGA:
- esp_gps->parsed_statement |= 1 << STATEMENT_GGA;
- break;
- #endif
- #if CONFIG_NMEA_STATEMENT_GSA
- case STATEMENT_GSA:
- esp_gps->parsed_statement |= 1 << STATEMENT_GSA;
- break;
- #endif
- #if CONFIG_NMEA_STATEMENT_RMC
- case STATEMENT_RMC:
- esp_gps->parsed_statement |= 1 << STATEMENT_RMC;
- break;
- #endif
- #if CONFIG_NMEA_STATEMENT_GSV
- case STATEMENT_GSV:
- if (esp_gps->sat_num == esp_gps->sat_count) {
- esp_gps->parsed_statement |= 1 << STATEMENT_GSV;
- }
- break;
- #endif
- #if CONFIG_NMEA_STATEMENT_GLL
- case STATEMENT_GLL:
- esp_gps->parsed_statement |= 1 << STATEMENT_GLL;
- break;
- #endif
- #if CONFIG_NMEA_STATEMENT_VTG
- case STATEMENT_VTG:
- esp_gps->parsed_statement |= 1 << STATEMENT_VTG;
- break;
- #endif
- default:
- break;
- }
- /* Check if all statements have been parsed */
- if (((esp_gps->parsed_statement) & esp_gps->all_statements) == esp_gps->all_statements) {
- esp_gps->parsed_statement = 0;
- /* Send signal to notify that GPS information has been updated */
- esp_event_post_to(esp_gps->event_loop_hdl, ESP_NMEA_EVENT, GPS_UPDATE,
- &(esp_gps->parent), sizeof(gps_t), 100 / portTICK_PERIOD_MS);
- }
- } else {
- ESP_LOGD(GPS_TAG, "CRC Error for statement:%s", esp_gps->buffer);
- }
- if (esp_gps->cur_statement == STATEMENT_UNKNOWN) {
- /* Send signal to notify that one unknown statement has been met */
- esp_event_post_to(esp_gps->event_loop_hdl, ESP_NMEA_EVENT, GPS_UNKNOWN,
- esp_gps->buffer, len, 100 / portTICK_PERIOD_MS);
- }
- }
- /* Other non-space character */
- else {
- if (!(esp_gps->asterisk)) {
- /* Add to CRC */
- esp_gps->crc ^= (uint8_t)(*d);
- }
- /* Add character to item */
- esp_gps->item_str[esp_gps->item_pos++] = *d;
- esp_gps->item_str[esp_gps->item_pos] = '\0';
- }
- /* Process next character */
- d++;
- }
- return ESP_OK;
- }
- /**
- * @brief Handle when a pattern has been detected by uart
- *
- * @param esp_gps esp_gps_t type object
- */
- static void esp_handle_uart_pattern(esp_gps_t *esp_gps)
- {
- int pos = uart_pattern_pop_pos(esp_gps->uart_port);
- if (pos != -1) {
- /* read one line(include '\n') */
- int read_len = uart_read_bytes(esp_gps->uart_port, esp_gps->buffer, pos + 1, 100 / portTICK_PERIOD_MS);
- /* make sure the line is a standard string */
- esp_gps->buffer[read_len] = '\0';
- /* Send new line to handle */
- if (gps_decode(esp_gps, read_len + 1) != ESP_OK) {
- ESP_LOGW(GPS_TAG, "GPS decode line failed");
- }
- } else {
- ESP_LOGW(GPS_TAG, "Pattern Queue Size too small");
- uart_flush_input(esp_gps->uart_port);
- }
- }
- /**
- * @brief NMEA Parser Task Entry
- *
- * @param arg argument
- */
- static void nmea_parser_task_entry(void *arg)
- {
- esp_gps_t *esp_gps = (esp_gps_t *)arg;
- uart_event_t event;
- while (1) {
- if (xQueueReceive(esp_gps->event_queue, &event, pdMS_TO_TICKS(200))) {
- switch (event.type) {
- case UART_DATA:
- break;
- case UART_FIFO_OVF:
- ESP_LOGW(GPS_TAG, "HW FIFO Overflow");
- uart_flush(esp_gps->uart_port);
- xQueueReset(esp_gps->event_queue);
- break;
- case UART_BUFFER_FULL:
- ESP_LOGW(GPS_TAG, "Ring Buffer Full");
- uart_flush(esp_gps->uart_port);
- xQueueReset(esp_gps->event_queue);
- break;
- case UART_BREAK:
- ESP_LOGW(GPS_TAG, "Rx Break");
- break;
- case UART_PARITY_ERR:
- ESP_LOGE(GPS_TAG, "Parity Error");
- break;
- case UART_FRAME_ERR:
- ESP_LOGE(GPS_TAG, "Frame Error");
- break;
- case UART_PATTERN_DET:
- esp_handle_uart_pattern(esp_gps);
- break;
- default:
- ESP_LOGW(GPS_TAG, "unknown uart event type: %d", event.type);
- break;
- }
- }
- /* Drive the event loop */
- esp_event_loop_run(esp_gps->event_loop_hdl, pdMS_TO_TICKS(50));
- }
- vTaskDelete(NULL);
- }
- /**
- * @brief Init NMEA Parser
- *
- * @param config Configuration of NMEA Parser
- * @return nmea_parser_handle_t handle of nmea_parser
- */
- nmea_parser_handle_t nmea_parser_init(const nmea_parser_config_t *config)
- {
- esp_gps_t *esp_gps = calloc(1, sizeof(esp_gps_t));
- if (!esp_gps) {
- ESP_LOGE(GPS_TAG, "calloc memory for esp_fps failed");
- goto err_gps;
- }
- esp_gps->buffer = calloc(1, NMEA_PARSER_RUNTIME_BUFFER_SIZE);
- if (!esp_gps->buffer) {
- ESP_LOGE(GPS_TAG, "calloc memory for runtime buffer failed");
- goto err_buffer;
- }
- #if CONFIG_NMEA_STATEMENT_GSA
- esp_gps->all_statements |= (1 << STATEMENT_GSA);
- #endif
- #if CONFIG_NMEA_STATEMENT_GSV
- esp_gps->all_statements |= (1 << STATEMENT_GSV);
- #endif
- #if CONFIG_NMEA_STATEMENT_GGA
- esp_gps->all_statements |= (1 << STATEMENT_GGA);
- #endif
- #if CONFIG_NMEA_STATEMENT_RMC
- esp_gps->all_statements |= (1 << STATEMENT_RMC);
- #endif
- #if CONFIG_NMEA_STATEMENT_GLL
- esp_gps->all_statements |= (1 << STATEMENT_GLL);
- #endif
- #if CONFIG_NMEA_STATEMENT_VTG
- esp_gps->all_statements |= (1 << STATEMENT_VTG);
- #endif
- /* Set attributes */
- esp_gps->uart_port = config->uart.uart_port;
- esp_gps->all_statements &= 0xFE;
- /* Install UART friver */
- uart_config_t uart_config = {
- .baud_rate = config->uart.baud_rate,
- .data_bits = config->uart.data_bits,
- .parity = config->uart.parity,
- .stop_bits = config->uart.stop_bits,
- .flow_ctrl = UART_HW_FLOWCTRL_DISABLE,
- .source_clk = UART_SCLK_APB,
- };
- if (uart_driver_install(esp_gps->uart_port, CONFIG_NMEA_PARSER_RING_BUFFER_SIZE, 0,
- config->uart.event_queue_size, &esp_gps->event_queue, 0) != ESP_OK) {
- ESP_LOGE(GPS_TAG, "install uart driver failed");
- goto err_uart_install;
- }
- if (uart_param_config(esp_gps->uart_port, &uart_config) != ESP_OK) {
- ESP_LOGE(GPS_TAG, "config uart parameter failed");
- goto err_uart_config;
- }
- if (uart_set_pin(esp_gps->uart_port, UART_PIN_NO_CHANGE, config->uart.rx_pin,
- UART_PIN_NO_CHANGE, UART_PIN_NO_CHANGE) != ESP_OK) {
- ESP_LOGE(GPS_TAG, "config uart gpio failed");
- goto err_uart_config;
- }
- /* Set pattern interrupt, used to detect the end of a line */
- uart_enable_pattern_det_baud_intr(esp_gps->uart_port, '\n', 1, 9, 0, 0);
- /* Set pattern queue size */
- uart_pattern_queue_reset(esp_gps->uart_port, config->uart.event_queue_size);
- uart_flush(esp_gps->uart_port);
- /* Create Event loop */
- esp_event_loop_args_t loop_args = {
- .queue_size = NMEA_EVENT_LOOP_QUEUE_SIZE,
- .task_name = NULL
- };
- if (esp_event_loop_create(&loop_args, &esp_gps->event_loop_hdl) != ESP_OK) {
- ESP_LOGE(GPS_TAG, "create event loop faild");
- goto err_eloop;
- }
- /* Create NMEA Parser task */
- BaseType_t err = xTaskCreate(
- nmea_parser_task_entry,
- "nmea_parser",
- CONFIG_NMEA_PARSER_TASK_STACK_SIZE,
- esp_gps,
- CONFIG_NMEA_PARSER_TASK_PRIORITY,
- &esp_gps->tsk_hdl);
- if (err != pdTRUE) {
- ESP_LOGE(GPS_TAG, "create NMEA Parser task failed");
- goto err_task_create;
- }
- ESP_LOGI(GPS_TAG, "NMEA Parser init OK");
- return esp_gps;
- /*Error Handling*/
- err_task_create:
- esp_event_loop_delete(esp_gps->event_loop_hdl);
- err_eloop:
- err_uart_install:
- uart_driver_delete(esp_gps->uart_port);
- err_uart_config:
- err_buffer:
- free(esp_gps->buffer);
- err_gps:
- free(esp_gps);
- return NULL;
- }
- /**
- * @brief Deinit NMEA Parser
- *
- * @param nmea_hdl handle of NMEA parser
- * @return esp_err_t ESP_OK on success,ESP_FAIL on error
- */
- esp_err_t nmea_parser_deinit(nmea_parser_handle_t nmea_hdl)
- {
- esp_gps_t *esp_gps = (esp_gps_t *)nmea_hdl;
- vTaskDelete(esp_gps->tsk_hdl);
- esp_event_loop_delete(esp_gps->event_loop_hdl);
- esp_err_t err = uart_driver_delete(esp_gps->uart_port);
- free(esp_gps->buffer);
- free(esp_gps);
- return err;
- }
- /**
- * @brief Add user defined handler for NMEA parser
- *
- * @param nmea_hdl handle of NMEA parser
- * @param event_handler user defined event handler
- * @param handler_args handler specific arguments
- * @return esp_err_t
- * - ESP_OK: Success
- * - ESP_ERR_NO_MEM: Cannot allocate memory for the handler
- * - ESP_ERR_INVALIG_ARG: Invalid combination of event base and event id
- * - Others: Fail
- */
- esp_err_t nmea_parser_add_handler(nmea_parser_handle_t nmea_hdl, esp_event_handler_t event_handler, void *handler_args)
- {
- esp_gps_t *esp_gps = (esp_gps_t *)nmea_hdl;
- return esp_event_handler_register_with(esp_gps->event_loop_hdl, ESP_NMEA_EVENT, ESP_EVENT_ANY_ID,
- event_handler, handler_args);
- }
- /**
- * @brief Remove user defined handler for NMEA parser
- *
- * @param nmea_hdl handle of NMEA parser
- * @param event_handler user defined event handler
- * @return esp_err_t
- * - ESP_OK: Success
- * - ESP_ERR_INVALIG_ARG: Invalid combination of event base and event id
- * - Others: Fail
- */
- esp_err_t nmea_parser_remove_handler(nmea_parser_handle_t nmea_hdl, esp_event_handler_t event_handler)
- {
- esp_gps_t *esp_gps = (esp_gps_t *)nmea_hdl;
- return esp_event_handler_unregister_with(esp_gps->event_loop_hdl, ESP_NMEA_EVENT, ESP_EVENT_ANY_ID, event_handler);
- }
|