rubyfit 0.0.2
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.
- data/ext/rubyfit/extconf.rb +2 -0
- data/ext/rubyfit/fit.c +281 -0
- data/ext/rubyfit/fit.h +253 -0
- data/ext/rubyfit/fit_config.h +36 -0
- data/ext/rubyfit/fit_convert.c +439 -0
- data/ext/rubyfit/fit_convert.h +154 -0
- data/ext/rubyfit/fit_crc.c +43 -0
- data/ext/rubyfit/fit_crc.h +35 -0
- data/ext/rubyfit/fit_product.c +21 -0
- data/ext/rubyfit/fit_product.h +21 -0
- data/ext/rubyfit/fit_sdk.c +618 -0
- data/ext/rubyfit/fit_sdk.h +2083 -0
- data/ext/rubyfit/rubyfit.c +590 -0
- data/lib/rubyfit/version.rb +3 -0
- data/lib/rubyfit.rb +2 -0
- metadata +63 -0
@@ -0,0 +1,439 @@
|
|
1
|
+
////////////////////////////////////////////////////////////////////////////////
|
2
|
+
// The following .FIT software provided may be used with .FIT devices only and
|
3
|
+
// remains the copyrighted property of Dynastream Innovations Inc.
|
4
|
+
// The software is being provided on an "as-is" basis and as an accommodation,
|
5
|
+
// and therefore all warranties, representations, or guarantees of any kind
|
6
|
+
// (whether express, implied or statutory) including, without limitation,
|
7
|
+
// warranties of merchantability, non-infringement, or fitness for a particular
|
8
|
+
// purpose, are specifically disclaimed.
|
9
|
+
//
|
10
|
+
// Copyright 2008 Dynastream Innovations Inc.
|
11
|
+
// All rights reserved. This software may not be reproduced by any means
|
12
|
+
// without express written approval of Dynastream Innovations Inc.
|
13
|
+
////////////////////////////////////////////////////////////////////////////////
|
14
|
+
|
15
|
+
#include <string.h>
|
16
|
+
|
17
|
+
#include "fit_convert.h"
|
18
|
+
#include "fit_crc.h"
|
19
|
+
|
20
|
+
//////////////////////////////////////////////////////////////////////////////////
|
21
|
+
// Private Variables
|
22
|
+
//////////////////////////////////////////////////////////////////////////////////
|
23
|
+
|
24
|
+
#if !defined(FIT_CONVERT_MULTI_THREAD)
|
25
|
+
static FIT_CONVERT_STATE state_struct;
|
26
|
+
#define state (&state_struct)
|
27
|
+
#endif
|
28
|
+
|
29
|
+
//////////////////////////////////////////////////////////////////////////////////
|
30
|
+
// Public Functions
|
31
|
+
//////////////////////////////////////////////////////////////////////////////////
|
32
|
+
|
33
|
+
///////////////////////////////////////////////////////////////////////
|
34
|
+
#if defined(FIT_CONVERT_MULTI_THREAD)
|
35
|
+
void FitConvert_Init(FIT_CONVERT_STATE *state, FIT_BOOL read_file_header)
|
36
|
+
#else
|
37
|
+
void FitConvert_Init(FIT_BOOL read_file_header)
|
38
|
+
#endif
|
39
|
+
{
|
40
|
+
state->mesg_offset = 0;
|
41
|
+
state->data_offset = 0;
|
42
|
+
|
43
|
+
#if defined(FIT_CONVERT_CHECK_CRC)
|
44
|
+
state->crc = 0;
|
45
|
+
#endif
|
46
|
+
#if defined(FIT_CONVERT_TIME_RECORD)
|
47
|
+
state->timestamp = 0;
|
48
|
+
state->last_time_offset = 0;
|
49
|
+
#endif
|
50
|
+
|
51
|
+
if (read_file_header)
|
52
|
+
{
|
53
|
+
state->file_bytes_left = 3; // Header size byte + CRC.
|
54
|
+
state->decode_state = FIT_CONVERT_DECODE_FILE_HDR;
|
55
|
+
}
|
56
|
+
else
|
57
|
+
{
|
58
|
+
state->file_bytes_left = 0; // Don't read header or check CRC.
|
59
|
+
state->decode_state = FIT_CONVERT_DECODE_RECORD;
|
60
|
+
}
|
61
|
+
}
|
62
|
+
|
63
|
+
///////////////////////////////////////////////////////////////////////
|
64
|
+
#if defined(FIT_CONVERT_MULTI_THREAD)
|
65
|
+
FIT_CONVERT_RETURN FitConvert_Read(FIT_CONVERT_STATE *state, const void *data, FIT_UINT32 size)
|
66
|
+
#else
|
67
|
+
FIT_CONVERT_RETURN FitConvert_Read(const void *data, FIT_UINT32 size)
|
68
|
+
#endif
|
69
|
+
{
|
70
|
+
while (state->data_offset < size)
|
71
|
+
{
|
72
|
+
FIT_UINT8 datum = *((FIT_UINT8 *) data + state->data_offset);
|
73
|
+
state->data_offset++;
|
74
|
+
|
75
|
+
//printf("fit_convert: 0x%02X - %d\n",datum, state->decode_state);
|
76
|
+
|
77
|
+
if (state->file_bytes_left > 0)
|
78
|
+
{
|
79
|
+
#if defined(FIT_CONVERT_CHECK_CRC)
|
80
|
+
state->crc = FitCRC_Get16(state->crc, datum);
|
81
|
+
#endif
|
82
|
+
|
83
|
+
state->file_bytes_left--;
|
84
|
+
|
85
|
+
if (state->file_bytes_left == 1) // CRC low byte.
|
86
|
+
{
|
87
|
+
if (state->decode_state != FIT_CONVERT_DECODE_RECORD)
|
88
|
+
return FIT_CONVERT_ERROR;
|
89
|
+
|
90
|
+
continue; // Next byte.
|
91
|
+
}
|
92
|
+
else if (state->file_bytes_left == 0) // CRC high byte.
|
93
|
+
{
|
94
|
+
#if defined(FIT_CONVERT_CHECK_CRC)
|
95
|
+
if (state->crc != 0)
|
96
|
+
return FIT_CONVERT_ERROR;
|
97
|
+
#endif
|
98
|
+
|
99
|
+
return FIT_CONVERT_END_OF_FILE;
|
100
|
+
}
|
101
|
+
}
|
102
|
+
|
103
|
+
switch (state->decode_state)
|
104
|
+
{
|
105
|
+
case FIT_CONVERT_DECODE_FILE_HDR:
|
106
|
+
*((FIT_UINT8 *) &state->u.file_hdr + state->mesg_offset) = datum;
|
107
|
+
|
108
|
+
if (state->mesg_offset == 0)
|
109
|
+
state->file_bytes_left = state->u.file_hdr.header_size + 2; // Increase to read header and CRC.
|
110
|
+
|
111
|
+
state->mesg_offset++;
|
112
|
+
|
113
|
+
if (state->mesg_offset >= state->u.file_hdr.header_size)
|
114
|
+
{
|
115
|
+
state->file_bytes_left = *((FIT_UINT8 *) &state->u.file_hdr.data_size);
|
116
|
+
state->file_bytes_left |= (FIT_UINT32)*((FIT_UINT8 *) &state->u.file_hdr.data_size + 1) << 8;
|
117
|
+
state->file_bytes_left |= (FIT_UINT32)*((FIT_UINT8 *) &state->u.file_hdr.data_size + 2) << 16;
|
118
|
+
state->file_bytes_left |= (FIT_UINT32)*((FIT_UINT8 *) &state->u.file_hdr.data_size + 3) << 24;
|
119
|
+
state->file_bytes_left += 2; // CRC.
|
120
|
+
|
121
|
+
if ((state->u.file_hdr.protocol_version & FIT_PROTOCOL_VERSION_MAJOR_MASK) > (FIT_PROTOCOL_VERSION_MAJOR << FIT_PROTOCOL_VERSION_MAJOR_SHIFT))
|
122
|
+
return FIT_CONVERT_PROTOCOL_VERSION_NOT_SUPPORTED;
|
123
|
+
|
124
|
+
#if defined(FIT_CONVERT_CHECK_FILE_HDR_DATA_TYPE)
|
125
|
+
if (memcmp(state->u.file_hdr.data_type, ".FIT", 4) != 0)
|
126
|
+
return FIT_CONVERT_DATA_TYPE_NOT_SUPPORTED;
|
127
|
+
#endif
|
128
|
+
|
129
|
+
state->decode_state = FIT_CONVERT_DECODE_RECORD;
|
130
|
+
}
|
131
|
+
break;
|
132
|
+
|
133
|
+
case FIT_CONVERT_DECODE_RECORD:
|
134
|
+
if (datum & FIT_HDR_TIME_REC_BIT)
|
135
|
+
{
|
136
|
+
// This is a message data record with time.
|
137
|
+
state->mesg_index = (datum & FIT_HDR_TIME_TYPE_MASK) >> FIT_HDR_TIME_TYPE_SHIFT;
|
138
|
+
|
139
|
+
#if defined(FIT_CONVERT_TIME_RECORD)
|
140
|
+
{
|
141
|
+
FIT_UINT8 time_offset = datum & FIT_HDR_TIME_OFFSET_MASK;
|
142
|
+
state->timestamp += (time_offset - state->last_time_offset) & FIT_HDR_TIME_OFFSET_MASK;
|
143
|
+
state->last_time_offset = time_offset;
|
144
|
+
}
|
145
|
+
#endif
|
146
|
+
|
147
|
+
state->decode_state = FIT_CONVERT_DECODE_FIELD_DATA;
|
148
|
+
}
|
149
|
+
else
|
150
|
+
{
|
151
|
+
state->mesg_index = datum & FIT_HDR_TYPE_MASK;
|
152
|
+
|
153
|
+
if ((datum & FIT_HDR_TYPE_DEF_BIT) == 0)
|
154
|
+
{
|
155
|
+
// This is a message data record.
|
156
|
+
state->decode_state = FIT_CONVERT_DECODE_FIELD_DATA;
|
157
|
+
}
|
158
|
+
else
|
159
|
+
{
|
160
|
+
// This is a message definition record.
|
161
|
+
state->mesg_sizes[state->mesg_index] = 0;
|
162
|
+
state->decode_state = FIT_CONVERT_DECODE_RESERVED1;
|
163
|
+
}
|
164
|
+
}
|
165
|
+
|
166
|
+
if (state->decode_state == FIT_CONVERT_DECODE_FIELD_DATA)
|
167
|
+
{
|
168
|
+
if (state->mesg_index < FIT_LOCAL_MESGS)
|
169
|
+
{
|
170
|
+
state->mesg_def = Fit_GetMesgDef(state->convert_table[state->mesg_index].global_mesg_num);
|
171
|
+
Fit_InitMesg(state->mesg_def, state->u.mesg);
|
172
|
+
|
173
|
+
#if defined(FIT_CONVERT_TIME_RECORD)
|
174
|
+
if (datum & FIT_HDR_TIME_REC_BIT)
|
175
|
+
{
|
176
|
+
FIT_UINT8 field_offset = Fit_GetFieldOffset(state->mesg_def, FIT_TIMESTAMP_FIELD_NUM);
|
177
|
+
|
178
|
+
if (field_offset != FIT_UINT8_INVALID)
|
179
|
+
memcpy(&state->u.mesg[field_offset], &state->timestamp, sizeof(state->timestamp));
|
180
|
+
}
|
181
|
+
#endif
|
182
|
+
}
|
183
|
+
|
184
|
+
if (state->mesg_sizes[state->mesg_index] == 0)
|
185
|
+
state->decode_state = FIT_CONVERT_DECODE_RECORD;
|
186
|
+
}
|
187
|
+
|
188
|
+
state->mesg_offset = 0; // Reset the message byte count.
|
189
|
+
state->field_index = 0;
|
190
|
+
state->field_offset = 0;
|
191
|
+
break;
|
192
|
+
|
193
|
+
case FIT_CONVERT_DECODE_RESERVED1:
|
194
|
+
if (state->mesg_index < FIT_LOCAL_MESGS)
|
195
|
+
state->convert_table[state->mesg_index].reserved_1 = datum;
|
196
|
+
|
197
|
+
state->decode_state = FIT_CONVERT_DECODE_ARCH;
|
198
|
+
break;
|
199
|
+
|
200
|
+
case FIT_CONVERT_DECODE_ARCH:
|
201
|
+
if (state->mesg_index < FIT_LOCAL_MESGS)
|
202
|
+
state->convert_table[state->mesg_index].arch = datum;
|
203
|
+
|
204
|
+
state->decode_state = FIT_CONVERT_DECODE_GTYPE_1;
|
205
|
+
break;
|
206
|
+
|
207
|
+
case FIT_CONVERT_DECODE_GTYPE_1:
|
208
|
+
if (state->mesg_index < FIT_LOCAL_MESGS)
|
209
|
+
state->convert_table[state->mesg_index].global_mesg_num = datum;
|
210
|
+
|
211
|
+
state->decode_state = FIT_CONVERT_DECODE_GTYPE_2;
|
212
|
+
break;
|
213
|
+
|
214
|
+
case FIT_CONVERT_DECODE_GTYPE_2:
|
215
|
+
if (state->mesg_index < FIT_LOCAL_MESGS)
|
216
|
+
{
|
217
|
+
if ((state->convert_table[state->mesg_index].arch & FIT_ARCH_ENDIAN_MASK) == FIT_ARCH_ENDIAN_BIG)
|
218
|
+
{
|
219
|
+
state->convert_table[state->mesg_index].global_mesg_num <<= 8;
|
220
|
+
state->convert_table[state->mesg_index].global_mesg_num |= datum;
|
221
|
+
}
|
222
|
+
else
|
223
|
+
{
|
224
|
+
state->convert_table[state->mesg_index].global_mesg_num |= ((FIT_UINT16) datum << 8);
|
225
|
+
}
|
226
|
+
|
227
|
+
state->convert_table[state->mesg_index].num_fields = 0; // Initialize.
|
228
|
+
state->mesg_def = Fit_GetMesgDef(state->convert_table[state->mesg_index].global_mesg_num);
|
229
|
+
}
|
230
|
+
|
231
|
+
state->decode_state = FIT_CONVERT_DECODE_NUM_FIELD_DEFS;
|
232
|
+
break;
|
233
|
+
|
234
|
+
case FIT_CONVERT_DECODE_NUM_FIELD_DEFS:
|
235
|
+
state->num_fields = datum;
|
236
|
+
|
237
|
+
if (state->num_fields == 0)
|
238
|
+
{
|
239
|
+
state->decode_state = FIT_CONVERT_DECODE_RECORD;
|
240
|
+
break;
|
241
|
+
}
|
242
|
+
|
243
|
+
state->field_index = 0;
|
244
|
+
state->decode_state = FIT_CONVERT_DECODE_FIELD_DEF;
|
245
|
+
break;
|
246
|
+
|
247
|
+
case FIT_CONVERT_DECODE_FIELD_DEF:
|
248
|
+
state->field_num = FIT_FIELD_NUM_INVALID;
|
249
|
+
|
250
|
+
if (state->mesg_index < FIT_LOCAL_MESGS)
|
251
|
+
{
|
252
|
+
if (state->mesg_def != FIT_NULL)
|
253
|
+
{
|
254
|
+
FIT_UINT8 local_field_index;
|
255
|
+
FIT_UINT8 local_field_offset = 0;
|
256
|
+
|
257
|
+
// Search for the field definition in the local mesg definition.
|
258
|
+
for (local_field_index = 0; local_field_index < state->mesg_def->num_fields; local_field_index++)
|
259
|
+
{
|
260
|
+
FIT_UINT8 field_size = state->mesg_def->fields[FIT_MESG_DEF_FIELD_OFFSET(size, local_field_index)];
|
261
|
+
|
262
|
+
if (state->mesg_def->fields[FIT_MESG_DEF_FIELD_OFFSET(field_def_num, local_field_index)] == datum)
|
263
|
+
{
|
264
|
+
state->field_num = datum;
|
265
|
+
state->convert_table[state->mesg_index].fields[state->convert_table[state->mesg_index].num_fields].offset_in = state->mesg_offset;
|
266
|
+
state->convert_table[state->mesg_index].fields[state->convert_table[state->mesg_index].num_fields].offset_local = local_field_offset;
|
267
|
+
state->convert_table[state->mesg_index].fields[state->convert_table[state->mesg_index].num_fields].size = field_size;
|
268
|
+
break;
|
269
|
+
}
|
270
|
+
|
271
|
+
local_field_offset += field_size;
|
272
|
+
}
|
273
|
+
}
|
274
|
+
}
|
275
|
+
|
276
|
+
state->decode_state = FIT_CONVERT_DECODE_FIELD_DEF_SIZE;
|
277
|
+
break;
|
278
|
+
|
279
|
+
case FIT_CONVERT_DECODE_FIELD_DEF_SIZE:
|
280
|
+
if (state->mesg_index < FIT_LOCAL_MESGS)
|
281
|
+
{
|
282
|
+
state->mesg_offset += datum;
|
283
|
+
|
284
|
+
if (state->field_num != FIT_FIELD_NUM_INVALID)
|
285
|
+
{
|
286
|
+
if (datum < state->convert_table[state->mesg_index].fields[state->convert_table[state->mesg_index].num_fields].size)
|
287
|
+
state->convert_table[state->mesg_index].fields[state->convert_table[state->mesg_index].num_fields].size = datum;
|
288
|
+
}
|
289
|
+
}
|
290
|
+
|
291
|
+
state->mesg_sizes[state->mesg_index] += datum;
|
292
|
+
|
293
|
+
state->decode_state = FIT_CONVERT_DECODE_FIELD_BASE_TYPE;
|
294
|
+
break;
|
295
|
+
|
296
|
+
case FIT_CONVERT_DECODE_FIELD_BASE_TYPE:
|
297
|
+
if (state->field_num != FIT_FIELD_NUM_INVALID)
|
298
|
+
{
|
299
|
+
state->convert_table[state->mesg_index].fields[state->convert_table[state->mesg_index].num_fields].base_type = datum;
|
300
|
+
state->convert_table[state->mesg_index].num_fields++;
|
301
|
+
}
|
302
|
+
|
303
|
+
state->field_index++;
|
304
|
+
|
305
|
+
if (state->field_index >= state->num_fields)
|
306
|
+
state->decode_state = FIT_CONVERT_DECODE_RECORD;
|
307
|
+
else
|
308
|
+
state->decode_state = FIT_CONVERT_DECODE_FIELD_DEF;
|
309
|
+
break;
|
310
|
+
|
311
|
+
case FIT_CONVERT_DECODE_FIELD_DATA:
|
312
|
+
state->mesg_offset++;
|
313
|
+
|
314
|
+
if (state->mesg_offset >= state->mesg_sizes[state->mesg_index])
|
315
|
+
{
|
316
|
+
state->decode_state = FIT_CONVERT_DECODE_RECORD;
|
317
|
+
}
|
318
|
+
|
319
|
+
if (state->mesg_index < FIT_LOCAL_MESGS)
|
320
|
+
{
|
321
|
+
if ((state->mesg_def != FIT_NULL) && (state->field_index < state->convert_table[state->mesg_index].num_fields))
|
322
|
+
{
|
323
|
+
if (state->mesg_offset == (state->convert_table[state->mesg_index].fields[state->field_index].offset_in + state->field_offset + 1))
|
324
|
+
{
|
325
|
+
FIT_UINT8 *field = &state->u.mesg[state->convert_table[state->mesg_index].fields[state->field_index].offset_local];
|
326
|
+
|
327
|
+
field[state->field_offset] = datum; // Store the incoming byte in the local mesg buffer.
|
328
|
+
state->field_offset++;
|
329
|
+
|
330
|
+
if (state->field_offset >= state->convert_table[state->mesg_index].fields[state->field_index].size)
|
331
|
+
{
|
332
|
+
if (
|
333
|
+
(state->convert_table[state->mesg_index].fields[state->field_index].base_type & FIT_BASE_TYPE_ENDIAN_FLAG) &&
|
334
|
+
((state->convert_table[state->mesg_index].arch & FIT_ARCH_ENDIAN_MASK) != (Fit_GetArch() & FIT_ARCH_ENDIAN_MASK))
|
335
|
+
)
|
336
|
+
{
|
337
|
+
FIT_UINT8 type_size = fit_base_type_sizes[state->convert_table[state->mesg_index].fields[state->field_index].base_type & FIT_BASE_TYPE_NUM_MASK];
|
338
|
+
FIT_UINT8 element_size = state->convert_table[state->mesg_index].fields[state->field_index].size / type_size;
|
339
|
+
FIT_UINT8 element;
|
340
|
+
FIT_UINT8 index;
|
341
|
+
|
342
|
+
for (element = 0; element < element_size; element++)
|
343
|
+
{
|
344
|
+
for (index = 0; index < (type_size / 2); index++)
|
345
|
+
{
|
346
|
+
FIT_UINT8 tmp = field[element * type_size + index];
|
347
|
+
field[element * type_size + index] = field[element * type_size + type_size - 1 - index];
|
348
|
+
field[element * type_size + type_size - 1 - index] = tmp;
|
349
|
+
}
|
350
|
+
}
|
351
|
+
}
|
352
|
+
|
353
|
+
state->field_offset = 0; // Reset the offset.
|
354
|
+
state->field_index++; // Move on to the next field.
|
355
|
+
|
356
|
+
if (state->field_index >= state->convert_table[state->mesg_index].num_fields)
|
357
|
+
{
|
358
|
+
#if defined(FIT_CONVERT_TIME_RECORD)
|
359
|
+
{
|
360
|
+
FIT_UINT8 timestamp_offset = Fit_GetFieldOffset(state->mesg_def, FIT_TIMESTAMP_FIELD_NUM);
|
361
|
+
|
362
|
+
if (timestamp_offset != FIT_UINT8_INVALID)
|
363
|
+
{
|
364
|
+
if (*((FIT_UINT32 *)&state->u.mesg[timestamp_offset]) != FIT_DATE_TIME_INVALID)
|
365
|
+
{
|
366
|
+
memcpy(&state->timestamp, &state->u.mesg[timestamp_offset], sizeof(state->timestamp));
|
367
|
+
state->last_time_offset = (FIT_UINT8)(state->timestamp & FIT_HDR_TIME_OFFSET_MASK);
|
368
|
+
}
|
369
|
+
}
|
370
|
+
}
|
371
|
+
#endif
|
372
|
+
|
373
|
+
// We have successfully decoded a mesg.
|
374
|
+
return FIT_CONVERT_MESSAGE_AVAILABLE;
|
375
|
+
}
|
376
|
+
}
|
377
|
+
}
|
378
|
+
}
|
379
|
+
}
|
380
|
+
break;
|
381
|
+
|
382
|
+
default:
|
383
|
+
// This shouldn't happen.
|
384
|
+
return FIT_CONVERT_ERROR;
|
385
|
+
}
|
386
|
+
}
|
387
|
+
|
388
|
+
state->data_offset = 0;
|
389
|
+
return FIT_CONVERT_CONTINUE;
|
390
|
+
}
|
391
|
+
|
392
|
+
///////////////////////////////////////////////////////////////////////
|
393
|
+
#if defined(FIT_CONVERT_MULTI_THREAD)
|
394
|
+
FIT_UINT16 FitConvert_GetMessageNumber(FIT_CONVERT_STATE *state)
|
395
|
+
#else
|
396
|
+
FIT_UINT16 FitConvert_GetMessageNumber(void)
|
397
|
+
#endif
|
398
|
+
{
|
399
|
+
return state->convert_table[state->mesg_index].global_mesg_num;
|
400
|
+
}
|
401
|
+
|
402
|
+
///////////////////////////////////////////////////////////////////////
|
403
|
+
#if defined(FIT_CONVERT_MULTI_THREAD)
|
404
|
+
const FIT_UINT8 *FitConvert_GetMessageData(FIT_CONVERT_STATE *state)
|
405
|
+
#else
|
406
|
+
const FIT_UINT8 *FitConvert_GetMessageData(void)
|
407
|
+
#endif
|
408
|
+
{
|
409
|
+
return state->u.mesg;
|
410
|
+
}
|
411
|
+
|
412
|
+
///////////////////////////////////////////////////////////////////////
|
413
|
+
#if defined(FIT_CONVERT_MULTI_THREAD)
|
414
|
+
void FitConvert_RestoreFields(FIT_CONVERT_STATE *state, const void *mesg)
|
415
|
+
#else
|
416
|
+
void FitConvert_RestoreFields(const void *mesg)
|
417
|
+
#endif
|
418
|
+
{
|
419
|
+
FIT_UINT8 offset = 0;
|
420
|
+
FIT_UINT8 field_index;
|
421
|
+
FIT_UINT8 convert_field;
|
422
|
+
|
423
|
+
if (state->mesg_def == FIT_NULL)
|
424
|
+
return;
|
425
|
+
|
426
|
+
for (field_index = 0; field_index < state->mesg_def->num_fields; field_index++)
|
427
|
+
{
|
428
|
+
for (convert_field=0; convert_field < state->convert_table[state->mesg_index].num_fields; convert_field++)
|
429
|
+
{
|
430
|
+
if (state->convert_table[state->mesg_index].fields[convert_field].offset_local == offset)
|
431
|
+
break;
|
432
|
+
}
|
433
|
+
|
434
|
+
if (convert_field == state->convert_table[state->mesg_index].num_fields)
|
435
|
+
memcpy(&state->u.mesg[offset], &((FIT_UINT8 *)mesg)[offset], state->mesg_def->fields[FIT_MESG_DEF_FIELD_OFFSET(size, field_index)]);
|
436
|
+
|
437
|
+
offset += state->mesg_def->fields[FIT_MESG_DEF_FIELD_OFFSET(size, field_index)];
|
438
|
+
}
|
439
|
+
}
|
@@ -0,0 +1,154 @@
|
|
1
|
+
////////////////////////////////////////////////////////////////////////////////
|
2
|
+
// The following .FIT software provided may be used with .FIT devices only and
|
3
|
+
// remains the copyrighted property of Dynastream Innovations Inc.
|
4
|
+
// The software is being provided on an "as-is" basis and as an accommodation,
|
5
|
+
// and therefore all warranties, representations, or guarantees of any kind
|
6
|
+
// (whether express, implied or statutory) including, without limitation,
|
7
|
+
// warranties of merchantability, non-infringement, or fitness for a particular
|
8
|
+
// purpose, are specifically disclaimed.
|
9
|
+
//
|
10
|
+
// Copyright 2008 Dynastream Innovations Inc.
|
11
|
+
// All rights reserved. This software may not be reproduced by any means
|
12
|
+
// without express written approval of Dynastream Innovations Inc.
|
13
|
+
////////////////////////////////////////////////////////////////////////////////
|
14
|
+
|
15
|
+
#if !defined(FIT_CONVERT_H)
|
16
|
+
#define FIT_CONVERT_H
|
17
|
+
|
18
|
+
#include "fit_product.h"
|
19
|
+
|
20
|
+
|
21
|
+
//////////////////////////////////////////////////////////////////////////////////
|
22
|
+
// Public Definitions
|
23
|
+
//////////////////////////////////////////////////////////////////////////////////
|
24
|
+
|
25
|
+
typedef enum
|
26
|
+
{
|
27
|
+
FIT_CONVERT_CONTINUE = 0,
|
28
|
+
FIT_CONVERT_MESSAGE_AVAILABLE,
|
29
|
+
FIT_CONVERT_ERROR,
|
30
|
+
FIT_CONVERT_END_OF_FILE,
|
31
|
+
FIT_CONVERT_PROTOCOL_VERSION_NOT_SUPPORTED,
|
32
|
+
FIT_CONVERT_DATA_TYPE_NOT_SUPPORTED
|
33
|
+
} FIT_CONVERT_RETURN;
|
34
|
+
|
35
|
+
typedef enum
|
36
|
+
{
|
37
|
+
FIT_CONVERT_DECODE_FILE_HDR,
|
38
|
+
FIT_CONVERT_DECODE_RECORD,
|
39
|
+
FIT_CONVERT_DECODE_RESERVED1,
|
40
|
+
FIT_CONVERT_DECODE_ARCH,
|
41
|
+
FIT_CONVERT_DECODE_GTYPE_1,
|
42
|
+
FIT_CONVERT_DECODE_GTYPE_2,
|
43
|
+
FIT_CONVERT_DECODE_NUM_FIELD_DEFS,
|
44
|
+
FIT_CONVERT_DECODE_FIELD_DEF,
|
45
|
+
FIT_CONVERT_DECODE_FIELD_DEF_SIZE,
|
46
|
+
FIT_CONVERT_DECODE_FIELD_BASE_TYPE,
|
47
|
+
FIT_CONVERT_DECODE_FIELD_DATA
|
48
|
+
} FIT_CONVERT_DECODE_STATE;
|
49
|
+
|
50
|
+
typedef struct
|
51
|
+
{
|
52
|
+
FIT_UINT32 file_bytes_left;
|
53
|
+
FIT_UINT32 data_offset;
|
54
|
+
#if defined(FIT_CONVERT_TIME_RECORD)
|
55
|
+
FIT_UINT32 timestamp;
|
56
|
+
#endif
|
57
|
+
union
|
58
|
+
{
|
59
|
+
FIT_FILE_HDR file_hdr;
|
60
|
+
FIT_UINT8 mesg[FIT_MESG_SIZE];
|
61
|
+
}u;
|
62
|
+
FIT_MESG_CONVERT convert_table[FIT_LOCAL_MESGS];
|
63
|
+
const FIT_MESG_DEF *mesg_def;
|
64
|
+
#if defined(FIT_CONVERT_CHECK_CRC)
|
65
|
+
FIT_UINT16 crc;
|
66
|
+
#endif
|
67
|
+
FIT_CONVERT_DECODE_STATE decode_state;
|
68
|
+
FIT_UINT8 mesg_index;
|
69
|
+
FIT_UINT8 mesg_sizes[FIT_MAX_LOCAL_MESGS];
|
70
|
+
FIT_UINT8 mesg_offset;
|
71
|
+
FIT_UINT8 num_fields;
|
72
|
+
FIT_UINT8 field_num;
|
73
|
+
FIT_UINT8 field_index;
|
74
|
+
FIT_UINT8 field_offset;
|
75
|
+
#if defined(FIT_CONVERT_TIME_RECORD)
|
76
|
+
FIT_UINT8 last_time_offset;
|
77
|
+
#endif
|
78
|
+
} FIT_CONVERT_STATE;
|
79
|
+
|
80
|
+
|
81
|
+
//////////////////////////////////////////////////////////////////////////////////
|
82
|
+
// Public Function Prototypes
|
83
|
+
//////////////////////////////////////////////////////////////////////////////////
|
84
|
+
|
85
|
+
#if defined(__cplusplus)
|
86
|
+
extern "C" {
|
87
|
+
#endif
|
88
|
+
|
89
|
+
#if defined(FIT_CONVERT_MULTI_THREAD)
|
90
|
+
void FitConvert_Init(FIT_CONVERT_STATE *state, FIT_BOOL read_file_header);
|
91
|
+
#else
|
92
|
+
void FitConvert_Init(FIT_BOOL read_file_header);
|
93
|
+
#endif
|
94
|
+
///////////////////////////////////////////////////////////////////////
|
95
|
+
// Initialize the state of the converter to start parsing the file.
|
96
|
+
///////////////////////////////////////////////////////////////////////
|
97
|
+
|
98
|
+
#if defined(FIT_CONVERT_MULTI_THREAD)
|
99
|
+
FIT_CONVERT_RETURN FitConvert_Read(FIT_CONVERT_STATE *state, const void *data, FIT_UINT32 size);
|
100
|
+
#else
|
101
|
+
FIT_CONVERT_RETURN FitConvert_Read(const void *data, FIT_UINT32 size);
|
102
|
+
#endif
|
103
|
+
///////////////////////////////////////////////////////////////////////
|
104
|
+
// Convert a stream of bytes.
|
105
|
+
// Parameters:
|
106
|
+
// state Pointer to converter state.
|
107
|
+
// data Pointer to a buffer containing bytes from the file stream.
|
108
|
+
// size Number of bytes in the data buffer.
|
109
|
+
//
|
110
|
+
// Returns FIT_CONVERT_CONTINUE when the all bytes in data have
|
111
|
+
// been decoded successfully and ready to accept next bytes in the
|
112
|
+
// file stream. No message is available yet.
|
113
|
+
// Returns FIT_CONVERT_MESSAGE_AVAILABLE when a message is
|
114
|
+
// complete. The message is valid until this function is called
|
115
|
+
// again.
|
116
|
+
// Returns FIT_CONVERT_ERROR if a decoding error occurs.
|
117
|
+
// Returns FIT_CONVERT_END_OF_FILE when the file has been decoded successfully.
|
118
|
+
///////////////////////////////////////////////////////////////////////
|
119
|
+
|
120
|
+
#if defined(FIT_CONVERT_MULTI_THREAD)
|
121
|
+
FIT_MESG_NUM FitConvert_GetMessageNumber(FIT_CONVERT_STATE *state);
|
122
|
+
#else
|
123
|
+
FIT_MESG_NUM FitConvert_GetMessageNumber(void);
|
124
|
+
#endif
|
125
|
+
///////////////////////////////////////////////////////////////////////
|
126
|
+
// Returns the global message number of the decoded message.
|
127
|
+
///////////////////////////////////////////////////////////////////////
|
128
|
+
|
129
|
+
#if defined(FIT_CONVERT_MULTI_THREAD)
|
130
|
+
const FIT_UINT8 *FitConvert_GetMessageData(FIT_CONVERT_STATE *state);
|
131
|
+
#else
|
132
|
+
const FIT_UINT8 *FitConvert_GetMessageData(void);
|
133
|
+
#endif
|
134
|
+
///////////////////////////////////////////////////////////////////////
|
135
|
+
// Returns a pointer to the data of the decoded message.
|
136
|
+
// Copy or cast to FIT_*_MESG structure.
|
137
|
+
///////////////////////////////////////////////////////////////////////
|
138
|
+
|
139
|
+
#if defined(FIT_CONVERT_MULTI_THREAD)
|
140
|
+
void FitConvert_RestoreFields(FIT_CONVERT_STATE *state, const void *mesg_data);
|
141
|
+
#else
|
142
|
+
void FitConvert_RestoreFields(const void *mesg_data);
|
143
|
+
#endif
|
144
|
+
///////////////////////////////////////////////////////////////////////
|
145
|
+
// Restores fields that are not in decoded message from mesg_data.
|
146
|
+
// Use when modifying an existing file.
|
147
|
+
///////////////////////////////////////////////////////////////////////
|
148
|
+
|
149
|
+
#if defined(__cplusplus)
|
150
|
+
}
|
151
|
+
#endif
|
152
|
+
|
153
|
+
#endif // !defined(FIT_CONVERT_H)
|
154
|
+
|
@@ -0,0 +1,43 @@
|
|
1
|
+
////////////////////////////////////////////////////////////////////////////////
|
2
|
+
// The following .FIT software provided may be used with .FIT devices only and
|
3
|
+
// remains the copyrighted property of Dynastream Innovations Inc.
|
4
|
+
// The software is being provided on an "as-is" basis and as an accommodation,
|
5
|
+
// and therefore all warranties, representations, or guarantees of any kind
|
6
|
+
// (whether express, implied or statutory) including, without limitation,
|
7
|
+
// warranties of merchantability, non-infringement, or fitness for a particular
|
8
|
+
// purpose, are specifically disclaimed.
|
9
|
+
//
|
10
|
+
// Copyright 2008 Dynastream Innovations Inc.
|
11
|
+
// All rights reserved. This software may not be reproduced by any means
|
12
|
+
// without express written approval of Dynastream Innovations Inc.
|
13
|
+
////////////////////////////////////////////////////////////////////////////////
|
14
|
+
|
15
|
+
#include "fit_crc.h"
|
16
|
+
|
17
|
+
//////////////////////////////////////////////////////////////////////////////////
|
18
|
+
// Public Functions
|
19
|
+
//////////////////////////////////////////////////////////////////////////////////
|
20
|
+
|
21
|
+
///////////////////////////////////////////////////////////////////////
|
22
|
+
FIT_UINT16 FitCRC_Get16(FIT_UINT16 crc, FIT_UINT8 byte)
|
23
|
+
{
|
24
|
+
static const FIT_UINT16 crc_table[16] =
|
25
|
+
{
|
26
|
+
0x0000, 0xCC01, 0xD801, 0x1400, 0xF001, 0x3C00, 0x2800, 0xE401,
|
27
|
+
0xA001, 0x6C00, 0x7800, 0xB401, 0x5000, 0x9C01, 0x8801, 0x4400
|
28
|
+
};
|
29
|
+
FIT_UINT16 tmp;
|
30
|
+
|
31
|
+
// compute checksum of lower four bits of byte
|
32
|
+
tmp = crc_table[crc & 0xF];
|
33
|
+
crc = (crc >> 4) & 0x0FFF;
|
34
|
+
crc = crc ^ tmp ^ crc_table[byte & 0xF];
|
35
|
+
|
36
|
+
// now compute checksum of upper four bits of byte
|
37
|
+
tmp = crc_table[crc & 0xF];
|
38
|
+
crc = (crc >> 4) & 0x0FFF;
|
39
|
+
crc = crc ^ tmp ^ crc_table[(byte >> 4) & 0xF];
|
40
|
+
|
41
|
+
return crc;
|
42
|
+
}
|
43
|
+
|