rubyfit 0.0.11 → 0.0.16
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.
- checksums.yaml +4 -4
- data/ext/rubyfit/fit.c +418 -412
- data/ext/rubyfit/fit.h +397 -380
- data/ext/rubyfit/fit_config.h +37 -36
- data/ext/rubyfit/fit_convert.c +619 -596
- data/ext/rubyfit/fit_convert.h +213 -203
- data/ext/rubyfit/fit_crc.c +67 -67
- data/ext/rubyfit/fit_crc.h +42 -42
- data/ext/rubyfit/fit_example.c +1512 -1431
- data/ext/rubyfit/fit_example.h +8000 -6147
- data/ext/rubyfit/fit_include.h +19 -19
- data/ext/rubyfit/fit_ram.c +211 -203
- data/ext/rubyfit/fit_ram.h +44 -39
- data/ext/rubyfit/rubyfit.c +560 -566
- data/lib/rubyfit/version.rb +1 -1
- metadata +3 -3
data/ext/rubyfit/fit_config.h
CHANGED
@@ -1,36 +1,37 @@
|
|
1
|
-
////////////////////////////////////////////////////////////////////////////////
|
2
|
-
// The following FIT Protocol software provided may be used with FIT protocol
|
3
|
-
// devices only and remains the copyrighted property of
|
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
|
11
|
-
////////////////////////////////////////////////////////////////////////////////
|
12
|
-
|
13
|
-
|
14
|
-
#if !defined(FIT_CONFIG_H)
|
15
|
-
#define FIT_CONFIG_H
|
16
|
-
|
17
|
-
|
18
|
-
#if defined(__cplusplus)
|
19
|
-
extern "C" {
|
20
|
-
#endif
|
21
|
-
|
22
|
-
#define FIT_USE_STDINT_H // Define to use stdint.h types. By default size in bytes of integer types assumed to be char=1, short=2, long=4.
|
23
|
-
|
24
|
-
#define FIT_LOCAL_MESGS 16 // 1-16. Sets maximum number of local messages that can be decoded. Lower to minimize RAM requirements.
|
25
|
-
#define FIT_ARCH_ENDIAN FIT_ARCH_ENDIAN_LITTLE // Set to correct endian for build architecture.
|
26
|
-
|
27
|
-
#define FIT_CONVERT_CHECK_CRC // Define to check file crc.
|
28
|
-
#define FIT_CONVERT_CHECK_FILE_HDR_DATA_TYPE // Define to check file header for FIT data type. Verifies file is FIT format before starting decode.
|
29
|
-
#define FIT_CONVERT_TIME_RECORD // Define to support time records (compressed timestamp).
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
1
|
+
////////////////////////////////////////////////////////////////////////////////
|
2
|
+
// The following FIT Protocol software provided may be used with FIT protocol
|
3
|
+
// devices only and remains the copyrighted property of Garmin Canada 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 2020 Garmin Canada Inc.
|
11
|
+
////////////////////////////////////////////////////////////////////////////////
|
12
|
+
|
13
|
+
|
14
|
+
#if !defined(FIT_CONFIG_H)
|
15
|
+
#define FIT_CONFIG_H
|
16
|
+
|
17
|
+
|
18
|
+
#if defined(__cplusplus)
|
19
|
+
extern "C" {
|
20
|
+
#endif
|
21
|
+
|
22
|
+
#define FIT_USE_STDINT_H // Define to use stdint.h types. By default size in bytes of integer types assumed to be char=1, short=2, long=4.
|
23
|
+
|
24
|
+
#define FIT_LOCAL_MESGS 16 // 1-16. Sets maximum number of local messages that can be decoded. Lower to minimize RAM requirements.
|
25
|
+
#define FIT_ARCH_ENDIAN FIT_ARCH_ENDIAN_LITTLE // Set to correct endian for build architecture.
|
26
|
+
|
27
|
+
#define FIT_CONVERT_CHECK_CRC // Define to check file crc.
|
28
|
+
#define FIT_CONVERT_CHECK_FILE_HDR_DATA_TYPE // Define to check file header for FIT data type. Verifies file is FIT format before starting decode.
|
29
|
+
#define FIT_CONVERT_TIME_RECORD // Define to support time records (compressed timestamp).
|
30
|
+
#define FIT_CONVERT_MULTI_THREAD // Define to support multiple conversion threads.
|
31
|
+
#define FIT_16BIT_MESG_LENGTH_SUPPORT
|
32
|
+
|
33
|
+
#if defined(__cplusplus)
|
34
|
+
}
|
35
|
+
#endif
|
36
|
+
|
37
|
+
#endif // !defined(FIT_CONFIG_H)
|
data/ext/rubyfit/fit_convert.c
CHANGED
@@ -1,596 +1,619 @@
|
|
1
|
-
////////////////////////////////////////////////////////////////////////////////
|
2
|
-
// The following FIT Protocol software provided may be used with FIT protocol
|
3
|
-
// devices only and remains the copyrighted property of
|
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
|
11
|
-
////////////////////////////////////////////////////////////////////////////////
|
12
|
-
// ****WARNING**** This file is auto-generated! Do NOT edit this file.
|
13
|
-
// Profile Version =
|
14
|
-
// Tag = production/akw/
|
15
|
-
// Product = EXAMPLE
|
16
|
-
// Alignment = 4 bytes, padding disabled.
|
17
|
-
////////////////////////////////////////////////////////////////////////////////
|
18
|
-
|
19
|
-
|
20
|
-
#include <string.h>
|
21
|
-
|
22
|
-
#include "fit_convert.h"
|
23
|
-
#include "fit_crc.h"
|
24
|
-
|
25
|
-
//////////////////////////////////////////////////////////////////////////////////
|
26
|
-
// Private Variables
|
27
|
-
//////////////////////////////////////////////////////////////////////////////////
|
28
|
-
|
29
|
-
#if !defined(FIT_CONVERT_MULTI_THREAD)
|
30
|
-
static FIT_CONVERT_STATE state_struct;
|
31
|
-
#define state (&state_struct)
|
32
|
-
#endif
|
33
|
-
|
34
|
-
//////////////////////////////////////////////////////////////////////////////////
|
35
|
-
// Public Functions
|
36
|
-
//////////////////////////////////////////////////////////////////////////////////
|
37
|
-
|
38
|
-
///////////////////////////////////////////////////////////////////////
|
39
|
-
#if defined(FIT_CONVERT_MULTI_THREAD)
|
40
|
-
void FitConvert_Init(FIT_CONVERT_STATE *state, FIT_BOOL read_file_header)
|
41
|
-
#else
|
42
|
-
void FitConvert_Init(FIT_BOOL read_file_header)
|
43
|
-
#endif
|
44
|
-
{
|
45
|
-
state->mesg_offset = 0;
|
46
|
-
state->data_offset = 0;
|
47
|
-
|
48
|
-
#if defined(FIT_CONVERT_CHECK_CRC)
|
49
|
-
state->crc = 0;
|
50
|
-
#endif
|
51
|
-
#if defined(FIT_CONVERT_TIME_RECORD)
|
52
|
-
state->timestamp = 0;
|
53
|
-
state->last_time_offset = 0;
|
54
|
-
#endif
|
55
|
-
|
56
|
-
if (read_file_header)
|
57
|
-
{
|
58
|
-
state->file_bytes_left = 3; // Header size byte + CRC.
|
59
|
-
state->decode_state = FIT_CONVERT_DECODE_FILE_HDR;
|
60
|
-
}
|
61
|
-
else
|
62
|
-
{
|
63
|
-
state->file_bytes_left = 0; // Don't read header or check CRC.
|
64
|
-
state->decode_state = FIT_CONVERT_DECODE_RECORD;
|
65
|
-
}
|
66
|
-
}
|
67
|
-
|
68
|
-
///////////////////////////////////////////////////////////////////////
|
69
|
-
#if defined(FIT_CONVERT_MULTI_THREAD)
|
70
|
-
FIT_CONVERT_RETURN FitConvert_Read(FIT_CONVERT_STATE *state, const void *data, FIT_UINT32 size)
|
71
|
-
#else
|
72
|
-
FIT_CONVERT_RETURN FitConvert_Read(const void *data, FIT_UINT32 size)
|
73
|
-
#endif
|
74
|
-
{
|
75
|
-
#if defined(FIT_CONVERT_MULTI_THREAD)
|
76
|
-
return FitConvert_ReadExt(state, data, size, FIT_FALSE);
|
77
|
-
#else
|
78
|
-
return FitConvert_ReadExt(data, size, FIT_FALSE);
|
79
|
-
#endif
|
80
|
-
}
|
81
|
-
|
82
|
-
///////////////////////////////////////////////////////////////////////
|
83
|
-
#if defined(FIT_CONVERT_MULTI_THREAD)
|
84
|
-
FIT_CONVERT_RETURN FitConvert_ReadExt(FIT_CONVERT_STATE *state, const void *data, FIT_UINT32 size, FIT_BOOL return_message_numbers)
|
85
|
-
#else
|
86
|
-
FIT_CONVERT_RETURN FitConvert_ReadExt(const void *data, FIT_UINT32 size, FIT_BOOL return_message_numbers)
|
87
|
-
#endif
|
88
|
-
{
|
89
|
-
while (state->data_offset < size)
|
90
|
-
{
|
91
|
-
FIT_UINT8 datum = *((FIT_UINT8 *) data + state->data_offset);
|
92
|
-
state->data_offset++;
|
93
|
-
|
94
|
-
//printf("fit_convert: 0x%02X - %d\n",datum, state->decode_state);
|
95
|
-
|
96
|
-
if (state->file_bytes_left > 0)
|
97
|
-
{
|
98
|
-
#if defined(FIT_CONVERT_CHECK_CRC)
|
99
|
-
state->crc = FitCRC_Get16(state->crc, datum);
|
100
|
-
#endif
|
101
|
-
|
102
|
-
state->file_bytes_left--;
|
103
|
-
|
104
|
-
if (state->file_bytes_left == 1) // CRC low byte.
|
105
|
-
{
|
106
|
-
if (state->decode_state != FIT_CONVERT_DECODE_RECORD)
|
107
|
-
return FIT_CONVERT_ERROR;
|
108
|
-
|
109
|
-
continue; // Next byte.
|
110
|
-
}
|
111
|
-
else if (state->file_bytes_left == 0) // CRC high byte.
|
112
|
-
{
|
113
|
-
#if defined(FIT_CONVERT_CHECK_CRC)
|
114
|
-
if (state->crc != 0)
|
115
|
-
return FIT_CONVERT_ERROR;
|
116
|
-
#endif
|
117
|
-
|
118
|
-
return FIT_CONVERT_END_OF_FILE;
|
119
|
-
}
|
120
|
-
}
|
121
|
-
|
122
|
-
switch (state->decode_state)
|
123
|
-
{
|
124
|
-
case FIT_CONVERT_DECODE_FILE_HDR:
|
125
|
-
if (state->mesg_offset < FIT_FILE_HDR_SIZE)
|
126
|
-
*((FIT_UINT8 *) &state->u.file_hdr + state->mesg_offset) = datum;
|
127
|
-
|
128
|
-
if (state->mesg_offset == 0)
|
129
|
-
state->file_bytes_left = state->u.file_hdr.header_size + 2; // Increase to read header and CRC.
|
130
|
-
|
131
|
-
state->mesg_offset++;
|
132
|
-
|
133
|
-
if (state->mesg_offset >= state->u.file_hdr.header_size)
|
134
|
-
{
|
135
|
-
state->file_bytes_left = *((FIT_UINT8 *) &state->u.file_hdr.data_size);
|
136
|
-
state->file_bytes_left |= (FIT_UINT32)*((FIT_UINT8 *) &state->u.file_hdr.data_size + 1) << 8;
|
137
|
-
state->file_bytes_left |= (FIT_UINT32)*((FIT_UINT8 *) &state->u.file_hdr.data_size + 2) << 16;
|
138
|
-
state->file_bytes_left |= (FIT_UINT32)*((FIT_UINT8 *) &state->u.file_hdr.data_size + 3) << 24;
|
139
|
-
state->file_bytes_left += 2; // CRC.
|
140
|
-
|
141
|
-
#if defined(FIT_CONVERT_CHECK_FILE_HDR_DATA_TYPE)
|
142
|
-
if (memcmp(state->u.file_hdr.data_type, ".FIT", 4) != 0)
|
143
|
-
return FIT_CONVERT_DATA_TYPE_NOT_SUPPORTED;
|
144
|
-
#endif
|
145
|
-
|
146
|
-
if (FIT_PROTOCOL_VERSION_MAJOR(state->u.file_hdr.protocol_version) >
|
147
|
-
FIT_PROTOCOL_VERSION_MAJOR(FIT_PROTOCOL_VERSION_MAX))
|
148
|
-
return FIT_CONVERT_PROTOCOL_VERSION_NOT_SUPPORTED;
|
149
|
-
|
150
|
-
state->decode_state = FIT_CONVERT_DECODE_RECORD;
|
151
|
-
}
|
152
|
-
break;
|
153
|
-
|
154
|
-
case FIT_CONVERT_DECODE_RECORD:
|
155
|
-
if (datum & FIT_HDR_TIME_REC_BIT)
|
156
|
-
{
|
157
|
-
// This is a message data record with time.
|
158
|
-
state->mesg_index = (datum & FIT_HDR_TIME_TYPE_MASK) >> FIT_HDR_TIME_TYPE_SHIFT;
|
159
|
-
|
160
|
-
#if defined(FIT_CONVERT_TIME_RECORD)
|
161
|
-
{
|
162
|
-
FIT_UINT8 time_offset = datum & FIT_HDR_TIME_OFFSET_MASK;
|
163
|
-
state->timestamp += (time_offset - state->last_time_offset) & FIT_HDR_TIME_OFFSET_MASK;
|
164
|
-
state->last_time_offset = time_offset;
|
165
|
-
}
|
166
|
-
#endif
|
167
|
-
|
168
|
-
state->decode_state = FIT_CONVERT_DECODE_FIELD_DATA;
|
169
|
-
}
|
170
|
-
else
|
171
|
-
{
|
172
|
-
state->mesg_index = datum & FIT_HDR_TYPE_MASK;
|
173
|
-
|
174
|
-
if ((datum & FIT_HDR_TYPE_DEF_BIT) == 0)
|
175
|
-
{
|
176
|
-
// This is a message data record.
|
177
|
-
state->decode_state = FIT_CONVERT_DECODE_FIELD_DATA;
|
178
|
-
}
|
179
|
-
else
|
180
|
-
{
|
181
|
-
state->has_dev_data = FIT_FALSE;
|
182
|
-
// This is a message definition record.
|
183
|
-
if ((datum & FIT_HDR_DEV_DATA_BIT) != 0)
|
184
|
-
{
|
185
|
-
// This message has Dev Data
|
186
|
-
state->has_dev_data = FIT_TRUE;
|
187
|
-
}
|
188
|
-
|
189
|
-
state->mesg_sizes[state->mesg_index] = 0;
|
190
|
-
state->dev_data_sizes[state->mesg_index] = 0;
|
191
|
-
state->decode_state = FIT_CONVERT_DECODE_RESERVED1;
|
192
|
-
}
|
193
|
-
}
|
194
|
-
|
195
|
-
if (state->decode_state == FIT_CONVERT_DECODE_FIELD_DATA)
|
196
|
-
{
|
197
|
-
if (state->mesg_index < FIT_LOCAL_MESGS)
|
198
|
-
{
|
199
|
-
state->mesg_def = Fit_GetMesgDef(state->convert_table[state->mesg_index].global_mesg_num);
|
200
|
-
Fit_InitMesg(state->mesg_def, state->u.mesg);
|
201
|
-
|
202
|
-
#if defined(FIT_CONVERT_TIME_RECORD)
|
203
|
-
if (datum & FIT_HDR_TIME_REC_BIT)
|
204
|
-
{
|
205
|
-
|
206
|
-
|
207
|
-
if (field_offset !=
|
208
|
-
memcpy(&state->u.mesg[field_offset], &state->timestamp, sizeof(state->timestamp));
|
209
|
-
}
|
210
|
-
#endif
|
211
|
-
}
|
212
|
-
|
213
|
-
if (state->mesg_sizes[state->mesg_index] == 0)
|
214
|
-
state->decode_state = FIT_CONVERT_DECODE_RECORD;
|
215
|
-
}
|
216
|
-
|
217
|
-
state->mesg_offset = 0; // Reset the message byte count.
|
218
|
-
state->field_index = 0;
|
219
|
-
state->field_offset = 0;
|
220
|
-
break;
|
221
|
-
|
222
|
-
case FIT_CONVERT_DECODE_RESERVED1:
|
223
|
-
if (state->mesg_index < FIT_LOCAL_MESGS)
|
224
|
-
state->convert_table[state->mesg_index].reserved_1 = datum;
|
225
|
-
|
226
|
-
state->decode_state = FIT_CONVERT_DECODE_ARCH;
|
227
|
-
break;
|
228
|
-
|
229
|
-
case FIT_CONVERT_DECODE_ARCH:
|
230
|
-
if (state->mesg_index < FIT_LOCAL_MESGS)
|
231
|
-
state->convert_table[state->mesg_index].arch = datum;
|
232
|
-
|
233
|
-
state->decode_state = FIT_CONVERT_DECODE_GTYPE_1;
|
234
|
-
break;
|
235
|
-
|
236
|
-
case FIT_CONVERT_DECODE_GTYPE_1:
|
237
|
-
if (state->mesg_index < FIT_LOCAL_MESGS)
|
238
|
-
state->convert_table[state->mesg_index].global_mesg_num = datum;
|
239
|
-
|
240
|
-
state->decode_state = FIT_CONVERT_DECODE_GTYPE_2;
|
241
|
-
break;
|
242
|
-
|
243
|
-
case FIT_CONVERT_DECODE_GTYPE_2:
|
244
|
-
if (state->mesg_index < FIT_LOCAL_MESGS)
|
245
|
-
{
|
246
|
-
if ((state->convert_table[state->mesg_index].arch & FIT_ARCH_ENDIAN_MASK) == FIT_ARCH_ENDIAN_BIG)
|
247
|
-
{
|
248
|
-
state->convert_table[state->mesg_index].global_mesg_num <<= 8;
|
249
|
-
state->convert_table[state->mesg_index].global_mesg_num |= datum;
|
250
|
-
}
|
251
|
-
else
|
252
|
-
{
|
253
|
-
state->convert_table[state->mesg_index].global_mesg_num |= ((FIT_UINT16) datum << 8);
|
254
|
-
}
|
255
|
-
|
256
|
-
state->convert_table[state->mesg_index].num_fields = 0; // Initialize.
|
257
|
-
state->mesg_def = Fit_GetMesgDef(state->convert_table[state->mesg_index].global_mesg_num);
|
258
|
-
}
|
259
|
-
|
260
|
-
state->decode_state = FIT_CONVERT_DECODE_NUM_FIELD_DEFS;
|
261
|
-
break;
|
262
|
-
|
263
|
-
case FIT_CONVERT_DECODE_NUM_FIELD_DEFS:
|
264
|
-
state->num_fields = datum;
|
265
|
-
|
266
|
-
if (state->num_fields == 0)
|
267
|
-
{
|
268
|
-
state->decode_state = state->has_dev_data ?
|
269
|
-
FIT_CONVERT_DECODE_NUM_DEV_FIELDS : FIT_CONVERT_DECODE_RECORD;
|
270
|
-
break;
|
271
|
-
}
|
272
|
-
|
273
|
-
state->field_index = 0;
|
274
|
-
state->decode_state = FIT_CONVERT_DECODE_FIELD_DEF;
|
275
|
-
|
276
|
-
//Return That a message number has been found (The user can then optionally over-ride the mesg_def property on the state object
|
277
|
-
//to use the alternate message definition if needed.
|
278
|
-
if ( return_message_numbers )
|
279
|
-
{
|
280
|
-
//When this event is received, the consuming application can call "FitConvert_SetMessageDefinition"
|
281
|
-
//to override the message definition to use (for alternate message definitions).
|
282
|
-
return FIT_CONVERT_MESSAGE_NUMBER_FOUND;
|
283
|
-
}
|
284
|
-
break;
|
285
|
-
|
286
|
-
case FIT_CONVERT_DECODE_FIELD_DEF:
|
287
|
-
state->field_num = FIT_FIELD_NUM_INVALID;
|
288
|
-
|
289
|
-
if (state->mesg_index < FIT_LOCAL_MESGS)
|
290
|
-
{
|
291
|
-
if (state->mesg_def != FIT_NULL)
|
292
|
-
{
|
293
|
-
FIT_UINT8 local_field_index;
|
294
|
-
|
295
|
-
|
296
|
-
// Search for the field definition in the local mesg definition.
|
297
|
-
for (local_field_index = 0; local_field_index < state->mesg_def->num_fields; local_field_index++)
|
298
|
-
{
|
299
|
-
FIT_UINT8 field_size = state->mesg_def->fields[FIT_MESG_DEF_FIELD_OFFSET(size, local_field_index)];
|
300
|
-
|
301
|
-
if (state->mesg_def->fields[FIT_MESG_DEF_FIELD_OFFSET(field_def_num, local_field_index)] == datum)
|
302
|
-
{
|
303
|
-
state->field_num = datum;
|
304
|
-
state->convert_table[state->mesg_index].fields[state->convert_table[state->mesg_index].num_fields].
|
305
|
-
state->convert_table[state->mesg_index].fields[state->convert_table[state->mesg_index].num_fields].
|
306
|
-
state->convert_table[state->mesg_index].fields[state->convert_table[state->mesg_index].num_fields].
|
307
|
-
|
308
|
-
|
309
|
-
|
310
|
-
|
311
|
-
|
312
|
-
|
313
|
-
|
314
|
-
|
315
|
-
|
316
|
-
|
317
|
-
|
318
|
-
|
319
|
-
|
320
|
-
|
321
|
-
|
322
|
-
|
323
|
-
|
324
|
-
|
325
|
-
|
326
|
-
|
327
|
-
|
328
|
-
|
329
|
-
|
330
|
-
|
331
|
-
|
332
|
-
|
333
|
-
|
334
|
-
|
335
|
-
|
336
|
-
|
337
|
-
|
338
|
-
|
339
|
-
state->convert_table[state->mesg_index].num_fields
|
340
|
-
|
341
|
-
|
342
|
-
|
343
|
-
|
344
|
-
|
345
|
-
|
346
|
-
|
347
|
-
|
348
|
-
|
349
|
-
|
350
|
-
|
351
|
-
|
352
|
-
|
353
|
-
|
354
|
-
|
355
|
-
|
356
|
-
|
357
|
-
|
358
|
-
|
359
|
-
|
360
|
-
|
361
|
-
|
362
|
-
|
363
|
-
|
364
|
-
|
365
|
-
state->
|
366
|
-
|
367
|
-
|
368
|
-
|
369
|
-
|
370
|
-
|
371
|
-
|
372
|
-
|
373
|
-
|
374
|
-
|
375
|
-
|
376
|
-
state->
|
377
|
-
|
378
|
-
|
379
|
-
|
380
|
-
|
381
|
-
|
382
|
-
|
383
|
-
|
384
|
-
|
385
|
-
|
386
|
-
|
387
|
-
|
388
|
-
|
389
|
-
|
390
|
-
|
391
|
-
|
392
|
-
|
393
|
-
|
394
|
-
|
395
|
-
|
396
|
-
|
397
|
-
|
398
|
-
|
399
|
-
|
400
|
-
|
401
|
-
|
402
|
-
|
403
|
-
|
404
|
-
|
405
|
-
|
406
|
-
|
407
|
-
|
408
|
-
|
409
|
-
|
410
|
-
|
411
|
-
|
412
|
-
|
413
|
-
|
414
|
-
state->field_offset
|
415
|
-
|
416
|
-
|
417
|
-
|
418
|
-
|
419
|
-
|
420
|
-
(
|
421
|
-
|
422
|
-
|
423
|
-
|
424
|
-
FIT_UINT8
|
425
|
-
FIT_UINT8
|
426
|
-
FIT_UINT8
|
427
|
-
|
428
|
-
|
429
|
-
|
430
|
-
|
431
|
-
|
432
|
-
|
433
|
-
|
434
|
-
|
435
|
-
|
436
|
-
|
437
|
-
|
438
|
-
|
439
|
-
|
440
|
-
|
441
|
-
|
442
|
-
field[element * type_size + type_size - 1 - index]
|
443
|
-
|
444
|
-
|
445
|
-
|
446
|
-
|
447
|
-
|
448
|
-
if
|
449
|
-
|
450
|
-
|
451
|
-
FIT_UINT8
|
452
|
-
|
453
|
-
|
454
|
-
|
455
|
-
|
456
|
-
FIT_UINT8
|
457
|
-
|
458
|
-
|
459
|
-
|
460
|
-
|
461
|
-
|
462
|
-
|
463
|
-
|
464
|
-
|
465
|
-
|
466
|
-
|
467
|
-
|
468
|
-
|
469
|
-
|
470
|
-
|
471
|
-
|
472
|
-
|
473
|
-
|
474
|
-
|
475
|
-
|
476
|
-
|
477
|
-
|
478
|
-
|
479
|
-
|
480
|
-
|
481
|
-
|
482
|
-
|
483
|
-
|
484
|
-
|
485
|
-
|
486
|
-
|
487
|
-
state->
|
488
|
-
|
489
|
-
|
490
|
-
|
491
|
-
|
492
|
-
|
493
|
-
|
494
|
-
|
495
|
-
|
496
|
-
|
497
|
-
|
498
|
-
|
499
|
-
|
500
|
-
state->
|
501
|
-
|
502
|
-
|
503
|
-
|
504
|
-
|
505
|
-
|
506
|
-
|
507
|
-
|
508
|
-
|
509
|
-
|
510
|
-
|
511
|
-
|
512
|
-
|
513
|
-
|
514
|
-
|
515
|
-
|
516
|
-
|
517
|
-
|
518
|
-
|
519
|
-
|
520
|
-
|
521
|
-
|
522
|
-
|
523
|
-
|
524
|
-
|
525
|
-
|
526
|
-
|
527
|
-
|
528
|
-
|
529
|
-
|
530
|
-
|
531
|
-
|
532
|
-
|
533
|
-
|
534
|
-
|
535
|
-
|
536
|
-
|
537
|
-
|
538
|
-
|
539
|
-
|
540
|
-
|
541
|
-
|
542
|
-
|
543
|
-
|
544
|
-
|
545
|
-
|
546
|
-
|
547
|
-
|
548
|
-
|
549
|
-
|
550
|
-
|
551
|
-
|
552
|
-
|
553
|
-
|
554
|
-
|
555
|
-
|
556
|
-
|
557
|
-
|
558
|
-
|
559
|
-
|
560
|
-
|
561
|
-
|
562
|
-
|
563
|
-
|
564
|
-
|
565
|
-
|
566
|
-
|
567
|
-
|
568
|
-
|
569
|
-
|
570
|
-
|
571
|
-
|
572
|
-
|
573
|
-
|
574
|
-
|
575
|
-
|
576
|
-
|
577
|
-
|
578
|
-
FIT_UINT8
|
579
|
-
|
580
|
-
|
581
|
-
|
582
|
-
|
583
|
-
|
584
|
-
|
585
|
-
|
586
|
-
|
587
|
-
|
588
|
-
|
589
|
-
|
590
|
-
|
591
|
-
|
592
|
-
|
593
|
-
|
594
|
-
|
595
|
-
|
596
|
-
}
|
1
|
+
////////////////////////////////////////////////////////////////////////////////
|
2
|
+
// The following FIT Protocol software provided may be used with FIT protocol
|
3
|
+
// devices only and remains the copyrighted property of Garmin Canada 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 2020 Garmin Canada Inc.
|
11
|
+
////////////////////////////////////////////////////////////////////////////////
|
12
|
+
// ****WARNING**** This file is auto-generated! Do NOT edit this file.
|
13
|
+
// Profile Version = 21.27Release
|
14
|
+
// Tag = production/akw/21.27.00-0-gef9575d
|
15
|
+
// Product = EXAMPLE
|
16
|
+
// Alignment = 4 bytes, padding disabled.
|
17
|
+
////////////////////////////////////////////////////////////////////////////////
|
18
|
+
|
19
|
+
|
20
|
+
#include <string.h>
|
21
|
+
|
22
|
+
#include "fit_convert.h"
|
23
|
+
#include "fit_crc.h"
|
24
|
+
|
25
|
+
//////////////////////////////////////////////////////////////////////////////////
|
26
|
+
// Private Variables
|
27
|
+
//////////////////////////////////////////////////////////////////////////////////
|
28
|
+
|
29
|
+
#if !defined(FIT_CONVERT_MULTI_THREAD)
|
30
|
+
static FIT_CONVERT_STATE state_struct;
|
31
|
+
#define state (&state_struct)
|
32
|
+
#endif
|
33
|
+
|
34
|
+
//////////////////////////////////////////////////////////////////////////////////
|
35
|
+
// Public Functions
|
36
|
+
//////////////////////////////////////////////////////////////////////////////////
|
37
|
+
|
38
|
+
///////////////////////////////////////////////////////////////////////
|
39
|
+
#if defined(FIT_CONVERT_MULTI_THREAD)
|
40
|
+
void FitConvert_Init(FIT_CONVERT_STATE *state, FIT_BOOL read_file_header)
|
41
|
+
#else
|
42
|
+
void FitConvert_Init(FIT_BOOL read_file_header)
|
43
|
+
#endif
|
44
|
+
{
|
45
|
+
state->mesg_offset = 0;
|
46
|
+
state->data_offset = 0;
|
47
|
+
|
48
|
+
#if defined(FIT_CONVERT_CHECK_CRC)
|
49
|
+
state->crc = 0;
|
50
|
+
#endif
|
51
|
+
#if defined(FIT_CONVERT_TIME_RECORD)
|
52
|
+
state->timestamp = 0;
|
53
|
+
state->last_time_offset = 0;
|
54
|
+
#endif
|
55
|
+
|
56
|
+
if (read_file_header)
|
57
|
+
{
|
58
|
+
state->file_bytes_left = 3; // Header size byte + CRC.
|
59
|
+
state->decode_state = FIT_CONVERT_DECODE_FILE_HDR;
|
60
|
+
}
|
61
|
+
else
|
62
|
+
{
|
63
|
+
state->file_bytes_left = 0; // Don't read header or check CRC.
|
64
|
+
state->decode_state = FIT_CONVERT_DECODE_RECORD;
|
65
|
+
}
|
66
|
+
}
|
67
|
+
|
68
|
+
///////////////////////////////////////////////////////////////////////
|
69
|
+
#if defined(FIT_CONVERT_MULTI_THREAD)
|
70
|
+
FIT_CONVERT_RETURN FitConvert_Read(FIT_CONVERT_STATE *state, const void *data, FIT_UINT32 size)
|
71
|
+
#else
|
72
|
+
FIT_CONVERT_RETURN FitConvert_Read(const void *data, FIT_UINT32 size)
|
73
|
+
#endif
|
74
|
+
{
|
75
|
+
#if defined(FIT_CONVERT_MULTI_THREAD)
|
76
|
+
return FitConvert_ReadExt(state, data, size, FIT_FALSE);
|
77
|
+
#else
|
78
|
+
return FitConvert_ReadExt(data, size, FIT_FALSE);
|
79
|
+
#endif
|
80
|
+
}
|
81
|
+
|
82
|
+
///////////////////////////////////////////////////////////////////////
|
83
|
+
#if defined(FIT_CONVERT_MULTI_THREAD)
|
84
|
+
FIT_CONVERT_RETURN FitConvert_ReadExt(FIT_CONVERT_STATE *state, const void *data, FIT_UINT32 size, FIT_BOOL return_message_numbers)
|
85
|
+
#else
|
86
|
+
FIT_CONVERT_RETURN FitConvert_ReadExt(const void *data, FIT_UINT32 size, FIT_BOOL return_message_numbers)
|
87
|
+
#endif
|
88
|
+
{
|
89
|
+
while (state->data_offset < size)
|
90
|
+
{
|
91
|
+
FIT_UINT8 datum = *((FIT_UINT8 *) data + state->data_offset);
|
92
|
+
state->data_offset++;
|
93
|
+
|
94
|
+
//printf("fit_convert: 0x%02X - %d\n",datum, state->decode_state);
|
95
|
+
|
96
|
+
if (state->file_bytes_left > 0)
|
97
|
+
{
|
98
|
+
#if defined(FIT_CONVERT_CHECK_CRC)
|
99
|
+
state->crc = FitCRC_Get16(state->crc, datum);
|
100
|
+
#endif
|
101
|
+
|
102
|
+
state->file_bytes_left--;
|
103
|
+
|
104
|
+
if (state->file_bytes_left == 1) // CRC low byte.
|
105
|
+
{
|
106
|
+
if (state->decode_state != FIT_CONVERT_DECODE_RECORD)
|
107
|
+
return FIT_CONVERT_ERROR;
|
108
|
+
|
109
|
+
continue; // Next byte.
|
110
|
+
}
|
111
|
+
else if (state->file_bytes_left == 0) // CRC high byte.
|
112
|
+
{
|
113
|
+
#if defined(FIT_CONVERT_CHECK_CRC)
|
114
|
+
if (state->crc != 0)
|
115
|
+
return FIT_CONVERT_ERROR;
|
116
|
+
#endif
|
117
|
+
|
118
|
+
return FIT_CONVERT_END_OF_FILE;
|
119
|
+
}
|
120
|
+
}
|
121
|
+
|
122
|
+
switch (state->decode_state)
|
123
|
+
{
|
124
|
+
case FIT_CONVERT_DECODE_FILE_HDR:
|
125
|
+
if (state->mesg_offset < FIT_FILE_HDR_SIZE)
|
126
|
+
*((FIT_UINT8 *) &state->u.file_hdr + state->mesg_offset) = datum;
|
127
|
+
|
128
|
+
if (state->mesg_offset == 0)
|
129
|
+
state->file_bytes_left = state->u.file_hdr.header_size + 2; // Increase to read header and CRC.
|
130
|
+
|
131
|
+
state->mesg_offset++;
|
132
|
+
|
133
|
+
if (state->mesg_offset >= state->u.file_hdr.header_size)
|
134
|
+
{
|
135
|
+
state->file_bytes_left = *((FIT_UINT8 *) &state->u.file_hdr.data_size);
|
136
|
+
state->file_bytes_left |= (FIT_UINT32)*((FIT_UINT8 *) &state->u.file_hdr.data_size + 1) << 8;
|
137
|
+
state->file_bytes_left |= (FIT_UINT32)*((FIT_UINT8 *) &state->u.file_hdr.data_size + 2) << 16;
|
138
|
+
state->file_bytes_left |= (FIT_UINT32)*((FIT_UINT8 *) &state->u.file_hdr.data_size + 3) << 24;
|
139
|
+
state->file_bytes_left += 2; // CRC.
|
140
|
+
|
141
|
+
#if defined(FIT_CONVERT_CHECK_FILE_HDR_DATA_TYPE)
|
142
|
+
if (memcmp(state->u.file_hdr.data_type, ".FIT", 4) != 0)
|
143
|
+
return FIT_CONVERT_DATA_TYPE_NOT_SUPPORTED;
|
144
|
+
#endif
|
145
|
+
|
146
|
+
if (FIT_PROTOCOL_VERSION_MAJOR(state->u.file_hdr.protocol_version) >
|
147
|
+
FIT_PROTOCOL_VERSION_MAJOR(FIT_PROTOCOL_VERSION_MAX))
|
148
|
+
return FIT_CONVERT_PROTOCOL_VERSION_NOT_SUPPORTED;
|
149
|
+
|
150
|
+
state->decode_state = FIT_CONVERT_DECODE_RECORD;
|
151
|
+
}
|
152
|
+
break;
|
153
|
+
|
154
|
+
case FIT_CONVERT_DECODE_RECORD:
|
155
|
+
if (datum & FIT_HDR_TIME_REC_BIT)
|
156
|
+
{
|
157
|
+
// This is a message data record with time.
|
158
|
+
state->mesg_index = (datum & FIT_HDR_TIME_TYPE_MASK) >> FIT_HDR_TIME_TYPE_SHIFT;
|
159
|
+
|
160
|
+
#if defined(FIT_CONVERT_TIME_RECORD)
|
161
|
+
{
|
162
|
+
FIT_UINT8 time_offset = datum & FIT_HDR_TIME_OFFSET_MASK;
|
163
|
+
state->timestamp += (time_offset - state->last_time_offset) & FIT_HDR_TIME_OFFSET_MASK;
|
164
|
+
state->last_time_offset = time_offset;
|
165
|
+
}
|
166
|
+
#endif
|
167
|
+
|
168
|
+
state->decode_state = FIT_CONVERT_DECODE_FIELD_DATA;
|
169
|
+
}
|
170
|
+
else
|
171
|
+
{
|
172
|
+
state->mesg_index = datum & FIT_HDR_TYPE_MASK;
|
173
|
+
|
174
|
+
if ((datum & FIT_HDR_TYPE_DEF_BIT) == 0)
|
175
|
+
{
|
176
|
+
// This is a message data record.
|
177
|
+
state->decode_state = FIT_CONVERT_DECODE_FIELD_DATA;
|
178
|
+
}
|
179
|
+
else
|
180
|
+
{
|
181
|
+
state->has_dev_data = FIT_FALSE;
|
182
|
+
// This is a message definition record.
|
183
|
+
if ((datum & FIT_HDR_DEV_DATA_BIT) != 0)
|
184
|
+
{
|
185
|
+
// This message has Dev Data
|
186
|
+
state->has_dev_data = FIT_TRUE;
|
187
|
+
}
|
188
|
+
|
189
|
+
state->mesg_sizes[state->mesg_index] = 0;
|
190
|
+
state->dev_data_sizes[state->mesg_index] = 0;
|
191
|
+
state->decode_state = FIT_CONVERT_DECODE_RESERVED1;
|
192
|
+
}
|
193
|
+
}
|
194
|
+
|
195
|
+
if (state->decode_state == FIT_CONVERT_DECODE_FIELD_DATA)
|
196
|
+
{
|
197
|
+
if (state->mesg_index < FIT_LOCAL_MESGS)
|
198
|
+
{
|
199
|
+
state->mesg_def = Fit_GetMesgDef(state->convert_table[state->mesg_index].global_mesg_num);
|
200
|
+
Fit_InitMesg(state->mesg_def, state->u.mesg);
|
201
|
+
|
202
|
+
#if defined(FIT_CONVERT_TIME_RECORD)
|
203
|
+
if (datum & FIT_HDR_TIME_REC_BIT)
|
204
|
+
{
|
205
|
+
FIT_UINT16 field_offset = Fit_GetFieldOffset(state->mesg_def, FIT_FIELD_NUM_TIMESTAMP);
|
206
|
+
|
207
|
+
if (field_offset != FIT_UINT16_INVALID)
|
208
|
+
memcpy(&state->u.mesg[field_offset], &state->timestamp, sizeof(state->timestamp));
|
209
|
+
}
|
210
|
+
#endif
|
211
|
+
}
|
212
|
+
|
213
|
+
if (state->mesg_sizes[state->mesg_index] == 0)
|
214
|
+
state->decode_state = FIT_CONVERT_DECODE_RECORD;
|
215
|
+
}
|
216
|
+
|
217
|
+
state->mesg_offset = 0; // Reset the message byte count.
|
218
|
+
state->field_index = 0;
|
219
|
+
state->field_offset = 0;
|
220
|
+
break;
|
221
|
+
|
222
|
+
case FIT_CONVERT_DECODE_RESERVED1:
|
223
|
+
if (state->mesg_index < FIT_LOCAL_MESGS)
|
224
|
+
state->convert_table[state->mesg_index].reserved_1 = datum;
|
225
|
+
|
226
|
+
state->decode_state = FIT_CONVERT_DECODE_ARCH;
|
227
|
+
break;
|
228
|
+
|
229
|
+
case FIT_CONVERT_DECODE_ARCH:
|
230
|
+
if (state->mesg_index < FIT_LOCAL_MESGS)
|
231
|
+
state->convert_table[state->mesg_index].arch = datum;
|
232
|
+
|
233
|
+
state->decode_state = FIT_CONVERT_DECODE_GTYPE_1;
|
234
|
+
break;
|
235
|
+
|
236
|
+
case FIT_CONVERT_DECODE_GTYPE_1:
|
237
|
+
if (state->mesg_index < FIT_LOCAL_MESGS)
|
238
|
+
state->convert_table[state->mesg_index].global_mesg_num = datum;
|
239
|
+
|
240
|
+
state->decode_state = FIT_CONVERT_DECODE_GTYPE_2;
|
241
|
+
break;
|
242
|
+
|
243
|
+
case FIT_CONVERT_DECODE_GTYPE_2:
|
244
|
+
if (state->mesg_index < FIT_LOCAL_MESGS)
|
245
|
+
{
|
246
|
+
if ((state->convert_table[state->mesg_index].arch & FIT_ARCH_ENDIAN_MASK) == FIT_ARCH_ENDIAN_BIG)
|
247
|
+
{
|
248
|
+
state->convert_table[state->mesg_index].global_mesg_num <<= 8;
|
249
|
+
state->convert_table[state->mesg_index].global_mesg_num |= datum;
|
250
|
+
}
|
251
|
+
else
|
252
|
+
{
|
253
|
+
state->convert_table[state->mesg_index].global_mesg_num |= ((FIT_UINT16) datum << 8);
|
254
|
+
}
|
255
|
+
|
256
|
+
state->convert_table[state->mesg_index].num_fields = 0; // Initialize.
|
257
|
+
state->mesg_def = Fit_GetMesgDef(state->convert_table[state->mesg_index].global_mesg_num);
|
258
|
+
}
|
259
|
+
|
260
|
+
state->decode_state = FIT_CONVERT_DECODE_NUM_FIELD_DEFS;
|
261
|
+
break;
|
262
|
+
|
263
|
+
case FIT_CONVERT_DECODE_NUM_FIELD_DEFS:
|
264
|
+
state->num_fields = datum;
|
265
|
+
|
266
|
+
if (state->num_fields == 0)
|
267
|
+
{
|
268
|
+
state->decode_state = state->has_dev_data ?
|
269
|
+
FIT_CONVERT_DECODE_NUM_DEV_FIELDS : FIT_CONVERT_DECODE_RECORD;
|
270
|
+
break;
|
271
|
+
}
|
272
|
+
|
273
|
+
state->field_index = 0;
|
274
|
+
state->decode_state = FIT_CONVERT_DECODE_FIELD_DEF;
|
275
|
+
|
276
|
+
//Return That a message number has been found (The user can then optionally over-ride the mesg_def property on the state object
|
277
|
+
//to use the alternate message definition if needed.
|
278
|
+
if ( return_message_numbers )
|
279
|
+
{
|
280
|
+
//When this event is received, the consuming application can call "FitConvert_SetMessageDefinition"
|
281
|
+
//to override the message definition to use (for alternate message definitions).
|
282
|
+
return FIT_CONVERT_MESSAGE_NUMBER_FOUND;
|
283
|
+
}
|
284
|
+
break;
|
285
|
+
|
286
|
+
case FIT_CONVERT_DECODE_FIELD_DEF:
|
287
|
+
state->field_num = FIT_FIELD_NUM_INVALID;
|
288
|
+
|
289
|
+
if (state->mesg_index < FIT_LOCAL_MESGS)
|
290
|
+
{
|
291
|
+
if (state->mesg_def != FIT_NULL)
|
292
|
+
{
|
293
|
+
FIT_UINT8 local_field_index;
|
294
|
+
FIT_UINT16 local_field_offset = 0;
|
295
|
+
|
296
|
+
// Search for the field definition in the local mesg definition.
|
297
|
+
for (local_field_index = 0; local_field_index < state->mesg_def->num_fields; local_field_index++)
|
298
|
+
{
|
299
|
+
FIT_UINT8 field_size = state->mesg_def->fields[FIT_MESG_DEF_FIELD_OFFSET(size, local_field_index)];
|
300
|
+
|
301
|
+
if (state->mesg_def->fields[FIT_MESG_DEF_FIELD_OFFSET(field_def_num, local_field_index)] == datum)
|
302
|
+
{
|
303
|
+
state->field_num = datum;
|
304
|
+
state->convert_table[state->mesg_index].fields[state->convert_table[state->mesg_index].num_fields].num = state->field_num;
|
305
|
+
state->convert_table[state->mesg_index].fields[state->convert_table[state->mesg_index].num_fields].offset_in = state->mesg_offset;
|
306
|
+
state->convert_table[state->mesg_index].fields[state->convert_table[state->mesg_index].num_fields].offset_local = local_field_offset;
|
307
|
+
state->convert_table[state->mesg_index].fields[state->convert_table[state->mesg_index].num_fields].size = field_size;
|
308
|
+
break;
|
309
|
+
}
|
310
|
+
|
311
|
+
local_field_offset += field_size;
|
312
|
+
}
|
313
|
+
}
|
314
|
+
}
|
315
|
+
|
316
|
+
state->decode_state = FIT_CONVERT_DECODE_FIELD_DEF_SIZE;
|
317
|
+
break;
|
318
|
+
|
319
|
+
case FIT_CONVERT_DECODE_FIELD_DEF_SIZE:
|
320
|
+
if (state->mesg_index < FIT_LOCAL_MESGS)
|
321
|
+
{
|
322
|
+
state->mesg_offset += datum;
|
323
|
+
|
324
|
+
if (state->field_num != FIT_FIELD_NUM_INVALID)
|
325
|
+
{
|
326
|
+
if (datum < state->convert_table[state->mesg_index].fields[state->convert_table[state->mesg_index].num_fields].size)
|
327
|
+
state->convert_table[state->mesg_index].fields[state->convert_table[state->mesg_index].num_fields].size = datum;
|
328
|
+
}
|
329
|
+
|
330
|
+
state->mesg_sizes[state->mesg_index] += datum;
|
331
|
+
}
|
332
|
+
|
333
|
+
state->decode_state = FIT_CONVERT_DECODE_FIELD_BASE_TYPE;
|
334
|
+
break;
|
335
|
+
|
336
|
+
case FIT_CONVERT_DECODE_FIELD_BASE_TYPE:
|
337
|
+
if (state->field_num != FIT_FIELD_NUM_INVALID)
|
338
|
+
{
|
339
|
+
state->convert_table[state->mesg_index].fields[state->convert_table[state->mesg_index].num_fields].base_type = datum;
|
340
|
+
state->convert_table[state->mesg_index].num_fields++;
|
341
|
+
}
|
342
|
+
|
343
|
+
state->field_index++;
|
344
|
+
|
345
|
+
if (state->field_index >= state->num_fields)
|
346
|
+
{
|
347
|
+
state->decode_state = state->has_dev_data ?
|
348
|
+
FIT_CONVERT_DECODE_NUM_DEV_FIELDS : FIT_CONVERT_DECODE_RECORD;
|
349
|
+
}
|
350
|
+
else
|
351
|
+
{
|
352
|
+
state->decode_state = FIT_CONVERT_DECODE_FIELD_DEF;
|
353
|
+
}
|
354
|
+
break;
|
355
|
+
|
356
|
+
case FIT_CONVERT_DECODE_NUM_DEV_FIELDS:
|
357
|
+
state->num_fields = datum;
|
358
|
+
|
359
|
+
if (state->num_fields == 0)
|
360
|
+
{
|
361
|
+
state->decode_state = FIT_CONVERT_DECODE_RECORD;
|
362
|
+
break;
|
363
|
+
}
|
364
|
+
|
365
|
+
state->field_index = 0;
|
366
|
+
state->decode_state = FIT_CONVERT_DECODE_DEV_FIELD_DEF;
|
367
|
+
break;
|
368
|
+
|
369
|
+
case FIT_CONVERT_DECODE_DEV_FIELD_DEF:
|
370
|
+
// Doesn't matter yet
|
371
|
+
state->decode_state = FIT_CONVERT_DECODE_DEV_FIELD_SIZE;
|
372
|
+
break;
|
373
|
+
|
374
|
+
case FIT_CONVERT_DECODE_DEV_FIELD_SIZE:
|
375
|
+
// Just keep track of the amount of data that we need to ignore
|
376
|
+
state->dev_data_sizes[state->mesg_index] += datum;
|
377
|
+
state->decode_state = FIT_CONVERT_DECODE_DEV_FIELD_INDEX;
|
378
|
+
break;
|
379
|
+
|
380
|
+
case FIT_CONVERT_DECODE_DEV_FIELD_INDEX:
|
381
|
+
// Increment the number of fields that we have read
|
382
|
+
state->field_index++;
|
383
|
+
|
384
|
+
if (state->field_index >= state->num_fields)
|
385
|
+
state->decode_state = FIT_CONVERT_DECODE_RECORD;
|
386
|
+
else
|
387
|
+
state->decode_state = FIT_CONVERT_DECODE_DEV_FIELD_DEF;
|
388
|
+
break;
|
389
|
+
|
390
|
+
case FIT_CONVERT_DECODE_FIELD_DATA:
|
391
|
+
state->mesg_offset++;
|
392
|
+
|
393
|
+
if (state->mesg_offset >= state->mesg_sizes[state->mesg_index])
|
394
|
+
{
|
395
|
+
if (state->dev_data_sizes[state->mesg_index] > 0)
|
396
|
+
{
|
397
|
+
// There is dev data to read
|
398
|
+
state->decode_state = FIT_CONVERT_DECODE_DEV_FIELD_DATA;
|
399
|
+
}
|
400
|
+
else
|
401
|
+
{
|
402
|
+
state->decode_state = FIT_CONVERT_DECODE_RECORD;
|
403
|
+
}
|
404
|
+
}
|
405
|
+
|
406
|
+
if (state->mesg_index < FIT_LOCAL_MESGS)
|
407
|
+
{
|
408
|
+
if ((state->mesg_def != FIT_NULL) && (state->field_index < state->convert_table[state->mesg_index].num_fields))
|
409
|
+
{
|
410
|
+
if (state->mesg_offset == (state->convert_table[state->mesg_index].fields[state->field_index].offset_in + state->field_offset + 1))
|
411
|
+
{
|
412
|
+
FIT_UINT8 *field = &state->u.mesg[state->convert_table[state->mesg_index].fields[state->field_index].offset_local];
|
413
|
+
|
414
|
+
field[state->field_offset] = datum; // Store the incoming byte in the local mesg buffer.
|
415
|
+
state->field_offset++;
|
416
|
+
|
417
|
+
if (state->field_offset >= state->convert_table[state->mesg_index].fields[state->field_index].size)
|
418
|
+
{
|
419
|
+
if (
|
420
|
+
(state->convert_table[state->mesg_index].fields[state->field_index].base_type & FIT_BASE_TYPE_ENDIAN_FLAG) &&
|
421
|
+
((state->convert_table[state->mesg_index].arch & FIT_ARCH_ENDIAN_MASK) != (Fit_GetArch() & FIT_ARCH_ENDIAN_MASK))
|
422
|
+
)
|
423
|
+
{
|
424
|
+
FIT_UINT8 type_size;
|
425
|
+
FIT_UINT8 element_size;
|
426
|
+
FIT_UINT8 element;
|
427
|
+
FIT_UINT8 index;
|
428
|
+
|
429
|
+
index = state->convert_table[state->mesg_index].fields[state->field_index].base_type & FIT_BASE_TYPE_NUM_MASK;
|
430
|
+
|
431
|
+
if (index >= FIT_BASE_TYPES)
|
432
|
+
return FIT_CONVERT_ERROR;
|
433
|
+
|
434
|
+
type_size = fit_base_type_sizes[index];
|
435
|
+
element_size = state->convert_table[state->mesg_index].fields[state->field_index].size / type_size;
|
436
|
+
|
437
|
+
for (element = 0; element < element_size; element++)
|
438
|
+
{
|
439
|
+
for (index = 0; index < (type_size / 2); index++)
|
440
|
+
{
|
441
|
+
FIT_UINT8 tmp = field[element * type_size + index];
|
442
|
+
field[element * type_size + index] = field[element * type_size + type_size - 1 - index];
|
443
|
+
field[element * type_size + type_size - 1 - index] = tmp;
|
444
|
+
}
|
445
|
+
}
|
446
|
+
}
|
447
|
+
|
448
|
+
// Null terminate last character if multi-byte beyond end of field.
|
449
|
+
if (state->convert_table[state->mesg_index].fields[state->field_index].base_type == FIT_BASE_TYPE_STRING)
|
450
|
+
{
|
451
|
+
FIT_UINT8 length = state->convert_table[state->mesg_index].fields[state->field_index].size;
|
452
|
+
FIT_UINT8 index = 0;
|
453
|
+
|
454
|
+
while (index < length)
|
455
|
+
{
|
456
|
+
FIT_UINT8 char_size;
|
457
|
+
FIT_UINT8 size_mask = 0x80;
|
458
|
+
|
459
|
+
if (field[index] & size_mask)
|
460
|
+
{
|
461
|
+
char_size = 0;
|
462
|
+
|
463
|
+
while (field[index] & size_mask) // # of bytes in character = # of MSBits
|
464
|
+
{
|
465
|
+
char_size++;
|
466
|
+
size_mask >>= 1;
|
467
|
+
}
|
468
|
+
}
|
469
|
+
else
|
470
|
+
{
|
471
|
+
char_size = 1;
|
472
|
+
}
|
473
|
+
|
474
|
+
if ((FIT_UINT16)(index + char_size) > length)
|
475
|
+
{
|
476
|
+
while (index < length)
|
477
|
+
{
|
478
|
+
field[index++] = 0;
|
479
|
+
}
|
480
|
+
break;
|
481
|
+
}
|
482
|
+
|
483
|
+
index += char_size;
|
484
|
+
}
|
485
|
+
}
|
486
|
+
|
487
|
+
state->field_offset = 0; // Reset the offset.
|
488
|
+
state->field_index++; // Move on to the next field.
|
489
|
+
|
490
|
+
if (state->field_index >= state->convert_table[state->mesg_index].num_fields)
|
491
|
+
{
|
492
|
+
#if defined(FIT_CONVERT_TIME_RECORD)
|
493
|
+
{
|
494
|
+
FIT_UINT16 timestamp_offset = Fit_GetFieldOffset(state->mesg_def, FIT_FIELD_NUM_TIMESTAMP);
|
495
|
+
|
496
|
+
if (timestamp_offset != FIT_UINT16_INVALID)
|
497
|
+
{
|
498
|
+
if (*((FIT_UINT32 *)&state->u.mesg[timestamp_offset]) != FIT_DATE_TIME_INVALID)
|
499
|
+
{
|
500
|
+
memcpy(&state->timestamp, &state->u.mesg[timestamp_offset], sizeof(state->timestamp));
|
501
|
+
state->last_time_offset = (FIT_UINT8)(state->timestamp & FIT_HDR_TIME_OFFSET_MASK);
|
502
|
+
}
|
503
|
+
}
|
504
|
+
}
|
505
|
+
#endif
|
506
|
+
|
507
|
+
state->field_index = 0;
|
508
|
+
if ( state->dev_data_sizes[state->mesg_index] == 0 )
|
509
|
+
{
|
510
|
+
// We have successfully decoded a mesg and there is no dev data to read.
|
511
|
+
return FIT_CONVERT_MESSAGE_AVAILABLE;
|
512
|
+
}
|
513
|
+
}
|
514
|
+
}
|
515
|
+
}
|
516
|
+
}
|
517
|
+
}
|
518
|
+
break;
|
519
|
+
|
520
|
+
case FIT_CONVERT_DECODE_DEV_FIELD_DATA:
|
521
|
+
state->field_offset++;
|
522
|
+
if (state->field_offset >= state->dev_data_sizes[state->mesg_index])
|
523
|
+
{
|
524
|
+
// Done Parsing Dev Field Data
|
525
|
+
state->decode_state = FIT_CONVERT_DECODE_RECORD;
|
526
|
+
|
527
|
+
// We have successfully decoded a mesg and there is no dev data to read.
|
528
|
+
return FIT_CONVERT_MESSAGE_AVAILABLE;
|
529
|
+
}
|
530
|
+
break;
|
531
|
+
|
532
|
+
default:
|
533
|
+
// This shouldn't happen.
|
534
|
+
return FIT_CONVERT_ERROR;
|
535
|
+
}
|
536
|
+
}
|
537
|
+
|
538
|
+
state->data_offset = 0;
|
539
|
+
return FIT_CONVERT_CONTINUE;
|
540
|
+
}
|
541
|
+
|
542
|
+
///////////////////////////////////////////////////////////////////////
|
543
|
+
#if !defined(FIT_CONVERT_MULTI_THREAD)
|
544
|
+
void FitConvert_SetMessageDefinition(FIT_MESG_DEF *mesg_def)
|
545
|
+
{
|
546
|
+
state->mesg_def = mesg_def;
|
547
|
+
}
|
548
|
+
#endif
|
549
|
+
|
550
|
+
///////////////////////////////////////////////////////////////////////
|
551
|
+
#if defined(FIT_CONVERT_MULTI_THREAD)
|
552
|
+
FIT_UINT16 FitConvert_GetMessageNumber(FIT_CONVERT_STATE *state)
|
553
|
+
#else
|
554
|
+
FIT_UINT16 FitConvert_GetMessageNumber(void)
|
555
|
+
#endif
|
556
|
+
{
|
557
|
+
return state->convert_table[state->mesg_index].global_mesg_num;
|
558
|
+
}
|
559
|
+
|
560
|
+
///////////////////////////////////////////////////////////////////////
|
561
|
+
#if defined(FIT_CONVERT_MULTI_THREAD)
|
562
|
+
const FIT_UINT8 *FitConvert_GetMessageData(FIT_CONVERT_STATE *state)
|
563
|
+
#else
|
564
|
+
const FIT_UINT8 *FitConvert_GetMessageData(void)
|
565
|
+
#endif
|
566
|
+
{
|
567
|
+
return state->u.mesg;
|
568
|
+
}
|
569
|
+
|
570
|
+
///////////////////////////////////////////////////////////////////////
|
571
|
+
#if defined(FIT_CONVERT_MULTI_THREAD)
|
572
|
+
void FitConvert_RestoreFields(FIT_CONVERT_STATE *state, const void *mesg)
|
573
|
+
#else
|
574
|
+
void FitConvert_RestoreFields(const void *mesg)
|
575
|
+
#endif
|
576
|
+
{
|
577
|
+
FIT_UINT16 offset = 0;
|
578
|
+
FIT_UINT8 field_index;
|
579
|
+
FIT_UINT8 convert_field;
|
580
|
+
|
581
|
+
if (state->mesg_def == FIT_NULL)
|
582
|
+
return;
|
583
|
+
|
584
|
+
for (field_index = 0; field_index < state->mesg_def->num_fields; field_index++)
|
585
|
+
{
|
586
|
+
for (convert_field=0; convert_field < state->convert_table[state->mesg_index].num_fields; convert_field++)
|
587
|
+
{
|
588
|
+
if (state->convert_table[state->mesg_index].fields[convert_field].offset_local == offset)
|
589
|
+
break;
|
590
|
+
}
|
591
|
+
|
592
|
+
if (convert_field == state->convert_table[state->mesg_index].num_fields)
|
593
|
+
memcpy(&state->u.mesg[offset], &((FIT_UINT8 *)mesg)[offset], state->mesg_def->fields[FIT_MESG_DEF_FIELD_OFFSET(size, field_index)]);
|
594
|
+
|
595
|
+
offset += state->mesg_def->fields[FIT_MESG_DEF_FIELD_OFFSET(size, field_index)];
|
596
|
+
}
|
597
|
+
}
|
598
|
+
|
599
|
+
///////////////////////////////////////////////////////////////////////
|
600
|
+
#if defined(FIT_CONVERT_MULTI_THREAD)
|
601
|
+
FIT_UINT8 FitConvert_GetFieldSize(FIT_CONVERT_STATE *state, FIT_UINT8 field_num)
|
602
|
+
#else
|
603
|
+
FIT_UINT8 FitConvert_GetFieldSize(FIT_UINT8 field_num)
|
604
|
+
#endif
|
605
|
+
{
|
606
|
+
FIT_UINT8 field_index = 0;
|
607
|
+
|
608
|
+
while( state->convert_table[state->mesg_index].fields[field_index].num != field_num )
|
609
|
+
{
|
610
|
+
field_index++;
|
611
|
+
|
612
|
+
if( field_index >= state->convert_table[state->mesg_index].num_fields )
|
613
|
+
{
|
614
|
+
return 0; // Field not found
|
615
|
+
}
|
616
|
+
}
|
617
|
+
|
618
|
+
return state->convert_table[state->mesg_index].fields[field_index].size;
|
619
|
+
}
|