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.
@@ -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 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 2016 Dynastream Innovations 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
-
32
- #if defined(__cplusplus)
33
- }
34
- #endif
35
-
36
- #endif // !defined(FIT_CONFIG_H)
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)
@@ -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 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 2016 Dynastream Innovations Inc.
11
- ////////////////////////////////////////////////////////////////////////////////
12
- // ****WARNING**** This file is auto-generated! Do NOT edit this file.
13
- // Profile Version = 20.16Release
14
- // Tag = production/akw/20.16.00-0-gce20b51
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_UINT8 field_offset = Fit_GetFieldOffset(state->mesg_def, FIT_FIELD_NUM_TIMESTAMP);
206
-
207
- if (field_offset != FIT_UINT8_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_UINT8 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].offset_in = state->mesg_offset;
305
- state->convert_table[state->mesg_index].fields[state->convert_table[state->mesg_index].num_fields].offset_local = local_field_offset;
306
- state->convert_table[state->mesg_index].fields[state->convert_table[state->mesg_index].num_fields].size = field_size;
307
- break;
308
- }
309
-
310
- local_field_offset += field_size;
311
- }
312
- }
313
- }
314
-
315
- state->decode_state = FIT_CONVERT_DECODE_FIELD_DEF_SIZE;
316
- break;
317
-
318
- case FIT_CONVERT_DECODE_FIELD_DEF_SIZE:
319
- if (state->mesg_index < FIT_LOCAL_MESGS)
320
- {
321
- state->mesg_offset += datum;
322
-
323
- if (state->field_num != FIT_FIELD_NUM_INVALID)
324
- {
325
- if (datum < state->convert_table[state->mesg_index].fields[state->convert_table[state->mesg_index].num_fields].size)
326
- state->convert_table[state->mesg_index].fields[state->convert_table[state->mesg_index].num_fields].size = datum;
327
- }
328
-
329
- state->mesg_sizes[state->mesg_index] += datum;
330
- }
331
-
332
- state->decode_state = FIT_CONVERT_DECODE_FIELD_BASE_TYPE;
333
- break;
334
-
335
- case FIT_CONVERT_DECODE_FIELD_BASE_TYPE:
336
- if (state->field_num != FIT_FIELD_NUM_INVALID)
337
- {
338
- state->convert_table[state->mesg_index].fields[state->convert_table[state->mesg_index].num_fields].base_type = datum;
339
- state->convert_table[state->mesg_index].num_fields++;
340
- }
341
-
342
- state->field_index++;
343
-
344
- if (state->field_index >= state->num_fields)
345
- {
346
- state->decode_state = state->has_dev_data ?
347
- FIT_CONVERT_DECODE_NUM_DEV_FIELDS : FIT_CONVERT_DECODE_RECORD;
348
- }
349
- else
350
- {
351
- state->decode_state = FIT_CONVERT_DECODE_FIELD_DEF;
352
- }
353
- break;
354
-
355
- case FIT_CONVERT_DECODE_NUM_DEV_FIELDS:
356
- state->num_fields = datum;
357
-
358
- if (state->num_fields == 0)
359
- {
360
- state->decode_state = FIT_CONVERT_DECODE_RECORD;
361
- break;
362
- }
363
-
364
- state->field_index = 0;
365
- state->decode_state = FIT_CONVERT_DECODE_DEV_FIELD_DEF;
366
- break;
367
-
368
- case FIT_CONVERT_DECODE_DEV_FIELD_DEF:
369
- // Doesn't matter yet
370
- state->decode_state = FIT_CONVERT_DECODE_DEV_FIELD_SIZE;
371
- break;
372
-
373
- case FIT_CONVERT_DECODE_DEV_FIELD_SIZE:
374
- // Just keep track of the amount of data that we need to ignore
375
- state->dev_data_sizes[state->mesg_index] += datum;
376
- state->decode_state = FIT_CONVERT_DECODE_DEV_FIELD_INDEX;
377
- break;
378
-
379
- case FIT_CONVERT_DECODE_DEV_FIELD_INDEX:
380
- // Increment the number of fields that we have read
381
- state->field_index++;
382
-
383
- if (state->field_index >= state->num_fields)
384
- state->decode_state = FIT_CONVERT_DECODE_RECORD;
385
- else
386
- state->decode_state = FIT_CONVERT_DECODE_DEV_FIELD_DEF;
387
- break;
388
-
389
- case FIT_CONVERT_DECODE_FIELD_DATA:
390
- state->mesg_offset++;
391
-
392
- if (state->mesg_offset >= state->mesg_sizes[state->mesg_index])
393
- {
394
- if (state->dev_data_sizes[state->mesg_index] > 0)
395
- {
396
- // There is dev data to read
397
- state->decode_state = FIT_CONVERT_DECODE_DEV_FIELD_DATA;
398
- }
399
- else
400
- {
401
- state->decode_state = FIT_CONVERT_DECODE_RECORD;
402
- }
403
- }
404
-
405
- if (state->mesg_index < FIT_LOCAL_MESGS)
406
- {
407
- if ((state->mesg_def != FIT_NULL) && (state->field_index < state->convert_table[state->mesg_index].num_fields))
408
- {
409
- if (state->mesg_offset == (state->convert_table[state->mesg_index].fields[state->field_index].offset_in + state->field_offset + 1))
410
- {
411
- FIT_UINT8 *field = &state->u.mesg[state->convert_table[state->mesg_index].fields[state->field_index].offset_local];
412
-
413
- field[state->field_offset] = datum; // Store the incoming byte in the local mesg buffer.
414
- state->field_offset++;
415
-
416
- if (state->field_offset >= state->convert_table[state->mesg_index].fields[state->field_index].size)
417
- {
418
- if (
419
- (state->convert_table[state->mesg_index].fields[state->field_index].base_type & FIT_BASE_TYPE_ENDIAN_FLAG) &&
420
- ((state->convert_table[state->mesg_index].arch & FIT_ARCH_ENDIAN_MASK) != (Fit_GetArch() & FIT_ARCH_ENDIAN_MASK))
421
- )
422
- {
423
- FIT_UINT8 type_size;
424
- FIT_UINT8 element_size;
425
- FIT_UINT8 element;
426
- FIT_UINT8 index;
427
-
428
- index = state->convert_table[state->mesg_index].fields[state->field_index].base_type & FIT_BASE_TYPE_NUM_MASK;
429
-
430
- if (index >= FIT_BASE_TYPES)
431
- return FIT_CONVERT_ERROR;
432
-
433
- type_size = fit_base_type_sizes[index];
434
- element_size = state->convert_table[state->mesg_index].fields[state->field_index].size / type_size;
435
-
436
- for (element = 0; element < element_size; element++)
437
- {
438
- for (index = 0; index < (type_size / 2); index++)
439
- {
440
- FIT_UINT8 tmp = field[element * type_size + index];
441
- field[element * type_size + index] = field[element * type_size + type_size - 1 - index];
442
- field[element * type_size + type_size - 1 - index] = tmp;
443
- }
444
- }
445
- }
446
-
447
- // Null terminate last character if multi-byte beyond end of field.
448
- if (state->convert_table[state->mesg_index].fields[state->field_index].base_type == FIT_BASE_TYPE_STRING)
449
- {
450
- FIT_UINT8 length = state->convert_table[state->mesg_index].fields[state->field_index].size;
451
- FIT_UINT8 index = 0;
452
-
453
- while (index < length)
454
- {
455
- FIT_UINT8 char_size;
456
- FIT_UINT8 size_mask = 0x80;
457
-
458
- if (field[index] & size_mask)
459
- {
460
- char_size = 0;
461
-
462
- while (field[index] & size_mask) // # of bytes in character = # of MSBits
463
- {
464
- char_size++;
465
- size_mask >>= 1;
466
- }
467
- }
468
- else
469
- {
470
- char_size = 1;
471
- }
472
-
473
- if ((FIT_UINT16)(index + char_size) > length)
474
- {
475
- while (index < length)
476
- {
477
- field[index++] = 0;
478
- }
479
- break;
480
- }
481
-
482
- index += char_size;
483
- }
484
- }
485
-
486
- state->field_offset = 0; // Reset the offset.
487
- state->field_index++; // Move on to the next field.
488
-
489
- if (state->field_index >= state->convert_table[state->mesg_index].num_fields)
490
- {
491
- #if defined(FIT_CONVERT_TIME_RECORD)
492
- {
493
- FIT_UINT8 timestamp_offset = Fit_GetFieldOffset(state->mesg_def, FIT_FIELD_NUM_TIMESTAMP);
494
-
495
- if (timestamp_offset != FIT_UINT8_INVALID)
496
- {
497
- if (*((FIT_UINT32 *)&state->u.mesg[timestamp_offset]) != FIT_DATE_TIME_INVALID)
498
- {
499
- memcpy(&state->timestamp, &state->u.mesg[timestamp_offset], sizeof(state->timestamp));
500
- state->last_time_offset = (FIT_UINT8)(state->timestamp & FIT_HDR_TIME_OFFSET_MASK);
501
- }
502
- }
503
- }
504
- #endif
505
-
506
- state->field_index = 0;
507
- if ( state->dev_data_sizes[state->mesg_index] == 0 )
508
- {
509
- // We have successfully decoded a mesg and there is no dev data to read.
510
- return FIT_CONVERT_MESSAGE_AVAILABLE;
511
- }
512
- }
513
- }
514
- }
515
- }
516
- }
517
- break;
518
-
519
- case FIT_CONVERT_DECODE_DEV_FIELD_DATA:
520
- state->field_offset++;
521
- if (state->field_offset >= state->dev_data_sizes[state->mesg_index])
522
- {
523
- // Done Parsing Dev Field Data
524
- state->decode_state = FIT_CONVERT_DECODE_RECORD;
525
-
526
- // We have successfully decoded a mesg and there is no dev data to read.
527
- return FIT_CONVERT_MESSAGE_AVAILABLE;
528
- }
529
- break;
530
-
531
- default:
532
- // This shouldn't happen.
533
- return FIT_CONVERT_ERROR;
534
- }
535
- }
536
-
537
- state->data_offset = 0;
538
- return FIT_CONVERT_CONTINUE;
539
- }
540
-
541
- ///////////////////////////////////////////////////////////////////////
542
- #if !defined(FIT_CONVERT_MULTI_THREAD)
543
- void FitConvert_SetMessageDefinition(FIT_MESG_DEF *mesg_def)
544
- {
545
- state->mesg_def = mesg_def;
546
- }
547
- #endif
548
-
549
- ///////////////////////////////////////////////////////////////////////
550
- #if defined(FIT_CONVERT_MULTI_THREAD)
551
- FIT_UINT16 FitConvert_GetMessageNumber(FIT_CONVERT_STATE *state)
552
- #else
553
- FIT_UINT16 FitConvert_GetMessageNumber(void)
554
- #endif
555
- {
556
- return state->convert_table[state->mesg_index].global_mesg_num;
557
- }
558
-
559
- ///////////////////////////////////////////////////////////////////////
560
- #if defined(FIT_CONVERT_MULTI_THREAD)
561
- const FIT_UINT8 *FitConvert_GetMessageData(FIT_CONVERT_STATE *state)
562
- #else
563
- const FIT_UINT8 *FitConvert_GetMessageData(void)
564
- #endif
565
- {
566
- return state->u.mesg;
567
- }
568
-
569
- ///////////////////////////////////////////////////////////////////////
570
- #if defined(FIT_CONVERT_MULTI_THREAD)
571
- void FitConvert_RestoreFields(FIT_CONVERT_STATE *state, const void *mesg)
572
- #else
573
- void FitConvert_RestoreFields(const void *mesg)
574
- #endif
575
- {
576
- FIT_UINT8 offset = 0;
577
- FIT_UINT8 field_index;
578
- FIT_UINT8 convert_field;
579
-
580
- if (state->mesg_def == FIT_NULL)
581
- return;
582
-
583
- for (field_index = 0; field_index < state->mesg_def->num_fields; field_index++)
584
- {
585
- for (convert_field=0; convert_field < state->convert_table[state->mesg_index].num_fields; convert_field++)
586
- {
587
- if (state->convert_table[state->mesg_index].fields[convert_field].offset_local == offset)
588
- break;
589
- }
590
-
591
- if (convert_field == state->convert_table[state->mesg_index].num_fields)
592
- memcpy(&state->u.mesg[offset], &((FIT_UINT8 *)mesg)[offset], state->mesg_def->fields[FIT_MESG_DEF_FIELD_OFFSET(size, field_index)]);
593
-
594
- offset += state->mesg_def->fields[FIT_MESG_DEF_FIELD_OFFSET(size, field_index)];
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
+ }