nmea_wrapper.c 5.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226
  1. /*
  2. * NMEA Wrapper for PC Compilation
  3. * Provides simplified NMEA parsing using main.h for PC compatibility
  4. */
  5. #define PC_BUILD
  6. #include "main.h"
  7. /* Prevent duplicate includes */
  8. #define _NMEA_H_ 1
  9. /* Helper function from nmea.c */
  10. static unsigned char nmea_checksum(const char *s) {
  11. unsigned char c = 0;
  12. while (*s && *s != '*') {
  13. c ^= *s;
  14. s++;
  15. }
  16. return c;
  17. }
  18. /* String comparison function from nmea.c */
  19. static char gp_comp(const char *s1, const char *s2) {
  20. while (*s1 && *s2) {
  21. if (*s1 != *s2)
  22. return *s1 - *s2;
  23. s1++;
  24. s2++;
  25. }
  26. if (*s1 == ',' && !*s2)
  27. return 0;
  28. return *s1 - *s2;
  29. }
  30. /* Forward declarations */
  31. static time_t gp_rmc_parse(const char *str);
  32. static void gp_gga_parse(const char *str);
  33. static void gp_vtg_parse(const char *str);
  34. /* Field extraction helper */
  35. static const char* get_field(const char **str, char *buf, size_t bufsize) {
  36. const char *s = *str;
  37. size_t i = 0;
  38. while (*s && *s != ',') s++;
  39. if (*s == ',') s++;
  40. while (*s && *s != ',' && *s != '*' && i < bufsize - 1) {
  41. buf[i++] = *s++;
  42. }
  43. buf[i] = '\0';
  44. *str = s;
  45. return buf;
  46. }
  47. /* Parse time from NMEA */
  48. static time_t parse_time(const char *timestr, const char *datestr) {
  49. struct tm t = {0};
  50. if (strlen(timestr) >= 6) {
  51. t.tm_hour = (timestr[0] - '0') * 10 + (timestr[1] - '0');
  52. t.tm_min = (timestr[2] - '0') * 10 + (timestr[3] - '0');
  53. t.tm_sec = (timestr[4] - '0') * 10 + (timestr[5] - '0');
  54. }
  55. if (strlen(datestr) >= 6) {
  56. t.tm_mday = (datestr[0] - '0') * 10 + (datestr[1] - '0');
  57. t.tm_mon = (datestr[2] - '0') * 10 + (datestr[3] - '0') - 1;
  58. t.tm_year = (datestr[4] - '0') * 10 + (datestr[5] - '0') + 100;
  59. }
  60. return mktime(&t);
  61. }
  62. /* Parse coordinate */
  63. static float parse_coord(const char *coord, const char *dir) {
  64. float deg, min;
  65. char *p;
  66. deg = strtof(coord, &p);
  67. if (!p || p == coord) return 0.0;
  68. min = fmodf(deg, 100.0f);
  69. deg = floorf(deg / 100.0f);
  70. float result = deg + min / 60.0f;
  71. if (*dir == 'S' || *dir == 'W')
  72. result = -result;
  73. return result;
  74. }
  75. /* RMC parser */
  76. static time_t gp_rmc_parse(const char *str) {
  77. char buf[32];
  78. const char *p = str;
  79. char timestr[16] = "", datestr[16] = "", status[2] = "";
  80. char lat[16] = "", latdir[2] = "", lon[16] = "", londir[2] = "";
  81. while (*p && *p != ',') p++;
  82. get_field(&p, timestr, sizeof(timestr));
  83. get_field(&p, status, sizeof(status));
  84. get_field(&p, lat, sizeof(lat));
  85. get_field(&p, latdir, sizeof(latdir));
  86. get_field(&p, lon, sizeof(lon));
  87. get_field(&p, londir, sizeof(londir));
  88. get_field(&p, buf, sizeof(buf)); /* speed */
  89. get_field(&p, buf, sizeof(buf)); /* course */
  90. get_field(&p, datestr, sizeof(datestr));
  91. if (status[0] == 'A') {
  92. location.lat = parse_coord(lat, latdir);
  93. location.lon = parse_coord(lon, londir);
  94. utc = parse_time(timestr, datestr);
  95. location.time = utc;
  96. return utc;
  97. }
  98. return 0;
  99. }
  100. /* GGA parser */
  101. static void gp_gga_parse(const char *str) {
  102. char buf[32];
  103. const char *p = str;
  104. char alt[16] = "", lat[16] = "", latdir[2] = "";
  105. char lon[16] = "", londir[2] = "";
  106. while (*p && *p != ',') p++;
  107. get_field(&p, buf, sizeof(buf)); /* time */
  108. get_field(&p, lat, sizeof(lat));
  109. get_field(&p, latdir, sizeof(latdir));
  110. get_field(&p, lon, sizeof(lon));
  111. get_field(&p, londir, sizeof(londir));
  112. get_field(&p, buf, sizeof(buf)); /* fix quality */
  113. get_field(&p, buf, sizeof(buf)); /* satellites */
  114. get_field(&p, buf, sizeof(buf)); /* HDOP */
  115. get_field(&p, alt, sizeof(alt));
  116. if (strlen(lat) > 0) {
  117. location.lat = parse_coord(lat, latdir);
  118. location.lon = parse_coord(lon, londir);
  119. }
  120. if (strlen(alt) > 0) {
  121. location.alt = atof(alt);
  122. }
  123. }
  124. /* VTG parser stub */
  125. static void gp_vtg_parse(const char *str) {
  126. (void)str;
  127. }
  128. /* Stub functions */
  129. void pmtk001_parse(const char *str) { (void)str; }
  130. void gps_initialize(void) {}
  131. void check_min_sat_limit(void) {}
  132. /* Main parse function */
  133. time_t gps_parse(const char *str) {
  134. signed int len = strlen(str) - 2;
  135. const char *checksum;
  136. unsigned char calc_checksum, inc_checksum;
  137. signed int i;
  138. char c;
  139. if (len < 4)
  140. return 0;
  141. for (i = len - 1; i && i >= (len - 2); i--) {
  142. if (str[i] == '*')
  143. break;
  144. }
  145. checksum = str + i + 1;
  146. inc_checksum = 0;
  147. while (*checksum && isalnum(*checksum)) {
  148. inc_checksum *= 16;
  149. c = *checksum++;
  150. if (c >= '0' && c <= '9') {
  151. inc_checksum += c - '0';
  152. } else if (c >= 'a' && c <= 'f') {
  153. inc_checksum += c - 'a' + 10;
  154. } else if (c >= 'A' && c <= 'F') {
  155. inc_checksum += c - 'A' + 10;
  156. } else {
  157. return 0;
  158. }
  159. }
  160. str++;
  161. calc_checksum = nmea_checksum(str);
  162. if (inc_checksum != calc_checksum) {
  163. xprintf("Invalid NMEA checksum: got %02X, expected %02X\n",
  164. inc_checksum, calc_checksum);
  165. return 0;
  166. }
  167. if (!gp_comp(str, "GPRMC") || !gp_comp(str, "GNRMC") ||
  168. !gp_comp(str, "BDRMC") || !gp_comp(str, "GARMC")) {
  169. return gp_rmc_parse(str);
  170. }
  171. if (!gp_comp(str, "GPGGA") || !gp_comp(str, "GNGGA") ||
  172. !gp_comp(str, "BDGGA") || !gp_comp(str, "GAGGA")) {
  173. gp_gga_parse(str);
  174. return 0;
  175. }
  176. if (!gp_comp(str, "GPVTG") || !gp_comp(str, "GNVTG")) {
  177. gp_vtg_parse(str);
  178. return 0;
  179. }
  180. return 0;
  181. }
  182. UINT get_line(char *buff, UINT sz_buf) {
  183. (void)buff;
  184. (void)sz_buf;
  185. return 0;
  186. }