nmea_parser.c 26 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794
  1. // Copyright 2015-2018 Espressif Systems (Shanghai) PTE LTD
  2. //
  3. // Licensed under the Apache License, Version 2.0 (the "License");
  4. // you may not use this file except in compliance with the License.
  5. // You may obtain a copy of the License at
  6. //
  7. // http://www.apache.org/licenses/LICENSE-2.0
  8. //
  9. // Unless required by applicable law or agreed to in writing, software
  10. // distributed under the License is distributed on an "AS IS" BASIS,
  11. // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  12. // See the License for the specific language governing permissions and
  13. // limitations under the License.
  14. #include <stdlib.h>
  15. #include <string.h>
  16. #include <ctype.h>
  17. #include <math.h>
  18. #include "freertos/FreeRTOS.h"
  19. #include "freertos/task.h"
  20. #include "esp_log.h"
  21. #include "nmea_parser.h"
  22. /**
  23. * @brief NMEA Parser runtime buffer size
  24. *
  25. */
  26. #define NMEA_PARSER_RUNTIME_BUFFER_SIZE (CONFIG_NMEA_PARSER_RING_BUFFER_SIZE / 2)
  27. #define NMEA_MAX_STATEMENT_ITEM_LENGTH (16)
  28. #define NMEA_EVENT_LOOP_QUEUE_SIZE (16)
  29. /**
  30. * @brief Define of NMEA Parser Event base
  31. *
  32. */
  33. ESP_EVENT_DEFINE_BASE(ESP_NMEA_EVENT);
  34. static const char *GPS_TAG = "nmea_parser";
  35. /**
  36. * @brief GPS parser library runtime structure
  37. *
  38. */
  39. typedef struct {
  40. uint8_t item_pos; /*!< Current position in item */
  41. uint8_t item_num; /*!< Current item number */
  42. uint8_t asterisk; /*!< Asterisk detected flag */
  43. uint8_t crc; /*!< Calculated CRC value */
  44. uint8_t parsed_statement; /*!< OR'd of statements that have been parsed */
  45. uint8_t sat_num; /*!< Satellite number */
  46. uint8_t sat_count; /*!< Satellite count */
  47. uint8_t cur_statement; /*!< Current statement ID */
  48. uint32_t all_statements; /*!< All statements mask */
  49. char item_str[NMEA_MAX_STATEMENT_ITEM_LENGTH]; /*!< Current item */
  50. gps_t parent; /*!< Parent class */
  51. uart_port_t uart_port; /*!< Uart port number */
  52. uint8_t *buffer; /*!< Runtime buffer */
  53. esp_event_loop_handle_t event_loop_hdl; /*!< Event loop handle */
  54. TaskHandle_t tsk_hdl; /*!< NMEA Parser task handle */
  55. QueueHandle_t event_queue; /*!< UART event queue handle */
  56. } esp_gps_t;
  57. /**
  58. * @brief parse latitude or longitude
  59. * format of latitude in NMEA is ddmm.sss and longitude is dddmm.sss
  60. * @param esp_gps esp_gps_t type object
  61. * @return float Latitude or Longitude value (unit: degree)
  62. */
  63. static float parse_lat_long(esp_gps_t *esp_gps)
  64. {
  65. float ll = strtof(esp_gps->item_str, NULL);
  66. int deg = ((int)ll) / 100;
  67. float min = ll - (deg * 100);
  68. ll = deg + min / 60.0f;
  69. return ll;
  70. }
  71. /**
  72. * @brief Converter two continuous numeric character into a uint8_t number
  73. *
  74. * @param digit_char numeric character
  75. * @return uint8_t result of converting
  76. */
  77. static inline uint8_t convert_two_digit2number(const char *digit_char)
  78. {
  79. return 10 * (digit_char[0] - '0') + (digit_char[1] - '0');
  80. }
  81. /**
  82. * @brief Parse UTC time in GPS statements
  83. *
  84. * @param esp_gps esp_gps_t type object
  85. */
  86. static void parse_utc_time(esp_gps_t *esp_gps)
  87. {
  88. esp_gps->parent.tim.hour = convert_two_digit2number(esp_gps->item_str + 0);
  89. esp_gps->parent.tim.minute = convert_two_digit2number(esp_gps->item_str + 2);
  90. esp_gps->parent.tim.second = convert_two_digit2number(esp_gps->item_str + 4);
  91. if (esp_gps->item_str[6] == '.') {
  92. uint16_t tmp = 0;
  93. uint8_t i = 7;
  94. while (esp_gps->item_str[i]) {
  95. tmp = 10 * tmp + esp_gps->item_str[i] - '0';
  96. i++;
  97. }
  98. esp_gps->parent.tim.thousand = tmp;
  99. }
  100. }
  101. #if CONFIG_NMEA_STATEMENT_GGA
  102. /**
  103. * @brief Parse GGA statements
  104. *
  105. * @param esp_gps esp_gps_t type object
  106. */
  107. static void parse_gga(esp_gps_t *esp_gps)
  108. {
  109. /* Process GGA statement */
  110. switch (esp_gps->item_num) {
  111. case 1: /* Process UTC time */
  112. parse_utc_time(esp_gps);
  113. break;
  114. case 2: /* Latitude */
  115. esp_gps->parent.latitude = parse_lat_long(esp_gps);
  116. break;
  117. case 3: /* Latitude north(1)/south(-1) information */
  118. if (esp_gps->item_str[0] == 'S' || esp_gps->item_str[0] == 's') {
  119. esp_gps->parent.latitude *= -1;
  120. }
  121. break;
  122. case 4: /* Longitude */
  123. esp_gps->parent.longitude = parse_lat_long(esp_gps);
  124. break;
  125. case 5: /* Longitude east(1)/west(-1) information */
  126. if (esp_gps->item_str[0] == 'W' || esp_gps->item_str[0] == 'w') {
  127. esp_gps->parent.longitude *= -1;
  128. }
  129. break;
  130. case 6: /* Fix status */
  131. esp_gps->parent.fix = (gps_fix_t)strtol(esp_gps->item_str, NULL, 10);
  132. break;
  133. case 7: /* Satellites in use */
  134. esp_gps->parent.sats_in_use = (uint8_t)strtol(esp_gps->item_str, NULL, 10);
  135. break;
  136. case 8: /* HDOP */
  137. esp_gps->parent.dop_h = strtof(esp_gps->item_str, NULL);
  138. break;
  139. case 9: /* Altitude */
  140. esp_gps->parent.altitude = strtof(esp_gps->item_str, NULL);
  141. break;
  142. case 11: /* Altitude above ellipsoid */
  143. esp_gps->parent.altitude += strtof(esp_gps->item_str, NULL);
  144. break;
  145. default:
  146. break;
  147. }
  148. }
  149. #endif
  150. #if CONFIG_NMEA_STATEMENT_GSA
  151. /**
  152. * @brief Parse GSA statements
  153. *
  154. * @param esp_gps esp_gps_t type object
  155. */
  156. static void parse_gsa(esp_gps_t *esp_gps)
  157. {
  158. /* Process GSA statement */
  159. switch (esp_gps->item_num) {
  160. case 2: /* Process fix mode */
  161. esp_gps->parent.fix_mode = (gps_fix_mode_t)strtol(esp_gps->item_str, NULL, 10);
  162. break;
  163. case 15: /* Process PDOP */
  164. esp_gps->parent.dop_p = strtof(esp_gps->item_str, NULL);
  165. break;
  166. case 16: /* Process HDOP */
  167. esp_gps->parent.dop_h = strtof(esp_gps->item_str, NULL);
  168. break;
  169. case 17: /* Process VDOP */
  170. esp_gps->parent.dop_v = strtof(esp_gps->item_str, NULL);
  171. break;
  172. default:
  173. /* Parse satellite IDs */
  174. if (esp_gps->item_num >= 3 && esp_gps->item_num <= 14) {
  175. esp_gps->parent.sats_id_in_use[esp_gps->item_num - 3] = (uint8_t)strtol(esp_gps->item_str, NULL, 10);
  176. }
  177. break;
  178. }
  179. }
  180. #endif
  181. #if CONFIG_NMEA_STATEMENT_GSV
  182. /**
  183. * @brief Parse GSV statements
  184. *
  185. * @param esp_gps esp_gps_t type object
  186. */
  187. static void parse_gsv(esp_gps_t *esp_gps)
  188. {
  189. /* Process GSV statement */
  190. switch (esp_gps->item_num) {
  191. case 1: /* total GSV numbers */
  192. esp_gps->sat_count = (uint8_t)strtol(esp_gps->item_str, NULL, 10);
  193. break;
  194. case 2: /* Current GSV statement number */
  195. esp_gps->sat_num = (uint8_t)strtol(esp_gps->item_str, NULL, 10);
  196. break;
  197. case 3: /* Process satellites in view */
  198. esp_gps->parent.sats_in_view = (uint8_t)strtol(esp_gps->item_str, NULL, 10);
  199. break;
  200. default:
  201. if (esp_gps->item_num >= 4 && esp_gps->item_num <= 19) {
  202. uint8_t item_num = esp_gps->item_num - 4; /* Normalize item number from 4-19 to 0-15 */
  203. uint8_t index;
  204. uint32_t value;
  205. index = 4 * (esp_gps->sat_num - 1) + item_num / 4; /* Get array index */
  206. if (index < GPS_MAX_SATELLITES_IN_VIEW) {
  207. value = strtol(esp_gps->item_str, NULL, 10);
  208. switch (item_num % 4) {
  209. case 0:
  210. esp_gps->parent.sats_desc_in_view[index].num = (uint8_t)value;
  211. break;
  212. case 1:
  213. esp_gps->parent.sats_desc_in_view[index].elevation = (uint8_t)value;
  214. break;
  215. case 2:
  216. esp_gps->parent.sats_desc_in_view[index].azimuth = (uint16_t)value;
  217. break;
  218. case 3:
  219. esp_gps->parent.sats_desc_in_view[index].snr = (uint8_t)value;
  220. break;
  221. default:
  222. break;
  223. }
  224. }
  225. }
  226. break;
  227. }
  228. }
  229. #endif
  230. #if CONFIG_NMEA_STATEMENT_RMC
  231. /**
  232. * @brief Parse RMC statements
  233. *
  234. * @param esp_gps esp_gps_t type object
  235. */
  236. static void parse_rmc(esp_gps_t *esp_gps)
  237. {
  238. /* Process GPRMC statement */
  239. switch (esp_gps->item_num) {
  240. case 1:/* Process UTC time */
  241. parse_utc_time(esp_gps);
  242. break;
  243. case 2: /* Process valid status */
  244. esp_gps->parent.valid = (esp_gps->item_str[0] == 'A');
  245. break;
  246. case 3:/* Latitude */
  247. esp_gps->parent.latitude = parse_lat_long(esp_gps);
  248. break;
  249. case 4: /* Latitude north(1)/south(-1) information */
  250. if (esp_gps->item_str[0] == 'S' || esp_gps->item_str[0] == 's') {
  251. esp_gps->parent.latitude *= -1;
  252. }
  253. break;
  254. case 5: /* Longitude */
  255. esp_gps->parent.longitude = parse_lat_long(esp_gps);
  256. break;
  257. case 6: /* Longitude east(1)/west(-1) information */
  258. if (esp_gps->item_str[0] == 'W' || esp_gps->item_str[0] == 'w') {
  259. esp_gps->parent.longitude *= -1;
  260. }
  261. break;
  262. case 7: /* Process ground speed in unit m/s */
  263. esp_gps->parent.speed = strtof(esp_gps->item_str, NULL) * 1.852;
  264. break;
  265. case 8: /* Process true course over ground */
  266. esp_gps->parent.cog = strtof(esp_gps->item_str, NULL);
  267. break;
  268. case 9: /* Process date */
  269. esp_gps->parent.date.day = convert_two_digit2number(esp_gps->item_str + 0);
  270. esp_gps->parent.date.month = convert_two_digit2number(esp_gps->item_str + 2);
  271. esp_gps->parent.date.year = convert_two_digit2number(esp_gps->item_str + 4);
  272. break;
  273. case 10: /* Process magnetic variation */
  274. esp_gps->parent.variation = strtof(esp_gps->item_str, NULL);
  275. break;
  276. default:
  277. break;
  278. }
  279. }
  280. #endif
  281. #if CONFIG_NMEA_STATEMENT_GLL
  282. /**
  283. * @brief Parse GLL statements
  284. *
  285. * @param esp_gps esp_gps_t type object
  286. */
  287. static void parse_gll(esp_gps_t *esp_gps)
  288. {
  289. /* Process GPGLL statement */
  290. switch (esp_gps->item_num) {
  291. case 1:/* Latitude */
  292. esp_gps->parent.latitude = parse_lat_long(esp_gps);
  293. break;
  294. case 2: /* Latitude north(1)/south(-1) information */
  295. if (esp_gps->item_str[0] == 'S' || esp_gps->item_str[0] == 's') {
  296. esp_gps->parent.latitude *= -1;
  297. }
  298. break;
  299. case 3: /* Longitude */
  300. esp_gps->parent.longitude = parse_lat_long(esp_gps);
  301. break;
  302. case 4: /* Longitude east(1)/west(-1) information */
  303. if (esp_gps->item_str[0] == 'W' || esp_gps->item_str[0] == 'w') {
  304. esp_gps->parent.longitude *= -1;
  305. }
  306. break;
  307. case 5:/* Process UTC time */
  308. parse_utc_time(esp_gps);
  309. break;
  310. case 6: /* Process valid status */
  311. esp_gps->parent.valid = (esp_gps->item_str[0] == 'A');
  312. break;
  313. default:
  314. break;
  315. }
  316. }
  317. #endif
  318. #if CONFIG_NMEA_STATEMENT_VTG
  319. /**
  320. * @brief Parse VTG statements
  321. *
  322. * @param esp_gps esp_gps_t type object
  323. */
  324. static void parse_vtg(esp_gps_t *esp_gps)
  325. {
  326. /* Process GPVGT statement */
  327. switch (esp_gps->item_num) {
  328. case 1: /* Process true course over ground */
  329. esp_gps->parent.cog = strtof(esp_gps->item_str, NULL);
  330. break;
  331. case 3:/* Process magnetic variation */
  332. esp_gps->parent.variation = strtof(esp_gps->item_str, NULL);
  333. break;
  334. case 5:/* Process ground speed in unit m/s */
  335. esp_gps->parent.speed = strtof(esp_gps->item_str, NULL) * 1.852;//knots to m/s
  336. break;
  337. case 7:/* Process ground speed in unit m/s */
  338. esp_gps->parent.speed = strtof(esp_gps->item_str, NULL) / 3.6;//km/h to m/s
  339. break;
  340. default:
  341. break;
  342. }
  343. }
  344. #endif
  345. /**
  346. * @brief Parse received item
  347. *
  348. * @param esp_gps esp_gps_t type object
  349. * @return esp_err_t ESP_OK on success, ESP_FAIL on error
  350. */
  351. static esp_err_t parse_item(esp_gps_t *esp_gps)
  352. {
  353. esp_err_t err = ESP_OK;
  354. /* start of a statement */
  355. if (esp_gps->item_num == 0 && esp_gps->item_str[0] == '$') {
  356. if (0) {
  357. }
  358. #if CONFIG_NMEA_STATEMENT_GGA
  359. else if (strstr(esp_gps->item_str, "GGA")) {
  360. esp_gps->cur_statement = STATEMENT_GGA;
  361. }
  362. #endif
  363. #if CONFIG_NMEA_STATEMENT_GSA
  364. else if (strstr(esp_gps->item_str, "GSA")) {
  365. esp_gps->cur_statement = STATEMENT_GSA;
  366. }
  367. #endif
  368. #if CONFIG_NMEA_STATEMENT_RMC
  369. else if (strstr(esp_gps->item_str, "RMC")) {
  370. esp_gps->cur_statement = STATEMENT_RMC;
  371. }
  372. #endif
  373. #if CONFIG_NMEA_STATEMENT_GSV
  374. else if (strstr(esp_gps->item_str, "GSV")) {
  375. esp_gps->cur_statement = STATEMENT_GSV;
  376. }
  377. #endif
  378. #if CONFIG_NMEA_STATEMENT_GLL
  379. else if (strstr(esp_gps->item_str, "GLL")) {
  380. esp_gps->cur_statement = STATEMENT_GLL;
  381. }
  382. #endif
  383. #if CONFIG_NMEA_STATEMENT_VTG
  384. else if (strstr(esp_gps->item_str, "VTG")) {
  385. esp_gps->cur_statement = STATEMENT_VTG;
  386. }
  387. #endif
  388. else {
  389. esp_gps->cur_statement = STATEMENT_UNKNOWN;
  390. }
  391. goto out;
  392. }
  393. /* Parse each item, depend on the type of the statement */
  394. if (esp_gps->cur_statement == STATEMENT_UNKNOWN) {
  395. goto out;
  396. }
  397. #if CONFIG_NMEA_STATEMENT_GGA
  398. else if (esp_gps->cur_statement == STATEMENT_GGA) {
  399. parse_gga(esp_gps);
  400. }
  401. #endif
  402. #if CONFIG_NMEA_STATEMENT_GSA
  403. else if (esp_gps->cur_statement == STATEMENT_GSA) {
  404. parse_gsa(esp_gps);
  405. }
  406. #endif
  407. #if CONFIG_NMEA_STATEMENT_GSV
  408. else if (esp_gps->cur_statement == STATEMENT_GSV) {
  409. parse_gsv(esp_gps);
  410. }
  411. #endif
  412. #if CONFIG_NMEA_STATEMENT_RMC
  413. else if (esp_gps->cur_statement == STATEMENT_RMC) {
  414. parse_rmc(esp_gps);
  415. }
  416. #endif
  417. #if CONFIG_NMEA_STATEMENT_GLL
  418. else if (esp_gps->cur_statement == STATEMENT_GLL) {
  419. parse_gll(esp_gps);
  420. }
  421. #endif
  422. #if CONFIG_NMEA_STATEMENT_VTG
  423. else if (esp_gps->cur_statement == STATEMENT_VTG) {
  424. parse_vtg(esp_gps);
  425. }
  426. #endif
  427. else {
  428. err = ESP_FAIL;
  429. }
  430. out:
  431. return err;
  432. }
  433. /**
  434. * @brief Parse NMEA statements from GPS receiver
  435. *
  436. * @param esp_gps esp_gps_t type object
  437. * @param len number of bytes to decode
  438. * @return esp_err_t ESP_OK on success, ESP_FAIL on error
  439. */
  440. static esp_err_t gps_decode(esp_gps_t *esp_gps, size_t len)
  441. {
  442. const uint8_t *d = esp_gps->buffer;
  443. while (*d) {
  444. /* Start of a statement */
  445. if (*d == '$') {
  446. /* Reset runtime information */
  447. esp_gps->asterisk = 0;
  448. esp_gps->item_num = 0;
  449. esp_gps->item_pos = 0;
  450. esp_gps->cur_statement = 0;
  451. esp_gps->crc = 0;
  452. esp_gps->sat_count = 0;
  453. esp_gps->sat_num = 0;
  454. /* Add character to item */
  455. esp_gps->item_str[esp_gps->item_pos++] = *d;
  456. esp_gps->item_str[esp_gps->item_pos] = '\0';
  457. }
  458. /* Detect item separator character */
  459. else if (*d == ',') {
  460. /* Parse current item */
  461. parse_item(esp_gps);
  462. /* Add character to CRC computation */
  463. esp_gps->crc ^= (uint8_t)(*d);
  464. /* Start with next item */
  465. esp_gps->item_pos = 0;
  466. esp_gps->item_str[0] = '\0';
  467. esp_gps->item_num++;
  468. }
  469. /* End of CRC computation */
  470. else if (*d == '*') {
  471. /* Parse current item */
  472. parse_item(esp_gps);
  473. /* Asterisk detected */
  474. esp_gps->asterisk = 1;
  475. /* Start with next item */
  476. esp_gps->item_pos = 0;
  477. esp_gps->item_str[0] = '\0';
  478. esp_gps->item_num++;
  479. }
  480. /* End of statement */
  481. else if (*d == '\r') {
  482. /* Convert received CRC from string (hex) to number */
  483. uint8_t crc = (uint8_t)strtol(esp_gps->item_str, NULL, 16);
  484. /* CRC passed */
  485. if (esp_gps->crc == crc) {
  486. switch (esp_gps->cur_statement) {
  487. #if CONFIG_NMEA_STATEMENT_GGA
  488. case STATEMENT_GGA:
  489. esp_gps->parsed_statement |= 1 << STATEMENT_GGA;
  490. break;
  491. #endif
  492. #if CONFIG_NMEA_STATEMENT_GSA
  493. case STATEMENT_GSA:
  494. esp_gps->parsed_statement |= 1 << STATEMENT_GSA;
  495. break;
  496. #endif
  497. #if CONFIG_NMEA_STATEMENT_RMC
  498. case STATEMENT_RMC:
  499. esp_gps->parsed_statement |= 1 << STATEMENT_RMC;
  500. break;
  501. #endif
  502. #if CONFIG_NMEA_STATEMENT_GSV
  503. case STATEMENT_GSV:
  504. if (esp_gps->sat_num == esp_gps->sat_count) {
  505. esp_gps->parsed_statement |= 1 << STATEMENT_GSV;
  506. }
  507. break;
  508. #endif
  509. #if CONFIG_NMEA_STATEMENT_GLL
  510. case STATEMENT_GLL:
  511. esp_gps->parsed_statement |= 1 << STATEMENT_GLL;
  512. break;
  513. #endif
  514. #if CONFIG_NMEA_STATEMENT_VTG
  515. case STATEMENT_VTG:
  516. esp_gps->parsed_statement |= 1 << STATEMENT_VTG;
  517. break;
  518. #endif
  519. default:
  520. break;
  521. }
  522. /* Check if all statements have been parsed */
  523. if (((esp_gps->parsed_statement) & esp_gps->all_statements) == esp_gps->all_statements) {
  524. esp_gps->parsed_statement = 0;
  525. /* Send signal to notify that GPS information has been updated */
  526. esp_event_post_to(esp_gps->event_loop_hdl, ESP_NMEA_EVENT, GPS_UPDATE,
  527. &(esp_gps->parent), sizeof(gps_t), 100 / portTICK_PERIOD_MS);
  528. }
  529. } else {
  530. ESP_LOGD(GPS_TAG, "CRC Error for statement:%s", esp_gps->buffer);
  531. }
  532. if (esp_gps->cur_statement == STATEMENT_UNKNOWN) {
  533. /* Send signal to notify that one unknown statement has been met */
  534. esp_event_post_to(esp_gps->event_loop_hdl, ESP_NMEA_EVENT, GPS_UNKNOWN,
  535. esp_gps->buffer, len, 100 / portTICK_PERIOD_MS);
  536. }
  537. }
  538. /* Other non-space character */
  539. else {
  540. if (!(esp_gps->asterisk)) {
  541. /* Add to CRC */
  542. esp_gps->crc ^= (uint8_t)(*d);
  543. }
  544. /* Add character to item */
  545. esp_gps->item_str[esp_gps->item_pos++] = *d;
  546. esp_gps->item_str[esp_gps->item_pos] = '\0';
  547. }
  548. /* Process next character */
  549. d++;
  550. }
  551. return ESP_OK;
  552. }
  553. /**
  554. * @brief Handle when a pattern has been detected by uart
  555. *
  556. * @param esp_gps esp_gps_t type object
  557. */
  558. static void esp_handle_uart_pattern(esp_gps_t *esp_gps)
  559. {
  560. int pos = uart_pattern_pop_pos(esp_gps->uart_port);
  561. if (pos != -1) {
  562. /* read one line(include '\n') */
  563. int read_len = uart_read_bytes(esp_gps->uart_port, esp_gps->buffer, pos + 1, 100 / portTICK_PERIOD_MS);
  564. /* make sure the line is a standard string */
  565. esp_gps->buffer[read_len] = '\0';
  566. /* Send new line to handle */
  567. if (gps_decode(esp_gps, read_len + 1) != ESP_OK) {
  568. ESP_LOGW(GPS_TAG, "GPS decode line failed");
  569. }
  570. } else {
  571. ESP_LOGW(GPS_TAG, "Pattern Queue Size too small");
  572. uart_flush_input(esp_gps->uart_port);
  573. }
  574. }
  575. /**
  576. * @brief NMEA Parser Task Entry
  577. *
  578. * @param arg argument
  579. */
  580. static void nmea_parser_task_entry(void *arg)
  581. {
  582. esp_gps_t *esp_gps = (esp_gps_t *)arg;
  583. uart_event_t event;
  584. while (1) {
  585. if (xQueueReceive(esp_gps->event_queue, &event, pdMS_TO_TICKS(200))) {
  586. switch (event.type) {
  587. case UART_DATA:
  588. break;
  589. case UART_FIFO_OVF:
  590. ESP_LOGW(GPS_TAG, "HW FIFO Overflow");
  591. uart_flush(esp_gps->uart_port);
  592. xQueueReset(esp_gps->event_queue);
  593. break;
  594. case UART_BUFFER_FULL:
  595. ESP_LOGW(GPS_TAG, "Ring Buffer Full");
  596. uart_flush(esp_gps->uart_port);
  597. xQueueReset(esp_gps->event_queue);
  598. break;
  599. case UART_BREAK:
  600. ESP_LOGW(GPS_TAG, "Rx Break");
  601. break;
  602. case UART_PARITY_ERR:
  603. ESP_LOGE(GPS_TAG, "Parity Error");
  604. break;
  605. case UART_FRAME_ERR:
  606. ESP_LOGE(GPS_TAG, "Frame Error");
  607. break;
  608. case UART_PATTERN_DET:
  609. esp_handle_uart_pattern(esp_gps);
  610. break;
  611. default:
  612. ESP_LOGW(GPS_TAG, "unknown uart event type: %d", event.type);
  613. break;
  614. }
  615. }
  616. /* Drive the event loop */
  617. esp_event_loop_run(esp_gps->event_loop_hdl, pdMS_TO_TICKS(50));
  618. }
  619. vTaskDelete(NULL);
  620. }
  621. /**
  622. * @brief Init NMEA Parser
  623. *
  624. * @param config Configuration of NMEA Parser
  625. * @return nmea_parser_handle_t handle of nmea_parser
  626. */
  627. nmea_parser_handle_t nmea_parser_init(const nmea_parser_config_t *config)
  628. {
  629. esp_gps_t *esp_gps = calloc(1, sizeof(esp_gps_t));
  630. if (!esp_gps) {
  631. ESP_LOGE(GPS_TAG, "calloc memory for esp_fps failed");
  632. goto err_gps;
  633. }
  634. esp_gps->buffer = calloc(1, NMEA_PARSER_RUNTIME_BUFFER_SIZE);
  635. if (!esp_gps->buffer) {
  636. ESP_LOGE(GPS_TAG, "calloc memory for runtime buffer failed");
  637. goto err_buffer;
  638. }
  639. #if CONFIG_NMEA_STATEMENT_GSA
  640. esp_gps->all_statements |= (1 << STATEMENT_GSA);
  641. #endif
  642. #if CONFIG_NMEA_STATEMENT_GSV
  643. esp_gps->all_statements |= (1 << STATEMENT_GSV);
  644. #endif
  645. #if CONFIG_NMEA_STATEMENT_GGA
  646. esp_gps->all_statements |= (1 << STATEMENT_GGA);
  647. #endif
  648. #if CONFIG_NMEA_STATEMENT_RMC
  649. esp_gps->all_statements |= (1 << STATEMENT_RMC);
  650. #endif
  651. #if CONFIG_NMEA_STATEMENT_GLL
  652. esp_gps->all_statements |= (1 << STATEMENT_GLL);
  653. #endif
  654. #if CONFIG_NMEA_STATEMENT_VTG
  655. esp_gps->all_statements |= (1 << STATEMENT_VTG);
  656. #endif
  657. /* Set attributes */
  658. esp_gps->uart_port = config->uart.uart_port;
  659. esp_gps->all_statements &= 0xFE;
  660. /* Install UART friver */
  661. uart_config_t uart_config = {
  662. .baud_rate = config->uart.baud_rate,
  663. .data_bits = config->uart.data_bits,
  664. .parity = config->uart.parity,
  665. .stop_bits = config->uart.stop_bits,
  666. .flow_ctrl = UART_HW_FLOWCTRL_DISABLE,
  667. .source_clk = UART_SCLK_APB,
  668. };
  669. if (uart_driver_install(esp_gps->uart_port, CONFIG_NMEA_PARSER_RING_BUFFER_SIZE, 0,
  670. config->uart.event_queue_size, &esp_gps->event_queue, 0) != ESP_OK) {
  671. ESP_LOGE(GPS_TAG, "install uart driver failed");
  672. goto err_uart_install;
  673. }
  674. if (uart_param_config(esp_gps->uart_port, &uart_config) != ESP_OK) {
  675. ESP_LOGE(GPS_TAG, "config uart parameter failed");
  676. goto err_uart_config;
  677. }
  678. if (uart_set_pin(esp_gps->uart_port, UART_PIN_NO_CHANGE, config->uart.rx_pin,
  679. UART_PIN_NO_CHANGE, UART_PIN_NO_CHANGE) != ESP_OK) {
  680. ESP_LOGE(GPS_TAG, "config uart gpio failed");
  681. goto err_uart_config;
  682. }
  683. /* Set pattern interrupt, used to detect the end of a line */
  684. uart_enable_pattern_det_baud_intr(esp_gps->uart_port, '\n', 1, 9, 0, 0);
  685. /* Set pattern queue size */
  686. uart_pattern_queue_reset(esp_gps->uart_port, config->uart.event_queue_size);
  687. uart_flush(esp_gps->uart_port);
  688. /* Create Event loop */
  689. esp_event_loop_args_t loop_args = {
  690. .queue_size = NMEA_EVENT_LOOP_QUEUE_SIZE,
  691. .task_name = NULL
  692. };
  693. if (esp_event_loop_create(&loop_args, &esp_gps->event_loop_hdl) != ESP_OK) {
  694. ESP_LOGE(GPS_TAG, "create event loop faild");
  695. goto err_eloop;
  696. }
  697. /* Create NMEA Parser task */
  698. BaseType_t err = xTaskCreate(
  699. nmea_parser_task_entry,
  700. "nmea_parser",
  701. CONFIG_NMEA_PARSER_TASK_STACK_SIZE,
  702. esp_gps,
  703. CONFIG_NMEA_PARSER_TASK_PRIORITY,
  704. &esp_gps->tsk_hdl);
  705. if (err != pdTRUE) {
  706. ESP_LOGE(GPS_TAG, "create NMEA Parser task failed");
  707. goto err_task_create;
  708. }
  709. ESP_LOGI(GPS_TAG, "NMEA Parser init OK");
  710. return esp_gps;
  711. /*Error Handling*/
  712. err_task_create:
  713. esp_event_loop_delete(esp_gps->event_loop_hdl);
  714. err_eloop:
  715. err_uart_install:
  716. uart_driver_delete(esp_gps->uart_port);
  717. err_uart_config:
  718. err_buffer:
  719. free(esp_gps->buffer);
  720. err_gps:
  721. free(esp_gps);
  722. return NULL;
  723. }
  724. /**
  725. * @brief Deinit NMEA Parser
  726. *
  727. * @param nmea_hdl handle of NMEA parser
  728. * @return esp_err_t ESP_OK on success,ESP_FAIL on error
  729. */
  730. esp_err_t nmea_parser_deinit(nmea_parser_handle_t nmea_hdl)
  731. {
  732. esp_gps_t *esp_gps = (esp_gps_t *)nmea_hdl;
  733. vTaskDelete(esp_gps->tsk_hdl);
  734. esp_event_loop_delete(esp_gps->event_loop_hdl);
  735. esp_err_t err = uart_driver_delete(esp_gps->uart_port);
  736. free(esp_gps->buffer);
  737. free(esp_gps);
  738. return err;
  739. }
  740. /**
  741. * @brief Add user defined handler for NMEA parser
  742. *
  743. * @param nmea_hdl handle of NMEA parser
  744. * @param event_handler user defined event handler
  745. * @param handler_args handler specific arguments
  746. * @return esp_err_t
  747. * - ESP_OK: Success
  748. * - ESP_ERR_NO_MEM: Cannot allocate memory for the handler
  749. * - ESP_ERR_INVALIG_ARG: Invalid combination of event base and event id
  750. * - Others: Fail
  751. */
  752. esp_err_t nmea_parser_add_handler(nmea_parser_handle_t nmea_hdl, esp_event_handler_t event_handler, void *handler_args)
  753. {
  754. esp_gps_t *esp_gps = (esp_gps_t *)nmea_hdl;
  755. return esp_event_handler_register_with(esp_gps->event_loop_hdl, ESP_NMEA_EVENT, ESP_EVENT_ANY_ID,
  756. event_handler, handler_args);
  757. }
  758. /**
  759. * @brief Remove user defined handler for NMEA parser
  760. *
  761. * @param nmea_hdl handle of NMEA parser
  762. * @param event_handler user defined event handler
  763. * @return esp_err_t
  764. * - ESP_OK: Success
  765. * - ESP_ERR_INVALIG_ARG: Invalid combination of event base and event id
  766. * - Others: Fail
  767. */
  768. esp_err_t nmea_parser_remove_handler(nmea_parser_handle_t nmea_hdl, esp_event_handler_t event_handler)
  769. {
  770. esp_gps_t *esp_gps = (esp_gps_t *)nmea_hdl;
  771. return esp_event_handler_unregister_with(esp_gps->event_loop_hdl, ESP_NMEA_EVENT, ESP_EVENT_ANY_ID, event_handler);
  772. }