fit-file-parser 1.20.0 → 2.0.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/.github/workflows/ci.yml +29 -0
- package/CHANGELOG.md +22 -22
- package/CONTRIBUTORS.md +3 -1
- package/README.md +39 -21
- package/dist/binary.d.ts +11 -0
- package/dist/binary.js +181 -221
- package/dist/fit-parser.d.ts +19 -0
- package/dist/fit-parser.js +232 -252
- package/dist/fit.d.ts +52 -0
- package/dist/fit.js +7886 -4295
- package/dist/helper.d.ts +3 -0
- package/dist/helper.js +63 -66
- package/dist/messages.d.ts +6 -0
- package/dist/messages.js +19 -20
- package/dist/types.d.ts +55 -0
- package/dist/types.js +1 -0
- package/eslint.config.js +7 -0
- package/package.json +38 -48
- package/tsconfig.json +15 -0
- package/vitest.config.js +8 -0
package/dist/fit-parser.js
CHANGED
|
@@ -1,261 +1,241 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
var blob = new Uint8Array((0, _binary.getArrayBuffer)(content));
|
|
36
|
-
|
|
37
|
-
if (blob.length < 12) {
|
|
38
|
-
callback('File to small to be a FIT file', {});
|
|
39
|
-
if (!this.options.force) {
|
|
40
|
-
return;
|
|
41
|
-
}
|
|
42
|
-
}
|
|
43
|
-
|
|
44
|
-
var headerLength = blob[0];
|
|
45
|
-
if (headerLength !== 14 && headerLength !== 12) {
|
|
46
|
-
callback('Incorrect header size', {});
|
|
47
|
-
if (!this.options.force) {
|
|
48
|
-
return;
|
|
49
|
-
}
|
|
50
|
-
}
|
|
51
|
-
|
|
52
|
-
var fileTypeString = '';
|
|
53
|
-
for (var i = 8; i < 12; i++) {
|
|
54
|
-
fileTypeString += String.fromCharCode(blob[i]);
|
|
55
|
-
}
|
|
56
|
-
if (fileTypeString !== '.FIT') {
|
|
57
|
-
callback('Missing \'.FIT\' in header', {});
|
|
58
|
-
if (!this.options.force) {
|
|
59
|
-
return;
|
|
1
|
+
import { calculateCRC, getArrayBuffer, readRecord } from './binary.js';
|
|
2
|
+
import { mapDataIntoLap, mapDataIntoSession } from './helper.js';
|
|
3
|
+
export default class FitParser {
|
|
4
|
+
constructor(options = {}) {
|
|
5
|
+
this.options = {
|
|
6
|
+
force: options.force != null ? options.force : true,
|
|
7
|
+
speedUnit: options.speedUnit || 'm/s',
|
|
8
|
+
lengthUnit: options.lengthUnit || 'm',
|
|
9
|
+
temperatureUnit: options.temperatureUnit || 'celsius',
|
|
10
|
+
elapsedRecordField: options.elapsedRecordField || false,
|
|
11
|
+
pressureUnit: options.pressureUnit || 'bar',
|
|
12
|
+
mode: options.mode || 'list',
|
|
13
|
+
};
|
|
14
|
+
}
|
|
15
|
+
parseAsync(content) {
|
|
16
|
+
return new Promise((resolve, reject) => {
|
|
17
|
+
this.parse(content, (error, data) => {
|
|
18
|
+
if (error) {
|
|
19
|
+
reject(error);
|
|
20
|
+
}
|
|
21
|
+
else if (data) {
|
|
22
|
+
resolve(data);
|
|
23
|
+
}
|
|
24
|
+
});
|
|
25
|
+
});
|
|
26
|
+
}
|
|
27
|
+
parse(content, callback) {
|
|
28
|
+
var _a;
|
|
29
|
+
const blob = new Uint8Array(getArrayBuffer(content));
|
|
30
|
+
if (blob.length < 12) {
|
|
31
|
+
callback('File to small to be a FIT file', undefined);
|
|
32
|
+
if (!this.options.force) {
|
|
33
|
+
return;
|
|
34
|
+
}
|
|
60
35
|
}
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
// callback('Header CRC mismatch', {});
|
|
68
|
-
// TODO: fix Header CRC check
|
|
69
|
-
if (!this.options.force) {
|
|
70
|
-
return;
|
|
71
|
-
}
|
|
36
|
+
const headerLength = blob[0];
|
|
37
|
+
if (headerLength !== 14 && headerLength !== 12) {
|
|
38
|
+
callback('Incorrect header size', undefined);
|
|
39
|
+
if (!this.options.force) {
|
|
40
|
+
return;
|
|
41
|
+
}
|
|
72
42
|
}
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
var profileVersion = blob[2] + (blob[3] << 8);
|
|
77
|
-
var dataLength = blob[4] + (blob[5] << 8) + (blob[6] << 16) + (blob[7] << 24);
|
|
78
|
-
var crcStart = dataLength + headerLength;
|
|
79
|
-
var crcFile = blob[crcStart] + (blob[crcStart + 1] << 8);
|
|
80
|
-
var crcFileCalc = (0, _binary.calculateCRC)(blob, headerLength === 12 ? 0 : headerLength, crcStart);
|
|
81
|
-
|
|
82
|
-
if (crcFile !== crcFileCalc) {
|
|
83
|
-
// callback('File CRC mismatch', {});
|
|
84
|
-
// TODO: fix File CRC check
|
|
85
|
-
if (!this.options.force) {
|
|
86
|
-
return;
|
|
43
|
+
let fileTypeString = '';
|
|
44
|
+
for (let i = 8; i < 12; i++) {
|
|
45
|
+
fileTypeString += String.fromCharCode(blob[i]);
|
|
87
46
|
}
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
fitObj.profileVersion = profileVersion;
|
|
93
|
-
|
|
94
|
-
var sessions = [];
|
|
95
|
-
var laps = [];
|
|
96
|
-
var records = [];
|
|
97
|
-
var events = [];
|
|
98
|
-
var hrv = [];
|
|
99
|
-
var devices = [];
|
|
100
|
-
var applications = [];
|
|
101
|
-
var fieldDescriptions = [];
|
|
102
|
-
var dive_gases = [];
|
|
103
|
-
var course_points = [];
|
|
104
|
-
var sports = [];
|
|
105
|
-
var monitors = [];
|
|
106
|
-
var stress = [];
|
|
107
|
-
var definitions = [];
|
|
108
|
-
var file_ids = [];
|
|
109
|
-
var monitor_info = [];
|
|
110
|
-
var lengths = [];
|
|
111
|
-
var tank_updates = [];
|
|
112
|
-
var tank_summaries = [];
|
|
113
|
-
|
|
114
|
-
var loopIndex = headerLength;
|
|
115
|
-
var messageTypes = [];
|
|
116
|
-
var developerFields = [];
|
|
117
|
-
|
|
118
|
-
var isModeCascade = this.options.mode === 'cascade';
|
|
119
|
-
var isCascadeNeeded = isModeCascade || this.options.mode === 'both';
|
|
120
|
-
|
|
121
|
-
var startDate = void 0;
|
|
122
|
-
var lastStopTimestamp = void 0;
|
|
123
|
-
var pausedTime = 0;
|
|
124
|
-
|
|
125
|
-
while (loopIndex < crcStart) {
|
|
126
|
-
var _readRecord = (0, _binary.readRecord)(blob, messageTypes, developerFields, loopIndex, this.options, startDate, pausedTime),
|
|
127
|
-
nextIndex = _readRecord.nextIndex,
|
|
128
|
-
messageType = _readRecord.messageType,
|
|
129
|
-
message = _readRecord.message;
|
|
130
|
-
|
|
131
|
-
loopIndex = nextIndex;
|
|
132
|
-
|
|
133
|
-
switch (messageType) {
|
|
134
|
-
case 'lap':
|
|
135
|
-
laps.push(message);
|
|
136
|
-
break;
|
|
137
|
-
case 'session':
|
|
138
|
-
sessions.push(message);
|
|
139
|
-
break;
|
|
140
|
-
case 'event':
|
|
141
|
-
if (message.event === 'timer') {
|
|
142
|
-
if (message.event_type === 'stop_all') {
|
|
143
|
-
lastStopTimestamp = message.timestamp;
|
|
144
|
-
} else if (message.event_type === 'start' && lastStopTimestamp) {
|
|
145
|
-
pausedTime += (message.timestamp - lastStopTimestamp) / 1000;
|
|
146
|
-
}
|
|
47
|
+
if (fileTypeString !== '.FIT') {
|
|
48
|
+
callback('Missing \'.FIT\' in header', undefined);
|
|
49
|
+
if (!this.options.force) {
|
|
50
|
+
return;
|
|
147
51
|
}
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
startDate = message.timestamp;
|
|
159
|
-
message.elapsed_time = 0;
|
|
160
|
-
message.timer_time = 0;
|
|
161
|
-
}
|
|
162
|
-
records.push(message);
|
|
163
|
-
break;
|
|
164
|
-
case 'field_description':
|
|
165
|
-
fieldDescriptions.push(message);
|
|
166
|
-
break;
|
|
167
|
-
case 'device_info':
|
|
168
|
-
devices.push(message);
|
|
169
|
-
break;
|
|
170
|
-
case 'developer_data_id':
|
|
171
|
-
applications.push(message);
|
|
172
|
-
break;
|
|
173
|
-
case 'dive_gas':
|
|
174
|
-
dive_gases.push(message);
|
|
175
|
-
break;
|
|
176
|
-
case 'course_point':
|
|
177
|
-
course_points.push(message);
|
|
178
|
-
break;
|
|
179
|
-
case 'sport':
|
|
180
|
-
sports.push(message);
|
|
181
|
-
break;
|
|
182
|
-
case 'file_id':
|
|
183
|
-
if (message) {
|
|
184
|
-
file_ids.push(message);
|
|
52
|
+
}
|
|
53
|
+
if (headerLength === 14) {
|
|
54
|
+
const crcHeader = blob[12] + (blob[13] << 8);
|
|
55
|
+
const crcHeaderCalc = calculateCRC(blob, 0, 12);
|
|
56
|
+
if (crcHeader !== crcHeaderCalc) {
|
|
57
|
+
// callback('Header CRC mismatch', {});
|
|
58
|
+
// TODO: fix Header CRC check
|
|
59
|
+
if (!this.options.force) {
|
|
60
|
+
return;
|
|
61
|
+
}
|
|
185
62
|
}
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
63
|
+
}
|
|
64
|
+
const protocolVersion = blob[1];
|
|
65
|
+
const profileVersion = blob[2] + (blob[3] << 8);
|
|
66
|
+
const dataLength = blob[4] + (blob[5] << 8) + (blob[6] << 16) + (blob[7] << 24);
|
|
67
|
+
const crcStart = dataLength + headerLength;
|
|
68
|
+
const crcFile = blob[crcStart] + (blob[crcStart + 1] << 8);
|
|
69
|
+
const crcFileCalc = calculateCRC(blob, headerLength === 12 ? 0 : headerLength, crcStart);
|
|
70
|
+
if (crcFile !== crcFileCalc) {
|
|
71
|
+
// callback('File CRC mismatch', {});
|
|
72
|
+
// TODO: fix File CRC check
|
|
73
|
+
if (!this.options.force) {
|
|
74
|
+
return;
|
|
190
75
|
}
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
76
|
+
}
|
|
77
|
+
const fitObj = {
|
|
78
|
+
profileVersion,
|
|
79
|
+
protocolVersion,
|
|
80
|
+
};
|
|
81
|
+
let sessions = [];
|
|
82
|
+
let laps = [];
|
|
83
|
+
const records = [];
|
|
84
|
+
const events = [];
|
|
85
|
+
const hr_zone = [];
|
|
86
|
+
const power_zone = [];
|
|
87
|
+
const hrv = [];
|
|
88
|
+
const devices = [];
|
|
89
|
+
const applications = [];
|
|
90
|
+
const fieldDescriptions = [];
|
|
91
|
+
const dive_gases = [];
|
|
92
|
+
const course_points = [];
|
|
93
|
+
const sports = [];
|
|
94
|
+
const monitors = [];
|
|
95
|
+
const stress = [];
|
|
96
|
+
const definitions = [];
|
|
97
|
+
const file_ids = [];
|
|
98
|
+
const monitor_info = [];
|
|
99
|
+
const lengths = [];
|
|
100
|
+
const tank_updates = [];
|
|
101
|
+
const tank_summaries = [];
|
|
102
|
+
let loopIndex = headerLength;
|
|
103
|
+
const messageTypes = [];
|
|
104
|
+
const developerFields = [];
|
|
105
|
+
const isModeCascade = this.options.mode === 'cascade';
|
|
106
|
+
const isCascadeNeeded = isModeCascade || this.options.mode === 'both';
|
|
107
|
+
let startDate;
|
|
108
|
+
let lastStopTimestamp;
|
|
109
|
+
let pausedTime = 0;
|
|
110
|
+
while (loopIndex < crcStart) {
|
|
111
|
+
const { nextIndex, messageType, message } = readRecord(blob, messageTypes, developerFields, loopIndex, this.options, startDate, pausedTime);
|
|
112
|
+
loopIndex = nextIndex;
|
|
113
|
+
switch (messageType) {
|
|
114
|
+
case 'lap':
|
|
115
|
+
laps.push(message);
|
|
116
|
+
break;
|
|
117
|
+
case 'session':
|
|
118
|
+
sessions.push(message);
|
|
119
|
+
break;
|
|
120
|
+
case 'event':
|
|
121
|
+
if (message.event === 'timer') {
|
|
122
|
+
if (message.event_type === 'stop_all') {
|
|
123
|
+
lastStopTimestamp = message.timestamp;
|
|
124
|
+
}
|
|
125
|
+
else if (message.event_type === 'start' && lastStopTimestamp) {
|
|
126
|
+
pausedTime += (message.timestamp - lastStopTimestamp) / 1000;
|
|
127
|
+
}
|
|
128
|
+
}
|
|
129
|
+
events.push(message);
|
|
130
|
+
break;
|
|
131
|
+
case 'length':
|
|
132
|
+
lengths.push(message);
|
|
133
|
+
break;
|
|
134
|
+
case 'hrv':
|
|
135
|
+
hrv.push(message);
|
|
136
|
+
break;
|
|
137
|
+
case 'hr_zone':
|
|
138
|
+
hr_zone.push(message);
|
|
139
|
+
break;
|
|
140
|
+
case 'power_zone':
|
|
141
|
+
power_zone.push(message);
|
|
142
|
+
break;
|
|
143
|
+
case 'record':
|
|
144
|
+
if (!startDate) {
|
|
145
|
+
startDate = message.timestamp;
|
|
146
|
+
message.elapsed_time = 0;
|
|
147
|
+
message.timer_time = 0;
|
|
148
|
+
}
|
|
149
|
+
records.push(message);
|
|
150
|
+
break;
|
|
151
|
+
case 'field_description':
|
|
152
|
+
fieldDescriptions.push(message);
|
|
153
|
+
break;
|
|
154
|
+
case 'device_info':
|
|
155
|
+
devices.push(message);
|
|
156
|
+
break;
|
|
157
|
+
case 'developer_data_id':
|
|
158
|
+
applications.push(message);
|
|
159
|
+
break;
|
|
160
|
+
case 'dive_gas':
|
|
161
|
+
dive_gases.push(message);
|
|
162
|
+
break;
|
|
163
|
+
case 'course_point':
|
|
164
|
+
course_points.push(message);
|
|
165
|
+
break;
|
|
166
|
+
case 'sport':
|
|
167
|
+
sports.push(message);
|
|
168
|
+
break;
|
|
169
|
+
case 'file_id':
|
|
170
|
+
if (message) {
|
|
171
|
+
file_ids.push(message);
|
|
172
|
+
}
|
|
173
|
+
break;
|
|
174
|
+
case 'definition':
|
|
175
|
+
if (message) {
|
|
176
|
+
definitions.push(message);
|
|
177
|
+
}
|
|
178
|
+
break;
|
|
179
|
+
case 'monitoring':
|
|
180
|
+
monitors.push(message);
|
|
181
|
+
break;
|
|
182
|
+
case 'monitoring_info':
|
|
183
|
+
monitor_info.push(message);
|
|
184
|
+
break;
|
|
185
|
+
case 'stress_level':
|
|
186
|
+
stress.push(message);
|
|
187
|
+
break;
|
|
188
|
+
case 'software':
|
|
189
|
+
fitObj.software = message;
|
|
190
|
+
break;
|
|
191
|
+
case 'tank_update':
|
|
192
|
+
tank_updates.push(message);
|
|
193
|
+
break;
|
|
194
|
+
case 'tank_summary':
|
|
195
|
+
tank_summaries.push(message);
|
|
196
|
+
break;
|
|
197
|
+
default:
|
|
198
|
+
if (messageType !== '') {
|
|
199
|
+
fitObj[messageType] = message;
|
|
200
|
+
}
|
|
201
|
+
break;
|
|
213
202
|
}
|
|
214
|
-
break;
|
|
215
203
|
}
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
fitObj
|
|
252
|
-
}
|
|
253
|
-
|
|
254
|
-
callback(null, fitObj);
|
|
204
|
+
if (isCascadeNeeded) {
|
|
205
|
+
laps = mapDataIntoLap(laps, 'records', records);
|
|
206
|
+
laps = mapDataIntoLap(laps, 'lengths', lengths);
|
|
207
|
+
sessions = mapDataIntoSession(sessions, laps);
|
|
208
|
+
fitObj.hr_zone = hr_zone;
|
|
209
|
+
fitObj.power_zone = power_zone;
|
|
210
|
+
fitObj.activity = Object.assign(Object.assign({}, ((_a = fitObj.activity) !== null && _a !== void 0 ? _a : {})), { // ugly but we assume the activity was parsed correctly with all other members correctly
|
|
211
|
+
sessions,
|
|
212
|
+
events,
|
|
213
|
+
hrv, device_infos: devices, developer_data_ids: applications, field_descriptions: fieldDescriptions, sports });
|
|
214
|
+
}
|
|
215
|
+
if (!isModeCascade) {
|
|
216
|
+
fitObj.sessions = sessions;
|
|
217
|
+
fitObj.laps = laps;
|
|
218
|
+
fitObj.lengths = lengths;
|
|
219
|
+
fitObj.records = records;
|
|
220
|
+
fitObj.events = events;
|
|
221
|
+
fitObj.device_infos = devices;
|
|
222
|
+
fitObj.developer_data_ids = applications;
|
|
223
|
+
fitObj.field_descriptions = fieldDescriptions;
|
|
224
|
+
fitObj.hrv = hrv;
|
|
225
|
+
fitObj.hr_zone = hr_zone;
|
|
226
|
+
fitObj.power_zone = power_zone;
|
|
227
|
+
fitObj.dive_gases = dive_gases;
|
|
228
|
+
fitObj.course_points = course_points;
|
|
229
|
+
fitObj.sports = sports;
|
|
230
|
+
fitObj.devices = devices;
|
|
231
|
+
fitObj.monitors = monitors;
|
|
232
|
+
fitObj.stress = stress;
|
|
233
|
+
fitObj.file_ids = file_ids;
|
|
234
|
+
fitObj.monitor_info = monitor_info;
|
|
235
|
+
fitObj.definitions = definitions;
|
|
236
|
+
fitObj.tank_updates = tank_updates;
|
|
237
|
+
fitObj.tank_summaries = tank_summaries;
|
|
238
|
+
}
|
|
239
|
+
callback(undefined, fitObj);
|
|
255
240
|
}
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
return FitParser;
|
|
259
|
-
}();
|
|
260
|
-
|
|
261
|
-
exports.default = FitParser;
|
|
241
|
+
}
|
package/dist/fit.d.ts
ADDED
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
export type SpeedUnits = 'm/s' | 'mph' | 'km/h';
|
|
2
|
+
export type LengthUnits = 'm' | 'mi' | 'km';
|
|
3
|
+
export type TemperatureUnits = '°C' | 'kelvin' | 'fahrenheit';
|
|
4
|
+
export type PressureUnits = 'cbar' | 'bar' | 'psi';
|
|
5
|
+
export type MessageName = 'file_id' | 'file_creator' | 'timestamp_correlation' | 'o_hr_settings' | 'software' | 'slave_device' | 'capabilities' | 'file_capabilities' | 'mesg_capabilities' | 'field_capabilities' | 'device_settings' | 'user_profile' | 'hrm_profile' | 'sdm_profile' | 'bike_profile' | 'connectivity' | 'watchface_settings' | 'ohr_settings' | 'time_in_zone' | 'zones_target' | 'sport' | 'hr_zone' | 'speed_zone' | 'cadence_zone' | 'power_zone' | 'met_zone' | 'dive_settings' | 'dive_alarm' | 'dive_gas' | 'goal' | 'activity' | 'session' | 'lap' | 'length' | 'record' | 'event' | 'device_info' | 'device_aux_battery_info' | 'training_file' | 'weather_conditions' | 'weather_alert' | 'gps_metadata' | 'camera_event' | 'gyroscope_data' | 'accelerometer_data' | 'magnetometer_data' | 'barometer_data' | 'three_d_sensor_calibration' | 'one_d_sensor_calibration' | 'video_frame' | 'obdii_data' | 'nmea_sentence' | 'aviation_attitude' | 'video' | 'video_title' | 'video_description' | 'video_clip' | 'set' | 'jump' | 'course' | 'course_point' | 'segment_id' | 'segment_leaderboard_entry' | 'segment_point' | 'segment_lap' | 'segment_file' | 'workout' | 'workout_session' | 'workout_step' | 'exercise_title' | 'schedule' | 'totals' | 'weight_scale' | 'blood_pressure' | 'monitoring_info' | 'monitoring' | 'monitoring_hr_data' | 'hr' | 'memo_glob' | 'stress_level' | 'dive_summary' | 'hrv' | 'beat_intervals' | 'respiration_rate' | 'spo2_data' | 'sleep_level' | 'pad' | 'field_description' | 'developer_data_id' | 'definition' | 'tank_update' | 'tank_summary';
|
|
6
|
+
export type Unit<T extends string> = Record<T, {
|
|
7
|
+
multiplier: number;
|
|
8
|
+
offset: number;
|
|
9
|
+
}>;
|
|
10
|
+
export interface FieldDefinition {
|
|
11
|
+
type: string | number;
|
|
12
|
+
fDefNo: number;
|
|
13
|
+
size: number;
|
|
14
|
+
endianAbility: boolean;
|
|
15
|
+
littleEndian: boolean;
|
|
16
|
+
baseTypeNo: number;
|
|
17
|
+
name: string;
|
|
18
|
+
dataType: string;
|
|
19
|
+
scale?: number;
|
|
20
|
+
offset?: number;
|
|
21
|
+
developerDataIndex?: number;
|
|
22
|
+
isDeveloperField?: boolean;
|
|
23
|
+
}
|
|
24
|
+
export interface MessageObject {
|
|
25
|
+
field: string;
|
|
26
|
+
type: string;
|
|
27
|
+
scale: number | null;
|
|
28
|
+
offset: number;
|
|
29
|
+
units: string;
|
|
30
|
+
}
|
|
31
|
+
interface Message {
|
|
32
|
+
name: MessageName;
|
|
33
|
+
[fieldId: number]: MessageObject;
|
|
34
|
+
}
|
|
35
|
+
export interface FitTypeOptions {
|
|
36
|
+
speedUnits: Unit<SpeedUnits>;
|
|
37
|
+
lengthUnits: Unit<LengthUnits>;
|
|
38
|
+
temperatureUnits: Unit<TemperatureUnits>;
|
|
39
|
+
pressureUnits: Unit<PressureUnits>;
|
|
40
|
+
}
|
|
41
|
+
export interface FitType {
|
|
42
|
+
scConst: number;
|
|
43
|
+
options: FitTypeOptions;
|
|
44
|
+
messages: {
|
|
45
|
+
[messageId: number]: Message;
|
|
46
|
+
};
|
|
47
|
+
types: {
|
|
48
|
+
[typeName: string]: Record<number, string | number>;
|
|
49
|
+
};
|
|
50
|
+
}
|
|
51
|
+
export declare const FIT: FitType;
|
|
52
|
+
export {};
|