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.

318 lines
11KB

  1. /*
  2. Handle energympro (GPS training watch) .cpo files
  3. Copyright (c) 2014 Zingo Andersen zingo@vectrace.com
  4. Copyright (C) 2014 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. #include "defs.h"
  18. #include <QtCore/QDebug>
  19. #include <limits.h>
  20. #define MYNAME "energympro"
  21. static gbfile* file_in;
  22. typedef struct tagDATE
  23. {
  24. uint8_t Year;
  25. uint8_t Month;
  26. uint8_t Day;
  27. } tw_date;
  28. typedef struct tagTIME
  29. {
  30. uint8_t Hour;
  31. uint8_t Minute;
  32. uint8_t Second;
  33. } tw_time;
  34. typedef struct Workout
  35. {
  36. tw_date dateStart; // start date
  37. tw_time timeStart; // start time
  38. uint16_t TotalRecPt; // Total record Point
  39. uint32_t TotalTime; // Total Time
  40. uint32_t TotalDist; // Total Distance
  41. uint16_t LapNumber; // Lap Number
  42. uint16_t Calory; // Calory
  43. uint32_t MaxSpeed; // Max Speed
  44. uint32_t AvgSpeed; // average Speed
  45. uint8_t MaxHeart; // Max Heartrate
  46. uint8_t AvgHeart; // average Heart
  47. uint16_t Ascent; // Ascent
  48. uint16_t Descent; // Descent
  49. int16_t MinAlti; // Min Altitude
  50. int16_t MaxAlti; // Max Altitude
  51. uint8_t AvgCad; // average Cadence
  52. uint8_t MaxCad; // Best Cadence
  53. uint16_t AvgPower; // average Power
  54. uint16_t MaxPower; // Max Power
  55. char VersionProduct[15];
  56. uint8_t reserved1;
  57. uint8_t VersionVerNum;
  58. uint8_t reserved2[17];
  59. } tw_workout;
  60. typedef struct Point
  61. {
  62. uint32_t Latitude;
  63. uint32_t Longitude;
  64. int16_t Altitude;
  65. uint16_t reserved1;
  66. uint32_t Speed;
  67. uint16_t IntervalDist; // Interval Distance
  68. uint16_t reserved2;
  69. uint32_t lntervalTime; // Interval time
  70. uint8_t Status; //Status (0 = ok, 1 = miss, 2 = no good, 3 = bad)
  71. uint8_t HR_Heartrate;
  72. uint8_t HR_Status;
  73. uint8_t reserved3;
  74. uint32_t Speed_Speed;
  75. uint8_t Speed_Status;
  76. uint8_t reserved4;
  77. uint8_t reserved5;
  78. uint8_t reserved6;
  79. uint8_t Cadence_Cadence;
  80. uint8_t Cadence_Status;
  81. uint16_t Power_Cadence;
  82. uint16_t Power_Power;
  83. uint8_t Power_Status;
  84. uint8_t reserved7;
  85. uint8_t Temp;
  86. uint8_t reserved8;
  87. uint8_t reserved9;
  88. uint8_t reserved10;
  89. } tw_point;
  90. typedef struct Lap
  91. {
  92. uint32_t splitTime; // split time
  93. uint32_t TotalTime; // Total Time
  94. uint16_t Number; // Number
  95. uint16_t reserved1;
  96. uint32_t lDistance; // Distance
  97. uint16_t Calorie; // Calorie
  98. uint16_t reserved2;
  99. uint32_t MaxSpeed; // Max Speed
  100. uint32_t AvgSpeed; // average Speed
  101. uint8_t MaxHeartrate; // Max Heartrate
  102. uint8_t AvgHeartrate; // average Heartrate
  103. int16_t MinAlti; // Min Altitude
  104. int16_t MaxAlti; // Max Altitude
  105. uint8_t AvgCad; // average Cadence
  106. uint8_t MaxCad; // Max Cadence
  107. uint16_t AvgPower; // average Power
  108. uint16_t MaxPower; // Max Power
  109. uint16_t StartRecPt; // start record point
  110. uint16_t FinishRecPt; // Finish record point
  111. } tw_lap;
  112. //*******************************************************************************
  113. // local helper functions
  114. //*******************************************************************************
  115. static void
  116. read_point(route_head* gpsbabel_route,gpsbabel::DateTime& gpsDateTime)
  117. {
  118. tw_point point;
  119. gbfread(&point,sizeof(tw_point),1,file_in);
  120. if (global_opts.debug_level > 1) {
  121. printf ("Point: lat:%8d long:%8d alt:%8d ",point.Latitude,point.Longitude,point.Altitude);
  122. printf ("speed:%6d dist:%5d time:%5d Status:%1d", point.Speed,point.IntervalDist,point.lntervalTime,point.Status);
  123. printf ("HR:(%3d,%1d)" , point.HR_Heartrate,point.HR_Status);
  124. printf ("Speed:(%8d,%1d)" , point.Speed_Speed,point.Speed_Status);
  125. printf ("Cad:(%3d,%1d)" , point.Cadence_Cadence, point.Cadence_Status);
  126. printf ("Power (Cad:%6d Pow:%6d,%2d)Temp:%3d\n" , point.Power_Cadence, point.Power_Power, point.Power_Status, point.Temp);
  127. qDebug() << "DateTime1:" << gpsDateTime.toString();
  128. qDebug() << "point.lntervalTime:" << point.lntervalTime;
  129. }
  130. //Time from last point in sec's * 10 (e.g. point.lntervalTime is sec multiplied witn 10)
  131. // convert to milisecs
  132. gpsbabel::DateTime gpsbabeltime = gpsDateTime.addMSecs(point.lntervalTime*100);
  133. gpsDateTime.setDate(gpsbabeltime.date());
  134. gpsDateTime.setTime(gpsbabeltime.time());
  135. //remove parts of sec (on purpose) on reported time, we keep track of parts of sec in
  136. // global structure so we don't drift
  137. qint64 mSecsSinceEpoc = gpsbabeltime.toMSecsSinceEpoch();
  138. gpsbabeltime.setMSecsSinceEpoch(mSecsSinceEpoc-mSecsSinceEpoc%1000);
  139. Waypoint* waypt;
  140. waypt = new Waypoint;
  141. waypt->latitude = (point.Latitude / (double)1000000);
  142. waypt->longitude = (point.Longitude / (double)1000000);
  143. waypt->altitude = point.Altitude;
  144. if (global_opts.debug_level > 1) {
  145. qDebug() << "DateTime2:" << gpsDateTime.toString();
  146. }
  147. waypt->SetCreationTime(gpsbabeltime);
  148. if (point.Speed_Status == 0) {
  149. WAYPT_SET(waypt, speed, point.Speed_Speed / 100.0f);
  150. }
  151. if (point.HR_Status == 0) {
  152. waypt->heartrate = point.HR_Heartrate;
  153. }
  154. if (point.Cadence_Status == 0) {
  155. waypt->cadence = point.Cadence_Cadence;
  156. }
  157. if (point.Power_Status == 0) {
  158. waypt->power = point.Power_Power;
  159. }
  160. WAYPT_SET(waypt, temperature, point.Temp);
  161. track_add_wpt(gpsbabel_route, waypt);
  162. }
  163. static void
  164. read_lap(void)
  165. {
  166. tw_lap lap;
  167. gbfread(&lap,sizeof(tw_lap),1,file_in);
  168. if (global_opts.debug_level > 1) {
  169. printf ("LAP: splitTime:%6ds TotalTime:%6ds LapNumber:%5d ",lap.splitTime/10,lap.TotalTime/10,lap.Number);
  170. printf ("dist:%08dm Cal:%5d Speed:(%6d,%6d) ", lap.lDistance,lap.Calorie,lap.MaxSpeed,lap.AvgSpeed);
  171. printf ("HR:(%3d,%3d)" , lap.MaxHeartrate,lap.AvgHeartrate);
  172. printf ("Alt:(%6d,%6d) ", lap.MinAlti,lap.MaxAlti);
  173. printf ("Cad:(%3d,%3d) ", lap.AvgCad,lap.MaxCad);
  174. printf ("Power:(%3d,%3d)w ", lap.AvgPower,lap.MaxPower);
  175. printf ("Pt:(%6d,%6d)\n", lap.StartRecPt,lap.FinishRecPt);
  176. }
  177. }
  178. //*******************************************************************************
  179. // global callbacks called by gpsbabel main process
  180. //*******************************************************************************
  181. static void
  182. rd_init(const QString& fname)
  183. {
  184. if (global_opts.debug_level > 1) {
  185. printf (MYNAME " rd_deinit()\n");
  186. }
  187. gbfile* fileorg_in = gbfopen(fname, "rb", MYNAME);
  188. /* copy file to memory stream (needed for seek-ops and piped commands) */
  189. file_in = gbfopen(NULL, "wb", MYNAME);
  190. gbsize_t size;
  191. size = gbfcopyfrom(file_in, fileorg_in, 0x7FFFFFFF);
  192. if(global_opts.debug_level > 1) {
  193. printf (MYNAME " filesize=%d\n",size);
  194. }
  195. gbfclose(fileorg_in);
  196. }
  197. static void
  198. rd_deinit(void)
  199. {
  200. if (global_opts.debug_level > 1) {
  201. printf (MYNAME " rd_deinit()\n");
  202. }
  203. gbfclose(file_in);
  204. }
  205. static void
  206. track_read(void)
  207. {
  208. if(global_opts.debug_level > 1) {
  209. printf (MYNAME " waypoint_read()\n");
  210. }
  211. gbfseek(file_in, 0L, SEEK_END);
  212. gbfseek(file_in, (int32_t) -(sizeof(tw_workout)), SEEK_CUR);
  213. tw_workout workout;
  214. workout.dateStart.Year = gbfgetc(file_in);
  215. workout.dateStart.Month = gbfgetc(file_in);
  216. workout.dateStart.Day = gbfgetc(file_in);
  217. workout.timeStart.Hour = gbfgetc(file_in);
  218. workout.timeStart.Minute = gbfgetc(file_in);
  219. workout.timeStart.Second = gbfgetc(file_in);
  220. workout.TotalRecPt = gbfgetint16(file_in);
  221. workout.TotalTime = gbfgetint32(file_in);
  222. workout.TotalDist = gbfgetint32(file_in);
  223. workout.LapNumber = gbfgetint16(file_in);
  224. workout.Calory = gbfgetint16(file_in);
  225. workout.MaxSpeed = gbfgetint32(file_in);
  226. workout.AvgSpeed = gbfgetint32(file_in);
  227. workout.MaxHeart = gbfgetc(file_in);
  228. workout.AvgHeart = gbfgetc(file_in);
  229. if (global_opts.debug_level > 1) {
  230. printf ("%04d-%02d-%02d ", workout.dateStart.Year+2000,workout.dateStart.Month, workout.dateStart.Day);
  231. printf ("%02d:%02d:%02d ", workout.timeStart.Hour,workout.timeStart.Minute, workout.timeStart.Second);
  232. printf ("Total(RecPt:%6d Time:%6ds Dist:%9dm) LapNumber:%5d \n",workout.TotalRecPt,workout.TotalTime/10, workout.TotalDist, workout.LapNumber);
  233. }
  234. /*
  235. * GPS year: 2000+; struct tm year: 1900+
  236. */
  237. QDate gpsDate = QDate(workout.dateStart.Year+2000,workout.dateStart.Month,workout.dateStart.Day);
  238. QTime gpsTime = QTime(workout.timeStart.Hour,workout.timeStart.Minute,workout.timeStart.Second);
  239. gpsbabel::DateTime gpsDateTime = gpsbabel::DateTime(gpsDate,gpsTime);
  240. gpsDateTime.setTimeSpec(Qt::UTC);
  241. route_head* gpsbabel_route = route_head_alloc();
  242. track_add_head(gpsbabel_route);
  243. gbfseek(file_in, 0L, SEEK_SET);
  244. for(int point=0;point<workout.TotalRecPt;point++) {
  245. read_point(gpsbabel_route,gpsDateTime);
  246. }
  247. gbfseek(file_in, sizeof(tw_point)*(workout.TotalRecPt), SEEK_SET);
  248. for(int lap=0;lap<workout.LapNumber;lap++) {
  249. read_lap();
  250. }
  251. }
  252. static void
  253. data_read(void)
  254. {
  255. if (global_opts.debug_level > 1) {
  256. printf (MYNAME " data_read()\n");
  257. }
  258. track_read();
  259. }
  260. ff_vecs_t energympro_vecs = {
  261. ff_type_file,
  262. {
  263. ff_cap_none, // waypoints
  264. ff_cap_read, // tracks
  265. ff_cap_none // routes
  266. },
  267. rd_init, // rd_init
  268. NULL, // wr_init
  269. rd_deinit, // rd_deinit
  270. NULL, // wr_deinit
  271. data_read, // read
  272. NULL, // write
  273. NULL, // exit
  274. NULL, //args
  275. CET_CHARSET_ASCII, 0 //encode,fixed_encode
  276. //NULL //name dynamic/internal?
  277. };