@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 CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@garmin/fitsdk",
3
- "version": "21.133.0",
3
+ "version": "21.158.0",
4
4
  "description": "FIT JavaScript SDK",
5
5
  "main": "src/index.js",
6
6
  "type": "module",
@@ -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.133.0Release
9
- // Tag = production/release/21.133.0-0-g6002091
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
- add(mesgNum, fieldNum, value) {
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] = new AccumulatedField(value);
42
+ this.#messages[mesgNum][fieldNum] = accumualtedField;
43
+
44
+ return accumualtedField;
41
45
  }
42
46
 
43
47
  accumulate(mesgNum, fieldNum, value, bits) {
44
- return this.#messages[mesgNum]?.[fieldNum]?.accumulate(value, bits) ?? value;
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.133.0Release
9
- // Tag = production/release/21.133.0-0-g6002091
8
+ // Profile Version = 21.158.0Release
9
+ // Tag = production/release/21.158.0-0-gc9428aa
10
10
  /////////////////////////////////////////////////////////////////////////////////////////////
11
11
 
12
12
 
@@ -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.133.0Release
9
- // Tag = production/release/21.133.0-0-g6002091
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.133.0Release
9
- // Tag = production/release/21.133.0-0-g6002091
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 ([14, 12].includes(fileHeaderSize) != true) {
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 === 14 && fileHeader.headerCRC !== 0x0000
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
- this.#stream.reset();
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 fileHeader = Decoder.#readFileHeader(this.#stream);
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 + fileHeader.headerSize + fileHeader.dataSize)) {
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.#accumulator.add(mesgNum, fieldDefinition.fieldDefinitionNumber, rawFieldValue);
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
- value = this.#accumulator.accumulate(mesgNum, targetField.num, value, field.bits[j]) ?? value;
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
- mesg[targetField.name].rawFieldValue.push(value);
595
+ const rawValue = (value + targetField.offset) * targetField.scale;
596
+ mesg[targetField.name].rawFieldValue.push(rawValue);
572
597
 
573
- if (value === mesg[targetField.name].invalidValue) {
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.133.0Release
9
- // Tag = production/release/21.133.0-0-g6002091
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.133.0Release
9
- // Tag = production/release/21.133.0-0-g6002091
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.133.0Release
9
- // Tag = production/release/21.133.0-0-g6002091
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: 133,
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 ( 0 - 100 ) -300 indicates invalid -200 indicates large motion -100 indicates off wrist
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 * 100 /min -300 indicates invalid -200 indicates large motion -100 indicates off wrist
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, // ms since last overnight_raw_bbi message
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: "rival",
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.133.0Release
9
- // Tag = production/release/21.133.0-0-g6002091
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.slice(this.#position, this.#position + size);
115
+ const bytes = new Uint8Array(this.#arrayBuffer, this.#position, size);
116
116
  this.#position += size;
117
117
 
118
- this.#crcCalculator?.addBytes(new Uint8Array(bytes), 0, size);
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 arrayBuffer = this.readBytes(size);
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(arrayBuffer).replace(/\uFFFD/g, "");
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(arrayBuffer);
192
+ const dataView = new DataView(bytes.buffer, bytes.byteOffset, bytes.byteLength);
193
193
  let values = [];
194
194
 
195
195
  const count = size / baseTypeSize;
@@ -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.133.0Release
9
- // Tag = production/release/21.133.0-0-g6002091
8
+ // Profile Version = 21.158.0Release
9
+ // Tag = production/release/21.158.0-0-gc9428aa
10
10
  /////////////////////////////////////////////////////////////////////////////////////////////
11
11
 
12
12
 
@@ -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.133.0Release
9
- // Tag = production/release/21.133.0-0-g6002091
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.133.0Release
9
- // Tag = production/release/21.133.0-0-g6002091
8
+ // Profile Version = 21.158.0Release
9
+ // Tag = production/release/21.158.0-0-gc9428aa
10
10
  /////////////////////////////////////////////////////////////////////////////////////////////
11
11
 
12
12