### Complete Encoding Workflow Example Source: https://github.com/garmin/fit-javascript-sdk/blob/main/_autodocs/MANIFEST.txt A comprehensive example demonstrating the entire process of encoding a FIT file, from initializing the Encoder to closing it and obtaining the final FIT data. ```javascript import { Encoder, FileIdMesg, RecordMesg, SessionMesg } from "@garmin/fit-sdk"; async function fullEncodingWorkflow() { const encoder = new Encoder(); // Add FileIdMesg, RecordMesg, SessionMesg, etc. encoder.onMesg(new FileIdMesg()); encoder.onMesg(new RecordMesg()); encoder.onMesg(new SessionMesg()); const fitFile = await encoder.close(); console.log('Full workflow encoded FIT:', fitFile); } ``` -------------------------------- ### RecordMesg Example Source: https://github.com/garmin/fit-javascript-sdk/blob/main/_autodocs/08-message-types.md Example of creating a RecordMesg with various training data points. Ensure correct units and scaling are applied as per the FIT profile. ```javascript encoder.onMesg(Profile.MesgNum.RECORD, { timestamp: Utils.convertDateToDateTime(new Date()), position_lat: Math.round(51.5074 * Math.PI / 180 * 2147483648), position_long: Math.round(-0.1278 * Math.PI / 180 * 2147483648), altitude: 1600, heart_rate: 140, cadence: 90, distance: 1000, speed: 25, power: 250, temperature: 20 }); ``` -------------------------------- ### Encode Session Message Example Source: https://github.com/garmin/fit-javascript-sdk/blob/main/_autodocs/08-message-types.md Example of encoding a 'start' session message. Key fields include 'event', 'eventType', 'startTime', 'totalElapsedTime', 'totalDistance', 'numLaps', 'totalCalories', 'avgHeartRate', and 'maxHeartRate'. ```javascript encoder.onMesg(Profile.MesgNum.SESSION, { event: 'session', eventType: 'start', startTime: Utils.convertDateToDateTime(new Date()), totalElapsedTime: 3600, totalDistance: 10000, numLaps: 1, totalCalories: 400, avgHeartRate: 130, maxHeartRate: 165 }); ``` -------------------------------- ### Install Garmin FIT JavaScript SDK Source: https://github.com/garmin/fit-javascript-sdk/blob/main/_autodocs/00-index.md Install the SDK using npm. This command is used to add the package to your project's dependencies. ```bash npm install @garmin/fitsdk ``` -------------------------------- ### Encode Activity Message Example Source: https://github.com/garmin/fit-javascript-sdk/blob/main/_autodocs/08-message-types.md Example of encoding an 'activity' start message. Requires 'timestamp', 'numSessions', 'type', 'event', and 'eventType'. ```javascript encoder.onMesg(Profile.MesgNum.ACTIVITY, { timestamp: Utils.convertDateToDateTime(new Date()), numSessions: 1, type: 'manual', event: 'activity', eventType: 'start' }); ``` -------------------------------- ### Basic FIT file decoding example Source: https://github.com/garmin/fit-javascript-sdk/blob/main/_autodocs/MANIFEST.txt A simple example demonstrating how to decode a FIT file. This involves importing the Decoder class and calling its read() method. ```javascript import { Decoder } from "@garmin/fit-sdk"; async function decodeFitFile(file) { const decoder = new Decoder(file); const messages = await decoder.read(); console.log('Decoded FIT messages:', messages); } ``` -------------------------------- ### Encode Lap Message Example Source: https://github.com/garmin/fit-javascript-sdk/blob/main/_autodocs/08-message-types.md Example of encoding a 'start' lap message. Ensure 'event', 'eventType', 'startTime', 'totalElapsedTime', 'totalDistance', and 'messageIndex' are provided. ```javascript encoder.onMesg(Profile.MesgNum.LAP, { event: 'lap', eventType: 'start', startTime: Utils.convertDateToDateTime(new Date()), totalElapsedTime: 3600, totalDistance: 10000, messageIndex: 0 }); ``` -------------------------------- ### FileCreatorMesg Example Source: https://github.com/garmin/fit-javascript-sdk/blob/main/_autodocs/08-message-types.md Example of adding a FileCreatorMesg to an encoder, specifying software and hardware versions. ```javascript encoder.onMesg(Profile.MesgNum.FILE_CREATOR, { softwareVersion: 100, hardwareVersion: 1 }); ``` -------------------------------- ### Encode DeviceInfo Message Example Source: https://github.com/garmin/fit-javascript-sdk/blob/main/_autodocs/08-message-types.md Example of encoding device information. Key fields include 'timestamp', 'deviceIndex', 'deviceType', 'manufacturer', 'serialNumber', 'product', 'softwareVersion', and 'hardwareVersion'. ```javascript encoder.onMesg(Profile.MesgNum.DEVICE_INFO, { timestamp: Utils.convertDateToDateTime(new Date()), deviceIndex: 0, deviceType: 'watch', manufacturer: 'garmin', serialNumber: 1234567890, product: 1, softwareVersion: 100, hardwareVersion: 1 }); ``` -------------------------------- ### EventMesg Example Source: https://github.com/garmin/fit-javascript-sdk/blob/main/_autodocs/08-message-types.md Example of adding an EventMesg to an encoder to signify the start of a lap. Common event types include 'timer', 'lap', and gear changes. ```javascript encoder.onMesg(Profile.MesgNum.EVENT, { timestamp: Utils.convertDateToDateTime(new Date()), event: 'lap', eventType: 'start' }); ``` -------------------------------- ### Example: Get Field Type from Base Type Number Source: https://github.com/garmin/fit-javascript-sdk/blob/main/_autodocs/04-utils.md Demonstrates how to use the BaseTypeToFieldType mapping to find the string representation of a FIT base type number. Includes an example of iterating through all mappings. ```javascript import { Utils } from '@garmin/fitsdk'; const baseTypeNum = 132; const fieldType = Utils.BaseTypeToFieldType[baseTypeNum]; console.log(fieldType); // "uint16" // Iterate all mappings Object.entries(Utils.BaseTypeToFieldType).forEach(([baseType, fieldType]) => { console.log(`Base type ${baseType} → ${fieldType}`); }); ``` -------------------------------- ### Simple FIT file encoding example Source: https://github.com/garmin/fit-javascript-sdk/blob/main/_autodocs/MANIFEST.txt A basic example of encoding a FIT file with a single message. This is useful for creating minimal FIT files for testing or specific use cases. ```javascript import { Encoder, FileIdMesg } from "@garmin/fit-sdk"; async function encodeSimpleFitFile() { const encoder = new Encoder(); const fileIdMessage = new FileIdMesg(); fileIdMessage.set("type", 0); // Activity encoder.onMesg(fileIdMessage); const fitFile = await encoder.close(); console.log('Simple encoded FIT file:', fitFile); } ``` -------------------------------- ### Enum Example Usage Source: https://github.com/garmin/fit-javascript-sdk/blob/main/_autodocs/07-types.md Demonstrates how to access and use sport enumerations from the Profile types. ```javascript import { Profile } from '@garmin/fitsdk'; // Sport enumeration const sports = Profile.types.sport; const sportValue = 1; // Represented as number const sportName = sports[sportValue]; // "cycling" ``` -------------------------------- ### Troubleshooting Guide Source: https://github.com/garmin/fit-javascript-sdk/blob/main/_autodocs/MANIFEST.txt Offers guidance on common issues encountered when using the FIT SDK and provides steps to diagnose and resolve them. ```javascript // Common issues: // - Invalid FIT file format: Use Decoder.isFIT() and checkIntegrity(). // - Incorrect data interpretation: Verify message types and field definitions using Profile. // - Encoding errors: Ensure all required messages are present and correctly configured. ``` -------------------------------- ### Decode a FIT file with basic options Source: https://github.com/garmin/fit-javascript-sdk/blob/main/_autodocs/MANIFEST.txt Demonstrates basic decoding of a FIT file. This example shows how to instantiate the Decoder and read messages without specific options. ```javascript import { Decoder } from "@garmin/fit-sdk"; async function basicDecode(file) { const decoder = new Decoder(file); const messages = await decoder.read(); console.log('Basic decoded messages:', messages); } ``` -------------------------------- ### Types: String and Byte type examples Source: https://github.com/garmin/fit-javascript-sdk/blob/main/_autodocs/MANIFEST.txt Demonstrates the String and Byte types as defined in the FIT SDK's Types namespace. ```javascript import { Types } from "@garmin/fit-sdk"; console.log('String type:', Types.String); console.log('Byte type:', Types.Byte); ``` -------------------------------- ### Example: Get Base Type Number from Field Type String Source: https://github.com/garmin/fit-javascript-sdk/blob/main/_autodocs/04-utils.md Shows how to use the FieldTypeToBaseType mapping to retrieve the base type number for a given FIT field-type name. Also includes a bidirectional conversion example. ```javascript import { Utils } from '@garmin/fitsdk'; const fieldType = "uint16"; const baseTypeNum = Utils.FieldTypeToBaseType[fieldType]; console.log(baseTypeNum); // 132 // Bidirectional conversion const original = "sint32"; const baseType = Utils.FieldTypeToBaseType[original]; const converted = Utils.BaseTypeToFieldType[baseType]; console.log(converted); // "sint32" ``` -------------------------------- ### FileIdMesg Example Source: https://github.com/garmin/fit-javascript-sdk/blob/main/_autodocs/08-message-types.md Example of how to create and add a FileIdMesg to an encoder. Use 'timeCreated' for creatable/erasable files and 'number' for read-only files. ```javascript import { Encoder, Profile } from '@garmin/fitsdk'; const encoder = new Encoder(); encoder.onMesg(Profile.MesgNum.FILE_ID, { type: 'activity', manufacturer: 'garmin', product: 1, serialNumber: 1234567890, timeCreated: new Date(), productName: 'Edge 1050' }); ``` -------------------------------- ### Encoder with Detailed Field Descriptions Source: https://github.com/garmin/fit-javascript-sdk/blob/main/_autodocs/02-encoder.md Example demonstrating how to configure the Encoder with specific developer field metadata, including application ID and field name. ```javascript const encoder = new Encoder({ fieldDescriptions: { 0: { developerDataIdMesg: { developerDataIndex: 0, applicationId: new Uint8Array([...]) }, fieldDescriptionMesg: { developerDataIndex: 0, fieldDefinitionNumber: 0, fitBaseType: 0x83, fieldName: "Custom Field" } } } }); ``` -------------------------------- ### Include Unknown Data (Enabled) Source: https://github.com/garmin/fit-javascript-sdk/blob/main/README.md Example showing an unknown field with its ID as the key. Use when 'includeUnknownData' is true. ```javascript { 249: 1234} // Unknown field with an id of 249 ``` -------------------------------- ### Expand Components (Enabled) Source: https://github.com/garmin/fit-javascript-sdk/blob/main/README.md Example showing expanded field components. Requires 'expandSubFields' to be true. ```javascript { event: 'rearGearChange' data: 16717829, gearChangeData:16717829, // Sub Field of data when event == 'rearGearChange frontGear: 2, // Expanded field of gearChangeData, bits 0-7 frontGearNum: 53, // Expanded field of gearChangeData, bits 8-15 rearGear: 11, // Expanded field of gearChangeData, bits 16-23 rearGearNum: 1 // Expanded field of gearChangeData, bits 24-31 } ``` -------------------------------- ### Add Developer Field Example Source: https://github.com/garmin/fit-javascript-sdk/blob/main/_autodocs/02-encoder.md Example of adding a developer field to the encoder. This demonstrates how to provide the key, developer data ID message, and field description message. It also shows how to use this method with a decoder's `fieldDescriptionListener` to copy developer fields. ```javascript const encoder = new Encoder(); encoder.addDeveloperField(0, { developerDataIndex: 0, applicationId: new Uint8Array([...]) }, { developerDataIndex: 0, fieldDefinitionNumber: 0, fitBaseType: 0x83, fieldName: "Custom Field" } ); // Can be used to copy developer fields from decoder to encoder const { messages, errors } = decoder.read({ fieldDescriptionListener: (key, devDataId, fieldDesc) => { encoder.addDeveloperField(key, devDataId, fieldDesc); } }); ``` -------------------------------- ### Construct a FIT Activity File with Message Processing Flow Source: https://github.com/garmin/fit-javascript-sdk/blob/main/_autodocs/08-message-types.md This example shows how to use the Encoder to build a FIT file by sequentially adding various message types, following the recommended processing order for an activity file. It includes essential messages like FileId, DeviceInfo, Record, Lap, and Session. ```javascript import { Encoder, Profile, Utils } from '@garmin/fitsdk'; const encoder = new Encoder(); // 1. File ID (required, first) encoder.onMesg(Profile.MesgNum.FILE_ID, { type: 'activity', manufacturer: 'garmin', product: 1, timeCreated: new Date() }); // 2. File Creator encoder.onMesg(Profile.MesgNum.FILE_CREATOR, { softwareVersion: 100 }); // 3. Device Info encoder.onMesg(Profile.MesgNum.DEVICE_INFO, { timestamp: Utils.convertDateToDateTime(new Date()), deviceIndex: 0, manufacturer: 'garmin', product: 1 }); // 4-5. Record data for (let i = 0; i < 100; i++) { encoder.onMesg(Profile.MesgNum.RECORD, { timestamp: Utils.convertDateToDateTime(new Date(Date.now() + i * 1000)), heart_rate: 130 + Math.random() * 30, cadence: 90, distance: i * 100 }); } // 6. Lap encoder.onMesg(Profile.MesgNum.LAP, { event: 'lap', eventType: 'start', startTime: Utils.convertDateToDateTime(new Date()), totalDistance: 10000 }); // 7. Session encoder.onMesg(Profile.MesgNum.SESSION, { event: 'session', eventType: 'start', startTime: Utils.convertDateToDateTime(new Date()), totalDistance: 10000, totalElapsedTime: 3600 }); // 8. Activity (optional, for multi-session files) encoder.onMesg(Profile.MesgNum.ACTIVITY, { timestamp: Utils.convertDateToDateTime(new Date()), numSessions: 1, type: 'manual' }); const uint8Array = encoder.close(); ``` -------------------------------- ### Close Encoder Example Source: https://github.com/garmin/fit-javascript-sdk/blob/main/_autodocs/02-encoder.md Example of finalizing the FIT file using the `close()` method and writing the resulting bytes to a file. It includes importing necessary modules and writing messages before closing. ```javascript import { Encoder, Profile } from '@garmin/fitsdk'; import * as fs from 'fs'; const encoder = new Encoder(); // Write messages encoder.onMesg(Profile.MesgNum.FILE_ID, { manufacturer: "development", product: 1, timeCreated: new Date(), type: "activity" }); // Finalize and get bytes const uint8Array = encoder.close(); // Write to file fs.writeFileSync('activity.fit', uint8Array); // Or send over network await fetch('/api/upload', { method: 'POST', body: uint8Array, headers: { 'Content-Type': 'application/octet-stream' } }); ``` -------------------------------- ### Encode DeveloperDataId Message Example Source: https://github.com/garmin/fit-javascript-sdk/blob/main/_autodocs/08-message-types.md Example of encoding a developer data ID. Requires 'developerDataIndex' and a 4-byte 'applicationId'. ```javascript const appId = new Uint8Array(4); // 4-byte application identifier appId[0] = 0x01; // Example ID encoder.onMesg(Profile.MesgNum.DEVELOPER_DATA_ID, { developerDataIndex: 0, applicationId: appId }); ``` -------------------------------- ### Expand SubFields (Enabled) Source: https://github.com/garmin/fit-javascript-sdk/blob/main/README.md Example showing expanded subfields. Use when 'expandSubFields' is true. ```javascript { event: 'rearGearChange', data: 16717829, gearChangeData:16717829 // Sub Field of data when event == 'rearGearChange' } ``` -------------------------------- ### Expand Components (Disabled) Source: https://github.com/garmin/fit-javascript-sdk/blob/main/README.md Example showing unexpanded field components. Use when 'expandComponents' is false. ```javascript { event: 'rearGearChange', data: 16717829, gearChangeData: 16717829 // Sub Field of data when event == 'rearGearChange' } ``` -------------------------------- ### Encode FieldDescription Message Example Source: https://github.com/garmin/fit-javascript-sdk/blob/main/_autodocs/08-message-types.md Example of encoding a field description for a custom field. Requires 'developerDataIndex', 'fieldDefinitionNumber', 'fitBaseType', 'fieldName', and optionally 'array', 'scale', 'offset', and 'units'. ```javascript encoder.onMesg(Profile.MesgNum.FIELD_DESCRIPTION, { developerDataIndex: 0, fieldDefinitionNumber: 0, fitBaseType: 0x83, // UINT32 fieldName: 'Custom Field', array: false, scale: 1, offset: 0, units: 'units' }); ``` -------------------------------- ### Browser Usage Notes Source: https://github.com/garmin/fit-javascript-sdk/blob/main/_autodocs/MANIFEST.txt Specific considerations and examples for using the FIT SDK within a web browser environment, including file handling and potential limitations. ```javascript // Use the File API to get file objects. // FileReader can be used to read file content into ArrayBuffer. // Example: // const fileInput = document.getElementById('fileInput'); // fileInput.addEventListener('change', async (event) => { // const file = event.target.files[0]; // const arrayBuffer = await file.arrayBuffer(); // const decoder = new Decoder(arrayBuffer); // // ... process messages // }); ``` -------------------------------- ### Encode a complete FIT activity Source: https://github.com/garmin/fit-javascript-sdk/blob/main/_autodocs/MANIFEST.txt This example shows how to encode a complete FIT activity, including multiple messages like FileIdMesg, RecordMesg, and SessionMesg. It covers a common scenario for activity data logging. ```javascript import { Encoder, FileIdMesg, RecordMesg, SessionMesg } from "@garmin/fit-sdk"; async function encodeFullActivity() { const encoder = new Encoder(); // File ID message const fileId = new FileIdMesg(); fileId.set("type", 0); // Activity encoder.onMesg(fileId); // Record messages const record1 = new RecordMesg(); record1.set("timestamp", 1678886400); record1.set("distance", 100); encoder.onMesg(record1); const record2 = new RecordMesg(); record2.set("timestamp", 1678886460); record2.set("distance", 200); encoder.onMesg(record2); // Session message const session = new SessionMesg(); session.set("timestamp", 1678886460); session.set("total_distance", 200); encoder.onMesg(session); const fitFile = await encoder.close(); console.log('Full activity FIT file encoded:', fitFile); } ``` -------------------------------- ### Sint64 Example Usage Source: https://github.com/garmin/fit-javascript-sdk/blob/main/_autodocs/07-types.md Shows the representation of the maximum signed 64-bit integer using bigint. ```javascript const value = 9223372036854775807n; // Max sint64 ``` -------------------------------- ### Encode a complete activity Source: https://github.com/garmin/fit-javascript-sdk/blob/main/_autodocs/MANIFEST.txt Example of encoding a complete FIT activity, including FileIdMesg, RecordMesgs, and a SessionMesg. This demonstrates a typical workflow for creating a FIT file representing an activity. ```javascript import { Encoder, FileIdMesg, RecordMesg, SessionMesg } from "@garmin/fit-sdk"; async function encodeCompleteActivity() { const encoder = new Encoder(); // File ID message (required first) const fileId = new FileIdMesg(); fileId.set("type", 0); // Activity fileId.set("manufacturer", 1); fileId.set("product", 1); fileId.set("serial_number", 12345); encoder.onMesg(fileId); // Record messages (multiple) const record1 = new RecordMesg(); record1.set("timestamp", 1678886400); record1.set("position_lat", 40.7128 * 116400000); record1.set("position_long", -74.0060 * 116400000); encoder.onMesg(record1); const record2 = new RecordMesg(); record2.set("timestamp", 1678886460); record2.set("position_lat", 40.7130 * 116400000); record2.set("position_long", -74.0062 * 116400000); encoder.onMesg(record2); // Session message (summary) const session = new SessionMesg(); session.set("timestamp", 1678886460); session.set("event", 1); // Stop session.set("event_type", 0); // Activity session.set("total_elapsed_time", 60); session.set("total_distance", 200); encoder.onMesg(session); const fitFile = await encoder.close(); console.log('Encoded complete activity FIT file:', fitFile); } ``` -------------------------------- ### Convert Types to Strings (Enabled) Source: https://github.com/garmin/fit-javascript-sdk/blob/main/README.md Example showing a 'type' field converted to a string. Use when 'convertTypesToStrings' is true. ```javascript { type:'activity'} ``` -------------------------------- ### Browser Usage: Fetching FIT from URL Source: https://github.com/garmin/fit-javascript-sdk/blob/main/_autodocs/09-quick-start.md Shows how to fetch a FIT file from a URL in a browser environment. It uses the `fetch` API to get the file as an `ArrayBuffer`, which is then used to create a FIT SDK stream. ```javascript // Fetching from URL const response = await fetch('/activity.fit'); const arrayBuffer = await response.arrayBuffer(); const stream = Stream.fromArrayBuffer(arrayBuffer); ``` -------------------------------- ### Apply Scale and Offset (Enabled) Source: https://github.com/garmin/fit-javascript-sdk/blob/main/README.md Example showing a decoded 'altitude' field with scale and offset applied. Use when 'applyScaleAndOffset' is true. ```javascript { altitude: 1587 // with a scale of 5 and offset of 500 applied } ``` -------------------------------- ### Types: Floating-point type examples Source: https://github.com/garmin/fit-javascript-sdk/blob/main/_autodocs/MANIFEST.txt Shows the definition and usage of Float32 and Float64 types within the FIT SDK's Types namespace. ```javascript import { Types } from "@garmin/fit-sdk"; console.log('Float32 type:', Types.Float32); console.log('Float64 type:', Types.Float64); ``` -------------------------------- ### Convert Types to Strings (Disabled) Source: https://github.com/garmin/fit-javascript-sdk/blob/main/README.md Example showing a 'type' field as a raw integer. Use when 'convertTypesToStrings' is false. ```javascript { type: 4 } ``` -------------------------------- ### Apply Scale and Offset (Disabled) Source: https://github.com/garmin/fit-javascript-sdk/blob/main/README.md Example showing a decoded 'altitude' field with raw value. Use when 'applyScaleAndOffset' is false. ```javascript { altitude: 10435 // raw value store in file } ``` -------------------------------- ### Browser Usage: Reading FIT from File Input Source: https://github.com/garmin/fit-javascript-sdk/blob/main/_autodocs/09-quick-start.md Demonstrates how to read a FIT file selected by the user in a web browser. It uses the `File` API to get an `ArrayBuffer` and then the FIT SDK's `Stream.fromArrayBuffer` to process it. ```javascript // Reading from a file input document.getElementById('fitFile').addEventListener('change', async (e) => { const file = e.target.files[0]; const arrayBuffer = await file.arrayBuffer(); const { Decoder, Stream } = await import('@garmin/fitsdk'); const stream = Stream.fromArrayBuffer(arrayBuffer); const decoder = new Decoder(stream); const { messages } = decoder.read(); console.log(messages); }); ``` -------------------------------- ### Types: Numeric type examples Source: https://github.com/garmin/fit-javascript-sdk/blob/main/_autodocs/MANIFEST.txt Illustrates the usage of various numeric FIT types, including Enum, Sint8-64, and Uint8-64, as defined in the Types namespace. ```javascript import { Types } from "@garmin/fit-sdk"; console.log('Enum type:', Types.Enum); console.log('Sint8 type:', Types.Sint8); console.log('Uint64 type:', Types.Uint64); ``` -------------------------------- ### Large File Processing with `mesgListener` Source: https://github.com/garmin/fit-javascript-sdk/blob/main/_autodocs/09-quick-start.md Processes large FIT files efficiently by using the `mesgListener` to handle messages on-the-fly, avoiding the need to store all messages in memory. This example calculates record count, total distance, and average heart rate. ```javascript let recordCount = 0; let totalDistance = 0; let avgHeartRate = 0; let hrCount = 0; const { errors } = decoder.read({ mesgListener: (mesgNum, message) => { if (mesgNum === Profile.MesgNum.RECORD) { recordCount++; if (message.distance) totalDistance = message.distance; if (message.heart_rate) { avgHeartRate += message.heart_rate; hrCount++; } } }, // Only decode needed data expandSubFields: false, expandComponents: false, convertTypesToStrings: true }); console.log(`Records: ${recordCount}`); console.log(`Distance: ${totalDistance}m`); console.log(`Avg HR: ${Math.floor(avgHeartRate / hrCount)}bpm`); ``` -------------------------------- ### Initialize and Use FIT Encoder Source: https://github.com/garmin/fit-javascript-sdk/blob/main/README.md Demonstrates how to import the SDK, create an Encoder instance, and write messages using onMesg() or writeMesg(). ```javascript // Import the SDK import { Encoder, Profile} from "@garmin/fitsdk"; // Create an Encoder const encoder = new Encoder(); // // Write messages to the output-stream // // The message data should match the format returned by // the Decoder. Field names should be camelCase. The fields // definitions can be found in the Profile. // // Pass the MesgNum and message data as separate parameters to the onMesg() method encoder.onMesg(Profile.MesgNum.FILE_ID, { manufacturer: "development", product: 1, timeCreated: new Date(), type: "activity", }); // The writeMesg() method expects the mesgNum to be included in the message data // Internally, writeMesg() calls onMesg() encoder.writeMesg({ mesgNum: Profile.MesgNum.FILE_ID, manufacturer: "development", product: 1, timeCreated: new Date(), type: "activity", }); // Unknown values in the message will be ignored by the Encoder encoder.onMesg(Profile.MesgNum.FILE_ID, { manufacturer: "development", product: 1, timeCreated: new Date(), type: "activity", customField: 12345, // This value will be ignored by the Encoder }); // Subfield values in the message will be ignored by the Encoder encoder.onMesg(Profile.MesgNum.FILE_ID, { manufacturer: "development", product: 4440, // This is the main product field, which is a uint16 garminProduct: "edge1050", // This value will be ignored by the Encoder, use the main field value instead timeCreated: new Date(), type: "activity", }); // Closing the encoder returns the file as an UInt8 Array const uint8Array = encoder.close(); // Write the file to disk, import * as fs from "fs"; fs.writeFileSync("example.fit", uint8Array); ``` -------------------------------- ### Extract Activity Summary Source: https://github.com/garmin/fit-javascript-sdk/blob/main/_autodocs/00-index.md Extracts and logs key summary statistics from a decoded FIT file's session messages. Useful for quickly getting overall activity metrics. ```javascript const { messages } = decoder.read(); const session = messages.sessionMesgs[0]; console.log({ distance: session.totalDistance, duration: session.totalElapsedTime, avgHeartRate: session.avgHeartRate, maxHeartRate: session.maxHeartRate, avgPower: session.avgPower, maxPower: session.maxPower }); ``` -------------------------------- ### Encode Developer Fields from Message Property Source: https://github.com/garmin/fit-javascript-sdk/blob/main/_autodocs/02-encoder.md Shows how developer fields are encoded from the `developerFields` property on messages. The example uses the `RECORD` message type and specifies a custom value for developer field key '0'. ```javascript encoder.onMesg(Profile.MesgNum.RECORD, { timestamp: new Date(), position_lat: 51.5074, position_long: -0.1278, developerFields: { "0": "custom value" // Developer field key "0" } }); ``` -------------------------------- ### Create a buffer slice from a stream Source: https://github.com/garmin/fit-javascript-sdk/blob/main/_autodocs/03-stream.md Use `slice` to get a copy of a portion of the underlying buffer without changing the stream's current read position. Specify the start (inclusive) and end (exclusive) indices. ```javascript const stream = Stream.fromByteArray([0x0E, 0x10, 0xD9, 0x07, 0x00, 0x00, 0x00, 0x00]); const headerBuffer = stream.slice(0, 8); console.log(new Uint8Array(headerBuffer)); // Uint8Array(8) [14, 16, 217, 7, 0, 0, 0, 0] ``` -------------------------------- ### Create and Encode a Simple Activity FIT File Source: https://github.com/garmin/fit-javascript-sdk/blob/main/_autodocs/09-quick-start.md Generate a FIT file representing a simple activity, including File ID, Device Info, Record data, Lap, Session, and Activity messages. Requires importing Encoder, Profile, and Utils. ```javascript import { Encoder, Profile, Utils } from '@garmin/fitsdk'; import * as fs from 'fs'; const encoder = new Encoder(); // File ID (required, must be first) encoder.onMesg(Profile.MesgNum.FILE_ID, { type: 'activity', manufacturer: 'garmin', product: 1, timeCreated: new Date(), serialNumber: 1234567890 }); // File Creator encoder.onMesg(Profile.MesgNum.FILE_CREATOR, { softwareVersion: 100, hardwareVersion: 1 }); // Device Info encoder.onMesg(Profile.MesgNum.DEVICE_INFO, { timestamp: Utils.convertDateToDateTime(new Date()), deviceIndex: 0, deviceType: 'watch', manufacturer: 'garmin', product: 1, serialNumber: 1234567890 }); // Record data (one for each timestamp) const startTime = new Date(); for (let i = 0; i < 60; i++) { const timestamp = new Date(startTime.getTime() + i * 1000); encoder.onMesg(Profile.MesgNum.RECORD, { timestamp: Utils.convertDateToDateTime(timestamp), heart_rate: 130 + Math.floor(Math.random() * 30), cadence: 90 + Math.floor(Math.random() * 5), distance: i * 100, speed: 25 + Math.random() * 5, power: 250 + Math.floor(Math.random() * 50), altitude: 100 + i }); } // Lap summary encoder.onMesg(Profile.MesgNum.LAP, { event: 'lap', eventType: 'start', startTime: Utils.convertDateToDateTime(startTime), totalElapsedTime: 60000, // ms totalDistance: 6000 }); // Session summary encoder.onMesg(Profile.MesgNum.SESSION, { event: 'session', eventType: 'start', startTime: Utils.convertDateToDateTime(startTime), totalElapsedTime: 60000, totalDistance: 6000, totalAscent: 50, totalCalories: 100, avgHeartRate: 145, maxHeartRate: 165, avgSpeed: 25, maxSpeed: 30, avgPower: 250, maxPower: 300, numLaps: 1 }); // Activity encoder.onMesg(Profile.MesgNum.ACTIVITY, { timestamp: Utils.convertDateToDateTime(new Date()), numSessions: 1, type: 'manual', event: 'activity', eventType: 'start' }); // Write to file const uint8Array = encoder.close(); fs.writeFileSync('output.fit', uint8Array); ``` -------------------------------- ### Performance Optimization Tips Source: https://github.com/garmin/fit-javascript-sdk/blob/main/_autodocs/MANIFEST.txt Provides advice on optimizing the performance of FIT file processing, such as efficient decoding options or minimizing object creation. ```javascript // - Use decoder options like skipCrcCheck when appropriate. // - Process messages in batches if possible. // - Avoid unnecessary object instantiations within loops. ``` -------------------------------- ### Typical Workflow Source: https://github.com/garmin/fit-javascript-sdk/blob/main/_autodocs/02-encoder.md A common workflow demonstrating how to decode an existing FIT file, copy its structure and developer fields, and then re-encode it with modifications. ```APIDOC ## Typical Workflow ```javascript import { Encoder, Decoder, Stream, Profile } from '@garmin/fitsdk'; import * as fs from 'fs'; // Decode an existing file to copy its structure and developer fields const inputBuffer = fs.readFileSync('input.fit'); const inputStream = Stream.fromBuffer(inputBuffer); const decoder = new Decoder(inputStream); const encoder = new Encoder(); // Copy developer field descriptions from input to encoder const { messages } = decoder.read({ fieldDescriptionListener: (key, devDataId, fieldDesc) => { encoder.addDeveloperField(key, devDataId, fieldDesc); }, mesgListener: (mesgNum, mesg) => { // Re-encode messages with modifications mesg.timestamp = new Date(); encoder.onMesg(mesgNum, mesg); } }); // Finalize and write const outputBytes = encoder.close(); fs.writeFileSync('output.fit', outputBytes); ``` ``` -------------------------------- ### Expand SubFields (Disabled) Source: https://github.com/garmin/fit-javascript-sdk/blob/main/README.md Example showing omitted subfields. Use when 'expandSubFields' is false. ```javascript { event: 'rearGearChange', data: 16717829 } ``` -------------------------------- ### Handle date and time conversions in FIT Source: https://github.com/garmin/fit-javascript-sdk/blob/main/_autodocs/MANIFEST.txt Demonstrates converting between JavaScript Date objects and FIT's epoch milliseconds using the Utils namespace. This is essential for accurate time representation. ```javascript import { Utils } from "@garmin/fit-sdk"; const jsDate = new Date(); const fitTimestamp = Utils.convertDateToDateTime(jsDate); console.log('FIT Timestamp:', fitTimestamp); const convertedJsDate = Utils.convertDateTimeToDate(fitTimestamp); console.log('Converted JS Date:', convertedJsDate); ``` -------------------------------- ### Create a Basic Encoder Source: https://github.com/garmin/fit-javascript-sdk/blob/main/_autodocs/02-encoder.md Instantiate the Encoder class without any options to create a basic FIT file encoder. ```javascript import { Encoder, Profile } from '@garmin/fitsdk'; // Create a basic encoder const encoder = new Encoder(); ``` -------------------------------- ### Import SDK Modules Source: https://github.com/garmin/fit-javascript-sdk/blob/main/_autodocs/00-index.md Import necessary classes from the Garmin FIT SDK. This is typically the first step in using the SDK. ```javascript const { Decoder, Encoder, Stream, Profile } = await import('@garmin/fitsdk'); ``` -------------------------------- ### Convert DateTimes to Dates (Disabled) Source: https://github.com/garmin/fit-javascript-sdk/blob/main/README.md Example showing 'timeCreated' as a FIT Epoch value. Use when 'convertDateTimesToDates' is false. ```javascript { timeCreated: 995749880 } ``` -------------------------------- ### Convert DateTimes to Dates (Enabled) Source: https://github.com/garmin/fit-javascript-sdk/blob/main/README.md Example showing 'timeCreated' as a JavaScript Date object. Use when 'convertDateTimesToDates' is true. ```javascript { timeCreated: {JavaScript Date object} } ``` -------------------------------- ### Typical FIT File Decoding Workflow Source: https://github.com/garmin/fit-javascript-sdk/blob/main/_autodocs/03-stream.md Illustrates a common workflow for reading and decoding a FIT file. It includes reading the file into a buffer, creating a stream, checking file integrity, and decoding messages. ```javascript import { Decoder, Stream } from '@garmin/fitsdk'; import * as fs from 'fs'; // Read file and create stream const buffer = fs.readFileSync('activity.fit'); const stream = Stream.fromBuffer(buffer); // Check if it's a valid FIT file if (Decoder.isFIT(stream)) { // Reset to beginning for decoding stream.reset(); const decoder = new Decoder(stream); if (decoder.checkIntegrity()) { const { messages, errors } = decoder.read(); console.log(messages); } } ``` -------------------------------- ### Handle date and time conversions Source: https://github.com/garmin/fit-javascript-sdk/blob/main/_autodocs/MANIFEST.txt Demonstrates converting between FIT's epoch milliseconds and JavaScript Date objects using the Utils namespace. This is crucial for accurate time-series data handling. ```javascript import { Utils } from "@garmin/fit-sdk"; const now = new Date(); const fitEpochMs = Utils.convertDateToDateTime(now); console.log('FIT Epoch Ms:', fitEpochMs); const jsDate = Utils.convertDateTimeToDate(fitEpochMs); console.log('JavaScript Date:', jsDate); ``` -------------------------------- ### Create Decoder Instance Source: https://github.com/garmin/fit-javascript-sdk/blob/main/_autodocs/01-decoder.md Instantiate the Decoder class with a Stream object containing FIT file data. Ensure the stream is not null or undefined. ```javascript import { Decoder, Stream } from '@garmin/fitsdk'; const bytes = Buffer.from([0x0E, 0x10, 0xD9, 0x07, ...]); const stream = Stream.fromBuffer(bytes); const decoder = new Decoder(stream); ``` -------------------------------- ### Date/Time Handling Source: https://github.com/garmin/fit-javascript-sdk/blob/main/_autodocs/04-utils.md Demonstrates how to automatically convert FIT date-time values to JavaScript Date objects during decoding, and how to manually convert between FIT epoch and JavaScript Date objects. ```APIDOC ## Date/Time Handling ### Automatic Conversion during Decoding When decoding FIT messages, you can enable automatic conversion of date-time values to JavaScript `Date` objects. ```javascript import { Decoder, Stream, Utils } from '@garmin/fitsdk'; const stream = Stream.fromBuffer(buffer); const decoder = new Decoder(stream); const { messages } = decoder.read({ convertDateTimesToDates: true // Dates are automatically converted }); // Access converted Date objects directly messages.recordMesgs.forEach(record => { console.log(record.timestamp); // Already a Date object }); ``` ### Manual Date Conversion If automatic conversion is not used, you can manually convert FIT epoch values to JavaScript `Date` objects and vice versa. ```javascript import { Utils } from '@garmin/fitsdk'; // Convert FIT epoch to JavaScript Date const fitValue = 995749880; const jsDate = Utils.convertDateTimeToDate(fitValue); console.log(jsDate.toLocaleString()); // Convert JavaScript Date back to FIT epoch const now = new Date(); const fitEpoch = Utils.convertDateToDateTime(now); console.log(fitEpoch); ``` ``` -------------------------------- ### Message Types: EventMesg Source: https://github.com/garmin/fit-javascript-sdk/blob/main/_autodocs/MANIFEST.txt Describes the EventMesg, used to record discrete events during an activity, such as start, stop, lap, or marker. ```javascript import { EventMesg } from "@garmin/fit-sdk"; const event = new EventMesg(); event.set("timestamp", 1678886460); event.set("event", 0); // Start event.set("event_type", 0); // Activity Start console.log('EventMesg:', event); ``` -------------------------------- ### Create a Complete Activity FIT File Source: https://github.com/garmin/fit-javascript-sdk/blob/main/_autodocs/00-index.md Constructs a new FIT file from activity data, including required metadata, device info, records, and summary messages. This is used for generating new FIT files programmatically. ```javascript const encoder = new Encoder(); // File metadata (required) encoder.onMesg(Profile.MesgNum.FILE_ID, { ... }); encoder.onMesg(Profile.MesgNum.FILE_CREATOR, { ... }); // Device info encoder.onMesg(Profile.MesgNum.DEVICE_INFO, { ... }); // Activity records for (const record of activityData) { encoder.onMesg(Profile.MesgNum.RECORD, record); } // Summaries encoder.onMesg(Profile.MesgNum.LAP, { ... }); encoder.onMesg(Profile.MesgNum.SESSION, { ... }); encoder.onMesg(Profile.MesgNum.ACTIVITY, { ... }); const fitFile = encoder.close(); ``` -------------------------------- ### Get Current CRC Value Source: https://github.com/garmin/fit-javascript-sdk/blob/main/_autodocs/05-crc-calculator.md Access the current running CRC value after processing bytes. This property reflects the accumulated CRC. ```javascript import { CrcCalculator } from '@garmin/fitsdk'; const calculator = new CrcCalculator(); const bytes = new Uint8Array([0x0E, 0x10, 0xD9, 0x07]); calculator.addBytes(bytes, 0, 4); console.log(calculator.crc); // Updated CRC value ``` -------------------------------- ### Types: Bool type example Source: https://github.com/garmin/fit-javascript-sdk/blob/main/_autodocs/MANIFEST.txt Illustrates the Bool type, which is represented as 0 or 1, as defined in the FIT SDK's Types namespace. ```javascript import { Types } from "@garmin/fit-sdk"; console.log('Bool type:', Types.Bool); ``` -------------------------------- ### Create Encoder with Developer Field Descriptions Source: https://github.com/garmin/fit-javascript-sdk/blob/main/_autodocs/02-encoder.md Initialize the Encoder with custom developer field descriptions using the fieldDescriptions option. This is equivalent to calling addDeveloperField() for each entry. ```javascript import { Encoder, Profile } from '@garmin/fitsdk'; // Or create with developer field descriptions const encoder = new Encoder({ fieldDescriptions: { 0: { developerDataIdMesg: { developerDataIndex: 0, applicationId: [...] }, fieldDescriptionMesg: { developerDataIndex: 0, fieldDefinitionNumber: 0, ... } } } }); ``` -------------------------------- ### Typical Workflow: Decode and Re-encode FIT File Source: https://github.com/garmin/fit-javascript-sdk/blob/main/_autodocs/02-encoder.md Illustrates a typical workflow involving decoding an existing FIT file to extract its structure and developer fields, then re-encoding messages with modifications using a new encoder. The process includes copying developer field descriptions and re-encoding messages before finalizing and writing the output file. ```javascript import { Encoder, Decoder, Stream, Profile } from '@garmin/fitsdk'; import * as fs from 'fs'; // Decode an existing file to copy its structure and developer fields const inputBuffer = fs.readFileSync('input.fit'); const inputStream = Stream.fromBuffer(inputBuffer); const decoder = new Decoder(inputStream); const encoder = new Encoder(); // Copy developer field descriptions from input to encoder const { messages } = decoder.read({ fieldDescriptionListener: (key, devDataId, fieldDesc) => { encoder.addDeveloperField(key, devDataId, fieldDesc); }, mesgListener: (mesgNum, mesg) => { // Re-encode messages with modifications mesg.timestamp = new Date(); encoder.onMesg(mesgNum, mesg); } }); // Finalize and write const outputBytes = encoder.close(); fs.writeFileSync('output.fit', outputBytes); ``` -------------------------------- ### Access Message Name and Keys Source: https://github.com/garmin/fit-javascript-sdk/blob/main/_autodocs/06-profile.md Inspect a specific FIT message definition to get its human-readable name and the key used in decoded message dictionaries. ```typescript interface ProfileMesg { num: number; name: string; messagesKey: string; fields: Record; } ``` ```javascript import { Profile } from '@garmin/fitsdk'; const fileIdMsg = Profile.messages[0]; console.log(fileIdMsg.name); // "file_id" console.log(fileIdMsg.messagesKey); // "fileIdMesgs" console.log(Object.keys(fileIdMsg.fields)); // ['0', '1', '2', ...] ``` -------------------------------- ### FIT Stream Operations Source: https://github.com/garmin/fit-javascript-sdk/blob/main/_autodocs/09-quick-start.md Demonstrates various ways to create and manipulate FIT data streams. Supports creation from byte arrays, buffers, and ArrayBuffers, along with methods for reading data and managing stream position. ```javascript import { Stream } from '@garmin/fitsdk'; // From various sources const fromByteArray = Stream.fromByteArray([0x0E, 0x10, 0xD9, ...]); const fromBuffer = Stream.fromBuffer(buffer); const fromArrayBuffer = Stream.fromArrayBuffer(arrayBuffer); // Reading values const value = stream.readUInt16(); const bytes = stream.readBytes(4); // Position management const position = stream.position; stream.seek(0); stream.reset(); // Peek without advancing const nextByte = stream.peekByte(); ``` -------------------------------- ### Access Common Field Numbers Source: https://github.com/garmin/fit-javascript-sdk/blob/main/_autodocs/06-profile.md Get the field numbers for common fields that appear across multiple FIT message types, such as Timestamp and MessageIndex. ```typescript Profile.CommonFields: { readonly PartIndex: number; readonly Timestamp: number; readonly MessageIndex: number; } ``` ```javascript import { Profile } from '@garmin/fitsdk'; console.log(Profile.CommonFields.Timestamp); // 253 ``` -------------------------------- ### FIT Type Mappings and Conversions Source: https://github.com/garmin/fit-javascript-sdk/blob/main/_autodocs/09-quick-start.md Utilizes `Profile.types` and `Utils` to map numeric FIT values to their string representations and vice versa. Also shows how to convert between FIT base types and field types. ```javascript import { Profile, Utils } from '@garmin/fitsdk'; // Map numeric values to strings function getValue(typeName, numValue) { const typeEnum = Profile.types[typeName]; return typeEnum ? typeEnum[numValue] : null; } function getValueNum(typeName, strValue) { const typeEnum = Profile.types[typeName]; for (const [num, str] of Object.entries(typeEnum)) { if (str === strValue) return parseInt(num); } return null; } // Usage console.log(getValue('manufacturer', 1)); // "garmin" console.log(getValueNum('manufacturer', 'garmin')); // 1 // Base type mappings console.log(Utils.BaseTypeToFieldType[132]); // "uint16" console.log(Utils.FieldTypeToBaseType['uint16']); // 132 ``` -------------------------------- ### Types: MesgNum type example Source: https://github.com/garmin/fit-javascript-sdk/blob/main/_autodocs/MANIFEST.txt Shows the MesgNum type, used for identifying FIT message numbers, as defined in the FIT SDK's Types namespace. ```javascript import { Types } from "@garmin/fit-sdk"; console.log('MesgNum type:', Types.MesgNum); ``` -------------------------------- ### Filter Records by Type Source: https://github.com/garmin/fit-javascript-sdk/blob/main/_autodocs/09-quick-start.md Extract specific types of records, such as cycling data, from a decoded FIT file. This example filters for records that have both cadence and power defined. ```javascript const { messages } = decoder.read(); // Get only cycling records const cyclingRecords = messages.recordMesgs.filter(r => { // Check based on cadence, power, etc. return r.cadence !== undefined && r.power !== undefined; }); ``` -------------------------------- ### Get Current Read Position in Stream Source: https://github.com/garmin/fit-javascript-sdk/blob/main/_autodocs/03-stream.md The `position` property provides the current 0-based index of the read head within the stream. It updates as data is read. ```javascript const stream = Stream.fromByteArray([0x00, 0x01, 0x02, 0x03]); console.log(stream.position); // 0 stream.readUInt16(); console.log(stream.position); // 2 ``` -------------------------------- ### Create FIT Stream from File (Node.js) Source: https://github.com/garmin/fit-javascript-sdk/blob/main/README.md Read a FIT file into a Node.js Buffer and then create a stream using Stream.fromBuffer. Requires the 'fs' module. ```javascript const buf = fs.readFileSync('activity.fit'); const streamfromFileSync = Stream.fromBuffer(buf); console.log("isFIT: " + Decoder.isFIT(streamfromFileSync)); ``` -------------------------------- ### Track Record Message Fields Source: https://github.com/garmin/fit-javascript-sdk/blob/main/README.md Example callback function to track field names across all Record messages. It adds field names to a Set for later inspection. ```javascript const recordFields = new Set(); const onMesg = (messageNumber, message) => { if (Profile.types.mesgNum[messageNumber] === "record") { Object.keys(message).forEach(field => recordFields.add(field)); } } const { messages, errors } = decoder.read({ mesgListener: onMesg }); console.log(recordFields); ``` -------------------------------- ### Stream.reset Source: https://github.com/garmin/fit-javascript-sdk/blob/main/_autodocs/03-stream.md Resets the stream's read position back to the beginning (index 0) without altering the stream's data. This allows for re-reading the stream from the start. ```APIDOC ## Stream.reset ### Description Resets the read position to 0. Does not modify stream data. ### Example ```javascript const stream = Stream.fromByteArray([0x0E, 0x10, 0xD9, 0x07]); stream.readUInt32(); // Advances position to 4 console.log(stream.position); // 4 stream.reset(); console.log(stream.position); // 0 ``` ``` -------------------------------- ### Get Stream Length Source: https://github.com/garmin/fit-javascript-sdk/blob/main/_autodocs/03-stream.md The `length` property returns the total size of the stream's underlying buffer in bytes. Access this property to know the stream's capacity. ```javascript const stream = Stream.fromByteArray([0x0E, 0x10, 0xD9, ...]); console.log(stream.length); // 3 (or more depending on input) ```