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,39 +1,44 @@
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
- #if !defined(FIT_RAM_H)
21
- #define FIT_RAM_H
22
-
23
- #include "fit_example.h"
24
-
25
- #if defined(FIT_RAM_INCLUDE)
26
-
27
- ///////////////////////////////////////////////////////////////////////////////
28
- // Public Function Prototypes
29
- ///////////////////////////////////////////////////////////////////////////////
30
-
31
- FIT_RAM_FILE FitRAM_LookupFile(FIT_FILE file);
32
- FIT_UINT32 FitRAM_GetFileSize(FIT_RAM_FILE file);
33
- void FitRAM_FileReadBytes(FIT_RAM_FILE file, FIT_UINT16 file_index, FIT_UINT32 file_offset, void *data, FIT_UINT32 data_size);
34
- void FitRAM_FileWriteBytes(FIT_RAM_FILE file, FIT_UINT16 file_index, FIT_UINT32 file_offset, const void *data, FIT_UINT32 data_size);
35
- void FitRAM_FileWriteMesg(FIT_RAM_FILE file, FIT_UINT16 file_index, FIT_UINT16 mesg_num, const void *mesg_data, FIT_BOOL restore_fields);
36
-
37
- #endif // defined(FIT_RAM_INCLUDE)
38
-
39
- #endif // !defined(FIT_RAM_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
+ // ****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
+ #if !defined(FIT_RAM_H)
21
+ #define FIT_RAM_H
22
+
23
+ #include "fit_example.h"
24
+
25
+ #if defined(FIT_RAM_INCLUDE)
26
+
27
+ ///////////////////////////////////////////////////////////////////////////////
28
+ // Public Function Prototypes
29
+ ///////////////////////////////////////////////////////////////////////////////
30
+
31
+ FIT_RAM_FILE FitRAM_LookupFile(FIT_FILE file);
32
+ FIT_UINT32 FitRAM_GetFileSize(FIT_RAM_FILE file);
33
+ void FitRAM_FileReadBytes(FIT_RAM_FILE file, FIT_UINT16 file_index, FIT_UINT32 file_offset, void *data, FIT_UINT32 data_size);
34
+ void FitRAM_FileWriteBytes(FIT_RAM_FILE file, FIT_UINT16 file_index, FIT_UINT32 file_offset, const void *data, FIT_UINT32 data_size);
35
+
36
+ #if defined(FIT_CONVERT_MULTI_THREAD)
37
+ void FitRAM_FileWriteMesg(FIT_CONVERT_STATE *state, FIT_RAM_FILE file, FIT_UINT16 file_index, FIT_UINT16 mesg_num, const void *mesg_data, FIT_BOOL restore_fields);
38
+ #else
39
+ void FitRAM_FileWriteMesg(FIT_RAM_FILE file, FIT_UINT16 file_index, FIT_UINT16 mesg_num, const void *mesg_data, FIT_BOOL restore_fields);
40
+ #endif // defined(FIT_CONVERT_MULTI_THREAD)
41
+
42
+ #endif // defined(FIT_RAM_INCLUDE)
43
+
44
+ #endif // !defined(FIT_RAM_H)
@@ -1,566 +1,560 @@
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 "stdio.h"
16
- #include "string.h"
17
- #include "ruby.h"
18
- #include "math.h"
19
-
20
- #include "fit_convert.h"
21
- #include "fit_crc.h"
22
-
23
- VALUE mRubyFit;
24
- VALUE cFitParser;
25
- VALUE cFitHandler;
26
- VALUE cFitHandlerPrintFun;
27
- VALUE cFitHandlerPrintErrFun;
28
- VALUE cFitHandlerActivityFun;
29
- VALUE cFitHandlerRecordFun;
30
- VALUE cFitHandlerLapFun;
31
- VALUE cFitHandlerSessionFun;
32
- VALUE cFitHandlerDeviceInfoFun;
33
- VALUE cFitHandlerUserProfileFun;
34
- VALUE cFitHandlerEventFun;
35
- VALUE cFitHandlerWeightScaleInfoFun;
36
- static ID HANDLER_ATTR;
37
- /*
38
- * garmin/dynastream, decided to pinch pennies on bits by tinkering with well
39
- * established time offsets. This is the magic number of seconds needed to add
40
- * to their number to get the true number of seconds since the epoch.
41
- * This is 20 years of seconds.
42
- */
43
- const long GARMIN_TIME_OFFSET = 631065600;
44
-
45
-
46
- void pass_message(char *msg) {
47
- rb_funcall(cFitHandler, cFitHandlerPrintFun, 1, rb_str_new2(msg));
48
- }
49
-
50
- void pass_err_message(char *msg) {
51
- rb_funcall(cFitHandler, cFitHandlerPrintErrFun, 1, rb_str_new2(msg));
52
- }
53
-
54
- static VALUE fit_pos_to_rb(FIT_SINT32 pos) {
55
- float tmp = pos * (180.0 / pow(2,31));
56
- tmp -= (tmp > 180.0 ? 360.0 : 0.0);
57
- return rb_float_new(tmp);
58
- }
59
-
60
-
61
- static VALUE init(VALUE self, VALUE handler) {
62
- cFitHandler = handler;
63
- rb_ivar_set(self, HANDLER_ATTR, handler);
64
-
65
- //callbacks
66
- cFitHandlerPrintFun = rb_intern("print_msg");
67
- cFitHandlerPrintErrFun = rb_intern("print_error_msg");
68
- cFitHandlerActivityFun = rb_intern("on_activity");
69
- cFitHandlerSessionFun = rb_intern("on_session");
70
- cFitHandlerLapFun = rb_intern("on_lap");
71
- cFitHandlerRecordFun = rb_intern("on_record");
72
- cFitHandlerEventFun = rb_intern("on_event");
73
- cFitHandlerDeviceInfoFun = rb_intern("on_device_info");
74
- cFitHandlerUserProfileFun = rb_intern("on_user_profile");
75
- cFitHandlerWeightScaleInfoFun = rb_intern("on_weight_scale_info");
76
-
77
- return Qnil;
78
- }
79
-
80
- static void pass_activity(const FIT_ACTIVITY_MESG *mesg) {
81
- VALUE rh = rb_hash_new();
82
-
83
- if(mesg->timestamp != FIT_DATE_TIME_INVALID)
84
- rb_hash_aset(rh, rb_str_new2("timestamp"), UINT2NUM(mesg->timestamp + GARMIN_TIME_OFFSET));
85
- if(mesg->total_timer_time != FIT_UINT32_INVALID)
86
- rb_hash_aset(rh, rb_str_new2("total_timer_time"), rb_float_new(mesg->total_timer_time / 1000.0));
87
- if(mesg->local_timestamp != FIT_DATE_TIME_INVALID)
88
- rb_hash_aset(rh, rb_str_new2("local_timestamp"), rb_float_new(mesg->local_timestamp + GARMIN_TIME_OFFSET));
89
- if(mesg->num_sessions != FIT_UINT16_INVALID)
90
- rb_hash_aset(rh, rb_str_new2("num_sessions"), UINT2NUM(mesg->num_sessions));
91
- if(mesg->type != FIT_ENUM_INVALID)
92
- rb_hash_aset(rh, rb_str_new2("type"), CHR2FIX(mesg->type));
93
- if(mesg->event != FIT_ENUM_INVALID)
94
- rb_hash_aset(rh, rb_str_new2("event"), CHR2FIX(mesg->event));
95
- if(mesg->event_type != FIT_ENUM_INVALID)
96
- rb_hash_aset(rh, rb_str_new2("event_type"), CHR2FIX(mesg->event_type));
97
- if(mesg->event_group != FIT_UINT8_INVALID)
98
- rb_hash_aset(rh, rb_str_new2("event_group"), UINT2NUM(mesg->event_group));
99
-
100
- rb_funcall(cFitHandler, cFitHandlerActivityFun, 1, rh);
101
- }
102
-
103
- static void pass_record(const FIT_RECORD_MESG *mesg) {
104
- VALUE rh = rb_hash_new();
105
-
106
- if(mesg->timestamp != FIT_DATE_TIME_INVALID)
107
- rb_hash_aset(rh, rb_str_new2("timestamp"), UINT2NUM(mesg->timestamp + GARMIN_TIME_OFFSET));
108
- if(mesg->position_lat != FIT_SINT32_INVALID)
109
- rb_hash_aset(rh, rb_str_new2("position_lat"), fit_pos_to_rb(mesg->position_lat));
110
- if(mesg->position_long != FIT_SINT32_INVALID)
111
- rb_hash_aset(rh, rb_str_new2("position_long"), fit_pos_to_rb(mesg->position_long));
112
- if(mesg->distance != FIT_UINT32_INVALID)
113
- rb_hash_aset(rh, rb_str_new2("distance"), rb_float_new(mesg->distance / 100.0));
114
- if(mesg->time_from_course != FIT_SINT32_INVALID)
115
- rb_hash_aset(rh, rb_str_new2("time_from_course"), rb_float_new(mesg->time_from_course / 1000.0));
116
- if(mesg->heart_rate != FIT_UINT8_INVALID)
117
- rb_hash_aset(rh, rb_str_new2("heart_rate"), UINT2NUM(mesg->heart_rate));
118
- if(mesg->altitude != FIT_UINT16_INVALID)
119
- rb_hash_aset(rh, rb_str_new2("altitude"), rb_float_new(mesg->altitude / 5.0 - 500));
120
- if(mesg->speed != FIT_UINT16_INVALID)
121
- rb_hash_aset(rh, rb_str_new2("speed"), rb_float_new(mesg->speed / 1000.0));
122
- if(mesg->grade != FIT_SINT16_INVALID)
123
- rb_hash_aset(rh, rb_str_new2("grade"), rb_float_new(mesg->grade / 100.0));
124
- if(mesg->power != FIT_UINT16_INVALID)
125
- rb_hash_aset(rh, rb_str_new2("power"), UINT2NUM(mesg->power));
126
- if(mesg->cadence != FIT_UINT8_INVALID)
127
- rb_hash_aset(rh, rb_str_new2("cadence"), UINT2NUM(mesg->cadence));
128
- if(mesg->resistance != FIT_UINT8_INVALID)
129
- rb_hash_aset(rh, rb_str_new2("resistance"), UINT2NUM(mesg->resistance));
130
- if(mesg->cycle_length != FIT_UINT8_INVALID)
131
- rb_hash_aset(rh, rb_str_new2("cycle_length"), UINT2NUM(mesg->cycle_length));
132
- if(mesg->temperature != FIT_SINT8_INVALID)
133
- rb_hash_aset(rh, rb_str_new2("temperature"), INT2FIX(mesg->temperature));
134
-
135
- if(mesg->left_right_balance != FIT_UINT8_INVALID)
136
- rb_hash_aset(rh, rb_str_new2("left_right_balance"), UINT2NUM(mesg->left_right_balance & FIT_LEFT_RIGHT_BALANCE_MASK));
137
- if(mesg->left_torque_effectiveness != FIT_UINT8_INVALID)
138
- rb_hash_aset(rh, rb_str_new2("left_torque_effectiveness"), UINT2NUM(mesg->left_torque_effectiveness));
139
- if(mesg->right_torque_effectiveness != FIT_UINT8_INVALID)
140
- rb_hash_aset(rh, rb_str_new2("right_torque_effectiveness"), UINT2NUM(mesg->right_torque_effectiveness));
141
- if(mesg->left_pedal_smoothness != FIT_UINT8_INVALID)
142
- rb_hash_aset(rh, rb_str_new2("left_pedal_smoothness"), UINT2NUM(mesg->left_pedal_smoothness));
143
- if(mesg->right_pedal_smoothness != FIT_UINT8_INVALID)
144
- rb_hash_aset(rh, rb_str_new2("right_pedal_smoothness"), UINT2NUM(mesg->right_pedal_smoothness));
145
- if(mesg->combined_pedal_smoothness != FIT_UINT8_INVALID)
146
- rb_hash_aset(rh, rb_str_new2("combined_pedal_smoothness"), UINT2NUM(mesg->combined_pedal_smoothness));
147
-
148
- rb_funcall(cFitHandler, cFitHandlerRecordFun, 1, rh);
149
- }
150
-
151
- static void pass_lap(const FIT_LAP_MESG *mesg) {
152
- VALUE rh = rb_hash_new();
153
-
154
- if(mesg->timestamp != FIT_DATE_TIME_INVALID)
155
- rb_hash_aset(rh, rb_str_new2("timestamp"), UINT2NUM(mesg->timestamp + GARMIN_TIME_OFFSET));
156
- if(mesg->start_time != FIT_DATE_TIME_INVALID)
157
- rb_hash_aset(rh, rb_str_new2("start_time"), UINT2NUM(mesg->start_time + GARMIN_TIME_OFFSET));
158
- if(mesg->start_position_lat != FIT_SINT32_INVALID)
159
- rb_hash_aset(rh, rb_str_new2("start_position_lat"), fit_pos_to_rb(mesg->start_position_lat));
160
- if(mesg->start_position_long != FIT_SINT32_INVALID)
161
- rb_hash_aset(rh, rb_str_new2("start_position_long"), fit_pos_to_rb(mesg->start_position_long));
162
- if(mesg->end_position_lat != FIT_SINT32_INVALID)
163
- rb_hash_aset(rh, rb_str_new2("end_position_lat"), fit_pos_to_rb(mesg->end_position_lat));
164
- if(mesg->end_position_long != FIT_SINT32_INVALID)
165
- rb_hash_aset(rh, rb_str_new2("end_position_long"), fit_pos_to_rb(mesg->end_position_long));
166
- if(mesg->total_elapsed_time != FIT_UINT32_INVALID)
167
- rb_hash_aset(rh, rb_str_new2("total_elapsed_time"), UINT2NUM(mesg->total_elapsed_time));
168
- if(mesg->total_timer_time != FIT_UINT32_INVALID)
169
- rb_hash_aset(rh, rb_str_new2("total_timer_time"), rb_float_new(mesg->total_timer_time / 1000.0));
170
- if(mesg->total_distance != FIT_UINT32_INVALID)
171
- rb_hash_aset(rh, rb_str_new2("total_distance"), rb_float_new(mesg->total_distance / 100.0));
172
- if(mesg->total_cycles != FIT_UINT32_INVALID)
173
- rb_hash_aset(rh, rb_str_new2("total_cycles"), UINT2NUM(mesg->total_cycles));
174
- if(mesg->message_index != FIT_UINT16_INVALID)
175
- rb_hash_aset(rh, rb_str_new2("message_index"), UINT2NUM(mesg->message_index));
176
- if(mesg->total_calories != FIT_UINT16_INVALID)
177
- rb_hash_aset(rh, rb_str_new2("total_calories"), UINT2NUM(mesg->total_calories));
178
- if(mesg->total_fat_calories != FIT_UINT16_INVALID)
179
- rb_hash_aset(rh, rb_str_new2("total_fat_calories"), UINT2NUM(mesg->total_fat_calories));
180
- if(mesg->avg_speed != FIT_UINT16_INVALID)
181
- rb_hash_aset(rh, rb_str_new2("avg_speed"), rb_float_new(mesg->avg_speed / 1000.0));
182
- if(mesg->max_speed != FIT_UINT16_INVALID)
183
- rb_hash_aset(rh, rb_str_new2("max_speed"), rb_float_new(mesg->max_speed / 1000.0));
184
- if(mesg->avg_power != FIT_UINT16_INVALID)
185
- rb_hash_aset(rh, rb_str_new2("avg_power"), UINT2NUM(mesg->avg_power));
186
- if(mesg->max_power != FIT_UINT16_INVALID)
187
- rb_hash_aset(rh, rb_str_new2("max_power"), UINT2NUM(mesg->max_power));
188
- if(mesg->total_ascent != FIT_UINT16_INVALID)
189
- rb_hash_aset(rh, rb_str_new2("total_ascent"), UINT2NUM(mesg->total_ascent));
190
- if(mesg->total_descent != FIT_UINT16_INVALID)
191
- rb_hash_aset(rh, rb_str_new2("total_descent"), UINT2NUM(mesg->total_descent));
192
- if(mesg->event != FIT_EVENT_INVALID)
193
- rb_hash_aset(rh, rb_str_new2("event"), CHR2FIX(mesg->event));
194
- if(mesg->event_type != FIT_EVENT_INVALID)
195
- rb_hash_aset(rh, rb_str_new2("event_type"), CHR2FIX(mesg->event_type));
196
- if(mesg->avg_heart_rate != FIT_UINT8_INVALID)
197
- rb_hash_aset(rh, rb_str_new2("avg_heart_rate"), UINT2NUM(mesg->avg_heart_rate));
198
- if(mesg->max_heart_rate != FIT_UINT8_INVALID)
199
- rb_hash_aset(rh, rb_str_new2("max_heart_rate"), UINT2NUM(mesg->max_heart_rate));
200
- if(mesg->avg_cadence != FIT_UINT8_INVALID)
201
- rb_hash_aset(rh, rb_str_new2("avg_cadence"), UINT2NUM(mesg->avg_cadence));
202
- if(mesg->max_cadence != FIT_UINT8_INVALID)
203
- rb_hash_aset(rh, rb_str_new2("max_cadence"), UINT2NUM(mesg->max_cadence));
204
- if(mesg->intensity != FIT_INTENSITY_INVALID)
205
- rb_hash_aset(rh, rb_str_new2("intensity"), CHR2FIX(mesg->intensity));
206
- if(mesg->lap_trigger != FIT_LAP_TRIGGER_INVALID)
207
- rb_hash_aset(rh, rb_str_new2("lap_trigger"), CHR2FIX(mesg->lap_trigger));
208
- if(mesg->sport != FIT_SPORT_INVALID)
209
- rb_hash_aset(rh, rb_str_new2("sport"), CHR2FIX(mesg->sport));
210
- if(mesg->event_group != FIT_UINT8_INVALID)
211
- rb_hash_aset(rh, rb_str_new2("event_group"), UINT2NUM(mesg->event_group));
212
-
213
- rb_funcall(cFitHandler, cFitHandlerLapFun, 1, rh);
214
- }
215
-
216
- static void pass_session(const FIT_SESSION_MESG *mesg) {
217
- VALUE rh = rb_hash_new();
218
-
219
- if(mesg->timestamp != FIT_DATE_TIME_INVALID)
220
- rb_hash_aset(rh, rb_str_new2("timestamp"), UINT2NUM(mesg->timestamp + GARMIN_TIME_OFFSET));
221
- if(mesg->start_time != FIT_DATE_TIME_INVALID)
222
- rb_hash_aset(rh, rb_str_new2("start_time"), UINT2NUM(mesg->start_time + GARMIN_TIME_OFFSET));
223
- if(mesg->start_position_lat != FIT_SINT32_INVALID)
224
- rb_hash_aset(rh, rb_str_new2("start_position_lat"), fit_pos_to_rb(mesg->start_position_lat));
225
- if(mesg->start_position_long != FIT_SINT32_INVALID)
226
- rb_hash_aset(rh, rb_str_new2("start_position_long"), fit_pos_to_rb(mesg->start_position_long));
227
- if(mesg->total_elapsed_time != FIT_UINT32_INVALID)
228
- rb_hash_aset(rh, rb_str_new2("total_elapsed_time"), rb_float_new(mesg->total_elapsed_time / 1000.0));
229
- if(mesg->total_timer_time != FIT_UINT32_INVALID)
230
- rb_hash_aset(rh, rb_str_new2("total_timer_time"), rb_float_new(mesg->total_timer_time / 1000.0));
231
- if(mesg->total_distance != FIT_UINT32_INVALID)
232
- rb_hash_aset(rh, rb_str_new2("total_distance"), rb_float_new(mesg->total_distance / 100.0));
233
- if(mesg->total_cycles != FIT_UINT32_INVALID)
234
- rb_hash_aset(rh, rb_str_new2("total_cycles"), UINT2NUM(mesg->total_cycles));
235
- if(mesg->nec_lat != FIT_SINT32_INVALID)
236
- rb_hash_aset(rh, rb_str_new2("nec_lat"), fit_pos_to_rb(mesg->nec_lat));
237
- if(mesg->nec_long != FIT_SINT32_INVALID)
238
- rb_hash_aset(rh, rb_str_new2("nec_long"), fit_pos_to_rb(mesg->nec_long));
239
- if(mesg->swc_lat != FIT_SINT32_INVALID)
240
- rb_hash_aset(rh, rb_str_new2("swc_lat"), fit_pos_to_rb(mesg->swc_lat));
241
- if(mesg->swc_long != FIT_SINT32_INVALID)
242
- rb_hash_aset(rh, rb_str_new2("swc_long"), fit_pos_to_rb(mesg->swc_long));
243
- if(mesg->message_index != FIT_MESSAGE_INDEX_INVALID)
244
- rb_hash_aset(rh, rb_str_new2("message_index"), UINT2NUM(mesg->message_index));
245
- if(mesg->total_calories != FIT_UINT16_INVALID)
246
- rb_hash_aset(rh, rb_str_new2("total_calories"), UINT2NUM(mesg->total_calories));
247
- if(mesg->total_fat_calories != FIT_UINT16_INVALID)
248
- rb_hash_aset(rh, rb_str_new2("total_fat_calories"), UINT2NUM(mesg->total_fat_calories));
249
- if(mesg->avg_speed != FIT_UINT16_INVALID)
250
- rb_hash_aset(rh, rb_str_new2("avg_speed"), rb_float_new(mesg->avg_speed / 1000.0));
251
- if(mesg->max_speed != FIT_UINT16_INVALID)
252
- rb_hash_aset(rh, rb_str_new2("max_speed"), rb_float_new(mesg->max_speed / 1000.0));
253
- if(mesg->avg_power != FIT_UINT16_INVALID)
254
- rb_hash_aset(rh, rb_str_new2("avg_power"), UINT2NUM(mesg->avg_power));
255
- if(mesg->max_power != FIT_UINT16_INVALID)
256
- rb_hash_aset(rh, rb_str_new2("max_power"), UINT2NUM(mesg->max_power));
257
- if(mesg->total_ascent != FIT_UINT16_INVALID)
258
- rb_hash_aset(rh, rb_str_new2("total_ascent"), UINT2NUM(mesg->total_ascent));
259
- if(mesg->total_descent != FIT_UINT16_INVALID)
260
- rb_hash_aset(rh, rb_str_new2("total_descent"), UINT2NUM(mesg->total_descent));
261
- if(mesg->first_lap_index != FIT_UINT16_INVALID)
262
- rb_hash_aset(rh, rb_str_new2("first_lap_index"), UINT2NUM(mesg->first_lap_index));
263
- if(mesg->num_laps != FIT_UINT16_INVALID)
264
- rb_hash_aset(rh, rb_str_new2("num_laps"), UINT2NUM(mesg->num_laps));
265
- if(mesg->event != FIT_EVENT_INVALID)
266
- rb_hash_aset(rh, rb_str_new2("event"), CHR2FIX(mesg->event));
267
- if(mesg->event_type != FIT_EVENT_INVALID)
268
- rb_hash_aset(rh, rb_str_new2("event_type"), CHR2FIX(mesg->event_type));
269
- if(mesg->avg_heart_rate != FIT_UINT8_INVALID)
270
- rb_hash_aset(rh, rb_str_new2("avg_heart_rate"), UINT2NUM(mesg->avg_heart_rate));
271
- if(mesg->max_heart_rate != FIT_UINT8_INVALID)
272
- rb_hash_aset(rh, rb_str_new2("max_heart_rate"), UINT2NUM(mesg->max_heart_rate));
273
- if(mesg->avg_cadence != FIT_UINT8_INVALID)
274
- rb_hash_aset(rh, rb_str_new2("avg_cadence"), UINT2NUM(mesg->avg_cadence));
275
- if(mesg->max_cadence != FIT_UINT8_INVALID)
276
- rb_hash_aset(rh, rb_str_new2("max_cadence"), UINT2NUM(mesg->max_cadence));
277
- if(mesg->sport != FIT_SPORT_INVALID)
278
- rb_hash_aset(rh, rb_str_new2("sport"), CHR2FIX(mesg->sport));
279
- if(mesg->sub_sport != FIT_SUB_SPORT_INVALID)
280
- rb_hash_aset(rh, rb_str_new2("sub_sport"), CHR2FIX(mesg->sub_sport));
281
- if(mesg->event_group != FIT_UINT8_INVALID)
282
- rb_hash_aset(rh, rb_str_new2("event_group"), UINT2NUM(mesg->event_group));
283
- if(mesg->total_training_effect != FIT_UINT8_INVALID)
284
- rb_hash_aset(rh, rb_str_new2("total_training_effect"), UINT2NUM(mesg->total_training_effect));
285
-
286
- rb_funcall(cFitHandler, cFitHandlerSessionFun, 1, rh);
287
- }
288
-
289
- static void pass_user_profile(const FIT_USER_PROFILE_MESG *mesg) {
290
- VALUE rh = rb_hash_new();
291
-
292
- if(mesg->friendly_name != FIT_STRING_INVALID)
293
- rb_hash_aset(rh, rb_str_new2("friendly_name"), rb_str_new2(mesg->friendly_name));
294
- if(mesg->message_index != FIT_MESSAGE_INDEX_INVALID)
295
- rb_hash_aset(rh, rb_str_new2("message_index"), UINT2NUM(mesg->message_index));
296
- if(mesg->weight != FIT_UINT16_INVALID)
297
- rb_hash_aset(rh, rb_str_new2("weight"), rb_float_new(mesg->weight / 10.0));
298
- if(mesg->gender != FIT_GENDER_INVALID)
299
- rb_hash_aset(rh, rb_str_new2("gender"), UINT2NUM(mesg->gender));
300
- if(mesg->age != FIT_UINT8_INVALID)
301
- rb_hash_aset(rh, rb_str_new2("age"), UINT2NUM(mesg->age));
302
- if(mesg->height != FIT_UINT8_INVALID)
303
- rb_hash_aset(rh, rb_str_new2("height"), rb_float_new(mesg->height / 100.0));
304
- if(mesg->language != FIT_LANGUAGE_INVALID)
305
- rb_hash_aset(rh, rb_str_new2("language"), UINT2NUM(mesg->language));
306
- if(mesg->elev_setting != FIT_DISPLAY_MEASURE_INVALID)
307
- rb_hash_aset(rh, rb_str_new2("elev_setting"), UINT2NUM(mesg->elev_setting));
308
- if(mesg->weight_setting != FIT_DISPLAY_MEASURE_INVALID)
309
- rb_hash_aset(rh, rb_str_new2("weight_setting"), UINT2NUM(mesg->weight_setting));
310
- if(mesg->resting_heart_rate != FIT_UINT8_INVALID)
311
- rb_hash_aset(rh, rb_str_new2("resting_heart_rate"), UINT2NUM(mesg->resting_heart_rate));
312
- if(mesg->default_max_running_heart_rate != FIT_UINT8_INVALID)
313
- rb_hash_aset(rh, rb_str_new2("default_max_running_heart_rate"), UINT2NUM(mesg->default_max_running_heart_rate));
314
- if(mesg->default_max_biking_heart_rate != FIT_UINT8_INVALID)
315
- rb_hash_aset(rh, rb_str_new2("default_max_biking_heart_rate"), UINT2NUM(mesg->default_max_biking_heart_rate));
316
- if(mesg->default_max_heart_rate != FIT_UINT8_INVALID)
317
- rb_hash_aset(rh, rb_str_new2("default_max_heart_rate"), UINT2NUM(mesg->default_max_heart_rate));
318
- if(mesg->hr_setting != FIT_DISPLAY_HEART_INVALID)
319
- rb_hash_aset(rh, rb_str_new2("hr_setting"), UINT2NUM(mesg->hr_setting));
320
- if(mesg->speed_setting != FIT_DISPLAY_MEASURE_INVALID)
321
- rb_hash_aset(rh, rb_str_new2("speed_setting"), UINT2NUM(mesg->speed_setting));
322
- if(mesg->dist_setting != FIT_DISPLAY_MEASURE_INVALID)
323
- rb_hash_aset(rh, rb_str_new2("dist_setting"), UINT2NUM(mesg->dist_setting));
324
- if(mesg->power_setting != FIT_DISPLAY_POWER_INVALID)
325
- rb_hash_aset(rh, rb_str_new2("power_setting"), UINT2NUM(mesg->power_setting));
326
- if(mesg->activity_class != FIT_ACTIVITY_CLASS_INVALID)
327
- rb_hash_aset(rh, rb_str_new2("activity_class"), UINT2NUM(mesg->activity_class));
328
- if(mesg->position_setting != FIT_DISPLAY_POSITION_INVALID)
329
- rb_hash_aset(rh, rb_str_new2("position_setting"), UINT2NUM(mesg->position_setting));
330
-
331
- rb_funcall(cFitHandler, cFitHandlerUserProfileFun, 1, rh);
332
- }
333
-
334
- static void pass_event(const FIT_EVENT_MESG *mesg) {
335
- VALUE rh = rb_hash_new();
336
-
337
- if(mesg->timestamp != FIT_DATE_TIME_INVALID)
338
- rb_hash_aset(rh, rb_str_new2("timestamp"), UINT2NUM(mesg->timestamp + GARMIN_TIME_OFFSET));
339
- if(mesg->data != FIT_UINT32_INVALID)
340
- rb_hash_aset(rh, rb_str_new2("data"), UINT2NUM(mesg->data));
341
- if(mesg->data16 != FIT_UINT16_INVALID)
342
- rb_hash_aset(rh, rb_str_new2("data16"), UINT2NUM(mesg->data16));
343
- if(mesg->timestamp != FIT_EVENT_INVALID)
344
- rb_hash_aset(rh, rb_str_new2("event"), CHR2FIX(mesg->event));
345
- if(mesg->timestamp != FIT_EVENT_TYPE_INVALID)
346
- rb_hash_aset(rh, rb_str_new2("event_type"), CHR2FIX(mesg->event_type));
347
- if(mesg->event_group != FIT_UINT8_INVALID)
348
- rb_hash_aset(rh, rb_str_new2("event_group"), UINT2NUM(mesg->event_group));
349
-
350
- rb_funcall(cFitHandler, cFitHandlerEventFun, 1, rh);
351
- }
352
-
353
- static void pass_device_info(const FIT_DEVICE_INFO_MESG *mesg) {
354
- VALUE rh = rb_hash_new();
355
-
356
- if(mesg->timestamp != FIT_DATE_TIME_INVALID)
357
- rb_hash_aset(rh, rb_str_new2("timestamp"), UINT2NUM(mesg->timestamp + GARMIN_TIME_OFFSET));
358
- if(mesg->serial_number != FIT_UINT32Z_INVALID)
359
- rb_hash_aset(rh, rb_str_new2("serial_number"), UINT2NUM(mesg->serial_number));
360
- if(mesg->manufacturer != FIT_MANUFACTURER_INVALID)
361
- rb_hash_aset(rh, rb_str_new2("manufacturer"), UINT2NUM(mesg->manufacturer));
362
- if(mesg->product != FIT_UINT16_INVALID)
363
- rb_hash_aset(rh, rb_str_new2("product"), UINT2NUM(mesg->product));
364
- if(mesg->software_version != FIT_UINT16_INVALID)
365
- rb_hash_aset(rh, rb_str_new2("software_version"), UINT2NUM(mesg->software_version));
366
- if(mesg->battery_voltage != FIT_UINT16_INVALID)
367
- rb_hash_aset(rh, rb_str_new2("battery_voltage"), UINT2NUM(mesg->battery_voltage));
368
- if(mesg->device_index != FIT_DEVICE_INDEX_INVALID)
369
- rb_hash_aset(rh, rb_str_new2("device_index"), UINT2NUM(mesg->device_index));
370
- if(mesg->device_type != FIT_ANTPLUS_DEVICE_TYPE_INVALID)
371
- rb_hash_aset(rh, rb_str_new2("device_type"), UINT2NUM(mesg->device_type));
372
- if(mesg->hardware_version != FIT_UINT8_INVALID)
373
- rb_hash_aset(rh, rb_str_new2("hardware_version"), UINT2NUM(mesg->hardware_version));
374
- if(mesg->battery_status != FIT_BATTERY_STATUS_INVALID)
375
- rb_hash_aset(rh, rb_str_new2("battery_status"), UINT2NUM(mesg->battery_status));
376
-
377
- rb_funcall(cFitHandler, cFitHandlerDeviceInfoFun, 1, rh);
378
- }
379
-
380
- static void pass_weight_scale_info(const FIT_WEIGHT_SCALE_MESG *mesg) {
381
- VALUE rh = rb_hash_new();
382
-
383
- if(mesg->timestamp != FIT_DATE_TIME_INVALID)
384
- rb_hash_aset(rh, rb_str_new2("timestamp"), UINT2NUM(mesg->timestamp + GARMIN_TIME_OFFSET));
385
- if(mesg->weight != FIT_WEIGHT_INVALID)
386
- rb_hash_aset(rh, rb_str_new2("weight"), rb_float_new(mesg->weight / 100.0));
387
- if(mesg->percent_fat != FIT_UINT16_INVALID)
388
- rb_hash_aset(rh, rb_str_new2("percent_fat"), rb_float_new(mesg->percent_fat / 100.0));
389
- if(mesg->percent_hydration != FIT_UINT16_INVALID)
390
- rb_hash_aset(rh, rb_str_new2("percent_hydration"), rb_float_new(mesg->percent_hydration / 100.0));
391
- if(mesg->visceral_fat_mass != FIT_UINT16_INVALID)
392
- rb_hash_aset(rh, rb_str_new2("visceral_fat_mass"), rb_float_new(mesg->visceral_fat_mass / 100.0));
393
- if(mesg->bone_mass != FIT_UINT16_INVALID)
394
- rb_hash_aset(rh, rb_str_new2("bone_mass"), rb_float_new(mesg->bone_mass / 100.0));
395
- if(mesg->muscle_mass != FIT_UINT16_INVALID)
396
- rb_hash_aset(rh, rb_str_new2("muscle_mass"), rb_float_new(mesg->muscle_mass / 100.0));
397
- if(mesg->basal_met != FIT_UINT16_INVALID)
398
- rb_hash_aset(rh, rb_str_new2("basal_met"), rb_float_new(mesg->basal_met / 4.0));
399
- if(mesg->active_met != FIT_UINT16_INVALID)
400
- rb_hash_aset(rh, rb_str_new2("active_met"), rb_float_new(mesg->active_met / 4.0));
401
- if(mesg->physique_rating != FIT_UINT8_INVALID)
402
- rb_hash_aset(rh, rb_str_new2("physique_rating"), rb_float_new(mesg->physique_rating));
403
- if(mesg->metabolic_age != FIT_UINT8_INVALID)
404
- rb_hash_aset(rh, rb_str_new2("metabolic_age"), rb_float_new(mesg->metabolic_age));
405
- if(mesg->visceral_fat_rating != FIT_UINT8_INVALID)
406
- rb_hash_aset(rh, rb_str_new2("visceral_fat_rating"), rb_float_new(mesg->visceral_fat_rating));
407
-
408
- rb_funcall(cFitHandler, cFitHandlerWeightScaleInfoFun, 1, rh);
409
- }
410
-
411
- static VALUE parse(VALUE self, VALUE original_str) {
412
- int i = 0;
413
- VALUE str = StringValue(original_str);
414
- char *p = RSTRING_PTR(str);
415
- char err_msg[128];
416
-
417
- FIT_UINT8 buf[8];
418
- FIT_CONVERT_RETURN convert_return = FIT_CONVERT_CONTINUE;
419
- FIT_UINT32 buf_size;
420
- FitConvert_Init(FIT_TRUE);
421
-
422
- if(RSTRING_LEN(str) == 0) {
423
- //sprintf(err_msg, "Passed in string with length of 0!");
424
- pass_err_message(err_msg);
425
- return Qnil;
426
- }
427
-
428
- while(i < RSTRING_LEN(str) && (convert_return == FIT_CONVERT_CONTINUE)) {
429
- for(buf_size=0;(buf_size < sizeof(buf)) && (p != NULL); buf_size++) {
430
- buf[buf_size] = *p;
431
- p++;
432
- i++;
433
- }
434
-
435
- do {
436
- convert_return = FitConvert_Read(buf, buf_size);
437
-
438
- switch(convert_return) {
439
- case FIT_CONVERT_MESSAGE_AVAILABLE: {
440
- const FIT_UINT8 *mesg = FitConvert_GetMessageData();
441
- FIT_UINT16 mesg_num = FitConvert_GetMessageNumber();
442
-
443
- switch(mesg_num) {
444
- case FIT_MESG_NUM_FILE_ID: {
445
- break;
446
- }
447
-
448
- case FIT_MESG_NUM_USER_PROFILE: {
449
- const FIT_USER_PROFILE_MESG *user_profile = (FIT_USER_PROFILE_MESG *) mesg;
450
- pass_user_profile(user_profile);
451
- break;
452
- }
453
-
454
- case FIT_MESG_NUM_ACTIVITY: {
455
- const FIT_ACTIVITY_MESG *activity = (FIT_ACTIVITY_MESG *) mesg;
456
- pass_activity(activity);
457
-
458
- {
459
- FIT_ACTIVITY_MESG old_mesg;
460
- old_mesg.num_sessions = 1;
461
- FitConvert_RestoreFields(&old_mesg);
462
- sprintf(err_msg, "Restored num_sessions=1 - Activity: timestamp=%u, type=%u, event=%u, event_type=%u, num_sessions=%u\n", activity->timestamp, activity->type, activity->event, activity->event_type, activity->num_sessions);
463
- pass_message(err_msg);
464
- }
465
- break;
466
- }
467
-
468
- case FIT_MESG_NUM_SESSION: {
469
- const FIT_SESSION_MESG *session = (FIT_SESSION_MESG *) mesg;
470
- pass_session(session);
471
- break;
472
- }
473
-
474
- case FIT_MESG_NUM_LAP: {
475
- const FIT_LAP_MESG *lap = (FIT_LAP_MESG *) mesg;
476
- pass_lap(lap);
477
- break;
478
- }
479
-
480
- case FIT_MESG_NUM_RECORD: {
481
- const FIT_RECORD_MESG *record = (FIT_RECORD_MESG *) mesg;
482
- pass_record(record);
483
- break;
484
- }
485
-
486
- case FIT_MESG_NUM_EVENT: {
487
- const FIT_EVENT_MESG *event = (FIT_EVENT_MESG *) mesg;
488
- pass_event(event);
489
- break;
490
- }
491
-
492
- case FIT_MESG_NUM_DEVICE_INFO: {
493
- const FIT_DEVICE_INFO_MESG *device_info = (FIT_DEVICE_INFO_MESG *) mesg;
494
- pass_device_info(device_info);
495
- break;
496
- }
497
-
498
- case FIT_MESG_NUM_WEIGHT_SCALE: {
499
- const FIT_WEIGHT_SCALE_MESG *weight_scale_info = (FIT_WEIGHT_SCALE_MESG *) mesg;
500
- pass_weight_scale_info(weight_scale_info);
501
- break;
502
- }
503
-
504
- default: {
505
- sprintf(err_msg, "Unknown message\n");
506
- pass_message(err_msg);
507
- break;
508
- }
509
- }
510
- break;
511
- }
512
- default:
513
- break;
514
- }
515
- } while (convert_return == FIT_CONVERT_MESSAGE_AVAILABLE);
516
- }
517
-
518
- if (convert_return == FIT_CONVERT_ERROR) {
519
- sprintf(err_msg, "Error decoding file.\n");
520
- pass_err_message(err_msg);
521
- return Qnil;
522
- }
523
-
524
- if (convert_return == FIT_CONVERT_CONTINUE) {
525
- sprintf(err_msg, "Unexpected end of file.\n");
526
- pass_err_message(err_msg);
527
- return Qnil;
528
- }
529
-
530
- if (convert_return == FIT_CONVERT_PROTOCOL_VERSION_NOT_SUPPORTED) {
531
- sprintf(err_msg, "Protocol version not supported.\n");
532
- pass_err_message(err_msg);
533
- return Qnil;
534
- }
535
-
536
- if (convert_return == FIT_CONVERT_END_OF_FILE) {
537
- sprintf(err_msg, "File converted successfully.\n");
538
- pass_message(err_msg);
539
- }
540
-
541
- return Qnil;
542
- }
543
-
544
- static VALUE update_crc(VALUE self, VALUE r_crc, VALUE r_data) {
545
- FIT_UINT16 crc = NUM2USHORT(r_crc);
546
- const char* data = StringValuePtr(r_data);
547
- const FIT_UINT16 byte_count = RSTRING_LEN(r_data);
548
- return UINT2NUM(FitCRC_Update16(crc, data, byte_count));
549
- }
550
-
551
- void Init_rubyfit() {
552
- mRubyFit = rb_define_module("RubyFit");
553
- cFitParser = rb_define_class_under(mRubyFit, "FitParser", rb_cObject);
554
-
555
- //instance methods
556
- rb_define_method(cFitParser, "initialize", init, 1);
557
- rb_define_method(cFitParser, "parse", parse, 1);
558
-
559
- //attributes
560
- HANDLER_ATTR = rb_intern("@handler");
561
- rb_define_attr(cFitParser, "handler", 1, 1);
562
-
563
- // CRC helper
564
- VALUE mCRC = rb_define_module_under(mRubyFit, "CRC");
565
- rb_define_singleton_method(mCRC, "update_crc", update_crc, 2);
566
- }
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 "stdio.h"
16
+ #include "string.h"
17
+ #include "ruby.h"
18
+ #include "math.h"
19
+
20
+ #include "fit_convert.h"
21
+ #include "fit_crc.h"
22
+
23
+ /*
24
+ * garmin/dynastream, decided to pinch pennies on bits by tinkering with well
25
+ * established time offsets. This is the magic number of seconds needed to add
26
+ * to their number to get the true number of seconds since the epoch.
27
+ * This is 20 years of seconds.
28
+ */
29
+ const long GARMIN_TIME_OFFSET = 631065600;
30
+
31
+
32
+ void pass_message(VALUE handler, char *msg) {
33
+ rb_funcall(handler, rb_intern("print_msg"), 1, rb_str_new2(msg));
34
+ }
35
+
36
+ void pass_err_message(VALUE handler, char *msg) {
37
+ rb_funcall(handler, rb_intern("print_error_msg"), 1, rb_str_new2(msg));
38
+ }
39
+
40
+ static VALUE fit_pos_to_rb(FIT_SINT32 pos) {
41
+ float tmp = pos * (180.0 / pow(2,31));
42
+ tmp -= (tmp > 180.0 ? 360.0 : 0.0);
43
+ return rb_float_new(tmp);
44
+ }
45
+
46
+
47
+ static VALUE init(VALUE self, VALUE handler) {
48
+ rb_ivar_set(self, rb_intern("@handler"), handler);
49
+
50
+ return Qnil;
51
+ }
52
+
53
+ static void pass_activity(VALUE handler, const FIT_ACTIVITY_MESG *mesg) {
54
+ VALUE rh = rb_hash_new();
55
+
56
+ if(mesg->timestamp != FIT_DATE_TIME_INVALID)
57
+ rb_hash_aset(rh, rb_str_new2("timestamp"), UINT2NUM(mesg->timestamp + GARMIN_TIME_OFFSET));
58
+ if(mesg->total_timer_time != FIT_UINT32_INVALID)
59
+ rb_hash_aset(rh, rb_str_new2("total_timer_time"), rb_float_new(mesg->total_timer_time / 1000.0));
60
+ if(mesg->local_timestamp != FIT_DATE_TIME_INVALID)
61
+ rb_hash_aset(rh, rb_str_new2("local_timestamp"), rb_float_new(mesg->local_timestamp + GARMIN_TIME_OFFSET));
62
+ if(mesg->num_sessions != FIT_UINT16_INVALID)
63
+ rb_hash_aset(rh, rb_str_new2("num_sessions"), UINT2NUM(mesg->num_sessions));
64
+ if(mesg->type != FIT_ENUM_INVALID)
65
+ rb_hash_aset(rh, rb_str_new2("type"), CHR2FIX(mesg->type));
66
+ if(mesg->event != FIT_ENUM_INVALID)
67
+ rb_hash_aset(rh, rb_str_new2("event"), CHR2FIX(mesg->event));
68
+ if(mesg->event_type != FIT_ENUM_INVALID)
69
+ rb_hash_aset(rh, rb_str_new2("event_type"), CHR2FIX(mesg->event_type));
70
+ if(mesg->event_group != FIT_UINT8_INVALID)
71
+ rb_hash_aset(rh, rb_str_new2("event_group"), UINT2NUM(mesg->event_group));
72
+
73
+ rb_funcall(handler, rb_intern("on_activity"), 1, rh);
74
+ }
75
+
76
+ static void pass_record(VALUE handler, const FIT_RECORD_MESG *mesg) {
77
+ VALUE rh = rb_hash_new();
78
+
79
+ if(mesg->timestamp != FIT_DATE_TIME_INVALID)
80
+ rb_hash_aset(rh, rb_str_new2("timestamp"), UINT2NUM(mesg->timestamp + GARMIN_TIME_OFFSET));
81
+ if(mesg->position_lat != FIT_SINT32_INVALID)
82
+ rb_hash_aset(rh, rb_str_new2("position_lat"), fit_pos_to_rb(mesg->position_lat));
83
+ if(mesg->position_long != FIT_SINT32_INVALID)
84
+ rb_hash_aset(rh, rb_str_new2("position_long"), fit_pos_to_rb(mesg->position_long));
85
+ if(mesg->distance != FIT_UINT32_INVALID)
86
+ rb_hash_aset(rh, rb_str_new2("distance"), rb_float_new(mesg->distance / 100.0));
87
+ if(mesg->time_from_course != FIT_SINT32_INVALID)
88
+ rb_hash_aset(rh, rb_str_new2("time_from_course"), rb_float_new(mesg->time_from_course / 1000.0));
89
+ if(mesg->heart_rate != FIT_UINT8_INVALID)
90
+ rb_hash_aset(rh, rb_str_new2("heart_rate"), UINT2NUM(mesg->heart_rate));
91
+ if(mesg->altitude != FIT_UINT16_INVALID)
92
+ rb_hash_aset(rh, rb_str_new2("altitude"), rb_float_new(mesg->altitude / 5.0 - 500));
93
+ if(mesg->enhanced_altitude != FIT_UINT32_INVALID)
94
+ rb_hash_aset(rh, rb_str_new2("enhanced_altitude"), rb_float_new(mesg->enhanced_altitude / 5.0 - 500));
95
+ if(mesg->speed != FIT_UINT16_INVALID)
96
+ rb_hash_aset(rh, rb_str_new2("speed"), rb_float_new(mesg->speed / 1000.0));
97
+ if(mesg->enhanced_speed != FIT_UINT32_INVALID)
98
+ rb_hash_aset(rh, rb_str_new2("enhanced_speed"), rb_float_new(mesg->enhanced_speed / 1000.0));
99
+ if(mesg->grade != FIT_SINT16_INVALID)
100
+ rb_hash_aset(rh, rb_str_new2("grade"), rb_float_new(mesg->grade / 100.0));
101
+ if(mesg->power != FIT_UINT16_INVALID)
102
+ rb_hash_aset(rh, rb_str_new2("power"), UINT2NUM(mesg->power));
103
+ if(mesg->cadence != FIT_UINT8_INVALID)
104
+ rb_hash_aset(rh, rb_str_new2("cadence"), UINT2NUM(mesg->cadence));
105
+ if(mesg->resistance != FIT_UINT8_INVALID)
106
+ rb_hash_aset(rh, rb_str_new2("resistance"), UINT2NUM(mesg->resistance));
107
+ if(mesg->cycle_length != FIT_UINT8_INVALID)
108
+ rb_hash_aset(rh, rb_str_new2("cycle_length"), UINT2NUM(mesg->cycle_length));
109
+ if(mesg->temperature != FIT_SINT8_INVALID)
110
+ rb_hash_aset(rh, rb_str_new2("temperature"), INT2FIX(mesg->temperature));
111
+
112
+ if(mesg->left_right_balance != FIT_UINT8_INVALID)
113
+ rb_hash_aset(rh, rb_str_new2("left_right_balance"), UINT2NUM(mesg->left_right_balance & FIT_LEFT_RIGHT_BALANCE_MASK));
114
+ if(mesg->left_torque_effectiveness != FIT_UINT8_INVALID)
115
+ rb_hash_aset(rh, rb_str_new2("left_torque_effectiveness"), UINT2NUM(mesg->left_torque_effectiveness));
116
+ if(mesg->right_torque_effectiveness != FIT_UINT8_INVALID)
117
+ rb_hash_aset(rh, rb_str_new2("right_torque_effectiveness"), UINT2NUM(mesg->right_torque_effectiveness));
118
+ if(mesg->left_pedal_smoothness != FIT_UINT8_INVALID)
119
+ rb_hash_aset(rh, rb_str_new2("left_pedal_smoothness"), UINT2NUM(mesg->left_pedal_smoothness));
120
+ if(mesg->right_pedal_smoothness != FIT_UINT8_INVALID)
121
+ rb_hash_aset(rh, rb_str_new2("right_pedal_smoothness"), UINT2NUM(mesg->right_pedal_smoothness));
122
+ if(mesg->combined_pedal_smoothness != FIT_UINT8_INVALID)
123
+ rb_hash_aset(rh, rb_str_new2("combined_pedal_smoothness"), UINT2NUM(mesg->combined_pedal_smoothness));
124
+
125
+ rb_funcall(handler, rb_intern("on_record"), 1, rh);
126
+ }
127
+
128
+ static void pass_lap(VALUE handler, const FIT_LAP_MESG *mesg) {
129
+ VALUE rh = rb_hash_new();
130
+
131
+ if(mesg->timestamp != FIT_DATE_TIME_INVALID)
132
+ rb_hash_aset(rh, rb_str_new2("timestamp"), UINT2NUM(mesg->timestamp + GARMIN_TIME_OFFSET));
133
+ if(mesg->start_time != FIT_DATE_TIME_INVALID)
134
+ rb_hash_aset(rh, rb_str_new2("start_time"), UINT2NUM(mesg->start_time + GARMIN_TIME_OFFSET));
135
+ if(mesg->start_position_lat != FIT_SINT32_INVALID)
136
+ rb_hash_aset(rh, rb_str_new2("start_position_lat"), fit_pos_to_rb(mesg->start_position_lat));
137
+ if(mesg->start_position_long != FIT_SINT32_INVALID)
138
+ rb_hash_aset(rh, rb_str_new2("start_position_long"), fit_pos_to_rb(mesg->start_position_long));
139
+ if(mesg->end_position_lat != FIT_SINT32_INVALID)
140
+ rb_hash_aset(rh, rb_str_new2("end_position_lat"), fit_pos_to_rb(mesg->end_position_lat));
141
+ if(mesg->end_position_long != FIT_SINT32_INVALID)
142
+ rb_hash_aset(rh, rb_str_new2("end_position_long"), fit_pos_to_rb(mesg->end_position_long));
143
+ if(mesg->total_elapsed_time != FIT_UINT32_INVALID)
144
+ rb_hash_aset(rh, rb_str_new2("total_elapsed_time"), UINT2NUM(mesg->total_elapsed_time));
145
+ if(mesg->total_timer_time != FIT_UINT32_INVALID)
146
+ rb_hash_aset(rh, rb_str_new2("total_timer_time"), rb_float_new(mesg->total_timer_time / 1000.0));
147
+ if(mesg->total_distance != FIT_UINT32_INVALID)
148
+ rb_hash_aset(rh, rb_str_new2("total_distance"), rb_float_new(mesg->total_distance / 100.0));
149
+ if(mesg->total_cycles != FIT_UINT32_INVALID)
150
+ rb_hash_aset(rh, rb_str_new2("total_cycles"), UINT2NUM(mesg->total_cycles));
151
+ if(mesg->message_index != FIT_UINT16_INVALID)
152
+ rb_hash_aset(rh, rb_str_new2("message_index"), UINT2NUM(mesg->message_index));
153
+ if(mesg->total_calories != FIT_UINT16_INVALID)
154
+ rb_hash_aset(rh, rb_str_new2("total_calories"), UINT2NUM(mesg->total_calories));
155
+ if(mesg->total_fat_calories != FIT_UINT16_INVALID)
156
+ rb_hash_aset(rh, rb_str_new2("total_fat_calories"), UINT2NUM(mesg->total_fat_calories));
157
+ if(mesg->avg_speed != FIT_UINT16_INVALID)
158
+ rb_hash_aset(rh, rb_str_new2("avg_speed"), rb_float_new(mesg->avg_speed / 1000.0));
159
+ if(mesg->max_speed != FIT_UINT16_INVALID)
160
+ rb_hash_aset(rh, rb_str_new2("max_speed"), rb_float_new(mesg->max_speed / 1000.0));
161
+ if(mesg->enhanced_avg_speed != FIT_UINT32_INVALID)
162
+ rb_hash_aset(rh, rb_str_new2("enhanced_avg_speed"), rb_float_new(mesg->enhanced_avg_speed / 1000.0));
163
+ if(mesg->enhanced_max_speed != FIT_UINT32_INVALID)
164
+ rb_hash_aset(rh, rb_str_new2("enhanced_max_speed"), rb_float_new(mesg->enhanced_max_speed / 1000.0));
165
+ if(mesg->avg_altitude != FIT_UINT16_INVALID)
166
+ rb_hash_aset(rh, rb_str_new2("avg_altitude"), rb_float_new(mesg->avg_altitude / 5.0 - 500));
167
+ if(mesg->max_altitude != FIT_UINT16_INVALID)
168
+ rb_hash_aset(rh, rb_str_new2("max_altitude"), rb_float_new(mesg->max_altitude / 5.0 - 500));
169
+ if(mesg->min_altitude != FIT_UINT16_INVALID)
170
+ rb_hash_aset(rh, rb_str_new2("min_altitude"), rb_float_new(mesg->min_altitude / 5.0 - 500));
171
+ if(mesg->enhanced_avg_altitude != FIT_UINT32_INVALID)
172
+ rb_hash_aset(rh, rb_str_new2("enhanced_avg_altitude"), rb_float_new(mesg->enhanced_avg_altitude / 5.0 - 500));
173
+ if(mesg->enhanced_max_altitude != FIT_UINT32_INVALID)
174
+ rb_hash_aset(rh, rb_str_new2("enhanced_max_altitude"), rb_float_new(mesg->enhanced_max_altitude / 5.0 - 500));
175
+ if(mesg->enhanced_min_altitude != FIT_UINT32_INVALID)
176
+ rb_hash_aset(rh, rb_str_new2("enhanced_min_altitude"), rb_float_new(mesg->enhanced_min_altitude / 5.0 - 500));
177
+ if(mesg->avg_power != FIT_UINT16_INVALID)
178
+ rb_hash_aset(rh, rb_str_new2("avg_power"), UINT2NUM(mesg->avg_power));
179
+ if(mesg->max_power != FIT_UINT16_INVALID)
180
+ rb_hash_aset(rh, rb_str_new2("max_power"), UINT2NUM(mesg->max_power));
181
+ if(mesg->total_ascent != FIT_UINT16_INVALID)
182
+ rb_hash_aset(rh, rb_str_new2("total_ascent"), UINT2NUM(mesg->total_ascent));
183
+ if(mesg->total_descent != FIT_UINT16_INVALID)
184
+ rb_hash_aset(rh, rb_str_new2("total_descent"), UINT2NUM(mesg->total_descent));
185
+ if(mesg->event != FIT_EVENT_INVALID)
186
+ rb_hash_aset(rh, rb_str_new2("event"), CHR2FIX(mesg->event));
187
+ if(mesg->event_type != FIT_EVENT_INVALID)
188
+ rb_hash_aset(rh, rb_str_new2("event_type"), CHR2FIX(mesg->event_type));
189
+ if(mesg->avg_heart_rate != FIT_UINT8_INVALID)
190
+ rb_hash_aset(rh, rb_str_new2("avg_heart_rate"), UINT2NUM(mesg->avg_heart_rate));
191
+ if(mesg->max_heart_rate != FIT_UINT8_INVALID)
192
+ rb_hash_aset(rh, rb_str_new2("max_heart_rate"), UINT2NUM(mesg->max_heart_rate));
193
+ if(mesg->avg_cadence != FIT_UINT8_INVALID)
194
+ rb_hash_aset(rh, rb_str_new2("avg_cadence"), UINT2NUM(mesg->avg_cadence));
195
+ if(mesg->max_cadence != FIT_UINT8_INVALID)
196
+ rb_hash_aset(rh, rb_str_new2("max_cadence"), UINT2NUM(mesg->max_cadence));
197
+ if(mesg->intensity != FIT_INTENSITY_INVALID)
198
+ rb_hash_aset(rh, rb_str_new2("intensity"), CHR2FIX(mesg->intensity));
199
+ if(mesg->lap_trigger != FIT_LAP_TRIGGER_INVALID)
200
+ rb_hash_aset(rh, rb_str_new2("lap_trigger"), CHR2FIX(mesg->lap_trigger));
201
+ if(mesg->sport != FIT_SPORT_INVALID)
202
+ rb_hash_aset(rh, rb_str_new2("sport"), CHR2FIX(mesg->sport));
203
+ if(mesg->event_group != FIT_UINT8_INVALID)
204
+ rb_hash_aset(rh, rb_str_new2("event_group"), UINT2NUM(mesg->event_group));
205
+
206
+ rb_funcall(handler, rb_intern("on_lap"), 1, rh);
207
+ }
208
+
209
+ static void pass_session(VALUE handler, const FIT_SESSION_MESG *mesg) {
210
+ VALUE rh = rb_hash_new();
211
+
212
+ if(mesg->timestamp != FIT_DATE_TIME_INVALID)
213
+ rb_hash_aset(rh, rb_str_new2("timestamp"), UINT2NUM(mesg->timestamp + GARMIN_TIME_OFFSET));
214
+ if(mesg->start_time != FIT_DATE_TIME_INVALID)
215
+ rb_hash_aset(rh, rb_str_new2("start_time"), UINT2NUM(mesg->start_time + GARMIN_TIME_OFFSET));
216
+ if(mesg->start_position_lat != FIT_SINT32_INVALID)
217
+ rb_hash_aset(rh, rb_str_new2("start_position_lat"), fit_pos_to_rb(mesg->start_position_lat));
218
+ if(mesg->start_position_long != FIT_SINT32_INVALID)
219
+ rb_hash_aset(rh, rb_str_new2("start_position_long"), fit_pos_to_rb(mesg->start_position_long));
220
+ if(mesg->total_elapsed_time != FIT_UINT32_INVALID)
221
+ rb_hash_aset(rh, rb_str_new2("total_elapsed_time"), rb_float_new(mesg->total_elapsed_time / 1000.0));
222
+ if(mesg->total_timer_time != FIT_UINT32_INVALID)
223
+ rb_hash_aset(rh, rb_str_new2("total_timer_time"), rb_float_new(mesg->total_timer_time / 1000.0));
224
+ if(mesg->total_distance != FIT_UINT32_INVALID)
225
+ rb_hash_aset(rh, rb_str_new2("total_distance"), rb_float_new(mesg->total_distance / 100.0));
226
+ if(mesg->total_cycles != FIT_UINT32_INVALID)
227
+ rb_hash_aset(rh, rb_str_new2("total_cycles"), UINT2NUM(mesg->total_cycles));
228
+ if(mesg->nec_lat != FIT_SINT32_INVALID)
229
+ rb_hash_aset(rh, rb_str_new2("nec_lat"), fit_pos_to_rb(mesg->nec_lat));
230
+ if(mesg->nec_long != FIT_SINT32_INVALID)
231
+ rb_hash_aset(rh, rb_str_new2("nec_long"), fit_pos_to_rb(mesg->nec_long));
232
+ if(mesg->swc_lat != FIT_SINT32_INVALID)
233
+ rb_hash_aset(rh, rb_str_new2("swc_lat"), fit_pos_to_rb(mesg->swc_lat));
234
+ if(mesg->swc_long != FIT_SINT32_INVALID)
235
+ rb_hash_aset(rh, rb_str_new2("swc_long"), fit_pos_to_rb(mesg->swc_long));
236
+ if(mesg->message_index != FIT_MESSAGE_INDEX_INVALID)
237
+ rb_hash_aset(rh, rb_str_new2("message_index"), UINT2NUM(mesg->message_index));
238
+ if(mesg->total_calories != FIT_UINT16_INVALID)
239
+ rb_hash_aset(rh, rb_str_new2("total_calories"), UINT2NUM(mesg->total_calories));
240
+ if(mesg->total_fat_calories != FIT_UINT16_INVALID)
241
+ rb_hash_aset(rh, rb_str_new2("total_fat_calories"), UINT2NUM(mesg->total_fat_calories));
242
+ if(mesg->avg_speed != FIT_UINT16_INVALID)
243
+ rb_hash_aset(rh, rb_str_new2("avg_speed"), rb_float_new(mesg->avg_speed / 1000.0));
244
+ if(mesg->max_speed != FIT_UINT16_INVALID)
245
+ rb_hash_aset(rh, rb_str_new2("max_speed"), rb_float_new(mesg->max_speed / 1000.0));
246
+ if(mesg->avg_power != FIT_UINT16_INVALID)
247
+ rb_hash_aset(rh, rb_str_new2("avg_power"), UINT2NUM(mesg->avg_power));
248
+ if(mesg->max_power != FIT_UINT16_INVALID)
249
+ rb_hash_aset(rh, rb_str_new2("max_power"), UINT2NUM(mesg->max_power));
250
+ if(mesg->total_ascent != FIT_UINT16_INVALID)
251
+ rb_hash_aset(rh, rb_str_new2("total_ascent"), UINT2NUM(mesg->total_ascent));
252
+ if(mesg->total_descent != FIT_UINT16_INVALID)
253
+ rb_hash_aset(rh, rb_str_new2("total_descent"), UINT2NUM(mesg->total_descent));
254
+ if(mesg->first_lap_index != FIT_UINT16_INVALID)
255
+ rb_hash_aset(rh, rb_str_new2("first_lap_index"), UINT2NUM(mesg->first_lap_index));
256
+ if(mesg->num_laps != FIT_UINT16_INVALID)
257
+ rb_hash_aset(rh, rb_str_new2("num_laps"), UINT2NUM(mesg->num_laps));
258
+ if(mesg->event != FIT_EVENT_INVALID)
259
+ rb_hash_aset(rh, rb_str_new2("event"), CHR2FIX(mesg->event));
260
+ if(mesg->event_type != FIT_EVENT_INVALID)
261
+ rb_hash_aset(rh, rb_str_new2("event_type"), CHR2FIX(mesg->event_type));
262
+ if(mesg->avg_heart_rate != FIT_UINT8_INVALID)
263
+ rb_hash_aset(rh, rb_str_new2("avg_heart_rate"), UINT2NUM(mesg->avg_heart_rate));
264
+ if(mesg->max_heart_rate != FIT_UINT8_INVALID)
265
+ rb_hash_aset(rh, rb_str_new2("max_heart_rate"), UINT2NUM(mesg->max_heart_rate));
266
+ if(mesg->avg_cadence != FIT_UINT8_INVALID)
267
+ rb_hash_aset(rh, rb_str_new2("avg_cadence"), UINT2NUM(mesg->avg_cadence));
268
+ if(mesg->max_cadence != FIT_UINT8_INVALID)
269
+ rb_hash_aset(rh, rb_str_new2("max_cadence"), UINT2NUM(mesg->max_cadence));
270
+ if(mesg->sport != FIT_SPORT_INVALID)
271
+ rb_hash_aset(rh, rb_str_new2("sport"), CHR2FIX(mesg->sport));
272
+ if(mesg->sub_sport != FIT_SUB_SPORT_INVALID)
273
+ rb_hash_aset(rh, rb_str_new2("sub_sport"), CHR2FIX(mesg->sub_sport));
274
+ if(mesg->event_group != FIT_UINT8_INVALID)
275
+ rb_hash_aset(rh, rb_str_new2("event_group"), UINT2NUM(mesg->event_group));
276
+ if(mesg->total_training_effect != FIT_UINT8_INVALID)
277
+ rb_hash_aset(rh, rb_str_new2("total_training_effect"), UINT2NUM(mesg->total_training_effect));
278
+
279
+ rb_funcall(handler, rb_intern("on_session"), 1, rh);
280
+ }
281
+
282
+ static void pass_user_profile(VALUE handler, const FIT_USER_PROFILE_MESG *mesg) {
283
+ VALUE rh = rb_hash_new();
284
+
285
+ if(*mesg->friendly_name != FIT_STRING_INVALID)
286
+ rb_hash_aset(rh, rb_str_new2("friendly_name"), rb_str_new2(mesg->friendly_name));
287
+ if(mesg->message_index != FIT_MESSAGE_INDEX_INVALID)
288
+ rb_hash_aset(rh, rb_str_new2("message_index"), UINT2NUM(mesg->message_index));
289
+ if(mesg->weight != FIT_UINT16_INVALID)
290
+ rb_hash_aset(rh, rb_str_new2("weight"), rb_float_new(mesg->weight / 10.0));
291
+ if(mesg->gender != FIT_GENDER_INVALID)
292
+ rb_hash_aset(rh, rb_str_new2("gender"), UINT2NUM(mesg->gender));
293
+ if(mesg->age != FIT_UINT8_INVALID)
294
+ rb_hash_aset(rh, rb_str_new2("age"), UINT2NUM(mesg->age));
295
+ if(mesg->height != FIT_UINT8_INVALID)
296
+ rb_hash_aset(rh, rb_str_new2("height"), rb_float_new(mesg->height / 100.0));
297
+ if(mesg->language != FIT_LANGUAGE_INVALID)
298
+ rb_hash_aset(rh, rb_str_new2("language"), UINT2NUM(mesg->language));
299
+ if(mesg->elev_setting != FIT_DISPLAY_MEASURE_INVALID)
300
+ rb_hash_aset(rh, rb_str_new2("elev_setting"), UINT2NUM(mesg->elev_setting));
301
+ if(mesg->weight_setting != FIT_DISPLAY_MEASURE_INVALID)
302
+ rb_hash_aset(rh, rb_str_new2("weight_setting"), UINT2NUM(mesg->weight_setting));
303
+ if(mesg->resting_heart_rate != FIT_UINT8_INVALID)
304
+ rb_hash_aset(rh, rb_str_new2("resting_heart_rate"), UINT2NUM(mesg->resting_heart_rate));
305
+ if(mesg->default_max_running_heart_rate != FIT_UINT8_INVALID)
306
+ rb_hash_aset(rh, rb_str_new2("default_max_running_heart_rate"), UINT2NUM(mesg->default_max_running_heart_rate));
307
+ if(mesg->default_max_biking_heart_rate != FIT_UINT8_INVALID)
308
+ rb_hash_aset(rh, rb_str_new2("default_max_biking_heart_rate"), UINT2NUM(mesg->default_max_biking_heart_rate));
309
+ if(mesg->default_max_heart_rate != FIT_UINT8_INVALID)
310
+ rb_hash_aset(rh, rb_str_new2("default_max_heart_rate"), UINT2NUM(mesg->default_max_heart_rate));
311
+ if(mesg->hr_setting != FIT_DISPLAY_HEART_INVALID)
312
+ rb_hash_aset(rh, rb_str_new2("hr_setting"), UINT2NUM(mesg->hr_setting));
313
+ if(mesg->speed_setting != FIT_DISPLAY_MEASURE_INVALID)
314
+ rb_hash_aset(rh, rb_str_new2("speed_setting"), UINT2NUM(mesg->speed_setting));
315
+ if(mesg->dist_setting != FIT_DISPLAY_MEASURE_INVALID)
316
+ rb_hash_aset(rh, rb_str_new2("dist_setting"), UINT2NUM(mesg->dist_setting));
317
+ if(mesg->power_setting != FIT_DISPLAY_POWER_INVALID)
318
+ rb_hash_aset(rh, rb_str_new2("power_setting"), UINT2NUM(mesg->power_setting));
319
+ if(mesg->activity_class != FIT_ACTIVITY_CLASS_INVALID)
320
+ rb_hash_aset(rh, rb_str_new2("activity_class"), UINT2NUM(mesg->activity_class));
321
+ if(mesg->position_setting != FIT_DISPLAY_POSITION_INVALID)
322
+ rb_hash_aset(rh, rb_str_new2("position_setting"), UINT2NUM(mesg->position_setting));
323
+
324
+ rb_funcall(handler, rb_intern("on_user_profile"), 1, rh);
325
+ }
326
+
327
+ static void pass_event(VALUE handler, const FIT_EVENT_MESG *mesg) {
328
+ VALUE rh = rb_hash_new();
329
+
330
+ if(mesg->timestamp != FIT_DATE_TIME_INVALID)
331
+ rb_hash_aset(rh, rb_str_new2("timestamp"), UINT2NUM(mesg->timestamp + GARMIN_TIME_OFFSET));
332
+ if(mesg->data != FIT_UINT32_INVALID)
333
+ rb_hash_aset(rh, rb_str_new2("data"), UINT2NUM(mesg->data));
334
+ if(mesg->data16 != FIT_UINT16_INVALID)
335
+ rb_hash_aset(rh, rb_str_new2("data16"), UINT2NUM(mesg->data16));
336
+ if(mesg->timestamp != FIT_EVENT_INVALID)
337
+ rb_hash_aset(rh, rb_str_new2("event"), CHR2FIX(mesg->event));
338
+ if(mesg->timestamp != FIT_EVENT_TYPE_INVALID)
339
+ rb_hash_aset(rh, rb_str_new2("event_type"), CHR2FIX(mesg->event_type));
340
+ if(mesg->event_group != FIT_UINT8_INVALID)
341
+ rb_hash_aset(rh, rb_str_new2("event_group"), UINT2NUM(mesg->event_group));
342
+
343
+ rb_funcall(handler, rb_intern("on_event"), 1, rh);
344
+ }
345
+
346
+ static void pass_device_info(VALUE handler, const FIT_DEVICE_INFO_MESG *mesg) {
347
+ VALUE rh = rb_hash_new();
348
+
349
+ if(mesg->timestamp != FIT_DATE_TIME_INVALID)
350
+ rb_hash_aset(rh, rb_str_new2("timestamp"), UINT2NUM(mesg->timestamp + GARMIN_TIME_OFFSET));
351
+ if(mesg->serial_number != FIT_UINT32Z_INVALID)
352
+ rb_hash_aset(rh, rb_str_new2("serial_number"), UINT2NUM(mesg->serial_number));
353
+ if(mesg->manufacturer != FIT_MANUFACTURER_INVALID)
354
+ rb_hash_aset(rh, rb_str_new2("manufacturer"), UINT2NUM(mesg->manufacturer));
355
+ if(mesg->product != FIT_UINT16_INVALID)
356
+ rb_hash_aset(rh, rb_str_new2("product"), UINT2NUM(mesg->product));
357
+ if(mesg->software_version != FIT_UINT16_INVALID)
358
+ rb_hash_aset(rh, rb_str_new2("software_version"), UINT2NUM(mesg->software_version));
359
+ if(mesg->battery_voltage != FIT_UINT16_INVALID)
360
+ rb_hash_aset(rh, rb_str_new2("battery_voltage"), UINT2NUM(mesg->battery_voltage));
361
+ if(mesg->device_index != FIT_DEVICE_INDEX_INVALID)
362
+ rb_hash_aset(rh, rb_str_new2("device_index"), UINT2NUM(mesg->device_index));
363
+ if(mesg->device_type != FIT_ANTPLUS_DEVICE_TYPE_INVALID)
364
+ rb_hash_aset(rh, rb_str_new2("device_type"), UINT2NUM(mesg->device_type));
365
+ if(mesg->hardware_version != FIT_UINT8_INVALID)
366
+ rb_hash_aset(rh, rb_str_new2("hardware_version"), UINT2NUM(mesg->hardware_version));
367
+ if(mesg->battery_status != FIT_BATTERY_STATUS_INVALID)
368
+ rb_hash_aset(rh, rb_str_new2("battery_status"), UINT2NUM(mesg->battery_status));
369
+
370
+ rb_funcall(handler, rb_intern("on_device_info"), 1, rh);
371
+ }
372
+
373
+ static void pass_weight_scale_info(VALUE handler, const FIT_WEIGHT_SCALE_MESG *mesg) {
374
+ VALUE rh = rb_hash_new();
375
+
376
+ if(mesg->timestamp != FIT_DATE_TIME_INVALID)
377
+ rb_hash_aset(rh, rb_str_new2("timestamp"), UINT2NUM(mesg->timestamp + GARMIN_TIME_OFFSET));
378
+ if(mesg->weight != FIT_WEIGHT_INVALID)
379
+ rb_hash_aset(rh, rb_str_new2("weight"), rb_float_new(mesg->weight / 100.0));
380
+ if(mesg->percent_fat != FIT_UINT16_INVALID)
381
+ rb_hash_aset(rh, rb_str_new2("percent_fat"), rb_float_new(mesg->percent_fat / 100.0));
382
+ if(mesg->percent_hydration != FIT_UINT16_INVALID)
383
+ rb_hash_aset(rh, rb_str_new2("percent_hydration"), rb_float_new(mesg->percent_hydration / 100.0));
384
+ if(mesg->visceral_fat_mass != FIT_UINT16_INVALID)
385
+ rb_hash_aset(rh, rb_str_new2("visceral_fat_mass"), rb_float_new(mesg->visceral_fat_mass / 100.0));
386
+ if(mesg->bone_mass != FIT_UINT16_INVALID)
387
+ rb_hash_aset(rh, rb_str_new2("bone_mass"), rb_float_new(mesg->bone_mass / 100.0));
388
+ if(mesg->muscle_mass != FIT_UINT16_INVALID)
389
+ rb_hash_aset(rh, rb_str_new2("muscle_mass"), rb_float_new(mesg->muscle_mass / 100.0));
390
+ if(mesg->basal_met != FIT_UINT16_INVALID)
391
+ rb_hash_aset(rh, rb_str_new2("basal_met"), rb_float_new(mesg->basal_met / 4.0));
392
+ if(mesg->active_met != FIT_UINT16_INVALID)
393
+ rb_hash_aset(rh, rb_str_new2("active_met"), rb_float_new(mesg->active_met / 4.0));
394
+ if(mesg->physique_rating != FIT_UINT8_INVALID)
395
+ rb_hash_aset(rh, rb_str_new2("physique_rating"), rb_float_new(mesg->physique_rating));
396
+ if(mesg->metabolic_age != FIT_UINT8_INVALID)
397
+ rb_hash_aset(rh, rb_str_new2("metabolic_age"), rb_float_new(mesg->metabolic_age));
398
+ if(mesg->visceral_fat_rating != FIT_UINT8_INVALID)
399
+ rb_hash_aset(rh, rb_str_new2("visceral_fat_rating"), rb_float_new(mesg->visceral_fat_rating));
400
+
401
+ rb_funcall(handler, rb_intern("on_weight_scale_info"), 1, rh);
402
+ }
403
+
404
+ static VALUE parse(VALUE self, VALUE original_str) {
405
+ int i = 0;
406
+ VALUE str = StringValue(original_str);
407
+ VALUE handler = rb_ivar_get(self, rb_intern("@handler"));
408
+ char *p = RSTRING_PTR(str);
409
+ char err_msg[128];
410
+
411
+ FIT_UINT8 buf[8];
412
+ FIT_CONVERT_RETURN convert_return = FIT_CONVERT_CONTINUE;
413
+ FIT_UINT32 buf_size;
414
+ FIT_CONVERT_STATE state;
415
+ FitConvert_Init(&state, FIT_TRUE);
416
+
417
+ if(RSTRING_LEN(str) == 0) {
418
+ //sprintf(err_msg, "Passed in string with length of 0!");
419
+ pass_err_message(handler, err_msg);
420
+ return Qnil;
421
+ }
422
+
423
+ while(i < RSTRING_LEN(str) && (convert_return == FIT_CONVERT_CONTINUE)) {
424
+ for(buf_size=0;(buf_size < sizeof(buf)) && (p != NULL); buf_size++) {
425
+ buf[buf_size] = *p;
426
+ p++;
427
+ i++;
428
+ }
429
+
430
+ do {
431
+ convert_return = FitConvert_Read(&state, buf, buf_size);
432
+
433
+ switch(convert_return) {
434
+ case FIT_CONVERT_MESSAGE_AVAILABLE: {
435
+ const FIT_UINT8 *mesg = FitConvert_GetMessageData(&state);
436
+ FIT_UINT16 mesg_num = FitConvert_GetMessageNumber(&state);
437
+
438
+ switch(mesg_num) {
439
+ case FIT_MESG_NUM_FILE_ID: {
440
+ break;
441
+ }
442
+
443
+ case FIT_MESG_NUM_USER_PROFILE: {
444
+ const FIT_USER_PROFILE_MESG *user_profile = (FIT_USER_PROFILE_MESG *) mesg;
445
+ pass_user_profile(handler, user_profile);
446
+ break;
447
+ }
448
+
449
+ case FIT_MESG_NUM_ACTIVITY: {
450
+ const FIT_ACTIVITY_MESG *activity = (FIT_ACTIVITY_MESG *) mesg;
451
+ pass_activity(handler, activity);
452
+
453
+ {
454
+ FIT_ACTIVITY_MESG old_mesg;
455
+ old_mesg.num_sessions = 1;
456
+ FitConvert_RestoreFields(&state, &old_mesg);
457
+ sprintf(err_msg, "Restored num_sessions=1 - Activity: timestamp=%u, type=%u, event=%u, event_type=%u, num_sessions=%u\n", activity->timestamp, activity->type, activity->event, activity->event_type, activity->num_sessions);
458
+ pass_message(handler, err_msg);
459
+ }
460
+ break;
461
+ }
462
+
463
+ case FIT_MESG_NUM_SESSION: {
464
+ const FIT_SESSION_MESG *session = (FIT_SESSION_MESG *) mesg;
465
+ pass_session(handler, session);
466
+ break;
467
+ }
468
+
469
+ case FIT_MESG_NUM_LAP: {
470
+ const FIT_LAP_MESG *lap = (FIT_LAP_MESG *) mesg;
471
+ pass_lap(handler, lap);
472
+ break;
473
+ }
474
+
475
+ case FIT_MESG_NUM_RECORD: {
476
+ const FIT_RECORD_MESG *record = (FIT_RECORD_MESG *) mesg;
477
+ pass_record(handler, record);
478
+ break;
479
+ }
480
+
481
+ case FIT_MESG_NUM_EVENT: {
482
+ const FIT_EVENT_MESG *event = (FIT_EVENT_MESG *) mesg;
483
+ pass_event(handler, event);
484
+ break;
485
+ }
486
+
487
+ case FIT_MESG_NUM_DEVICE_INFO: {
488
+ const FIT_DEVICE_INFO_MESG *device_info = (FIT_DEVICE_INFO_MESG *) mesg;
489
+ pass_device_info(handler, device_info);
490
+ break;
491
+ }
492
+
493
+ case FIT_MESG_NUM_WEIGHT_SCALE: {
494
+ const FIT_WEIGHT_SCALE_MESG *weight_scale_info = (FIT_WEIGHT_SCALE_MESG *) mesg;
495
+ pass_weight_scale_info(handler, weight_scale_info);
496
+ break;
497
+ }
498
+
499
+ default: {
500
+ sprintf(err_msg, "Unknown message\n");
501
+ pass_message(handler, err_msg);
502
+ break;
503
+ }
504
+ }
505
+ break;
506
+ }
507
+ default:
508
+ break;
509
+ }
510
+ } while (convert_return == FIT_CONVERT_MESSAGE_AVAILABLE);
511
+ }
512
+
513
+ if (convert_return == FIT_CONVERT_ERROR) {
514
+ sprintf(err_msg, "Error decoding file.\n");
515
+ pass_err_message(handler, err_msg);
516
+ return Qnil;
517
+ }
518
+
519
+ if (convert_return == FIT_CONVERT_CONTINUE) {
520
+ sprintf(err_msg, "Unexpected end of file.\n");
521
+ pass_err_message(handler, err_msg);
522
+ return Qnil;
523
+ }
524
+
525
+ if (convert_return == FIT_CONVERT_PROTOCOL_VERSION_NOT_SUPPORTED) {
526
+ sprintf(err_msg, "Protocol version not supported.\n");
527
+ pass_err_message(handler, err_msg);
528
+ return Qnil;
529
+ }
530
+
531
+ if (convert_return == FIT_CONVERT_END_OF_FILE) {
532
+ sprintf(err_msg, "File converted successfully.\n");
533
+ pass_message(handler, err_msg);
534
+ }
535
+
536
+ return Qnil;
537
+ }
538
+
539
+ static VALUE update_crc(VALUE self, VALUE r_crc, VALUE r_data) {
540
+ FIT_UINT16 crc = NUM2USHORT(r_crc);
541
+ const char* data = StringValuePtr(r_data);
542
+ const FIT_UINT16 byte_count = RSTRING_LEN(r_data);
543
+ return UINT2NUM(FitCRC_Update16(crc, data, byte_count));
544
+ }
545
+
546
+ void Init_rubyfit() {
547
+ VALUE mRubyFit = rb_define_module("RubyFit");
548
+ VALUE cFitParser = rb_define_class_under(mRubyFit, "FitParser", rb_cObject);
549
+
550
+ //instance methods
551
+ rb_define_method(cFitParser, "initialize", init, 1);
552
+ rb_define_method(cFitParser, "parse", parse, 1);
553
+
554
+ //attributes
555
+ rb_define_attr(cFitParser, "handler", 1, 1);
556
+
557
+ // CRC helper
558
+ VALUE mCRC = rb_define_module_under(mRubyFit, "CRC");
559
+ rb_define_singleton_method(mCRC, "update_crc", update_crc, 2);
560
+ }