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.

880 lines
28KB

  1. /*
  2. Global data for GPSBabel.
  3. Copyright (C) 2012-2016, Zingo Andersen zingo@zingo.org
  4. Copyright (C) 2016 Robert Lipe, robertlipe+source@gpsbabel.org
  5. This program is free software; you can redistribute it and/or modify
  6. it under the terms of the GNU General Public License as published by
  7. the Free Software Foundation; either version 2 of the License, or
  8. (at your option) any later version.
  9. This program is distributed in the hope that it will be useful,
  10. but WITHOUT ANY WARRANTY; without even the implied warranty of
  11. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  12. GNU General Public License for more details.
  13. You should have received a copy of the GNU General Public License
  14. along with this program; if not, write to the Free Software
  15. Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111 USA
  16. */
  17. /*
  18. * This is the bridge between the GPSBabel and globalsat sport devices
  19. * gh625XT. Globalsat has a few devices under the sport brand and they
  20. * are using a similar USB serial protocal.
  21. * Currently only gh625XT is supported by this driver but the code could
  22. * extended (maybe autodetect) support more devices in the future.
  23. *
  24. * The code is based on GH625XT-COMMUNICATION_SPECS_20111205-1.pdf from Globasat
  25. * that they nicely supplied on request.
  26. *
  27. * Usage examples:
  28. * gpsbabel -i globalsat -f /dev/ttyUSB0 -o gpx,garminextensions -F xxx.gpx
  29. * gpsbabel -i globalsat -f /dev/ttyUSB0 -o gtrnctr,course=0,sport=Running -F xxx.fit
  30. *
  31. */
  32. #include <ctype.h>
  33. #include <limits.h>
  34. #include <stdio.h>
  35. #include "defs.h"
  36. #include "gbser.h"
  37. #define MYNAME "GlobalsatSport"
  38. static void* serial_handle;
  39. static int isSizeSwaped;
  40. static char* showlist = NULL; // if true show a list instead of download tracks
  41. static char* track = 0; // if not 0 only download this track, if 0 download all
  42. static char* opt_dump_file = 0; // dump raw data to this file (optional)
  43. static char* opt_input_dump_file = NULL; // if true input is from a dump-file instead of serial console
  44. static gbfile* dumpfile = NULL; // used for creating bin/RAW datadump files, usefull for testing
  45. static gbfile* in_file = NULL; // used for reading from bin/RAW datadump files, usefull for testing
  46. static
  47. arglist_t globalsat_args[] = {
  48. {"showlist", &showlist, "list tracks", NULL, ARGTYPE_BOOL, ARG_NOMINMAX},
  49. {"track", &track, "get track", "0", ARGTYPE_INT, ARG_NOMINMAX},
  50. {"dump-file", &opt_dump_file, "Dump raw data to this file", NULL, ARGTYPE_OUTFILE, ARG_NOMINMAX},
  51. {"input-is-dump-file", &opt_input_dump_file, "Dump raw data to this file", NULL, ARGTYPE_BOOL, ARG_NOMINMAX},
  52. ARG_TERMINATOR
  53. };
  54. typedef enum {
  55. CommandWhoAmI = 0xBF,
  56. CommandGetSystemInformation = 0x85,
  57. CommandGetSystemConfiguration = 0x86,
  58. CommandSetSystemConfiguration = 0x96,
  59. CommandSetSystemInformation = 0x98,
  60. CommandGetScreenshot = 0x83,
  61. CommandGetWaypoints = 0x77,
  62. CommandSendWaypoint = 0x76,
  63. CommandDeleteWaypoints = 0x75,
  64. CommandSendRoute = 0x93,
  65. CommandDeleteAllRoutes = 0x97,
  66. CommandGetTrackFileHeaders = 0x78,
  67. CommandGetTrackFileSections = 0x80,
  68. CommandGetNextTrackSection = 0x81,
  69. //CommandReGetLastSection = 0x82,
  70. CommandId_FINISH = 0x8A,
  71. CommandSendTrackStart = 0x90,
  72. CommandSendTrackSection = 0x91,
  73. HeaderTypeLaps = 0xAA,
  74. HeaderTypeTrackPoints = 0x55,
  75. ResponseInsuficientMemory = 0x95,
  76. ResponseResendTrackSection = 0x92,
  77. ResponseSendTrackFinish = 0x9A
  78. } globalsat_commands_e;
  79. typedef struct tagDATE {
  80. uint8_t Year;
  81. uint8_t Month;
  82. uint8_t Day;
  83. } gh_date;
  84. typedef struct tagTIME {
  85. uint8_t Hour;
  86. uint8_t Minute;
  87. uint8_t Second;
  88. } gh_time;
  89. typedef struct tagTRAINHEADER {
  90. gh_date dateStart;
  91. gh_time timeStart;
  92. uint32_t TotalPoint; //6-9
  93. uint32_t TotalTime; //10-13
  94. uint32_t TotalDistance; //14-17
  95. uint16_t LapCnts; //18-19
  96. union {
  97. uint32_t Index;
  98. uint32_t StartPt;
  99. } gh_ptrec; //20-23
  100. union {
  101. uint32_t LapIndex;
  102. uint32_t EndPt;
  103. } gh_laprec; //24-27
  104. uint8_t DataType; //28
  105. } gh_trainheader;
  106. typedef struct tagDB_TRAIN {
  107. gh_date dateStart;
  108. gh_time timeStart;
  109. uint32_t TotalPoint; //6-9
  110. uint32_t TotalTime; //10-13
  111. uint32_t TotalDistance; //14-17
  112. uint16_t LapCnts; //18-19
  113. union {
  114. uint32_t Index;
  115. uint32_t StartPt;
  116. } gh_ptrec; //20-23
  117. union {
  118. uint32_t LapIndex;
  119. uint32_t EndPt;
  120. } gh_laprec; //24-27
  121. uint8_t MultiSport; //28 on/off
  122. uint16_t Calory; //29-30
  123. uint32_t MaxSpeed;
  124. uint8_t MaxHeart;
  125. uint8_t AvgHeart;
  126. uint16_t Ascent;
  127. uint16_t Descent;
  128. int16_t MinAlti;
  129. int16_t MaxAlti;
  130. uint16_t AvgCadns;
  131. uint16_t BestCadns;
  132. uint16_t AvgPower;
  133. uint16_t MaxPower;
  134. uint8_t Sport1;
  135. uint8_t Sport2;
  136. uint8_t Sport3;
  137. uint8_t Sport4;
  138. uint8_t Sport5;
  139. } gh_db_train;
  140. typedef struct tagDB_LAP {
  141. uint32_t AccruedTime;
  142. uint32_t TotalTime;
  143. uint32_t TotalDistance;
  144. uint16_t Calory;
  145. uint32_t MaxSpeed;
  146. uint8_t MaxHeart;
  147. uint8_t AvgHeart;
  148. int16_t MinAlti;
  149. int16_t MaxAlti;
  150. uint16_t AvgCadns;
  151. uint16_t BestCadns;
  152. uint16_t AvgPower;
  153. uint16_t MaxPower;
  154. uint8_t MultiSportIndex;
  155. uint32_t StartPt;
  156. uint32_t EndPt;
  157. } gh_db_lap;
  158. typedef struct tagRECPOINT {
  159. uint32_t Latitude;
  160. uint32_t Longitude;
  161. int16_t Altitude;
  162. uint32_t Speed;
  163. uint8_t HeartRate;
  164. uint32_t IntervalTime;
  165. uint16_t Cadence;
  166. uint16_t PwrCadence;
  167. uint16_t Power;
  168. } gh_recpoint;
  169. static void
  170. serial_init(const char* fname)
  171. {
  172. if (serial_handle = gbser_init(fname), NULL == serial_handle) {
  173. fatal(MYNAME ": Can't open port '%s'\n", fname);
  174. }
  175. if (gbser_set_speed(serial_handle, 115200) != gbser_OK) {
  176. fatal(MYNAME ": Can't configure port '%s'\n", fname);
  177. }
  178. // Toss anything that came in before our speed was set
  179. gbser_flush(serial_handle);
  180. }
  181. static void
  182. serial_deinit(void)
  183. {
  184. if (global_opts.debug_level > 1) {
  185. printf(MYNAME " serial_deinit()\n");
  186. }
  187. gbser_deinit(serial_handle);
  188. serial_handle = NULL;
  189. if (global_opts.debug_level > 1) {
  190. printf(MYNAME " serial_deinit() Done\n");
  191. }
  192. }
  193. static int
  194. serial_recv_byte()
  195. {
  196. int result;
  197. /* allow for a delay of 4s */
  198. result = gbser_readc_wait(serial_handle, 4000);
  199. switch (result) {
  200. case gbser_ERROR:
  201. fatal("serial_recv_byte(): error reading one byte\n");
  202. break;
  203. case gbser_NOTHING:
  204. fatal("serial_recv_byte(): read timeout\n");
  205. break;
  206. }
  207. return result;
  208. }
  209. static void
  210. serial_write_byte(uint8_t byte)
  211. {
  212. int n;
  213. if (global_opts.debug_level > 1) {
  214. printf("0x%02x (%d), ", byte, byte);
  215. }
  216. n = gbser_writec(serial_handle, byte);
  217. if (n == gbser_ERROR) {
  218. fatal("globalsat_probe_device(): write failed\n");
  219. }
  220. }
  221. static int
  222. recv_byte()
  223. {
  224. int result=0;
  225. // Read from serial or dumpfile
  226. if (!opt_input_dump_file) {
  227. result=serial_recv_byte();
  228. } else {
  229. int bytes;
  230. bytes=gbfread(&result, 1, 1, in_file);
  231. is_fatal((bytes != 1), MYNAME ": read error");
  232. }
  233. // Check if byte sould be dumped also into a file
  234. if (dumpfile) {
  235. gbfwrite(&result, 1, 1, dumpfile);
  236. }
  237. return result;
  238. }
  239. static void
  240. write_byte(uint8_t byte)
  241. {
  242. // Write serial or not at all if input is a dumpfile
  243. if (!opt_input_dump_file) {
  244. serial_write_byte(byte);
  245. }
  246. //else {
  247. // Do nothing as commands are not used when dumpfile is used instead
  248. // of serial device
  249. //}
  250. }
  251. static void
  252. globalsat_write_package(uint8_t* payload, uint32_t size)
  253. {
  254. //All globalsat devices but gh561
  255. //2 <len_h> <len_l> <payload...> <crc>
  256. // gh561 (isSizeSwaped)
  257. //2 <len_l> <len_h> <payload...> <crc>
  258. uint32_t i;
  259. uint8_t crc = 0;
  260. write_byte(2);
  261. if (!isSizeSwaped) {
  262. write_byte((0xff00 & size) >> 8);
  263. crc ^= (0xff00 & size) >> 8;
  264. write_byte(0xff & size);
  265. crc ^= (0xff & size);
  266. } else {
  267. write_byte(0xff & size);
  268. crc ^= (0xff & size);
  269. write_byte((0xff00 & size) >> 8);
  270. crc ^= (0xff00 & size) >> 8;
  271. }
  272. if (payload != NULL) {
  273. for (i = 0; i < size; i++) {
  274. write_byte(payload[i]);
  275. crc ^= payload[i];
  276. }
  277. }
  278. write_byte(crc);
  279. if (global_opts.debug_level > 1) {
  280. printf("\n");
  281. }
  282. }
  283. static uint8_t*
  284. globalsat_read_package(int* out_length, uint8_t* out_DeviceCommand)
  285. {
  286. uint8_t DeviceCommand, len_h, len_l, crc;
  287. uint8_t* payload;
  288. int length;
  289. int i;
  290. uint8_t calc_crc = 0;
  291. DeviceCommand = recv_byte();
  292. if (global_opts.debug_level > 1) {
  293. printf("DeviceCommand: 0x%02x ", DeviceCommand);
  294. }
  295. len_h = recv_byte();
  296. calc_crc ^= len_h;
  297. len_l = recv_byte();
  298. calc_crc ^= len_l;
  299. length = (len_h << 8) + len_l;
  300. if (global_opts.debug_level > 1) {
  301. printf("len=%d Payload:", length);
  302. }
  303. payload = (uint8_t*) malloc(length);
  304. if (payload == NULL) {
  305. goto error_out;
  306. }
  307. for (i = 0; i < length; i++) {
  308. payload[i] = recv_byte();
  309. calc_crc ^= payload[i];
  310. }
  311. crc = recv_byte();
  312. if (global_opts.debug_level > 1) {
  313. printf("crc=0x%x should be=0x%x\n", crc, calc_crc);
  314. }
  315. if (crc == calc_crc) {
  316. *out_DeviceCommand = DeviceCommand;
  317. *out_length = length;
  318. return payload;
  319. }
  320. //crc error
  321. free(payload);
  322. error_out:
  323. *out_length = 0;
  324. return NULL;
  325. }
  326. /*
  327. * Send one byte package
  328. */
  329. static void
  330. globalsat_send_simple(uint8_t command)
  331. {
  332. uint8_t payload[1];
  333. payload[0] = command;
  334. globalsat_write_package(payload, 1);
  335. }
  336. static void
  337. globalsat_probe_device()
  338. {
  339. //TODO try this first if fails try with false, to support 561
  340. isSizeSwaped = FALSE; //all devices but gh561 since gh561 has swaped size.
  341. globalsat_send_simple(CommandWhoAmI);
  342. uint8_t* payload;
  343. int len;
  344. uint8_t DeviceCommand;
  345. payload = globalsat_read_package(&len, &DeviceCommand);
  346. if ((len > 0) && (payload != NULL)) {
  347. if (global_opts.debug_level > 1) {
  348. printf("Got package!!!\n");
  349. }
  350. //TODO figure out what device it is if we start to support more devices then gh625XT
  351. }
  352. if (payload) {
  353. free(payload);
  354. }
  355. }
  356. static void
  357. rd_init(const QString& fname)
  358. {
  359. if (global_opts.debug_level > 1) {
  360. printf(MYNAME " rd_init()\n");
  361. }
  362. if (opt_dump_file) {
  363. dumpfile = gbfopen(opt_dump_file, "w", MYNAME);
  364. if (!dumpfile) {
  365. printf(MYNAME " rd_init() creating dumpfile %s FAILED continue anyway\n",opt_dump_file);
  366. } else {
  367. if (global_opts.debug_level > 1) {
  368. printf(MYNAME " rd_init() creating dumpfile %s for writing binnary copy of serial stream\n",opt_dump_file);
  369. }
  370. }
  371. }
  372. if (!opt_input_dump_file) {
  373. serial_init(qPrintable(fname));
  374. } else {
  375. // read from dump-file instead of serial
  376. in_file = gbfopen(fname, "r", MYNAME);
  377. is_fatal(!in_file, "Could not open dumpfile for input: %s", qPrintable(fname));
  378. }
  379. globalsat_probe_device();
  380. }
  381. static void
  382. wr_init(const QString& fname)
  383. {
  384. if (global_opts.debug_level > 1) {
  385. printf(MYNAME " wr_init()\n");
  386. }
  387. serial_init(qPrintable(fname));
  388. }
  389. static void
  390. rd_deinit(void)
  391. {
  392. if (global_opts.debug_level > 1) {
  393. printf(MYNAME " rd_deinit()\n");
  394. }
  395. if (!opt_input_dump_file) {
  396. serial_deinit();
  397. } else {
  398. if (in_file) {
  399. gbfclose(in_file);
  400. }
  401. }
  402. if (dumpfile) {
  403. gbfclose(dumpfile);
  404. dumpfile = NULL;
  405. }
  406. if (global_opts.debug_level > 1) {
  407. printf(MYNAME " rd_deinit() Done\n");
  408. }
  409. }
  410. static void
  411. wr_deinit(void)
  412. {
  413. if (global_opts.debug_level > 1) {
  414. printf(MYNAME " wr_deinit()\n");
  415. }
  416. serial_deinit();
  417. }
  418. static void track_read(void);
  419. static void
  420. waypoint_read(void)
  421. {
  422. if (global_opts.debug_level > 1) {
  423. printf(MYNAME " waypoint_read()\n");
  424. }
  425. //CommandGetTrackFileHeaders
  426. globalsat_send_simple(CommandGetWaypoints);
  427. uint8_t* in_payload;
  428. int len;
  429. uint8_t DeviceCommand;
  430. in_payload = globalsat_read_package(&len, &DeviceCommand);
  431. if ((len > 0) && (in_payload != NULL)) {
  432. if (global_opts.debug_level > 1) {
  433. printf("Got package!!!\n");
  434. }
  435. }
  436. if (in_payload) {
  437. free(in_payload);
  438. }
  439. track_read();
  440. }
  441. static void
  442. track_read(void)
  443. {
  444. if (global_opts.debug_level > 1) {
  445. printf(MYNAME " track_read()\n");
  446. }
  447. //CommandGetTrackFileHeaders
  448. globalsat_send_simple(CommandGetTrackFileHeaders);
  449. if (global_opts.debug_level > 1) {
  450. printf("Sent...\n");
  451. }
  452. uint8_t* payload;
  453. int length;
  454. uint8_t DeviceCommand;
  455. payload = globalsat_read_package(&length, &DeviceCommand);
  456. if ((length > 0) && (payload != NULL)) {
  457. if (global_opts.debug_level > 1) {
  458. printf("Got package!!! headers\n");
  459. }
  460. int number_headers;
  461. //payload is packed with a number of trainingheaders with the size of 29bytes each
  462. number_headers = length / 29; //29=packed sizeof(gh_trainheader)
  463. if (global_opts.debug_level > 1) {
  464. printf("length=%d sizeof(gh_trainheader)=%d number_headers=%d\n", (int) length, (int) 29, (int) number_headers);
  465. }
  466. for (int i = 0; i < number_headers; i++) {
  467. int pos = i * 29; //29=packed sizeof(gh_trainheader)
  468. uint8_t* hdr = (uint8_t*) & (payload[pos]);
  469. gh_trainheader header;
  470. header.dateStart.Year = hdr[0];
  471. header.dateStart.Month = hdr[1];
  472. header.dateStart.Day = hdr[2];
  473. header.timeStart.Hour = hdr[3];
  474. header.timeStart.Minute = hdr[4];
  475. header.timeStart.Second = hdr[5];
  476. header.TotalPoint = be_read32(hdr+6);
  477. header.TotalTime = be_read32(hdr+10);
  478. header.TotalDistance = be_read32(hdr+14);
  479. header.LapCnts = be_read16(hdr+18);
  480. header.gh_ptrec.Index = be_read32(hdr+20);
  481. header.gh_laprec.LapIndex = be_read32(hdr+24);
  482. header.DataType = hdr[28];
  483. if (showlist || global_opts.debug_level > 1) {
  484. printf("Track[%02i]: %02d-%02d-%02d ", i,header.dateStart.Year,header.dateStart.Month, header.dateStart.Day);
  485. printf("%02d:%02d:%02d ", header.timeStart.Hour,header.timeStart.Minute, header.timeStart.Second);
  486. int time_s=header.TotalTime / 10;
  487. int time_h=time_s/(60*60);
  488. time_s-=time_h*(60*60);
  489. int time_m=time_s/60;
  490. time_s-=time_m*60;
  491. printf("Points:%6d Time:%02d:%02d:%02d Dist:%9dm LapCnts:%5d ", header.TotalPoint, time_h,time_m,time_s, header.TotalDistance, header.LapCnts);
  492. printf("Index/StartPt:%d ", header.gh_ptrec.Index);
  493. printf("LapIndex/EndPt:%d ", header.gh_laprec.LapIndex);
  494. printf("DataType:0x%x\n", header.DataType);
  495. }
  496. if (!showlist) {
  497. route_head* trk = route_head_alloc();
  498. QString str;
  499. str.sprintf("%02d-%02d-%02d_%02d:%02d:%02d", header.dateStart.Year, header.dateStart.Month, header.dateStart.Day, header.timeStart.Hour, header.timeStart.Minute, header.timeStart.Second);
  500. trk->rte_name = str;
  501. trk->rte_desc = QString("GH625XT GPS tracklog data");
  502. track_add_head(trk);
  503. uint8_t GetTrack[5];
  504. GetTrack[0] = CommandGetTrackFileSections;
  505. GetTrack[1] = 0x0;
  506. GetTrack[2] = 0x1;
  507. GetTrack[3] = (0xFF00 & header.gh_ptrec.Index) >> 8;
  508. GetTrack[4] = 0xFF & header.gh_ptrec.Index;
  509. globalsat_write_package(GetTrack, 5);
  510. uint8_t trackDeviceCommand;
  511. int track_length;
  512. uint8_t* track_payload = NULL;
  513. track_payload = globalsat_read_package(&track_length, &trackDeviceCommand);
  514. is_fatal(((track_length == 0) || (track_payload == NULL)) , "tracklength in 0 bytes or payload nonexistant");
  515. // printf("Got track package!!! Train data\n");
  516. uint8_t* dbtrain = (uint8_t*) track_payload;
  517. gh_db_train db_train;
  518. db_train.dateStart.Year = dbtrain[0];
  519. db_train.dateStart.Month = dbtrain[1];
  520. db_train.dateStart.Day = dbtrain[2];
  521. db_train.timeStart.Hour = dbtrain[3];
  522. db_train.timeStart.Minute = dbtrain[4];
  523. db_train.timeStart.Second = dbtrain[5];
  524. db_train.TotalPoint = be_read32(dbtrain+6);
  525. db_train.TotalTime = be_read32(dbtrain+10);
  526. db_train.TotalDistance = be_read32(dbtrain+14);
  527. db_train.LapCnts = be_read16(dbtrain+18);
  528. db_train.gh_ptrec.Index = be_read32(dbtrain+20);
  529. db_train.gh_laprec.LapIndex = be_read32(dbtrain+24);
  530. db_train.MultiSport = dbtrain[28];
  531. db_train.Calory = be_readu16(dbtrain+29);
  532. db_train.MaxSpeed = be_read32(dbtrain+31);
  533. db_train.MaxHeart = dbtrain[35];
  534. db_train.AvgHeart = dbtrain[36];
  535. db_train.Ascent = be_readu16(dbtrain+37);
  536. db_train.Descent = be_readu16(dbtrain+39);
  537. db_train.MinAlti = be_read16(dbtrain+41);
  538. db_train.MaxAlti = be_read16(dbtrain+43);
  539. db_train.AvgCadns = be_readu16(dbtrain+45);
  540. db_train.BestCadns = be_readu16(dbtrain+47);
  541. db_train.AvgPower = be_readu16(dbtrain+49);
  542. db_train.MaxPower = be_readu16(dbtrain+51);
  543. db_train.Sport1 = dbtrain[53];
  544. db_train.Sport2 = dbtrain[54];
  545. db_train.Sport3 = dbtrain[55];
  546. db_train.Sport4 = dbtrain[56];
  547. db_train.Sport5 = dbtrain[57];
  548. if (global_opts.debug_level > 1) {
  549. printf("\nTrainData:%02d-%02d-%02d ", db_train.dateStart.Year,db_train.dateStart.Month, db_train.dateStart.Day);
  550. printf("%02d:%02d:%02d ", db_train.timeStart.Hour, db_train.timeStart.Minute, db_train.timeStart.Second);
  551. printf("Total(points:%6d time:%6ds dist:%9dm) LapCnts:%5d ", db_train.TotalPoint,db_train.TotalTime / 10,db_train.TotalDistance, db_train.LapCnts);
  552. printf("Index/StartPt:%d ", db_train.gh_ptrec.Index);
  553. printf("LapIndex/EndPt:%d ", db_train.gh_laprec.LapIndex);
  554. printf("MultiSport:0x%x ", db_train.MultiSport);
  555. }
  556. int total_laps = db_train.LapCnts;
  557. int total_laps_left = total_laps;
  558. free(track_payload);
  559. track_payload = NULL;
  560. gpsbabel::DateTime gpsDateTime;
  561. // Get laps
  562. while (total_laps_left > 0) {
  563. globalsat_send_simple(CommandGetNextTrackSection);
  564. track_payload = globalsat_read_package(&track_length, &trackDeviceCommand);
  565. is_fatal(((track_length == 0) || (track_payload == NULL)), "tracklength in 0 bytes or payload nonexistant");
  566. // printf("Got track package!!! Laps data\n");
  567. uint8_t* hdr = (uint8_t*) track_payload;
  568. gh_trainheader header;
  569. header.dateStart.Year = hdr[0];
  570. header.dateStart.Month = hdr[1];
  571. header.dateStart.Day = hdr[2];
  572. header.timeStart.Hour = hdr[3];
  573. header.timeStart.Minute = hdr[4];
  574. header.timeStart.Second = hdr[5];
  575. header.TotalPoint = be_read32(hdr+6);
  576. header.TotalTime = be_read32(hdr+10);
  577. header.TotalDistance = be_read32(hdr+14);
  578. header.LapCnts = be_read16(hdr+18);
  579. header.gh_ptrec.Index = be_read32(hdr+20);
  580. header.gh_laprec.LapIndex = be_read32(hdr+24);
  581. header.DataType = hdr[28];
  582. if (global_opts.debug_level > 1) {
  583. printf("Lap Trainheader: %02d-%02d-%02d ", header.dateStart.Year, header.dateStart.Month, header.dateStart.Day);
  584. printf("%02d:%02d:%02d ", header.timeStart.Hour, header.timeStart.Minute, header.timeStart.Second);
  585. printf("Total(points:%6d time:%6ds dist:%9dm) LapCnts:%5d ", header.TotalPoint,header.TotalTime / 10, header.TotalDistance, header.LapCnts);
  586. printf("Index/StartPt:%d ", header.gh_ptrec.Index);
  587. printf("LapIndex/EndPt:%d ", header.gh_laprec.LapIndex);
  588. printf("DataType:0x%x\n", header.DataType);
  589. }
  590. /*
  591. * GPS year: 2000+; struct tm year: 1900+
  592. * GPS month: 1-12, struct tm month: 0-11
  593. */
  594. QDate gpsDate = QDate(header.dateStart.Year+2000,header.dateStart.Month,header.dateStart.Day);
  595. QTime gpsTime = QTime(header.timeStart.Hour-2,header.timeStart.Minute,header.timeStart.Second);
  596. gpsDateTime = gpsbabel::DateTime(gpsDate,gpsTime);
  597. gpsDateTime.setTimeSpec(Qt::UTC);
  598. int laps_in_package = header.gh_laprec.LapIndex - header.gh_ptrec.Index + 1;
  599. // printf("Lap Data:\n");
  600. uint8_t* lap_start_pos = track_payload + 29; //29=packed sizeof(gh_trainheader)
  601. int lap;
  602. for (lap = 0; lap < laps_in_package; lap++) {
  603. uint8_t* dblap = (uint8_t*)(lap_start_pos) + lap * 41; // packed sizeof(gh_db_lap)=41
  604. gh_db_lap db_lap;
  605. db_lap.AccruedTime = be_read32(dblap+0);
  606. db_lap.TotalTime = be_read32(dblap+4);
  607. db_lap.TotalDistance = be_read32(dblap+8);
  608. db_lap.Calory = be_readu16(dblap+12);
  609. db_lap.MaxSpeed = be_read32(dblap+14);
  610. db_lap.MaxHeart = dblap[18];
  611. db_lap.AvgHeart = dblap[19];
  612. db_lap.MinAlti = be_read16(dblap+20);
  613. db_lap.MaxAlti = be_read16(dblap+22);
  614. db_lap.AvgCadns = be_readu16(dblap+24);
  615. db_lap.BestCadns = be_readu16(dblap+26);
  616. db_lap.AvgPower = be_readu16(dblap+28);
  617. db_lap.MaxPower = be_readu16(dblap+30);
  618. db_lap.MultiSportIndex = dblap[32];
  619. db_lap.StartPt = be_read32(dblap+33);
  620. db_lap.EndPt = be_read32(dblap+37);
  621. if (global_opts.debug_level > 1) {
  622. printf(" lap[%d] AccruedTime:%ds TotalTime:%ds TotalDist:%dm", lap, db_lap.AccruedTime, db_lap.TotalTime / 10, db_lap.TotalDistance);
  623. printf(" Calory:%d MaxSpeed:%d Hearth max:%d avg:%d ", db_lap.Calory, db_lap.MaxSpeed, db_lap.MaxHeart, db_lap.AvgHeart);
  624. printf(" Alt min:%d max:%d", db_lap.MinAlti, db_lap.MaxAlti);
  625. printf(" Cadns avg:%d best:%d", db_lap.AvgCadns, db_lap.BestCadns);
  626. printf(" Power avg:%d Max:%d", db_lap.AvgPower, db_lap.MaxPower);
  627. printf(" MultisportIndex:%d", db_lap.MultiSportIndex);
  628. printf(" StartPt:%d EndPt:%d\n", db_lap.StartPt, db_lap.EndPt);
  629. }
  630. }
  631. free(track_payload);
  632. track_payload = NULL;
  633. total_laps_left -= laps_in_package;
  634. }
  635. globalsat_send_simple(CommandGetNextTrackSection);
  636. do {
  637. if (track_payload) {
  638. // rest of the time in the loop
  639. free(track_payload);
  640. globalsat_send_simple(CommandGetNextTrackSection);
  641. }
  642. track_payload = globalsat_read_package(&track_length, &trackDeviceCommand);
  643. if ((track_length > 0) && (track_payload != NULL)) {
  644. // printf("Got track package!!! Train data\n");
  645. uint8_t* hdr = (uint8_t*) track_payload;
  646. gh_trainheader header;
  647. header.dateStart.Year = hdr[0];
  648. header.dateStart.Month = hdr[1];
  649. header.dateStart.Day = hdr[2];
  650. header.timeStart.Hour = hdr[3];
  651. header.timeStart.Minute = hdr[4];
  652. header.timeStart.Second = hdr[5];
  653. header.TotalPoint = be_read32(hdr+6);
  654. header.TotalTime = be_read32(hdr+10);
  655. header.TotalDistance = be_read32(hdr+14);
  656. header.LapCnts = be_read16(hdr+18);
  657. header.gh_ptrec.StartPt = be_read32(hdr+20);
  658. header.gh_laprec.EndPt = be_read32(hdr+24);
  659. header.DataType = hdr[28];
  660. if (global_opts.debug_level > 1) {
  661. printf("Lap Trainheader: %02d-%02d-%02d ", header.dateStart.Year, header.dateStart.Month, header.dateStart.Day);
  662. printf("%02d:%02d:%02d ", header.timeStart.Hour, header.timeStart.Minute, header.timeStart.Second);
  663. printf("Total(points:%6d time:%6ds dist:%9dm) LapCnts:%5d ", header.TotalPoint, header.TotalTime / 10, header.TotalDistance, header.LapCnts);
  664. printf("StartPt:%d ", header.gh_ptrec.StartPt);
  665. printf("EndPt:%d ", header.gh_laprec.EndPt);
  666. printf("DataType:0x%x\n", header.DataType);
  667. }
  668. int recpoints_in_package = header.gh_laprec.EndPt - header.gh_ptrec.StartPt + 1;
  669. // printf("Recpoints Data:\n");
  670. uint8_t* recpoints_start_pos = track_payload + 29; //29=packed sizeof(gh_trainheader)
  671. int recpoint;
  672. for (recpoint = 0; recpoint < recpoints_in_package; recpoint++) {
  673. uint8_t* ghpoint = (uint8_t*)(recpoints_start_pos + recpoint * 25); // packed sizeof(gh_recpoint)=25
  674. gh_recpoint point;
  675. point.Latitude = be_read32(ghpoint);
  676. point.Longitude = be_read32(ghpoint+4);
  677. point.Altitude = be_read16(ghpoint+8);
  678. point.Speed = be_read32(ghpoint+10);
  679. point.HeartRate = ghpoint[14];
  680. point.IntervalTime = be_read32(ghpoint+15);
  681. point.Cadence = be_readu16(ghpoint+19);
  682. point.PwrCadence = be_readu16(ghpoint+21);
  683. point.Power = be_readu16(ghpoint+23);
  684. //Time from last point in sec's * 10 (e.g. point.lntervalTime is sec multiplied witn 10)
  685. // convert to milisecs
  686. gpsbabel::DateTime gpsbabeltime = gpsDateTime.addMSecs(point.IntervalTime*100);
  687. gpsbabeltime.setTimeSpec(Qt::UTC);
  688. gpsDateTime.setDate(gpsbabeltime.date());
  689. gpsDateTime.setTime(gpsbabeltime.time());
  690. // if (global_opts.debug_level > 1) {
  691. // qDebug() << "DateTime2:" << gpsDateTime.toString();
  692. // }
  693. if (global_opts.debug_level > 1) {
  694. printf(" recpoint[%2d] Lat:%f Long:%f Alt:%dm", recpoint,(double)((int32_t) point.Latitude) / 1000000.0,(double)((int32_t) point.Longitude) / 1000000.0, point.Altitude);
  695. printf(" Speed:%f HR:%d",(double) point.Speed / 100, point.HeartRate);
  696. printf(" Time:%d Cadence:%d", point.IntervalTime, point.Cadence);
  697. printf(" PwrCadense:%d Power:%d\n", point.PwrCadence,point.Power);
  698. }
  699. Waypoint* wpt = new Waypoint(); // waypt_new();
  700. //wpt->creation_time = mkgmtime(&gpstime);
  701. wpt->SetCreationTime(gpsbabeltime);
  702. wpt->longitude = ((int32_t) point.Longitude) / 1000000.0;
  703. wpt->latitude = ((int32_t) point.Latitude) / 1000000.0;
  704. wpt->altitude = point.Altitude;
  705. wpt->speed = ((double) point.Speed / 100.0) * 1000.0 / 3600.0;
  706. wpt->heartrate = point.HeartRate;
  707. wpt->cadence = point.Cadence; //TODO convert in any way??
  708. wpt->power = point.Power; //TODO convert in any way??
  709. track_add_wpt(trk, wpt);
  710. }
  711. }
  712. } while (trackDeviceCommand == CommandGetTrackFileSections);
  713. if (track_payload) {
  714. free(track_payload);
  715. }
  716. }
  717. }
  718. }
  719. if (payload) {
  720. free(payload);
  721. }
  722. }
  723. static void
  724. route_read(void)
  725. {
  726. if (global_opts.debug_level > 1) {
  727. printf(MYNAME " route_read() TODO\n");
  728. }
  729. }
  730. static void
  731. data_read(void)
  732. {
  733. if (global_opts.debug_level > 1) {
  734. printf(MYNAME " data_read()\n");
  735. }
  736. if (global_opts.masked_objective & WPTDATAMASK) {
  737. waypoint_read();
  738. }
  739. if (global_opts.masked_objective & TRKDATAMASK) {
  740. track_read();
  741. }
  742. if (global_opts.masked_objective & RTEDATAMASK) {
  743. route_read();
  744. }
  745. if (!(global_opts.masked_objective &
  746. (WPTDATAMASK | TRKDATAMASK | RTEDATAMASK | POSNDATAMASK))) {
  747. fatal(MYNAME ": Nothing to do.\n");
  748. }
  749. }
  750. // This used the serial comunication to the watch
  751. ff_vecs_t globalsat_sport_vecs = {
  752. ff_type_serial, //type
  753. FF_CAP_RW_ALL, //cap[3]
  754. rd_init, //rd_init
  755. wr_init, //wr_init
  756. rd_deinit, //rd_deinit
  757. wr_deinit, //wr_deinit
  758. data_read, //read
  759. NULL, //write
  760. NULL, //exit
  761. globalsat_args, //args
  762. CET_CHARSET_ASCII, 0 //encode,fixed_encode
  763. //NULL //name dynamic/internal?
  764. };
  765. // This reads from a RAW dump bile from a watch
  766. // Usefull for testing generata a dumpfile with
  767. // gpsbabel -i globalsat,dump-file=<dumpfilename> -f /dev/ttyUSB0 -o gpx,garminextensions -F <1:st gpx file name>
  768. // gpsbabel -i globalsat-bin -f <dumpfilename> -o gpx,garminextensions -F <2:nd gpx file name>
  769. ff_vecs_t globalsat_sport_fvecs = {
  770. ff_type_serial, //type
  771. FF_CAP_RW_ALL, //cap[3]
  772. rd_init, //rd_init
  773. wr_init, //wr_init
  774. rd_deinit, //rd_deinit
  775. wr_deinit, //wr_deinit
  776. data_read, //read
  777. NULL, //write
  778. NULL, //exit
  779. globalsat_args, //args
  780. CET_CHARSET_ASCII, 0 //encode,fixed_encode
  781. //NULL //name dynamic/internal?
  782. };