fit-file-parser
Version:
Parse your .FIT files easily, directly from JS (Garmin, Polar, Suunto)
261 lines (234 loc) • 8.53 kB
JavaScript
'use strict';
Object.defineProperty(exports, "__esModule", {
value: true
});
var _createClass = function () { function defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } return function (Constructor, protoProps, staticProps) { if (protoProps) defineProperties(Constructor.prototype, protoProps); if (staticProps) defineProperties(Constructor, staticProps); return Constructor; }; }();
var _binary = require('./binary');
var _helper = require('./helper');
function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }
var FitParser = function () {
function FitParser() {
var options = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {};
_classCallCheck(this, FitParser);
this.options = {
force: options.force != null ? options.force : true,
speedUnit: options.speedUnit || 'm/s',
lengthUnit: options.lengthUnit || 'm',
temperatureUnit: options.temperatureUnit || 'celsius',
elapsedRecordField: options.elapsedRecordField || false,
pressureUnit: options.pressureUnit || 'bar',
mode: options.mode || 'list'
};
}
_createClass(FitParser, [{
key: 'parse',
value: function parse(content, callback) {
var blob = new Uint8Array((0, _binary.getArrayBuffer)(content));
if (blob.length < 12) {
callback('File to small to be a FIT file', {});
if (!this.options.force) {
return;
}
}
var headerLength = blob[0];
if (headerLength !== 14 && headerLength !== 12) {
callback('Incorrect header size', {});
if (!this.options.force) {
return;
}
}
var fileTypeString = '';
for (var i = 8; i < 12; i++) {
fileTypeString += String.fromCharCode(blob[i]);
}
if (fileTypeString !== '.FIT') {
callback('Missing \'.FIT\' in header', {});
if (!this.options.force) {
return;
}
}
if (headerLength === 14) {
var crcHeader = blob[12] + (blob[13] << 8);
var crcHeaderCalc = (0, _binary.calculateCRC)(blob, 0, 12);
if (crcHeader !== crcHeaderCalc) {
// callback('Header CRC mismatch', {});
// TODO: fix Header CRC check
if (!this.options.force) {
return;
}
}
}
var protocolVersion = blob[1];
var profileVersion = blob[2] + (blob[3] << 8);
var dataLength = blob[4] + (blob[5] << 8) + (blob[6] << 16) + (blob[7] << 24);
var crcStart = dataLength + headerLength;
var crcFile = blob[crcStart] + (blob[crcStart + 1] << 8);
var crcFileCalc = (0, _binary.calculateCRC)(blob, headerLength === 12 ? 0 : headerLength, crcStart);
if (crcFile !== crcFileCalc) {
// callback('File CRC mismatch', {});
// TODO: fix File CRC check
if (!this.options.force) {
return;
}
}
var fitObj = {};
fitObj.protocolVersion = protocolVersion;
fitObj.profileVersion = profileVersion;
var sessions = [];
var laps = [];
var records = [];
var events = [];
var hrv = [];
var devices = [];
var applications = [];
var fieldDescriptions = [];
var dive_gases = [];
var course_points = [];
var sports = [];
var monitors = [];
var stress = [];
var definitions = [];
var file_ids = [];
var monitor_info = [];
var lengths = [];
var tank_updates = [];
var tank_summaries = [];
var loopIndex = headerLength;
var messageTypes = [];
var developerFields = [];
var isModeCascade = this.options.mode === 'cascade';
var isCascadeNeeded = isModeCascade || this.options.mode === 'both';
var startDate = void 0;
var lastStopTimestamp = void 0;
var pausedTime = 0;
while (loopIndex < crcStart) {
var _readRecord = (0, _binary.readRecord)(blob, messageTypes, developerFields, loopIndex, this.options, startDate, pausedTime),
nextIndex = _readRecord.nextIndex,
messageType = _readRecord.messageType,
message = _readRecord.message;
loopIndex = nextIndex;
switch (messageType) {
case 'lap':
laps.push(message);
break;
case 'session':
sessions.push(message);
break;
case 'event':
if (message.event === 'timer') {
if (message.event_type === 'stop_all') {
lastStopTimestamp = message.timestamp;
} else if (message.event_type === 'start' && lastStopTimestamp) {
pausedTime += (message.timestamp - lastStopTimestamp) / 1000;
}
}
events.push(message);
break;
case 'length':
lengths.push(message);
break;
case 'hrv':
hrv.push(message);
break;
case 'record':
if (!startDate) {
startDate = message.timestamp;
message.elapsed_time = 0;
message.timer_time = 0;
}
records.push(message);
break;
case 'field_description':
fieldDescriptions.push(message);
break;
case 'device_info':
devices.push(message);
break;
case 'developer_data_id':
applications.push(message);
break;
case 'dive_gas':
dive_gases.push(message);
break;
case 'course_point':
course_points.push(message);
break;
case 'sport':
sports.push(message);
break;
case 'file_id':
if (message) {
file_ids.push(message);
}
break;
case 'definition':
if (message) {
definitions.push(message);
}
break;
case 'monitoring':
monitors.push(message);
break;
case 'monitoring_info':
monitor_info.push(message);
break;
case 'stress_level':
stress.push(message);
break;
case 'software':
fitObj.software = message;
break;
case 'tank_update':
tank_updates.push(message);
break;
case 'tank_summary':
tank_summaries.push(message);
break;
default:
if (messageType !== '') {
fitObj[messageType] = message;
}
break;
}
}
if (isCascadeNeeded) {
fitObj.activity = fitObj.activity || {};
laps = (0, _helper.mapDataIntoLap)(laps, 'records', records);
laps = (0, _helper.mapDataIntoLap)(laps, 'lengths', lengths);
sessions = (0, _helper.mapDataIntoSession)(sessions, laps);
fitObj.activity.sessions = sessions;
fitObj.activity.events = events;
fitObj.activity.hrv = hrv;
fitObj.activity.device_infos = devices;
fitObj.activity.developer_data_ids = applications;
fitObj.activity.field_descriptions = fieldDescriptions;
fitObj.activity.sports = sports;
}
if (!isModeCascade) {
fitObj.sessions = sessions;
fitObj.laps = laps;
fitObj.lengths = lengths;
fitObj.records = records;
fitObj.events = events;
fitObj.device_infos = devices;
fitObj.developer_data_ids = applications;
fitObj.field_descriptions = fieldDescriptions;
fitObj.hrv = hrv;
fitObj.dive_gases = dive_gases;
fitObj.course_points = course_points;
fitObj.sports = sports;
fitObj.devices = devices;
fitObj.monitors = monitors;
fitObj.stress = stress;
fitObj.file_ids = file_ids;
fitObj.monitor_info = monitor_info;
fitObj.definitions = definitions;
fitObj.tank_updates = tank_updates;
fitObj.tank_summaries = tank_summaries;
}
callback(null, fitObj);
}
}]);
return FitParser;
}();
exports.default = FitParser;