fit-file-parser 5.2.0 → 6.0.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +18 -187
- package/PROFILE.md +43 -0
- package/README.md +75 -81
- package/dist/binary.d.ts +2 -0
- package/dist/binary.js +28 -58
- package/dist/cjs/binary.d.ts +2 -0
- package/dist/cjs/binary.js +28 -58
- package/dist/cjs/fit-parser.d.ts +2 -0
- package/dist/cjs/fit-parser.js +25 -3
- package/dist/cjs/fit.d.ts +0 -6
- package/dist/cjs/fit.js +4 -114
- package/dist/cjs/fit_types.d.ts +1 -0
- package/dist/cjs/profile.d.ts +9 -0
- package/dist/{garmin_profile.generated.js → cjs/profile.js} +285 -8
- package/dist/cjs/type_generator.js +1 -0
- package/dist/fit-parser.d.ts +2 -0
- package/dist/fit-parser.js +25 -3
- package/dist/fit.d.ts +0 -6
- package/dist/fit.js +3 -113
- package/dist/fit_types.d.ts +1 -0
- package/dist/profile.d.ts +9 -0
- package/dist/{cjs/garmin_profile.generated.js → profile.js} +282 -11
- package/dist/type_generator.js +1 -0
- package/package.json +10 -9
- package/dist/cjs/garmin_profile.generated.d.ts +0 -9
- package/dist/garmin_profile.generated.d.ts +0 -9
package/dist/cjs/binary.js
CHANGED
|
@@ -14,36 +14,14 @@ const GarminTimeOffset = 631065600000;
|
|
|
14
14
|
const InvalidFieldData = Symbol('invalid FIT field data');
|
|
15
15
|
const formatTypeMetadata = new Map();
|
|
16
16
|
const uint8CompatibleTypes = new Set(['enum', 'uint8', 'byte']);
|
|
17
|
-
const fitBaseTypeWidths = new Map([
|
|
18
|
-
[0, 1],
|
|
19
|
-
[1, 1],
|
|
20
|
-
[2, 1],
|
|
21
|
-
[3, 2],
|
|
22
|
-
[4, 2],
|
|
23
|
-
[5, 4],
|
|
24
|
-
[6, 4],
|
|
25
|
-
[7, 1],
|
|
26
|
-
[8, 4],
|
|
27
|
-
[9, 8],
|
|
28
|
-
[10, 1],
|
|
29
|
-
[11, 2],
|
|
30
|
-
[12, 4],
|
|
31
|
-
[13, 1],
|
|
32
|
-
[14, 8],
|
|
33
|
-
[15, 8],
|
|
34
|
-
[16, 8],
|
|
35
|
-
]);
|
|
36
17
|
function retainsRawMessages(options) {
|
|
37
18
|
return options.includeRawMessages === true
|
|
38
19
|
|| Array.isArray(options.includeRawMessages);
|
|
39
20
|
}
|
|
40
|
-
function
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
const typeId = baseType & 0x1F;
|
|
45
|
-
const width = fitBaseTypeWidths.get(typeId);
|
|
46
|
-
return width !== undefined && (typeId === 7 || size % width === 0);
|
|
21
|
+
function retainsRawMessage(options, globalMessageNumber) {
|
|
22
|
+
return options.includeRawMessages === true
|
|
23
|
+
|| (Array.isArray(options.includeRawMessages)
|
|
24
|
+
&& options.includeRawMessages.includes(globalMessageNumber));
|
|
47
25
|
}
|
|
48
26
|
function baseTypeSize(type) {
|
|
49
27
|
switch (type) {
|
|
@@ -486,18 +464,11 @@ function readRecord(blob, messageTypes, developerFields, startIndex, options, st
|
|
|
486
464
|
rawData: [],
|
|
487
465
|
};
|
|
488
466
|
const message = (0, messages_js_1.getFitMessage)(mTypeDef.globalMessageNumber);
|
|
489
|
-
const nativeFieldNumbers = new Set();
|
|
490
467
|
for (let i = 0; i < numberOfFields; i++) {
|
|
491
468
|
const fDefIndex = startIndex + 6 + i * 3;
|
|
492
469
|
const baseType = blob[fDefIndex + 2];
|
|
493
470
|
const fieldNumber = blob[fDefIndex];
|
|
494
471
|
const fieldSize = blob[fDefIndex + 1];
|
|
495
|
-
if (retainsRawMessages(options)
|
|
496
|
-
&& (nativeFieldNumbers.has(fieldNumber)
|
|
497
|
-
|| !isValidRawFieldDefinition(fieldSize, baseType))) {
|
|
498
|
-
throw new Error('Invalid FIT native field definition');
|
|
499
|
-
}
|
|
500
|
-
nativeFieldNumbers.add(fieldNumber);
|
|
501
472
|
const wireType = fit_js_1.FIT.types.fit_base_type[baseType];
|
|
502
473
|
const { field, type, baseType: profileBaseType, array, scale, offset, units, } = message.getAttributes(blob[fDefIndex]);
|
|
503
474
|
const profileCompatible = areProfileBaseTypesCompatible(profileBaseType, wireType);
|
|
@@ -521,15 +492,8 @@ function readRecord(blob, messageTypes, developerFields, startIndex, options, st
|
|
|
521
492
|
};
|
|
522
493
|
mTypeDef.fieldDefs.push(fDef);
|
|
523
494
|
}
|
|
524
|
-
const developerFieldNumbers = new Set();
|
|
525
495
|
for (let i = 0; i < numberOfDeveloperDataFields; i++) {
|
|
526
496
|
const fDefIndex = startIndex + 6 + numberOfFields * 3 + 1 + i * 3;
|
|
527
|
-
const developerFieldKey = `${blob[fDefIndex + 2]}:${blob[fDefIndex]}`;
|
|
528
|
-
if (retainsRawMessages(options)
|
|
529
|
-
&& (blob[fDefIndex + 1] === 0 || developerFieldNumbers.has(developerFieldKey))) {
|
|
530
|
-
throw new Error('Invalid FIT developer field definition');
|
|
531
|
-
}
|
|
532
|
-
developerFieldNumbers.add(developerFieldKey);
|
|
533
497
|
(_a = mTypeDef.developerFieldDefs) === null || _a === void 0 ? void 0 : _a.push({
|
|
534
498
|
fieldDefinitionNumber: blob[fDefIndex],
|
|
535
499
|
size: blob[fDefIndex + 1],
|
|
@@ -552,29 +516,20 @@ function readRecord(blob, messageTypes, developerFields, startIndex, options, st
|
|
|
552
516
|
if (!messageType) {
|
|
553
517
|
throw new Error('FIT data record has no local definition');
|
|
554
518
|
}
|
|
555
|
-
if (isCompressedTimestamp && retainsRawMessages(options)) {
|
|
556
|
-
const timestampField = messageType.fieldDefs[0];
|
|
557
|
-
if (!timestampField
|
|
558
|
-
|| timestampField.fDefNo !== 253
|
|
559
|
-
|| timestampField.size !== 4
|
|
560
|
-
|| (timestampField.baseTypeNo & 0x1F) !== 6) {
|
|
561
|
-
throw new Error('Invalid FIT compressed timestamp definition');
|
|
562
|
-
}
|
|
563
|
-
}
|
|
564
519
|
let messageSize = 0;
|
|
565
520
|
let readDataFromIndex = startIndex + 1;
|
|
566
521
|
const fields = {};
|
|
567
522
|
const message = (0, messages_js_1.getFitMessage)(messageType.globalMessageNumber);
|
|
568
523
|
const developerFieldDefs = (_b = messageType.developerFieldDefs) !== null && _b !== void 0 ? _b : [];
|
|
569
524
|
const totalFieldCount = messageType.fieldDefs.length + developerFieldDefs.length;
|
|
570
|
-
const includeRawMessage = options.
|
|
571
|
-
|| (Array.isArray(options.includeRawMessages)
|
|
572
|
-
&& options.includeRawMessages.includes(messageType.globalMessageNumber));
|
|
525
|
+
const includeRawMessage = retainsRawMessage(options, messageType.globalMessageNumber);
|
|
573
526
|
const includeRawDeveloperFields = options.includeRawDeveloperFields === true
|
|
574
527
|
|| (Array.isArray(options.includeRawDeveloperFields)
|
|
575
528
|
&& options.includeRawDeveloperFields.includes(messageType.globalMessageNumber));
|
|
576
529
|
const rawFields = includeRawMessage ? [] : undefined;
|
|
577
530
|
const rawDeveloperFields = includeRawDeveloperFields || includeRawMessage ? [] : undefined;
|
|
531
|
+
const unmappedFields = options.includeUnmappedMessages ? [] : undefined;
|
|
532
|
+
const unmappedDeveloperFields = options.includeUnmappedMessages ? [] : undefined;
|
|
578
533
|
if (retainsRawMessages(options)) {
|
|
579
534
|
const nativeSize = messageType.fieldDefs.reduce((total, field, index) => (total + (isCompressedTimestamp && index === 0 && field.fDefNo === 253 ? 0 : field.size)), 0);
|
|
580
535
|
const developerSize = developerFieldDefs.reduce((total, field) => total + field.size, 0);
|
|
@@ -590,12 +545,17 @@ function readRecord(blob, messageTypes, developerFields, startIndex, options, st
|
|
|
590
545
|
rawData[i] = InvalidFieldData;
|
|
591
546
|
continue;
|
|
592
547
|
}
|
|
593
|
-
if (rawFields
|
|
594
|
-
|
|
548
|
+
if ((rawFields || (unmappedFields && !isOutputFieldName(fDef.name)))
|
|
549
|
+
&& readDataFromIndex + fDef.size <= dataEnd) {
|
|
550
|
+
const rawField = {
|
|
595
551
|
fieldDefinitionNumber: fDef.fDefNo,
|
|
596
552
|
baseType: fDef.baseTypeNo,
|
|
597
553
|
rawValue: Array.from(blob.subarray(readDataFromIndex, readDataFromIndex + fDef.size)),
|
|
598
|
-
}
|
|
554
|
+
};
|
|
555
|
+
rawFields === null || rawFields === void 0 ? void 0 : rawFields.push(rawField);
|
|
556
|
+
if (!isOutputFieldName(fDef.name)) {
|
|
557
|
+
unmappedFields === null || unmappedFields === void 0 ? void 0 : unmappedFields.push(rawField);
|
|
558
|
+
}
|
|
599
559
|
}
|
|
600
560
|
const data = readData(blob, dataView, fDef, readDataFromIndex);
|
|
601
561
|
if (data !== InvalidFieldData
|
|
@@ -619,15 +579,21 @@ function readRecord(blob, messageTypes, developerFields, startIndex, options, st
|
|
|
619
579
|
for (let i = 0; i < developerFieldDefs.length; i++) {
|
|
620
580
|
const developerFieldDef = developerFieldDefs[i];
|
|
621
581
|
const rawDataIndex = messageType.fieldDefs.length + i;
|
|
622
|
-
|
|
582
|
+
let rawDeveloperField;
|
|
583
|
+
if ((rawDeveloperFields
|
|
584
|
+
|| (unmappedDeveloperFields && developerFieldDef.resolvedFieldDef === undefined))
|
|
623
585
|
&& readDataFromIndex + developerFieldDef.size <= dataEnd) {
|
|
624
|
-
|
|
586
|
+
rawDeveloperField = {
|
|
625
587
|
developerDataIndex: developerFieldDef.developerDataIndex,
|
|
626
588
|
fieldDefinitionNumber: developerFieldDef.fieldDefinitionNumber,
|
|
627
589
|
rawValue: Array.from(blob.subarray(readDataFromIndex, readDataFromIndex + developerFieldDef.size)),
|
|
628
|
-
}
|
|
590
|
+
};
|
|
591
|
+
rawDeveloperFields === null || rawDeveloperFields === void 0 ? void 0 : rawDeveloperFields.push(rawDeveloperField);
|
|
629
592
|
}
|
|
630
593
|
const fDef = resolveDeveloperFieldDefinition(developerFieldDef, messageType.littleEndian, developerFields, options);
|
|
594
|
+
if (!fDef && rawDeveloperField) {
|
|
595
|
+
unmappedDeveloperFields === null || unmappedDeveloperFields === void 0 ? void 0 : unmappedDeveloperFields.push(rawDeveloperField);
|
|
596
|
+
}
|
|
631
597
|
if (fDef) {
|
|
632
598
|
const data = readData(blob, dataView, fDef, readDataFromIndex);
|
|
633
599
|
if (data !== InvalidFieldData
|
|
@@ -745,6 +711,10 @@ function readRecord(blob, messageTypes, developerFields, startIndex, options, st
|
|
|
745
711
|
message: fields,
|
|
746
712
|
rawFields,
|
|
747
713
|
rawDeveloperFields,
|
|
714
|
+
unmappedFields: unmappedFields && unmappedFields.length > 0 ? unmappedFields : undefined,
|
|
715
|
+
unmappedDeveloperFields: unmappedDeveloperFields && unmappedDeveloperFields.length > 0
|
|
716
|
+
? unmappedDeveloperFields
|
|
717
|
+
: undefined,
|
|
748
718
|
};
|
|
749
719
|
}
|
|
750
720
|
function getArrayBuffer(buffer) {
|
package/dist/cjs/fit-parser.d.ts
CHANGED
|
@@ -15,6 +15,8 @@ export interface FitParserOptions {
|
|
|
15
15
|
includeRawDeveloperFields?: boolean | readonly number[];
|
|
16
16
|
/** Retains exact native and developer fields for all or selected global message numbers. */
|
|
17
17
|
includeRawMessages?: boolean | readonly number[];
|
|
18
|
+
/** Retains exact bytes for fields that have no semantic profile mapping. */
|
|
19
|
+
includeUnmappedMessages?: boolean;
|
|
18
20
|
/** Returns only parser metadata and retained raw messages instead of decoded activity collections. */
|
|
19
21
|
rawMessagesOnly?: boolean;
|
|
20
22
|
}
|
package/dist/cjs/fit-parser.js
CHANGED
|
@@ -8,7 +8,7 @@ Object.defineProperty(exports, "FitBaseType", { enumerable: true, get: function
|
|
|
8
8
|
Object.defineProperty(exports, "FitEncoder", { enumerable: true, get: function () { return fit_encoder_js_1.FitEncoder; } });
|
|
9
9
|
class FitParser {
|
|
10
10
|
constructor(options = {}) {
|
|
11
|
-
var _a, _b, _c;
|
|
11
|
+
var _a, _b, _c, _d;
|
|
12
12
|
this.options = {
|
|
13
13
|
force: options.force != null ? options.force : true,
|
|
14
14
|
speedUnit: options.speedUnit || 'm/s',
|
|
@@ -19,7 +19,8 @@ class FitParser {
|
|
|
19
19
|
mode: options.mode || 'list',
|
|
20
20
|
includeRawDeveloperFields: (_a = options.includeRawDeveloperFields) !== null && _a !== void 0 ? _a : false,
|
|
21
21
|
includeRawMessages: (_b = options.includeRawMessages) !== null && _b !== void 0 ? _b : false,
|
|
22
|
-
|
|
22
|
+
includeUnmappedMessages: (_c = options.includeUnmappedMessages) !== null && _c !== void 0 ? _c : false,
|
|
23
|
+
rawMessagesOnly: (_d = options.rawMessagesOnly) !== null && _d !== void 0 ? _d : false,
|
|
23
24
|
};
|
|
24
25
|
}
|
|
25
26
|
parseAsync(content) {
|
|
@@ -130,6 +131,7 @@ class FitParser {
|
|
|
130
131
|
|| Array.isArray(this.options.includeRawMessages)
|
|
131
132
|
? []
|
|
132
133
|
: undefined;
|
|
134
|
+
const unmappedMessages = this.options.includeUnmappedMessages ? [] : undefined;
|
|
133
135
|
const messageCountsByGlobalNumber = new Map();
|
|
134
136
|
let loopIndex = headerLength;
|
|
135
137
|
const messageTypes = [];
|
|
@@ -141,7 +143,7 @@ class FitParser {
|
|
|
141
143
|
let lastStopTimestamp;
|
|
142
144
|
let pausedTime = 0;
|
|
143
145
|
while (loopIndex < crcStart) {
|
|
144
|
-
const { globalMessageNumber, littleEndian, message, messageType, nextIndex, compressedTimestamp, rawFields: recordRawFields, rawDeveloperFields: recordRawDeveloperFields, } = (0, binary_js_1.readRecord)(blob, messageTypes, developerFields, loopIndex, this.options, startDate, pausedTime, dataView, decoderState, crcStart);
|
|
146
|
+
const { globalMessageNumber, littleEndian, message, messageType, nextIndex, compressedTimestamp, rawFields: recordRawFields, rawDeveloperFields: recordRawDeveloperFields, unmappedFields: recordUnmappedFields, unmappedDeveloperFields: recordUnmappedDeveloperFields, } = (0, binary_js_1.readRecord)(blob, messageTypes, developerFields, loopIndex, this.options, startDate, pausedTime, dataView, decoderState, crcStart);
|
|
145
147
|
loopIndex = nextIndex;
|
|
146
148
|
if (globalMessageNumber !== undefined) {
|
|
147
149
|
const messageIndex = (_a = messageCountsByGlobalNumber.get(globalMessageNumber)) !== null && _a !== void 0 ? _a : 0;
|
|
@@ -168,6 +170,20 @@ class FitParser {
|
|
|
168
170
|
raw_value: field.rawValue,
|
|
169
171
|
});
|
|
170
172
|
});
|
|
173
|
+
if (littleEndian !== undefined
|
|
174
|
+
&& ((recordUnmappedFields === null || recordUnmappedFields === void 0 ? void 0 : recordUnmappedFields.length) || (recordUnmappedDeveloperFields === null || recordUnmappedDeveloperFields === void 0 ? void 0 : recordUnmappedDeveloperFields.length))) {
|
|
175
|
+
unmappedMessages === null || unmappedMessages === void 0 ? void 0 : unmappedMessages.push(Object.assign(Object.assign({ global_message_number: globalMessageNumber, message_index: messageIndex, little_endian: littleEndian }, (compressedTimestamp === undefined
|
|
176
|
+
? {}
|
|
177
|
+
: { compressed_timestamp: compressedTimestamp })), { fields: (recordUnmappedFields !== null && recordUnmappedFields !== void 0 ? recordUnmappedFields : []).map(field => ({
|
|
178
|
+
field_definition_number: field.fieldDefinitionNumber,
|
|
179
|
+
base_type: field.baseType,
|
|
180
|
+
raw_value: field.rawValue,
|
|
181
|
+
})), developer_fields: (recordUnmappedDeveloperFields !== null && recordUnmappedDeveloperFields !== void 0 ? recordUnmappedDeveloperFields : []).map(field => ({
|
|
182
|
+
developer_data_index: field.developerDataIndex,
|
|
183
|
+
field_definition_number: field.fieldDefinitionNumber,
|
|
184
|
+
raw_value: field.rawValue,
|
|
185
|
+
})) }));
|
|
186
|
+
}
|
|
171
187
|
}
|
|
172
188
|
if (this.options.rawMessagesOnly) {
|
|
173
189
|
continue;
|
|
@@ -298,6 +314,9 @@ class FitParser {
|
|
|
298
314
|
if (rawMessages) {
|
|
299
315
|
fitObj.raw_messages = rawMessages;
|
|
300
316
|
}
|
|
317
|
+
if (unmappedMessages && unmappedMessages.length > 0) {
|
|
318
|
+
fitObj.unmapped_messages = unmappedMessages;
|
|
319
|
+
}
|
|
301
320
|
callback(undefined, fitObj);
|
|
302
321
|
return;
|
|
303
322
|
}
|
|
@@ -326,6 +345,9 @@ class FitParser {
|
|
|
326
345
|
if (rawMessages) {
|
|
327
346
|
fitObj.raw_messages = rawMessages;
|
|
328
347
|
}
|
|
348
|
+
if (unmappedMessages && unmappedMessages.length > 0) {
|
|
349
|
+
fitObj.unmapped_messages = unmappedMessages;
|
|
350
|
+
}
|
|
329
351
|
if (isCascadeNeeded) {
|
|
330
352
|
laps = (0, helper_js_1.mapDataIntoLap)(laps, 'records', records);
|
|
331
353
|
laps = (0, helper_js_1.mapDataIntoLap)(laps, 'lengths', lengths);
|
package/dist/cjs/fit.d.ts
CHANGED
|
@@ -37,10 +37,4 @@ export interface FitType {
|
|
|
37
37
|
messages: Record<number, Message>;
|
|
38
38
|
types: Record<string, Record<number, string | number>>;
|
|
39
39
|
}
|
|
40
|
-
/**
|
|
41
|
-
* Garmin fields observed in the external FIT corpus but absent from the pinned
|
|
42
|
-
* public SDK profile. These additions may not replace standard SDK fields.
|
|
43
|
-
*/
|
|
44
|
-
export declare const FIT_VENDOR_MESSAGE_EXTENSIONS: Record<number, Message>;
|
|
45
|
-
export declare const FIT_VENDOR_TYPE_EXTENSIONS: Record<string, Record<number, string>>;
|
|
46
40
|
export declare const FIT: FitType;
|
package/dist/cjs/fit.js
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.FIT =
|
|
4
|
-
const
|
|
3
|
+
exports.FIT = void 0;
|
|
4
|
+
const profile_js_1 = require("./profile.js");
|
|
5
5
|
const metersInOneKilometer = 1000;
|
|
6
6
|
const secondsInOneHour = 3600;
|
|
7
7
|
// according to https://en.wikipedia.org/wiki/Mile
|
|
@@ -31,119 +31,9 @@ const options = {
|
|
|
31
31
|
psi: { multiplier: psiInOneBar, offset: 0 },
|
|
32
32
|
},
|
|
33
33
|
};
|
|
34
|
-
/**
|
|
35
|
-
* Garmin fields observed in the external FIT corpus but absent from the pinned
|
|
36
|
-
* public SDK profile. These additions may not replace standard SDK fields.
|
|
37
|
-
*/
|
|
38
|
-
exports.FIT_VENDOR_MESSAGE_EXTENSIONS = {
|
|
39
|
-
18: {
|
|
40
|
-
name: 'session',
|
|
41
|
-
178: field('est_sweat_loss', 'uint16', 1, 'ml'),
|
|
42
|
-
188: field('primary_benefit', 'uint8'),
|
|
43
|
-
205: field('beginning_potential_stamina', 'uint8', 1, 'percent'),
|
|
44
|
-
206: field('ending_potential_stamina', 'uint8', 1, 'percent'),
|
|
45
|
-
207: field('min_stamina', 'uint8', 1, 'percent'),
|
|
46
|
-
},
|
|
47
|
-
20: {
|
|
48
|
-
name: 'record',
|
|
49
|
-
90: field('garmin_performance_condition', 'sint8'),
|
|
50
|
-
137: field('potential_stamina', 'uint8', 1, 'percent'),
|
|
51
|
-
138: field('stamina', 'uint8', 1, 'percent'),
|
|
52
|
-
},
|
|
53
|
-
23: {
|
|
54
|
-
name: 'device_info',
|
|
55
|
-
24: field('ant_id', 'uint32z'),
|
|
56
|
-
},
|
|
57
|
-
// Undocumented Garmin user metrics message observed in activity FIT files.
|
|
58
|
-
79: {
|
|
59
|
-
name: 'user_metrics',
|
|
60
|
-
0: field('vo2_max', 'uint16', 1024 / 3.5, 'ml/kg/min'),
|
|
61
|
-
1: field('age', 'uint8', 1, 'years'),
|
|
62
|
-
2: field('height', 'uint8', 100, 'm'),
|
|
63
|
-
3: field('weight', 'uint16', 10, 'kg'),
|
|
64
|
-
4: field('gender', 'gender'),
|
|
65
|
-
6: field('max_heart_rate', 'uint8', 1, 'bpm'),
|
|
66
|
-
8: field('remaining_recovery_time', 'uint16'),
|
|
67
|
-
11: field('lthr', 'uint16', 1, 'bpm'),
|
|
68
|
-
12: field('ltpower', 'uint16', 1, 'watts'),
|
|
69
|
-
13: field('ltspeed', 'uint16', 1000, 'm/s'),
|
|
70
|
-
16: field('start_of_activity', 'date_time'),
|
|
71
|
-
19: field('first_vo2_max', 'uint32', 65536 / 3.5, 'ml/kg/min'),
|
|
72
|
-
35: field('end_of_previous_activity', 'date_time'),
|
|
73
|
-
253: field('timestamp', 'date_time'),
|
|
74
|
-
},
|
|
75
|
-
// Undocumented Garmin activity metrics message observed in activity FIT files.
|
|
76
|
-
140: {
|
|
77
|
-
name: 'activity_metrics',
|
|
78
|
-
1: field('new_max_heart_rate', 'uint8', 1, 'bpm'),
|
|
79
|
-
4: field('aerobic_training_effect', 'uint8', 10),
|
|
80
|
-
7: field('vo2_max', 'uint32', 65536 / 3.5, 'ml/kg/min'),
|
|
81
|
-
9: field('recovery_time', 'uint16', 1, 'min'),
|
|
82
|
-
11: field('sport', 'sport'),
|
|
83
|
-
20: field('anaerobic_training_effect', 'uint8', 10),
|
|
84
|
-
29: field('first_vo2_max', 'uint32', 65536 / 3.5, 'ml/kg/min'),
|
|
85
|
-
41: field('primary_benefit', 'uint8'),
|
|
86
|
-
60: field('total_ascent', 'uint16', 1, 'm'),
|
|
87
|
-
61: field('total_descent', 'uint16', 1, 'm'),
|
|
88
|
-
62: field('avg_power', 'uint16', 1, 'watts'),
|
|
89
|
-
63: field('avg_heart_rate', 'uint8', 1, 'bpm'),
|
|
90
|
-
},
|
|
91
|
-
312: {
|
|
92
|
-
name: 'split',
|
|
93
|
-
107: field('beginning_potential_stamina', 'uint8', 1, 'percent'),
|
|
94
|
-
108: field('ending_potential_stamina', 'uint8', 1, 'percent'),
|
|
95
|
-
109: field('min_stamina', 'uint8', 1, 'percent'),
|
|
96
|
-
},
|
|
97
|
-
};
|
|
98
|
-
exports.FIT_VENDOR_TYPE_EXTENSIONS = {
|
|
99
|
-
mesg_num: {
|
|
100
|
-
79: 'user_metrics',
|
|
101
|
-
140: 'activity_metrics',
|
|
102
|
-
},
|
|
103
|
-
};
|
|
104
|
-
function field(name, type, scale = 1, units = '', baseType) {
|
|
105
|
-
return Object.assign(Object.assign({ field: name, type }, (baseType ? { baseType } : {})), { scale, offset: 0, units });
|
|
106
|
-
}
|
|
107
|
-
function mergeVendorMessages() {
|
|
108
|
-
const messages = Object.assign({}, garmin_profile_generated_js_1.GARMIN_MESSAGES);
|
|
109
|
-
Object.entries(exports.FIT_VENDOR_MESSAGE_EXTENSIONS).forEach(([messageIdText, extension]) => {
|
|
110
|
-
const messageId = Number(messageIdText);
|
|
111
|
-
const standardMessage = messages[messageId];
|
|
112
|
-
if (!standardMessage) {
|
|
113
|
-
messages[messageId] = extension;
|
|
114
|
-
return;
|
|
115
|
-
}
|
|
116
|
-
if (standardMessage.name !== extension.name) {
|
|
117
|
-
throw new Error(`Vendor message ${messageId} conflicts with the Garmin SDK name`);
|
|
118
|
-
}
|
|
119
|
-
Object.keys(extension)
|
|
120
|
-
.filter(key => key !== 'name')
|
|
121
|
-
.forEach((fieldId) => {
|
|
122
|
-
if (standardMessage[Number(fieldId)]) {
|
|
123
|
-
throw new Error(`Vendor message ${messageId}, field ${fieldId} conflicts with the Garmin SDK profile`);
|
|
124
|
-
}
|
|
125
|
-
});
|
|
126
|
-
messages[messageId] = Object.assign(Object.assign({}, standardMessage), extension);
|
|
127
|
-
});
|
|
128
|
-
return messages;
|
|
129
|
-
}
|
|
130
|
-
function mergeVendorTypes() {
|
|
131
|
-
const types = Object.fromEntries(Object.entries(garmin_profile_generated_js_1.GARMIN_TYPES).map(([name, values]) => [name, Object.assign({}, values)]));
|
|
132
|
-
Object.entries(exports.FIT_VENDOR_TYPE_EXTENSIONS).forEach(([name, extension]) => {
|
|
133
|
-
var _a;
|
|
134
|
-
const standardValues = (_a = types[name]) !== null && _a !== void 0 ? _a : {};
|
|
135
|
-
Object.keys(extension).forEach((valueId) => {
|
|
136
|
-
if (standardValues[Number(valueId)] !== undefined) {
|
|
137
|
-
throw new Error(`Vendor type ${name}, value ${valueId} conflicts with the Garmin SDK profile`);
|
|
138
|
-
}
|
|
139
|
-
});
|
|
140
|
-
types[name] = Object.assign(Object.assign({}, standardValues), extension);
|
|
141
|
-
});
|
|
142
|
-
return types;
|
|
143
|
-
}
|
|
144
34
|
exports.FIT = {
|
|
145
35
|
scConst: 180 / Math.pow(2, 31),
|
|
146
36
|
options,
|
|
147
|
-
messages:
|
|
148
|
-
types:
|
|
37
|
+
messages: profile_js_1.PROFILE_MESSAGES,
|
|
38
|
+
types: profile_js_1.PROFILE_TYPES,
|
|
149
39
|
};
|
package/dist/cjs/fit_types.d.ts
CHANGED
|
@@ -2097,6 +2097,7 @@ export interface ParsedFit {
|
|
|
2097
2097
|
messages?: ParsedMessages;
|
|
2098
2098
|
raw_developer_fields?: ParsedRawDeveloperField[];
|
|
2099
2099
|
raw_messages?: ParsedRawFitMessage[];
|
|
2100
|
+
unmapped_messages?: ParsedRawFitMessage[];
|
|
2100
2101
|
file_creator: ParsedFileCreator;
|
|
2101
2102
|
device_settings: ParsedDeviceSettings;
|
|
2102
2103
|
dive_summary?: ParsedDiveSummary;
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import type { Message } from './fit.js';
|
|
2
|
+
/**
|
|
3
|
+
* Static, community-maintained FIT interoperability profile.
|
|
4
|
+
*
|
|
5
|
+
* This table is ordinary project source maintained under the repository's MIT
|
|
6
|
+
* license. See PROFILE.md for the maintenance and verification policy.
|
|
7
|
+
*/
|
|
8
|
+
export declare const PROFILE_MESSAGES: Record<number, Message>;
|
|
9
|
+
export declare const PROFILE_TYPES: Record<string, Record<number, string | number>>;
|