fit4ruby 3.5.0 → 3.9.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/Gemfile.lock +1 -1
- data/fit4ruby.gemspec +2 -2
- data/lib/fit4ruby/Activity.rb +94 -55
- data/lib/fit4ruby/BDFieldNameTranslator.rb +36 -0
- data/lib/fit4ruby/DeviceInfo.rb +37 -0
- data/lib/fit4ruby/FDR_DevField_Extension.rb +81 -0
- data/lib/fit4ruby/FieldDescription.rb +26 -8
- data/lib/fit4ruby/FileId.rb +2 -1
- data/lib/fit4ruby/FitDataRecord.rb +85 -32
- data/lib/fit4ruby/FitDefinition.rb +11 -4
- data/lib/fit4ruby/FitDefinitionField.rb +6 -6
- data/lib/fit4ruby/FitDefinitionFieldBase.rb +15 -6
- data/lib/fit4ruby/FitDeveloperDataFieldDefinition.rb +1 -1
- data/lib/fit4ruby/FitFile.rb +2 -0
- data/lib/fit4ruby/FitMessageRecord.rb +26 -21
- data/lib/fit4ruby/FitRecord.rb +2 -1
- data/lib/fit4ruby/FitTypeDefs.rb +2 -2
- data/lib/fit4ruby/GlobalFitDictionaries.rb +366 -23
- data/lib/fit4ruby/GlobalFitMessage.rb +84 -14
- data/lib/fit4ruby/GlobalFitMessages.rb +83 -3
- data/lib/fit4ruby/Lap.rb +10 -1
- data/lib/fit4ruby/Record.rb +11 -2
- data/lib/fit4ruby/version.rb +1 -1
- data/spec/FitFile_spec.rb +198 -100
- metadata +11 -10
@@ -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, '
|
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
|
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
|
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?(
|
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 (
|
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 ==
|
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
|
-
|
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
|
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(
|
346
|
+
definition.setup(self, @field_values_by_name)
|
277
347
|
definition.write(io)
|
278
348
|
end
|
279
349
|
|