@garmin/fitsdk 21.133.0 → 21.158.0
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/package.json +1 -1
- package/src/accumulator.js +15 -5
- package/src/bit-stream.js +2 -2
- package/src/crc-calculator.js +2 -2
- package/src/decoder.js +80 -24
- package/src/fit.js +2 -2
- package/src/index.js +2 -2
- package/src/profile.js +173 -16
- package/src/stream.js +7 -7
- package/src/utils-hr-mesg.js +2 -2
- package/src/utils-internal.js +2 -2
- package/src/utils.js +2 -2
package/package.json
CHANGED
package/src/accumulator.js
CHANGED
|
@@ -5,8 +5,8 @@
|
|
|
5
5
|
// Transfer (FIT) Protocol License.
|
|
6
6
|
/////////////////////////////////////////////////////////////////////////////////////////////
|
|
7
7
|
// ****WARNING**** This file is auto-generated! Do NOT edit this file.
|
|
8
|
-
// Profile Version = 21.
|
|
9
|
-
// Tag = production/release/21.
|
|
8
|
+
// Profile Version = 21.158.0Release
|
|
9
|
+
// Tag = production/release/21.158.0-0-gc9428aa
|
|
10
10
|
/////////////////////////////////////////////////////////////////////////////////////////////
|
|
11
11
|
|
|
12
12
|
|
|
@@ -32,16 +32,26 @@ class AccumulatedField {
|
|
|
32
32
|
class Accumulator {
|
|
33
33
|
#messages = {};
|
|
34
34
|
|
|
35
|
-
|
|
35
|
+
createAccumulatedField(mesgNum, fieldNum, value) {
|
|
36
|
+
const accumualtedField = new AccumulatedField(value);
|
|
37
|
+
|
|
36
38
|
if (this.#messages[mesgNum] == null) {
|
|
37
39
|
this.#messages[mesgNum] = {};
|
|
38
40
|
}
|
|
39
41
|
|
|
40
|
-
this.#messages[mesgNum][fieldNum] =
|
|
42
|
+
this.#messages[mesgNum][fieldNum] = accumualtedField;
|
|
43
|
+
|
|
44
|
+
return accumualtedField;
|
|
41
45
|
}
|
|
42
46
|
|
|
43
47
|
accumulate(mesgNum, fieldNum, value, bits) {
|
|
44
|
-
|
|
48
|
+
let accumualtedField = this.#messages[mesgNum]?.[fieldNum];
|
|
49
|
+
|
|
50
|
+
if(accumualtedField == null) {
|
|
51
|
+
accumualtedField = this.createAccumulatedField(mesgNum, fieldNum, value);
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
return accumualtedField.accumulate(value, bits);
|
|
45
55
|
}
|
|
46
56
|
}
|
|
47
57
|
|
package/src/bit-stream.js
CHANGED
|
@@ -5,8 +5,8 @@
|
|
|
5
5
|
// Transfer (FIT) Protocol License.
|
|
6
6
|
/////////////////////////////////////////////////////////////////////////////////////////////
|
|
7
7
|
// ****WARNING**** This file is auto-generated! Do NOT edit this file.
|
|
8
|
-
// Profile Version = 21.
|
|
9
|
-
// Tag = production/release/21.
|
|
8
|
+
// Profile Version = 21.158.0Release
|
|
9
|
+
// Tag = production/release/21.158.0-0-gc9428aa
|
|
10
10
|
/////////////////////////////////////////////////////////////////////////////////////////////
|
|
11
11
|
|
|
12
12
|
|
package/src/crc-calculator.js
CHANGED
|
@@ -5,8 +5,8 @@
|
|
|
5
5
|
// Transfer (FIT) Protocol License.
|
|
6
6
|
/////////////////////////////////////////////////////////////////////////////////////////////
|
|
7
7
|
// ****WARNING**** This file is auto-generated! Do NOT edit this file.
|
|
8
|
-
// Profile Version = 21.
|
|
9
|
-
// Tag = production/release/21.
|
|
8
|
+
// Profile Version = 21.158.0Release
|
|
9
|
+
// Tag = production/release/21.158.0-0-gc9428aa
|
|
10
10
|
/////////////////////////////////////////////////////////////////////////////////////////////
|
|
11
11
|
|
|
12
12
|
|
package/src/decoder.js
CHANGED
|
@@ -5,8 +5,8 @@
|
|
|
5
5
|
// Transfer (FIT) Protocol License.
|
|
6
6
|
/////////////////////////////////////////////////////////////////////////////////////////////
|
|
7
7
|
// ****WARNING**** This file is auto-generated! Do NOT edit this file.
|
|
8
|
-
// Profile Version = 21.
|
|
9
|
-
// Tag = production/release/21.
|
|
8
|
+
// Profile Version = 21.158.0Release
|
|
9
|
+
// Tag = production/release/21.158.0-0-gc9428aa
|
|
10
10
|
/////////////////////////////////////////////////////////////////////////////////////////////
|
|
11
11
|
|
|
12
12
|
|
|
@@ -25,8 +25,17 @@ const MESG_DEFINITION_MASK = 0x40;
|
|
|
25
25
|
const DEV_DATA_MASK = 0x20;
|
|
26
26
|
const MESG_HEADER_MASK = 0x00;
|
|
27
27
|
const LOCAL_MESG_NUM_MASK = 0x0F;
|
|
28
|
+
|
|
29
|
+
const HEADER_WITH_CRC_SIZE = 14;
|
|
30
|
+
const HEADER_WITHOUT_CRC_SIZE = 12;
|
|
28
31
|
const CRC_SIZE = 2;
|
|
29
32
|
|
|
33
|
+
const DecodeMode = Object.freeze({
|
|
34
|
+
NORMAL: "normal",
|
|
35
|
+
SKIP_HEADER: "skipHeader",
|
|
36
|
+
DATA_ONLY: "dataOnly"
|
|
37
|
+
});
|
|
38
|
+
|
|
30
39
|
class Decoder {
|
|
31
40
|
#localMessageDefinitions = [];
|
|
32
41
|
#developerDataDefinitions = {};
|
|
@@ -36,6 +45,8 @@ class Decoder {
|
|
|
36
45
|
#fieldsWithSubFields = [];
|
|
37
46
|
#fieldsToExpand = [];
|
|
38
47
|
|
|
48
|
+
#decodeMode = DecodeMode.NORMAL;
|
|
49
|
+
|
|
39
50
|
#mesgListener = null;
|
|
40
51
|
#optExpandSubFields = true;
|
|
41
52
|
#optExpandComponents = true;
|
|
@@ -67,7 +78,7 @@ class Decoder {
|
|
|
67
78
|
static isFIT(stream) {
|
|
68
79
|
try {
|
|
69
80
|
const fileHeaderSize = stream.peekByte();
|
|
70
|
-
if ([
|
|
81
|
+
if ([HEADER_WITH_CRC_SIZE, HEADER_WITHOUT_CRC_SIZE].includes(fileHeaderSize) != true) {
|
|
71
82
|
return false;
|
|
72
83
|
}
|
|
73
84
|
|
|
@@ -75,7 +86,7 @@ class Decoder {
|
|
|
75
86
|
return false;
|
|
76
87
|
}
|
|
77
88
|
|
|
78
|
-
const fileHeader = Decoder.#readFileHeader(stream, true);
|
|
89
|
+
const fileHeader = Decoder.#readFileHeader(stream, { resetPosition: true, });
|
|
79
90
|
if (fileHeader.dataType !== ".FIT") {
|
|
80
91
|
return false;
|
|
81
92
|
}
|
|
@@ -105,7 +116,7 @@ class Decoder {
|
|
|
105
116
|
return false;
|
|
106
117
|
}
|
|
107
118
|
|
|
108
|
-
const fileHeader = Decoder.#readFileHeader(this.#stream, true);
|
|
119
|
+
const fileHeader = Decoder.#readFileHeader(this.#stream, { resetPosition: true, });
|
|
109
120
|
|
|
110
121
|
if (this.#stream.length < fileHeader.headerSize + fileHeader.dataSize + CRC_SIZE) {
|
|
111
122
|
return false;
|
|
@@ -113,7 +124,7 @@ class Decoder {
|
|
|
113
124
|
|
|
114
125
|
const buf = new Uint8Array(this.#stream.slice(0, this.#stream.length))
|
|
115
126
|
|
|
116
|
-
if (fileHeader.headerSize ===
|
|
127
|
+
if (fileHeader.headerSize === HEADER_WITH_CRC_SIZE && fileHeader.headerCRC !== 0x0000
|
|
117
128
|
&& fileHeader.headerCRC != CrcCalculator.calculateCRC(buf, 0, 12)) {
|
|
118
129
|
return false;
|
|
119
130
|
}
|
|
@@ -150,6 +161,8 @@ class Decoder {
|
|
|
150
161
|
* @param {boolean} [options.convertDateTimesToDates=true] - (optional, default true)
|
|
151
162
|
* @param {Boolean} [options.includeUnknownData=false] - (optional, default false)
|
|
152
163
|
* @param {boolean} [options.mergeHeartRates=true] - (optional, default false)
|
|
164
|
+
* @param {boolean} [options.skipHeader=false] - (optional, default false)
|
|
165
|
+
* @param {boolean} [options.dataOnly=false] - (optional, default false)
|
|
153
166
|
* @return {Object} result - {messages:Array, errors:Array}
|
|
154
167
|
*/
|
|
155
168
|
read({
|
|
@@ -160,7 +173,9 @@ class Decoder {
|
|
|
160
173
|
convertTypesToStrings = true,
|
|
161
174
|
convertDateTimesToDates = true,
|
|
162
175
|
includeUnknownData = false,
|
|
163
|
-
mergeHeartRates = true
|
|
176
|
+
mergeHeartRates = true,
|
|
177
|
+
skipHeader = false,
|
|
178
|
+
dataOnly = false,} = {}) {
|
|
164
179
|
|
|
165
180
|
this.#mesgListener = mesgListener;
|
|
166
181
|
this.#optExpandSubFields = expandSubFields
|
|
@@ -182,7 +197,11 @@ class Decoder {
|
|
|
182
197
|
this.#throwError("mergeHeartRates requires applyScaleAndOffset and expandComponents to be enabled");
|
|
183
198
|
}
|
|
184
199
|
|
|
185
|
-
|
|
200
|
+
if (dataOnly && skipHeader) {
|
|
201
|
+
this.#throwError("dataOnly and skipHeader cannot both be enabled")
|
|
202
|
+
}
|
|
203
|
+
|
|
204
|
+
this.#decodeMode = skipHeader ? DecodeMode.SKIP_HEADER : dataOnly ? DecodeMode.DATA_ONLY : DecodeMode.NORMAL;
|
|
186
205
|
|
|
187
206
|
while (this.#stream.position < this.#stream.length) {
|
|
188
207
|
this.#decodeNextFile();
|
|
@@ -203,23 +222,23 @@ class Decoder {
|
|
|
203
222
|
#decodeNextFile() {
|
|
204
223
|
const position = this.#stream.position;
|
|
205
224
|
|
|
206
|
-
if (!this.isFIT()) {
|
|
225
|
+
if (this.#decodeMode === DecodeMode.NORMAL && !this.isFIT()) {
|
|
207
226
|
this.#throwError("input is not a FIT file");
|
|
208
227
|
}
|
|
209
228
|
|
|
210
229
|
this.#stream.crcCalculator = new CrcCalculator();
|
|
211
230
|
|
|
212
|
-
const
|
|
231
|
+
const { headerSize, dataSize } = Decoder.#readFileHeader(this.#stream, { decodeMode: this.#decodeMode });
|
|
213
232
|
|
|
214
233
|
// Read data messages and definitions
|
|
215
|
-
while (this.#stream.position < (position +
|
|
234
|
+
while (this.#stream.position < (position + headerSize + dataSize)) {
|
|
216
235
|
this.#decodeNextRecord();
|
|
217
236
|
}
|
|
218
237
|
|
|
219
238
|
// Check the CRC
|
|
220
239
|
const calculatedCrc = this.#stream.crcCalculator.crc;
|
|
221
240
|
const crc = this.#stream.readUInt16();
|
|
222
|
-
if (crc !== calculatedCrc) {
|
|
241
|
+
if (this.#decodeMode === DecodeMode.NORMAL && crc !== calculatedCrc) {
|
|
223
242
|
this.#throwError("CRC error");
|
|
224
243
|
}
|
|
225
244
|
}
|
|
@@ -341,7 +360,7 @@ class Decoder {
|
|
|
341
360
|
}
|
|
342
361
|
|
|
343
362
|
if (field?.isAccumulated) {
|
|
344
|
-
this.#
|
|
363
|
+
this.#setAccumulatedField(messageDefinition, message, field, rawFieldValue);
|
|
345
364
|
}
|
|
346
365
|
}
|
|
347
366
|
});
|
|
@@ -530,7 +549,7 @@ class Decoder {
|
|
|
530
549
|
while (this.#fieldsToExpand.length > 0) {
|
|
531
550
|
const name = this.#fieldsToExpand.shift();
|
|
532
551
|
|
|
533
|
-
const { rawFieldValue, fieldDefinitionNumber, isSubField } = message[name];
|
|
552
|
+
const { rawFieldValue, fieldDefinitionNumber, isSubField } = message[name] ?? mesg[name];
|
|
534
553
|
let field = Profile.messages[mesgNum].fields[fieldDefinitionNumber];
|
|
535
554
|
field = isSubField ? this.#lookupSubfield(field, name) : field;
|
|
536
555
|
const baseType = FIT.FieldTypeToBaseType[field.type];
|
|
@@ -546,6 +565,10 @@ class Decoder {
|
|
|
546
565
|
const bitStream = new BitStream(rawFieldValue, baseType);
|
|
547
566
|
|
|
548
567
|
for (let j = 0; j < field.components.length; j++) {
|
|
568
|
+
if (bitStream.bitsAvailable < field.bits[j]) {
|
|
569
|
+
break;
|
|
570
|
+
}
|
|
571
|
+
|
|
549
572
|
const targetField = fields[field.components[j]];
|
|
550
573
|
if (mesg[targetField.name] == null) {
|
|
551
574
|
const baseType = FIT.FieldTypeToBaseType[targetField.type];
|
|
@@ -560,22 +583,22 @@ class Decoder {
|
|
|
560
583
|
};
|
|
561
584
|
}
|
|
562
585
|
|
|
563
|
-
if (bitStream.bitsAvailable < field.bits[j]) {
|
|
564
|
-
break;
|
|
565
|
-
}
|
|
566
|
-
|
|
567
586
|
let value = bitStream.readBits(field.bits[j]);
|
|
568
587
|
|
|
569
|
-
|
|
588
|
+
if (targetField.isAccumulated) {
|
|
589
|
+
value = this.#accumulator.accumulate(mesgNum, targetField.num, value, field.bits[j]);
|
|
590
|
+
}
|
|
591
|
+
|
|
592
|
+
// Undo component scale and offset before applying the destination field's scale and offset
|
|
593
|
+
value = (value / field.scale[j] - field.offset[j]);
|
|
570
594
|
|
|
571
|
-
|
|
595
|
+
const rawValue = (value + targetField.offset) * targetField.scale;
|
|
596
|
+
mesg[targetField.name].rawFieldValue.push(rawValue);
|
|
572
597
|
|
|
573
|
-
if (
|
|
598
|
+
if (rawValue === mesg[targetField.name].invalidValue) {
|
|
574
599
|
mesg[targetField.name].fieldValue.push(null);
|
|
575
600
|
}
|
|
576
601
|
else {
|
|
577
|
-
value = value / field.scale[j] - field.offset[j];
|
|
578
|
-
|
|
579
602
|
if (this.#optConvertTypesToStrings) {
|
|
580
603
|
value = this.#convertTypeToString(mesg, targetField, value);
|
|
581
604
|
}
|
|
@@ -681,6 +704,26 @@ class Decoder {
|
|
|
681
704
|
}
|
|
682
705
|
}
|
|
683
706
|
|
|
707
|
+
#setAccumulatedField(messageDefinition, message, field, rawFieldValue) {
|
|
708
|
+
const rawFieldValues = Array.isArray(rawFieldValue) ? rawFieldValue : [rawFieldValue];
|
|
709
|
+
|
|
710
|
+
rawFieldValues.forEach((value) => {
|
|
711
|
+
Object.values(message).forEach((containingField) => {
|
|
712
|
+
let components = messageDefinition.fields[containingField.fieldDefinitionNumber].components ?? []
|
|
713
|
+
|
|
714
|
+
components.forEach((componentFieldNum, i) => {
|
|
715
|
+
const targetField = messageDefinition.fields[componentFieldNum];
|
|
716
|
+
|
|
717
|
+
if(targetField?.num == field.num && targetField?.isAccumulated) {
|
|
718
|
+
value = (((value / field.scale) - field.offset) + containingField.offset[i]) * containingField.scale[i];
|
|
719
|
+
}
|
|
720
|
+
});
|
|
721
|
+
});
|
|
722
|
+
|
|
723
|
+
this.#accumulator.createAccumulatedField(messageDefinition.num, field.num, value);
|
|
724
|
+
});
|
|
725
|
+
}
|
|
726
|
+
|
|
684
727
|
#convertTypeToString(messageDefinition, field, rawFieldValue) {
|
|
685
728
|
if ([Profile.MesgNum.DEVELOPER_DATA_ID, Profile.MesgNum.FIELD_DESCRIPTION].includes(messageDefinition.globalMessageNumber)) {
|
|
686
729
|
return rawFieldValue;
|
|
@@ -711,9 +754,22 @@ class Decoder {
|
|
|
711
754
|
return subField != null ? subField : {};
|
|
712
755
|
}
|
|
713
756
|
|
|
714
|
-
static #readFileHeader(stream, resetPosition = false) {
|
|
757
|
+
static #readFileHeader(stream, { resetPosition = false, decodeMode = DecodeMode.NORMAL }) {
|
|
715
758
|
const position = stream.position;
|
|
716
759
|
|
|
760
|
+
if(decodeMode !== DecodeMode.NORMAL) {
|
|
761
|
+
if(decodeMode === DecodeMode.SKIP_HEADER) {
|
|
762
|
+
stream.seek(HEADER_WITH_CRC_SIZE);
|
|
763
|
+
}
|
|
764
|
+
|
|
765
|
+
const headerSize = decodeMode === DecodeMode.SKIP_HEADER ? HEADER_WITH_CRC_SIZE : 0;
|
|
766
|
+
|
|
767
|
+
return {
|
|
768
|
+
headerSize,
|
|
769
|
+
dataSize: stream.length - headerSize - CRC_SIZE,
|
|
770
|
+
};
|
|
771
|
+
}
|
|
772
|
+
|
|
717
773
|
const fileHeader = {
|
|
718
774
|
headerSize: stream.readByte(),
|
|
719
775
|
protocolVersion: stream.readByte(),
|
package/src/fit.js
CHANGED
|
@@ -5,8 +5,8 @@
|
|
|
5
5
|
// Transfer (FIT) Protocol License.
|
|
6
6
|
/////////////////////////////////////////////////////////////////////////////////////////////
|
|
7
7
|
// ****WARNING**** This file is auto-generated! Do NOT edit this file.
|
|
8
|
-
// Profile Version = 21.
|
|
9
|
-
// Tag = production/release/21.
|
|
8
|
+
// Profile Version = 21.158.0Release
|
|
9
|
+
// Tag = production/release/21.158.0-0-gc9428aa
|
|
10
10
|
/////////////////////////////////////////////////////////////////////////////////////////////
|
|
11
11
|
|
|
12
12
|
|
package/src/index.js
CHANGED
|
@@ -5,8 +5,8 @@
|
|
|
5
5
|
// Transfer (FIT) Protocol License.
|
|
6
6
|
/////////////////////////////////////////////////////////////////////////////////////////////
|
|
7
7
|
// ****WARNING**** This file is auto-generated! Do NOT edit this file.
|
|
8
|
-
// Profile Version = 21.
|
|
9
|
-
// Tag = production/release/21.
|
|
8
|
+
// Profile Version = 21.158.0Release
|
|
9
|
+
// Tag = production/release/21.158.0-0-gc9428aa
|
|
10
10
|
/////////////////////////////////////////////////////////////////////////////////////////////
|
|
11
11
|
|
|
12
12
|
|
package/src/profile.js
CHANGED
|
@@ -5,15 +5,15 @@
|
|
|
5
5
|
// Transfer (FIT) Protocol License.
|
|
6
6
|
/////////////////////////////////////////////////////////////////////////////////////////////
|
|
7
7
|
// ****WARNING**** This file is auto-generated! Do NOT edit this file.
|
|
8
|
-
// Profile Version = 21.
|
|
9
|
-
// Tag = production/release/21.
|
|
8
|
+
// Profile Version = 21.158.0Release
|
|
9
|
+
// Tag = production/release/21.158.0-0-gc9428aa
|
|
10
10
|
/////////////////////////////////////////////////////////////////////////////////////////////
|
|
11
11
|
|
|
12
12
|
|
|
13
13
|
const Profile = {
|
|
14
14
|
version: {
|
|
15
15
|
major: 21,
|
|
16
|
-
minor:
|
|
16
|
+
minor: 158,
|
|
17
17
|
patch: 0,
|
|
18
18
|
type: "Release"
|
|
19
19
|
},
|
|
@@ -6485,6 +6485,34 @@ const Profile = {
|
|
|
6485
6485
|
hasComponents: false,
|
|
6486
6486
|
subFields: []
|
|
6487
6487
|
},
|
|
6488
|
+
192: {
|
|
6489
|
+
num: 192, // A 0-100 scale representing how a user felt while performing a workout. Low values are considered feeling bad, while high values are good.
|
|
6490
|
+
name: "workoutFeel",
|
|
6491
|
+
type: "uint8",
|
|
6492
|
+
array: "false",
|
|
6493
|
+
scale: 1,
|
|
6494
|
+
offset: 0,
|
|
6495
|
+
units: "",
|
|
6496
|
+
bits: [],
|
|
6497
|
+
components: [],
|
|
6498
|
+
isAccumulated: false,
|
|
6499
|
+
hasComponents: false,
|
|
6500
|
+
subFields: []
|
|
6501
|
+
},
|
|
6502
|
+
193: {
|
|
6503
|
+
num: 193, // Common Borg CR10 / 0-10 RPE scale, multiplied 10x.. Aggregate score for all workouts in a single session.
|
|
6504
|
+
name: "workoutRpe",
|
|
6505
|
+
type: "uint8",
|
|
6506
|
+
array: "false",
|
|
6507
|
+
scale: 1,
|
|
6508
|
+
offset: 0,
|
|
6509
|
+
units: "",
|
|
6510
|
+
bits: [],
|
|
6511
|
+
components: [],
|
|
6512
|
+
isAccumulated: false,
|
|
6513
|
+
hasComponents: false,
|
|
6514
|
+
subFields: []
|
|
6515
|
+
},
|
|
6488
6516
|
194: {
|
|
6489
6517
|
num: 194, // Average SPO2 for the monitoring session
|
|
6490
6518
|
name: "avgSpo2",
|
|
@@ -16296,6 +16324,20 @@ const Profile = {
|
|
|
16296
16324
|
hasComponents: false,
|
|
16297
16325
|
subFields: []
|
|
16298
16326
|
},
|
|
16327
|
+
17: {
|
|
16328
|
+
num: 17, // Description of the workout
|
|
16329
|
+
name: "wktDescription",
|
|
16330
|
+
type: "string",
|
|
16331
|
+
array: "true",
|
|
16332
|
+
scale: 1,
|
|
16333
|
+
offset: 0,
|
|
16334
|
+
units: "",
|
|
16335
|
+
bits: [],
|
|
16336
|
+
components: [],
|
|
16337
|
+
isAccumulated: false,
|
|
16338
|
+
hasComponents: false,
|
|
16339
|
+
subFields: []
|
|
16340
|
+
},
|
|
16299
16341
|
},
|
|
16300
16342
|
},
|
|
16301
16343
|
158: {
|
|
@@ -18869,7 +18911,7 @@ const Profile = {
|
|
|
18869
18911
|
subFields: []
|
|
18870
18912
|
},
|
|
18871
18913
|
1: {
|
|
18872
|
-
num: 1, // Body battery level
|
|
18914
|
+
num: 1, // Body battery level: [0,100] Blank: -16
|
|
18873
18915
|
name: "level",
|
|
18874
18916
|
type: "sint8",
|
|
18875
18917
|
array: "true",
|
|
@@ -18932,7 +18974,7 @@ const Profile = {
|
|
|
18932
18974
|
subFields: []
|
|
18933
18975
|
},
|
|
18934
18976
|
0: {
|
|
18935
|
-
num: 0, // Event ID
|
|
18977
|
+
num: 0, // Event ID. Health SDK use only
|
|
18936
18978
|
name: "eventId",
|
|
18937
18979
|
type: "uint8",
|
|
18938
18980
|
array: "false",
|
|
@@ -19177,7 +19219,7 @@ const Profile = {
|
|
|
19177
19219
|
subFields: []
|
|
19178
19220
|
},
|
|
19179
19221
|
0: {
|
|
19180
|
-
num: 0, // Processing interval length in seconds
|
|
19222
|
+
num: 0, // Processing interval length in seconds. File start: 0xFFFFFFEF File stop: 0xFFFFFFEE
|
|
19181
19223
|
name: "processingInterval",
|
|
19182
19224
|
type: "uint16",
|
|
19183
19225
|
array: "false",
|
|
@@ -19240,7 +19282,7 @@ const Profile = {
|
|
|
19240
19282
|
subFields: []
|
|
19241
19283
|
},
|
|
19242
19284
|
1: {
|
|
19243
|
-
num: 1, // SpO2 Reading
|
|
19285
|
+
num: 1, // SpO2 Reading: [70,100] Blank: 240
|
|
19244
19286
|
name: "readingSpo2",
|
|
19245
19287
|
type: "uint8",
|
|
19246
19288
|
array: "true",
|
|
@@ -19254,7 +19296,7 @@ const Profile = {
|
|
|
19254
19296
|
subFields: []
|
|
19255
19297
|
},
|
|
19256
19298
|
2: {
|
|
19257
|
-
num: 2, // SpO2 Confidence
|
|
19299
|
+
num: 2, // SpO2 Confidence: [0,254]
|
|
19258
19300
|
name: "confidence",
|
|
19259
19301
|
type: "uint8",
|
|
19260
19302
|
array: "true",
|
|
@@ -19303,7 +19345,7 @@ const Profile = {
|
|
|
19303
19345
|
subFields: []
|
|
19304
19346
|
},
|
|
19305
19347
|
1: {
|
|
19306
|
-
num: 1, // Stress Level
|
|
19348
|
+
num: 1, // Stress Level: [0,100] Off wrist: -1 Excess motion: -2 Not enough data: -3 Recovering from exercise: -4 Unidentified: -5 Blank: -16
|
|
19307
19349
|
name: "stressLevel",
|
|
19308
19350
|
type: "sint8",
|
|
19309
19351
|
array: "true",
|
|
@@ -19352,7 +19394,7 @@ const Profile = {
|
|
|
19352
19394
|
subFields: []
|
|
19353
19395
|
},
|
|
19354
19396
|
1: {
|
|
19355
|
-
num: 1, // Breaths
|
|
19397
|
+
num: 1, // Breaths / min: [1,100] Invalid: 255 Excess motion: 254 Off wrist: 253 Not available: 252 Blank: 2.4
|
|
19356
19398
|
name: "respirationRate",
|
|
19357
19399
|
type: "sint16",
|
|
19358
19400
|
array: "true",
|
|
@@ -19415,7 +19457,7 @@ const Profile = {
|
|
|
19415
19457
|
subFields: []
|
|
19416
19458
|
},
|
|
19417
19459
|
2: {
|
|
19418
|
-
num: 2, // Beats / min
|
|
19460
|
+
num: 2, // Beats / min. Blank: 0
|
|
19419
19461
|
name: "heartRate",
|
|
19420
19462
|
type: "uint8",
|
|
19421
19463
|
array: "true",
|
|
@@ -19450,7 +19492,7 @@ const Profile = {
|
|
|
19450
19492
|
subFields: []
|
|
19451
19493
|
},
|
|
19452
19494
|
0: {
|
|
19453
|
-
num: 0,
|
|
19495
|
+
num: 0, // Encoded configuration data. Health SDK use only
|
|
19454
19496
|
name: "data",
|
|
19455
19497
|
type: "byte",
|
|
19456
19498
|
array: "true",
|
|
@@ -20892,7 +20934,7 @@ const Profile = {
|
|
|
20892
20934
|
subFields: []
|
|
20893
20935
|
},
|
|
20894
20936
|
0: {
|
|
20895
|
-
num: 0, //
|
|
20937
|
+
num: 0, // Millisecond resolution of the timestamp
|
|
20896
20938
|
name: "timestampMs",
|
|
20897
20939
|
type: "uint16",
|
|
20898
20940
|
array: "false",
|
|
@@ -20934,7 +20976,7 @@ const Profile = {
|
|
|
20934
20976
|
subFields: []
|
|
20935
20977
|
},
|
|
20936
20978
|
3: {
|
|
20937
|
-
num: 3,
|
|
20979
|
+
num: 3, // 1 = high confidence. 0 = low confidence. N/A when gap = 1
|
|
20938
20980
|
name: "quality",
|
|
20939
20981
|
type: "uint8",
|
|
20940
20982
|
array: "true",
|
|
@@ -20948,7 +20990,7 @@ const Profile = {
|
|
|
20948
20990
|
subFields: []
|
|
20949
20991
|
},
|
|
20950
20992
|
4: {
|
|
20951
|
-
num: 4,
|
|
20993
|
+
num: 4, // 1 = gap (time represents ms gap length). 0 = BBI data
|
|
20952
20994
|
name: "gap",
|
|
20953
20995
|
type: "uint8",
|
|
20954
20996
|
array: "true",
|
|
@@ -21101,6 +21143,20 @@ const Profile = {
|
|
|
21101
21143
|
hasComponents: false,
|
|
21102
21144
|
subFields: []
|
|
21103
21145
|
},
|
|
21146
|
+
6: {
|
|
21147
|
+
num: 6,
|
|
21148
|
+
name: "standardDeviation",
|
|
21149
|
+
type: "uint32",
|
|
21150
|
+
array: "false",
|
|
21151
|
+
scale: 1000,
|
|
21152
|
+
offset: 0,
|
|
21153
|
+
units: "m/s",
|
|
21154
|
+
bits: [],
|
|
21155
|
+
components: [],
|
|
21156
|
+
isAccumulated: false,
|
|
21157
|
+
hasComponents: false,
|
|
21158
|
+
subFields: []
|
|
21159
|
+
},
|
|
21104
21160
|
},
|
|
21105
21161
|
},
|
|
21106
21162
|
388: {
|
|
@@ -21480,6 +21536,83 @@ const Profile = {
|
|
|
21480
21536
|
subFields: []
|
|
21481
21537
|
},
|
|
21482
21538
|
},
|
|
21539
|
+
},
|
|
21540
|
+
398: {
|
|
21541
|
+
num: 398,
|
|
21542
|
+
name: "skinTempOvernight",
|
|
21543
|
+
messagesKey: "skinTempOvernightMesgs",
|
|
21544
|
+
fields: {
|
|
21545
|
+
253: {
|
|
21546
|
+
num: 253,
|
|
21547
|
+
name: "timestamp",
|
|
21548
|
+
type: "dateTime",
|
|
21549
|
+
array: "false",
|
|
21550
|
+
scale: 1,
|
|
21551
|
+
offset: 0,
|
|
21552
|
+
units: "",
|
|
21553
|
+
bits: [],
|
|
21554
|
+
components: [],
|
|
21555
|
+
isAccumulated: false,
|
|
21556
|
+
hasComponents: false,
|
|
21557
|
+
subFields: []
|
|
21558
|
+
},
|
|
21559
|
+
0: {
|
|
21560
|
+
num: 0,
|
|
21561
|
+
name: "localTimestamp",
|
|
21562
|
+
type: "localDateTime",
|
|
21563
|
+
array: "false",
|
|
21564
|
+
scale: 1,
|
|
21565
|
+
offset: 0,
|
|
21566
|
+
units: "",
|
|
21567
|
+
bits: [],
|
|
21568
|
+
components: [],
|
|
21569
|
+
isAccumulated: false,
|
|
21570
|
+
hasComponents: false,
|
|
21571
|
+
subFields: []
|
|
21572
|
+
},
|
|
21573
|
+
1: {
|
|
21574
|
+
num: 1, // The average overnight deviation from baseline temperature in degrees C
|
|
21575
|
+
name: "averageDeviation",
|
|
21576
|
+
type: "float32",
|
|
21577
|
+
array: "false",
|
|
21578
|
+
scale: 1,
|
|
21579
|
+
offset: 0,
|
|
21580
|
+
units: "",
|
|
21581
|
+
bits: [],
|
|
21582
|
+
components: [],
|
|
21583
|
+
isAccumulated: false,
|
|
21584
|
+
hasComponents: false,
|
|
21585
|
+
subFields: []
|
|
21586
|
+
},
|
|
21587
|
+
2: {
|
|
21588
|
+
num: 2, // The average 7 day overnight deviation from baseline temperature in degrees C
|
|
21589
|
+
name: "average7DayDeviation",
|
|
21590
|
+
type: "float32",
|
|
21591
|
+
array: "false",
|
|
21592
|
+
scale: 1,
|
|
21593
|
+
offset: 0,
|
|
21594
|
+
units: "",
|
|
21595
|
+
bits: [],
|
|
21596
|
+
components: [],
|
|
21597
|
+
isAccumulated: false,
|
|
21598
|
+
hasComponents: false,
|
|
21599
|
+
subFields: []
|
|
21600
|
+
},
|
|
21601
|
+
4: {
|
|
21602
|
+
num: 4, // Final overnight temperature value
|
|
21603
|
+
name: "nightlyValue",
|
|
21604
|
+
type: "float32",
|
|
21605
|
+
array: "false",
|
|
21606
|
+
scale: 1,
|
|
21607
|
+
offset: 0,
|
|
21608
|
+
units: "",
|
|
21609
|
+
bits: [],
|
|
21610
|
+
components: [],
|
|
21611
|
+
isAccumulated: false,
|
|
21612
|
+
hasComponents: false,
|
|
21613
|
+
subFields: []
|
|
21614
|
+
},
|
|
21615
|
+
},
|
|
21483
21616
|
},
|
|
21484
21617
|
105: {
|
|
21485
21618
|
num: 105,
|
|
@@ -21631,6 +21764,7 @@ types: {
|
|
|
21631
21764
|
388: "chronoShotData",
|
|
21632
21765
|
389: "hsaConfigurationData",
|
|
21633
21766
|
393: "diveApneaAlarm",
|
|
21767
|
+
398: "skinTempOvernight",
|
|
21634
21768
|
409: "hsaWristTemperatureData", // Message number for the HSA wrist temperature data message
|
|
21635
21769
|
0xFF00: "mfgRangeMin", // 0xFF00 - 0xFFFE reserved for manufacturer specific messages
|
|
21636
21770
|
0xFFFE: "mfgRangeMax", // 0xFF00 - 0xFFFE reserved for manufacturer specific messages
|
|
@@ -22190,6 +22324,7 @@ types: {
|
|
|
22190
22324
|
4: "positionWaypoint",
|
|
22191
22325
|
5: "positionMarked",
|
|
22192
22326
|
6: "off",
|
|
22327
|
+
13: "autoSelect",
|
|
22193
22328
|
},
|
|
22194
22329
|
lapTrigger: {
|
|
22195
22330
|
0: "manual",
|
|
@@ -22603,6 +22738,8 @@ types: {
|
|
|
22603
22738
|
148: "ezon",
|
|
22604
22739
|
149: "laisi",
|
|
22605
22740
|
150: "myzone",
|
|
22741
|
+
151: "abawo",
|
|
22742
|
+
152: "bafang",
|
|
22606
22743
|
255: "development",
|
|
22607
22744
|
257: "healthandlife",
|
|
22608
22745
|
258: "lezyne",
|
|
@@ -22676,6 +22813,10 @@ types: {
|
|
|
22676
22813
|
326: "nike",
|
|
22677
22814
|
327: "magicshine",
|
|
22678
22815
|
328: "ictrainer",
|
|
22816
|
+
329: "absoluteCycling",
|
|
22817
|
+
330: "eoSwimbetter",
|
|
22818
|
+
331: "mywhoosh",
|
|
22819
|
+
332: "ravemen",
|
|
22679
22820
|
5759: "actigraphcorp",
|
|
22680
22821
|
},
|
|
22681
22822
|
garminProduct: {
|
|
@@ -22975,6 +23116,7 @@ types: {
|
|
|
22975
23116
|
3449: "marqCommanderAsia",
|
|
22976
23117
|
3450: "marqExpeditionAsia",
|
|
22977
23118
|
3451: "marqAthleteAsia",
|
|
23119
|
+
3461: "indexSmartScale2",
|
|
22978
23120
|
3466: "instinctSolar",
|
|
22979
23121
|
3469: "fr45Asia",
|
|
22980
23122
|
3473: "vivoactive3Daimler",
|
|
@@ -23095,10 +23237,20 @@ types: {
|
|
|
23095
23237
|
4380: "lily2",
|
|
23096
23238
|
4394: "instinct2x",
|
|
23097
23239
|
4426: "vivoactive5",
|
|
23240
|
+
4432: "fr165",
|
|
23241
|
+
4433: "fr165Music",
|
|
23242
|
+
4440: "edge1050",
|
|
23098
23243
|
4442: "descentT2",
|
|
23099
23244
|
4446: "hrmFit",
|
|
23100
23245
|
4472: "marqGen2Commander",
|
|
23246
|
+
4477: "lilyAthlete", // aka the Lily 2 Active
|
|
23247
|
+
4532: "fenix8Solar",
|
|
23248
|
+
4533: "fenix8SolarLarge",
|
|
23249
|
+
4534: "fenix8Small",
|
|
23250
|
+
4536: "fenix8",
|
|
23101
23251
|
4556: "d2Mach1Pro",
|
|
23252
|
+
4575: "enduro3",
|
|
23253
|
+
4666: "fenixE",
|
|
23102
23254
|
10007: "sdm4", // SDM4 footpod
|
|
23103
23255
|
10014: "edgeRemote",
|
|
23104
23256
|
20533: "tacxTrainingAppWin",
|
|
@@ -23509,8 +23661,12 @@ types: {
|
|
|
23509
23661
|
6: "qom",
|
|
23510
23662
|
7: "pr",
|
|
23511
23663
|
8: "goal",
|
|
23512
|
-
9: "
|
|
23664
|
+
9: "carrot",
|
|
23513
23665
|
10: "clubLeader",
|
|
23666
|
+
11: "rival",
|
|
23667
|
+
12: "last",
|
|
23668
|
+
13: "recentBest",
|
|
23669
|
+
14: "courseRecord",
|
|
23514
23670
|
},
|
|
23515
23671
|
segmentDeleteStatus: {
|
|
23516
23672
|
0: "doNotDelete",
|
|
@@ -25603,6 +25759,7 @@ MesgNum : {
|
|
|
25603
25759
|
TANK_UPDATE: 319,
|
|
25604
25760
|
TANK_SUMMARY: 323,
|
|
25605
25761
|
SLEEP_ASSESSMENT: 346,
|
|
25762
|
+
SKIN_TEMP_OVERNIGHT: 398,
|
|
25606
25763
|
PAD: 105,
|
|
25607
25764
|
}
|
|
25608
25765
|
}
|
package/src/stream.js
CHANGED
|
@@ -5,8 +5,8 @@
|
|
|
5
5
|
// Transfer (FIT) Protocol License.
|
|
6
6
|
/////////////////////////////////////////////////////////////////////////////////////////////
|
|
7
7
|
// ****WARNING**** This file is auto-generated! Do NOT edit this file.
|
|
8
|
-
// Profile Version = 21.
|
|
9
|
-
// Tag = production/release/21.
|
|
8
|
+
// Profile Version = 21.158.0Release
|
|
9
|
+
// Tag = production/release/21.158.0-0-gc9428aa
|
|
10
10
|
/////////////////////////////////////////////////////////////////////////////////////////////
|
|
11
11
|
|
|
12
12
|
|
|
@@ -112,10 +112,10 @@ class Stream {
|
|
|
112
112
|
throw Error(`FIT Runtime Error end of stream at byte ${this.#position}`);
|
|
113
113
|
}
|
|
114
114
|
|
|
115
|
-
const bytes = this.#arrayBuffer
|
|
115
|
+
const bytes = new Uint8Array(this.#arrayBuffer, this.#position, size);
|
|
116
116
|
this.#position += size;
|
|
117
117
|
|
|
118
|
-
this.#crcCalculator?.addBytes(
|
|
118
|
+
this.#crcCalculator?.addBytes(bytes, 0, size);
|
|
119
119
|
|
|
120
120
|
return bytes;
|
|
121
121
|
}
|
|
@@ -168,14 +168,14 @@ class Stream {
|
|
|
168
168
|
const baseTypeSize = FIT.BaseTypeDefinitions[baseType].size;
|
|
169
169
|
const baseTypeInvalid = FIT.BaseTypeDefinitions[baseType].invalid;
|
|
170
170
|
|
|
171
|
-
const
|
|
171
|
+
const bytes = this.readBytes(size);
|
|
172
172
|
|
|
173
173
|
if (size % baseTypeSize !== 0) {
|
|
174
174
|
return convertInvalidToNull ? null : baseTypeInvalid;
|
|
175
175
|
}
|
|
176
176
|
|
|
177
177
|
if (baseType === FIT.BaseType.STRING) {
|
|
178
|
-
const string = this.#textDecoder.decode(
|
|
178
|
+
const string = this.#textDecoder.decode(bytes).replace(/\uFFFD/g, "");
|
|
179
179
|
const strings = string.split('\0');
|
|
180
180
|
|
|
181
181
|
while (strings[strings.length - 1] === "") {
|
|
@@ -189,7 +189,7 @@ class Stream {
|
|
|
189
189
|
return strings.length === 1 ? strings[0] : strings;
|
|
190
190
|
}
|
|
191
191
|
|
|
192
|
-
const dataView = new DataView(
|
|
192
|
+
const dataView = new DataView(bytes.buffer, bytes.byteOffset, bytes.byteLength);
|
|
193
193
|
let values = [];
|
|
194
194
|
|
|
195
195
|
const count = size / baseTypeSize;
|
package/src/utils-hr-mesg.js
CHANGED
|
@@ -5,8 +5,8 @@
|
|
|
5
5
|
// Transfer (FIT) Protocol License.
|
|
6
6
|
/////////////////////////////////////////////////////////////////////////////////////////////
|
|
7
7
|
// ****WARNING**** This file is auto-generated! Do NOT edit this file.
|
|
8
|
-
// Profile Version = 21.
|
|
9
|
-
// Tag = production/release/21.
|
|
8
|
+
// Profile Version = 21.158.0Release
|
|
9
|
+
// Tag = production/release/21.158.0-0-gc9428aa
|
|
10
10
|
/////////////////////////////////////////////////////////////////////////////////////////////
|
|
11
11
|
|
|
12
12
|
|
package/src/utils-internal.js
CHANGED
|
@@ -5,8 +5,8 @@
|
|
|
5
5
|
// Transfer (FIT) Protocol License.
|
|
6
6
|
/////////////////////////////////////////////////////////////////////////////////////////////
|
|
7
7
|
// ****WARNING**** This file is auto-generated! Do NOT edit this file.
|
|
8
|
-
// Profile Version = 21.
|
|
9
|
-
// Tag = production/release/21.
|
|
8
|
+
// Profile Version = 21.158.0Release
|
|
9
|
+
// Tag = production/release/21.158.0-0-gc9428aa
|
|
10
10
|
/////////////////////////////////////////////////////////////////////////////////////////////
|
|
11
11
|
|
|
12
12
|
|
package/src/utils.js
CHANGED
|
@@ -5,8 +5,8 @@
|
|
|
5
5
|
// Transfer (FIT) Protocol License.
|
|
6
6
|
/////////////////////////////////////////////////////////////////////////////////////////////
|
|
7
7
|
// ****WARNING**** This file is auto-generated! Do NOT edit this file.
|
|
8
|
-
// Profile Version = 21.
|
|
9
|
-
// Tag = production/release/21.
|
|
8
|
+
// Profile Version = 21.158.0Release
|
|
9
|
+
// Tag = production/release/21.158.0-0-gc9428aa
|
|
10
10
|
/////////////////////////////////////////////////////////////////////////////////////////////
|
|
11
11
|
|
|
12
12
|
|