@@ -393,7 +393,7 @@ class phpFITFileAnalysis
393
393
1497 => 'Edge 800 ' , // 'edge800_korea',
394
394
1499 => 'swim ' ,
395
395
1537 => 'Forerunner 910XT ' , // 'fr910xt_china',
396
- 1551 => 'fenix ' ,
396
+ 1551 => 'Fenix ' , // fenix
397
397
1555 => 'edge200_taiwan ' ,
398
398
1561 => 'Edge 510 ' , // 'edge510',
399
399
1567 => 'Edge 810 ' , // 'edge810',
@@ -421,12 +421,70 @@ class phpFITFileAnalysis
421
421
1929 => 'Forerunner 620 ' , // 'fr620_china',
422
422
1930 => 'Forerunner 220 ' , // 'fr220_japan',
423
423
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
426
483
10014 => 'edge_remote ' ,
427
484
20119 => 'training_center ' ,
485
+ 65531 => 'connectiq_simulator ' ,
428
486
65532 => 'android_antplus_plugin ' ,
429
- 65534 => 'connect '
487
+ 65534 => 'Garmin Connect website ' // connect
430
488
],
431
489
'sport ' => [ // Have capitalised and replaced underscores with spaces.
432
490
0 => 'Generic ' ,
@@ -496,7 +554,7 @@ class phpFITFileAnalysis
496
554
];
497
555
498
556
/**
499
- * D00001275 Flexible & Interoperable Data Transfer (FIT) Protocol Rev 1.7 .pdf
557
+ * D00001275 Flexible & Interoperable Data Transfer (FIT) Protocol Rev 2.2 .pdf
500
558
* Table 4-6. FIT Base Types and Invalid Values
501
559
*
502
560
* $types array holds a string used by the PHP unpack() function to format binary data.
@@ -518,6 +576,9 @@ class phpFITFileAnalysis
518
576
139 => 'vtmp ' , // uint16z
519
577
140 => 'Vtmp ' , // uint32z
520
578
13 => 'Ctmp ' , // byte
579
+ 142 => 'Ptmp ' , // sint64 - manually convert uint64 to sint64 in fixData()
580
+ 143 => 'Ptmp ' , // uint64
581
+ 144 => 'Ptmp ' // uint64z
521
582
],
522
583
1 => [ // Big Endianness
523
584
0 => 'Ctmp ' , // enum
@@ -534,6 +595,9 @@ class phpFITFileAnalysis
534
595
139 => 'ntmp ' , // uint16z
535
596
140 => 'Ntmp ' , // uint32z
536
597
13 => 'Ctmp ' , // byte
598
+ 142 => 'Jtmp ' , // sint64 - manually convert uint64 to sint64 in fixData()
599
+ 143 => 'Jtmp ' , // uint64
600
+ 144 => 'Jtmp ' // uint64z
537
601
]
538
602
];
539
603
@@ -552,6 +616,9 @@ class phpFITFileAnalysis
552
616
139 => 0 , // 0x0000
553
617
140 => 0 , // 0x00000000
554
618
13 => 255 , // 0xFF
619
+ 142 => 9223372036854775807 , // 0x7FFFFFFFFFFFFFFF
620
+ 143 => 18446744073709551615 , // 0xFFFFFFFFFFFFFFFF
621
+ 144 => 0 // 0x0000000000000000
555
622
];
556
623
557
624
/**
@@ -931,6 +998,35 @@ class phpFITFileAnalysis
931
998
253 => ['field_name ' => 'timestamp ' , 'scale ' => 1 , 'offset ' => 0 , 'units ' => 's ' ],
932
999
254 => ['field_name ' => 'message_index ' , 'scale ' => 1 , 'offset ' => 0 , 'units ' => '' ]
933
1000
]
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
+ ]
934
1030
]
935
1031
];
936
1032
@@ -1009,20 +1105,22 @@ private function readDataRecords()
1009
1105
{
1010
1106
$ record_header_byte = 0 ;
1011
1107
$ message_type = 0 ;
1108
+ $ developer_data_flag = 0 ;
1012
1109
$ local_mesg_type = 0 ;
1013
1110
1014
1111
while ($ this ->file_header ['header_size ' ] + $ this ->file_header ['data_size ' ] > $ this ->file_pointer ) {
1015
1112
$ record_header_byte = ord (substr ($ this ->file_contents , $ this ->file_pointer , 1 ));
1016
1113
$ this ->file_pointer ++;
1017
1114
1018
1115
/**
1019
- * D00001275 Flexible & Interoperable Data Transfer (FIT) Protocol Rev 1.7 .pdf
1116
+ * D00001275 Flexible & Interoperable Data Transfer (FIT) Protocol Rev 2.2 .pdf
1020
1117
* Table 4-1. Normal Header Bit Field Description
1021
1118
*/
1022
1119
if (($ record_header_byte >> 7 ) & 1 ) { // Check that it's a normal header
1023
1120
throw new \Exception ('phpFITFileAnalysis->readDataRecords(): this class can only handle normal headers! ' );
1024
1121
}
1025
1122
$ 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
1026
1124
$ local_mesg_type = $ record_header_byte & 15 ; // bindec('1111') == 15
1027
1125
1028
1126
switch ($ message_type ) {
@@ -1058,16 +1156,39 @@ private function readDataRecords()
1058
1156
$ total_size += $ size ;
1059
1157
}
1060
1158
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
+
1061
1178
$ this ->defn_mesgs [$ local_mesg_type ] = [
1062
1179
'global_mesg_num ' => $ global_mesg_num ,
1063
1180
'num_fields ' => $ num_fields ,
1064
1181
'field_defns ' => $ field_definitions ,
1182
+ 'num_dev_fields ' => $ num_dev_fields ,
1183
+ 'dev_field_definitions ' => $ dev_field_definitions ,
1065
1184
'total_size ' => $ total_size
1066
1185
];
1067
1186
$ this ->defn_mesgs_all [] = [
1068
1187
'global_mesg_num ' => $ global_mesg_num ,
1069
1188
'num_fields ' => $ num_fields ,
1070
1189
'field_defns ' => $ field_definitions ,
1190
+ 'num_dev_fields ' => $ num_dev_fields ,
1191
+ 'dev_field_definitions ' => $ dev_field_definitions ,
1071
1192
'total_size ' => $ total_size
1072
1193
];
1073
1194
break ;
@@ -1104,6 +1225,11 @@ private function readDataRecords()
1104
1225
$ this ->file_pointer += $ field_defn ['size ' ];
1105
1226
}
1106
1227
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
+
1107
1233
// Process the temporary array and load values into the public data messages array
1108
1234
if (!empty ($ tmp_record_array )) {
1109
1235
$ timestamp = isset ($ this ->data_mesgs ['record ' ]['timestamp ' ]) ? max ($ this ->data_mesgs ['record ' ]['timestamp ' ]) + 1 : 0 ;
@@ -1178,6 +1304,7 @@ private function fixData($options)
1178
1304
// http://php.net/manual/en/function.pack.php - signed integers endianness is always machine dependent.
1179
1305
// 131 s signed short (always 16 bit, machine byte order)
1180
1306
// 133 l signed long (always 32 bit, machine byte order)
1307
+ // 142 q signed long long (always 64 bit, machine byte order)
1181
1308
foreach ($ this ->defn_mesgs_all as $ mesg ) {
1182
1309
if (isset ($ this ->data_mesg_info [$ mesg ['global_mesg_num ' ]])) {
1183
1310
$ mesg_name = $ this ->data_mesg_info [$ mesg ['global_mesg_num ' ]]['mesg_name ' ];
@@ -1223,6 +1350,26 @@ private function fixData($options)
1223
1350
$ this ->data_mesgs [$ mesg_name ][$ field_name ] = -1 * ($ this ->data_mesgs [$ mesg_name ][$ field_name ] - 0x7FFFFFFF );
1224
1351
}
1225
1352
}
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
+ }
1226
1373
}
1227
1374
}
1228
1375
}
0 commit comments