diff --git a/package.json b/package.json index 31aa650..fd3a704 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "@garmin/fitsdk", - "version": "21.178.0", + "version": "21.188.0", "description": "FIT JavaScript SDK", "main": "src/index.js", "type": "module", diff --git a/src/accumulator.js b/src/accumulator.js index 2032c10..8dbe3e1 100644 --- a/src/accumulator.js +++ b/src/accumulator.js @@ -5,8 +5,8 @@ // Transfer (FIT) Protocol License. ///////////////////////////////////////////////////////////////////////////////////////////// // ****WARNING**** This file is auto-generated! Do NOT edit this file. -// Profile Version = 21.178.0Release -// Tag = production/release/21.178.0-0-g3bea629 +// Profile Version = 21.188.0Release +// Tag = production/release/21.188.0-0-g55050f8 ///////////////////////////////////////////////////////////////////////////////////////////// diff --git a/src/bit-stream.js b/src/bit-stream.js index cddb035..b95c670 100644 --- a/src/bit-stream.js +++ b/src/bit-stream.js @@ -5,8 +5,8 @@ // Transfer (FIT) Protocol License. ///////////////////////////////////////////////////////////////////////////////////////////// // ****WARNING**** This file is auto-generated! Do NOT edit this file. -// Profile Version = 21.178.0Release -// Tag = production/release/21.178.0-0-g3bea629 +// Profile Version = 21.188.0Release +// Tag = production/release/21.188.0-0-g55050f8 ///////////////////////////////////////////////////////////////////////////////////////////// diff --git a/src/crc-calculator.js b/src/crc-calculator.js index 252b6b7..810561d 100644 --- a/src/crc-calculator.js +++ b/src/crc-calculator.js @@ -5,8 +5,8 @@ // Transfer (FIT) Protocol License. ///////////////////////////////////////////////////////////////////////////////////////////// // ****WARNING**** This file is auto-generated! Do NOT edit this file. -// Profile Version = 21.178.0Release -// Tag = production/release/21.178.0-0-g3bea629 +// Profile Version = 21.188.0Release +// Tag = production/release/21.188.0-0-g55050f8 ///////////////////////////////////////////////////////////////////////////////////////////// diff --git a/src/decoder.js b/src/decoder.js index 5e5f96d..088f8a0 100644 --- a/src/decoder.js +++ b/src/decoder.js @@ -5,8 +5,8 @@ // Transfer (FIT) Protocol License. ///////////////////////////////////////////////////////////////////////////////////////////// // ****WARNING**** This file is auto-generated! Do NOT edit this file. -// Profile Version = 21.178.0Release -// Tag = production/release/21.178.0-0-g3bea629 +// Profile Version = 21.188.0Release +// Tag = production/release/21.188.0-0-g55050f8 ///////////////////////////////////////////////////////////////////////////////////////////// @@ -30,6 +30,7 @@ const LOCAL_MESG_NUM_MASK = 0x0F; const HEADER_WITH_CRC_SIZE = 14; const HEADER_WITHOUT_CRC_SIZE = 12; const CRC_SIZE = 2; +const PROFILE_VERSION_SCALE_CHANGE_VALUE = 2199; const DecodeMode = Object.freeze({ NORMAL: "normal", @@ -43,6 +44,7 @@ class Decoder { #stream = null; #accumulator = new Accumulator(); #messages = {}; + #profileVersion = null; #fieldsWithSubFields = []; #fieldsToExpand = []; @@ -200,7 +202,7 @@ class Decoder { mergeHeartRates = true, decodeMemoGlobs = false, skipHeader = false, - dataOnly = false,} = {}) { + dataOnly = false, } = {}) { this.#mesgListener = mesgListener; this.#mesgDefinitionListener = mesgDefinitionListener; @@ -217,6 +219,7 @@ class Decoder { this.#localMessageDefinitions = []; this.#developerDataDefinitions = {}; this.#messages = {}; + this.#profileVersion = null; const errors = []; @@ -247,7 +250,7 @@ class Decoder { errors.push(error); } finally { - return { messages: this.#messages, errors: errors }; + return { messages: this.#messages, profileVersion: this.#profileVersion, errors: errors }; } } @@ -260,7 +263,8 @@ class Decoder { this.#stream.crcCalculator = new CrcCalculator(); - const { headerSize, dataSize } = Decoder.#readFileHeader(this.#stream, { decodeMode: this.#decodeMode }); + const { headerSize, dataSize, profileVersion, } = Decoder.#readFileHeader(this.#stream, { decodeMode: this.#decodeMode }); + this.#profileVersion ??= profileVersion; // Read data messages and definitions while (this.#stream.position < (position + headerSize + dataSize)) { @@ -313,7 +317,7 @@ class Decoder { const fieldDefinition = { fieldDefinitionNumber: this.#stream.readByte(), size: this.#stream.readByte(), - baseType: this.#stream.readByte() + baseType: this.#stream.readByte() & FIT.BaseTypeMask, }; if (!(fieldDefinition.baseType in FIT.BaseTypeDefinitions)) { @@ -515,7 +519,7 @@ class Decoder { this.#developerDataDefinitions[message.developerDataIndex.rawFieldValue].fields.push({ developerDataIndex: message.developerDataIndex?.rawFieldValue, fieldDefinitionNumber: message.fieldDefinitionNumber?.rawFieldValue, - fitBaseTypeId: message.fitBaseTypeId?.rawFieldValue ?? null, + fitBaseTypeId: message.fitBaseTypeId?.rawFieldValue & FIT.BaseTypeMask ?? null, fieldName: message.fieldName?.rawFieldValue ?? null, array: message.array?.rawFieldValue ?? null, components: message.components?.rawFieldValue ?? null, @@ -799,26 +803,27 @@ class Decoder { static #readFileHeader(stream, { resetPosition = false, decodeMode = DecodeMode.NORMAL }) { const position = stream.position; - if(decodeMode !== DecodeMode.NORMAL) { - if(decodeMode === DecodeMode.SKIP_HEADER) { + if (decodeMode !== DecodeMode.NORMAL) { + if (decodeMode === DecodeMode.SKIP_HEADER) { stream.seek(HEADER_WITH_CRC_SIZE); } const headerSize = decodeMode === DecodeMode.SKIP_HEADER ? HEADER_WITH_CRC_SIZE : 0; + const dataSize = stream.length - headerSize - CRC_SIZE; return { headerSize, - dataSize: stream.length - headerSize - CRC_SIZE, + dataSize, }; } const fileHeader = { headerSize: stream.readByte(), protocolVersion: stream.readByte(), - profileVersion: stream.readUInt16(), + profileVersion: this.#expandProfileVersion(stream.readUInt16()), dataSize: stream.readUInt32(), dataType: stream.readString(4), - headerCRC: 0 + headerCRC: null }; if (fileHeader.headerSize === 14) { @@ -835,6 +840,14 @@ class Decoder { #throwError(error = "") { throw Error(`FIT Runtime Error at byte ${this.#stream.position} ${error}`.trimEnd()); } + + static #expandProfileVersion = (profileVersion) => { + const scale = profileVersion > PROFILE_VERSION_SCALE_CHANGE_VALUE ? 1000 : 100 + return { + major: Math.floor(profileVersion / scale), + minor: profileVersion % scale + } + } } export default Decoder; \ No newline at end of file diff --git a/src/encoder.js b/src/encoder.js index 0bd6c8d..732e291 100644 --- a/src/encoder.js +++ b/src/encoder.js @@ -5,8 +5,8 @@ // Transfer (FIT) Protocol License. ///////////////////////////////////////////////////////////////////////////////////////////// // ****WARNING**** This file is auto-generated! Do NOT edit this file. -// Profile Version = 21.178.0Release -// Tag = production/release/21.178.0-0-g3bea629 +// Profile Version = 21.188.0Release +// Tag = production/release/21.188.0-0-g55050f8 ///////////////////////////////////////////////////////////////////////////////////////////// diff --git a/src/fit.js b/src/fit.js index efb6f1e..fa63ba9 100644 --- a/src/fit.js +++ b/src/fit.js @@ -5,8 +5,8 @@ // Transfer (FIT) Protocol License. ///////////////////////////////////////////////////////////////////////////////////////////// // ****WARNING**** This file is auto-generated! Do NOT edit this file. -// Profile Version = 21.178.0Release -// Tag = production/release/21.178.0-0-g3bea629 +// Profile Version = 21.188.0Release +// Tag = production/release/21.188.0-0-g55050f8 ///////////////////////////////////////////////////////////////////////////////////////////// @@ -17,40 +17,42 @@ const BaseType = { ENUM: 0x00, SINT8: 0x01, UINT8: 0x02, - SINT16: 0x83, - UINT16: 0x84, - SINT32: 0x85, - UINT32: 0x86, + SINT16: 0x03, + UINT16: 0x04, + SINT32: 0x05, + UINT32: 0x06, STRING: 0x07, - FLOAT32: 0x88, - FLOAT64: 0x89, + FLOAT32: 0x08, + FLOAT64: 0x09, UINT8Z: 0x0A, - UINT16Z: 0x8B, - UINT32Z: 0x8C, + UINT16Z: 0x0B, + UINT32Z: 0x0C, BYTE: 0x0D, - SINT64: 0x8E, - UINT64: 0x8F, - UINT64Z: 0x90 + SINT64: 0x0E, + UINT64: 0x0F, + UINT64Z: 0x10 }; +const BaseTypeMask = 0x1F; + const BaseTypeDefinitions = { - 0x00: { size: 1, type: BaseType.ENUM, invalid: 0xFF }, - 0x01: { size: 1, type: BaseType.SINT8, invalid: 0x7F }, - 0x02: { size: 1, type: BaseType.UINT8, invalid: 0xFF }, - 0x83: { size: 2, type: BaseType.SINT16, invalid: 0x7FFF }, - 0x84: { size: 2, type: BaseType.UINT16, invalid: 0xFFFF }, - 0x85: { size: 4, type: BaseType.SINT32, invalid: 0x7FFFFFFF }, - 0x86: { size: 4, type: BaseType.UINT32, invalid: 0xFFFFFFFF }, - 0x07: { size: 1, type: BaseType.STRING, invalid: 0x00 }, - 0x88: { size: 4, type: BaseType.FLOAT32, invalid: 0xFFFFFFFF }, - 0x89: { size: 8, type: BaseType.FLOAT64, invalid: 0xFFFFFFFFFFFFFFFF }, - 0x0A: { size: 1, type: BaseType.UINT8Z, invalid: 0x00 }, - 0x8B: { size: 2, type: BaseType.UINT16Z, invalid: 0x0000 }, - 0x8C: { size: 4, type: BaseType.UINT32Z, invalid: 0x00000000 }, - 0x0D: { size: 1, type: BaseType.BYTE, invalid: 0xFF }, - 0x8E: { size: 8, type: BaseType.SINT64, invalid: 0x7FFFFFFFFFFFFFFF }, - 0x8F: { size: 8, type: BaseType.UINT64, invalid: 0xFFFFFFFFFFFFFFFF }, - 0x90: { size: 8, type: BaseType.UINT64Z, invalid: 0x0000000000000000 }, + 0x00: { size: 1, type: BaseType.ENUM, baseTypeEndianFlag: 0x00, invalid: 0xFF }, + 0x01: { size: 1, type: BaseType.SINT8, baseTypeEndianFlag: 0x00, invalid: 0x7F }, + 0x02: { size: 1, type: BaseType.UINT8, baseTypeEndianFlag: 0x00, invalid: 0xFF }, + 0x03: { size: 2, type: BaseType.SINT16, baseTypeEndianFlag: 0x80, invalid: 0x7FFF }, + 0x04: { size: 2, type: BaseType.UINT16, baseTypeEndianFlag: 0x80, invalid: 0xFFFF }, + 0x05: { size: 4, type: BaseType.SINT32, baseTypeEndianFlag: 0x80, invalid: 0x7FFFFFFF }, + 0x06: { size: 4, type: BaseType.UINT32, baseTypeEndianFlag: 0x80, invalid: 0xFFFFFFFF }, + 0x07: { size: 1, type: BaseType.STRING, baseTypeEndianFlag: 0x00, invalid: 0x00 }, + 0x08: { size: 4, type: BaseType.FLOAT32, baseTypeEndianFlag: 0x80, invalid: 0xFFFFFFFF }, + 0x09: { size: 8, type: BaseType.FLOAT64, baseTypeEndianFlag: 0x80, invalid: 0xFFFFFFFFFFFFFFFF }, + 0x0A: { size: 1, type: BaseType.UINT8Z, baseTypeEndianFlag: 0x00, invalid: 0x00 }, + 0x0B: { size: 2, type: BaseType.UINT16Z, baseTypeEndianFlag: 0x80, invalid: 0x0000 }, + 0x0C: { size: 4, type: BaseType.UINT32Z, baseTypeEndianFlag: 0x80, invalid: 0x00000000 }, + 0x0D: { size: 1, type: BaseType.BYTE, baseTypeEndianFlag: 0x00, invalid: 0xFF }, + 0x0E: { size: 8, type: BaseType.SINT64, baseTypeEndianFlag: 0x80, invalid: 0x7FFFFFFFFFFFFFFF }, + 0x0F: { size: 8, type: BaseType.UINT64, baseTypeEndianFlag: 0x80, invalid: 0xFFFFFFFFFFFFFFFF }, + 0x10: { size: 8, type: BaseType.UINT64Z, baseTypeEndianFlag: 0x80, invalid: 0x0000000000000000 }, }; const NumericFieldTypes = [ @@ -158,6 +160,7 @@ const isNumberStringDateOrBoolean = (obj) => { export default { BaseType, + BaseTypeMask, BaseTypeDefinitions, NumericFieldTypes, FloatingPointFieldTypes, diff --git a/src/index.js b/src/index.js index 9913ce5..c9d4c85 100644 --- a/src/index.js +++ b/src/index.js @@ -5,8 +5,8 @@ // Transfer (FIT) Protocol License. ///////////////////////////////////////////////////////////////////////////////////////////// // ****WARNING**** This file is auto-generated! Do NOT edit this file. -// Profile Version = 21.178.0Release -// Tag = production/release/21.178.0-0-g3bea629 +// Profile Version = 21.188.0Release +// Tag = production/release/21.188.0-0-g55050f8 ///////////////////////////////////////////////////////////////////////////////////////////// diff --git a/src/mesg-definition.js b/src/mesg-definition.js index 5a342e5..ce751da 100644 --- a/src/mesg-definition.js +++ b/src/mesg-definition.js @@ -5,8 +5,8 @@ // Transfer (FIT) Protocol License. ///////////////////////////////////////////////////////////////////////////////////////////// // ****WARNING**** This file is auto-generated! Do NOT edit this file. -// Profile Version = 21.178.0Release -// Tag = production/release/21.178.0-0-g3bea629 +// Profile Version = 21.188.0Release +// Tag = production/release/21.188.0-0-g55050f8 ///////////////////////////////////////////////////////////////////////////////////////////// @@ -67,6 +67,7 @@ class MesgDefinition { num: fieldProfile[1].num, size: this.#fieldSize(mesg[fieldName], baseTypeDef), baseType: baseType, + baseTypeEndianFlag: baseTypeDef.baseTypeEndianFlag, type: fieldProfile[1].type, scale, offset, @@ -77,11 +78,11 @@ class MesgDefinition { Object.keys(mesg.developerFields ?? {})?.sort()?.forEach((key) => { const { developerDataIdMesg, fieldDescriptionMesg, } = this.#fieldDescriptionForKey(fieldDescriptions, key); - const baseTypeDef = FIT.BaseTypeDefinitions[fieldDescriptionMesg.fitBaseTypeId]; + const baseTypeDef = FIT.BaseTypeDefinitions[fieldDescriptionMesg.fitBaseTypeId & FIT.BaseTypeMask]; this.developerFieldDefinitions.push({ key, - baseType: fieldDescriptionMesg.fitBaseTypeId, + baseType: fieldDescriptionMesg.fitBaseTypeId & FIT.BaseTypeMask, fieldDefinitionNumber: fieldDescriptionMesg.fieldDefinitionNumber, size: this.#fieldSize(mesg.developerFields[key], baseTypeDef), developerDataIndex: developerDataIdMesg.developerDataIndex, @@ -137,7 +138,7 @@ class MesgDefinition { this.fieldDefinitions.forEach((fieldDefinition) => { outputStream.writeUInt8(fieldDefinition.num); outputStream.writeUInt8(fieldDefinition.size); - outputStream.writeUInt8(fieldDefinition.baseType); + outputStream.writeUInt8(fieldDefinition.baseType | fieldDefinition.baseTypeEndianFlag); }); // Developer Field Definitions diff --git a/src/output-stream.js b/src/output-stream.js index 7b6efe7..cb6a934 100644 --- a/src/output-stream.js +++ b/src/output-stream.js @@ -5,8 +5,8 @@ // Transfer (FIT) Protocol License. ///////////////////////////////////////////////////////////////////////////////////////////// // ****WARNING**** This file is auto-generated! Do NOT edit this file. -// Profile Version = 21.178.0Release -// Tag = production/release/21.178.0-0-g3bea629 +// Profile Version = 21.188.0Release +// Tag = production/release/21.188.0-0-g55050f8 ///////////////////////////////////////////////////////////////////////////////////////////// diff --git a/src/profile.js b/src/profile.js index ce67945..038ade5 100644 --- a/src/profile.js +++ b/src/profile.js @@ -5,15 +5,15 @@ // Transfer (FIT) Protocol License. ///////////////////////////////////////////////////////////////////////////////////////////// // ****WARNING**** This file is auto-generated! Do NOT edit this file. -// Profile Version = 21.178.0Release -// Tag = production/release/21.178.0-0-g3bea629 +// Profile Version = 21.188.0Release +// Tag = production/release/21.188.0-0-g55050f8 ///////////////////////////////////////////////////////////////////////////////////////////// const Profile = { version: { major: 21, - minor: 178, + minor: 188, patch: 0, type: "Release" }, @@ -4763,7 +4763,7 @@ const Profile = { subFields: [] }, 253: { - num: 253, // Sesson end time. + num: 253, name: "timestamp", type: "dateTime", baseType: "uint32", @@ -7170,7 +7170,7 @@ const Profile = { subFields: [] }, 253: { - num: 253, // Lap end time. + num: 253, name: "timestamp", type: "dateTime", baseType: "uint32", @@ -15771,7 +15771,7 @@ const Profile = { subFields: [] }, 253: { - num: 253, // Lap end time. + num: 253, name: "timestamp", type: "dateTime", baseType: "uint32", @@ -24796,6 +24796,7 @@ types: { 4446: "hrmFit", 4472: "marqGen2Commander", 4477: "lilyAthlete", // aka the Lily 2 Active + 4525: "rallyX10", // Rally 110/210 4532: "fenix8Solar", 4533: "fenix8SolarLarge", 4534: "fenix8Small", @@ -24811,13 +24812,22 @@ types: { 4603: "venuX1", 4606: "hrm200", 4625: "vivoactive6", + 4631: "fenix8Pro", + 4633: "edge550", + 4634: "edge850", + 4643: "venu4", + 4644: "venu4s", 4647: "approachS44", 4655: "edgeMtb", 4656: "approachS50", 4666: "fenixE", + 4745: "bounce2", 4759: "instinct3Solar50mm", 4775: "tactix8Amoled", 4776: "tactix8Solar", + 4879: "d2Mach2", + 4678: "instinctCrossoverAmoled", + 4944: "d2AirX15", 10007: "sdm4", // SDM4 footpod 10014: "edgeRemote", 20533: "tacxTrainingAppWin", diff --git a/src/stream.js b/src/stream.js index 1f9fede..5f7ba6f 100644 --- a/src/stream.js +++ b/src/stream.js @@ -5,8 +5,8 @@ // Transfer (FIT) Protocol License. ///////////////////////////////////////////////////////////////////////////////////////////// // ****WARNING**** This file is auto-generated! Do NOT edit this file. -// Profile Version = 21.178.0Release -// Tag = production/release/21.178.0-0-g3bea629 +// Profile Version = 21.188.0Release +// Tag = production/release/21.188.0-0-g55050f8 ///////////////////////////////////////////////////////////////////////////////////////////// diff --git a/src/utils-hr-mesg.js b/src/utils-hr-mesg.js index 4406de6..d5effbb 100644 --- a/src/utils-hr-mesg.js +++ b/src/utils-hr-mesg.js @@ -5,8 +5,8 @@ // Transfer (FIT) Protocol License. ///////////////////////////////////////////////////////////////////////////////////////////// // ****WARNING**** This file is auto-generated! Do NOT edit this file. -// Profile Version = 21.178.0Release -// Tag = production/release/21.178.0-0-g3bea629 +// Profile Version = 21.188.0Release +// Tag = production/release/21.188.0-0-g55050f8 ///////////////////////////////////////////////////////////////////////////////////////////// diff --git a/src/utils-internal.js b/src/utils-internal.js index f348db0..81ce703 100644 --- a/src/utils-internal.js +++ b/src/utils-internal.js @@ -5,8 +5,8 @@ // Transfer (FIT) Protocol License. ///////////////////////////////////////////////////////////////////////////////////////////// // ****WARNING**** This file is auto-generated! Do NOT edit this file. -// Profile Version = 21.178.0Release -// Tag = production/release/21.178.0-0-g3bea629 +// Profile Version = 21.188.0Release +// Tag = production/release/21.188.0-0-g55050f8 ///////////////////////////////////////////////////////////////////////////////////////////// diff --git a/src/utils-memo-glob.js b/src/utils-memo-glob.js index e3876ce..27516e7 100644 --- a/src/utils-memo-glob.js +++ b/src/utils-memo-glob.js @@ -5,8 +5,8 @@ // Transfer (FIT) Protocol License. ///////////////////////////////////////////////////////////////////////////////////////////// // ****WARNING**** This file is auto-generated! Do NOT edit this file. -// Profile Version = 21.178.0Release -// Tag = production/release/21.178.0-0-g3bea629 +// Profile Version = 21.188.0Release +// Tag = production/release/21.188.0-0-g55050f8 ///////////////////////////////////////////////////////////////////////////////////////////// import Profile from "./profile.js"; diff --git a/src/utils.js b/src/utils.js index fc391f1..27df85e 100644 --- a/src/utils.js +++ b/src/utils.js @@ -5,8 +5,8 @@ // Transfer (FIT) Protocol License. ///////////////////////////////////////////////////////////////////////////////////////////// // ****WARNING**** This file is auto-generated! Do NOT edit this file. -// Profile Version = 21.178.0Release -// Tag = production/release/21.178.0-0-g3bea629 +// Profile Version = 21.188.0Release +// Tag = production/release/21.188.0-0-g55050f8 ///////////////////////////////////////////////////////////////////////////////////////////// diff --git a/test/data/test-data.js b/test/data/test-data.js index aee1031..6076925 100644 --- a/test/data/test-data.js +++ b/test/data/test-data.js @@ -101,6 +101,16 @@ const fitFileDevDataWithoutFieldDescription = [ 0x5C, 0xF2, 0x6D, 0x00, 0x36, 0xEE, 0x80, 0x78, 0x3B ]; +const fitFileShortMultibyteDevData = [ + 0x0E, 0x20, 0xB9, 0x52, 0x3F, 0x00, 0x00, 0x00, 0x2E, 0x46, 0x49, 0x54, + 0xED, 0x8A, 0x40, 0x00, 0x01, 0x00, 0xCF, 0x01, 0x03, 0x01, 0x02, 0x00, + 0x00, 0x40, 0x00, 0x01, 0x00, 0xCE, 0x05, 0x00, 0x01, 0x02, 0x01, 0x01, + 0x02, 0x02, 0x01, 0x02, 0x08, 0x07, 0x07, 0x0E, 0x02, 0x84, 0x00, 0x00, + 0x00, 0x84, 0x70, 0x6F, 0x69, 0x6E, 0x74, 0x73, 0x00, 0x00, 0x12, 0x60, + 0x00, 0x01, 0x00, 0x12, 0x01, 0xFE, 0x02, 0x84, 0x01, 0x00, 0x02, 0x00, + 0x00, 0x00, 0x00, 0x04, 0xD2, 0x97, 0x59 +]; + const fitFileMonitoring = [ 0x0E, 0x10, 0x28, 0x23, 0x37, 0x00, 0x00, 0x00, 0x2E, 0x46, 0x49, 0x54, 0x2C, 0xC6, 0x41, 0x00, 0x01, 0x00, 0x37, 0x03, 0xFD, 0x04, 0x86, 0x18, @@ -677,6 +687,7 @@ export default { fitFileChained, fitFileChainedWeirdVivoki, fitFileDevDataWithoutFieldDescription, + fitFileShortMultibyteDevData, fitFileMonitoring, fitFileAccumulatedComponents, fitFileCompressedSpeedAndDistanceWithInitialDistance, diff --git a/test/decoder.test.js b/test/decoder.test.js index 864cf33..2fdddea 100644 --- a/test/decoder.test.js +++ b/test/decoder.test.js @@ -161,6 +161,20 @@ describe("Decoder Tests", () => { }); }); + describe("Profile Version Tests", () => { + test("Profile version should be parsed and returned", () => { + const buf = fs.readFileSync("test/data/WithGearChangeData.fit"); + const stream = Stream.fromBuffer(buf); + const decode = new Decoder(stream); + const { profileVersion, errors } = decode.read(); + expect(errors.length).toBe(0); + expect(profileVersion).toEqual({ + major: 21, + minor: 173 + }); + }); + }); + describe("Skip Header Flag Tests", () => { test("File with invalid header should not fail when skipHeader: true", () => { const stream = Stream.fromByteArray(Data.fitFileShortInvalidHeader); @@ -376,6 +390,16 @@ describe("Decoder Tests", () => { expect(errors.length).toBe(0); expect(messages.activityMesgs.length).toBe(1); }); + + test("When Developer Data is a multibyte base type, it should be decoded correctly", () => { + const stream = Stream.fromByteArray(Data.fitFileShortMultibyteDevData); + const decode = new Decoder(stream); + const { messages, errors } = decode.read(); + expect(errors.length).toBe(0); + expect(messages.sessionMesgs.length).toBe(1); + + expect(messages.sessionMesgs[0].developerFields[0]).toBe(1234); + }); }); describe("Component Expansion Tests", () => { diff --git a/test/encoder.test.js b/test/encoder.test.js index ba860bf..7789696 100644 --- a/test/encoder.test.js +++ b/test/encoder.test.js @@ -171,6 +171,55 @@ describe("Encoder Tests", () => { encoder.close(); }); }); + + test("Encoder writes base types with endianness bit", () => { + const fileIdMesg = { + product: 0x1234, + } + + const encoder = new Encoder(); + encoder.onMesg(Profile.MesgNum.FILE_ID, fileIdMesg); + const uint8Array = encoder.close(); + + // Base type UINT16 with endianness is 0x84 + expect(uint8Array[22]).toBe(0x84); + }) + + test("Encoder writes developer data field base types with endianness bit", () => { + const developerDataIdMesg = { + developerDataIndex: 0, + }; + + const fieldDescriptionMesg = { + developerDataIndex: 0, + fieldDefinitionNumber: 1, + fitBaseTypeId: 0x84, + }; + + const fieldDescriptions = { + 0: { + developerDataIdMesg, + fieldDescriptionMesg, + }, + }; + + const sessionMesg = { + messageIndex: 2, + developerFields: { + 0: 0x1234 + }, + }; + + const encoder = new Encoder({ fieldDescriptions }); + + encoder.onMesg(Profile.MesgNum.DEVELOPER_DATA_ID, developerDataIdMesg); + encoder.onMesg(Profile.MesgNum.FIELD_DESCRIPTION, fieldDescriptionMesg); + encoder.onMesg(Profile.MesgNum.SESSION, sessionMesg); + const uint8Array = encoder.close(); + + // Dev data FIT Base type UINT16 with endianness is 0x84 + expect(uint8Array[43]).toBe(0x84); + }); }); describe("Encoder-Decoder Integration Tests", () => { @@ -306,5 +355,49 @@ describe("Encoder-Decoder Integration Tests", () => { throw error; } }); + + test("Encoder should correctly encode and decode fields and developer fields with mulitbyte base types", () => { + const developerDataIdMesg = { + developerDataIndex: 0, + }; + + const fieldDescriptionMesg = { + developerDataIndex: 0, + fieldDefinitionNumber: 1, + fitBaseTypeId: 0x84, + }; + + const fileIdMesg = { + product: 0x5555, + developerFields: { + 0: 0x1234 + }, + }; + + const fieldDescriptions = { + 0: { + developerDataIdMesg, + fieldDescriptionMesg, + }, + }; + + const encoder = new Encoder({ fieldDescriptions }); + + encoder.onMesg(Profile.MesgNum.DEVELOPER_DATA_ID, developerDataIdMesg); + encoder.onMesg(Profile.MesgNum.FIELD_DESCRIPTION, fieldDescriptionMesg); + encoder.onMesg(Profile.MesgNum.FILE_ID, fileIdMesg); + + const stream = Stream.fromByteArray(encoder.close()); + const decoder = new Decoder(stream); + + const { messages, errors, } = decoder.read(DECODER_OPTIONS); + + expect(errors.length).toBe(0); + expect(messages.fileIdMesgs.length).toBe(1); + + const decodedFileIdMesg = messages.fileIdMesgs[0]; + expect(decodedFileIdMesg.product).toBe(fileIdMesg.product); + expect(decodedFileIdMesg.developerFields[0]).toBe(fileIdMesg.developerFields[0]); + }); });