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.

dg-100.cc 21KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803
  1. /*
  2. GlobalSat DG-100/DG-200 GPS data logger download.
  3. Copyright (C) 2007 Mirko Parthey, mirko.parthey@informatik.tu-chemnitz.de
  4. Copyright (C) 2005-2008 Robert Lipe, robertlipe+source@gpsbabel.org
  5. Copyright (C) 2012 Nicolas Boullis, nboullis@debian.org
  6. Copyright (C) 2014 Jean-Claude Repetto, gpsbabel@repetto.org
  7. This program is free software; you can redistribute it and/or modify
  8. it under the terms of the GNU General Public License as published by
  9. the Free Software Foundation; either version 2 of the License, or
  10. (at your option) any later version.
  11. This program is distributed in the hope that it will be useful,
  12. but WITHOUT ANY WARRANTY; without even the implied warranty of
  13. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  14. GNU General Public License for more details.
  15. You should have received a copy of the GNU General Public License
  16. along with this program; if not, write to the Free Software
  17. Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111 USA
  18. */
  19. /*
  20. DG-100 / DG-200 communication protocol specification:
  21. http://www.usglobalsat.com/s-176-developer-information.aspx
  22. */
  23. #include "defs.h"
  24. #include <ctype.h>
  25. #include "gbser.h"
  26. #include <assert.h>
  27. #include <stdio.h>
  28. #include <stdlib.h>
  29. #define MYNAME "DG-100"
  30. typedef struct {
  31. const char *name;
  32. unsigned speed;
  33. int has_trailing_bytes;
  34. int has_payload_end_seq;
  35. struct dg100_command *commands;
  36. unsigned int numcommands;
  37. } model_t;
  38. static const model_t* model;
  39. static void* serial_handle;
  40. /* maximum frame size observed so far: 1817 bytes
  41. * (dg100cmd_getfileheader returning 150 entries)
  42. * dg100cmd_getfileheader is the only answer type of variable length,
  43. * answers of other types are always shorter than 1817 bytes */
  44. #define FRAME_MAXLEN 4096
  45. enum dg100_command_id {
  46. dg100cmd_getconfig = 0xB7,
  47. dg100cmd_setconfig = 0xB8,
  48. dg100cmd_getfileheader = 0xBB,
  49. dg100cmd_getfile = 0xB5,
  50. dg100cmd_erase = 0xBA,
  51. dg100cmd_getid = 0xBF,
  52. dg100cmd_setid = 0xC0,
  53. dg100cmd_gpsmouse = 0xBC,
  54. dg200cmd_reset = 0x80
  55. };
  56. struct dg100_command {
  57. int id;
  58. int sendsize;
  59. int recvsize;
  60. int trailing_bytes;
  61. const char* text; /* Textual description for debugging */
  62. };
  63. struct dg100_command dg100_commands[] = {
  64. { dg100cmd_getfile, 2, 1024, 2, "getfile" },
  65. /* the getfileheader answer has variable length, -1 is a dummy value */
  66. { dg100cmd_getfileheader, 2, -1, 2, "getfileheader" },
  67. { dg100cmd_erase, 2, 4, 2, "erase" },
  68. { dg100cmd_getconfig, 0, 44, 2, "getconfig" },
  69. { dg100cmd_setconfig, 41, 4, 2, "setconfig" },
  70. { dg100cmd_getid, 0, 8, 2, "getid" },
  71. { dg100cmd_setid, 8, 4, 2, "setid" },
  72. { dg100cmd_gpsmouse, 1, 0, 0, "gpsmouse" }
  73. };
  74. struct dg100_command dg200_commands[] = {
  75. { dg100cmd_getfile, 2, 1024, 2, "getfile" },
  76. /* the getfileheader answer has variable length, -1 is a dummy value */
  77. { dg100cmd_getfileheader, 2, -1, 2, "getfileheader" },
  78. { dg100cmd_erase, 2, 4, 2, "erase" },
  79. { dg100cmd_getconfig, 0, 45, 2, "getconfig" },
  80. { dg100cmd_setconfig, 42, 4, 2, "setconfig" },
  81. { dg100cmd_getid, 0, 8, 2, "getid" },
  82. { dg100cmd_setid, 8, 4, 2, "setid" },
  83. { dg100cmd_gpsmouse, 1, 0, 0, "gpsmouse" },
  84. { dg200cmd_reset , 24, 0, 0, "reset" }
  85. };
  86. struct dynarray16 {
  87. unsigned count; /* number of elements used */
  88. unsigned limit; /* number of elements allocated */
  89. int16_t* data;
  90. };
  91. /* helper functions */
  92. static struct dg100_command*
  93. dg100_findcmd(int id) {
  94. unsigned int i;
  95. /* linear search should be OK as long as dg100_numcommands is small */
  96. for (i = 0; i < model->numcommands; i++) {
  97. if (model->commands[i].id == id) {
  98. return(&model->commands[i]);
  99. }
  100. }
  101. return NULL;
  102. }
  103. static void
  104. dynarray16_init(struct dynarray16* a, unsigned limit)
  105. {
  106. a->count = 0;
  107. a->limit = limit;
  108. a->data = (int16_t*) xmalloc(sizeof(a->data[0]) * a->limit);
  109. }
  110. static int16_t*
  111. dynarray16_alloc(struct dynarray16* a, unsigned n)
  112. {
  113. unsigned oldcount, need;
  114. const unsigned elements_per_chunk = 4096 / sizeof(a->data[0]);
  115. oldcount = a->count;
  116. a->count += n;
  117. if (a->count > a->limit) {
  118. need = a->count - a->limit;
  119. need = (need > elements_per_chunk) ? need : elements_per_chunk;
  120. a->limit += need;
  121. a->data = (int16_t*) xrealloc(a->data, sizeof(a->data[0]) * a->limit);
  122. }
  123. return(a->data + oldcount);
  124. }
  125. static time_t
  126. bintime2utc(int date, int time)
  127. {
  128. struct tm gpstime;
  129. gpstime.tm_sec = time % 100;
  130. time /= 100;
  131. gpstime.tm_min = time % 100;
  132. time /= 100;
  133. gpstime.tm_hour = time;
  134. /*
  135. * GPS year: 2000+; struct tm year: 1900+
  136. * GPS month: 1-12, struct tm month: 0-11
  137. */
  138. gpstime.tm_year = date % 100 + 100;
  139. date /= 100;
  140. gpstime.tm_mon = date % 100 - 1;
  141. date /= 100;
  142. gpstime.tm_mday = date;
  143. return(mkgmtime(&gpstime));
  144. }
  145. static void
  146. dg100_debug(const char* hdr, int include_nl, size_t sz, unsigned char* buf)
  147. {
  148. unsigned int i;
  149. /* Only give byte dumps for higher debug levels */
  150. if (global_opts.debug_level < 5) {
  151. return;
  152. }
  153. fprintf(stderr, "%s", hdr);
  154. for (i = 0; i < sz; i++) {
  155. fprintf(stderr, "%02x ", buf[i]);
  156. }
  157. if (include_nl) {
  158. fprintf(stderr, "\n");
  159. }
  160. }
  161. static void
  162. dg100_log(const char* fmt, ...)
  163. {
  164. va_list ap;
  165. va_start(ap, fmt);
  166. if (global_opts.debug_level > 0) {
  167. vfprintf(stderr, fmt, ap);
  168. }
  169. va_end(ap);
  170. }
  171. /* TODO: check whether negative lat/lon (West/South) are handled correctly */
  172. static float
  173. bin2deg(int val)
  174. {
  175. /* Assume that val prints in decimal digits as [-]dddmmffff
  176. * ddd: degrees
  177. * mm: the integer part of minutes
  178. * ffff: the fractional part of minutes (decimal fraction 0.ffff)
  179. */
  180. float deg;
  181. int deg_int, min_scaled, isneg;
  182. unsigned absval;
  183. /* avoid division of negative integers,
  184. * which has platform-dependent results */
  185. absval = abs(val);
  186. isneg = (val < 0);
  187. deg_int = absval / 1000000; /* extract ddd */
  188. min_scaled = absval % 1000000; /* extract mmffff (minutes * 10^4) */
  189. deg = deg_int + (double) min_scaled / (10000 * 60);
  190. /* restore the sign */
  191. deg = isneg ? -deg : deg;
  192. return(deg);
  193. }
  194. static void
  195. process_gpsfile(uint8_t data[], route_head** track)
  196. {
  197. const int recordsizes[3] = {8, 20, 32};
  198. int i, style, recsize;
  199. int lat, lon, bintime, bindate;
  200. Waypoint* wpt;
  201. /* the first record of each file is always full-sized; its style field
  202. * determines the format of all subsequent records in the file */
  203. style = be_read32(data + 28);
  204. if (style > 2) {
  205. fprintf(stderr, "unknown GPS record style %d", style);
  206. return;
  207. }
  208. recsize = recordsizes[style];
  209. for (i = 0; i <= 2048 - recsize; i += (i == 0) ? 32 : recsize) {
  210. float latitude;
  211. int manual_point = 0;
  212. lat = be_read32(data + i + 0);
  213. lon = be_read32(data + i + 4);
  214. /* skip invalid trackpoints (blank records) */
  215. if (lat == -1 && lon == -1) {
  216. continue;
  217. }
  218. if ((i == 0) && (be_read32(data + i + 8) & 0x80000000)) {
  219. /* This is the first point recorded after power-on; start a new track */
  220. *track = NULL;
  221. }
  222. if (*track == NULL) {
  223. time_t creation_time;
  224. char buf[1024];
  225. bintime = be_read32(data + i + 8) & 0x7FFFFFFF;
  226. bindate = be_read32(data + i + 12);
  227. creation_time = bintime2utc(bindate, bintime);
  228. strncpy(buf, model->name, sizeof(buf));
  229. strftime(&buf[strlen(model->name)], sizeof(buf)-strlen(model->name), " tracklog (%Y/%m/%d %H:%M:%S)",
  230. gmtime(&creation_time));
  231. *track = route_head_alloc();
  232. (*track)->rte_name = buf;
  233. (*track)->rte_desc = "GPS tracklog data";
  234. track_add_head(*track);
  235. }
  236. wpt = new Waypoint;
  237. latitude = bin2deg(lat);
  238. if (latitude >= 100) {
  239. manual_point = 1;
  240. latitude -= 100;
  241. } else if (latitude <= -100) {
  242. manual_point = 1;
  243. latitude += 100;
  244. }
  245. wpt->latitude = latitude;
  246. wpt->longitude = bin2deg(lon);
  247. if (style >= 1) {
  248. bintime = be_read32(data + i + 8) & 0x7FFFFFFF;
  249. bindate = be_read32(data + i + 12);
  250. wpt->SetCreationTime(bintime2utc(bindate, bintime));
  251. /* The device presents the speed as a fixed-point number
  252. * with a scaling factor of 100, in km/h.
  253. * The waypoint struct wants the speed as a
  254. * floating-point number, in m/s. */
  255. wpt->speed = KPH_TO_MPS(be_read32(data + i + 16) / 100.0);
  256. wpt->wpt_flags.speed = 1;
  257. }
  258. if (style >= 2) {
  259. wpt->altitude = be_read32(data + i + 20) / 10000.0;
  260. }
  261. if (manual_point) {
  262. waypt_add(wpt);
  263. } else {
  264. track_add_wpt(*track, wpt);
  265. }
  266. }
  267. }
  268. static uint16_t
  269. dg100_checksum(uint8_t buf[], int count)
  270. {
  271. uint16_t sum = 0;
  272. int i;
  273. for (i = 0; i < count; i++) {
  274. sum += buf[i];
  275. }
  276. sum &= (1<<15) - 1;
  277. return(sum);
  278. }
  279. /* communication functions */
  280. static size_t
  281. dg100_send(uint8_t cmd, const void* payload, size_t param_len)
  282. {
  283. uint8_t frame[FRAME_MAXLEN];
  284. uint16_t checksum, payload_len;
  285. size_t framelen;
  286. int n;
  287. payload_len = 1 + param_len;
  288. /* Frame length calculation:
  289. * frame start sequence(2), payload length field(2), command id(1),
  290. * param(variable length),
  291. * checksum(2), frame end sequence(2) */
  292. framelen = 2 + 2 + 1 + param_len + 2 + 2;
  293. assert(framelen <= FRAME_MAXLEN);
  294. /* create frame head + command */
  295. be_write16(frame + 0, 0xA0A2);
  296. be_write16(frame + 2, payload_len);
  297. frame[4] = cmd;
  298. /* copy payload */
  299. memcpy(frame + 5, payload, param_len);
  300. /* create frame tail */
  301. checksum = dg100_checksum(frame + 4, framelen - 8);
  302. be_write16(frame + framelen - 4, checksum);
  303. be_write16(frame + framelen - 2, 0xB0B3);
  304. n = gbser_write(serial_handle, frame, framelen);
  305. if (global_opts.debug_level) {
  306. struct dg100_command* cmdp = dg100_findcmd(cmd);
  307. dg100_debug(n == 0 ? "Sent: " : "Error Sending:",
  308. 1, framelen, frame);
  309. dg100_log("TX: Frame Start %02x %02x Payload_Len %04x Cmd: %s\n",
  310. frame[0], frame[1], payload_len, cmdp->text);
  311. }
  312. if (n == gbser_ERROR) {
  313. fatal("dg_100_send: write failed\n");
  314. }
  315. return (n);
  316. }
  317. static int
  318. dg100_recv_byte()
  319. {
  320. int result;
  321. /* allow for a delay of 40s;
  322. * erasing the whole DG-100 memory takes about 21s */
  323. result = gbser_readc_wait(serial_handle, 40000);
  324. switch (result) {
  325. case gbser_ERROR:
  326. fatal("dg100_recv_byte(): error reading one byte\n");
  327. case gbser_NOTHING:
  328. fatal("dg100_recv_byte(): read timeout\n");
  329. }
  330. return result;
  331. }
  332. /* payload returns a pointer into a static buffer (which also contains the
  333. * framing around the data), so the caller must copy the data before calling
  334. * this function again */
  335. static int
  336. dg100_recv_frame(struct dg100_command** cmdinfo_result, uint8_t** payload)
  337. {
  338. static uint8_t buf[FRAME_MAXLEN];
  339. uint16_t frame_start_seq, payload_len_field;
  340. uint16_t payload_end_seq, payload_checksum, frame_end_seq;
  341. uint16_t frame_head, numheaders, sum;
  342. uint8_t c, cmd;
  343. int i, param_len, frame_len;
  344. struct dg100_command* cmdinfo;
  345. /* consume input until frame head sequence 0xA0A2 was received */
  346. frame_head = 0;
  347. dg100_debug("Receiving ", 0, 0, NULL);
  348. do {
  349. c = dg100_recv_byte();
  350. dg100_debug("", 0, 1, &c);
  351. frame_head <<= 8;
  352. frame_head |= c;
  353. } while (frame_head != 0xA0A2);
  354. be_write16(buf + 0, frame_head);
  355. /* To read the remaining data, we need to know how long the frame is.
  356. *
  357. * The obvious source of this information would be the payload length
  358. * field, but the spec says that this field should be ignored in answers.
  359. * Indeed, its value differs from the actual payload length.
  360. *
  361. * We could scan for the frame end sequences,
  362. * but there is no guarantee that they do not appear within valid data.
  363. *
  364. * This means we can only calculate the length using information from
  365. * the beginning of the frame, other than the payload length.
  366. *
  367. * The solution implemented here is to derive the frame length from the
  368. * Command ID field, which is more of an answer ID. This is possible
  369. * since for each answer ID, the frame length is either constant or it
  370. * can be derived from the first two bytes of payload data.
  371. */
  372. /* read Payload Length, Command ID, and two further bytes */
  373. i = gbser_read_wait(serial_handle, &buf[2], 5, 1000);
  374. if (i < 5) {
  375. fatal("Expected to read 5 bytes, but got %d\n", i);
  376. }
  377. dg100_debug("", 0, 5, &buf[2]);
  378. payload_len_field = be_read16(buf + 2);
  379. cmd = buf[4];
  380. /*
  381. * getconfig/setconfig have the same answer ID -
  382. * this seems to be a firmware bug we must work around.
  383. * Distinguish them by the (otherwise ignored) Payload Len field,
  384. * which was observed as 53 for getconfig and 5 for setconfig.
  385. */
  386. if (cmd == dg100cmd_getconfig && payload_len_field <= 20) {
  387. cmd = dg100cmd_setconfig;
  388. }
  389. cmdinfo = dg100_findcmd(cmd);
  390. if (!cmdinfo) {
  391. /* TODO: consume data until frame end signature,
  392. * then report failure to the caller? */
  393. fatal("unknown answer ID %02x\n", cmd);
  394. }
  395. param_len = cmdinfo->recvsize;
  396. /*
  397. * the getfileheader answer has a varying param_len,
  398. * we need to calculate it
  399. */
  400. if (cmd == dg100cmd_getfileheader) {
  401. numheaders = be_read16(buf + 5);
  402. param_len = 2 + 2 + 12 * numheaders;
  403. }
  404. if (model->has_trailing_bytes) {
  405. param_len += cmdinfo->trailing_bytes;
  406. }
  407. /* Frame length calculation:
  408. * frame start sequence(2), payload length field(2), command id(1),
  409. * param(variable length),
  410. * payload end sequence(2 or 0), checksum(2), frame end sequence(2) */
  411. frame_len = 2 + 2 + 1 + param_len + ((model->has_payload_end_seq) ? 2 : 0) + 2 + 2;
  412. if (frame_len > FRAME_MAXLEN) {
  413. fatal("frame too large (frame_len=%d, FRAME_MAXLEN=%d)\n",
  414. frame_len, FRAME_MAXLEN);
  415. }
  416. i = gbser_read_wait(serial_handle, &buf[7], frame_len - 7, 1000);
  417. if (i < frame_len - 7) {
  418. fatal("Expected to read %d bytes, but got %d\n",
  419. frame_len - 7, i);
  420. }
  421. dg100_debug("", 0, frame_len - 7, &buf[7]);
  422. frame_start_seq = be_read16(buf + 0);
  423. payload_len_field = be_read16(buf + 2);
  424. if (model->has_payload_end_seq) {
  425. payload_end_seq = be_read16(buf + frame_len - 6);
  426. }
  427. payload_checksum = be_read16(buf + frame_len - 4);
  428. frame_end_seq = be_read16(buf + frame_len - 2);
  429. (void) payload_end_seq;
  430. (void) frame_end_seq;
  431. dg100_log("RX: Start %04x Len %04x Cmd: %s\n",
  432. frame_start_seq, payload_len_field, cmdinfo->text);
  433. /* calculate checksum */
  434. sum = dg100_checksum(buf + 4, frame_len - 8);
  435. if (sum != payload_checksum) {
  436. fatal("checksum mismatch: data sum is 0x%04x, checksum received is 0x%04x\n",
  437. sum, payload_checksum);
  438. }
  439. /*
  440. * TODO: check signatures;
  441. * on failure, flush input or scan for end sequence
  442. */
  443. *cmdinfo_result = cmdinfo;
  444. *payload = buf + 5;
  445. dg100_debug("\n", 0, 0, &buf[i]);
  446. return(param_len);
  447. }
  448. /* return value: number of bytes copied into buf, -1 on error */
  449. static int
  450. dg100_recv(uint8_t expected_id, void* buf, unsigned int len)
  451. {
  452. int n;
  453. struct dg100_command* cmdinfo;
  454. uint8_t* data;
  455. unsigned int copysize, trailing_bytes;
  456. n = dg100_recv_frame(&cmdinfo, &data);
  457. /* check whether the received frame matches the expected answer type */
  458. if (cmdinfo->id != expected_id) {
  459. fprintf(stderr, "ERROR: answer type %02x, expecting %02x", cmdinfo->id, expected_id);
  460. return -1;
  461. }
  462. trailing_bytes = (model->has_trailing_bytes) ? (cmdinfo->trailing_bytes) : 0;
  463. copysize = n - trailing_bytes;
  464. /* check for buffer overflow */
  465. if (len < copysize) {
  466. fprintf(stderr, "ERROR: buffer too small, size=%d, need=%d", len, copysize);
  467. return -1;
  468. }
  469. memcpy(buf, data, copysize);
  470. return(copysize);
  471. }
  472. /* the number of bytes to be sent is determined by cmd,
  473. * count is the size of recvbuf */
  474. static int
  475. dg100_request(uint8_t cmd, const void* sendbuf, void* recvbuf, size_t count)
  476. {
  477. struct dg100_command* cmdinfo;
  478. int n, i, frames, fill;
  479. uint8_t* buf;
  480. cmdinfo = dg100_findcmd(cmd);
  481. assert(cmdinfo != NULL);
  482. dg100_send(cmd, sendbuf, cmdinfo->sendsize);
  483. /* the number of frames the answer will comprise */
  484. frames = (cmd == dg100cmd_getfile) ? 2 : 1;
  485. /* alias pointer for easy typecasting */
  486. buf = (uint8_t*) recvbuf;
  487. fill = 0;
  488. for (i = 0; i < frames; i++) {
  489. n = dg100_recv(cmd, buf + fill, count - fill);
  490. if (n < 0) {
  491. return(-1);
  492. }
  493. fill += n;
  494. }
  495. return(fill);
  496. }
  497. /* higher level communication functions */
  498. static void
  499. dg100_getfileheaders(struct dynarray16* headers)
  500. {
  501. uint8_t request[2];
  502. uint8_t answer[FRAME_MAXLEN];
  503. int seqnum;
  504. int16_t numheaders, nextheader, *h;
  505. int i, offset;
  506. nextheader = 0;
  507. do {
  508. /* request the next batch of headers */
  509. be_write16(request, nextheader);
  510. dg100_request(dg100cmd_getfileheader, request, answer, sizeof(answer));
  511. /* process the answer */
  512. numheaders = be_read16(answer);
  513. nextheader = be_read16(answer + 2);
  514. dg100_log("found %d headers, nextheader=%d\n",
  515. numheaders, nextheader);
  516. if (numheaders <= 0) {
  517. dg100_log("no further headers, aborting the loop\n");
  518. break;
  519. }
  520. h = dynarray16_alloc(headers, numheaders);
  521. for (i = 0; i < numheaders; i++) {
  522. offset = 4 + i * 12;
  523. seqnum = be_read32(answer + offset + 8);
  524. h[i] = seqnum;
  525. if (global_opts.debug_level) {
  526. int time = be_read32(answer + offset) & 0x7FFFFFFF;
  527. int date = be_read32(answer + offset + 4);
  528. time_t ti = bintime2utc(date, time);
  529. dg100_log("Header #%d: Seq: %d Time: %s",
  530. i, seqnum, ctime(&ti));
  531. }
  532. }
  533. } while (nextheader != 0);
  534. }
  535. static void
  536. dg100_getconfig()
  537. {
  538. uint8_t answer[45];
  539. dg100_request(dg100cmd_getconfig, NULL, answer, sizeof(answer));
  540. }
  541. static void
  542. dg100_getfile(int16_t num, route_head** track)
  543. {
  544. uint8_t request[2];
  545. uint8_t answer[2048];
  546. be_write16(request, num);
  547. dg100_request(dg100cmd_getfile, request, answer, sizeof(answer));
  548. process_gpsfile(answer, track);
  549. }
  550. static void
  551. dg100_getfiles()
  552. {
  553. unsigned int i;
  554. int filenum;
  555. struct dynarray16 headers;
  556. route_head* track = NULL;
  557. /* maximum number of headers observed so far: 672
  558. * if necessary, the dynarray will grow even further */
  559. dynarray16_init(&headers, 1024);
  560. dg100_getfileheaders(&headers);
  561. for (i = 0; i < headers.count; i++) {
  562. filenum = headers.data[i];
  563. dg100_getfile(filenum, &track);
  564. }
  565. dg100_getconfig(); // To light on the green LED on the DG-200
  566. }
  567. static int
  568. dg100_erase()
  569. {
  570. uint8_t request[2] = { 0xFF, 0xFF };
  571. uint8_t answer[4];
  572. dg100_request(dg100cmd_erase, request, answer, sizeof(answer));
  573. if (be_read32(answer) != 1) {
  574. fprintf(stderr, "dg100_erase() FAILED\n");
  575. return(-1);
  576. }
  577. return(0);
  578. }
  579. /* GPSBabel integration */
  580. static char* erase;
  581. static char* erase_only;
  582. static
  583. arglist_t dg100_args[] = {
  584. {
  585. "erase", &erase, "Erase device data after download",
  586. "0", ARGTYPE_BOOL, ARG_NOMINMAX
  587. },
  588. {
  589. "erase_only", &erase_only, "Only erase device data, do not download anything",
  590. "0", ARGTYPE_BOOL, ARG_NOMINMAX
  591. },
  592. ARG_TERMINATOR
  593. };
  594. /*******************************************************************************
  595. * %%% global callbacks called by gpsbabel main process %%% *
  596. *******************************************************************************/
  597. static void
  598. common_rd_init(const QString& fname)
  599. {
  600. if (serial_handle = gbser_init(qPrintable(fname)), NULL == serial_handle) {
  601. fatal(MYNAME ": Can't open port '%s'\n", qPrintable(fname));
  602. }
  603. if (gbser_set_speed(serial_handle, model->speed) != gbser_OK) {
  604. fatal(MYNAME ": Can't configure port '%s'\n", qPrintable(fname));
  605. }
  606. // Toss anything that came in before our speed was set, particularly
  607. // for the bluetooth BT-335 product.
  608. gbser_flush(serial_handle);
  609. }
  610. static void
  611. dg100_rd_init(const QString& fname)
  612. {
  613. static const model_t dg100_model = { "DG-100", 115200, 1, 1, dg100_commands, sizeof(dg100_commands) / sizeof(struct dg100_command) };
  614. model = &dg100_model;
  615. common_rd_init(fname);
  616. }
  617. static void
  618. dg200_rd_init(const QString& fname)
  619. {
  620. static const model_t dg200_model = { "DG-200", 230400, 0, 0, dg200_commands, sizeof(dg200_commands) / sizeof(struct dg100_command) };
  621. model = &dg200_model;
  622. common_rd_init(fname);
  623. }
  624. static void
  625. dg100_rd_deinit(void)
  626. {
  627. gbser_deinit(serial_handle);
  628. serial_handle = NULL;
  629. }
  630. static void
  631. dg100_read(void)
  632. {
  633. if (*erase_only == '1') {
  634. dg100_erase();
  635. return;
  636. }
  637. dg100_getfiles();
  638. if (*erase == '1') {
  639. dg100_erase();
  640. }
  641. }
  642. /**************************************************************************/
  643. // capabilities below means: we can read tracks and waypoints
  644. ff_vecs_t dg100_vecs = {
  645. ff_type_serial,
  646. {
  647. ff_cap_read /* waypoints */,
  648. ff_cap_read /* tracks */,
  649. ff_cap_none /* routes */
  650. },
  651. dg100_rd_init,
  652. NULL,
  653. dg100_rd_deinit,
  654. NULL,
  655. dg100_read,
  656. NULL,
  657. NULL,
  658. dg100_args,
  659. CET_CHARSET_ASCII, 0 /* ascii is the expected character set */
  660. /* not fixed, can be changed through command line parameter */
  661. };
  662. ff_vecs_t dg200_vecs = {
  663. ff_type_serial,
  664. {
  665. ff_cap_read /* waypoints */,
  666. ff_cap_read /* tracks */,
  667. ff_cap_none /* routes */
  668. },
  669. dg200_rd_init,
  670. NULL,
  671. dg100_rd_deinit,
  672. NULL,
  673. dg100_read,
  674. NULL,
  675. NULL,
  676. dg100_args,
  677. CET_CHARSET_ASCII, 0 /* ascii is the expected character set */
  678. /* not fixed, can be changed through command line parameter */
  679. };
  680. /**************************************************************************/