fit4ruby 3.0.0 → 3.1.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: b4ee014802983dc12f9d4204e29e1c80d33be729
4
- data.tar.gz: 7d52d887dea393412752a72974d189452ffea3e3
3
+ metadata.gz: d789b2e373decc4dfff48739b65a320c66da88fd
4
+ data.tar.gz: 1a40f4aac55b45f66cb082b6ffef4ca6e3c3ed9e
5
5
  SHA512:
6
- metadata.gz: 0d306e3ff6d58837943461a2508c6a81d05043b49eb186e352f273e11b341ffe6b0db92e500d764e327c37f38c5f3a5ec466a8bb8172599dd1df563a3b9a0075
7
- data.tar.gz: cb7692535f35056b613c8f9e3a334d9690400ec2f614c8e5676af0919cb8132b1a280caa7efcd3c6265044008def7deed8a6e706e4718aad1be57a96b12700f3
6
+ metadata.gz: 2ec0e96be6dd2d0cf44b03a5ac41197a693d4a4b8861063a55f7d37e98252656f380d8cb57bb4d77476d7f805fdab1668c598f5ec81208e7225102e151b12e8a
7
+ data.tar.gz: d92c14c4af7c98c043d3a675bb8eefa741fe30b18a05d4606358cd69a49c05b4564355b1c213dac9c9196d1b1c2f0bf5122bca7808652db310fccf1c59fe92f1
@@ -261,10 +261,10 @@ module Fit4Ruby
261
261
  @events.each do |e|
262
262
  return e.vo2max if e.event == 'vo2max'
263
263
  end
264
- # Then check the user_profile entries for a metmax entry. METmax * 3.5
264
+ # Then check the user_data entries for a metmax entry. METmax * 3.5
265
265
  # is same value as VO2max.
266
- @user_profiles.each do |u|
267
- return u.metmax * 3.5 if u.metmax
266
+ @user_data.each do |u|
267
+ return ((u.metmax * 1000.0) * 3.5) / 1024.0 if u.metmax
268
268
  end
269
269
 
270
270
  nil
@@ -0,0 +1,58 @@
1
+ #!/usr/bin/env ruby -w
2
+ # encoding: UTF-8
3
+ #
4
+ # = CRC16.rb -- Fit4Ruby - FIT file processing library for Ruby
5
+ #
6
+ # Copyright (c) 2014, 2015, 2016, 2017, 2018
7
+ # by Chris Schlaeger <cs@taskjuggler.org>
8
+ #
9
+ # This program is free software; you can redistribute it and/or modify
10
+ # it under the terms of version 2 of the GNU General Public License as
11
+ # published by the Free Software Foundation.
12
+ #
13
+
14
+ module Fit4Ruby
15
+
16
+ module CRC16
17
+
18
+ def write_crc(io, start_pos, end_pos)
19
+ # Compute the checksum over the data section of the file and append it
20
+ # to the file. Ideally, we should compute the CRC from data in memory
21
+ # instead of the file data.
22
+ crc = compute_crc(io, start_pos, end_pos)
23
+ io.seek(end_pos)
24
+ BinData::Uint16le.new(crc).write(io)
25
+
26
+ crc
27
+ end
28
+
29
+ def compute_crc(io, start_pos, end_pos)
30
+ crc_table = [
31
+ 0x0000, 0xCC01, 0xD801, 0x1400, 0xF001, 0x3C00, 0x2800, 0xE401,
32
+ 0xA001, 0x6C00, 0x7800, 0xB401, 0x5000, 0x9C01, 0x8801, 0x4400
33
+ ]
34
+
35
+ io.seek(start_pos)
36
+
37
+ crc = 0
38
+ while io.pos < end_pos
39
+ if io.eof?
40
+ raise IOError, "Premature end of file"
41
+ end
42
+
43
+ byte = io.readbyte
44
+
45
+ 0.upto(1) do |i|
46
+ tmp = crc_table[crc & 0xF]
47
+ crc = (crc >> 4) & 0x0FFF
48
+ crc = crc ^ tmp ^ crc_table[(byte >> (4 * i)) & 0xF]
49
+ end
50
+ end
51
+
52
+ crc
53
+ end
54
+
55
+ end
56
+
57
+ end
58
+
@@ -3,7 +3,8 @@
3
3
  #
4
4
  # = FitFile.rb -- Fit4Ruby - FIT file processing library for Ruby
5
5
  #
6
- # Copyright (c) 2014, 2015 by Chris Schlaeger <cs@taskjuggler.org>
6
+ # Copyright (c) 2014, 2015, 2016, 2017, 2018
7
+ # by Chris Schlaeger <cs@taskjuggler.org>
7
8
  #
8
9
  # This program is free software; you can redistribute it and/or modify
9
10
  # it under the terms of version 2 of the GNU General Public License as
@@ -11,6 +12,7 @@
11
12
  #
12
13
 
13
14
  require 'fit4ruby/Log'
15
+ require 'fit4ruby/CRC16'
14
16
  require 'fit4ruby/FileNameCoder'
15
17
  require 'fit4ruby/FitHeader'
16
18
  require 'fit4ruby/FitFileEntity'
@@ -24,6 +26,8 @@ module Fit4Ruby
24
26
 
25
27
  class FitFile
26
28
 
29
+ include CRC16
30
+
27
31
  def initialize()
28
32
  @header = nil
29
33
  end
@@ -43,9 +47,14 @@ module Fit4Ruby
43
47
  offset = io.pos
44
48
 
45
49
  header = FitHeader.read(io)
46
- header.check
47
50
 
48
- check_crc(io, io.pos, offset + header.end_pos)
51
+ # If the header has a CRC the header is not included in the
52
+ # checksumed bytes. Otherwise it is included.
53
+ check_crc(io, header.has_crc? ? header.header_size : 0,
54
+ offset + header.end_pos)
55
+
56
+ # Rewind back to the beginning of the data right after the header.
57
+ io.seek(header.header_size)
49
58
 
50
59
  entity = FitFileEntity.new
51
60
  # This Array holds the raw data of the records that may be needed to
@@ -86,6 +95,7 @@ module Fit4Ruby
86
95
  # Create a header object, but don't yet write it into the file.
87
96
  header = FitHeader.new
88
97
  start_pos = header.header_size
98
+
89
99
  # Move the pointer behind the header section.
90
100
  io.seek(start_pos)
91
101
  id_mapper = FitMessageIdMapper.new
@@ -97,7 +107,6 @@ module Fit4Ruby
97
107
  # Complete the data of the header section and write it at the start of
98
108
  # the file.
99
109
  header.data_size = end_pos - start_pos
100
- header.crc = crc
101
110
  io.seek(0)
102
111
  header.write(io)
103
112
  ensure
@@ -113,47 +122,14 @@ module Fit4Ruby
113
122
  # Read the 2 CRC bytes from the end of the file
114
123
  io.seek(end_pos)
115
124
  crc_ref = io.readbyte.to_i | (io.readbyte.to_i << 8)
116
- io.seek(start_pos)
117
125
 
118
126
  unless crc == crc_ref
119
- Log.fatal "Checksum error in file '#{@file_name}'. " +
127
+ Log.error "Checksum error of segment #{start_pos} to #{end_pos} " +
128
+ "in file '#{@file_name}'. " +
120
129
  "Computed 0x#{"%04X" % crc} instead of 0x#{"%04X" % crc_ref}."
121
130
  end
122
131
  end
123
132
 
124
- def write_crc(io, start_pos, end_pos)
125
- # Compute the checksum over the data section of the file and append it
126
- # to the file. Ideally, we should compute the CRC from data in memory
127
- # instead of the file data.
128
- crc = compute_crc(io, start_pos, end_pos)
129
- io.seek(end_pos)
130
- BinData::Uint16le.new(crc).write(io)
131
-
132
- crc
133
- end
134
-
135
- def compute_crc(io, start_pos, end_pos)
136
- crc_table = [
137
- 0x0000, 0xCC01, 0xD801, 0x1400, 0xF001, 0x3C00, 0x2800, 0xE401,
138
- 0xA001, 0x6C00, 0x7800, 0xB401, 0x5000, 0x9C01, 0x8801, 0x4400
139
- ]
140
-
141
- io.seek(start_pos)
142
-
143
- crc = 0
144
- while io.pos < end_pos
145
- byte = io.readbyte
146
-
147
- 0.upto(1) do |i|
148
- tmp = crc_table[crc & 0xF]
149
- crc = (crc >> 4) & 0x0FFF
150
- crc = crc ^ tmp ^ crc_table[(byte >> (4 * i)) & 0xF]
151
- end
152
- end
153
-
154
- crc
155
- end
156
-
157
133
  def dump_records(records)
158
134
  # For each message number we keep a count for how often we already had
159
135
  # this kind of message.
@@ -3,7 +3,8 @@
3
3
  #
4
4
  # = FitHeader.rb -- Fit4Ruby - FIT file processing library for Ruby
5
5
  #
6
- # Copyright (c) 2014 by Chris Schlaeger <cs@taskjuggler.org>
6
+ # Copyright (c) 2014, 2015, 2016, 2017, 2018
7
+ # by Chris Schlaeger <cs@taskjuggler.org>
7
8
  #
8
9
  # This program is free software; you can redistribute it and/or modify
9
10
  # it under the terms of version 2 of the GNU General Public License as
@@ -12,41 +13,60 @@
12
13
 
13
14
  require 'bindata'
14
15
  require 'fit4ruby/Log'
16
+ require 'fit4ruby/CRC16'
15
17
 
16
18
  module Fit4Ruby
17
19
 
18
20
  class FitHeader < BinData::Record
19
21
 
22
+ include CRC16
23
+
20
24
  endian :little
21
25
 
22
26
  uint8 :header_size, :initial_value => 14
23
- uint8 :protocol_version, :initial_value => 16
27
+ uint8 :protocol_version, :initial_value => 32
24
28
  uint16 :profile_version, :initial_value => 1012
25
29
  uint32 :data_size, :initial_value => 0
26
30
  string :data_type, :read_length => 4, :initial_value => '.FIT'
27
- uint16 :crc, :initial_value => 0
31
+ uint16 :crc, :initial_value => 0, :onlyif => :has_crc?
32
+
33
+ def read(io)
34
+ super
28
35
 
29
- def check
30
- unless header_size == 14
31
- Log.fatal "Unsupported header size #{header_size}"
36
+ unless header_size.snapshot == 12 || header_size.snapshot == 14
37
+ Log.fatal "Unsupported header size #{header_size.snapshot}"
32
38
  end
33
- unless data_type == '.FIT'
34
- Log.fatal "Unknown file type #{data_type}"
39
+ unless data_type.snapshot == '.FIT'
40
+ Log.fatal "Unknown file type #{data_type.snapshot}"
35
41
  end
42
+ if crc.snapshot != 0 &&
43
+ compute_crc(io, 0, header_size.snapshot - 2) != crc.snapshot
44
+ Log.fatal "CRC mismatch in header."
45
+ end
46
+ end
47
+
48
+ def write(io)
49
+ super
50
+
51
+ write_crc(io, 0, header_size.snapshot - 2)
36
52
  end
37
53
 
38
54
  def dump
39
55
  puts <<"EOT"
40
56
  Fit File Header
41
- Header Size: #{header_size}
42
- Protocol Version: #{protocol_version}
43
- Profile Version: #{profile_version}
44
- Data Size: #{data_size}
57
+ Header Size: #{header_size.snapshot}
58
+ Protocol Version: #{protocol_version.snapshot}
59
+ Profile Version: #{profile_version.snapshot}
60
+ Data Size: #{data_size.snapshot}
45
61
  EOT
46
62
  end
47
63
 
64
+ def has_crc?
65
+ header_size.snapshot == 14
66
+ end
67
+
48
68
  def end_pos
49
- header_size + data_size
69
+ header_size.snapshot + data_size.snapshot
50
70
  end
51
71
 
52
72
  end
@@ -304,6 +304,8 @@ module Fit4Ruby
304
304
 
305
305
  dict 'garmin_product'
306
306
  entry 8, 'hrm_run_single_byte_product_id'
307
+ entry 9, 'bsm'
308
+ entry 10, 'bcm'
307
309
  entry 1551, 'fenix'
308
310
  # The Fenix3 is rumored to have a Mediatek MT3333 GPS chipset. Not sure if
309
311
  # that would be a beter name.
@@ -470,7 +472,61 @@ module Fit4Ruby
470
472
  entry 85, 'woodway'
471
473
  entry 86, 'elite'
472
474
  entry 95, 'stryd'
475
+ entry 96, 'icg'
476
+ entry 97, 'MiPulse'
477
+ entry 98, 'bsx_athletics'
478
+ entry 99, 'look'
479
+ entry 100, 'campagnolo_srl'
480
+ entry 101, 'body_bike_smart'
481
+ entry 102, 'praxisworks'
482
+ entry 103, 'limits_technology'
483
+ entry 104, 'topaction_technology'
484
+ entry 105, 'cosinuss'
485
+ entry 106, 'fitcare'
486
+ entry 107, 'magene'
487
+ entry 108, 'giant_manufacturing_co'
488
+ entry 109, 'tigrasport'
489
+ entry 110, 'salutron'
490
+ entry 111, 'technogym'
491
+ entry 112, 'bryton_sensors'
492
+ entry 113, 'latitude_limited'
493
+ entry 114, 'soaring_technology'
494
+ entry 115, 'igpsport'
495
+ entry 116, 'thinkrider'
496
+ entry 117, 'gopher_sport'
497
+ entry 118, 'waterrower'
473
498
  entry 255, 'development'
499
+ entry 257, 'healthandlife'
500
+ entry 258, 'lezyne'
501
+ entry 259, 'scribe_labs'
502
+ entry 260, 'zwift'
503
+ entry 261, 'watteam'
504
+ entry 262, 'recon'
505
+ entry 263, 'favero_electronics'
506
+ entry 264, 'dynovelo'
507
+ entry 265, 'strava'
508
+ entry 266, 'precor'
509
+ entry 267, 'bryton'
510
+ entry 268, 'sram'
511
+ entry 269, 'navman'
512
+ entry 270, 'cobi'
513
+ entry 271, 'spivi'
514
+ entry 272, 'mio_magellan'
515
+ entry 273, 'evesports'
516
+ entry 274, 'sensitivus_gauge'
517
+ entry 275, 'podoon'
518
+ entry 276, 'life_time_fitness'
519
+ entry 277, 'falco_e_motors'
520
+ entry 278, 'minoura'
521
+ entry 279, 'cycliq'
522
+ entry 280, 'luxottica'
523
+ entry 281, 'trainer_road'
524
+ entry 282, 'the_sufferfest'
525
+ entry 283, 'fullspeedahead'
526
+ entry 284, 'virtualtraining'
527
+ entry 285, 'feedbacksports'
528
+ entry 286, 'omata'
529
+ entry 287, 'vdo'
474
530
  entry 5759, 'actigraphcorp'
475
531
 
476
532
  dict 'message_index'
@@ -560,6 +616,39 @@ module Fit4Ruby
560
616
  entry 24, 'challenge'
561
617
  entry 25, 'indoor_skiing'
562
618
  entry 26, 'cardio_training'
619
+ entry 27, 'indoor_walking '
620
+ entry 28, 'e_bike_fitness '
621
+ entry 29, 'bmx'
622
+ entry 30, 'casual_walking '
623
+ entry 31, 'speed_walking'
624
+ entry 32, 'bike_to_run_transition '
625
+ entry 33, 'run_to_bike_transition '
626
+ entry 34, 'swim_to_bike_transition'
627
+ entry 35, 'atv'
628
+ entry 36, 'motocross'
629
+ entry 37, 'backcountry'
630
+ entry 38, 'resort '
631
+ entry 39, 'rc_drone '
632
+ entry 40, 'wingsuit '
633
+ entry 41, 'whitewater '
634
+ entry 42, 'skate_skiing '
635
+ entry 43, 'yoga '
636
+ entry 44, 'pilates'
637
+ entry 45, 'indoor_running '
638
+ entry 46, 'gravel_cycling '
639
+ entry 47, 'e_bike_mountain'
640
+ entry 48, 'commuting'
641
+ entry 49, 'mixed_surface'
642
+ entry 50, 'navigate '
643
+ entry 51, 'track_me '
644
+ entry 52, 'map'
645
+ entry 53, 'single_gas_diving'
646
+ entry 54, 'multi_gas_diving '
647
+ entry 55, 'gauge_diving '
648
+ entry 56, 'apnea_diving '
649
+ entry 57, 'apnea_hunting'
650
+ entry 58, 'virtual_activity '
651
+ entry 59, 'obstacle '
563
652
  entry 254, 'all'
564
653
 
565
654
  end
@@ -100,6 +100,7 @@ module Fit4Ruby
100
100
  field 128, 'enum', 'undocumented_field_128'
101
101
  field 133, 'enum', 'undocumented_field_133'
102
102
  field 138, 'enum', 'undocumented_field_138'
103
+ field 144, 'enum', 'true_up_enabled'
103
104
 
104
105
  message 3, 'user_profile'
105
106
  field 0, 'string', 'friendly_name'
@@ -134,6 +135,7 @@ module Fit4Ruby
134
135
  field 41, 'uint32', 'undocumented_field_41'
135
136
  field 42, 'uint32', 'undocumented_field_42'
136
137
  field 43, 'enum', 'undocumented_field_43'
138
+ field 253, 'uint32', 'timestamp', :type => 'date_time'
137
139
 
138
140
  message 7, 'zones_target'
139
141
  field 1, 'uint8', 'max_heart_rate'
@@ -202,6 +204,8 @@ module Fit4Ruby
202
204
  field 55, 'enum', 'undocumented_field_55'
203
205
  field 57, 'enum', 'undocumented_field_57'
204
206
  field 60, 'enum', 'undocumented_field_60'
207
+ field 65, 'enum', 'undocumented_field_65'
208
+ field 66, 'enum', 'undocumented_field_66'
205
209
  field 254, 'uint16', 'message_index'
206
210
 
207
211
  message 18, 'session'
@@ -417,7 +421,11 @@ module Fit4Ruby
417
421
  field 5, 'uint32', 'distance', :scale => 100, :unit => 'm'
418
422
  field 6, 'uint16', 'speed', :scale => 1000, :unit => 'm/s'
419
423
  field 7, 'uint16', 'power', :unit => 'watts'
424
+ field 8, 'byte', 'compressed_speed_distance', :array => true
425
+ field 9, 'sint16', 'grade', :scale => 100, :unit => '%'
426
+ field 10, 'uint8', 'resistence'
420
427
  field 11, 'sint32', 'time_from_course', :scale => 1000, :unit => 's'
428
+ field 12, 'uint8', 'cycle_length', :scale => 100, :unit => 'm'
421
429
  field 13, 'sint8', 'temperature', :unit => 'C'
422
430
  field 14, 'uint32', 'undefined_field_14'
423
431
  field 15, 'uint32', 'undefined_field_15'
@@ -572,6 +580,7 @@ module Fit4Ruby
572
580
  field 4, 'enum', 'event_type', :dict => 'event_type'
573
581
  field 5, 'uint32', 'local_timestamp', :type => 'date_time'
574
582
  field 6, 'uint8', 'event_group'
583
+ field 7, 'uint8', 'undocumented_field_7'
575
584
  field 253, 'uint32', 'timestamp', :type => 'date_time'
576
585
 
577
586
  message 35, 'software'
@@ -581,6 +590,7 @@ module Fit4Ruby
581
590
  message 49, 'file_creator'
582
591
  field 0, 'uint16', 'software_version'
583
592
  field 1, 'uint8', 'hardware_version'
593
+ field 2, 'string', 'undocumented_field_2'
584
594
  field 254, 'uint16', 'message_index', :dict => 'message_index'
585
595
 
586
596
  message 55, 'monitoring'
@@ -744,6 +754,10 @@ module Fit4Ruby
744
754
  field 23, 'uint8', 'undocumented_field_23'
745
755
  field 24, 'sint32', 'undocumented_field_24'
746
756
  field 25, 'uint8', 'undocumented_field_25'
757
+ field 26, 'sint32', 'undocumented_field_26'
758
+ field 29, 'sint32', 'undocumented_field_29'
759
+ field 34, 'enum', 'undocumented_field_34'
760
+ field 35, 'uint32', 'undocumented_field_35'
747
761
  field 253, 'uint32', 'timestamp', :type => 'date_time'
748
762
 
749
763
  # Not part of the official ANT SDK doc. The message name is guessed and
@@ -812,6 +826,11 @@ module Fit4Ruby
812
826
  field 62, 'uint8', 'undocumented_field_62'
813
827
  field 254, 'uint16', 'message_index'
814
828
 
829
+ # Not part of the official ANT SDK doc.
830
+ message 188, 'undocumented_188'
831
+ field 0, 'enum', 'undocumented_field_0'
832
+ field 253, 'uint32', 'timestamp', :type => 'date_time'
833
+
815
834
  message 206, 'field_description'
816
835
  field 0, 'uint8', 'developer_data_index'
817
836
  field 1, 'uint8', 'field_definition_number'
@@ -857,11 +876,10 @@ module Fit4Ruby
857
876
  field 15, 'uint16', 'undocumented_field_15'
858
877
  field 253, 'uint32', 'timestamp', :type => 'date_time'
859
878
 
860
- # Not part of the official ANT SDK doc.
861
- message 227, 'stress'
862
- field 0, 'sint16', 'undocumented_0'
863
- field 1, 'uint32', 'undocumented_1'
864
- field 2, 'sint8', 'level'
879
+ message 227, 'stress_level'
880
+ field 0, 'sint16', 'stress_level_value'
881
+ field 1, 'uint32', 'stress_level_time', :type => 'date_time'
882
+ field 2, 'sint8', 'undocumented_field_2'
865
883
 
866
884
  message 1024, 'undocumented_1024'
867
885
  field 0, 'enum', 'undocumented_field_0'
@@ -1,4 +1,4 @@
1
1
  module Fit4Ruby
2
2
  # The version number of the library.
3
- VERSION = '3.0.0'
3
+ VERSION = '3.1.0'
4
4
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: fit4ruby
3
3
  version: !ruby/object:Gem::Version
4
- version: 3.0.0
4
+ version: 3.1.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Chris Schlaeger
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2018-03-04 00:00:00.000000000 Z
11
+ date: 2018-06-17 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: bindata
@@ -84,6 +84,7 @@ files:
84
84
  - fit4ruby.gemspec
85
85
  - lib/fit4ruby.rb
86
86
  - lib/fit4ruby/Activity.rb
87
+ - lib/fit4ruby/CRC16.rb
87
88
  - lib/fit4ruby/Converters.rb
88
89
  - lib/fit4ruby/DataSources.rb
89
90
  - lib/fit4ruby/DeveloperDataId.rb