From 48547279a034cf3e7d7878b3e8ebb08c4dbfc864 Mon Sep 17 00:00:00 2001 From: jdwil Date: Mon, 10 Aug 2020 11:52:40 -0500 Subject: [PATCH] Fall back to a single Byte when the message field length is not a multiple of the base type size. Updated the profile. --- fitparse/base.py | 5 +- fitparse/profile.py | 785 ++++++++++++++++++++++++++++++++++++++------ 2 files changed, 688 insertions(+), 102 deletions(-) diff --git a/fitparse/base.py b/fitparse/base.py index d3370b4..db36cd4 100644 --- a/fitparse/base.py +++ b/fitparse/base.py @@ -191,10 +191,7 @@ def _parse_definition_message(self, header): base_type = BASE_TYPES.get(base_type_num, BASE_TYPE_BYTE) if (field_size % base_type.size) != 0: - # NOTE: we could fall back to byte encoding if there's any - # examples in the wild. For now, just throw an exception - raise FitParseError("Invalid field size %d for type '%s' (expected a multiple of %d)" % ( - field_size, base_type.name, base_type.size)) + base_type = BASE_TYPE_BYTE # If the field has components that are accumulators # start recording their accumulation at 0 diff --git a/fitparse/profile.py b/fitparse/profile.py index aa6ddbd..ef7927a 100644 --- a/fitparse/profile.py +++ b/fitparse/profile.py @@ -1,8 +1,8 @@ # ***************** BEGIN AUTOMATICALLY GENERATED FIT PROFILE ****************** # *************************** DO NOT EDIT THIS FILE **************************** -# ************ EXPORTED PROFILE FROM SDK VERSION 20.8 ON 2019-03-05 ************ -# ********* PARSED 161 TYPES (2985 VALUES), 85 MESSAGES (1038 FIELDS) ********** +# *********** EXPORTED PROFILE FROM SDK VERSION 21.32 ON 2020-08-09 ************ +# ********* PARSED 165 TYPES (3214 VALUES), 87 MESSAGES (1079 FIELDS) ********** from fitparse.records import ( ComponentField, @@ -126,6 +126,7 @@ 36: 'bike_light_shared', 38: 'exd', 40: 'bike_radar', + 46: 'bike_aero', 119: 'weight_scale', 120: 'heart_rate', 121: 'bike_speed_cadence', @@ -487,6 +488,15 @@ 22: 'standing_stability_reverse_chop', }, ), + 'climb_pro_event': FieldType( + name='climb_pro_event', + base_type=BASE_TYPES[0x00], # enum + values={ + 0: 'approach', + 1: 'start', + 2: 'complete', + }, + ), 'comm_timeout_type': FieldType( name='comm_timeout_type', base_type=BASE_TYPES[0x84], # uint16 @@ -585,6 +595,33 @@ 43: 'overhead_walk', 44: 'inchworm', 45: 'weighted_modified_front_lever', + 46: 'russian_twist', + 47: 'abdominal_leg_rotations', + 48: 'arm_and_leg_extension_on_knees', + 49: 'bicycle', + 50: 'bicep_curl_with_leg_extension', + 51: 'cat_cow', + 52: 'corkscrew', + 53: 'criss_cross', + 54: 'criss_cross_with_ball', + 55: 'double_leg_stretch', + 56: 'knee_folds', + 57: 'lower_lift', + 58: 'neck_pull', + 59: 'pelvic_clocks', + 60: 'roll_over', + 61: 'roll_up', + 62: 'rolling', + 63: 'rowing_1', + 64: 'rowing_2', + 65: 'scissors', + 66: 'single_leg_circles', + 67: 'single_leg_stretch', + 68: 'snake_twist_1_and_2', + 69: 'swan', + 70: 'swimming', + 71: 'teaser', + 72: 'the_hundred', }, ), 'course_capabilities': FieldType( @@ -724,6 +761,7 @@ 81: 'toes_to_bar', 82: 'weighted_toes_to_bar', 83: 'crunch', + 84: 'straight_leg_crunch_with_ball', }, ), 'curl_exercise_name': FieldType( @@ -992,6 +1030,7 @@ 45: 'elev_high_alert', # Group 0. Start / stop when in alert condition. 46: 'elev_low_alert', # Group 0. Start / stop when in alert condition. 47: 'comm_timeout', # marker + 75: 'radar_threat_alert', # start/stop/marker }, ), 'event_type': FieldType( @@ -1290,6 +1329,14 @@ 65534: 'unknown', }, ), + 'favero_product': FieldType( + name='favero_product', + base_type=BASE_TYPES[0x84], # uint16 + values={ + 10: 'assioma_uno', + 12: 'assioma_duo', + }, + ), 'file': FieldType( name='file', base_type=BASE_TYPES[0x00], # enum @@ -1379,6 +1426,8 @@ 5: 'kneeling_rear_flye', 6: 'single_arm_standing_cable_reverse_flye', 7: 'swiss_ball_dumbbell_flye', + 8: 'arm_rotations', + 9: 'hug_a_tree', }, ), 'garmin_product': FieldType( @@ -1397,6 +1446,7 @@ 10: 'bcm', # BCM model for ANT+ messaging 11: 'axs01', # AXS01 HRM Bike Chipset model for ANT+ messaging 12: 'hrm_tri_single_byte_product_id', # hrm_tri model for HRM ANT+ messaging + 13: 'hrm4_run_single_byte_product_id', # hrm4 run model for HRM ANT+ messaging 14: 'fr225_single_byte_product_id', # fr225 model for HRM ANT+ messaging 473: 'fr301_china', 474: 'fr301_japan', @@ -1426,6 +1476,7 @@ 1381: 'vector_cp', 1386: 'edge800_china', 1387: 'edge500_china', + 1405: 'approach_g10', 1410: 'fr610_japan', 1422: 'edge500_korea', 1436: 'fr70', @@ -1492,6 +1543,7 @@ 2153: 'fr225', 2156: 'fr630', 2157: 'fr230', + 2158: 'fr735xt', 2160: 'vivo_active_apac', 2161: 'vector_2', 2162: 'vector_2s', @@ -1508,16 +1560,36 @@ 2225: 'varia_radar_taillight', 2226: 'varia_radar_display', 2238: 'edge20', + 2260: 'edge520_asia', + 2261: 'edge520_japan', 2262: 'd2_bravo', 2266: 'approach_s20', + 2271: 'vivo_smart2', + 2274: 'edge1000_thai', 2276: 'varia_remote', + 2288: 'edge25_asia', + 2289: 'edge25_jpn', + 2290: 'edge20_asia', + 2292: 'approach_x40', + 2293: 'fenix3_japan', + 2294: 'vivo_smart_emea', + 2310: 'fr630_asia', + 2311: 'fr630_jpn', + 2313: 'fr230_jpn', 2327: 'hrm4_run', + 2332: 'epix_japan', 2337: 'vivo_active_hr', 2347: 'vivo_smart_gps_hr', 2348: 'vivo_smart_hr', + 2361: 'vivo_smart_hr_asia', + 2362: 'vivo_smart_gps_hr_asia', 2368: 'vivo_move', + 2379: 'varia_taillight', + 2397: 'fr235_japan', 2398: 'varia_vision', 2406: 'vivo_fit3', + 2407: 'fenix3_korea', + 2408: 'fenix3_sea', 2413: 'fenix3_hr', 2417: 'virb_ultra_30', 2429: 'index_smart_scale', @@ -1525,17 +1597,132 @@ 2432: 'fenix3_chronos', 2441: 'oregon7xx', 2444: 'rino7xx', + 2457: 'epix_korea', + 2473: 'fenix3_hr_chn', + 2474: 'fenix3_hr_twn', + 2475: 'fenix3_hr_jpn', + 2476: 'fenix3_hr_sea', + 2477: 'fenix3_hr_kor', 2496: 'nautix', + 2497: 'vivo_active_hr_apac', + 2512: 'oregon7xx_ww', 2530: 'edge_820', 2531: 'edge_explore_820', + 2533: 'fr735xt_apac', + 2534: 'fr735xt_japan', 2544: 'fenix5s', 2547: 'd2_bravo_titanium', 2567: 'varia_ut800', # Varia UT 800 SW 2593: 'running_dynamics_pod', + 2599: 'edge_820_china', + 2600: 'edge_820_japan', 2604: 'fenix5x', 2606: 'vivo_fit_jr', + 2622: 'vivo_smart3', + 2623: 'vivo_sport', + 2628: 'edge_820_taiwan', + 2629: 'edge_820_korea', + 2630: 'edge_820_sea', + 2650: 'fr35_hebrew', + 2656: 'approach_s60', + 2667: 'fr35_apac', + 2668: 'fr35_japan', + 2675: 'fenix3_chronos_asia', + 2687: 'virb_360', 2691: 'fr935', 2697: 'fenix5', + 2700: 'vivoactive3', + 2713: 'edge_1030', + 2733: 'fr235_china_nfc', + 2769: 'foretrex_601_701', + 2772: 'vivo_move_hr', + 2796: 'fenix5_asia', + 2797: 'fenix5s_asia', + 2798: 'fenix5x_asia', + 2806: 'approach_z80', + 2814: 'fr35_korea', + 2819: 'd2charlie', + 2831: 'vivo_smart3_apac', + 2832: 'vivo_sport_apac', + 2833: 'fr935_asia', + 2859: 'descent', + 2886: 'fr645', + 2888: 'fr645m', + 2891: 'fr30', + 2900: 'fenix5s_plus', + 2909: 'Edge_130', + 2924: 'edge_1030_asia', + 2927: 'vivosmart_4', + 2945: 'vivo_move_hr_asia', + 2962: 'approach_x10', + 2977: 'fr30_asia', + 2988: 'vivoactive3m_w', + 3003: 'fr645_asia', + 3004: 'fr645m_asia', + 3011: 'edge_explore', + 3028: 'gpsmap66', + 3049: 'approach_s10', + 3066: 'vivoactive3m_l', + 3085: 'approach_g80', + 3092: 'edge_130_asia', + 3095: 'edge_1030_bontrager', + 3110: 'fenix5_plus', + 3111: 'fenix5x_plus', + 3112: 'edge_520_plus', + 3121: 'edge_530', + 3122: 'edge_830', + 3134: 'fenix5s_plus_apac', + 3135: 'fenix5x_plus_apac', + 3142: 'edge_520_plus_apac', + 3144: 'fr235l_asia', + 3145: 'fr245_asia', + 3163: 'vivo_active3m_apac', + 3218: 'vivo_smart4_asia', + 3224: 'vivoactive4_small', + 3225: 'vivoactive4_large', + 3226: 'venu', + 3246: 'marq_driver', + 3247: 'marq_aviator', + 3248: 'marq_captain', + 3249: 'marq_commander', + 3250: 'marq_expedition', + 3251: 'marq_athlete', + 3287: 'fenix6S_sport', + 3288: 'fenix6S', + 3289: 'fenix6_sport', + 3290: 'fenix6', + 3291: 'fenix6x', + 3299: 'hrm_dual', # HRM-Dual + 3308: 'vivo_move3_premium', + 3314: 'approach_s40', + 3321: 'fr245m_asia', + 3349: 'edge_530_apac', + 3350: 'edge_830_apac', + 3378: 'vivo_move3', + 3387: 'vivo_active4_small_asia', + 3388: 'vivo_active4_large_asia', + 3389: 'vivo_active4_oled_asia', + 3405: 'swim2', + 3420: 'marq_driver_asia', + 3421: 'marq_aviator_asia', + 3422: 'vivo_move3_asia', + 3446: 'vivo_active3t_chn', + 3448: 'marq_captain_asia', + 3449: 'marq_commander_asia', + 3450: 'marq_expedition_asia', + 3451: 'marq_athlete_asia', + 3469: 'fr45_asia', + 3473: 'vivoactive3_daimler', + 3512: 'fenix6s_sport_asia', + 3513: 'fenix6s_asia', + 3514: 'fenix6_sport_asia', + 3515: 'fenix6_asia', + 3516: 'fenix6x_asia', + 3624: 'marq_adventurer', + 3639: 'swim2_apac', + 3648: 'marq_adventurer_asia', + 3737: 'venu_daimler_asia', + 3740: 'venu_daimler', 10007: 'sdm4', # SDM4 footpod 10014: 'edge_remote', 20119: 'training_center', @@ -1633,6 +1820,13 @@ 40: 'single_leg_hip_raise_with_head_on_bosu_ball', 41: 'weighted_single_leg_hip_raise_with_head_on_bosu_ball', 42: 'weighted_clam_bridge', + 43: 'single_leg_swiss_ball_hip_raise_and_leg_curl', + 44: 'clams', + 45: 'inner_thigh_circles', + 46: 'inner_thigh_side_lift', + 47: 'leg_circles', + 48: 'leg_lift', + 49: 'leg_lift_in_external_rotation', }, ), 'hip_stability_exercise_name': FieldType( @@ -1742,6 +1936,9 @@ 34: 'weighted_swiss_ball_hyperextension', 35: 'swiss_ball_opposite_arm_and_leg_lift', 36: 'weighted_swiss_ball_opposite_arm_and_leg_lift', + 37: 'superman_on_swiss_ball', + 38: 'cobra', + 39: 'supine_floor_barre', }, ), 'intensity': FieldType( @@ -1918,6 +2115,8 @@ 29: 'underhand_grip_rear_lateral_raise', 30: 'wall_slide', 31: 'weighted_wall_slide', + 32: 'arm_circles', + 33: 'shaving_the_head', }, ), 'left_right_balance': FieldType( @@ -2217,6 +2416,14 @@ 122: 'johnson_health_tech', 123: 'polar_electro', 124: 'seesense', + 125: 'nci_technology', + 126: 'iqsquare', + 127: 'leomo', + 128: 'ifit_com', + 129: 'coros_byte', + 130: 'versa_design', + 131: 'chileaf', + 132: 'cycplus', 255: 'development', 257: 'healthandlife', 258: 'lezyne', @@ -2255,6 +2462,17 @@ 291: 'shapelog', 292: 'dabuziduo', 293: 'jetblack', + 294: 'coros', + 295: 'virtugo', + 296: 'velosense', + 297: 'cycligentinc', + 298: 'trailforks', + 299: 'mahle_ebikemotion', + 300: 'nurvv', + 301: 'microprogram', + 302: 'zone5cloud', + 303: 'greenteg', + 304: 'yamaha_motors', 5759: 'actigraphcorp', }, ), @@ -2357,6 +2575,8 @@ 262: 'dive_alarm', 264: 'exercise_title', 268: 'dive_summary', + 285: 'jump', + 317: 'climb_pro', }, ), 'message_index': FieldType( @@ -2527,6 +2747,13 @@ 125: 'weighted_mountain_climber_with_hands_on_bench', 126: 'weighted_swiss_ball_plank_leg_lift_and_hold', 127: 'weighted_wide_stance_plank_with_opposite_arm_and_leg_lift', + 128: 'plank_with_feet_on_swiss_ball', + 129: 'side_plank_to_plank_with_reach_under', + 130: 'bridge_with_glute_lower_lift', + 131: 'bridge_one_leg_bridge', + 132: 'plank_with_arm_variations', + 133: 'plank_with_leg_lift', + 134: 'reverse_plank_with_leg_pull', }, ), 'plyo_exercise_name': FieldType( @@ -2705,6 +2932,7 @@ 75: 'ring_push_up', 76: 'weighted_ring_push_up', 77: 'push_up', + 78: 'pilates_pushup', }, ), 'pwr_zone_calc': FieldType( @@ -2715,6 +2943,16 @@ 1: 'percent_ftp', }, ), + 'radar_threat_level_type': FieldType( + name='radar_threat_level_type', + base_type=BASE_TYPES[0x00], # enum + values={ + 0: 'threat_unknown', + 1: 'threat_none', + 2: 'threat_approaching', + 3: 'threat_approaching_fast', + }, + ), 'rider_position_type': FieldType( name='rider_position_type', base_type=BASE_TYPES[0x00], # enum @@ -3262,6 +3500,11 @@ 84: 'wide_stance_barbell_squat', 85: 'wide_stance_goblet_squat', 86: 'zercher_squat', + 87: 'kbs_overhead', + 88: 'squat_and_side_kick', + 89: 'squat_jumps_in_n_out', + 90: 'pilates_plie_squats_parallel_turned_out_flat_and_heels', + 91: 'releve_straight_leg_and_knee_bent_with_one_leg_variation', }, ), 'stroke_type': FieldType( @@ -3324,7 +3567,7 @@ 41: 'whitewater', # Kayaking/Rafting 42: 'skate_skiing', # Cross Country Skiing 43: 'yoga', # Training - 44: 'pilates', # Training + 44: 'pilates', # Fitness Equipment 45: 'indoor_running', # Run 46: 'gravel_cycling', # Cycling 47: 'e_bike_mountain', # Cycling @@ -3379,6 +3622,15 @@ 2: 'auto', }, ), + 'tap_sensitivity': FieldType( + name='tap_sensitivity', + base_type=BASE_TYPES[0x00], # enum + values={ + 0: 'high', + 1: 'medium', + 2: 'low', + }, + ), 'time_into_day': FieldType( # number of seconds into the day since 00:00:00 UTC name='time_into_day', base_type=BASE_TYPES[0x86], # uint32 @@ -3892,6 +4144,7 @@ 27: 'repeat_until_training_peaks_tss', 28: 'repetition_time', 29: 'reps', + 31: 'time_only', }, ), 'wkt_step_target': FieldType( @@ -3987,6 +4240,19 @@ type=BASE_TYPES[0x84], # uint16 def_num=2, subfields=( + SubField( + name='favero_product', + def_num=2, + type=FIELD_TYPES['favero_product'], + ref_fields=( + ReferenceField( + name='manufacturer', + def_num=1, + value='favero_electronics', + raw_value=263, + ), + ), + ), SubField( name='garmin_product', def_num=2, @@ -4065,37 +4331,6 @@ ), }, ), - 4: MessageType( - name='hrm_profile', - mesg_num=4, - fields={ - 0: Field( - name='enabled', - type=FIELD_TYPES['bool'], - def_num=0, - ), - 1: Field( - name='hrm_ant_id', - type=BASE_TYPES[0x8B], # uint16z - def_num=1, - ), - 2: Field( - name='log_hrv', - type=FIELD_TYPES['bool'], - def_num=2, - ), - 3: Field( - name='hrm_ant_id_trans_type', - type=BASE_TYPES[0x0A], # uint8z - def_num=3, - ), - 254: Field( - name='message_index', - type=FIELD_TYPES['message_index'], - def_num=254, - ), - }, - ), 5: MessageType( name='sdm_profile', mesg_num=5, @@ -4664,25 +4899,25 @@ type=FIELD_TYPES['session_trigger'], def_num=28, ), - 29: Field( + 29: Field( # North east corner latitude name='nec_lat', type=BASE_TYPES[0x85], # sint32 def_num=29, units='semicircles', ), - 30: Field( + 30: Field( # North east corner longitude name='nec_long', type=BASE_TYPES[0x85], # sint32 def_num=30, units='semicircles', ), - 31: Field( + 31: Field( # South west corner latitude name='swc_lat', type=BASE_TYPES[0x85], # sint32 def_num=31, units='semicircles', ), - 32: Field( + 32: Field( # South west corner longitude name='swc_long', type=BASE_TYPES[0x85], # sint32 def_num=32, @@ -5289,6 +5524,35 @@ scale=1000, units='m/s', ), + 181: Field( # The grit score estimates how challenging a route could be for a cyclist in terms of time spent going over sharp turns or large grade slopes. + name='total_grit', + type=BASE_TYPES[0x88], # float32 + def_num=181, + units='kGrit', + ), + 182: Field( # The flow score estimates how long distance wise a cyclist deaccelerates over intervals where deacceleration is unnecessary such as smooth turns or small grade angle intervals. + name='total_flow', + type=BASE_TYPES[0x88], # float32 + def_num=182, + units='Flow', + ), + 183: Field( + name='jump_count', + type=BASE_TYPES[0x84], # uint16 + def_num=183, + ), + 186: Field( # The grit score estimates how challenging a route could be for a cyclist in terms of time spent going over sharp turns or large grade slopes. + name='avg_grit', + type=BASE_TYPES[0x88], # float32 + def_num=186, + units='kGrit', + ), + 187: Field( # The flow score estimates how long distance wise a cyclist deaccelerates over intervals where deacceleration is unnecessary such as smooth turns or small grade angle intervals. + name='avg_flow', + type=BASE_TYPES[0x88], # float32 + def_num=187, + units='Flow', + ), 253: FIELD_TYPE_TIMESTAMP, # Sesson end time. 254: Field( # Selected bit is set for the current session. name='message_index', @@ -6082,6 +6346,35 @@ scale=1000, units='m/s', ), + 149: Field( # The grit score estimates how challenging a route could be for a cyclist in terms of time spent going over sharp turns or large grade slopes. + name='total_grit', + type=BASE_TYPES[0x88], # float32 + def_num=149, + units='kGrit', + ), + 150: Field( # The flow score estimates how long distance wise a cyclist deaccelerates over intervals where deacceleration is unnecessary such as smooth turns or small grade angle intervals. + name='total_flow', + type=BASE_TYPES[0x88], # float32 + def_num=150, + units='Flow', + ), + 151: Field( + name='jump_count', + type=BASE_TYPES[0x84], # uint16 + def_num=151, + ), + 153: Field( # The grit score estimates how challenging a route could be for a cyclist in terms of time spent going over sharp turns or large grade slopes. + name='avg_grit', + type=BASE_TYPES[0x88], # float32 + def_num=153, + units='kGrit', + ), + 154: Field( # The flow score estimates how long distance wise a cyclist deaccelerates over intervals where deacceleration is unnecessary such as smooth turns or small grade angle intervals. + name='avg_flow', + type=BASE_TYPES[0x88], # float32 + def_num=154, + units='Flow', + ), 253: FIELD_TYPE_TIMESTAMP, # Lap end time. 254: Field( name='message_index', @@ -6584,6 +6877,40 @@ def_num=98, units='percent', ), + 114: Field( # The grit score estimates how challenging a route could be for a cyclist in terms of time spent going over sharp turns or large grade slopes. + name='grit', + type=BASE_TYPES[0x88], # float32 + def_num=114, + ), + 115: Field( # The flow score estimates how long distance wise a cyclist deaccelerates over intervals where deacceleration is unnecessary such as smooth turns or small grade angle intervals. + name='flow', + type=BASE_TYPES[0x88], # float32 + def_num=115, + ), + 117: Field( + name='ebike_travel_range', + type=BASE_TYPES[0x84], # uint16 + def_num=117, + units='km', + ), + 118: Field( + name='ebike_battery_level', + type=BASE_TYPES[0x02], # uint8 + def_num=118, + units='percent', + ), + 119: Field( + name='ebike_assist_mode', + type=BASE_TYPES[0x02], # uint8 + def_num=119, + units='depends on sensor', + ), + 120: Field( + name='ebike_assist_level_percent', + type=BASE_TYPES[0x02], # uint8 + def_num=120, + units='percent', + ), 253: FIELD_TYPE_TIMESTAMP, }, ), @@ -6836,6 +7163,35 @@ ), ), ), + SubField( # Thefirstbyteistheradar_threat_level_max, thesecondbyteistheradar_threat_count, and thelast16bitsarereservedforfutureuseandshouldbesettoFFFF. + name='radar_threat_alert', + def_num=3, + type=BASE_TYPES[0x86], # uint32 + ref_fields=( + ReferenceField( + name='event', + def_num=0, + value='radar_threat_alert', + raw_value=75, + ), + ), + components=( + ComponentField( + name='radar_threat_level_max', + def_num=21, + accumulate=False, + bits=8, + bit_offset=0, + ), + ComponentField( + name='radar_threat_count', + def_num=22, + accumulate=False, + bits=8, + bit_offset=8, + ), + ), + ), SubField( # Indicates the rider position value. name='rider_position', def_num=3, @@ -6958,32 +7314,32 @@ type=BASE_TYPES[0x02], # uint8 def_num=4, ), - 7: Field( # Do not populate directly. Autogenerated by decoder for sport_point subfield components + 7: Field( # Do not populate directly. Autogenerated by decoder for sport_point subfield components name='score', type=BASE_TYPES[0x84], # uint16 def_num=7, ), - 8: Field( # Do not populate directly. Autogenerated by decoder for sport_point subfield components + 8: Field( # Do not populate directly. Autogenerated by decoder for sport_point subfield components name='opponent_score', type=BASE_TYPES[0x84], # uint16 def_num=8, ), - 9: Field( # Do not populate directly. Autogenerated by decoder for gear_change subfield components. Front gear number. 1 is innermost. + 9: Field( # Do not populate directly. Autogenerated by decoder for gear_change subfield components. Front gear number. 1 is innermost. name='front_gear_num', type=BASE_TYPES[0x0A], # uint8z def_num=9, ), - 10: Field( # Do not populate directly. Autogenerated by decoder for gear_change subfield components. Number of front teeth. + 10: Field( # Do not populate directly. Autogenerated by decoder for gear_change subfield components. Number of front teeth. name='front_gear', type=BASE_TYPES[0x0A], # uint8z def_num=10, ), - 11: Field( # Do not populate directly. Autogenerated by decoder for gear_change subfield components. Rear gear number. 1 is innermost. + 11: Field( # Do not populate directly. Autogenerated by decoder for gear_change subfield components. Rear gear number. 1 is innermost. name='rear_gear_num', type=BASE_TYPES[0x0A], # uint8z def_num=11, ), - 12: Field( # Do not populate directly. Autogenerated by decoder for gear_change subfield components. Number of rear teeth. + 12: Field( # Do not populate directly. Autogenerated by decoder for gear_change subfield components. Number of rear teeth. name='rear_gear', type=BASE_TYPES[0x0A], # uint8z def_num=12, @@ -6993,6 +7349,16 @@ type=FIELD_TYPES['device_index'], def_num=13, ), + 21: Field( # Do not populate directly. Autogenerated by decoder for threat_alert subfield components. + name='radar_threat_level_max', + type=FIELD_TYPES['radar_threat_level_type'], + def_num=21, + ), + 22: Field( # Do not populate directly. Autogenerated by decoder for threat_alert subfield components. + name='radar_threat_count', + type=BASE_TYPES[0x02], # uint8 + def_num=22, + ), 253: FIELD_TYPE_TIMESTAMP, }, ), @@ -7053,6 +7419,19 @@ type=BASE_TYPES[0x84], # uint16 def_num=4, subfields=( + SubField( + name='favero_product', + def_num=4, + type=FIELD_TYPES['favero_product'], + ref_fields=( + ReferenceField( + name='manufacturer', + def_num=2, + value='favero_electronics', + raw_value=263, + ), + ), + ), SubField( name='garmin_product', def_num=4, @@ -8156,6 +8535,19 @@ type=BASE_TYPES[0x84], # uint16 def_num=2, subfields=( + SubField( + name='favero_product', + def_num=2, + type=FIELD_TYPES['favero_product'], + ref_fields=( + ReferenceField( + name='manufacturer', + def_num=1, + value='favero_electronics', + raw_value=263, + ), + ), + ), SubField( name='garmin_product', def_num=2, @@ -8556,6 +8948,19 @@ type=BASE_TYPES[0x84], # uint16 def_num=1, subfields=( + SubField( + name='favero_product', + def_num=1, + type=FIELD_TYPES['favero_product'], + ref_fields=( + ReferenceField( + name='manufacturer', + def_num=0, + value='favero_electronics', + raw_value=263, + ), + ), + ), SubField( name='garmin_product', def_num=1, @@ -9489,6 +9894,30 @@ type=FIELD_TYPES['manufacturer'], def_num=83, ), + 84: Field( # The grit score estimates how challenging a route could be for a cyclist in terms of time spent going over sharp turns or large grade slopes. + name='total_grit', + type=BASE_TYPES[0x88], # float32 + def_num=84, + units='kGrit', + ), + 85: Field( # The flow score estimates how long distance wise a cyclist deaccelerates over intervals where deacceleration is unnecessary such as smooth turns or small grade angle intervals. + name='total_flow', + type=BASE_TYPES[0x88], # float32 + def_num=85, + units='Flow', + ), + 86: Field( # The grit score estimates how challenging a route could be for a cyclist in terms of time spent going over sharp turns or large grade slopes. + name='avg_grit', + type=BASE_TYPES[0x88], # float32 + def_num=86, + units='kGrit', + ), + 87: Field( # The flow score estimates how long distance wise a cyclist deaccelerates over intervals where deacceleration is unnecessary such as smooth turns or small grade angle intervals. + name='avg_flow', + type=BASE_TYPES[0x88], # float32 + def_num=87, + units='Flow', + ), 253: FIELD_TYPE_TIMESTAMP, # Lap end time. 254: Field( name='message_index', @@ -9585,6 +10014,57 @@ ), }, ), + 151: MessageType( # Summary of the unique segment and leaderboard information associated with a segment file. This message is used to compile a segment list file describing all segment files on a device. The segment list file is used when refreshing the contents of a segment file with the latest available leaderboard information. + name='segment_file', + mesg_num=151, + fields={ + 1: Field( # UUID of the segment file + name='file_uuid', + type=BASE_TYPES[0x07], # string + def_num=1, + ), + 3: Field( # Enabled state of the segment file + name='enabled', + type=FIELD_TYPES['bool'], + def_num=3, + ), + 4: Field( # Primary key of the user that created the segment file + name='user_profile_primary_key', + type=BASE_TYPES[0x86], # uint32 + def_num=4, + ), + 7: Field( # Leader type of each leader in the segment file + name='leader_type', + type=FIELD_TYPES['segment_leaderboard_type'], + def_num=7, + ), + 8: Field( # Group primary key of each leader in the segment file + name='leader_group_primary_key', + type=BASE_TYPES[0x86], # uint32 + def_num=8, + ), + 9: Field( # Activity ID of each leader in the segment file + name='leader_activity_id', + type=BASE_TYPES[0x86], # uint32 + def_num=9, + ), + 10: Field( # String version of the activity ID of each leader in the segment file. 21 characters long for each ID, express in decimal + name='leader_activity_id_string', + type=BASE_TYPES[0x07], # string + def_num=10, + ), + 11: Field( # Index for the Leader Board entry selected as the default race participant + name='default_race_leader', + type=BASE_TYPES[0x02], # uint8 + def_num=11, + ), + 254: Field( + name='message_index', + type=FIELD_TYPES['message_index'], + def_num=254, + ), + }, + ), 158: MessageType( name='workout_session', mesg_num=158, @@ -10286,6 +10766,7 @@ type=FIELD_TYPES['switch'], def_num=0, ), + 253: FIELD_TYPE_TIMESTAMP, }, ), 200: MessageType( @@ -11093,6 +11574,118 @@ 253: FIELD_TYPE_TIMESTAMP, }, ), + 285: MessageType( + name='jump', + mesg_num=285, + fields={ + 0: Field( + name='distance', + type=BASE_TYPES[0x88], # float32 + def_num=0, + units='m', + ), + 1: Field( + name='height', + type=BASE_TYPES[0x88], # float32 + def_num=1, + units='m', + ), + 2: Field( + name='rotations', + type=BASE_TYPES[0x02], # uint8 + def_num=2, + ), + 3: Field( + name='hang_time', + type=BASE_TYPES[0x88], # float32 + def_num=3, + units='s', + ), + 4: Field( # A score for a jump calculated based on hang time, rotations, and distance. + name='score', + type=BASE_TYPES[0x88], # float32 + def_num=4, + ), + 5: Field( + name='position_lat', + type=BASE_TYPES[0x85], # sint32 + def_num=5, + units='semicircles', + ), + 6: Field( + name='position_long', + type=BASE_TYPES[0x85], # sint32 + def_num=6, + units='semicircles', + ), + 7: Field( + name='speed', + type=BASE_TYPES[0x84], # uint16 + def_num=7, + scale=1000, + units='m/s', + components=( + ComponentField( + name='enhanced_speed', + def_num=8, + scale=1000, + units='m/s', + accumulate=False, + bits=16, + bit_offset=0, + ), + ), + ), + 8: Field( + name='enhanced_speed', + type=BASE_TYPES[0x86], # uint32 + def_num=8, + scale=1000, + units='m/s', + ), + 253: FIELD_TYPE_TIMESTAMP, + }, + ), + 317: MessageType( + name='climb_pro', + mesg_num=317, + fields={ + 0: Field( + name='position_lat', + type=BASE_TYPES[0x85], # sint32 + def_num=0, + units='semicircles', + ), + 1: Field( + name='position_long', + type=BASE_TYPES[0x85], # sint32 + def_num=1, + units='semicircles', + ), + 2: Field( + name='climb_pro_event', + type=FIELD_TYPES['climb_pro_event'], + def_num=2, + ), + 3: Field( + name='climb_number', + type=BASE_TYPES[0x84], # uint16 + def_num=3, + ), + 4: Field( + name='climb_category', + type=BASE_TYPES[0x02], # uint8 + def_num=4, + ), + 5: Field( + name='current_dist', + type=BASE_TYPES[0x88], # float32 + def_num=5, + units='m', + ), + 253: FIELD_TYPE_TIMESTAMP, + }, + ), # ************************* Activity File Messages ************************* @@ -11422,6 +12015,19 @@ type=BASE_TYPES[0x84], # uint16 def_num=1, subfields=( + SubField( + name='favero_product', + def_num=1, + type=FIELD_TYPES['favero_product'], + ref_fields=( + ReferenceField( + name='manufacturer', + def_num=0, + value='favero_electronics', + raw_value=263, + ), + ), + ), SubField( name='garmin_product', def_num=1, @@ -11532,60 +12138,6 @@ ), - # *********************** Segment List File Messages *********************** - 151: MessageType( # Summary of the unique segment and leaderboard information associated with a segment file. This message is used to compile a segment list file describing all segment files on a device. The segment list file is used when refreshing the contents of a segment file with the latest available leaderboard information. - name='segment_file', - mesg_num=151, - fields={ - 1: Field( # UUID of the segment file - name='file_uuid', - type=BASE_TYPES[0x07], # string - def_num=1, - ), - 3: Field( # Enabled state of the segment file - name='enabled', - type=FIELD_TYPES['bool'], - def_num=3, - ), - 4: Field( # Primary key of the user that created the segment file - name='user_profile_primary_key', - type=BASE_TYPES[0x86], # uint32 - def_num=4, - ), - 7: Field( # Leader type of each leader in the segment file - name='leader_type', - type=FIELD_TYPES['segment_leaderboard_type'], - def_num=7, - ), - 8: Field( # Group primary key of each leader in the segment file - name='leader_group_primary_key', - type=BASE_TYPES[0x86], # uint32 - def_num=8, - ), - 9: Field( # Activity ID of each leader in the segment file - name='leader_activity_id', - type=BASE_TYPES[0x86], # uint32 - def_num=9, - ), - 10: Field( # String version of the activity ID of each leader in the segment file. 21 characters long for each ID, express in decimal - name='leader_activity_id_string', - type=BASE_TYPES[0x07], # string - def_num=10, - ), - 11: Field( # Index for the Leader Board entry selected as the default race participant - name='default_race_leader', - type=BASE_TYPES[0x02], # uint8 - def_num=11, - ), - 254: Field( - name='message_index', - type=FIELD_TYPES['message_index'], - def_num=254, - ), - }, - ), - - # ************************* Settings File Messages ************************* 2: MessageType( name='device_settings', @@ -11711,6 +12263,12 @@ type=FIELD_TYPES['switch'], def_num=134, ), + 174: Field( # Used to hold the tap threshold setting + name='tap_sensitivity', + type=FIELD_TYPES['tap_sensitivity'], + def_num=174, + offset=1, + ), }, ), 3: MessageType( @@ -11877,6 +12435,37 @@ ), }, ), + 4: MessageType( + name='hrm_profile', + mesg_num=4, + fields={ + 0: Field( + name='enabled', + type=FIELD_TYPES['bool'], + def_num=0, + ), + 1: Field( + name='hrm_ant_id', + type=BASE_TYPES[0x8B], # uint16z + def_num=1, + ), + 2: Field( + name='log_hrv', + type=FIELD_TYPES['bool'], + def_num=2, + ), + 3: Field( + name='hrm_ant_id_trans_type', + type=BASE_TYPES[0x0A], # uint8z + def_num=3, + ), + 254: Field( + name='message_index', + type=FIELD_TYPES['message_index'], + def_num=254, + ), + }, + ), # ********************** Sport Settings File Messages **********************