Skip to content
This repository was archived by the owner on May 8, 2025. It is now read-only.

Commit 294cfee

Browse files
committed
Developer Data support added
1 parent c14d0ae commit 294cfee

File tree

1 file changed

+50
-15
lines changed

1 file changed

+50
-15
lines changed

src/phpFITFileAnalysis.php

Lines changed: 50 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,8 @@
3838
class 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

Comments
 (0)