fit4ruby 3.5.0 → 3.9.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -23,7 +23,50 @@ module Fit4Ruby
23
23
  entry 3, 'transition'
24
24
  entry 4, 'fitness_equipment'
25
25
  entry 5, 'swimming'
26
- entry 6, 'walking'
26
+ entry 6, 'basketball'
27
+ entry 7, 'soccer'
28
+ entry 8, 'tennis'
29
+ entry 9, 'american_football'
30
+ entry 10, 'training'
31
+ entry 11, 'walking'
32
+ entry 12, 'cross_country_skiing'
33
+ entry 13, 'alpine_skiing'
34
+ entry 14, 'snowboarding'
35
+ entry 15, 'rowing'
36
+ entry 16, 'mountaineering'
37
+ entry 17, 'hiking'
38
+ entry 18, 'multisport'
39
+ entry 19, 'paddling'
40
+ entry 20, 'flying'
41
+ entry 21, 'e_biking'
42
+ entry 22, 'motorcycling'
43
+ entry 23, 'boating'
44
+ entry 24, 'driving'
45
+ entry 25, 'golf'
46
+ entry 26, 'hang_gliding'
47
+ entry 27, 'horseback_riding'
48
+ entry 28, 'hunting'
49
+ entry 29, 'fishing'
50
+ entry 30, 'inline_skating'
51
+ entry 31, 'rock_climbing'
52
+ entry 32, 'sailing'
53
+ entry 33, 'ice_skating'
54
+ entry 34, 'sky_diving'
55
+ entry 35, 'snowshoeing'
56
+ entry 36, 'snowmobiling'
57
+ entry 37, 'stand_up_paddleboarding'
58
+ entry 38, 'surfing'
59
+ entry 39, 'wakeboarding'
60
+ entry 40, 'water_skiing'
61
+ entry 41, 'kayaking'
62
+ entry 42, 'rafting'
63
+ entry 43, 'windsurfing'
64
+ entry 44, 'kitesurfing'
65
+ entry 45, 'tactical'
66
+ entry 46, 'jumpmaster'
67
+ entry 47, 'boxing'
68
+ entry 48, 'floor_climbing'
69
+ entry 53, 'diving'
27
70
  entry 254, 'all'
28
71
 
29
72
  dict 'activity_level'
@@ -51,6 +94,52 @@ module Fit4Ruby
51
94
  entry 16, 'stair_climbing'
52
95
  entry 17, 'lap_swimming'
53
96
  entry 18, 'open_water'
97
+ entry 19, 'flexibility_training'
98
+ entry 20, 'strength_training'
99
+ entry 21, 'warm_up'
100
+ entry 22, 'match'
101
+ entry 23, 'exercise'
102
+ entry 24, 'challenge'
103
+ entry 25, 'indoor_skiing'
104
+ entry 26, 'cardio_training'
105
+ entry 27, 'indoor_walking'
106
+ entry 28, 'e_bike_fitness'
107
+ entry 29, 'bmx'
108
+ entry 30, 'casual_walking'
109
+ entry 31, 'speed_walking'
110
+ entry 32, 'bike_to_run_transition'
111
+ entry 33, 'run_to_bike_transition'
112
+ entry 34, 'swim_to_bike_transition'
113
+ entry 35, 'atv'
114
+ entry 36, 'motocross'
115
+ entry 37, 'backcountry'
116
+ entry 38, 'resort'
117
+ entry 39, 'rc_drone'
118
+ entry 40, 'wingsuit'
119
+ entry 41, 'whitewater'
120
+ entry 42, 'skate_skiing'
121
+ entry 43, 'yoga'
122
+ entry 44, 'pilates'
123
+ entry 45, 'indoor_running'
124
+ entry 46, 'gravel_cycling'
125
+ entry 47, 'e_bike_mountain'
126
+ entry 48, 'commuting'
127
+ entry 49, 'mixed_surface'
128
+ entry 50, 'navigate'
129
+ entry 51, 'track_me'
130
+ entry 52, 'map'
131
+ entry 53, 'single_gas_diving'
132
+ entry 54, 'multi_gas_diving'
133
+ entry 55, 'gauge_diving'
134
+ entry 56, 'apnea_diving'
135
+ entry 57, 'apnea_hunting'
136
+ entry 58, 'virtual_activity'
137
+ entry 59, 'obstacle'
138
+ entry 62, 'breathing'
139
+ entry 65, 'sail_race'
140
+ entry 67, 'ultra'
141
+ entry 68, 'indoor_climbing'
142
+ entry 69, 'bouldering'
54
143
  entry 254, 'all'
55
144
 
56
145
  dict 'ant_network'
@@ -312,52 +401,306 @@ module Fit4Ruby
312
401
  entry 144, 'uint64z'
313
402
 
314
403
  dict 'garmin_product'
404
+ entry 1, 'hrm1'
405
+ entry 2, 'axh01'
406
+ entry 3, 'axb01'
407
+ entry 4, 'axb02'
408
+ entry 5, 'hrm2ss'
409
+ entry 6, 'dsi_alf02'
410
+ entry 7, 'hrm3ss'
315
411
  entry 8, 'hrm_run_single_byte_product_id'
316
412
  entry 9, 'bsm'
317
413
  entry 10, 'bcm'
414
+ entry 11, 'axs01'
415
+ entry 12, 'hrm_tri_single_byte_product_id'
416
+ entry 13, 'hrm4_run_single_byte_product_id'
417
+ entry 14, 'fr225_single_byte_product_id'
418
+ entry 473, 'fr301_china'
419
+ entry 474, 'fr301_japan'
420
+ entry 475, 'fr301_korea'
421
+ entry 494, 'fr301_taiwan'
422
+ entry 717, 'fr405'
423
+ entry 782, 'fr50'
424
+ entry 987, 'fr405_japan'
425
+ entry 988, 'fr60'
426
+ entry 1011, 'dsi_alf01'
427
+ entry 1018, 'fr310xt'
428
+ entry 1036, 'edge500'
429
+ entry 1124, 'fr110'
430
+ entry 1169, 'edge800'
431
+ entry 1199, 'edge500_taiwan'
432
+ entry 1213, 'edge500_japan'
433
+ entry 1253, 'chirp'
434
+ entry 1274, 'fr110_japan'
435
+ entry 1325, 'edge200'
436
+ entry 1328, 'fr910xt'
437
+ entry 1333, 'edge800_taiwan'
438
+ entry 1334, 'edge800_japan'
439
+ entry 1341, 'alf04'
440
+ entry 1345, 'fr610'
441
+ entry 1360, 'fr210_japan'
442
+ entry 1380, 'vector_ss'
443
+ entry 1381, 'vector_cp'
444
+ entry 1386, 'edge800_china'
445
+ entry 1387, 'edge500_china'
446
+ entry 1405, 'approach_g10'
447
+ entry 1410, 'fr610_japan'
448
+ entry 1422, 'edge500_korea'
449
+ entry 1436, 'fr70'
450
+ entry 1446, 'fr310xt_4t'
451
+ entry 1461, 'amx'
452
+ entry 1482, 'fr10'
453
+ entry 1497, 'edge800_korea'
454
+ entry 1499, 'swim'
455
+ entry 1537, 'fr910xt_china'
318
456
  entry 1551, 'fenix'
457
+ entry 1555, 'edge200_taiwan'
458
+ entry 1561, 'edge510'
459
+ entry 1567, 'edge810'
460
+ entry 1570, 'tempe'
461
+ entry 1600, 'fr910xt_japan'
319
462
  # The Fenix3 is rumored to have a Mediatek MT3333 GPS chipset. Not sure if
320
463
  # that would be a beter name.
321
464
  entry 1620, 'fenix3_gps' # Just a guess
322
465
  entry 1621, 'fenix5_gps' # Just a guess
323
466
  entry 1623, 'fr620'
324
467
  entry 1632, 'fr220'
468
+ entry 1664, 'fr910xt_korea'
469
+ entry 1688, 'fr10_japan'
325
470
  # The FR620 is rumored to have a MediaTek MT3339 GPS chipset while the
326
471
  # FR920XT is rumored to have a MT3333. Not sure why they have the same ID
327
472
  # in the FIT file for the GPS device.
328
473
  entry 1689, 'fr620_fr920xt_gps' # Just a guess
474
+ entry 1721, 'edge810_japan'
475
+ entry 1735, 'virb_elite'
476
+ entry 1736, 'edge_touring'
477
+ entry 1742, 'edge510_japan'
329
478
  entry 1743, 'hrm_tri'
330
479
  entry 1752, 'hrm_run'
331
480
  entry 1765, 'fr920xt'
481
+ entry 1821, 'edge510_asia'
482
+ entry 1822, 'edge810_china'
483
+ entry 1823, 'edge810_taiwan'
484
+ entry 1836, 'edge1000'
485
+ entry 1837, 'vivo_fit'
486
+ entry 1853, 'virb_remote'
487
+ entry 1885, 'vivo_ki'
488
+ entry 1903, 'fr15'
489
+ entry 1907, 'vivo_active'
490
+ entry 1918, 'edge510_korea'
332
491
  entry 1928, 'fr620_japan'
333
492
  entry 1929, 'fr620_china'
334
493
  entry 1930, 'fr220_japan'
335
494
  entry 1931, 'fr220_china'
495
+ entry 1936, 'approach_s6'
496
+ entry 1956, 'vivo_smart'
336
497
  entry 1967, 'fenix2'
337
498
  entry 1988, 'epix'
338
499
  entry 2050, 'fenix3'
500
+ entry 2052, 'edge1000_taiwan'
501
+ entry 2053, 'edge1000_japan'
502
+ entry 2061, 'fr15_japan'
503
+ entry 2067, 'edge520'
504
+ entry 2070, 'edge1000_china'
339
505
  entry 2072, 'fr620_russia'
340
506
  entry 2073, 'fr220_russia'
507
+ entry 2079, 'vector_s'
508
+ entry 2100, 'edge1000_korea'
341
509
  entry 2130, 'fr920xt_taiwan'
342
510
  entry 2131, 'fr920xt_china'
343
511
  entry 2132, 'fr920xt_japan'
512
+ entry 2134, 'virbx'
513
+ entry 2135, 'vivo_smart_apac'
514
+ entry 2140, 'etrex_touch'
515
+ entry 2147, 'edge25'
516
+ entry 2148, 'fr25'
517
+ entry 2150, 'vivo_fit2'
518
+ entry 2153, 'fr225'
519
+ entry 2156, 'fr630'
520
+ entry 2157, 'fr230'
521
+ entry 2158, 'fr735xt'
522
+ entry 2160, 'vivo_active_apac'
523
+ entry 2161, 'vector_2'
524
+ entry 2162, 'vector_2s'
525
+ entry 2172, 'virbxe'
344
526
  entry 2173, 'fr620_taiwan'
527
+ entry 2174, 'fr220_taiwan'
528
+ entry 2175, 'truswing'
345
529
  entry 2188, 'fenix3_china'
346
530
  entry 2189, 'fenix3_twn'
531
+ entry 2192, 'varia_headlight'
532
+ entry 2193, 'varia_taillight_old'
533
+ entry 2204, 'edge_explore_1000'
534
+ entry 2219, 'fr225_asia'
535
+ entry 2225, 'varia_radar_taillight'
536
+ entry 2226, 'varia_radar_display'
537
+ entry 2238, 'edge20'
538
+ entry 2260, 'edge520_asia'
539
+ entry 2261, 'edge520_japan'
540
+ entry 2262, 'd2_bravo'
541
+ entry 2266, 'approach_s20'
542
+ entry 2271, 'vivo_smart2'
543
+ entry 2274, 'edge1000_thai'
544
+ entry 2276, 'varia_remote'
545
+ entry 2288, 'edge25_asia'
546
+ entry 2289, 'edge25_jpn'
547
+ entry 2290, 'edge20_asia'
548
+ entry 2292, 'approach_x40'
549
+ entry 2293, 'fenix3_japan'
550
+ entry 2294, 'vivo_smart_emea'
551
+ entry 2310, 'fr630_asia'
552
+ entry 2311, 'fr630_jpn'
553
+ entry 2313, 'fr230_jpn'
347
554
  entry 2327, 'hrm4_run'
555
+ entry 2332, 'epix_japan'
556
+ entry 2337, 'vivo_active_hr'
557
+ entry 2347, 'vivo_smart_gps_hr'
558
+ entry 2348, 'vivo_smart_hr'
559
+ entry 2361, 'vivo_smart_hr_asia'
560
+ entry 2362, 'vivo_smart_gps_hr_asia'
561
+ entry 2368, 'vivo_move'
562
+ entry 2379, 'varia_taillight'
563
+ entry 2397, 'fr235_japan'
564
+ entry 2398, 'varia_vision'
565
+ entry 2406, 'vivo_fit3'
566
+ entry 2407, 'fenix3_korea'
567
+ entry 2408, 'fenix3_sea'
348
568
  entry 2413, 'fenix3_hr'
569
+ entry 2417, 'virb_ultra_30'
570
+ entry 2429, 'index_smart_scale'
349
571
  entry 2431, 'fr235'
350
572
  entry 2432, 'fenix3_chronos'
573
+ entry 2441, 'oregon7xx'
574
+ entry 2444, 'rino7xx'
575
+ entry 2457, 'epix_korea'
576
+ entry 2473, 'fenix3_hr_chn'
577
+ entry 2474, 'fenix3_hr_twn'
578
+ entry 2475, 'fenix3_hr_jpn'
579
+ entry 2476, 'fenix3_hr_sea'
580
+ entry 2477, 'fenix3_hr_kor'
581
+ entry 2496, 'nautix'
582
+ entry 2497, 'vivo_active_hr_apac'
583
+ entry 2512, 'oregon7xx_ww'
584
+ entry 2530, 'edge_820'
585
+ entry 2531, 'edge_explore_820'
586
+ entry 2533, 'fr735xt_apac'
587
+ entry 2534, 'fr735xt_japan'
351
588
  entry 2544, 'fenix5s'
352
- entry 2604, 'fenix5x'
589
+ entry 2547, 'd2_bravo_titanium'
590
+ entry 2567, 'varia_ut800'
353
591
  entry 2593, 'running_dynamics_pod'
592
+ entry 2599, 'edge_820_china'
593
+ entry 2600, 'edge_820_japan'
594
+ entry 2604, 'fenix5x'
595
+ entry 2606, 'vivo_fit_jr'
596
+ entry 2622, 'vivo_smart3'
597
+ entry 2623, 'vivo_sport'
598
+ entry 2628, 'edge_820_taiwan'
599
+ entry 2629, 'edge_820_korea'
600
+ entry 2630, 'edge_820_sea'
601
+ entry 2650, 'fr35_hebrew'
602
+ entry 2656, 'approach_s60'
603
+ entry 2667, 'fr35_apac'
604
+ entry 2668, 'fr35_japan'
605
+ entry 2675, 'fenix3_chronos_asia'
606
+ entry 2687, 'virb_360'
354
607
  entry 2691, 'fr935'
355
608
  entry 2697, 'fenix5'
609
+ entry 2700, 'vivoactive3'
610
+ entry 2733, 'fr235_china_nfc'
611
+ entry 2769, 'foretrex_601_701'
612
+ entry 2772, 'vivo_move_hr'
613
+ entry 2713, 'edge_1030'
614
+ entry 2796, 'fenix5_asia'
615
+ entry 2797, 'fenix5s_asia'
616
+ entry 2798, 'fenix5x_asia'
617
+ entry 2806, 'approach_z80'
618
+ entry 2814, 'fr35_korea'
619
+ entry 2819, 'd2charlie'
620
+ entry 2831, 'vivo_smart3_apac'
621
+ entry 2832, 'vivo_sport_apac'
622
+ entry 2833, 'fr935_asia'
623
+ entry 2859, 'descent'
624
+ entry 2886, 'fr645'
625
+ entry 2888, 'fr645m'
626
+ entry 2891, 'fr30'
627
+ entry 2900, 'fenix5s_plus'
628
+ entry 2909, 'Edge_130'
629
+ entry 2924, 'edge_1030_asia'
630
+ entry 2927, 'vivosmart_4'
631
+ entry 2945, 'vivo_move_hr_asia'
356
632
  entry 2957, 'fenix5_gps_galileo' # Just a guess
633
+ entry 2962, 'approach_x10'
634
+ entry 2977, 'fr30_asia'
635
+ entry 2988, 'vivoactive3m_w'
636
+ entry 3003, 'fr645_asia'
637
+ entry 3004, 'fr645m_asia'
638
+ entry 3011, 'edge_explore'
639
+ entry 3028, 'gpsmap66'
640
+ entry 3049, 'approach_s10'
641
+ entry 3066, 'vivoactive3m_l'
642
+ entry 3085, 'approach_g80'
643
+ entry 3092, 'edge_130_asia'
644
+ entry 3095, 'edge_1030_bontrager'
645
+ entry 3110, 'fenix5_plus'
357
646
  entry 3111, 'fenix5x_plus'
358
- entry 3126, 'instinct'
647
+ entry 3112, 'edge_520_plus'
648
+ entry 3121, 'edge_530'
649
+ entry 3122, 'edge_830'
650
+ entry 3134, 'fenix5s_plus_apac'
651
+ entry 3135, 'fenix5x_plus_apac'
652
+ entry 3142, 'edge_520_plus_apac'
653
+ entry 3144, 'fr235l_asia'
654
+ entry 3145, 'fr245_asia'
655
+ entry 3163, 'vivo_active3m_apac'
656
+ entry 3218, 'vivo_smart4_asia'
657
+ entry 3224, 'vivoactive4_small'
658
+ entry 3225, 'vivoactive4_large'
659
+ entry 3226, 'venu'
660
+ entry 3246, 'marq_driver'
661
+ entry 3247, 'marq_aviator'
662
+ entry 3248, 'marq_captain'
663
+ entry 3249, 'marq_commander'
664
+ entry 3250, 'marq_expedition'
665
+ entry 3251, 'marq_athlete'
666
+ entry 3287, 'fenix6S_sport'
667
+ entry 3288, 'fenix6S'
668
+ entry 3289, 'fenix6_sport'
669
+ entry 3290, 'fenix6'
359
670
  entry 3291, 'fenix6x'
671
+ entry 3299, 'hrm_dual'
672
+ entry 3308, 'vivo_move3_premium'
673
+ entry 3314, 'approach_s40'
674
+ entry 3321, 'fr245m_asia'
675
+ entry 3349, 'edge_530_apac'
676
+ entry 3350, 'edge_830_apac'
677
+ entry 3378, 'vivo_move3'
678
+ entry 3387, 'vivo_active4_small_asia'
679
+ entry 3388, 'vivo_active4_large_asia'
680
+ entry 3389, 'vivo_active4_oled_asia'
681
+ entry 3405, 'swim2'
682
+ entry 3420, 'marq_driver_asia'
683
+ entry 3421, 'marq_aviator_asia'
684
+ entry 3422, 'vivo_move3_asia'
685
+ entry 3446, 'vivo_active3t_chn'
686
+ entry 3448, 'marq_captain_asia'
687
+ entry 3449, 'marq_commander_asia'
688
+ entry 3450, 'marq_expedition_asia'
689
+ entry 3451, 'marq_athlete_asia'
690
+ entry 3469, 'fr45_asia'
691
+ entry 3473, 'vivoactive3_daimler'
692
+ entry 3512, 'fenix6s_sport_asia'
693
+ entry 3513, 'fenix6s_asia'
694
+ entry 3514, 'fenix6_sport_asia'
695
+ entry 3515, 'fenix6_asia'
696
+ entry 3516, 'fenix6x_asia'
697
+ entry 3624, 'marq_adventurer'
698
+ entry 3648, 'marq_adventurer_asia'
699
+ entry 3639, 'swim2_apac'
700
+ entry 3737, 'venu_daimler_asia'
701
+ entry 3740, 'venu_daimler'
360
702
  entry 10007, 'sdm4'
703
+ entry 10014, 'edge_remote'
361
704
  entry 20119, 'training_center'
362
705
  entry 65532, 'android_antplus_plugin'
363
706
  entry 65534, 'connect'
@@ -629,39 +972,39 @@ module Fit4Ruby
629
972
  entry 24, 'challenge'
630
973
  entry 25, 'indoor_skiing'
631
974
  entry 26, 'cardio_training'
632
- entry 27, 'indoor_walking '
633
- entry 28, 'e_bike_fitness '
975
+ entry 27, 'indoor_walking'
976
+ entry 28, 'e_bike_fitness'
634
977
  entry 29, 'bmx'
635
- entry 30, 'casual_walking '
978
+ entry 30, 'casual_walking'
636
979
  entry 31, 'speed_walking'
637
- entry 32, 'bike_to_run_transition '
638
- entry 33, 'run_to_bike_transition '
980
+ entry 32, 'bike_to_run_transition'
981
+ entry 33, 'run_to_bike_transition'
639
982
  entry 34, 'swim_to_bike_transition'
640
983
  entry 35, 'atv'
641
984
  entry 36, 'motocross'
642
985
  entry 37, 'backcountry'
643
- entry 38, 'resort '
644
- entry 39, 'rc_drone '
645
- entry 40, 'wingsuit '
646
- entry 41, 'whitewater '
647
- entry 42, 'skate_skiing '
648
- entry 43, 'yoga '
986
+ entry 38, 'resort'
987
+ entry 39, 'rc_drone'
988
+ entry 40, 'wingsuit'
989
+ entry 41, 'whitewater'
990
+ entry 42, 'skate_skiing'
991
+ entry 43, 'yoga'
649
992
  entry 44, 'pilates'
650
- entry 45, 'indoor_running '
651
- entry 46, 'gravel_cycling '
993
+ entry 45, 'indoor_running'
994
+ entry 46, 'gravel_cycling'
652
995
  entry 47, 'e_bike_mountain'
653
996
  entry 48, 'commuting'
654
997
  entry 49, 'mixed_surface'
655
- entry 50, 'navigate '
656
- entry 51, 'track_me '
998
+ entry 50, 'navigate'
999
+ entry 51, 'track_me'
657
1000
  entry 52, 'map'
658
1001
  entry 53, 'single_gas_diving'
659
- entry 54, 'multi_gas_diving '
660
- entry 55, 'gauge_diving '
661
- entry 56, 'apnea_diving '
1002
+ entry 54, 'multi_gas_diving'
1003
+ entry 55, 'gauge_diving'
1004
+ entry 56, 'apnea_diving'
662
1005
  entry 57, 'apnea_hunting'
663
- entry 58, 'virtual_activity '
664
- entry 59, 'obstacle '
1006
+ entry 58, 'virtual_activity'
1007
+ entry 59, 'obstacle'
665
1008
  entry 254, 'all'
666
1009
 
667
1010
  dict 'training_status'
@@ -3,7 +3,7 @@
3
3
  #
4
4
  # = GlobalFitMessage.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, 2020 by Chris Schlaeger <cs@taskjuggler.org>
7
7
  #
8
8
  # This program is free software; you can redistribute it and/or modify
9
9
  # it under the terms of version 2 of the GNU General Public License as
@@ -21,7 +21,8 @@ module Fit4Ruby
21
21
  # the data fields of the message.
22
22
  class GlobalFitMessage
23
23
 
24
- attr_reader :name, :number, :fields_by_name, :fields_by_number
24
+ attr_reader :name, :number, :fields_by_name, :fields_by_number,
25
+ :field_values_by_name
25
26
 
26
27
  # The Field objects describe the name, type and optional attributes of a
27
28
  # FitMessage definition field. It also provides methods to convert field
@@ -38,8 +39,21 @@ module Fit4Ruby
38
39
  @opts = opts
39
40
  end
40
41
 
42
+ def is_undefined?(value)
43
+ value == FitDefinitionFieldBase.undefined_value(@type)
44
+ end
45
+
46
+ def is_string?
47
+ @type == 'string'
48
+ end
49
+
50
+ def is_array?
51
+ @opts[:array] == true
52
+ end
53
+
41
54
  def to_machine(value)
42
- return nil if value.nil?
55
+ return nil if value.nil? ||
56
+ value == FitDefinitionFieldBase.undefined_value(@type)
43
57
 
44
58
  if @opts.include?(:dict) &&
45
59
  (dict = GlobalFitDictionaries[@opts[:dict]])
@@ -51,6 +65,13 @@ module Fit4Ruby
51
65
  value *= 180.0 / 2147483648
52
66
  when 'date_time'
53
67
  value = fit_time_to_time(value)
68
+ when 'float'
69
+ if value >= 4294967295.0
70
+ return nil
71
+ end
72
+ end
73
+ if value.is_a?(Float) && value >= 4294967295.0
74
+ return nil
54
75
  end
55
76
  value /= @opts[:scale].to_f if @opts[:scale]
56
77
  value -= @opts[:offset] if @opts[:offset]
@@ -133,7 +154,7 @@ module Fit4Ruby
133
154
  value
134
155
  end
135
156
 
136
- def to_s(value)
157
+ def to_s(value = nil)
137
158
  return "[no value]" if value.nil?
138
159
 
139
160
  human_readable = to_human(value)
@@ -167,7 +188,7 @@ module Fit4Ruby
167
188
 
168
189
  def field(ref_value, type, name, opts = {})
169
190
  field = Field.new(type, name, opts)
170
- if ref_value.respond_to?('each')
191
+ if ref_value.respond_to?(:each)
171
192
  ref_value.each do |rv|
172
193
  @fields[rv] = field
173
194
  end
@@ -180,13 +201,13 @@ module Fit4Ruby
180
201
  # Select the alternative field based on the actual field values of the
181
202
  # FitMessageRecord.
182
203
  def select(field_values_by_name)
183
- unless (value = field_values_by_name[@ref_field])
204
+ unless (value_of_referenced_field = field_values_by_name[@ref_field])
184
205
  Log.fatal "The selection field #{@ref_field} for the alternative " +
185
206
  "field is undefined in global message #{@message.name}: " +
186
207
  field_values_by_name.inspect
187
208
  end
188
209
  @fields.each do |ref_value, field|
189
- return field if ref_value == value
210
+ return field if ref_value == value_of_referenced_field
190
211
  end
191
212
  return @fields[:default] if @fields[:default]
192
213
 
@@ -199,7 +220,7 @@ module Fit4Ruby
199
220
  # Create a new GlobalFitMessage definition.
200
221
  # @param name [String] name of the FIT message
201
222
  # @param number [Fixnum] global message number
202
- def initialize(name, number)
223
+ def initialize(name, number, field_values_by_name = {})
203
224
  @name = name
204
225
  @number = number
205
226
  # Field names must be unique. A name always matches a single Field.
@@ -207,13 +228,57 @@ module Fit4Ruby
207
228
  # Field numbers are not unique. A group of alternative fields shares the
208
229
  # same number and is stored as an AltField. Otherwise as Field.
209
230
  @fields_by_number = {}
231
+ # To generate the proper definition message we need to know the length
232
+ # of String and Array fields. This is only needed when writing FIT
233
+ # files.
234
+ @field_values_by_name = field_values_by_name
210
235
  end
211
236
 
212
237
  # Two GlobalFitMessage objects are considered equal if they have the same
213
- # number, name and list of named fields.
238
+ # number, name and list of named fields. In case they have String or Array
239
+ # values, they must have identical size.
214
240
  def ==(m)
215
- @number == m.number && @name == m.name &&
216
- @fields_by_name.keys.sort == m.fields_by_name.keys.sort
241
+ unless @number == m.number && @name == m.name &&
242
+ @fields_by_name.keys.sort == m.fields_by_name.keys.sort
243
+ return false
244
+ end
245
+
246
+ unless @field_values_by_name.size == m.field_values_by_name.size
247
+ return false
248
+ end
249
+
250
+ unless @field_values_by_name.empty?
251
+ @field_values_by_name.keys.each do |name|
252
+ a = @field_values_by_name[name]
253
+ b = m.field_values_by_name[name]
254
+ if a.class != b.class
255
+ return false
256
+ end
257
+ if a.is_a?(String)
258
+ if a.bytes.length != b.bytes.length
259
+ return false
260
+ end
261
+ elsif a.is_a?(Array)
262
+ if a.length != b.length
263
+ return false
264
+ end
265
+ end
266
+ end
267
+ end
268
+
269
+ true
270
+ end
271
+
272
+ def each_field(field_values)
273
+ @fields_by_number.each do |number, field|
274
+ if field.is_a?(AltField)
275
+ # For alternative fields, we need to look at the value of the
276
+ # selector field and pick the corresponding Field.
277
+ field = field.select(field_values)
278
+ end
279
+
280
+ yield(number, field)
281
+ end
217
282
  end
218
283
 
219
284
  # Define a new Field for this message definition.
@@ -223,6 +288,11 @@ module Fit4Ruby
223
288
  register_field_by_number(field, number)
224
289
  end
225
290
 
291
+ # Check if a field with the given name already exists?
292
+ def has_field?(name)
293
+ return @fields_by_name.include?(name)
294
+ end
295
+
226
296
  # Define a new set of Field alternatives for this message definition.
227
297
  def alt_field(number, ref_field, &block)
228
298
  unless @fields_by_name.include?(ref_field)
@@ -250,7 +320,7 @@ module Fit4Ruby
250
320
  end
251
321
 
252
322
  def construct(field_values_by_name)
253
- gfm = GlobalFitMessage.new(@name, @number)
323
+ gfm = GlobalFitMessage.new(@name, @number, field_values_by_name)
254
324
 
255
325
  @fields_by_number.each do |number, field|
256
326
  if field.is_a?(AltField)
@@ -264,7 +334,7 @@ module Fit4Ruby
264
334
  gfm
265
335
  end
266
336
 
267
- def write(io, local_message_type, global_fit_message = self)
337
+ def write(io, local_message_type)
268
338
  header = FitRecordHeader.new
269
339
  header.normal = 0
270
340
  header.message_type = 1
@@ -273,7 +343,7 @@ module Fit4Ruby
273
343
 
274
344
  definition = FitDefinition.new
275
345
  definition.global_message_number = @number
276
- definition.setup(global_fit_message)
346
+ definition.setup(self, @field_values_by_name)
277
347
  definition.write(io)
278
348
  end
279
349