rubyfit 0.0.2
Sign up to get free protection for your applications and to get access to all the features.
- data/ext/rubyfit/extconf.rb +2 -0
- data/ext/rubyfit/fit.c +281 -0
- data/ext/rubyfit/fit.h +253 -0
- data/ext/rubyfit/fit_config.h +36 -0
- data/ext/rubyfit/fit_convert.c +439 -0
- data/ext/rubyfit/fit_convert.h +154 -0
- data/ext/rubyfit/fit_crc.c +43 -0
- data/ext/rubyfit/fit_crc.h +35 -0
- data/ext/rubyfit/fit_product.c +21 -0
- data/ext/rubyfit/fit_product.h +21 -0
- data/ext/rubyfit/fit_sdk.c +618 -0
- data/ext/rubyfit/fit_sdk.h +2083 -0
- data/ext/rubyfit/rubyfit.c +590 -0
- data/lib/rubyfit/version.rb +3 -0
- data/lib/rubyfit.rb +2 -0
- metadata +63 -0
@@ -0,0 +1,590 @@
|
|
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
|
+
|
22
|
+
VALUE mRubyFit;
|
23
|
+
VALUE cFitParser;
|
24
|
+
VALUE cFitHandler;
|
25
|
+
VALUE cFitHandlerPrintFun;
|
26
|
+
VALUE cFitHandlerActivityFun;
|
27
|
+
VALUE cFitHandlerRecordFun;
|
28
|
+
VALUE cFitHandlerLapFun;
|
29
|
+
VALUE cFitHandlerSessionFun;
|
30
|
+
VALUE cFitHandlerDeviceInfoFun;
|
31
|
+
VALUE cFitHandlerUserProfileFun;
|
32
|
+
VALUE cFitHandlerEventFun;
|
33
|
+
VALUE cFitHandlerWeightScaleInfoFun;
|
34
|
+
static ID HANDLER_ATTR;
|
35
|
+
//garmin/dynastream, in their infinite wisdom, decided to pinch pennies on bits
|
36
|
+
//by tinkering with well established time offsets. This is the magic number of
|
37
|
+
//seconds needed to add to their number to get the true number of seconds since
|
38
|
+
//the epoch. For those math challenged, this is 20 years of seconds.
|
39
|
+
const GARMIN_SUCKS_OFFSET = 631065600;
|
40
|
+
|
41
|
+
|
42
|
+
void pass_message(char *msg) {
|
43
|
+
rb_funcall(cFitHandler, cFitHandlerPrintFun, 1, rb_str_new2(msg));
|
44
|
+
}
|
45
|
+
|
46
|
+
static VALUE fit_pos_to_rb(FIT_SINT32 pos) {
|
47
|
+
float tmp = pos * (180.0 / pow(2,31));
|
48
|
+
tmp -= (tmp > 180.0 ? 360.0 : 0.0);
|
49
|
+
return rb_float_new(tmp);
|
50
|
+
}
|
51
|
+
|
52
|
+
|
53
|
+
static VALUE init(VALUE self, VALUE handler) {
|
54
|
+
cFitHandler = handler;
|
55
|
+
rb_ivar_set(self, HANDLER_ATTR, handler);
|
56
|
+
|
57
|
+
//callbacks
|
58
|
+
cFitHandlerPrintFun = rb_intern("print_msg");
|
59
|
+
cFitHandlerActivityFun = rb_intern("on_activity");
|
60
|
+
cFitHandlerSessionFun = rb_intern("on_session");
|
61
|
+
cFitHandlerLapFun = rb_intern("on_lap");
|
62
|
+
cFitHandlerRecordFun = rb_intern("on_record");
|
63
|
+
cFitHandlerEventFun = rb_intern("on_event");
|
64
|
+
cFitHandlerDeviceInfoFun = rb_intern("on_device_info");
|
65
|
+
cFitHandlerUserProfileFun = rb_intern("on_user_profile");
|
66
|
+
cFitHandlerWeightScaleInfoFun = rb_intern("on_weight_scale_info");
|
67
|
+
|
68
|
+
return Qnil;
|
69
|
+
}
|
70
|
+
|
71
|
+
static pass_activity(const FIT_ACTIVITY_MESG *mesg) {
|
72
|
+
VALUE rh = rb_hash_new();
|
73
|
+
|
74
|
+
if(mesg->timestamp != FIT_DATE_TIME_INVALID)
|
75
|
+
rb_hash_aset(rh, rb_str_new2("timestamp"), UINT2NUM(mesg->timestamp + GARMIN_SUCKS_OFFSET));
|
76
|
+
if(mesg->total_timer_time != FIT_UINT32_INVALID)
|
77
|
+
rb_hash_aset(rh, rb_str_new2("total_timer_time"), rb_float_new(mesg->total_timer_time / 1000.0));
|
78
|
+
if(mesg->local_timestamp != FIT_DATE_TIME_INVALID)
|
79
|
+
rb_hash_aset(rh, rb_str_new2("local_timestamp"), rb_float_new(mesg->local_timestamp + GARMIN_SUCKS_OFFSET));
|
80
|
+
if(mesg->num_sessions != FIT_UINT16_INVALID)
|
81
|
+
rb_hash_aset(rh, rb_str_new2("num_sessions"), UINT2NUM(mesg->num_sessions));
|
82
|
+
if(mesg->type != FIT_ENUM_INVALID)
|
83
|
+
rb_hash_aset(rh, rb_str_new2("type"), CHR2FIX(mesg->type));
|
84
|
+
if(mesg->event != FIT_ENUM_INVALID)
|
85
|
+
rb_hash_aset(rh, rb_str_new2("event"), CHR2FIX(mesg->event));
|
86
|
+
if(mesg->event_type != FIT_ENUM_INVALID)
|
87
|
+
rb_hash_aset(rh, rb_str_new2("event_type"), CHR2FIX(mesg->event_type));
|
88
|
+
if(mesg->event_group != FIT_UINT8_INVALID)
|
89
|
+
rb_hash_aset(rh, rb_str_new2("event_group"), UINT2NUM(mesg->event_group));
|
90
|
+
|
91
|
+
rb_funcall(cFitHandler, cFitHandlerActivityFun, 1, rh);
|
92
|
+
}
|
93
|
+
|
94
|
+
static pass_record(const FIT_RECORD_MESG *mesg) {
|
95
|
+
VALUE rh = rb_hash_new();
|
96
|
+
|
97
|
+
if(mesg->timestamp != FIT_DATE_TIME_INVALID)
|
98
|
+
rb_hash_aset(rh, rb_str_new2("timestamp"), UINT2NUM(mesg->timestamp + GARMIN_SUCKS_OFFSET));
|
99
|
+
if(mesg->position_lat != FIT_SINT32_INVALID)
|
100
|
+
rb_hash_aset(rh, rb_str_new2("position_lat"), fit_pos_to_rb(mesg->position_lat));
|
101
|
+
if(mesg->position_long != FIT_SINT32_INVALID)
|
102
|
+
rb_hash_aset(rh, rb_str_new2("position_long"), fit_pos_to_rb(mesg->position_long));
|
103
|
+
if(mesg->distance != FIT_UINT32_INVALID)
|
104
|
+
rb_hash_aset(rh, rb_str_new2("distance"), rb_float_new(mesg->distance / 100.0));
|
105
|
+
if(mesg->time_from_course != FIT_SINT32_INVALID)
|
106
|
+
rb_hash_aset(rh, rb_str_new2("time_from_course"), rb_float_new(mesg->time_from_course / 1000.0));
|
107
|
+
if(mesg->heart_rate != FIT_UINT8_INVALID)
|
108
|
+
rb_hash_aset(rh, rb_str_new2("heart_rate"), UINT2NUM(mesg->heart_rate));
|
109
|
+
if(mesg->altitude != FIT_UINT16_INVALID)
|
110
|
+
rb_hash_aset(rh, rb_str_new2("altitude"), rb_float_new(mesg->altitude / 5.0 - 500));
|
111
|
+
if(mesg->speed != FIT_UINT16_INVALID)
|
112
|
+
rb_hash_aset(rh, rb_str_new2("speed"), rb_float_new(mesg->speed / 1000.0));
|
113
|
+
if(mesg->grade != FIT_SINT16_INVALID)
|
114
|
+
rb_hash_aset(rh, rb_str_new2("grade"), rb_float_new(mesg->grade / 100.0));
|
115
|
+
if(mesg->power != FIT_UINT16_INVALID)
|
116
|
+
rb_hash_aset(rh, rb_str_new2("power"), UINT2NUM(mesg->power));
|
117
|
+
if(mesg->cadence != FIT_UINT8_INVALID)
|
118
|
+
rb_hash_aset(rh, rb_str_new2("cadence"), UINT2NUM(mesg->cadence));
|
119
|
+
if(mesg->resistance != FIT_UINT8_INVALID)
|
120
|
+
rb_hash_aset(rh, rb_str_new2("resistance"), UINT2NUM(mesg->resistance));
|
121
|
+
if(mesg->cycle_length != FIT_UINT8_INVALID)
|
122
|
+
rb_hash_aset(rh, rb_str_new2("cycle_length"), UINT2NUM(mesg->cycle_length));
|
123
|
+
if(mesg->temperature != FIT_SINT8_INVALID)
|
124
|
+
rb_hash_aset(rh, rb_str_new2("temperature"), INT2FIX(mesg->temperature));
|
125
|
+
|
126
|
+
rb_funcall(cFitHandler, cFitHandlerRecordFun, 1, rh);
|
127
|
+
}
|
128
|
+
|
129
|
+
static pass_lap(const FIT_LAP_MESG *mesg) {
|
130
|
+
VALUE rh = rb_hash_new();
|
131
|
+
|
132
|
+
if(mesg->timestamp != FIT_DATE_TIME_INVALID)
|
133
|
+
rb_hash_aset(rh, rb_str_new2("timestamp"), UINT2NUM(mesg->timestamp + GARMIN_SUCKS_OFFSET));
|
134
|
+
if(mesg->start_time != FIT_DATE_TIME_INVALID)
|
135
|
+
rb_hash_aset(rh, rb_str_new2("start_time"), UINT2NUM(mesg->start_time + GARMIN_SUCKS_OFFSET));
|
136
|
+
if(mesg->start_position_lat != FIT_SINT32_INVALID)
|
137
|
+
rb_hash_aset(rh, rb_str_new2("start_position_lat"), fit_pos_to_rb(mesg->start_position_lat));
|
138
|
+
if(mesg->start_position_long != FIT_SINT32_INVALID)
|
139
|
+
rb_hash_aset(rh, rb_str_new2("start_position_long"), fit_pos_to_rb(mesg->start_position_long));
|
140
|
+
if(mesg->end_position_lat != FIT_SINT32_INVALID)
|
141
|
+
rb_hash_aset(rh, rb_str_new2("end_position_lat"), fit_pos_to_rb(mesg->end_position_lat));
|
142
|
+
if(mesg->end_position_long != FIT_SINT32_INVALID)
|
143
|
+
rb_hash_aset(rh, rb_str_new2("end_position_long"), fit_pos_to_rb(mesg->end_position_long));
|
144
|
+
if(mesg->total_elapsed_time != FIT_UINT32_INVALID)
|
145
|
+
rb_hash_aset(rh, rb_str_new2("total_elapsed_time"), UINT2NUM(mesg->total_elapsed_time));
|
146
|
+
if(mesg->total_timer_time != FIT_UINT32_INVALID)
|
147
|
+
rb_hash_aset(rh, rb_str_new2("total_timer_time"), rb_float_new(mesg->total_timer_time / 1000.0));
|
148
|
+
if(mesg->total_distance != FIT_UINT32_INVALID)
|
149
|
+
rb_hash_aset(rh, rb_str_new2("total_distance"), rb_float_new(mesg->total_distance / 100.0));
|
150
|
+
if(mesg->total_cycles != FIT_UINT32_INVALID)
|
151
|
+
rb_hash_aset(rh, rb_str_new2("total_cycles"), UINT2NUM(mesg->total_cycles));
|
152
|
+
if(mesg->nec_lat != FIT_SINT32_INVALID)
|
153
|
+
rb_hash_aset(rh, rb_str_new2("nec_lat"), fit_pos_to_rb(mesg->nec_lat));
|
154
|
+
if(mesg->nec_long != FIT_SINT32_INVALID)
|
155
|
+
rb_hash_aset(rh, rb_str_new2("nec_long"), fit_pos_to_rb(mesg->nec_long));
|
156
|
+
if(mesg->swc_lat != FIT_SINT32_INVALID)
|
157
|
+
rb_hash_aset(rh, rb_str_new2("swc_lat"), fit_pos_to_rb(mesg->swc_lat));
|
158
|
+
if(mesg->swc_long != FIT_SINT32_INVALID)
|
159
|
+
rb_hash_aset(rh, rb_str_new2("swc_long"), fit_pos_to_rb(mesg->swc_long));
|
160
|
+
if(mesg->message_index != FIT_UINT16_INVALID)
|
161
|
+
rb_hash_aset(rh, rb_str_new2("message_index"), UINT2NUM(mesg->message_index));
|
162
|
+
if(mesg->total_calories != FIT_UINT16_INVALID)
|
163
|
+
rb_hash_aset(rh, rb_str_new2("total_calories"), UINT2NUM(mesg->total_calories));
|
164
|
+
if(mesg->total_fat_calories != FIT_UINT16_INVALID)
|
165
|
+
rb_hash_aset(rh, rb_str_new2("total_fat_calories"), UINT2NUM(mesg->total_fat_calories));
|
166
|
+
if(mesg->avg_speed != FIT_UINT16_INVALID)
|
167
|
+
rb_hash_aset(rh, rb_str_new2("avg_speed"), rb_float_new(mesg->avg_speed / 1000.0));
|
168
|
+
if(mesg->max_speed != FIT_UINT16_INVALID)
|
169
|
+
rb_hash_aset(rh, rb_str_new2("max_speed"), rb_float_new(mesg->max_speed / 1000.0));
|
170
|
+
if(mesg->avg_power != FIT_UINT16_INVALID)
|
171
|
+
rb_hash_aset(rh, rb_str_new2("avg_power"), UINT2NUM(mesg->avg_power));
|
172
|
+
if(mesg->max_power != FIT_UINT16_INVALID)
|
173
|
+
rb_hash_aset(rh, rb_str_new2("max_power"), UINT2NUM(mesg->max_power));
|
174
|
+
if(mesg->total_ascent != FIT_UINT16_INVALID)
|
175
|
+
rb_hash_aset(rh, rb_str_new2("total_ascent"), UINT2NUM(mesg->total_ascent));
|
176
|
+
if(mesg->total_descent != FIT_UINT16_INVALID)
|
177
|
+
rb_hash_aset(rh, rb_str_new2("total_descent"), UINT2NUM(mesg->total_descent));
|
178
|
+
if(mesg->event != FIT_EVENT_INVALID)
|
179
|
+
rb_hash_aset(rh, rb_str_new2("event"), CHR2FIX(mesg->event));
|
180
|
+
if(mesg->event_type != FIT_EVENT_INVALID)
|
181
|
+
rb_hash_aset(rh, rb_str_new2("event_type"), CHR2FIX(mesg->event_type));
|
182
|
+
if(mesg->avg_heart_rate != FIT_UINT8_INVALID)
|
183
|
+
rb_hash_aset(rh, rb_str_new2("avg_heart_rate"), UINT2NUM(mesg->avg_heart_rate));
|
184
|
+
if(mesg->max_heart_rate != FIT_UINT8_INVALID)
|
185
|
+
rb_hash_aset(rh, rb_str_new2("max_heart_rate"), UINT2NUM(mesg->max_heart_rate));
|
186
|
+
if(mesg->avg_cadence != FIT_UINT8_INVALID)
|
187
|
+
rb_hash_aset(rh, rb_str_new2("avg_cadence"), UINT2NUM(mesg->avg_cadence));
|
188
|
+
if(mesg->max_cadence != FIT_UINT8_INVALID)
|
189
|
+
rb_hash_aset(rh, rb_str_new2("max_cadence"), UINT2NUM(mesg->max_cadence));
|
190
|
+
if(mesg->intensity != FIT_INTENSITY_INVALID)
|
191
|
+
rb_hash_aset(rh, rb_str_new2("intensity"), CHR2FIX(mesg->intensity));
|
192
|
+
if(mesg->lap_trigger != FIT_LAP_TRIGGER_INVALID)
|
193
|
+
rb_hash_aset(rh, rb_str_new2("lap_trigger"), CHR2FIX(mesg->lap_trigger));
|
194
|
+
if(mesg->sport != FIT_SPORT_INVALID)
|
195
|
+
rb_hash_aset(rh, rb_str_new2("sport"), CHR2FIX(mesg->sport));
|
196
|
+
if(mesg->event_group != FIT_UINT8_INVALID)
|
197
|
+
rb_hash_aset(rh, rb_str_new2("event_group"), UINT2NUM(mesg->event_group));
|
198
|
+
|
199
|
+
rb_funcall(cFitHandler, cFitHandlerLapFun, 1, rh);
|
200
|
+
}
|
201
|
+
|
202
|
+
static pass_session(const FIT_SESSION_MESG *mesg) {
|
203
|
+
VALUE rh = rb_hash_new();
|
204
|
+
|
205
|
+
if(mesg->timestamp != FIT_DATE_TIME_INVALID)
|
206
|
+
rb_hash_aset(rh, rb_str_new2("timestamp"), UINT2NUM(mesg->timestamp + GARMIN_SUCKS_OFFSET));
|
207
|
+
if(mesg->start_time != FIT_DATE_TIME_INVALID)
|
208
|
+
rb_hash_aset(rh, rb_str_new2("start_time"), UINT2NUM(mesg->start_time + GARMIN_SUCKS_OFFSET));
|
209
|
+
if(mesg->start_position_lat != FIT_SINT32_INVALID)
|
210
|
+
rb_hash_aset(rh, rb_str_new2("start_position_lat"), fit_pos_to_rb(mesg->start_position_lat));
|
211
|
+
if(mesg->start_position_long != FIT_SINT32_INVALID)
|
212
|
+
rb_hash_aset(rh, rb_str_new2("start_position_long"), fit_pos_to_rb(mesg->start_position_long));
|
213
|
+
if(mesg->total_elapsed_time != FIT_UINT32_INVALID)
|
214
|
+
rb_hash_aset(rh, rb_str_new2("total_elapsed_time"), rb_float_new(mesg->total_elapsed_time / 1000.0));
|
215
|
+
if(mesg->total_timer_time != FIT_UINT32_INVALID)
|
216
|
+
rb_hash_aset(rh, rb_str_new2("total_timer_time"), rb_float_new(mesg->total_timer_time / 1000.0));
|
217
|
+
if(mesg->total_distance != FIT_UINT32_INVALID)
|
218
|
+
rb_hash_aset(rh, rb_str_new2("total_distance"), rb_float_new(mesg->total_distance / 100.0));
|
219
|
+
if(mesg->total_cycles != FIT_UINT32_INVALID)
|
220
|
+
rb_hash_aset(rh, rb_str_new2("total_cycles"), UINT2NUM(mesg->total_cycles));
|
221
|
+
if(mesg->nec_lat != FIT_SINT32_INVALID)
|
222
|
+
rb_hash_aset(rh, rb_str_new2("nec_lat"), fit_pos_to_rb(mesg->nec_lat));
|
223
|
+
if(mesg->nec_long != FIT_SINT32_INVALID)
|
224
|
+
rb_hash_aset(rh, rb_str_new2("nec_long"), fit_pos_to_rb(mesg->nec_long));
|
225
|
+
if(mesg->swc_lat != FIT_SINT32_INVALID)
|
226
|
+
rb_hash_aset(rh, rb_str_new2("swc_lat"), fit_pos_to_rb(mesg->swc_lat));
|
227
|
+
if(mesg->swc_long != FIT_SINT32_INVALID)
|
228
|
+
rb_hash_aset(rh, rb_str_new2("swc_long"), fit_pos_to_rb(mesg->swc_long));
|
229
|
+
if(mesg->message_index != FIT_MESSAGE_INDEX_INVALID)
|
230
|
+
rb_hash_aset(rh, rb_str_new2("message_index"), UINT2NUM(mesg->message_index));
|
231
|
+
if(mesg->total_calories != FIT_UINT16_INVALID)
|
232
|
+
rb_hash_aset(rh, rb_str_new2("total_calories"), UINT2NUM(mesg->total_calories));
|
233
|
+
if(mesg->total_fat_calories != FIT_UINT16_INVALID)
|
234
|
+
rb_hash_aset(rh, rb_str_new2("total_fat_calories"), UINT2NUM(mesg->total_fat_calories));
|
235
|
+
if(mesg->avg_speed != FIT_UINT16_INVALID)
|
236
|
+
rb_hash_aset(rh, rb_str_new2("avg_speed"), rb_float_new(mesg->avg_speed / 1000.0));
|
237
|
+
if(mesg->max_speed != FIT_UINT16_INVALID)
|
238
|
+
rb_hash_aset(rh, rb_str_new2("max_speed"), rb_float_new(mesg->max_speed / 1000.0));
|
239
|
+
if(mesg->avg_power != FIT_UINT16_INVALID)
|
240
|
+
rb_hash_aset(rh, rb_str_new2("avg_power"), UINT2NUM(mesg->avg_power));
|
241
|
+
if(mesg->max_power != FIT_UINT16_INVALID)
|
242
|
+
rb_hash_aset(rh, rb_str_new2("max_power"), UINT2NUM(mesg->max_power));
|
243
|
+
if(mesg->total_ascent != FIT_UINT16_INVALID)
|
244
|
+
rb_hash_aset(rh, rb_str_new2("total_ascent"), UINT2NUM(mesg->total_ascent));
|
245
|
+
if(mesg->total_descent != FIT_UINT16_INVALID)
|
246
|
+
rb_hash_aset(rh, rb_str_new2("total_descent"), UINT2NUM(mesg->total_descent));
|
247
|
+
if(mesg->first_lap_index != FIT_UINT16_INVALID)
|
248
|
+
rb_hash_aset(rh, rb_str_new2("first_lap_index"), UINT2NUM(mesg->first_lap_index));
|
249
|
+
if(mesg->num_laps != FIT_UINT16_INVALID)
|
250
|
+
rb_hash_aset(rh, rb_str_new2("num_laps"), UINT2NUM(mesg->num_laps));
|
251
|
+
if(mesg->event != FIT_EVENT_INVALID)
|
252
|
+
rb_hash_aset(rh, rb_str_new2("event"), CHR2FIX(mesg->event));
|
253
|
+
if(mesg->event_type != FIT_EVENT_INVALID)
|
254
|
+
rb_hash_aset(rh, rb_str_new2("event_type"), CHR2FIX(mesg->event_type));
|
255
|
+
if(mesg->avg_heart_rate != FIT_UINT8_INVALID)
|
256
|
+
rb_hash_aset(rh, rb_str_new2("avg_heart_rate"), UINT2NUM(mesg->avg_heart_rate));
|
257
|
+
if(mesg->max_heart_rate != FIT_UINT8_INVALID)
|
258
|
+
rb_hash_aset(rh, rb_str_new2("max_heart_rate"), UINT2NUM(mesg->max_heart_rate));
|
259
|
+
if(mesg->avg_cadence != FIT_UINT8_INVALID)
|
260
|
+
rb_hash_aset(rh, rb_str_new2("avg_cadence"), UINT2NUM(mesg->avg_cadence));
|
261
|
+
if(mesg->max_cadence != FIT_UINT8_INVALID)
|
262
|
+
rb_hash_aset(rh, rb_str_new2("max_cadence"), UINT2NUM(mesg->max_cadence));
|
263
|
+
if(mesg->sport != FIT_SPORT_INVALID)
|
264
|
+
rb_hash_aset(rh, rb_str_new2("sport"), CHR2FIX(mesg->sport));
|
265
|
+
if(mesg->sub_sport != FIT_SUB_SPORT_INVALID)
|
266
|
+
rb_hash_aset(rh, rb_str_new2("sub_sport"), CHR2FIX(mesg->sub_sport));
|
267
|
+
if(mesg->event_group != FIT_UINT8_INVALID)
|
268
|
+
rb_hash_aset(rh, rb_str_new2("event_group"), UINT2NUM(mesg->event_group));
|
269
|
+
if(mesg->total_training_effect != FIT_UINT8_INVALID)
|
270
|
+
rb_hash_aset(rh, rb_str_new2("total_training_effect"), UINT2NUM(mesg->total_training_effect));
|
271
|
+
|
272
|
+
rb_funcall(cFitHandler, cFitHandlerSessionFun, 1, rh);
|
273
|
+
}
|
274
|
+
|
275
|
+
static pass_user_profile(const FIT_USER_PROFILE_MESG *mesg) {
|
276
|
+
VALUE rh = rb_hash_new();
|
277
|
+
|
278
|
+
if(mesg->friendly_name != FIT_STRING_INVALID)
|
279
|
+
rb_hash_aset(rh, rb_str_new2("friendly_name"), rb_str_new2(mesg->friendly_name));
|
280
|
+
if(mesg->message_index != FIT_MESSAGE_INDEX_INVALID)
|
281
|
+
rb_hash_aset(rh, rb_str_new2("message_index"), UINT2NUM(mesg->message_index));
|
282
|
+
if(mesg->weight != FIT_UINT16_INVALID)
|
283
|
+
rb_hash_aset(rh, rb_str_new2("weight"), rb_float_new(mesg->weight / 10.0));
|
284
|
+
if(mesg->gender != FIT_GENDER_INVALID)
|
285
|
+
rb_hash_aset(rh, rb_str_new2("gender"), UINT2NUM(mesg->gender));
|
286
|
+
if(mesg->age != FIT_UINT8_INVALID)
|
287
|
+
rb_hash_aset(rh, rb_str_new2("age"), UINT2NUM(mesg->age));
|
288
|
+
if(mesg->height != FIT_UINT8_INVALID)
|
289
|
+
rb_hash_aset(rh, rb_str_new2("height"), rb_float_new(mesg->height / 100.0));
|
290
|
+
if(mesg->language != FIT_LANGUAGE_INVALID)
|
291
|
+
rb_hash_aset(rh, rb_str_new2("language"), UINT2NUM(mesg->language));
|
292
|
+
if(mesg->elev_setting != FIT_DISPLAY_MEASURE_INVALID)
|
293
|
+
rb_hash_aset(rh, rb_str_new2("elev_setting"), UINT2NUM(mesg->elev_setting));
|
294
|
+
if(mesg->weight_setting != FIT_DISPLAY_MEASURE_INVALID)
|
295
|
+
rb_hash_aset(rh, rb_str_new2("weight_setting"), UINT2NUM(mesg->weight_setting));
|
296
|
+
if(mesg->resting_heart_rate != FIT_UINT8_INVALID)
|
297
|
+
rb_hash_aset(rh, rb_str_new2("resting_heart_rate"), UINT2NUM(mesg->resting_heart_rate));
|
298
|
+
if(mesg->default_max_running_heart_rate != FIT_UINT8_INVALID)
|
299
|
+
rb_hash_aset(rh, rb_str_new2("default_max_running_heart_rate"), UINT2NUM(mesg->default_max_running_heart_rate));
|
300
|
+
if(mesg->default_max_biking_heart_rate != FIT_UINT8_INVALID)
|
301
|
+
rb_hash_aset(rh, rb_str_new2("default_max_biking_heart_rate"), UINT2NUM(mesg->default_max_biking_heart_rate));
|
302
|
+
if(mesg->default_max_heart_rate != FIT_UINT8_INVALID)
|
303
|
+
rb_hash_aset(rh, rb_str_new2("default_max_heart_rate"), UINT2NUM(mesg->default_max_heart_rate));
|
304
|
+
if(mesg->hr_setting != FIT_DISPLAY_HEART_INVALID)
|
305
|
+
rb_hash_aset(rh, rb_str_new2("hr_setting"), UINT2NUM(mesg->hr_setting));
|
306
|
+
if(mesg->speed_setting != FIT_DISPLAY_MEASURE_INVALID)
|
307
|
+
rb_hash_aset(rh, rb_str_new2("speed_setting"), UINT2NUM(mesg->speed_setting));
|
308
|
+
if(mesg->dist_setting != FIT_DISPLAY_MEASURE_INVALID)
|
309
|
+
rb_hash_aset(rh, rb_str_new2("dist_setting"), UINT2NUM(mesg->dist_setting));
|
310
|
+
if(mesg->power_setting != FIT_DISPLAY_POWER_INVALID)
|
311
|
+
rb_hash_aset(rh, rb_str_new2("power_setting"), UINT2NUM(mesg->power_setting));
|
312
|
+
if(mesg->activity_class != FIT_ACTIVITY_CLASS_INVALID)
|
313
|
+
rb_hash_aset(rh, rb_str_new2("activity_class"), UINT2NUM(mesg->activity_class));
|
314
|
+
if(mesg->position_setting != FIT_DISPLAY_POSITION_INVALID)
|
315
|
+
rb_hash_aset(rh, rb_str_new2("position_setting"), UINT2NUM(mesg->position_setting));
|
316
|
+
|
317
|
+
rb_funcall(cFitHandler, cFitHandlerUserProfileFun, 1, rh);
|
318
|
+
}
|
319
|
+
|
320
|
+
static pass_event(const FIT_EVENT_MESG *mesg) {
|
321
|
+
VALUE rh = rb_hash_new();
|
322
|
+
|
323
|
+
if(mesg->timestamp != FIT_DATE_TIME_INVALID)
|
324
|
+
rb_hash_aset(rh, rb_str_new2("timestamp"), UINT2NUM(mesg->timestamp + GARMIN_SUCKS_OFFSET));
|
325
|
+
if(mesg->data != FIT_UINT32_INVALID)
|
326
|
+
rb_hash_aset(rh, rb_str_new2("data"), UINT2NUM(mesg->data));
|
327
|
+
if(mesg->data16 != FIT_UINT16_INVALID)
|
328
|
+
rb_hash_aset(rh, rb_str_new2("data16"), UINT2NUM(mesg->data16));
|
329
|
+
if(mesg->timestamp != FIT_EVENT_INVALID)
|
330
|
+
rb_hash_aset(rh, rb_str_new2("event"), CHR2FIX(mesg->event));
|
331
|
+
if(mesg->timestamp != FIT_EVENT_TYPE_INVALID)
|
332
|
+
rb_hash_aset(rh, rb_str_new2("event_type"), CHR2FIX(mesg->event_type));
|
333
|
+
if(mesg->event_group != FIT_UINT8_INVALID)
|
334
|
+
rb_hash_aset(rh, rb_str_new2("event_group"), UINT2NUM(mesg->event_group));
|
335
|
+
|
336
|
+
rb_funcall(cFitHandler, cFitHandlerEventFun, 1, rh);
|
337
|
+
}
|
338
|
+
|
339
|
+
static pass_device_info(const FIT_DEVICE_INFO_MESG *mesg) {
|
340
|
+
VALUE rh = rb_hash_new();
|
341
|
+
|
342
|
+
if(mesg->timestamp != FIT_DATE_TIME_INVALID)
|
343
|
+
rb_hash_aset(rh, rb_str_new2("timestamp"), UINT2NUM(mesg->timestamp + GARMIN_SUCKS_OFFSET));
|
344
|
+
if(mesg->serial_number != FIT_UINT32Z_INVALID)
|
345
|
+
rb_hash_aset(rh, rb_str_new2("serial_number"), UINT2NUM(mesg->serial_number));
|
346
|
+
if(mesg->manufacturer != FIT_MANUFACTURER_INVALID)
|
347
|
+
rb_hash_aset(rh, rb_str_new2("manufacturer"), UINT2NUM(mesg->manufacturer));
|
348
|
+
if(mesg->product != FIT_UINT16_INVALID)
|
349
|
+
rb_hash_aset(rh, rb_str_new2("product"), UINT2NUM(mesg->product));
|
350
|
+
if(mesg->software_version != FIT_UINT16_INVALID)
|
351
|
+
rb_hash_aset(rh, rb_str_new2("software_version"), UINT2NUM(mesg->software_version));
|
352
|
+
if(mesg->battery_voltage != FIT_UINT16_INVALID)
|
353
|
+
rb_hash_aset(rh, rb_str_new2("battery_voltage"), UINT2NUM(mesg->battery_voltage));
|
354
|
+
if(mesg->device_index != FIT_DEVICE_INDEX_INVALID)
|
355
|
+
rb_hash_aset(rh, rb_str_new2("device_index"), UINT2NUM(mesg->device_index));
|
356
|
+
if(mesg->device_type != FIT_DEVICE_TYPE_INVALID)
|
357
|
+
rb_hash_aset(rh, rb_str_new2("device_type"), UINT2NUM(mesg->device_type));
|
358
|
+
if(mesg->hardware_version != FIT_UINT8_INVALID)
|
359
|
+
rb_hash_aset(rh, rb_str_new2("hardware_version"), UINT2NUM(mesg->hardware_version));
|
360
|
+
if(mesg->battery_status != FIT_BATTERY_STATUS_INVALID)
|
361
|
+
rb_hash_aset(rh, rb_str_new2("battery_status"), UINT2NUM(mesg->battery_status));
|
362
|
+
|
363
|
+
rb_funcall(cFitHandler, cFitHandlerDeviceInfoFun, 1, rh);
|
364
|
+
}
|
365
|
+
|
366
|
+
static pass_weight_scale_info(const FIT_WEIGHT_SCALE_MESG *mesg) {
|
367
|
+
VALUE rh = rb_hash_new();
|
368
|
+
|
369
|
+
if(mesg->timestamp != FIT_DATE_TIME_INVALID)
|
370
|
+
rb_hash_aset(rh, rb_str_new2("timestamp"), UINT2NUM(mesg->timestamp + GARMIN_SUCKS_OFFSET));
|
371
|
+
if(mesg->weight != FIT_WEIGHT_INVALID)
|
372
|
+
rb_hash_aset(rh, rb_str_new2("weight"), rb_float_new(mesg->weight / 100.0));
|
373
|
+
if(mesg->percent_fat != FIT_UINT16_INVALID)
|
374
|
+
rb_hash_aset(rh, rb_str_new2("percent_fat"), rb_float_new(mesg->percent_fat / 100.0));
|
375
|
+
if(mesg->percent_hydration != FIT_UINT16_INVALID)
|
376
|
+
rb_hash_aset(rh, rb_str_new2("percent_hydration"), rb_float_new(mesg->percent_hydration / 100.0));
|
377
|
+
if(mesg->visceral_fat_mass != FIT_UINT16_INVALID)
|
378
|
+
rb_hash_aset(rh, rb_str_new2("visceral_fat_mass"), rb_float_new(mesg->visceral_fat_mass / 100.0));
|
379
|
+
if(mesg->bone_mass != FIT_UINT16_INVALID)
|
380
|
+
rb_hash_aset(rh, rb_str_new2("bone_mass"), rb_float_new(mesg->bone_mass / 100.0));
|
381
|
+
if(mesg->muscle_mass != FIT_UINT16_INVALID)
|
382
|
+
rb_hash_aset(rh, rb_str_new2("muscle_mass"), rb_float_new(mesg->muscle_mass / 100.0));
|
383
|
+
if(mesg->basal_met != FIT_UINT16_INVALID)
|
384
|
+
rb_hash_aset(rh, rb_str_new2("basal_met"), rb_float_new(mesg->basal_met / 4.0));
|
385
|
+
if(mesg->active_met != FIT_UINT16_INVALID)
|
386
|
+
rb_hash_aset(rh, rb_str_new2("active_met"), rb_float_new(mesg->active_met / 4.0));
|
387
|
+
if(mesg->physique_rating != FIT_UINT8_INVALID)
|
388
|
+
rb_hash_aset(rh, rb_str_new2("physique_rating"), rb_float_new(mesg->physique_rating));
|
389
|
+
if(mesg->metabolic_age != FIT_UINT8_INVALID)
|
390
|
+
rb_hash_aset(rh, rb_str_new2("metabolic_age"), rb_float_new(mesg->metabolic_age));
|
391
|
+
if(mesg->visceral_fat_rating != FIT_UINT8_INVALID)
|
392
|
+
rb_hash_aset(rh, rb_str_new2("visceral_fat_rating"), rb_float_new(mesg->visceral_fat_rating));
|
393
|
+
|
394
|
+
rb_funcall(cFitHandler, cFitHandlerWeightScaleInfoFun, 1, rh);
|
395
|
+
}
|
396
|
+
|
397
|
+
static VALUE parse(VALUE self, VALUE original_str) {
|
398
|
+
int i = 0;
|
399
|
+
VALUE str = StringValue(original_str);
|
400
|
+
char *p = RSTRING_PTR(str);
|
401
|
+
char err_msg[128];
|
402
|
+
|
403
|
+
FIT_UINT8 buf[8];
|
404
|
+
FIT_CONVERT_RETURN convert_return = FIT_CONVERT_CONTINUE;
|
405
|
+
FIT_UINT32 buf_size;
|
406
|
+
FIT_UINT32 mesg_index = 0;
|
407
|
+
#if defined(FIT_CONVERT_MULTI_THREAD)
|
408
|
+
FIT_CONVERT_STATE state;
|
409
|
+
#endif
|
410
|
+
|
411
|
+
#if defined(FIT_CONVERT_MULTI_THREAD)
|
412
|
+
FitConvert_Init(&state, FIT_TRUE);
|
413
|
+
#else
|
414
|
+
FitConvert_Init(FIT_TRUE);
|
415
|
+
#endif
|
416
|
+
|
417
|
+
if(RSTRING_LEN(str) == 0) {
|
418
|
+
//sprintf(err_msg, "Passed in string with length of 0!");
|
419
|
+
pass_message(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
|
+
#if defined(FIT_CONVERT_MULTI_THREAD)
|
432
|
+
convert_return = FitConvert_Read(&state, buf, buf_size);
|
433
|
+
#else
|
434
|
+
convert_return = FitConvert_Read(buf, buf_size);
|
435
|
+
#endif
|
436
|
+
|
437
|
+
switch(convert_return) {
|
438
|
+
case FIT_CONVERT_MESSAGE_AVAILABLE: {
|
439
|
+
#if defined(FIT_CONVERT_MULTI_THREAD)
|
440
|
+
const FIT_UINT8 *mesg = FitConvert_GetMessageData(&state);
|
441
|
+
FIT_UINT16 mesg_num = FitConvert_GetMessageNumber(&state);
|
442
|
+
#else
|
443
|
+
const FIT_UINT8 *mesg = FitConvert_GetMessageData();
|
444
|
+
FIT_UINT16 mesg_num = FitConvert_GetMessageNumber();
|
445
|
+
#endif
|
446
|
+
|
447
|
+
//sprintf(err_msg, "Mesg %d (%d) - ", mesg_index++, mesg_num);
|
448
|
+
//pass_message(err_msg);
|
449
|
+
|
450
|
+
switch(mesg_num) {
|
451
|
+
case FIT_MESG_NUM_FILE_ID: {
|
452
|
+
const FIT_FILE_ID_MESG *id = (FIT_FILE_ID_MESG *) mesg;
|
453
|
+
//sprintf(err_msg, "File ID: type=%u, number=%u\n", id->type, id->number);
|
454
|
+
//pass_message(err_msg);
|
455
|
+
break;
|
456
|
+
}
|
457
|
+
|
458
|
+
case FIT_MESG_NUM_USER_PROFILE: {
|
459
|
+
const FIT_USER_PROFILE_MESG *user_profile = (FIT_USER_PROFILE_MESG *) mesg;
|
460
|
+
//sprintf(err_msg, "User Profile: weight=%0.1fkg\n", user_profile->weight / 10.0f);
|
461
|
+
//pass_message(err_msg);
|
462
|
+
pass_user_profile(user_profile);
|
463
|
+
break;
|
464
|
+
}
|
465
|
+
|
466
|
+
case FIT_MESG_NUM_ACTIVITY: {
|
467
|
+
const FIT_ACTIVITY_MESG *activity = (FIT_ACTIVITY_MESG *) mesg;
|
468
|
+
//sprintf(err_msg, "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);
|
469
|
+
//pass_message(err_msg);
|
470
|
+
pass_activity(activity);
|
471
|
+
|
472
|
+
{
|
473
|
+
FIT_ACTIVITY_MESG old_mesg;
|
474
|
+
old_mesg.num_sessions = 1;
|
475
|
+
#if defined(FIT_CONVERT_MULTI_THREAD)
|
476
|
+
FitConvert_RestoreFields(&state, &old_mesg);
|
477
|
+
#else
|
478
|
+
FitConvert_RestoreFields(&old_mesg);
|
479
|
+
#endif
|
480
|
+
//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);
|
481
|
+
//pass_message(err_msg);
|
482
|
+
}
|
483
|
+
break;
|
484
|
+
}
|
485
|
+
|
486
|
+
case FIT_MESG_NUM_SESSION: {
|
487
|
+
const FIT_SESSION_MESG *session = (FIT_SESSION_MESG *) mesg;
|
488
|
+
//sprintf(err_msg, "Session: timestamp=%u\n", session->timestamp);
|
489
|
+
//pass_message(err_msg);
|
490
|
+
pass_session(session);
|
491
|
+
break;
|
492
|
+
}
|
493
|
+
|
494
|
+
case FIT_MESG_NUM_LAP: {
|
495
|
+
const FIT_LAP_MESG *lap = (FIT_LAP_MESG *) mesg;
|
496
|
+
//sprintf(err_msg, "Lap: timestamp=%u, total_ascent=%u, total_distance=%f\n", lap->timestamp, lap->total_ascent, (lap->total_distance / 100.0) / 1000.0 * 0.621371192);
|
497
|
+
//pass_message(err_msg);
|
498
|
+
pass_lap(lap);
|
499
|
+
break;
|
500
|
+
}
|
501
|
+
|
502
|
+
case FIT_MESG_NUM_RECORD: {
|
503
|
+
const FIT_RECORD_MESG *record = (FIT_RECORD_MESG *) mesg;
|
504
|
+
|
505
|
+
//sprintf(err_msg, "Record: timestamp=%u", record->timestamp);
|
506
|
+
//pass_message(err_msg);
|
507
|
+
pass_record(record);
|
508
|
+
break;
|
509
|
+
}
|
510
|
+
|
511
|
+
case FIT_MESG_NUM_EVENT: {
|
512
|
+
const FIT_EVENT_MESG *event = (FIT_EVENT_MESG *) mesg;
|
513
|
+
//sprintf(err_msg, "Event: timestamp=%u, event_type = %i\n", event->timestamp, event->event_type);
|
514
|
+
//pass_message(err_msg);
|
515
|
+
pass_event(event);
|
516
|
+
break;
|
517
|
+
}
|
518
|
+
|
519
|
+
case FIT_MESG_NUM_DEVICE_INFO: {
|
520
|
+
const FIT_DEVICE_INFO_MESG *device_info = (FIT_DEVICE_INFO_MESG *) mesg;
|
521
|
+
//sprintf(err_msg, "Device Info: timestamp=%u, battery_status=%u\n", (unsigned int)device_info->timestamp, device_info->battery_voltage);
|
522
|
+
//pass_message(err_msg);
|
523
|
+
pass_device_info(device_info);
|
524
|
+
break;
|
525
|
+
}
|
526
|
+
|
527
|
+
case FIT_MESG_NUM_WEIGHT_SCALE: {
|
528
|
+
const FIT_WEIGHT_SCALE_MESG *weight_scale_info = (FIT_WEIGHT_SCALE_MESG *) mesg;
|
529
|
+
//sprintf(err_msg, "Device Info: timestamp=%u, battery_status=%u\n", (unsigned int)device_info->timestamp, device_info->battery_voltage);
|
530
|
+
//pass_message(err_msg);
|
531
|
+
pass_weight_scale_info(weight_scale_info);
|
532
|
+
break;
|
533
|
+
}
|
534
|
+
|
535
|
+
default: {
|
536
|
+
//sprintf(err_msg, "Unknown\n");
|
537
|
+
//pass_message(err_msg);
|
538
|
+
break;
|
539
|
+
}
|
540
|
+
}
|
541
|
+
break;
|
542
|
+
}
|
543
|
+
default:
|
544
|
+
break;
|
545
|
+
}
|
546
|
+
} while (convert_return == FIT_CONVERT_MESSAGE_AVAILABLE);
|
547
|
+
}
|
548
|
+
|
549
|
+
if (convert_return == FIT_CONVERT_ERROR) {
|
550
|
+
//sprintf(err_msg, "Error decoding file.\n");
|
551
|
+
pass_message(err_msg);
|
552
|
+
//fclose(file);
|
553
|
+
return Qnil;
|
554
|
+
}
|
555
|
+
|
556
|
+
if (convert_return == FIT_CONVERT_CONTINUE) {
|
557
|
+
//sprintf(err_msg, "Unexpected end of file.\n");
|
558
|
+
//pass_message(err_msg);
|
559
|
+
//fclose(file);
|
560
|
+
//return Qnil;
|
561
|
+
}
|
562
|
+
|
563
|
+
if (convert_return == FIT_CONVERT_PROTOCOL_VERSION_NOT_SUPPORTED) {
|
564
|
+
//sprintf(err_msg, "Protocol version not supported.\n");
|
565
|
+
pass_message(err_msg);
|
566
|
+
//fclose(file);
|
567
|
+
return Qnil;
|
568
|
+
}
|
569
|
+
|
570
|
+
if (convert_return == FIT_CONVERT_END_OF_FILE) {
|
571
|
+
//sprintf(err_msg, "File converted successfully.\n");
|
572
|
+
pass_message(err_msg);
|
573
|
+
}
|
574
|
+
|
575
|
+
return Qnil;
|
576
|
+
}
|
577
|
+
|
578
|
+
void Init_rubyfit() {
|
579
|
+
mRubyFit = rb_define_module("RubyFit");
|
580
|
+
cFitParser = rb_define_class_under(mRubyFit, "FitParser", rb_cObject);
|
581
|
+
//cFitParser = rb_define_class("FitParser", rb_cObject);
|
582
|
+
|
583
|
+
//instance methods
|
584
|
+
rb_define_method(cFitParser, "initialize", init, 1);
|
585
|
+
rb_define_method(cFitParser, "parse", parse, 1);
|
586
|
+
|
587
|
+
//attributes
|
588
|
+
HANDLER_ATTR = rb_intern("@handler");
|
589
|
+
rb_define_attr(cFitParser, "handler", 1, 1);
|
590
|
+
}
|
data/lib/rubyfit.rb
ADDED
metadata
ADDED
@@ -0,0 +1,63 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: rubyfit
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.0.2
|
5
|
+
prerelease:
|
6
|
+
platform: ruby
|
7
|
+
authors:
|
8
|
+
- Cullen King
|
9
|
+
autorequire:
|
10
|
+
bindir: bin
|
11
|
+
cert_chain: []
|
12
|
+
date: 2012-02-23 00:00:00.000000000 Z
|
13
|
+
dependencies: []
|
14
|
+
description: FIT files are binary, and as a result, are a pain to parse. This is
|
15
|
+
a wrapper around the FIT SDK, which makes creating a stream based parser simple.
|
16
|
+
email:
|
17
|
+
- cullen@ridewithgps.com
|
18
|
+
executables: []
|
19
|
+
extensions:
|
20
|
+
- ext/rubyfit/extconf.rb
|
21
|
+
extra_rdoc_files: []
|
22
|
+
files:
|
23
|
+
- lib/rubyfit/version.rb
|
24
|
+
- lib/rubyfit.rb
|
25
|
+
- ext/rubyfit/fit_convert.c
|
26
|
+
- ext/rubyfit/rubyfit.c
|
27
|
+
- ext/rubyfit/fit.c
|
28
|
+
- ext/rubyfit/fit_crc.c
|
29
|
+
- ext/rubyfit/fit_sdk.c
|
30
|
+
- ext/rubyfit/fit_product.c
|
31
|
+
- ext/rubyfit/fit.h
|
32
|
+
- ext/rubyfit/fit_convert.h
|
33
|
+
- ext/rubyfit/fit_crc.h
|
34
|
+
- ext/rubyfit/fit_config.h
|
35
|
+
- ext/rubyfit/fit_sdk.h
|
36
|
+
- ext/rubyfit/fit_product.h
|
37
|
+
- ext/rubyfit/extconf.rb
|
38
|
+
homepage: http://cullenking.com
|
39
|
+
licenses: []
|
40
|
+
post_install_message:
|
41
|
+
rdoc_options: []
|
42
|
+
require_paths:
|
43
|
+
- lib
|
44
|
+
- ext
|
45
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
46
|
+
none: false
|
47
|
+
requirements:
|
48
|
+
- - ! '>='
|
49
|
+
- !ruby/object:Gem::Version
|
50
|
+
version: '0'
|
51
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
52
|
+
none: false
|
53
|
+
requirements:
|
54
|
+
- - ! '>='
|
55
|
+
- !ruby/object:Gem::Version
|
56
|
+
version: '0'
|
57
|
+
requirements: []
|
58
|
+
rubyforge_project: rubyfit
|
59
|
+
rubygems_version: 1.8.10
|
60
|
+
signing_key:
|
61
|
+
specification_version: 3
|
62
|
+
summary: A stream based parser for FIT files.
|
63
|
+
test_files: []
|