@@ -393,7 +393,7 @@ class phpFITFileAnalysis
393393 1497 => 'Edge 800 ' , // 'edge800_korea',
394394 1499 => 'swim ' ,
395395 1537 => 'Forerunner 910XT ' , // 'fr910xt_china',
396- 1551 => 'fenix ' ,
396+ 1551 => 'Fenix ' , // fenix
397397 1555 => 'edge200_taiwan ' ,
398398 1561 => 'Edge 510 ' , // 'edge510',
399399 1567 => 'Edge 810 ' , // 'edge810',
@@ -421,12 +421,70 @@ class phpFITFileAnalysis
421421 1929 => 'Forerunner 620 ' , // 'fr620_china',
422422 1930 => 'Forerunner 220 ' , // 'fr220_japan',
423423 1931 => 'Forerunner 220 ' , // 'fr220_china',
424- 1967 => 'fenix2 ' ,
425- 10007 => 'sdm4 ' ,
424+ 1967 => 'Fenix 2 ' , // fenix2
425+ 1988 => 'epix ' ,
426+ 2050 => 'Fenix 3 ' , // fenix3
427+ 2052 => 'Edge 1000 ' , // edge1000_taiwan
428+ 2053 => 'Edge 1000 ' , // edge1000_japan
429+ 2061 => 'Forerunner 15 ' , // fr15_japan
430+ 2067 => 'Edge 520 ' , // edge520
431+ 2070 => 'Edge 1000 ' , // edge1000_china
432+ 2072 => 'Forerunner 620 ' , // fr620_russia
433+ 2073 => 'Forerunner 220 ' , // fr220_russia
434+ 2079 => 'vector_s ' ,
435+ 2100 => 'Edge 1000 ' , // edge1000_korea
436+ 2130 => 'Forerunner 920 ' , // fr920xt_taiwan
437+ 2131 => 'Forerunner 920 ' , // fr920xt_china
438+ 2132 => 'Forerunner 920 ' , // fr920xt_japan
439+ 2134 => 'virbx ' ,
440+ 2135 => 'vivo_smart_apac ' ,
441+ 2140 => 'etrex_touch ' ,
442+ 2147 => 'Edge 25 ' , // edge25
443+ 2148 => 'Forerunner 25 ' , // fr25
444+ 2150 => 'vivo_fit2 ' ,
445+ 2153 => 'Forerunner 225 ' , // fr225
446+ 2156 => 'Forerunner 630 ' , // fr630
447+ 2157 => 'Forerunner 230 ' , // fr230
448+ 2160 => 'vivo_active_apac ' ,
449+ 2161 => 'vector_2 ' ,
450+ 2162 => 'vector_2s ' ,
451+ 2172 => 'virbxe ' ,
452+ 2173 => 'Forerunner 620 ' , // fr620_taiwan
453+ 2174 => 'Forerunner 220 ' , // fr220_taiwan
454+ 2175 => 'truswing ' ,
455+ 2188 => 'Fenix 3 ' , // fenix3_china
456+ 2189 => 'Fenix 3 ' , // fenix3_twn
457+ 2192 => 'varia_headlight ' ,
458+ 2193 => 'varia_taillight_old ' ,
459+ 2204 => 'Edge Explore 1000 ' , // edge_explore_1000
460+ 2219 => 'Forerunner 225 ' , // fr225_asia
461+ 2225 => 'varia_radar_taillight ' ,
462+ 2226 => 'varia_radar_display ' ,
463+ 2238 => 'Edge 20 ' , // edge20
464+ 2262 => 'd2_bravo ' ,
465+ 2266 => 'approach_s20 ' ,
466+ 2276 => 'varia_remote ' ,
467+ 2327 => 'hrm4_run ' ,
468+ 2337 => 'vivo_active_hr ' ,
469+ 2347 => 'vivo_smart_gps_hr ' ,
470+ 2348 => 'vivo_smart_hr ' ,
471+ 2368 => 'vivo_move ' ,
472+ 2398 => 'varia_vision ' ,
473+ 2406 => 'vivo_fit3 ' ,
474+ 2413 => 'Fenix 3 HR ' , // fenix3_hr
475+ 2429 => 'index_smart_scale ' ,
476+ 2431 => 'Forerunner 235 ' , // fr235
477+ 2441 => 'oregon7xx ' ,
478+ 2444 => 'rino7xx ' ,
479+ 2496 => 'nautix ' ,
480+ 2530 => 'Edge 820 ' , // edge_820
481+ 2531 => 'Edge Explore 820 ' , // edge_explore_820
482+ 10007 => 'SDM4 footpod ' , // sdm4
426483 10014 => 'edge_remote ' ,
427484 20119 => 'training_center ' ,
485+ 65531 => 'connectiq_simulator ' ,
428486 65532 => 'android_antplus_plugin ' ,
429- 65534 => 'connect '
487+ 65534 => 'Garmin Connect website ' // connect
430488 ],
431489 'sport ' => [ // Have capitalised and replaced underscores with spaces.
432490 0 => 'Generic ' ,
@@ -496,7 +554,7 @@ class phpFITFileAnalysis
496554 ];
497555
498556 /**
499- * D00001275 Flexible & Interoperable Data Transfer (FIT) Protocol Rev 1.7 .pdf
557+ * D00001275 Flexible & Interoperable Data Transfer (FIT) Protocol Rev 2.2 .pdf
500558 * Table 4-6. FIT Base Types and Invalid Values
501559 *
502560 * $types array holds a string used by the PHP unpack() function to format binary data.
@@ -518,6 +576,9 @@ class phpFITFileAnalysis
518576 139 => 'vtmp ' , // uint16z
519577 140 => 'Vtmp ' , // uint32z
520578 13 => 'Ctmp ' , // byte
579+ 142 => 'Ptmp ' , // sint64 - manually convert uint64 to sint64 in fixData()
580+ 143 => 'Ptmp ' , // uint64
581+ 144 => 'Ptmp ' // uint64z
521582 ],
522583 1 => [ // Big Endianness
523584 0 => 'Ctmp ' , // enum
@@ -534,6 +595,9 @@ class phpFITFileAnalysis
534595 139 => 'ntmp ' , // uint16z
535596 140 => 'Ntmp ' , // uint32z
536597 13 => 'Ctmp ' , // byte
598+ 142 => 'Jtmp ' , // sint64 - manually convert uint64 to sint64 in fixData()
599+ 143 => 'Jtmp ' , // uint64
600+ 144 => 'Jtmp ' // uint64z
537601 ]
538602 ];
539603
@@ -552,6 +616,9 @@ class phpFITFileAnalysis
552616 139 => 0 , // 0x0000
553617 140 => 0 , // 0x00000000
554618 13 => 255 , // 0xFF
619+ 142 => 9223372036854775807 , // 0x7FFFFFFFFFFFFFFF
620+ 143 => 18446744073709551615 , // 0xFFFFFFFFFFFFFFFF
621+ 144 => 0 // 0x0000000000000000
555622 ];
556623
557624 /**
@@ -931,6 +998,35 @@ class phpFITFileAnalysis
931998 253 => ['field_name ' => 'timestamp ' , 'scale ' => 1 , 'offset ' => 0 , 'units ' => 's ' ],
932999 254 => ['field_name ' => 'message_index ' , 'scale ' => 1 , 'offset ' => 0 , 'units ' => '' ]
9331000 ]
1001+ ],
1002+
1003+ 206 => [
1004+ 'mesg_name ' => 'field_description ' , 'field_defns ' => [
1005+ 0 => ['field_name ' => 'developer_data_index ' , 'scale ' => 1 , 'offset ' => 0 , 'units ' => '' ],
1006+ 1 => ['field_name ' => 'field_definition_number ' , 'scale ' => 1 , 'offset ' => 0 , 'units ' => '' ],
1007+ 2 => ['field_name ' => 'fit_base_type_id ' , 'scale ' => 1 , 'offset ' => 0 , 'units ' => '' ],
1008+ 3 => ['field_name ' => 'field_name ' , 'scale ' => 1 , 'offset ' => 0 , 'units ' => '' ],
1009+ 4 => ['field_name ' => 'array ' , 'scale ' => 1 , 'offset ' => 0 , 'units ' => '' ],
1010+ 5 => ['field_name ' => 'components ' , 'scale ' => 1 , 'offset ' => 0 , 'units ' => '' ],
1011+ 6 => ['field_name ' => 'scale ' , 'scale ' => 1 , 'offset ' => 0 , 'units ' => '' ],
1012+ 7 => ['field_name ' => 'offset ' , 'scale ' => 1 , 'offset ' => 0 , 'units ' => '' ],
1013+ 8 => ['field_name ' => 'units ' , 'scale ' => 1 , 'offset ' => 0 , 'units ' => '' ],
1014+ 9 => ['field_name ' => 'bits ' , 'scale ' => 1 , 'offset ' => 0 , 'units ' => '' ],
1015+ 10 => ['field_name ' => 'accumulate ' , 'scale ' => 1 , 'offset ' => 0 , 'units ' => '' ],
1016+ 13 => ['field_name ' => 'fit_base_unit_id ' , 'scale ' => 1 , 'offset ' => 0 , 'units ' => '' ],
1017+ 14 => ['field_name ' => 'native_mesg_num ' , 'scale ' => 1 , 'offset ' => 0 , 'units ' => '' ],
1018+ 15 => ['field_name ' => 'native_field_num ' , 'scale ' => 1 , 'offset ' => 0 , 'units ' => '' ]
1019+ ]
1020+ ],
1021+
1022+ 207 => [
1023+ 'mesg_name ' => 'developer_data_id ' , 'field_defns ' => [
1024+ 0 => ['field_name ' => 'developer_id ' , 'scale ' => 1 , 'offset ' => 0 , 'units ' => '' ],
1025+ 1 => ['field_name ' => 'application_id ' , 'scale ' => 1 , 'offset ' => 0 , 'units ' => '' ],
1026+ 2 => ['field_name ' => 'manufacturer_id ' , 'scale ' => 1 , 'offset ' => 0 , 'units ' => '' ],
1027+ 3 => ['field_name ' => 'developer_data_index ' , 'scale ' => 1 , 'offset ' => 0 , 'units ' => '' ],
1028+ 4 => ['field_name ' => 'application_version ' , 'scale ' => 1 , 'offset ' => 0 , 'units ' => '' ]
1029+ ]
9341030 ]
9351031 ];
9361032
@@ -1009,20 +1105,22 @@ private function readDataRecords()
10091105 {
10101106 $ record_header_byte = 0 ;
10111107 $ message_type = 0 ;
1108+ $ developer_data_flag = 0 ;
10121109 $ local_mesg_type = 0 ;
10131110
10141111 while ($ this ->file_header ['header_size ' ] + $ this ->file_header ['data_size ' ] > $ this ->file_pointer ) {
10151112 $ record_header_byte = ord (substr ($ this ->file_contents , $ this ->file_pointer , 1 ));
10161113 $ this ->file_pointer ++;
10171114
10181115 /**
1019- * D00001275 Flexible & Interoperable Data Transfer (FIT) Protocol Rev 1.7 .pdf
1116+ * D00001275 Flexible & Interoperable Data Transfer (FIT) Protocol Rev 2.2 .pdf
10201117 * Table 4-1. Normal Header Bit Field Description
10211118 */
10221119 if (($ record_header_byte >> 7 ) & 1 ) { // Check that it's a normal header
10231120 throw new \Exception ('phpFITFileAnalysis->readDataRecords(): this class can only handle normal headers! ' );
10241121 }
10251122 $ message_type = ($ record_header_byte >> 6 ) & 1 ; // 1: DEFINITION_MESSAGE; 0: DATA_MESSAGE
1123+ $ developer_data_flag = ($ record_header_byte >> 5 ) & 1 ; // 1: DEFINITION_MESSAGE; 0: DATA_MESSAGE
10261124 $ local_mesg_type = $ record_header_byte & 15 ; // bindec('1111') == 15
10271125
10281126 switch ($ message_type ) {
@@ -1058,16 +1156,39 @@ private function readDataRecords()
10581156 $ total_size += $ size ;
10591157 }
10601158
1159+ $ num_dev_fields = 0 ;
1160+ $ dev_field_definitions = [];
1161+ if ($ developer_data_flag === 1 ) {
1162+ $ num_dev_fields = ord (substr ($ this ->file_contents , $ this ->file_pointer , 1 ));
1163+ $ this ->file_pointer ++;
1164+
1165+ for ($ i =0 ; $ i <$ num_dev_fields ; ++$ i ) {
1166+ $ field_definition_number = ord (substr ($ this ->file_contents , $ this ->file_pointer , 1 ));
1167+ $ this ->file_pointer ++;
1168+ $ size = ord (substr ($ this ->file_contents , $ this ->file_pointer , 1 ));
1169+ $ this ->file_pointer ++;
1170+ $ developer_data_index = ord (substr ($ this ->file_contents , $ this ->file_pointer , 1 ));
1171+ $ this ->file_pointer ++;
1172+
1173+ $ dev_field_definitions [] = ['field_definition_number ' => $ field_definition_number , 'size ' => $ size , 'developer_data_index ' => $ developer_data_index ];
1174+ $ total_size += $ size ;
1175+ }
1176+ }
1177+
10611178 $ this ->defn_mesgs [$ local_mesg_type ] = [
10621179 'global_mesg_num ' => $ global_mesg_num ,
10631180 'num_fields ' => $ num_fields ,
10641181 'field_defns ' => $ field_definitions ,
1182+ 'num_dev_fields ' => $ num_dev_fields ,
1183+ 'dev_field_definitions ' => $ dev_field_definitions ,
10651184 'total_size ' => $ total_size
10661185 ];
10671186 $ this ->defn_mesgs_all [] = [
10681187 'global_mesg_num ' => $ global_mesg_num ,
10691188 'num_fields ' => $ num_fields ,
10701189 'field_defns ' => $ field_definitions ,
1190+ 'num_dev_fields ' => $ num_dev_fields ,
1191+ 'dev_field_definitions ' => $ dev_field_definitions ,
10711192 'total_size ' => $ total_size
10721193 ];
10731194 break ;
@@ -1104,6 +1225,11 @@ private function readDataRecords()
11041225 $ this ->file_pointer += $ field_defn ['size ' ];
11051226 }
11061227
1228+ // TODO: process Developer Data correctly - just skipping over it at the moment
1229+ foreach ($ this ->defn_mesgs [$ local_mesg_type ]['dev_field_definitions ' ] as $ field_defn ) {
1230+ $ this ->file_pointer += $ field_defn ['size ' ];
1231+ }
1232+
11071233 // Process the temporary array and load values into the public data messages array
11081234 if (!empty ($ tmp_record_array )) {
11091235 $ timestamp = isset ($ this ->data_mesgs ['record ' ]['timestamp ' ]) ? max ($ this ->data_mesgs ['record ' ]['timestamp ' ]) + 1 : 0 ;
@@ -1178,6 +1304,7 @@ private function fixData($options)
11781304 // http://php.net/manual/en/function.pack.php - signed integers endianness is always machine dependent.
11791305 // 131 s signed short (always 16 bit, machine byte order)
11801306 // 133 l signed long (always 32 bit, machine byte order)
1307+ // 142 q signed long long (always 64 bit, machine byte order)
11811308 foreach ($ this ->defn_mesgs_all as $ mesg ) {
11821309 if (isset ($ this ->data_mesg_info [$ mesg ['global_mesg_num ' ]])) {
11831310 $ mesg_name = $ this ->data_mesg_info [$ mesg ['global_mesg_num ' ]]['mesg_name ' ];
@@ -1223,6 +1350,26 @@ private function fixData($options)
12231350 $ this ->data_mesgs [$ mesg_name ][$ field_name ] = -1 * ($ this ->data_mesgs [$ mesg_name ][$ field_name ] - 0x7FFFFFFF );
12241351 }
12251352 }
1353+ } // Convert uint64 to sint64
1354+ elseif ($ field ['base_type ' ] === 142 && isset ($ this ->data_mesg_info [$ mesg ['global_mesg_num ' ]]['field_defns ' ][$ field ['field_definition_number ' ]]['field_name ' ])) {
1355+ $ field_name = $ this ->data_mesg_info [$ mesg ['global_mesg_num ' ]]['field_defns ' ][$ field ['field_definition_number ' ]]['field_name ' ];
1356+ if (isset ($ this ->data_mesgs [$ mesg_name ][$ field_name ])) {
1357+ if (is_array ($ this ->data_mesgs [$ mesg_name ][$ field_name ])) {
1358+ foreach ($ this ->data_mesgs [$ mesg_name ][$ field_name ] as &$ v ) {
1359+ if (PHP_INT_SIZE === 8 && $ v > 0x7FFFFFFFFFFFFFFF ) {
1360+ $ v -= 0x10000000000000000 ;
1361+ }
1362+ if ($ v > 0x7FFFFFFFFFFFFFFF ) {
1363+ $ v = -1 * ($ v - 0x7FFFFFFFFFFFFFFF );
1364+ }
1365+ }
1366+ } elseif ($ this ->data_mesgs [$ mesg_name ][$ field_name ] > 0x7FFFFFFFFFFFFFFF ) {
1367+ if (PHP_INT_SIZE === 8 ) {
1368+ $ this ->data_mesgs [$ mesg_name ][$ field_name ] -= 0x10000000000000000 ;
1369+ }
1370+ $ this ->data_mesgs [$ mesg_name ][$ field_name ] = -1 * ($ this ->data_mesgs [$ mesg_name ][$ field_name ] - 0x7FFFFFFFFFFFFFFF );
1371+ }
1372+ }
12261373 }
12271374 }
12281375 }
0 commit comments