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.

343 lines
7.9KB

  1. /*
  2. Magellan ".gs" files as they appear on USB of Explorist 400,500,600.
  3. Copyright (C) 2005, 2006, 2008 robertlipe+source@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 "defs.h"
  17. #include "csv_util.h"
  18. #include "xmlgeneric.h"
  19. #include "magellan.h"
  20. #include <QtCore/QXmlStreamAttributes>
  21. #include <cmath>
  22. #include <stdlib.h>
  23. #include <stdio.h>
  24. #define MYNAME "maggeo"
  25. /* Turn this on (remove) after 5.2 becomes widespread. */
  26. #define FIRMWARE_DOES_88591 0
  27. static gbfile* maggeofile_in;
  28. static gbfile* maggeofile_out;
  29. static short_handle desc_handle = NULL;
  30. static QDateTime maggeo_parsedate(char* dmy);
  31. static void
  32. maggeo_writemsg(const char* const buf)
  33. {
  34. unsigned int osum = mag_checksum(buf);
  35. gbfprintf(maggeofile_out, "$%s*%02X\r\n",buf, osum);
  36. }
  37. static void
  38. maggeo_rd_init(const QString& fname)
  39. {
  40. maggeofile_in = gbfopen(fname, "rb", MYNAME);
  41. }
  42. static void
  43. maggeo_rd_deinit(void)
  44. {
  45. gbfclose(maggeofile_in);
  46. }
  47. static void
  48. maggeo_wr_init(const QString& fname)
  49. {
  50. if (waypt_count() > 200) {
  51. fatal(MYNAME ": eXplorist does not support more than 200 waypoints in one .gs file.\nDecrease the number of waypoints sent.\n");
  52. }
  53. maggeofile_out = gbfopen(fname, "wb", MYNAME);
  54. desc_handle = mkshort_new_handle();
  55. setshort_length(desc_handle, 20);
  56. setshort_badchars(desc_handle, "\"$,");
  57. }
  58. static void
  59. maggeo_wr_deinit(void)
  60. {
  61. maggeo_writemsg("PMGNCMD,END");
  62. mkshort_del_handle(&desc_handle);
  63. gbfclose(maggeofile_out);
  64. }
  65. static void
  66. maggeo_read(void)
  67. {
  68. char* buff;
  69. while ((buff = gbfgetstr(maggeofile_in))) {
  70. Waypoint* wpt_tmp;
  71. geocache_data* gcdata;
  72. char* s = NULL;
  73. int fld;
  74. buff = lrtrim(buff);
  75. if (*buff == '\0') {
  76. continue;
  77. }
  78. if (strncmp(buff, "$PMGNGEO,", 9)) {
  79. continue;
  80. }
  81. buff += 9; /* skip field no. 1 */
  82. fld = 1;
  83. wpt_tmp = new Waypoint;
  84. gcdata = wpt_tmp->AllocGCData();
  85. while ((s = csv_lineparse(buff, ",", "", fld++))) {
  86. buff = NULL;
  87. s = lrtrim(s);
  88. if (*s == '\0') {
  89. continue;
  90. }
  91. switch (fld) {
  92. case 2:
  93. wpt_tmp->latitude = ddmm2degrees(atof(s));
  94. break;
  95. case 3:
  96. if (s[0] == 'S') {
  97. wpt_tmp->latitude = -wpt_tmp->latitude;
  98. }
  99. break;
  100. case 4:
  101. wpt_tmp->longitude = ddmm2degrees(atof(s));
  102. break;
  103. case 5:
  104. if (s[0] == 'W') {
  105. wpt_tmp->longitude = -wpt_tmp->longitude;
  106. }
  107. break;
  108. case 6:
  109. wpt_tmp->altitude = atof(s);
  110. break;
  111. case 7:
  112. if (s[0] == 'F') {
  113. wpt_tmp->altitude = METERS_TO_FEET(wpt_tmp->altitude);
  114. }
  115. break;
  116. case 8:
  117. wpt_tmp->shortname = s;
  118. break;
  119. case 9:
  120. wpt_tmp->description = s;
  121. break;
  122. case 10:
  123. gcdata->placer = s;
  124. break;
  125. case 11:
  126. gcdata->hint = s;
  127. break;
  128. case 12: // cache type
  129. if (strcmp(s, "Mystery Cache") == 0) {
  130. gcdata->type = gt_suprise;
  131. } else {
  132. gcdata->type = gs_mktype(s);
  133. }
  134. break;
  135. case 13:
  136. wpt_tmp->creation_time = maggeo_parsedate(s);
  137. break;
  138. case 14: // last found date was ignored. Implemented 2013-02-27.
  139. gcdata->last_found = maggeo_parsedate(s);
  140. break;
  141. case 15:
  142. gcdata->diff = 10 * atof(s);
  143. break;
  144. case 16:
  145. gcdata->terr = 10 * atof(s);
  146. break;
  147. }
  148. }
  149. waypt_add(wpt_tmp);
  150. }
  151. }
  152. static
  153. QString
  154. maggeo_fmtdate(QDateTime dt)
  155. {
  156. QDate date = dt.date();
  157. int y = date.year() - 1900;
  158. int m = date.month();
  159. int d = date.day();
  160. int r = d * 100000 + m * 1000 + y;
  161. return QString("%1").arg(r, 7, 10, QChar('0'));
  162. }
  163. /*
  164. * The maggeo date format s DDMMYYY where "YYY" is the number
  165. * of years since 1900. This, of course, means anything in this
  166. * century is three digits but anything from before 2000, we'd have
  167. * two digit years. This makes this easier to parse as strings.
  168. */
  169. static QDateTime maggeo_parsedate(char* dmy)
  170. {
  171. QString date(dmy);
  172. int d = date.mid(0,2).toInt();
  173. int m = date.mid(2,2).toInt();
  174. int y = date.mid(4,3).toInt();
  175. QDateTime r(QDate(y + 1900, m, d));
  176. return r;
  177. }
  178. /*
  179. * Append an optional UTF string to buf, prepending a comma,
  180. * cleansing it of NMEA-isms and decomposing to ASCII as we go.
  181. */
  182. static
  183. void
  184. append(char* buf, const char* str)
  185. {
  186. char* cleansed1, *cleansed2;
  187. strcat(buf, ",");
  188. if (!str) {
  189. return;
  190. }
  191. cleansed1 = xstrdup(str);
  192. #if FIRMWARE_DOES_88591
  193. /* Actually, this function needs needs refactored... */
  194. cleansed2 = xstrdup(cleansed1);
  195. #else
  196. cleansed2 = xstrdup(m330_cleanse(cleansed1));
  197. #endif
  198. strcat(buf, cleansed2);
  199. xfree(cleansed1);
  200. xfree(cleansed2);
  201. }
  202. static void
  203. maggeo_waypt_pr(const Waypoint* waypointp)
  204. {
  205. char obuf[4096];
  206. double ilon, ilat;
  207. double lon, lat;
  208. int lon_deg, lat_deg;
  209. const char* ctype = NULL;
  210. QString placer;
  211. ilat = waypointp->latitude;
  212. ilon = waypointp->longitude;
  213. lon = fabs(ilon);
  214. lat = fabs(ilat);
  215. lon_deg = lon;
  216. lat_deg = lat;
  217. lon = (lon - lon_deg) * 60.0;
  218. lat = (lat - lat_deg) * 60.0;
  219. lon = (lon_deg * 100.0 + lon);
  220. lat = (lat_deg * 100.0 + lat);
  221. /*
  222. * For some reason, Magellan used exactly the GPX spellings of
  223. * everything except this one...
  224. */
  225. if (waypointp->gc_data->type == gt_suprise) {
  226. ctype = "Mystery Cache";
  227. } else {
  228. ctype = gs_get_cachetype(waypointp->gc_data->type);
  229. }
  230. QString placeddate = maggeo_fmtdate(waypointp->creation_time);
  231. QString lfounddate = maggeo_fmtdate(waypointp->gc_data->last_found);
  232. QString cname = mkshort(desc_handle,
  233. waypointp->notes.isEmpty() ? waypointp->description : waypointp->notes);
  234. placer = waypointp->gc_data->placer;
  235. /*
  236. * As of this writing on 05/04, the firmware in the units will
  237. * let you write fields of just about any width, but appears to
  238. * only use the following:
  239. * shortname - 8 chars
  240. * cname - 20 chars (scrolls in some places, not others)
  241. * placer - display limited by width
  242. * hint - 50 chars
  243. * cache type - appears to be parsed by f/w for icon matching.
  244. *
  245. *
  246. */
  247. snprintf(obuf, sizeof(obuf),
  248. "PMGNGEO,%4.3f,%c,%08.3f,%c,%04.0f,F",
  249. lat, ilat < 0 ? 'S' : 'N',
  250. lon, ilon < 0 ? 'W' : 'E',
  251. waypointp->altitude == unknown_alt ?
  252. 0 : waypointp->altitude);
  253. append(obuf, CSTRc(waypointp->shortname));
  254. append(obuf, CSTR(cname));
  255. append(obuf, CSTR(placer));
  256. append(obuf, CSTR(waypointp->gc_data->hint));
  257. append(obuf, ctype);
  258. append(obuf, placeddate.toUtf8());
  259. append(obuf, lfounddate.toUtf8());
  260. if (waypointp->gc_data->diff/10.0)
  261. sprintf(obuf + strlen(obuf), ",%3.1f",
  262. waypointp->gc_data->diff/10.0);
  263. else {
  264. strcat(obuf, ",");
  265. }
  266. if (waypointp->gc_data->terr/10.0)
  267. sprintf(obuf + strlen(obuf), ",%3.1f",
  268. waypointp->gc_data->terr/10.0);
  269. else {
  270. strcat(obuf, ",");
  271. }
  272. maggeo_writemsg(obuf);
  273. }
  274. static void
  275. maggeo_write(void)
  276. {
  277. waypt_disp_all(maggeo_waypt_pr);
  278. }
  279. ff_vecs_t maggeo_vecs = {
  280. ff_type_file,
  281. { (ff_cap)(ff_cap_read | ff_cap_write), ff_cap_none, ff_cap_none },
  282. maggeo_rd_init,
  283. maggeo_wr_init,
  284. maggeo_rd_deinit,
  285. maggeo_wr_deinit,
  286. maggeo_read,
  287. maggeo_write,
  288. NULL,
  289. NULL,
  290. #if FIRMWARE_DOES_88591
  291. CET_CHARSET_LATIN1, 0 /* CET-REVIEW */
  292. #else
  293. CET_CHARSET_ASCII, 0 /* CET-REVIEW */
  294. #endif
  295. };