rubyfit 0.0.11 → 0.0.16

Sign up to get free protection for your applications and to get access to all the features.
@@ -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
+ }