3838class phpFITFileAnalysis
3939{
4040 public $ data_mesgs = []; // Used to store the data read from the file in associative arrays.
41+ private $ dev_field_descriptions = [];
42+ private $ field_descriptions = [];
4143
4244 private $ options = null ; // Options provided to __construct().
4345 private $ file_contents = '' ; // FIT file is read-in to memory as a string, split into an array, and reversed. See __construct().
@@ -855,7 +857,7 @@ class phpFITFileAnalysis
855857 ]
856858 ],
857859
858- 20 => [
860+ 20 => [
859861 'mesg_name ' => 'record ' , 'field_defns ' => [
860862 0 => ['field_name ' => 'position_lat ' , 'scale ' => 1 , 'offset ' => 0 , 'units ' => 'semicircles ' ],
861863 1 => ['field_name ' => 'position_long ' , 'scale ' => 1 , 'offset ' => 0 , 'units ' => 'semicircles ' ],
@@ -1103,6 +1105,11 @@ public function __construct($file_path, $options = null)
11031105 if (isset ($ options ['garmin_timestamps ' ]) && $ options ['garmin_timestamps ' ] == true ) {
11041106 $ this ->garmin_timestamps = true ;
11051107 }
1108+ if (!isset ($ this ->options ['overwrite_with_dev_data ' ]) || $ this ->options ['overwrite_with_dev_data ' ] == true ) {
1109+ $ this ->options ['overwrite_with_dev_data ' ] = true ;
1110+ } else {
1111+ $ this ->options ['overwrite_with_dev_data ' ] = false ;
1112+ }
11061113 $ this ->php_trader_ext_loaded = extension_loaded ('trader ' );
11071114
11081115 /**
@@ -1187,8 +1194,7 @@ private function readDataRecords()
11871194 $ local_mesg_type = ($ record_header_byte >> 5 ) & 3 ; // bindec('0011') == 3
11881195 $ tsOffset = $ record_header_byte & 31 ;
11891196 $ compressedTimestamp = true ;
1190- }
1191- else {
1197+ } else {
11921198 //Normal header
11931199 $ message_type = ($ record_header_byte >> 6 ) & 1 ; // 1: DEFINITION_MESSAGE; 0: DATA_MESSAGE
11941200 $ developer_data_flag = ($ record_header_byte >> 5 ) & 1 ; // 1: DEFINITION_MESSAGE; 0: DATA_MESSAGE
@@ -1284,6 +1290,8 @@ private function readDataRecords()
12841290 // If it's a Record data message, store all the pieces in the temporary array as the timestamp may not be first...
12851291 if ($ this ->defn_mesgs [$ local_mesg_type ]['global_mesg_num ' ] === 20 ) {
12861292 $ tmp_record_array [$ this ->data_mesg_info [$ this ->defn_mesgs [$ local_mesg_type ]['global_mesg_num ' ]]['field_defns ' ][$ field_defn ['field_definition_number ' ]]['field_name ' ]] = $ tmp_value / $ this ->data_mesg_info [$ this ->defn_mesgs [$ local_mesg_type ]['global_mesg_num ' ]]['field_defns ' ][$ field_defn ['field_definition_number ' ]]['scale ' ] - $ this ->data_mesg_info [$ this ->defn_mesgs [$ local_mesg_type ]['global_mesg_num ' ]]['field_defns ' ][$ field_defn ['field_definition_number ' ]]['offset ' ];
1293+ } elseif ($ this ->defn_mesgs [$ local_mesg_type ]['global_mesg_num ' ] === 206 ) {
1294+ $ tmp_record_array [$ this ->data_mesg_info [$ this ->defn_mesgs [$ local_mesg_type ]['global_mesg_num ' ]]['field_defns ' ][$ field_defn ['field_definition_number ' ]]['field_name ' ]] = $ tmp_value ;
12871295 } else {
12881296 if ($ field_defn ['base_type ' ] === 7 ) { // Handle strings appropriately
12891297 $ this ->data_mesgs [$ this ->data_mesg_info [$ this ->defn_mesgs [$ local_mesg_type ]['global_mesg_num ' ]]['mesg_name ' ]][$ this ->data_mesg_info [$ this ->defn_mesgs [$ local_mesg_type ]['global_mesg_num ' ]]['field_defns ' ][$ field_defn ['field_definition_number ' ]]['field_name ' ]][] = filter_var ($ tmp_value , FILTER_SANITIZE_STRING );
@@ -1296,8 +1304,28 @@ private function readDataRecords()
12961304 $ this ->file_pointer += $ field_defn ['size ' ];
12971305 }
12981306
1299- // TODO: process Developer Data correctly - just skipping over it at the moment
1307+ // Handle Developer Data
1308+ if ($ this ->defn_mesgs [$ local_mesg_type ]['global_mesg_num ' ] === 206 ) {
1309+ $ developer_data_index = $ tmp_record_array ['developer_data_index ' ];
1310+ $ field_definition_number = $ tmp_record_array ['field_definition_number ' ];
1311+ unset($ tmp_record_array ['developer_data_index ' ]);
1312+ unset($ tmp_record_array ['field_definition_number ' ]);
1313+ if (isset ($ tmp_record_array ['field_name ' ])) { // Get rid of special/invalid characters after the null terminated string
1314+ $ tmp_record_array ['field_name ' ] = strtolower (implode ('' , explode ("\0" , $ tmp_record_array ['field_name ' ])));
1315+ }
1316+ if (isset ($ tmp_record_array ['units ' ])) {
1317+ $ tmp_record_array ['units ' ] = strtolower (implode ('' , explode ("\0" , $ tmp_record_array ['units ' ])));
1318+ }
1319+ $ this ->dev_field_descriptions [$ developer_data_index ][$ field_definition_number ] = $ tmp_record_array ;
1320+ unset($ tmp_record_array );
1321+ }
13001322 foreach ($ this ->defn_mesgs [$ local_mesg_type ]['dev_field_definitions ' ] as $ field_defn ) {
1323+ // Units
1324+ $ this ->data_mesgs ['developer_data ' ][$ this ->dev_field_descriptions [$ field_defn ['developer_data_index ' ]][$ field_defn ['field_definition_number ' ]]['field_name ' ]]['units ' ] = $ this ->dev_field_descriptions [$ field_defn ['developer_data_index ' ]][$ field_defn ['field_definition_number ' ]]['units ' ];
1325+
1326+ // Data
1327+ $ this ->data_mesgs ['developer_data ' ][$ this ->dev_field_descriptions [$ field_defn ['developer_data_index ' ]][$ field_defn ['field_definition_number ' ]]['field_name ' ]]['data ' ][] = unpack ($ this ->types [$ this ->dev_field_descriptions [$ field_defn ['developer_data_index ' ]][$ field_defn ['field_definition_number ' ]]['fit_base_type_id ' ]], substr ($ this ->file_contents , $ this ->file_pointer , $ field_defn ['size ' ]))['tmp ' ];
1328+
13011329 $ this ->file_pointer += $ field_defn ['size ' ];
13021330 }
13031331
@@ -1313,7 +1341,7 @@ private function readDataRecords()
13131341 if ($ tsOffset >= $ fiveLsb ) {
13141342 // No rollover
13151343 $ timestamp = $ previousTS - $ fiveLsb + $ tsOffset ;
1316- } else {
1344+ } else {
13171345 // Rollover
13181346 $ timestamp = $ previousTS - $ fiveLsb + $ tsOffset + 32 ;
13191347 }
@@ -1343,6 +1371,16 @@ private function readDataRecords()
13431371 }
13441372 }
13451373 }
1374+ // Overwrite native FIT fields (e.g. Power, HR, Cadence, etc) with developer data by default
1375+ if ($ this ->options ['overwrite_with_dev_data ' ] && !empty ($ this ->dev_field_descriptions )) {
1376+ foreach ($ this ->dev_field_descriptions as $ developer_data_index ) {
1377+ foreach ($ developer_data_index as $ field_definition_number ) {
1378+ if (isset ($ field_definition_number ['native_field_num ' ])) {
1379+ $ this ->data_mesgs ['record ' ][$ field_definition_number ['field_name ' ]] = $ this ->data_mesgs ['developer_data ' ][$ field_definition_number ['field_name ' ]]['data ' ];
1380+ }
1381+ }
1382+ }
1383+ }
13461384 }
13471385
13481386 /**
@@ -1656,6 +1694,9 @@ private function interpolateMissingData(&$missing_keys, &$array)
16561694 private function oneElementArrays ()
16571695 {
16581696 foreach ($ this ->data_mesgs as $ mesg_key => $ mesg ) {
1697+ if ($ mesg_key === 'developer_data ' ) {
1698+ continue ;
1699+ }
16591700 foreach ($ mesg as $ field_key => $ field ) {
16601701 if (count ($ field ) === 1 ) {
16611702 $ first_key = key ($ field );
@@ -1926,7 +1967,6 @@ public function hrZonesMax($hr_maximum, $percentages_array = [0.60, 0.75, 0.85,
19261967 {
19271968 if (array_walk ($ percentages_array , function (&$ value , $ key , $ hr_maximum ) {
19281969 $ value = round ($ value * $ hr_maximum );
1929-
19301970 }, $ hr_maximum )) {
19311971 return $ percentages_array ;
19321972 } else {
@@ -1941,7 +1981,6 @@ public function hrZonesReserve($hr_resting, $hr_maximum, $percentages_array = [0
19411981 {
19421982 if (array_walk ($ percentages_array , function (&$ value , $ key , $ params ) {
19431983 $ value = round ($ params [0 ] + ($ value * $ params [1 ]));
1944-
19451984 }, [$ hr_resting , $ hr_maximum - $ hr_resting ])) {
19461985 return $ percentages_array ;
19471986 } else {
@@ -1956,7 +1995,6 @@ public function powerZones($functional_threshold_power, $percentages_array = [0.
19561995 {
19571996 if (array_walk ($ percentages_array , function (&$ value , $ key , $ functional_threshold_power ) {
19581997 $ value = round ($ value * $ functional_threshold_power ) + 1 ;
1959-
19601998 }, $ functional_threshold_power )) {
19611999 return $ percentages_array ;
19622000 } else {
@@ -2016,7 +2054,6 @@ public function partitionData($record_field = '', $thresholds = null, $percentag
20162054 $ total = array_sum ($ result );
20172055 array_walk ($ result , function (&$ value , $ key , $ total ) {
20182056 $ value = round ($ value / $ total * 100 , 1 );
2019-
20202057 }, $ total );
20212058 }
20222059
@@ -2396,17 +2433,15 @@ public function gearChanges($bIgnoreTimerPaused = true)
23962433 if (isset ($ fgc [0 ]['timestamp ' ])) {
23972434 if ($ first_ts == $ fgc [0 ]['timestamp ' ]) {
23982435 $ fg = $ fgc [0 ]['front_gear ' ];
2399- }
2400- else {
2436+ } else {
24012437 $ fg = $ fgc [0 ]['front_gear_num ' ] == 1 ? $ front_gears [2 ] : $ front_gears [1 ];
24022438 }
24032439 }
24042440
24052441 if (isset ($ rgc [0 ]['timestamp ' ])) {
24062442 if ($ first_ts == $ rgc [0 ]['timestamp ' ]) {
24072443 $ rg = $ rgc [0 ]['rear_gear ' ];
2408- }
2409- else {
2444+ } else {
24102445 $ rg = $ rgc [0 ]['rear_gear_num ' ] == min ($ rear_gears ) ? $ rear_gears [$ rgc [0 ]['rear_gear_num ' ] + 1 ] : $ rear_gears [$ rgc [0 ]['rear_gear_num ' ] - 1 ];
24112446 }
24122447 }
@@ -2416,14 +2451,14 @@ public function gearChanges($bIgnoreTimerPaused = true)
24162451 $ combined = [];
24172452 $ gears_array = [];
24182453
2419- if ($ bIgnoreTimerPaused === true ) {
2454+ if ($ bIgnoreTimerPaused === true ) {
24202455 $ is_paused = $ this ->isPaused ();
24212456 }
24222457
24232458 reset ($ fgc );
24242459 reset ($ rgc );
24252460 for ($ i = $ first_ts ; $ i < $ last_ts ; ++$ i ) {
2426- if ($ bIgnoreTimerPaused === true && $ is_paused [$ i ] === true ) {
2461+ if ($ bIgnoreTimerPaused === true && $ is_paused [$ i ] === true ) {
24272462 continue ;
24282463 }
24292464
0 commit comments