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.

810 lines
19KB

  1. /*
  2. Copyright (C) 2008 Andreas Grimme, andreas.grimme(at)gmx.net
  3. Copyright (C) 2005 Robert Lipe, 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. /*
  17. This module will download track data from a
  18. XAiOX iTrackU BLUETOOTH GPS-RECEIVER SiRF III
  19. http://www.xaiox.com/itracku_sirf3.htm
  20. Example usage::
  21. # Read from USB port, output trackpoints & waypoints in GPX format
  22. ./gpsbabel -i itracku -f com14 -o gpx -F out.gpx
  23. */
  24. #include "defs.h"
  25. #include "gbser.h"
  26. #include <ctype.h>
  27. #include <math.h>
  28. #include <stdio.h>
  29. #define MYNAME "itracku"
  30. /* memory layout of the iTrackU data record */
  31. typedef struct {
  32. uint8_t longitude[4];
  33. uint8_t latitude[4];
  34. uint8_t creation_time[4];
  35. uint8_t altitude[2];
  36. uint8_t speed;
  37. uint8_t flag;
  38. } itracku_data_record;
  39. static int itracku_is_valid_data_record(itracku_data_record* d);
  40. static void to_itracku_data_record(const Waypoint* wp, itracku_data_record* d);
  41. static Waypoint* to_waypoint(itracku_data_record* d);
  42. /* itracku file access */
  43. static void itracku_file_read_data_record(gbfile* fin, itracku_data_record* d);
  44. static uint32_t itracku_file_read_last_time(gbfile* fin);
  45. static void itracku_file_read_waypts(gbfile* fin, void (*waypt_add)(Waypoint* wpt));
  46. static void itracku_file_write_waypt(gbfile* fout, const Waypoint* wpt);
  47. /* itracku device access */
  48. static const unsigned char read_update_data_command[] = { 0x60, 0xb5, 0, 0, 0, 0, 0 }; /* command string to start memory dump */
  49. static const int timeout = 1000; /* timeout for all read operations */
  50. static const char update_end_marker[] = "WP Update Over"; /* end marker for the memory dump */
  51. static const int update_end_marker_size = sizeof(update_end_marker);
  52. #if LATER
  53. static const int port_auto_detect_max_port = 32;
  54. /* Special port name for auto detect. If used, gpsbabel will try to detect the serial
  55. port with the itracku device automatically. */
  56. static const char port_auto_detect_filename[] = "auto:";
  57. #endif
  58. static int update_data_buffer_read_count = 0;
  59. static char update_data_buffer[1024];
  60. static char* update_data_buffer_read;
  61. static char* update_data_buffer_write;
  62. static char* update_data_buffer_end;
  63. static void itracku_device_dump_waypts(void* fd, void (*waypt_add)(Waypoint* wpt));
  64. static int itracku_device_update_data_init();
  65. static int itracku_device_update_data_read(void* buf, int len);
  66. static void itracku_device_write_string(const char* s);
  67. static const char* itracku_device_read_string();
  68. /* global variables */
  69. static void* fd; /* serial fd */
  70. static gbfile* fin; /* input file handle */
  71. static gbfile* fout; /* output file handle */
  72. static gbfile* fbackup; /* backup file handle */
  73. static uint32_t backup_last_creation_time; /* time of last data record in backup file */
  74. static uint32_t new_waypoint_count; /* count of new waypoints */
  75. static char* port; /* serial port name */
  76. static char* backup_file_name; /* "backup" command option */
  77. static char* only_new; /* "new" command option */
  78. static void
  79. dbg(int l, const char* msg, ...)
  80. {
  81. va_list ap;
  82. va_start(ap, msg);
  83. if (global_opts.debug_level >= l) {
  84. fprintf(stderr, MYNAME ": ");
  85. vfprintf(stderr,msg, ap);
  86. fprintf(stderr, "\n");
  87. fflush(stderr);
  88. }
  89. va_end(ap);
  90. }
  91. static void
  92. itracku_device_write_string(const char* s)
  93. {
  94. int size = strlen(s) + 1;
  95. dbg(1, "write to device: %s", s);
  96. gbser_write(fd, s, size);
  97. }
  98. static const char*
  99. itracku_device_read_string()
  100. {
  101. const int size = 1024;
  102. char* s = (char*) xmalloc(size);
  103. gbser_read_line(fd, s, size, 1000, 0, 0);
  104. dbg(1, "read from device: %s", s);
  105. return s;
  106. }
  107. static int
  108. itracku_device_update_data_init()
  109. {
  110. update_data_buffer_read = update_data_buffer;
  111. update_data_buffer_write = update_data_buffer;
  112. update_data_buffer_end = update_data_buffer + sizeof(update_data_buffer);
  113. update_data_buffer_read_count = 0;
  114. dbg(1, "start memory dump");
  115. return 0;
  116. }
  117. static int
  118. itracku_device_update_data_read(void* buf, int len)
  119. {
  120. int rc;
  121. if (update_data_buffer_write - update_data_buffer_read >= len) {
  122. memcpy(buf, update_data_buffer_read, len);
  123. update_data_buffer_read += len;
  124. return len;
  125. }
  126. if (update_data_buffer_read + update_end_marker_size > update_data_buffer_end) {
  127. memcpy(update_data_buffer, update_data_buffer_read, update_data_buffer_write - update_data_buffer_read);
  128. update_data_buffer_write = update_data_buffer + (update_data_buffer_write - update_data_buffer_read);
  129. update_data_buffer_read = update_data_buffer;
  130. }
  131. rc = gbser_read_wait(fd, update_data_buffer_write, update_data_buffer_end - update_data_buffer_write, timeout);
  132. if (rc == gbser_ERROR) {
  133. return 0;
  134. }
  135. update_data_buffer_write += rc;
  136. update_data_buffer_read_count += rc;
  137. dbg(1, "%5d kbyte read", update_data_buffer_read_count / 1024);
  138. if (0 == strncmp(update_end_marker, update_data_buffer_write - update_end_marker_size, update_end_marker_size - 1)) {
  139. dbg(1, "end memory dump");
  140. return 0;
  141. }
  142. return itracku_device_update_data_read(buf, len);
  143. }
  144. /*
  145. Convert the degrees format of itracku to double.
  146. itracku stores degrees in a
  147. 32-bit unsigned integer. The lower
  148. 6 digits in 10-base notation denote the
  149. minutes multiplied by 10000, and digits
  150. 7-9 denote the degrees.
  151. To express a negative number 0x80000000 is added
  152. to integer.
  153. Example: the integer 49347687 is interpreted
  154. as
  155. ddmmmmmm
  156. 49347687
  157. d=49
  158. m=34.7687
  159. 49 degrees 34.7687 minutes
  160. */
  161. // The argument is marked 'volatile' because of an issue in Apple's v1.5 clang.
  162. // Without this, the sign of 'x' mysteriously changes while in the function.
  163. // adding a printf inside branches not taken changes the behaviour. Very
  164. // mysterious, but not worth tracking down at this time. When xcode 4 comes
  165. // along (or anyone really cares about mega performance of this fairly obscure
  166. // target, we should revisit this.
  167. double
  168. deg_min_to_deg(volatile uint32_t x)
  169. {
  170. double sign;
  171. uint32_t sep;
  172. uint32_t d;
  173. uint32_t m10000;
  174. // determine the sign
  175. if (x > 0x80000000) {
  176. sign = -1.0;
  177. x -= 0x80000000;
  178. } else {
  179. sign = 1.0;
  180. }
  181. sep = 1000000;
  182. // extract degrees
  183. d = (unsigned int) x / (unsigned int) sep;
  184. // extract (minutes * 10000)
  185. m10000 = x - d * sep;
  186. // convert minutes and degrees to a double
  187. return sign * ((double)d + ((double)m10000) / 600000.0);
  188. }
  189. /*
  190. Convert degrees to the degrees format of itracku.
  191. */
  192. uint32_t
  193. deg_to_deg_min(double x)
  194. {
  195. int32_t sign;
  196. double d;
  197. double f;
  198. // determine sign
  199. if (x >= 0) {
  200. sign = 1;
  201. } else {
  202. sign = -1;
  203. x = -x;
  204. }
  205. // integer degrees
  206. d = floor(x);
  207. // fractional part
  208. f = x - d;
  209. return
  210. (uint32_t)d * 1000000 + // multiply integer degrees to shift it to the right digits.
  211. (uint32_t)(f * 600000.0) + // multiply fractional part to convert to minutes and to to shift it to the right digits.
  212. ((sign > 0) ? 0 : 0x80000000); // add 0x80000000 for negative degrees
  213. }
  214. /*
  215. Convert the itracku time format to time_t.
  216. */
  217. static time_t
  218. decode_itracku_time(uint32_t date)
  219. {
  220. struct tm t;
  221. t.tm_sec = date & 63;
  222. t.tm_min = (date >> 6) & 63;
  223. t.tm_hour = (date >> 12) & 31;
  224. t.tm_mday = (date >> 17) & 31;
  225. t.tm_mon = ((date >> 22) & 15) - 1;
  226. t.tm_year = ((date >> 26) & 63) + 100;
  227. return mkgmtime(&t);
  228. }
  229. /*
  230. Convert time_t to the itracku time format.
  231. */
  232. static uint32_t
  233. encode_itracku_time(time_t time)
  234. {
  235. struct tm* t = gmtime(&time);
  236. return
  237. (t->tm_sec) +
  238. (t->tm_min << 6) +
  239. (t->tm_hour << 12) +
  240. (t->tm_mday << 17) +
  241. ((t->tm_mon + 1) << 22) +
  242. ((t->tm_year - 100) << 26);
  243. }
  244. /*
  245. Converts a itracku waypoint record to a gpsbabel waypoint.
  246. */
  247. static Waypoint*
  248. to_waypoint(itracku_data_record* d)
  249. {
  250. Waypoint* wp;
  251. wp = new Waypoint;
  252. wp->longitude = deg_min_to_deg(le_read32(d->longitude));
  253. wp->latitude = deg_min_to_deg(le_read32(d->latitude));
  254. wp->SetCreationTime(decode_itracku_time(le_read32(d->creation_time)));
  255. wp->speed = KNOTS_TO_MPS((float)d->speed);
  256. wp->wpt_flags.speed = 1;
  257. wp->altitude = le_read16(d->altitude);
  258. return wp;
  259. }
  260. static void
  261. to_itracku_data_record(const Waypoint* wp, itracku_data_record* d)
  262. {
  263. le_write32(d->longitude, deg_to_deg_min(wp->longitude));
  264. le_write32(d->latitude, deg_to_deg_min(wp->latitude));
  265. le_write32(d->creation_time, encode_itracku_time(wp->creation_time.toTime_t()));
  266. d->speed = MPS_TO_KNOTS(wp->speed);
  267. le_write16(d->altitude, wp->altitude);
  268. d->flag = 0xff;
  269. }
  270. /*
  271. Tries to initialize an itracku device attached to
  272. serial port fd. fd must already be opened.
  273. Returns gbser_OK if the initialization is sucessful, a
  274. non-zero integer otherwise.
  275. */
  276. int
  277. init_device()
  278. {
  279. int rc;
  280. const char* greeting;
  281. // verify that we have a MTK based logger...
  282. dbg(1, "verifying device on port %s", port);
  283. itracku_device_write_string("WP AP-Exit");
  284. gbser_flush(fd);
  285. itracku_device_write_string("W'P Camera Detect");
  286. greeting = itracku_device_read_string();
  287. if (0 == strcmp(greeting , "WP GPS+BT")) {
  288. dbg(1, "device recognised on port %s", port);
  289. rc = gbser_OK;
  290. } else {
  291. dbg(1, "device not recognised on port %s", port);
  292. rc = gbser_ERROR;
  293. }
  294. xfree((void*)greeting);
  295. return rc;
  296. }
  297. // Any arg in this list will appear in command line help and will be
  298. // populated for you.
  299. // Values for ARGTYPE_xxx can be found in defs.h and are used to
  300. // select the type of option.
  301. static
  302. arglist_t itracku_args[] = {
  303. { "backup", &backup_file_name, "Appends the input to a backup file", NULL, ARGTYPE_STRING, ARG_NOMINMAX },
  304. { "new", &only_new, "Only waypoints that are not the backup file", NULL, ARGTYPE_STRING, ARG_NOMINMAX },
  305. // "default", ARGYTPE_STRING, ARG_NOMINMAX} ,
  306. ARG_TERMINATOR
  307. };
  308. /*******************************************************************************
  309. * %%% global callbacks called by gpsbabel main process %%% *
  310. *******************************************************************************/
  311. static void
  312. itracku_rd_init_common(const QString& fname)
  313. {
  314. new_waypoint_count = 0;
  315. if (backup_file_name != NULL) {
  316. fbackup = gbfopen(backup_file_name, "a+", MYNAME);
  317. backup_last_creation_time = itracku_file_read_last_time(fbackup);
  318. gbfseek(fbackup, 0, SEEK_END);
  319. } else {
  320. fbackup = NULL;
  321. backup_last_creation_time = 0;
  322. }
  323. }
  324. static void
  325. itracku_rd_ser_init(const QString& fname)
  326. {
  327. #if LATER
  328. int i;
  329. if (0 == strcmp(qPrintable(fname), port_auto_detect_filename)) {
  330. dbg(1, "auto detecting port for iTrackU device");
  331. for (i=1; !fd && i<port_auto_detect_max_port; ++i) {
  332. xasprintf(&port, "com%d", i);
  333. if (!gbser_is_serial(port)) {
  334. break;
  335. }
  336. dbg(1, "trying port %s", port);
  337. if ((fd = gbser_init(port)) == NULL) {
  338. dbg(1, "port %s not available.", port);
  339. continue;
  340. }
  341. if (gbser_OK == init_device()) {
  342. break;
  343. }
  344. gbser_deinit(fd);
  345. fd = NULL;
  346. xfree(port);
  347. }
  348. for (i=0; !fd && i<port_auto_detect_max_port; ++i) {
  349. xasprintf(&port, "/dev/ttyUSB%d", i);
  350. if (!gbser_is_serial(port)) {
  351. break;
  352. }
  353. dbg(1, "trying port %s", port);
  354. if ((fd = gbser_init(port)) == NULL) {
  355. dbg(1, "port %s not available.", port);
  356. continue;
  357. }
  358. if (gbser_OK == init_device()) {
  359. break;
  360. }
  361. gbser_deinit(fd);
  362. fd = NULL;
  363. xfree(port);
  364. }
  365. if (fd == NULL) {
  366. fatal(MYNAME ": could not find device");
  367. }
  368. } else
  369. #endif
  370. {
  371. if (gbser_is_serial(qPrintable(fname))) {
  372. port = xstrdup(qPrintable(fname));
  373. dbg(1, "opening port %s", qPrintable(fname));
  374. if ((fd = gbser_init(port)) == NULL) {
  375. fatal(MYNAME ": can't initialise port \"%s\"", port);
  376. }
  377. if (gbser_OK != init_device()) {
  378. fatal(MYNAME ": can't initialise device on port \"%s\"", port);
  379. }
  380. } else {
  381. fatal(MYNAME ": \"%s\" is not a valid serial port", qPrintable(fname));
  382. }
  383. }
  384. itracku_rd_init_common(fname);
  385. }
  386. static void
  387. itracku_rd_init(const QString& fname)
  388. {
  389. fin = gbfopen(fname, "r", MYNAME);
  390. itracku_rd_init_common(fname);
  391. }
  392. static void
  393. itracku_rd_deinit(void)
  394. {
  395. dbg(1, "%d new waypoints", new_waypoint_count);
  396. if (fd) {
  397. dbg(3, "closing port %s", port);
  398. gbser_deinit(fd);
  399. fd = NULL;
  400. xfree(port);
  401. port = NULL;
  402. }
  403. if (fin) {
  404. gbfclose(fin);
  405. fin = NULL;
  406. }
  407. if (fbackup) {
  408. gbfclose(fbackup);
  409. fbackup = NULL;
  410. }
  411. }
  412. /* Returns true if the waypoint is new, i.e. if it is not already in the
  413. backup file. */
  414. static int
  415. import_data_record(itracku_data_record* d)
  416. {
  417. int result = 0;
  418. if (!itracku_is_valid_data_record(d)) {
  419. result = 0;
  420. } else {
  421. if (fbackup) {
  422. if ((uint32_t)le_read32(d->creation_time) > backup_last_creation_time) {
  423. backup_last_creation_time = le_read32(d->creation_time);
  424. gbfwrite(d, sizeof(*d), 1, fbackup);
  425. result = -1;
  426. } else {
  427. result = (only_new == NULL);
  428. }
  429. } else {
  430. result = -1;
  431. }
  432. }
  433. if (result) {
  434. ++new_waypoint_count;
  435. }
  436. return result;
  437. }
  438. static int
  439. itracku_is_valid_data_record(itracku_data_record* d)
  440. {
  441. return !(le_read32(d->longitude) == -1);
  442. }
  443. static void
  444. itracku_device_dump_waypts(void* fd, void (*waypt_add)(Waypoint* wpt))
  445. {
  446. itracku_data_record d;
  447. dbg(1, "reading memory");
  448. gbser_write(fd, read_update_data_command, sizeof(read_update_data_command));
  449. itracku_device_update_data_init();
  450. while (itracku_device_update_data_read(&d, sizeof(d))) {
  451. if (itracku_is_valid_data_record(&d)) {
  452. if (import_data_record(&d)) {
  453. waypt_add(to_waypoint(&d));
  454. }
  455. }
  456. }
  457. }
  458. static void
  459. itracku_file_read_data_record(gbfile* fin, itracku_data_record* d)
  460. {
  461. gbfread(d, sizeof(*d), 1, fin);
  462. }
  463. static uint32_t
  464. itracku_file_read_last_time(gbfile* fin)
  465. {
  466. itracku_data_record d;
  467. gbsize_t s;
  468. s = sizeof(itracku_data_record);
  469. gbfseek(fin, 0, SEEK_END);
  470. if (gbftell(fin) < s) {
  471. return 0;
  472. }
  473. gbfseek(fin, -(int)s, SEEK_END);
  474. itracku_file_read_data_record(fin, &d);
  475. return (uint32_t) le_read32(d.creation_time);
  476. }
  477. static void
  478. itracku_file_read_waypts(gbfile* fin, void (*waypt_add)(Waypoint* wpt))
  479. {
  480. itracku_data_record d;
  481. while (gbfread(&d, sizeof(d), 1, fin)) {
  482. if (le_read32(d.longitude) == -1) {
  483. continue;
  484. }
  485. if (import_data_record(&d)) {
  486. waypt_add(to_waypoint(&d));
  487. }
  488. }
  489. }
  490. static void
  491. itracku_file_write_waypt(gbfile* fout, const Waypoint* wpt)
  492. {
  493. itracku_data_record d;
  494. to_itracku_data_record(wpt, &d);
  495. gbfwrite(&d, sizeof(d), 1, fout);
  496. }
  497. static void
  498. itracku_waypt_input(void (*waypt_add)(Waypoint* wpt))
  499. {
  500. if (fd) {
  501. itracku_device_dump_waypts(fd, waypt_add);
  502. } else {
  503. itracku_file_read_waypts(fin, waypt_add);
  504. }
  505. }
  506. static void
  507. itracku_read_waypt(void)
  508. {
  509. itracku_waypt_input(&waypt_add);
  510. }
  511. static route_head* itracku_read_trk_track;
  512. static void
  513. itracku_read_trk_waypt_add(Waypoint* wpt)
  514. {
  515. track_add_wpt(itracku_read_trk_track, wpt);
  516. }
  517. static void
  518. itracku_read_trk(void)
  519. {
  520. itracku_read_trk_track = route_head_alloc();
  521. track_add_head(itracku_read_trk_track);
  522. itracku_waypt_input(&itracku_read_trk_waypt_add);
  523. }
  524. static void
  525. itracku_read(void)
  526. {
  527. switch (global_opts.objective) {
  528. case wptdata:
  529. case unknown_gpsdata:
  530. itracku_read_waypt();
  531. break;
  532. case trkdata:
  533. itracku_read_trk();
  534. break;
  535. case rtedata:
  536. fatal(MYNAME ": reading routes is not supported.\n");
  537. break;
  538. case posndata:
  539. break;
  540. }
  541. }
  542. static void
  543. itracku_wr_init(const QString& fname)
  544. {
  545. fout = gbfopen(fname, "w", MYNAME);
  546. }
  547. static void
  548. itracku_wr_deinit(void)
  549. {
  550. gbfclose(fout);
  551. }
  552. static void
  553. itracku_output_waypoint(const Waypoint* wp)
  554. {
  555. itracku_file_write_waypt(fout, wp);
  556. }
  557. static void
  558. itracku_write(void)
  559. {
  560. waypt_disp_all(itracku_output_waypoint);
  561. }
  562. static void
  563. itracku_exit(void) /* optional */
  564. {
  565. }
  566. static void
  567. itracku_rt_init(const QString& fname)
  568. {
  569. itracku_rd_ser_init(fname);
  570. itracku_device_write_string("WP AP-Exit");
  571. }
  572. static void
  573. nmea_set_waypoint_time(Waypoint* wpt, struct tm* time, double fsec)
  574. {
  575. if (time->tm_year == 0) {
  576. wpt->SetCreationTime(((((time_t)time->tm_hour * 60) + time->tm_min) * 60) + time->tm_sec, lround(1000.0 * fsec));
  577. if (wpt->wpt_flags.fmt_use == 0) {
  578. wpt->wpt_flags.fmt_use = 1;
  579. }
  580. } else {
  581. wpt->SetCreationTime(mkgmtime(time), lround(1000.0 * fsec));
  582. if (wpt->wpt_flags.fmt_use != 0) {
  583. wpt->wpt_flags.fmt_use = 0;
  584. }
  585. }
  586. }
  587. static Waypoint*
  588. gprmc_parse(char* ibuf)
  589. {
  590. double latdeg, lngdeg;
  591. char lngdir, latdir;
  592. double hms;
  593. char fix;
  594. unsigned int dmy;
  595. double speed,course;
  596. Waypoint* waypt;
  597. double fsec;
  598. struct tm tm;
  599. int rc = sscanf(ibuf,"$GPRMC,%lf,%c,%lf,%c,%lf,%c,%lf,%lf,%u",
  600. &hms, &fix, &latdeg, &latdir,
  601. &lngdeg, &lngdir,
  602. &speed, &course, &dmy);
  603. if (rc == 0) {
  604. return NULL;
  605. }
  606. fsec = hms - (int)hms;
  607. tm.tm_sec = (long) hms % 100;
  608. hms = hms / 100;
  609. tm.tm_min = (long) hms % 100;
  610. hms = hms / 100;
  611. tm.tm_hour = (long) hms % 100;
  612. tm.tm_year = dmy % 100 + 100;
  613. dmy = dmy / 100;
  614. tm.tm_mon = dmy % 100 - 1;
  615. dmy = dmy / 100;
  616. tm.tm_mday = dmy;
  617. waypt = new Waypoint;
  618. WAYPT_SET(waypt, speed, KNOTS_TO_MPS(speed));
  619. WAYPT_SET(waypt, course, course);
  620. nmea_set_waypoint_time(waypt, &tm, fsec);
  621. if (latdir == 'S') {
  622. latdeg = -latdeg;
  623. }
  624. waypt->latitude = ddmm2degrees(latdeg);
  625. if (lngdir == 'W') {
  626. lngdeg = -lngdeg;
  627. }
  628. waypt->longitude = ddmm2degrees(lngdeg);
  629. return waypt;
  630. }
  631. /*
  632. TODO: this function should rather call code from
  633. nmea.c instead of using a local copy of
  634. gprmc_parse
  635. andreas.grimme@gmx.net
  636. */
  637. static Waypoint*
  638. itracku_rt_position(posn_status* posn_status)
  639. {
  640. char line[1024];
  641. Waypoint* wpt;
  642. while (1) {
  643. gbser_read_line(fd, line, sizeof(line), 5000, 13, 10);
  644. dbg(1, line);
  645. wpt = gprmc_parse(line);
  646. if (wpt) {
  647. return wpt;
  648. }
  649. }
  650. }
  651. static void
  652. itracku_rt_deinit(void)
  653. {
  654. itracku_rd_deinit();
  655. }
  656. /**************************************************************************/
  657. // capabilities below means: we can only read and write waypoints
  658. // please change this depending on your new module
  659. ff_vecs_t itracku_vecs = {
  660. ff_type_file,
  661. {
  662. ff_cap_read /* waypoints */,
  663. ff_cap_read /* tracks */,
  664. ff_cap_none /* routes */
  665. },
  666. itracku_rd_ser_init,
  667. NULL,
  668. itracku_rd_deinit,
  669. NULL,
  670. itracku_read,
  671. itracku_write,
  672. itracku_exit,
  673. itracku_args,
  674. CET_CHARSET_ASCII, 0, /* ascii is the expected character set */
  675. /* not fixed, can be changed through command line parameter */
  676. { itracku_rt_init, itracku_rt_position, itracku_rt_deinit, NULL, NULL, NULL }
  677. };
  678. ff_vecs_t itracku_fvecs = {
  679. ff_type_file,
  680. {
  681. (ff_cap)(ff_cap_read | ff_cap_write) /* waypoints */,
  682. (ff_cap)(ff_cap_read | ff_cap_write) /* tracks */,
  683. ff_cap_none /* routes */
  684. },
  685. itracku_rd_init,
  686. itracku_wr_init,
  687. itracku_rd_deinit,
  688. itracku_wr_deinit,
  689. itracku_read,
  690. itracku_write,
  691. itracku_exit,
  692. itracku_args,
  693. CET_CHARSET_ASCII, 0, /* ascii is the expected character set */
  694. /* not fixed, can be changed through command line parameter */
  695. { NULL, NULL, NULL, NULL, NULL, NULL }
  696. };
  697. /**************************************************************************/