You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

293 lines
6.9KB

  1. /*
  2. Support for "GeoGrid Viewer" binary tracklogs (*.log)
  3. Copyright (C) 2007 Olaf Klein, o.b.klein@gpsbabel.org
  4. This program is free software; you can redistribute it and/or modify
  5. it under the terms of the GNU General Public License as published by
  6. the Free Software Foundation; either version 2 of the License, or
  7. (at your option) any later version.
  8. This program is distributed in the hope that it will be useful,
  9. but WITHOUT ANY WARRANTY; without even the implied warranty of
  10. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  11. GNU General Public License for more details.
  12. You should have received a copy of the GNU General Public License
  13. along with this program; if not, write to the Free Software
  14. Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111 USA
  15. */
  16. #include <ctype.h>
  17. #include <math.h>
  18. #include <stdio.h>
  19. #include <time.h>
  20. #include "defs.h"
  21. #include "grtcirc.h"
  22. #include "jeeps/gpsmath.h"
  23. #define MYNAME "ggv_log"
  24. static gbfile* fin, *fout;
  25. static int ggv_log_ver;
  26. static
  27. arglist_t ggv_log_args[] = {
  28. ARG_TERMINATOR
  29. };
  30. /*******************************************************************************
  31. * %%% global callbacks called by gpsbabel main process %%% *
  32. *******************************************************************************/
  33. static void
  34. ggv_log_rd_init(const QString& fname)
  35. {
  36. static char magic[32];
  37. int len = 0;
  38. fin = gbfopen(fname, "rb", MYNAME);
  39. for (;;) {
  40. int cin;
  41. cin = gbfgetc(fin);
  42. if (cin < 0) {
  43. break;
  44. }
  45. magic[len++] = cin;
  46. if (cin == '\0') {
  47. double ver = 0;
  48. char* sver;
  49. if (strncmp(magic, "DOMGVGPS Logfile V", 18) != 0) {
  50. break;
  51. }
  52. sver = &magic[18];
  53. sscanf(sver, "%lf:", &ver);
  54. ggv_log_ver = ver * 10;
  55. if ((ggv_log_ver == 10) || (ggv_log_ver == 25)) {
  56. return; /* header accepted */
  57. }
  58. fatal(MYNAME ": Sorry, unsupported version (%s)!\n", sver);
  59. } else if (len == sizeof(magic)) {
  60. break;
  61. }
  62. }
  63. fatal(MYNAME ": Invalid header. Probably no " MYNAME " file!\n");
  64. }
  65. static void
  66. ggv_log_rd_deinit(void)
  67. {
  68. gbfclose(fin);
  69. }
  70. static void
  71. ggv_log_read(void)
  72. {
  73. signed char* buf;
  74. int bufsz = 0, len;
  75. route_head* trk = NULL;
  76. switch (ggv_log_ver) {
  77. case 10:
  78. bufsz = 0x2A;
  79. break;
  80. case 25:
  81. bufsz = 0x6F;
  82. break;
  83. }
  84. buf = (signed char*) xmalloc(bufsz);
  85. while ((len = gbfread(buf, 1, bufsz, fin))) {
  86. int deg, min;
  87. double xlat, xlon;
  88. float sec;
  89. struct tm tm;
  90. Waypoint* wpt;
  91. if (len != bufsz) {
  92. break;
  93. }
  94. if (trk == NULL) {
  95. trk = route_head_alloc();
  96. track_add_head(trk);
  97. }
  98. memset(&tm, 0, sizeof(tm));
  99. wpt = new Waypoint;
  100. deg = (int16_t) le_read16(&buf[0]);
  101. min = le_read16(&buf[2]);
  102. sec = le_read_float(&buf[4]);
  103. xlat = (double)deg + ((double)min / (double)60) + (sec / (double)3600.0);
  104. wpt->latitude = xlat;
  105. deg = (int16_t) le_read16(&buf[8]);
  106. min = le_read16(&buf[10]);
  107. sec = le_read_float(&buf[12]);
  108. xlon = (double)deg + ((double)min / (double)60) + (sec / (double)3600.0);
  109. wpt->longitude = xlon;
  110. WAYPT_SET(wpt, course, le_read16(&buf[16 + 0]));
  111. int milliseconds = 0;
  112. if (ggv_log_ver == 10) {
  113. double secs;
  114. wpt->altitude = le_read16(&buf[16 + 2]);
  115. WAYPT_SET(wpt, speed, le_read16(&buf[16 + 4]));
  116. tm.tm_year = le_read16(&buf[16 + 8]);
  117. tm.tm_mon = le_read16(&buf[16 + 10]);
  118. tm.tm_mday = le_read16(&buf[16 + 12]);
  119. tm.tm_hour = le_read16(&buf[16 + 14]);
  120. tm.tm_min = le_read16(&buf[16 + 16]);
  121. secs = le_read_double(&buf[16 + 18]);
  122. tm.tm_sec = (int)secs;
  123. milliseconds = lround((secs - tm.tm_sec) * 1000.0);
  124. } else {
  125. wpt->altitude = le_read16(&buf[16 + 4]);
  126. wpt->sat = (unsigned char)buf[16 + 14];
  127. /* other probably valid double values at offset:
  128. 22: 0.0 - 20.0
  129. 43: 0.0 - 59.0
  130. 51: -1.0
  131. 61: -1.0
  132. 79: .. - 20.0 ? speed over ground ? (++)
  133. 87: ? course ?
  134. 95: 0.0 - 3.1 (++)
  135. 103: -1
  136. */
  137. }
  138. if (wpt->altitude == 0) {
  139. wpt->altitude = unknown_alt;
  140. }
  141. if (tm.tm_year >= 1900) {
  142. tm.tm_year -= 1900;
  143. if (tm.tm_mon > 0) {
  144. tm.tm_mon--;
  145. wpt->SetCreationTime(mkgmtime(&tm), milliseconds);
  146. }
  147. }
  148. track_add_wpt(trk, wpt);
  149. }
  150. xfree(buf);
  151. }
  152. static void
  153. ggv_log_wr_init(const QString& fname)
  154. {
  155. fout = gbfopen(fname, "wb", MYNAME);
  156. gbfputcstr("DOMGVGPS Logfile V1.0:", fout);
  157. }
  158. static void
  159. ggv_log_wr_deinit(void)
  160. {
  161. gbfclose(fout);
  162. }
  163. static void
  164. ggv_log_track_head_cb(const route_head* trk)
  165. {
  166. queue* elem, *tmp;
  167. Waypoint* prev = NULL;
  168. QUEUE_FOR_EACH((queue*)&trk->waypoint_list, elem, tmp) {
  169. double latmin, lonmin, latsec, lonsec;
  170. int latint, lonint;
  171. double course = 0, speed = 0;
  172. struct tm tm;
  173. Waypoint* wpt = (Waypoint*)elem;
  174. double secs = 0;
  175. latint = wpt->latitude;
  176. lonint = wpt->longitude;
  177. latmin = 60.0 * (fabs(wpt->latitude) - latint);
  178. lonmin = 60.0 * (fabs(wpt->longitude) - lonint);
  179. latsec = 60.0 * (latmin - floor(latmin));
  180. lonsec = 60.0 * (lonmin - floor(lonmin));
  181. if (wpt->creation_time.isValid()) {
  182. time_t t = wpt->GetCreationTime().toTime_t();
  183. tm = *gmtime(&t);
  184. tm.tm_mon += 1;
  185. tm.tm_year += 1900;
  186. } else {
  187. memset(&tm, 0, sizeof(tm));
  188. }
  189. if (prev != NULL) {
  190. course = heading_true_degrees(
  191. prev->latitude, prev->longitude,
  192. wpt->latitude, wpt->longitude);
  193. speed = waypt_speed(prev, wpt);
  194. }
  195. if (wpt->creation_time.isValid()) {
  196. secs = (double)tm.tm_sec + wpt->GetCreationTime().time().msec() / 1000.0;
  197. }
  198. gbfputint16((int16_t) latint, fout);
  199. gbfputint16((int16_t) latmin, fout);
  200. gbfputflt(latsec, fout);
  201. gbfputint16((int16_t) lonint, fout);
  202. gbfputint16((int16_t) lonmin, fout);
  203. gbfputflt(lonsec, fout);
  204. gbfputint16((int16_t) course, fout);
  205. gbfputint16((int16_t)(wpt->altitude != unknown_alt) ? wpt->altitude : 0, fout);
  206. gbfputint16((int16_t) speed, fout);
  207. gbfputint16(0, fout);
  208. gbfputint16(tm.tm_year, fout);
  209. gbfputint16(tm.tm_mon, fout);
  210. gbfputint16(tm.tm_mday, fout);
  211. gbfputint16(tm.tm_hour, fout);
  212. gbfputint16(tm.tm_min, fout);
  213. gbfputdbl(secs, fout);
  214. prev = wpt;
  215. }
  216. }
  217. static void
  218. ggv_log_write(void)
  219. {
  220. track_disp_all(ggv_log_track_head_cb, NULL, NULL);
  221. }
  222. /**************************************************************************/
  223. ff_vecs_t ggv_log_vecs = {
  224. ff_type_file,
  225. {
  226. ff_cap_none, /* waypoints */
  227. (ff_cap)(ff_cap_read | ff_cap_write), /* tracks */
  228. ff_cap_none /* routes */
  229. },
  230. ggv_log_rd_init,
  231. ggv_log_wr_init,
  232. ggv_log_rd_deinit,
  233. ggv_log_wr_deinit,
  234. ggv_log_read,
  235. ggv_log_write,
  236. NULL,
  237. ggv_log_args,
  238. CET_CHARSET_ASCII, 1
  239. };
  240. /**************************************************************************/