diff --git a/fitparse/profile.py b/fitparse/profile.py index daaf579..d98c892 100644 --- a/fitparse/profile.py +++ b/fitparse/profile.py @@ -1,7 +1,7 @@ # ***************** 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.67 ON 2021-11-01 ************ +# ********* PARSED 165 TYPES (3296 VALUES), 87 MESSAGES (1098 FIELDS) ********** from fitparse.records import ( ComponentField, @@ -121,10 +121,12 @@ 26: 'racquet', 27: 'control_hub', 31: 'muscle_oxygen', + 34: 'shifting', 35: 'bike_light_main', 36: 'bike_light_shared', 38: 'exd', 40: 'bike_radar', + 46: 'bike_aero', 119: 'weight_scale', 120: 'heart_rate', 121: 'bike_speed_cadence', @@ -486,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 @@ -584,6 +595,33 @@ 43: 'overhead_walk', 44: 'inchworm', 45: 'weighted_modified_front_lever', + 46: 'russian_twist', + 47: 'abdominal_leg_rotations', # Deprecated do not use + 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', # Deprecated do not use + 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', # Deprecated do not use + 69: 'swan', + 70: 'swimming', + 71: 'teaser', + 72: 'the_hundred', }, ), 'course_capabilities': FieldType( @@ -723,6 +761,7 @@ 81: 'toes_to_bar', 82: 'weighted_toes_to_bar', 83: 'crunch', + 84: 'straight_leg_crunch_with_ball', }, ), 'curl_exercise_name': FieldType( @@ -991,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( @@ -1197,6 +1237,7 @@ 5: 'full_quarter_split', 6: 'half_vertical_left_split', 7: 'half_horizontal_top_split', + 8: 'dynamic', # The EXD may display the configured concepts in any layout it sees fit. }, ), 'exd_qualifiers': FieldType( @@ -1289,6 +1330,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 @@ -1378,6 +1427,8 @@ 5: 'kneeling_rear_flye', 6: 'single_arm_standing_cable_reverse_flye', 7: 'swiss_ball_dumbbell_flye', + 8: 'arm_rotations', + 9: 'hug_a_tree', }, ), 'strava_product': FieldType( @@ -1404,7 +1455,10 @@ 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 + 15: 'gen3_bsm_single_byte_product_id', # gen3_bsm model for Bike Speed ANT+ messaging + 16: 'gen3_bcm_single_byte_product_id', # gen3_bcm model for Bike Cadence ANT+ messaging 473: 'fr301_china', 474: 'fr301_japan', 475: 'fr301_korea', @@ -1433,6 +1487,7 @@ 1381: 'vector_cp', 1386: 'edge800_china', 1387: 'edge500_china', + 1405: 'approach_g10', 1410: 'fr610_japan', 1422: 'edge500_korea', 1436: 'fr70', @@ -1456,7 +1511,7 @@ 1735: 'virb_elite', 1736: 'edge_touring', # Also Edge Touring Plus 1742: 'edge510_japan', - 1743: 'hrm_tri', + 1743: 'hrm_tri', # Also HRM-Swim 1752: 'hrm_run', 1765: 'fr920xt', 1821: 'edge510_asia', @@ -1499,6 +1554,7 @@ 2153: 'fr225', 2156: 'fr630', 2157: 'fr230', + 2158: 'fr735xt', 2160: 'vivo_active_apac', 2161: 'vector_2', 2162: 'vector_2s', @@ -1506,6 +1562,7 @@ 2173: 'fr620_taiwan', 2174: 'fr220_taiwan', 2175: 'truswing', + 2187: 'd2airvenu', 2188: 'fenix3_china', 2189: 'fenix3_twn', 2192: 'varia_headlight', @@ -1515,16 +1572,37 @@ 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', + 2396: 'fr235_asia', + 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', @@ -1532,20 +1610,190 @@ 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', + 2787: 'vector_3', + 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', + 2878: 'vivo_fit4', + 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', + 3113: 'fr945', + 3121: 'edge_530', + 3122: 'edge_830', + 3126: 'instinct_esports', + 3134: 'fenix5s_plus_apac', + 3135: 'fenix5x_plus_apac', + 3142: 'edge_520_plus_apac', + 3144: 'fr235l_asia', + 3145: 'fr245_asia', + 3163: 'vivo_active3m_apac', + 3192: 'gen3_bsm', # gen3 bike speed sensor + 3193: 'gen3_bcm', # gen3 bike cadence sensor + 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', + 3258: 'descent_mk2', + 3284: 'gpsmap66i', + 3287: 'fenix6S_sport', + 3288: 'fenix6S', + 3289: 'fenix6_sport', + 3290: 'fenix6', + 3291: 'fenix6x', + 3299: 'hrm_dual', # HRM-Dual + 3300: 'hrm_pro', # HRM-Pro + 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', + 3441: 'fr945_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', + 3498: 'legacy_rey', + 3499: 'legacy_darth_vader', + 3500: 'legacy_captain_marvel', + 3501: 'legacy_first_avenger', + 3512: 'fenix6s_sport_asia', + 3513: 'fenix6s_asia', + 3514: 'fenix6_sport_asia', + 3515: 'fenix6_asia', + 3516: 'fenix6x_asia', + 3535: 'legacy_captain_marvel_asia', + 3536: 'legacy_first_avenger_asia', + 3537: 'legacy_rey_asia', + 3538: 'legacy_darth_vader_asia', + 3542: 'descent_mk2s', + 3558: 'edge_130_plus', + 3570: 'edge_1030_plus', + 3578: 'rally_200', # Rally 100/200 Power Meter Series + 3589: 'fr745', + 3600: 'venusq', + 3615: 'lily', + 3624: 'marq_adventurer', + 3638: 'enduro', + 3639: 'swim2_apac', + 3648: 'marq_adventurer_asia', + 3652: 'fr945_lte', + 3702: 'descent_mk2_asia', # Mk2 and Mk2i + 3703: 'venu2', + 3704: 'venu2s', + 3737: 'venu_daimler_asia', + 3739: 'marq_golfer', + 3740: 'venu_daimler', + 3794: 'fr745_asia', + 3809: 'lily_asia', + 3812: 'edge_1030_plus_asia', + 3813: 'edge_130_plus_asia', + 3823: 'approach_s12', + 3837: 'venusq_asia', + 3850: 'marq_golfer_asia', + 3869: 'fr55', + 3872: 'enduro_asia', + 3930: 'descent_mk2s_asia', + 3934: 'approach_s42', + 3949: 'venu2s_asia', + 3950: 'venu2_asia', + 3978: 'fr945_lte_asia', + 3986: 'approach_S12_asia', + 4002: 'approach_s42_asia', + 4033: 'fr55_asia', 10007: 'sdm4', # SDM4 footpod 10014: 'edge_remote', + 3927: 'approach_g12', + 4001: 'approach_g12_asia', 20119: 'training_center', + 20533: 'tacx_training_app_win', + 20534: 'tacx_training_app_mac', + 30045: 'tacx_training_app_android', + 30046: 'tacx_training_app_ios', + 30047: 'tacx_training_app_legacy', 65531: 'connectiq_simulator', 65532: 'android_antplus_plugin', 65534: 'connect', # Garmin Connect website @@ -1640,6 +1888,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', # Deprecated do not use + 46: 'inner_thigh_side_lift', # Deprecated do not use + 47: 'leg_circles', + 48: 'leg_lift', + 49: 'leg_lift_in_external_rotation', }, ), 'hip_stability_exercise_name': FieldType( @@ -1749,6 +2004,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', # Deprecated do not use }, ), 'intensity': FieldType( @@ -1759,6 +2017,9 @@ 1: 'rest', 2: 'warmup', 3: 'cooldown', + 4: 'recovery', + 5: 'interval', + 6: 'other', }, ), 'language': FieldType( @@ -1925,6 +2186,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( @@ -2143,6 +2406,7 @@ 38: 'osynce', 39: 'holux', 40: 'concept2', + 41: 'shimano', 42: 'one_giant_leap', 43: 'ace_sensor', 44: 'brim_brothers', @@ -2224,6 +2488,18 @@ 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', + 133: 'gravaa_byte', + 134: 'sigeyi', + 135: 'coospo', + 136: 'geoid', 255: 'development', 257: 'healthandlife', 258: 'lezyne', @@ -2262,6 +2538,24 @@ 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', + 305: 'whoop', + 306: 'gravaa', + 307: 'onelap', + 308: 'monark_exercise', + 309: 'form', + 310: 'decathlon', + 311: 'syncros', 5759: 'actigraphcorp', }, ), @@ -2364,6 +2658,8 @@ 262: 'dive_alarm', 264: 'exercise_title', 268: 'dive_summary', + 285: 'jump', + 317: 'climb_pro', }, ), 'message_index': FieldType( @@ -2534,6 +2830,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( @@ -2712,6 +3015,7 @@ 75: 'ring_push_up', 76: 'weighted_ring_push_up', 77: 'push_up', + 78: 'pilates_pushup', }, ), 'pwr_zone_calc': FieldType( @@ -2722,6 +3026,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 @@ -3069,6 +3383,7 @@ 46: 'jumpmaster', 47: 'boxing', 48: 'floor_climbing', + 53: 'diving', 254: 'all', # All is for goals only to include all sports. }, ), @@ -3269,6 +3584,11 @@ 84: 'wide_stance_barbell_squat', 85: 'wide_stance_goblet_squat', 86: 'zercher_squat', + 87: 'kbs_overhead', # Deprecated do not use + 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( @@ -3331,7 +3651,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 @@ -3347,6 +3667,11 @@ 57: 'apnea_hunting', # Diving 58: 'virtual_activity', 59: 'obstacle', # Used for events where participants run, crawl through mud, climb over walls, etc. + 62: 'breathing', + 65: 'sail_race', # Sailing + 67: 'ultra', # Ultramarathon + 68: 'indoor_climbing', # Climbing + 69: 'bouldering', # Climbing 254: 'all', }, ), @@ -3386,6 +3711,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 @@ -3682,7 +4016,7 @@ 13: 'neck_rotations', 14: 'opposite_arm_and_leg_balance', 15: 'reach_roll_and_lift', - 16: 'scorpion', + 16: 'scorpion', # Deprecated do not use 17: 'shoulder_circles', 18: 'side_to_side_leg_swings', 19: 'sleeper_stretch', @@ -3899,6 +4233,7 @@ 27: 'repeat_until_training_peaks_tss', 28: 'repetition_time', 29: 'reps', + 31: 'time_only', }, ), 'wkt_step_target': FieldType( @@ -3974,7 +4309,7 @@ MESSAGE_TYPES = { - # **************************** Common Messages ***************************** + # ************************************ ************************************ 0: MessageType( # Must be first message in file. name='file_id', mesg_num=0, @@ -3994,6 +4329,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, @@ -4017,6 +4365,12 @@ value='dynastream_oem', raw_value=13, ), + ReferenceField( + name='manufacturer', + def_num=1, + value='tacx', + raw_value=89, + ), ) ), SubField( @@ -4056,9 +4410,6 @@ ), }, ), - - - # ************************************ ************************************ 1: MessageType( name='capabilities', mesg_num=1, @@ -4085,153 +4436,448 @@ ), }, ), - 4: MessageType( - name='hrm_profile', - mesg_num=4, + 2: MessageType( + name='device_settings', + mesg_num=2, fields={ - 0: Field( - name='enabled', - type=FIELD_TYPES['bool'], + 0: Field( # Index into time zone arrays. + name='active_time_zone', + type=BASE_TYPES[0x02], # uint8 def_num=0, ), - 1: Field( - name='hrm_ant_id', - type=BASE_TYPES[0x8B], # uint16z + 1: Field( # Offset from system time. Required to convert timestamp from system time to UTC. + name='utc_offset', + type=BASE_TYPES[0x86], # uint32 def_num=1, ), - 2: Field( - name='log_hrv', - type=FIELD_TYPES['bool'], + 2: Field( # Offset from system time. + name='time_offset', + type=BASE_TYPES[0x86], # uint32 def_num=2, + units='s', ), - 3: Field( - name='hrm_ant_id_trans_type', - type=BASE_TYPES[0x0A], # uint8z - def_num=3, + 4: Field( # Display mode for the time + name='time_mode', + type=FIELD_TYPES['time_mode'], + def_num=4, ), - 254: Field( - name='message_index', - type=FIELD_TYPES['message_index'], - def_num=254, + 5: Field( # timezone offset in 1/4 hour increments + name='time_zone_offset', + type=BASE_TYPES[0x01], # sint8 + def_num=5, + scale=4, + units='hr', ), - }, - ), - 5: MessageType( - name='sdm_profile', - mesg_num=5, - fields={ - 0: Field( - name='enabled', + 12: Field( # Mode for backlight + name='backlight_mode', + type=FIELD_TYPES['backlight_mode'], + def_num=12, + ), + 36: Field( # Enabled state of the activity tracker functionality + name='activity_tracker_enabled', type=FIELD_TYPES['bool'], - def_num=0, + def_num=36, ), - 1: Field( - name='sdm_ant_id', - type=BASE_TYPES[0x8B], # uint16z - def_num=1, + 39: Field( # UTC timestamp used to set the devices clock and date + name='clock_time', + type=FIELD_TYPES['date_time'], + def_num=39, ), - 2: Field( - name='sdm_cal_factor', + 40: Field( # Bitfield to configure enabled screens for each supported loop + name='pages_enabled', type=BASE_TYPES[0x84], # uint16 - def_num=2, - scale=10, - units='%', + def_num=40, ), - 3: Field( - name='odometer', - type=BASE_TYPES[0x86], # uint32 - def_num=3, - scale=100, - units='m', + 46: Field( # Enabled state of the move alert + name='move_alert_enabled', + type=FIELD_TYPES['bool'], + def_num=46, ), - 4: Field( # Use footpod for speed source instead of GPS - name='speed_source', + 47: Field( # Display mode for the date + name='date_mode', + type=FIELD_TYPES['date_mode'], + def_num=47, + ), + 55: Field( + name='display_orientation', + type=FIELD_TYPES['display_orientation'], + def_num=55, + ), + 56: Field( + name='mounting_side', + type=FIELD_TYPES['side'], + def_num=56, + ), + 57: Field( # Bitfield to indicate one page as default for each supported loop + name='default_page', + type=BASE_TYPES[0x84], # uint16 + def_num=57, + ), + 58: Field( # Minimum steps before an autosync can occur + name='autosync_min_steps', + type=BASE_TYPES[0x84], # uint16 + def_num=58, + units='steps', + ), + 59: Field( # Minimum minutes before an autosync can occur + name='autosync_min_time', + type=BASE_TYPES[0x84], # uint16 + def_num=59, + units='minutes', + ), + 80: Field( # Enable auto-detect setting for the lactate threshold feature. + name='lactate_threshold_autodetect_enabled', type=FIELD_TYPES['bool'], - def_num=4, + def_num=80, ), - 5: Field( - name='sdm_ant_id_trans_type', - type=BASE_TYPES[0x0A], # uint8z - def_num=5, + 86: Field( # Automatically upload using BLE + name='ble_auto_upload_enabled', + type=FIELD_TYPES['bool'], + def_num=86, ), - 7: Field( # Rollover counter that can be used to extend the odometer - name='odometer_rollover', + 89: Field( # Helps to conserve battery by changing modes + name='auto_sync_frequency', + type=FIELD_TYPES['auto_sync_frequency'], + def_num=89, + ), + 90: Field( # Allows setting specific activities auto-activity detect enabled/disabled settings + name='auto_activity_detect', + type=FIELD_TYPES['auto_activity_detect'], + def_num=90, + ), + 94: Field( # Number of screens configured to display + name='number_of_screens', type=BASE_TYPES[0x02], # uint8 - def_num=7, + def_num=94, ), - 254: Field( - name='message_index', - type=FIELD_TYPES['message_index'], - def_num=254, + 95: Field( # Smart Notification display orientation + name='smart_notification_display_orientation', + type=FIELD_TYPES['display_orientation'], + def_num=95, + ), + 134: Field( + name='tap_interface', + 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, ), }, ), - 6: MessageType( - name='bike_profile', - mesg_num=6, + 3: MessageType( + name='user_profile', + mesg_num=3, fields={ 0: Field( - name='name', + name='friendly_name', type=BASE_TYPES[0x07], # string def_num=0, ), 1: Field( - name='sport', - type=FIELD_TYPES['sport'], + name='gender', + type=FIELD_TYPES['gender'], def_num=1, ), 2: Field( - name='sub_sport', - type=FIELD_TYPES['sub_sport'], + name='age', + type=BASE_TYPES[0x02], # uint8 def_num=2, + units='years', ), 3: Field( - name='odometer', - type=BASE_TYPES[0x86], # uint32 + name='height', + type=BASE_TYPES[0x02], # uint8 def_num=3, scale=100, units='m', ), 4: Field( - name='bike_spd_ant_id', - type=BASE_TYPES[0x8B], # uint16z + name='weight', + type=BASE_TYPES[0x84], # uint16 def_num=4, + scale=10, + units='kg', ), 5: Field( - name='bike_cad_ant_id', - type=BASE_TYPES[0x8B], # uint16z + name='language', + type=FIELD_TYPES['language'], def_num=5, ), 6: Field( - name='bike_spdcad_ant_id', - type=BASE_TYPES[0x8B], # uint16z + name='elev_setting', + type=FIELD_TYPES['display_measure'], def_num=6, ), 7: Field( - name='bike_power_ant_id', - type=BASE_TYPES[0x8B], # uint16z + name='weight_setting', + type=FIELD_TYPES['display_measure'], def_num=7, ), 8: Field( - name='custom_wheelsize', - type=BASE_TYPES[0x84], # uint16 + name='resting_heart_rate', + type=BASE_TYPES[0x02], # uint8 def_num=8, - scale=1000, - units='m', + units='bpm', ), 9: Field( - name='auto_wheelsize', - type=BASE_TYPES[0x84], # uint16 + name='default_max_running_heart_rate', + type=BASE_TYPES[0x02], # uint8 def_num=9, - scale=1000, - units='m', + units='bpm', ), 10: Field( - name='bike_weight', - type=BASE_TYPES[0x84], # uint16 + name='default_max_biking_heart_rate', + type=BASE_TYPES[0x02], # uint8 def_num=10, - scale=10, - units='kg', + units='bpm', + ), + 11: Field( + name='default_max_heart_rate', + type=BASE_TYPES[0x02], # uint8 + def_num=11, + units='bpm', + ), + 12: Field( + name='hr_setting', + type=FIELD_TYPES['display_heart'], + def_num=12, + ), + 13: Field( + name='speed_setting', + type=FIELD_TYPES['display_measure'], + def_num=13, + ), + 14: Field( + name='dist_setting', + type=FIELD_TYPES['display_measure'], + def_num=14, + ), + 16: Field( + name='power_setting', + type=FIELD_TYPES['display_power'], + def_num=16, + ), + 17: Field( + name='activity_class', + type=FIELD_TYPES['activity_class'], + def_num=17, + ), + 18: Field( + name='position_setting', + type=FIELD_TYPES['display_position'], + def_num=18, + ), + 21: Field( + name='temperature_setting', + type=FIELD_TYPES['display_measure'], + def_num=21, + ), + 22: Field( + name='local_id', + type=FIELD_TYPES['user_local_id'], + def_num=22, + ), + 23: Field( + name='global_id', + type=BASE_TYPES[0x0D], # byte + def_num=23, + ), + 28: Field( # Typical wake time + name='wake_time', + type=FIELD_TYPES['localtime_into_day'], + def_num=28, + ), + 29: Field( # Typical bed time + name='sleep_time', + type=FIELD_TYPES['localtime_into_day'], + def_num=29, + ), + 30: Field( + name='height_setting', + type=FIELD_TYPES['display_measure'], + def_num=30, + ), + 31: Field( # User defined running step length set to 0 for auto length + name='user_running_step_length', + type=BASE_TYPES[0x84], # uint16 + def_num=31, + scale=1000, + units='m', + ), + 32: Field( # User defined walking step length set to 0 for auto length + name='user_walking_step_length', + type=BASE_TYPES[0x84], # uint16 + def_num=32, + scale=1000, + units='m', + ), + 47: Field( + name='depth_setting', + type=FIELD_TYPES['display_measure'], + def_num=47, + ), + 49: Field( + name='dive_count', + type=BASE_TYPES[0x86], # uint32 + def_num=49, + ), + 254: Field( + name='message_index', + type=FIELD_TYPES['message_index'], + def_num=254, + ), + }, + ), + 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, + fields={ + 0: Field( + name='enabled', + type=FIELD_TYPES['bool'], + def_num=0, + ), + 1: Field( + name='sdm_ant_id', + type=BASE_TYPES[0x8B], # uint16z + def_num=1, + ), + 2: Field( + name='sdm_cal_factor', + type=BASE_TYPES[0x84], # uint16 + def_num=2, + scale=10, + units='%', + ), + 3: Field( + name='odometer', + type=BASE_TYPES[0x86], # uint32 + def_num=3, + scale=100, + units='m', + ), + 4: Field( # Use footpod for speed source instead of GPS + name='speed_source', + type=FIELD_TYPES['bool'], + def_num=4, + ), + 5: Field( + name='sdm_ant_id_trans_type', + type=BASE_TYPES[0x0A], # uint8z + def_num=5, + ), + 7: Field( # Rollover counter that can be used to extend the odometer + name='odometer_rollover', + type=BASE_TYPES[0x02], # uint8 + def_num=7, + ), + 254: Field( + name='message_index', + type=FIELD_TYPES['message_index'], + def_num=254, + ), + }, + ), + 6: MessageType( + name='bike_profile', + mesg_num=6, + fields={ + 0: Field( + name='name', + type=BASE_TYPES[0x07], # string + def_num=0, + ), + 1: Field( + name='sport', + type=FIELD_TYPES['sport'], + def_num=1, + ), + 2: Field( + name='sub_sport', + type=FIELD_TYPES['sub_sport'], + def_num=2, + ), + 3: Field( + name='odometer', + type=BASE_TYPES[0x86], # uint32 + def_num=3, + scale=100, + units='m', + ), + 4: Field( + name='bike_spd_ant_id', + type=BASE_TYPES[0x8B], # uint16z + def_num=4, + ), + 5: Field( + name='bike_cad_ant_id', + type=BASE_TYPES[0x8B], # uint16z + def_num=5, + ), + 6: Field( + name='bike_spdcad_ant_id', + type=BASE_TYPES[0x8B], # uint16z + def_num=6, + ), + 7: Field( + name='bike_power_ant_id', + type=BASE_TYPES[0x8B], # uint16z + def_num=7, + ), + 8: Field( + name='custom_wheelsize', + type=BASE_TYPES[0x84], # uint16 + def_num=8, + scale=1000, + units='m', + ), + 9: Field( + name='auto_wheelsize', + type=BASE_TYPES[0x84], # uint16 + def_num=9, + scale=1000, + units='m', + ), + 10: Field( + name='bike_weight', + type=BASE_TYPES[0x84], # uint16 + def_num=10, + scale=10, + units='kg', ), 11: Field( name='power_cal_factor', @@ -4345,19 +4991,50 @@ ), }, ), - 8: MessageType( - name='hr_zone', - mesg_num=8, + 7: MessageType( + name='zones_target', + mesg_num=7, fields={ 1: Field( - name='high_bpm', + name='max_heart_rate', type=BASE_TYPES[0x02], # uint8 def_num=1, - units='bpm', ), 2: Field( - name='name', - type=BASE_TYPES[0x07], # string + name='threshold_heart_rate', + type=BASE_TYPES[0x02], # uint8 + def_num=2, + ), + 3: Field( + name='functional_threshold_power', + type=BASE_TYPES[0x84], # uint16 + def_num=3, + ), + 5: Field( + name='hr_calc_type', + type=FIELD_TYPES['hr_zone_calc'], + def_num=5, + ), + 7: Field( + name='pwr_calc_type', + type=FIELD_TYPES['pwr_zone_calc'], + def_num=7, + ), + }, + ), + 8: MessageType( + name='hr_zone', + mesg_num=8, + fields={ + 1: Field( + name='high_bpm', + type=BASE_TYPES[0x02], # uint8 + def_num=1, + units='bpm', + ), + 2: Field( + name='name', + type=BASE_TYPES[0x07], # string def_num=2, ), 254: Field( @@ -4440,6 +5117,77 @@ ), }, ), + 15: MessageType( + name='goal', + mesg_num=15, + fields={ + 0: Field( + name='sport', + type=FIELD_TYPES['sport'], + def_num=0, + ), + 1: Field( + name='sub_sport', + type=FIELD_TYPES['sub_sport'], + def_num=1, + ), + 2: Field( + name='start_date', + type=FIELD_TYPES['date_time'], + def_num=2, + ), + 3: Field( + name='end_date', + type=FIELD_TYPES['date_time'], + def_num=3, + ), + 4: Field( + name='type', + type=FIELD_TYPES['goal'], + def_num=4, + ), + 5: Field( + name='value', + type=BASE_TYPES[0x86], # uint32 + def_num=5, + ), + 6: Field( + name='repeat', + type=FIELD_TYPES['bool'], + def_num=6, + ), + 7: Field( + name='target_value', + type=BASE_TYPES[0x86], # uint32 + def_num=7, + ), + 8: Field( + name='recurrence', + type=FIELD_TYPES['goal_recurrence'], + def_num=8, + ), + 9: Field( + name='recurrence_value', + type=BASE_TYPES[0x84], # uint16 + def_num=9, + ), + 10: Field( + name='enabled', + type=FIELD_TYPES['bool'], + def_num=10, + ), + 11: Field( + name='source', + type=FIELD_TYPES['goal_source'], + def_num=11, + ), + 254: Field( + name='message_index', + type=FIELD_TYPES['message_index'], + def_num=254, + ), + }, + ), 18: MessageType( name='session', mesg_num=18, @@ -4528,6 +5276,38 @@ ), ), ), + SubField( + name='total_strokes', + def_num=10, + type=BASE_TYPES[0x86], # uint32 + units='strokes', + ref_fields=( + ReferenceField( + name='sport', + def_num=5, + value='cycling', + raw_value=2, + ), + ReferenceField( + name='sport', + def_num=5, + value='swimming', + raw_value=5, + ), + ReferenceField( + name='sport', + def_num=5, + value='rowing', + raw_value=15, + ), + ReferenceField( + name='sport', + def_num=5, + value='stand_up_paddleboarding', + raw_value=37, + ), + ), + ), ), ), 11: Field( @@ -4684,30 +5464,36 @@ 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, units='semicircles', ), + 33: Field( # # of lengths of swim pool + name='num_lengths', + type=BASE_TYPES[0x84], # uint16 + def_num=33, + units='lengths', + ), 34: Field( name='normalized_power', type=BASE_TYPES[0x84], # uint16 @@ -5309,6 +6095,70 @@ 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', + ), + 199: Field( # fractional part of total_ascent + name='total_fractional_ascent', + type=BASE_TYPES[0x02], # uint8 + def_num=199, + scale=100, + units='m', + ), + 200: Field( # fractional part of total_descent + name='total_fractional_descent', + type=BASE_TYPES[0x02], # uint8 + def_num=200, + scale=100, + units='m', + ), + 208: Field( + name='avg_core_temperature', + type=BASE_TYPES[0x84], # uint16 + def_num=208, + scale=100, + units='C', + ), + 209: Field( + name='min_core_temperature', + type=BASE_TYPES[0x84], # uint16 + def_num=209, + scale=100, + units='C', + ), + 210: Field( + name='max_core_temperature', + type=BASE_TYPES[0x84], # uint16 + def_num=210, + scale=100, + units='C', + ), 253: FIELD_TYPE_TIMESTAMP, # Sesson end time. 254: Field( # Selected bit is set for the current session. name='message_index', @@ -5407,6 +6257,38 @@ ), ), ), + SubField( + name='total_strokes', + def_num=10, + type=BASE_TYPES[0x86], # uint32 + units='strokes', + ref_fields=( + ReferenceField( + name='sport', + def_num=25, + value='cycling', + raw_value=2, + ), + ReferenceField( + name='sport', + def_num=25, + value='swimming', + raw_value=5, + ), + ReferenceField( + name='sport', + def_num=25, + value='rowing', + raw_value=15, + ), + ReferenceField( + name='sport', + def_num=25, + value='stand_up_paddleboarding', + raw_value=37, + ), + ), + ), ), ), 11: Field( @@ -6102,6 +6984,70 @@ 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', + ), + 156: Field( # fractional part of total_ascent + name='total_fractional_ascent', + type=BASE_TYPES[0x02], # uint8 + def_num=156, + scale=100, + units='m', + ), + 157: Field( # fractional part of total_descent + name='total_fractional_descent', + type=BASE_TYPES[0x02], # uint8 + def_num=157, + scale=100, + units='m', + ), + 158: Field( + name='avg_core_temperature', + type=BASE_TYPES[0x84], # uint16 + def_num=158, + scale=100, + units='C', + ), + 159: Field( + name='min_core_temperature', + type=BASE_TYPES[0x84], # uint16 + def_num=159, + scale=100, + units='C', + ), + 160: Field( + name='max_core_temperature', + type=BASE_TYPES[0x84], # uint16 + def_num=160, + scale=100, + units='C', + ), 253: FIELD_TYPE_TIMESTAMP, # Lap end time. 254: Field( name='message_index', @@ -6604,29 +7550,70 @@ def_num=98, units='percent', ), - 253: FIELD_TYPE_TIMESTAMP, - }, - ), - 21: MessageType( - name='event', - mesg_num=21, - fields={ - 0: Field( - name='event', - type=FIELD_TYPES['event'], - def_num=0, + 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, ), - 1: Field( - name='event_type', - type=FIELD_TYPES['event_type'], - def_num=1, + 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, ), - 2: Field( - name='data16', + 117: Field( + name='ebike_travel_range', type=BASE_TYPES[0x84], # uint16 - def_num=2, - components=( - ComponentField( + 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', + ), + 139: Field( + name='core_temperature', + type=BASE_TYPES[0x84], # uint16 + def_num=139, + scale=100, + units='C', + ), + 253: FIELD_TYPE_TIMESTAMP, + }, + ), + 21: MessageType( + name='event', + mesg_num=21, + fields={ + 0: Field( + name='event', + type=FIELD_TYPES['event'], + def_num=0, + ), + 1: Field( + name='event_type', + type=FIELD_TYPES['event_type'], + def_num=1, + ), + 2: Field( + name='data16', + type=BASE_TYPES[0x84], # uint16 + def_num=2, + components=( + ComponentField( name='data', def_num=3, accumulate=False, @@ -6856,6 +7843,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, @@ -6978,32 +7994,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, @@ -7013,6 +8029,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, }, ), @@ -7073,6 +8099,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, @@ -7096,6 +8135,12 @@ value='dynastream_oem', raw_value=13, ), + ReferenceField( + name='manufacturer', + def_num=2, + value='tacx', + raw_value=89, + ), ), ), SubField( @@ -7180,6 +8225,49 @@ 253: FIELD_TYPE_TIMESTAMP, }, ), + 26: MessageType( + name='workout', + mesg_num=26, + fields={ + 4: Field( + name='sport', + type=FIELD_TYPES['sport'], + def_num=4, + ), + 5: Field( + name='capabilities', + type=FIELD_TYPES['workout_capabilities'], + def_num=5, + ), + 6: Field( # number of valid steps + name='num_valid_steps', + type=BASE_TYPES[0x84], # uint16 + def_num=6, + ), + 8: Field( + name='wkt_name', + type=BASE_TYPES[0x07], # string + def_num=8, + ), + 11: Field( + name='sub_sport', + type=FIELD_TYPES['sub_sport'], + def_num=11, + ), + 14: Field( + name='pool_length', + type=BASE_TYPES[0x84], # uint16 + def_num=14, + scale=100, + units='m', + ), + 15: Field( + name='pool_length_unit', + type=FIELD_TYPES['display_measure'], + def_num=15, + ), + }, + ), 27: MessageType( name='workout_step', mesg_num=27, @@ -7705,157 +8793,245 @@ ), }, ), - 32: MessageType( - name='course_point', - mesg_num=32, + 28: MessageType( + name='schedule', + mesg_num=28, fields={ - 1: Field( - name='timestamp', - type=FIELD_TYPES['date_time'], + 0: Field( # Corresponds to file_id of scheduled workout / course. + name='manufacturer', + type=FIELD_TYPES['manufacturer'], + def_num=0, + ), + 1: Field( # Corresponds to file_id of scheduled workout / course. + name='product', + 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, + type=FIELD_TYPES['garmin_product'], + ref_fields=( + ReferenceField( + name='manufacturer', + def_num=0, + value='garmin', + raw_value=1, + ), + ReferenceField( + name='manufacturer', + def_num=0, + value='dynastream', + raw_value=15, + ), + ReferenceField( + name='manufacturer', + def_num=0, + value='dynastream_oem', + raw_value=13, + ), + ReferenceField( + name='manufacturer', + def_num=0, + value='tacx', + raw_value=89, + ), + ), + ), + ), ), - 2: Field( - name='position_lat', - type=BASE_TYPES[0x85], # sint32 + 2: Field( # Corresponds to file_id of scheduled workout / course. + name='serial_number', + type=BASE_TYPES[0x8C], # uint32z def_num=2, - units='semicircles', ), - 3: Field( - name='position_long', - type=BASE_TYPES[0x85], # sint32 + 3: Field( # Corresponds to file_id of scheduled workout / course. + name='time_created', + type=FIELD_TYPES['date_time'], def_num=3, - units='semicircles', ), - 4: Field( - name='distance', - type=BASE_TYPES[0x86], # uint32 + 4: Field( # TRUE if this activity has been started + name='completed', + type=FIELD_TYPES['bool'], def_num=4, - scale=100, - units='m', ), 5: Field( name='type', - type=FIELD_TYPES['course_point'], + type=FIELD_TYPES['schedule'], def_num=5, ), 6: Field( - name='name', - type=BASE_TYPES[0x07], # string + name='scheduled_time', + type=FIELD_TYPES['local_date_time'], def_num=6, ), - 8: Field( - name='favorite', - type=FIELD_TYPES['bool'], - def_num=8, - ), - 254: Field( - name='message_index', - type=FIELD_TYPES['message_index'], - def_num=254, - ), }, ), - 37: MessageType( - name='file_capabilities', - mesg_num=37, + 30: MessageType( + name='weight_scale', + mesg_num=30, fields={ 0: Field( - name='type', - type=FIELD_TYPES['file'], + name='weight', + type=FIELD_TYPES['weight'], def_num=0, + scale=100, + units='kg', ), 1: Field( - name='flags', - type=FIELD_TYPES['file_flags'], + name='percent_fat', + type=BASE_TYPES[0x84], # uint16 def_num=1, + scale=100, + units='%', ), 2: Field( - name='directory', - type=BASE_TYPES[0x07], # string + name='percent_hydration', + type=BASE_TYPES[0x84], # uint16 def_num=2, + scale=100, + units='%', ), 3: Field( - name='max_count', + name='visceral_fat_mass', type=BASE_TYPES[0x84], # uint16 def_num=3, + scale=100, + units='kg', ), 4: Field( - name='max_size', - type=BASE_TYPES[0x86], # uint32 + name='bone_mass', + type=BASE_TYPES[0x84], # uint16 def_num=4, - units='bytes', - ), - 254: Field( - name='message_index', + scale=100, + units='kg', + ), + 5: Field( + name='muscle_mass', + type=BASE_TYPES[0x84], # uint16 + def_num=5, + scale=100, + units='kg', + ), + 7: Field( + name='basal_met', + type=BASE_TYPES[0x84], # uint16 + def_num=7, + scale=4, + units='kcal/day', + ), + 8: Field( + name='physique_rating', + type=BASE_TYPES[0x02], # uint8 + def_num=8, + ), + 9: Field( # ~4kJ per kcal, 0.25 allows max 16384 kcal + name='active_met', + type=BASE_TYPES[0x84], # uint16 + def_num=9, + scale=4, + units='kcal/day', + ), + 10: Field( + name='metabolic_age', + type=BASE_TYPES[0x02], # uint8 + def_num=10, + units='years', + ), + 11: Field( + name='visceral_fat_rating', + type=BASE_TYPES[0x02], # uint8 + def_num=11, + ), + 12: Field( # Associates this weight scale message to a user. This corresponds to the index of the user profile message in the weight scale file. + name='user_profile_index', type=FIELD_TYPES['message_index'], - def_num=254, + def_num=12, ), + 253: FIELD_TYPE_TIMESTAMP, }, ), - 38: MessageType( - name='mesg_capabilities', - mesg_num=38, + 31: MessageType( + name='course', + mesg_num=31, fields={ - 0: Field( - name='file', - type=FIELD_TYPES['file'], - def_num=0, + 4: Field( + name='sport', + type=FIELD_TYPES['sport'], + def_num=4, + ), + 5: Field( + name='name', + type=BASE_TYPES[0x07], # string + def_num=5, + ), + 6: Field( + name='capabilities', + type=FIELD_TYPES['course_capabilities'], + def_num=6, + ), + 7: Field( + name='sub_sport', + type=FIELD_TYPES['sub_sport'], + def_num=7, ), + }, + ), + 32: MessageType( + name='course_point', + mesg_num=32, + fields={ 1: Field( - name='mesg_num', - type=FIELD_TYPES['mesg_num'], + name='timestamp', + type=FIELD_TYPES['date_time'], def_num=1, ), 2: Field( - name='count_type', - type=FIELD_TYPES['mesg_count'], + name='position_lat', + type=BASE_TYPES[0x85], # sint32 def_num=2, + units='semicircles', ), 3: Field( - name='count', - type=BASE_TYPES[0x84], # uint16 + name='position_long', + type=BASE_TYPES[0x85], # sint32 def_num=3, - subfields=( - SubField( - name='max_per_file', - def_num=3, - type=BASE_TYPES[0x84], # uint16 - ref_fields=( - ReferenceField( - name='count_type', - def_num=2, - value='max_per_file', - raw_value=1, - ), - ), - ), - SubField( - name='max_per_file_type', - def_num=3, - type=BASE_TYPES[0x84], # uint16 - ref_fields=( - ReferenceField( - name='count_type', - def_num=2, - value='max_per_file_type', - raw_value=2, - ), - ), - ), - SubField( - name='num_per_file', - def_num=3, - type=BASE_TYPES[0x84], # uint16 - ref_fields=( - ReferenceField( - name='count_type', - def_num=2, - value='num_per_file', - raw_value=0, - ), - ), - ), - ), + units='semicircles', + ), + 4: Field( + name='distance', + type=BASE_TYPES[0x86], # uint32 + def_num=4, + scale=100, + units='m', + ), + 5: Field( + name='type', + type=FIELD_TYPES['course_point'], + def_num=5, + ), + 6: Field( + name='name', + type=BASE_TYPES[0x07], # string + def_num=6, + ), + 8: Field( + name='favorite', + type=FIELD_TYPES['bool'], + def_num=8, ), 254: Field( name='message_index', @@ -7864,69 +9040,56 @@ ), }, ), - 39: MessageType( - name='field_capabilities', - mesg_num=39, + 33: MessageType( + name='totals', + mesg_num=33, fields={ - 0: Field( - name='file', - type=FIELD_TYPES['file'], + 0: Field( # Excludes pauses + name='timer_time', + type=BASE_TYPES[0x86], # uint32 def_num=0, + units='s', ), 1: Field( - name='mesg_num', - type=FIELD_TYPES['mesg_num'], + name='distance', + type=BASE_TYPES[0x86], # uint32 def_num=1, + units='m', ), 2: Field( - name='field_num', - type=BASE_TYPES[0x02], # uint8 + name='calories', + type=BASE_TYPES[0x86], # uint32 def_num=2, + units='kcal', ), 3: Field( - name='count', - type=BASE_TYPES[0x84], # uint16 + name='sport', + type=FIELD_TYPES['sport'], def_num=3, ), - 254: Field( - name='message_index', - type=FIELD_TYPES['message_index'], - def_num=254, + 4: Field( # Includes pauses + name='elapsed_time', + type=BASE_TYPES[0x86], # uint32 + def_num=4, + units='s', ), - }, - ), - 49: MessageType( - name='file_creator', - mesg_num=49, - fields={ - 0: Field( - name='software_version', + 5: Field( + name='sessions', type=BASE_TYPES[0x84], # uint16 - def_num=0, - ), - 1: Field( - name='hardware_version', - type=BASE_TYPES[0x02], # uint8 - def_num=1, + def_num=5, ), - }, - ), - 53: MessageType( - name='speed_zone', - mesg_num=53, - fields={ - 0: Field( - name='high_value', - type=BASE_TYPES[0x84], # uint16 - def_num=0, - scale=1000, - units='m/s', + 6: Field( + name='active_time', + type=BASE_TYPES[0x86], # uint32 + def_num=6, + units='s', ), - 1: Field( - name='name', - type=BASE_TYPES[0x07], # string - def_num=1, + 9: Field( + name='sport_index', + type=BASE_TYPES[0x02], # uint8 + def_num=9, ), + 253: FIELD_TYPE_TIMESTAMP, 254: Field( name='message_index', type=FIELD_TYPES['message_index'], @@ -7934,134 +9097,443 @@ ), }, ), - 55: MessageType( - name='monitoring', - mesg_num=55, + 34: MessageType( + name='activity', + mesg_num=34, fields={ - 0: Field( # Associates this data to device_info message. Not required for file with single device (sensor). - name='device_index', - type=FIELD_TYPES['device_index'], + 0: Field( # Exclude pauses + name='total_timer_time', + type=BASE_TYPES[0x86], # uint32 def_num=0, + scale=1000, + units='s', ), - 1: Field( # Accumulated total calories. Maintained by MonitoringReader for each activity_type. See SDK documentation - name='calories', + 1: Field( + name='num_sessions', type=BASE_TYPES[0x84], # uint16 def_num=1, - units='kcal', ), - 2: Field( # Accumulated distance. Maintained by MonitoringReader for each activity_type. See SDK documentation. - name='distance', - type=BASE_TYPES[0x86], # uint32 + 2: Field( + name='type', + type=FIELD_TYPES['activity'], def_num=2, + ), + 3: Field( + name='event', + type=FIELD_TYPES['event'], + def_num=3, + ), + 4: Field( + name='event_type', + type=FIELD_TYPES['event_type'], + def_num=4, + ), + 5: Field( # timestamp epoch expressed in local time, used to convert activity timestamps to local time + name='local_timestamp', + type=FIELD_TYPES['local_date_time'], + def_num=5, + ), + 6: Field( + name='event_group', + type=BASE_TYPES[0x02], # uint8 + def_num=6, + ), + 253: FIELD_TYPE_TIMESTAMP, + }, + ), + 35: MessageType( + name='software', + mesg_num=35, + fields={ + 3: Field( + name='version', + type=BASE_TYPES[0x84], # uint16 + def_num=3, scale=100, - units='m', ), - 3: Field( # Accumulated cycles. Maintained by MonitoringReader for each activity_type. See SDK documentation. - name='cycles', + 5: Field( + name='part_number', + type=BASE_TYPES[0x07], # string + def_num=5, + ), + 254: Field( + name='message_index', + type=FIELD_TYPES['message_index'], + def_num=254, + ), + }, + ), + 37: MessageType( + name='file_capabilities', + mesg_num=37, + fields={ + 0: Field( + name='type', + type=FIELD_TYPES['file'], + def_num=0, + ), + 1: Field( + name='flags', + type=FIELD_TYPES['file_flags'], + def_num=1, + ), + 2: Field( + name='directory', + type=BASE_TYPES[0x07], # string + def_num=2, + ), + 3: Field( + name='max_count', + type=BASE_TYPES[0x84], # uint16 + def_num=3, + ), + 4: Field( + name='max_size', type=BASE_TYPES[0x86], # uint32 + def_num=4, + units='bytes', + ), + 254: Field( + name='message_index', + type=FIELD_TYPES['message_index'], + def_num=254, + ), + }, + ), + 38: MessageType( + name='mesg_capabilities', + mesg_num=38, + fields={ + 0: Field( + name='file', + type=FIELD_TYPES['file'], + def_num=0, + ), + 1: Field( + name='mesg_num', + type=FIELD_TYPES['mesg_num'], + def_num=1, + ), + 2: Field( + name='count_type', + type=FIELD_TYPES['mesg_count'], + def_num=2, + ), + 3: Field( + name='count', + type=BASE_TYPES[0x84], # uint16 def_num=3, - scale=2, - units='cycles', subfields=( SubField( - name='steps', + name='max_per_file', def_num=3, - type=BASE_TYPES[0x86], # uint32 - units='steps', + type=BASE_TYPES[0x84], # uint16 ref_fields=( ReferenceField( - name='activity_type', - def_num=5, - value='walking', - raw_value=6, - ), - ReferenceField( - name='activity_type', - def_num=5, - value='running', + name='count_type', + def_num=2, + value='max_per_file', raw_value=1, ), ), ), SubField( - name='strokes', + name='max_per_file_type', def_num=3, - type=BASE_TYPES[0x86], # uint32 - scale=2, - units='strokes', + type=BASE_TYPES[0x84], # uint16 ref_fields=( ReferenceField( - name='activity_type', - def_num=5, - value='cycling', + name='count_type', + def_num=2, + value='max_per_file_type', raw_value=2, ), + ), + ), + SubField( + name='num_per_file', + def_num=3, + type=BASE_TYPES[0x84], # uint16 + ref_fields=( ReferenceField( - name='activity_type', - def_num=5, - value='swimming', - raw_value=5, + name='count_type', + def_num=2, + value='num_per_file', + raw_value=0, ), ), ), ), ), - 4: Field( - name='active_time', - type=BASE_TYPES[0x86], # uint32 - def_num=4, - scale=1000, - units='s', + 254: Field( + name='message_index', + type=FIELD_TYPES['message_index'], + def_num=254, ), - 5: Field( - name='activity_type', - type=FIELD_TYPES['activity_type'], - def_num=5, + }, + ), + 39: MessageType( + name='field_capabilities', + mesg_num=39, + fields={ + 0: Field( + name='file', + type=FIELD_TYPES['file'], + def_num=0, ), - 6: Field( - name='activity_subtype', - type=FIELD_TYPES['activity_subtype'], - def_num=6, + 1: Field( + name='mesg_num', + type=FIELD_TYPES['mesg_num'], + def_num=1, ), - 7: Field( - name='activity_level', - type=FIELD_TYPES['activity_level'], - def_num=7, + 2: Field( + name='field_num', + type=BASE_TYPES[0x02], # uint8 + def_num=2, ), - 8: Field( - name='distance_16', + 3: Field( + name='count', type=BASE_TYPES[0x84], # uint16 - def_num=8, - units='100*m', + def_num=3, ), - 9: Field( - name='cycles_16', - type=BASE_TYPES[0x84], # uint16 - def_num=9, - units='2*cycles or steps', + 254: Field( + name='message_index', + type=FIELD_TYPES['message_index'], + def_num=254, ), - 10: Field( - name='active_time_16', + }, + ), + 49: MessageType( + name='file_creator', + mesg_num=49, + fields={ + 0: Field( + name='software_version', type=BASE_TYPES[0x84], # uint16 - def_num=10, - units='s', + def_num=0, ), - 11: Field( # Must align to logging interval, for example, time must be 00:00:00 for daily log. - name='local_timestamp', - type=FIELD_TYPES['local_date_time'], - def_num=11, + 1: Field( + name='hardware_version', + type=BASE_TYPES[0x02], # uint8 + def_num=1, ), - 12: Field( # Avg temperature during the logging interval ended at timestamp - name='temperature', - type=BASE_TYPES[0x83], # sint16 - def_num=12, - scale=100, - units='C', + }, + ), + 51: MessageType( + name='blood_pressure', + mesg_num=51, + fields={ + 0: Field( + name='systolic_pressure', + type=BASE_TYPES[0x84], # uint16 + def_num=0, + units='mmHg', ), - 14: Field( # Min temperature during the logging interval ended at timestamp - name='temperature_min', - type=BASE_TYPES[0x83], # sint16 - def_num=14, + 1: Field( + name='diastolic_pressure', + type=BASE_TYPES[0x84], # uint16 + def_num=1, + units='mmHg', + ), + 2: Field( + name='mean_arterial_pressure', + type=BASE_TYPES[0x84], # uint16 + def_num=2, + units='mmHg', + ), + 3: Field( + name='map_3_sample_mean', + type=BASE_TYPES[0x84], # uint16 + def_num=3, + units='mmHg', + ), + 4: Field( + name='map_morning_values', + type=BASE_TYPES[0x84], # uint16 + def_num=4, + units='mmHg', + ), + 5: Field( + name='map_evening_values', + type=BASE_TYPES[0x84], # uint16 + def_num=5, + units='mmHg', + ), + 6: Field( + name='heart_rate', + type=BASE_TYPES[0x02], # uint8 + def_num=6, + units='bpm', + ), + 7: Field( + name='heart_rate_type', + type=FIELD_TYPES['hr_type'], + def_num=7, + ), + 8: Field( + name='status', + type=FIELD_TYPES['bp_status'], + def_num=8, + ), + 9: Field( # Associates this blood pressure message to a user. This corresponds to the index of the user profile message in the blood pressure file. + name='user_profile_index', + type=FIELD_TYPES['message_index'], + def_num=9, + ), + 253: FIELD_TYPE_TIMESTAMP, + }, + ), + 53: MessageType( + name='speed_zone', + mesg_num=53, + fields={ + 0: Field( + name='high_value', + type=BASE_TYPES[0x84], # uint16 + def_num=0, + scale=1000, + units='m/s', + ), + 1: Field( + name='name', + type=BASE_TYPES[0x07], # string + def_num=1, + ), + 254: Field( + name='message_index', + type=FIELD_TYPES['message_index'], + def_num=254, + ), + }, + ), + 55: MessageType( + name='monitoring', + mesg_num=55, + fields={ + 0: Field( # Associates this data to device_info message. Not required for file with single device (sensor). + name='device_index', + type=FIELD_TYPES['device_index'], + def_num=0, + ), + 1: Field( # Accumulated total calories. Maintained by MonitoringReader for each activity_type. See SDK documentation + name='calories', + type=BASE_TYPES[0x84], # uint16 + def_num=1, + units='kcal', + ), + 2: Field( # Accumulated distance. Maintained by MonitoringReader for each activity_type. See SDK documentation. + name='distance', + type=BASE_TYPES[0x86], # uint32 + def_num=2, + scale=100, + units='m', + ), + 3: Field( # Accumulated cycles. Maintained by MonitoringReader for each activity_type. See SDK documentation. + name='cycles', + type=BASE_TYPES[0x86], # uint32 + def_num=3, + scale=2, + units='cycles', + subfields=( + SubField( + name='steps', + def_num=3, + type=BASE_TYPES[0x86], # uint32 + units='steps', + ref_fields=( + ReferenceField( + name='activity_type', + def_num=5, + value='walking', + raw_value=6, + ), + ReferenceField( + name='activity_type', + def_num=5, + value='running', + raw_value=1, + ), + ), + ), + SubField( + name='strokes', + def_num=3, + type=BASE_TYPES[0x86], # uint32 + scale=2, + units='strokes', + ref_fields=( + ReferenceField( + name='activity_type', + def_num=5, + value='cycling', + raw_value=2, + ), + ReferenceField( + name='activity_type', + def_num=5, + value='swimming', + raw_value=5, + ), + ), + ), + ), + ), + 4: Field( + name='active_time', + type=BASE_TYPES[0x86], # uint32 + def_num=4, + scale=1000, + units='s', + ), + 5: Field( + name='activity_type', + type=FIELD_TYPES['activity_type'], + def_num=5, + ), + 6: Field( + name='activity_subtype', + type=FIELD_TYPES['activity_subtype'], + def_num=6, + ), + 7: Field( + name='activity_level', + type=FIELD_TYPES['activity_level'], + def_num=7, + ), + 8: Field( + name='distance_16', + type=BASE_TYPES[0x84], # uint16 + def_num=8, + units='100*m', + ), + 9: Field( + name='cycles_16', + type=BASE_TYPES[0x84], # uint16 + def_num=9, + units='2*cycles or steps', + ), + 10: Field( + name='active_time_16', + type=BASE_TYPES[0x84], # uint16 + def_num=10, + units='s', + ), + 11: Field( # Must align to logging interval, for example, time must be 00:00:00 for daily log. + name='local_timestamp', + type=FIELD_TYPES['local_date_time'], + def_num=11, + ), + 12: Field( # Avg temperature during the logging interval ended at timestamp + name='temperature', + type=BASE_TYPES[0x83], # sint16 + def_num=12, + scale=100, + units='C', + ), + 14: Field( # Min temperature during the logging interval ended at timestamp + name='temperature_min', + type=BASE_TYPES[0x83], # sint16 + def_num=14, scale=100, units='C', ), @@ -8189,6 +9661,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, @@ -8212,6 +9697,12 @@ value='dynastream_oem', raw_value=13, ), + ReferenceField( + name='manufacturer', + def_num=1, + value='tacx', + raw_value=89, + ), ), ), ), @@ -8575,6 +10066,44 @@ ), }, ), + 103: MessageType( + name='monitoring_info', + mesg_num=103, + fields={ + 0: Field( # Use to convert activity timestamps to local time if device does not support time zone and daylight savings time correction. + name='local_timestamp', + type=FIELD_TYPES['local_date_time'], + def_num=0, + units='s', + ), + 1: Field( + name='activity_type', + type=FIELD_TYPES['activity_type'], + def_num=1, + ), + 3: Field( # Indexed by activity_type + name='cycles_to_distance', + type=BASE_TYPES[0x84], # uint16 + def_num=3, + scale=5000, + units='m/cycle', + ), + 4: Field( # Indexed by activity_type + name='cycles_to_calories', + type=BASE_TYPES[0x84], # uint16 + def_num=4, + scale=5000, + units='kcal/cycle', + ), + 5: Field( + name='resting_metabolic_rate', + type=BASE_TYPES[0x84], # uint16 + def_num=5, + units='kcal/day', + ), + 253: FIELD_TYPE_TIMESTAMP, + }, + ), 106: MessageType( name='slave_device', mesg_num=106, @@ -8589,6 +10118,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, @@ -8612,6 +10154,12 @@ value='dynastream_oem', raw_value=13, ), + ReferenceField( + name='manufacturer', + def_num=0, + value='tacx', + raw_value=89, + ), ), ), SubField( @@ -9409,1547 +10957,474 @@ 63: Field( name='avg_combined_pedal_smoothness', type=BASE_TYPES[0x02], # uint8 - def_num=63, - scale=2, - units='percent', - ), - 64: Field( - name='status', - type=FIELD_TYPES['segment_lap_status'], - def_num=64, - ), - 65: Field( - name='uuid', - type=BASE_TYPES[0x07], # string - def_num=65, - ), - 66: Field( # fractional part of the avg_cadence - name='avg_fractional_cadence', - type=BASE_TYPES[0x02], # uint8 - def_num=66, - scale=128, - units='rpm', - ), - 67: Field( # fractional part of the max_cadence - name='max_fractional_cadence', - type=BASE_TYPES[0x02], # uint8 - def_num=67, - scale=128, - units='rpm', - ), - 68: Field( # fractional part of the total_cycles - name='total_fractional_cycles', - type=BASE_TYPES[0x02], # uint8 - def_num=68, - scale=128, - units='cycles', - ), - 69: Field( - name='front_gear_shift_count', - type=BASE_TYPES[0x84], # uint16 - def_num=69, - ), - 70: Field( - name='rear_gear_shift_count', - type=BASE_TYPES[0x84], # uint16 - def_num=70, - ), - 71: Field( # Total time spent in the standing position - name='time_standing', - type=BASE_TYPES[0x86], # uint32 - def_num=71, - scale=1000, - units='s', - ), - 72: Field( # Number of transitions to the standing state - name='stand_count', - type=BASE_TYPES[0x84], # uint16 - def_num=72, - ), - 73: Field( # Average left platform center offset - name='avg_left_pco', - type=BASE_TYPES[0x01], # sint8 - def_num=73, - units='mm', - ), - 74: Field( # Average right platform center offset - name='avg_right_pco', - type=BASE_TYPES[0x01], # sint8 - def_num=74, - units='mm', - ), - 75: Field( # Average left power phase angles. Data value indexes defined by power_phase_type. - name='avg_left_power_phase', - type=BASE_TYPES[0x02], # uint8 - def_num=75, - scale=0.7111111, - units='degrees', - ), - 76: Field( # Average left power phase peak angles. Data value indexes defined by power_phase_type. - name='avg_left_power_phase_peak', - type=BASE_TYPES[0x02], # uint8 - def_num=76, - scale=0.7111111, - units='degrees', - ), - 77: Field( # Average right power phase angles. Data value indexes defined by power_phase_type. - name='avg_right_power_phase', - type=BASE_TYPES[0x02], # uint8 - def_num=77, - scale=0.7111111, - units='degrees', - ), - 78: Field( # Average right power phase peak angles. Data value indexes defined by power_phase_type. - name='avg_right_power_phase_peak', - type=BASE_TYPES[0x02], # uint8 - def_num=78, - scale=0.7111111, - units='degrees', - ), - 79: Field( # Average power by position. Data value indexes defined by rider_position_type. - name='avg_power_position', - type=BASE_TYPES[0x84], # uint16 - def_num=79, - units='watts', - ), - 80: Field( # Maximum power by position. Data value indexes defined by rider_position_type. - name='max_power_position', - type=BASE_TYPES[0x84], # uint16 - def_num=80, - units='watts', - ), - 81: Field( # Average cadence by position. Data value indexes defined by rider_position_type. - name='avg_cadence_position', - type=BASE_TYPES[0x02], # uint8 - def_num=81, - units='rpm', - ), - 82: Field( # Maximum cadence by position. Data value indexes defined by rider_position_type. - name='max_cadence_position', - type=BASE_TYPES[0x02], # uint8 - def_num=82, - units='rpm', - ), - 83: Field( # Manufacturer that produced the segment - name='manufacturer', - type=FIELD_TYPES['manufacturer'], - def_num=83, - ), - 253: FIELD_TYPE_TIMESTAMP, # Lap end time. - 254: Field( - name='message_index', - type=FIELD_TYPES['message_index'], - def_num=254, - ), - }, - ), - 149: MessageType( # Unique Identification data for an individual segment leader within a segment file - name='segment_leaderboard_entry', - mesg_num=149, - fields={ - 0: Field( # Friendly name assigned to leader - name='name', - type=BASE_TYPES[0x07], # string - def_num=0, - ), - 1: Field( # Leader classification - name='type', - type=FIELD_TYPES['segment_leaderboard_type'], - def_num=1, - ), - 2: Field( # Primary user ID of this leader - name='group_primary_key', - type=BASE_TYPES[0x86], # uint32 - def_num=2, - ), - 3: Field( # ID of the activity associated with this leader time - name='activity_id', - type=BASE_TYPES[0x86], # uint32 - def_num=3, - ), - 4: Field( # Segment Time (includes pauses) - name='segment_time', - type=BASE_TYPES[0x86], # uint32 - def_num=4, - scale=1000, - units='s', - ), - 5: Field( # String version of the activity_id. 21 characters long, express in decimal - name='activity_id_string', - type=BASE_TYPES[0x07], # string - def_num=5, - ), - 254: Field( - name='message_index', - type=FIELD_TYPES['message_index'], - def_num=254, - ), - }, - ), - 150: MessageType( # Navigation and race evaluation point for a segment decribing a point along the segment path and time it took each segment leader to reach that point - name='segment_point', - mesg_num=150, - fields={ - 1: Field( - name='position_lat', - type=BASE_TYPES[0x85], # sint32 - def_num=1, - units='semicircles', - ), - 2: Field( - name='position_long', - type=BASE_TYPES[0x85], # sint32 - def_num=2, - units='semicircles', - ), - 3: Field( # Accumulated distance along the segment at the described point - name='distance', - type=BASE_TYPES[0x86], # uint32 - def_num=3, - scale=100, - units='m', - ), - 4: Field( # Accumulated altitude along the segment at the described point - name='altitude', - type=BASE_TYPES[0x84], # uint16 - def_num=4, - scale=5, - offset=500, - units='m', - ), - 5: Field( # Accumualted time each leader board member required to reach the described point. This value is zero for all leader board members at the starting point of the segment. - name='leader_time', - type=BASE_TYPES[0x86], # uint32 - def_num=5, - scale=1000, - units='s', - ), - 254: Field( - name='message_index', - type=FIELD_TYPES['message_index'], - def_num=254, - ), - }, - ), - 158: MessageType( - name='workout_session', - mesg_num=158, - fields={ - 0: Field( - name='sport', - type=FIELD_TYPES['sport'], - def_num=0, - ), - 1: Field( - name='sub_sport', - type=FIELD_TYPES['sub_sport'], - def_num=1, - ), - 2: Field( - name='num_valid_steps', - type=BASE_TYPES[0x84], # uint16 - def_num=2, - ), - 3: Field( - name='first_step_index', - type=BASE_TYPES[0x84], # uint16 - def_num=3, - ), - 4: Field( - name='pool_length', - type=BASE_TYPES[0x84], # uint16 - def_num=4, - scale=100, - units='m', - ), - 5: Field( - name='pool_length_unit', - type=FIELD_TYPES['display_measure'], - def_num=5, - ), - 254: Field( - name='message_index', - type=FIELD_TYPES['message_index'], - def_num=254, - ), - }, - ), - 159: MessageType( - name='watchface_settings', - mesg_num=159, - fields={ - 0: Field( - name='mode', - type=FIELD_TYPES['watchface_mode'], - def_num=0, - ), - 1: Field( - name='layout', - type=BASE_TYPES[0x0D], # byte - def_num=1, - subfields=( - SubField( - name='analog_layout', - def_num=1, - type=FIELD_TYPES['analog_watchface_layout'], - ref_fields=( - ReferenceField( - name='mode', - def_num=0, - value='analog', - raw_value=1, - ), - ), - ), - SubField( - name='digital_layout', - def_num=1, - type=FIELD_TYPES['digital_watchface_layout'], - ref_fields=( - ReferenceField( - name='mode', - def_num=0, - value='digital', - raw_value=0, - ), - ), - ), - ), - ), - 254: Field( - name='message_index', - type=FIELD_TYPES['message_index'], - def_num=254, - ), - }, - ), - 160: MessageType( - name='gps_metadata', - mesg_num=160, - fields={ - 0: Field( # Millisecond part of the timestamp. - name='timestamp_ms', - type=BASE_TYPES[0x84], # uint16 - def_num=0, - units='ms', - ), - 1: Field( - name='position_lat', - type=BASE_TYPES[0x85], # sint32 - def_num=1, - units='semicircles', - ), - 2: Field( - name='position_long', - type=BASE_TYPES[0x85], # sint32 - def_num=2, - units='semicircles', - ), - 3: Field( - name='enhanced_altitude', - type=BASE_TYPES[0x86], # uint32 - def_num=3, - scale=5, - offset=500, - units='m', - ), - 4: Field( - name='enhanced_speed', - type=BASE_TYPES[0x86], # uint32 - def_num=4, - scale=1000, - units='m/s', - ), - 5: Field( - name='heading', - type=BASE_TYPES[0x84], # uint16 - def_num=5, - scale=100, - units='degrees', - ), - 6: Field( # Used to correlate UTC to system time if the timestamp of the message is in system time. This UTC time is derived from the GPS data. - name='utc_timestamp', - type=FIELD_TYPES['date_time'], - def_num=6, - units='s', - ), - 7: Field( # velocity[0] is lon velocity. Velocity[1] is lat velocity. Velocity[2] is altitude velocity. - name='velocity', - type=BASE_TYPES[0x83], # sint16 - def_num=7, - scale=100, - units='m/s', - ), - 253: FIELD_TYPE_TIMESTAMP, # Whole second part of the timestamp. - }, - ), - 161: MessageType( - name='camera_event', - mesg_num=161, - fields={ - 0: Field( # Millisecond part of the timestamp. - name='timestamp_ms', - type=BASE_TYPES[0x84], # uint16 - def_num=0, - units='ms', - ), - 1: Field( - name='camera_event_type', - type=FIELD_TYPES['camera_event_type'], - def_num=1, - ), - 2: Field( - name='camera_file_uuid', - type=BASE_TYPES[0x07], # string - def_num=2, - ), - 3: Field( - name='camera_orientation', - type=FIELD_TYPES['camera_orientation_type'], - def_num=3, - ), - 253: FIELD_TYPE_TIMESTAMP, # Whole second part of the timestamp. - }, - ), - 162: MessageType( - name='timestamp_correlation', - mesg_num=162, - fields={ - 0: Field( # Fractional part of the UTC timestamp at the time the system timestamp was recorded. - name='fractional_timestamp', - type=BASE_TYPES[0x84], # uint16 - def_num=0, - scale=32768, - units='s', - ), - 1: Field( # Whole second part of the system timestamp - name='system_timestamp', - type=FIELD_TYPES['date_time'], - def_num=1, - units='s', - ), - 2: Field( # Fractional part of the system timestamp - name='fractional_system_timestamp', - type=BASE_TYPES[0x84], # uint16 - def_num=2, - scale=32768, - units='s', - ), - 3: Field( # timestamp epoch expressed in local time used to convert timestamps to local time - name='local_timestamp', - type=FIELD_TYPES['local_date_time'], - def_num=3, - units='s', - ), - 4: Field( # Millisecond part of the UTC timestamp at the time the system timestamp was recorded. - name='timestamp_ms', - type=BASE_TYPES[0x84], # uint16 - def_num=4, - units='ms', - ), - 5: Field( # Millisecond part of the system timestamp - name='system_timestamp_ms', - type=BASE_TYPES[0x84], # uint16 - def_num=5, - units='ms', - ), - 253: FIELD_TYPE_TIMESTAMP, # Whole second part of UTC timestamp at the time the system timestamp was recorded. - }, - ), - 164: MessageType( - name='gyroscope_data', - mesg_num=164, - fields={ - 0: Field( # Millisecond part of the timestamp. - name='timestamp_ms', - type=BASE_TYPES[0x84], # uint16 - def_num=0, - units='ms', - ), - 1: Field( # Each time in the array describes the time at which the gyro sample with the corrosponding index was taken. Limited to 30 samples in each message. The samples may span across seconds. Array size must match the number of samples in gyro_x and gyro_y and gyro_z - name='sample_time_offset', - type=BASE_TYPES[0x84], # uint16 - def_num=1, - units='ms', - ), - 2: Field( # These are the raw ADC reading. Maximum number of samples is 30 in each message. The samples may span across seconds. A conversion will need to be done on this data once read. - name='gyro_x', - type=BASE_TYPES[0x84], # uint16 - def_num=2, - units='counts', - ), - 3: Field( # These are the raw ADC reading. Maximum number of samples is 30 in each message. The samples may span across seconds. A conversion will need to be done on this data once read. - name='gyro_y', - type=BASE_TYPES[0x84], # uint16 - def_num=3, - units='counts', - ), - 4: Field( # These are the raw ADC reading. Maximum number of samples is 30 in each message. The samples may span across seconds. A conversion will need to be done on this data once read. - name='gyro_z', - type=BASE_TYPES[0x84], # uint16 - def_num=4, - units='counts', - ), - 5: Field( # Calibrated gyro reading - name='calibrated_gyro_x', - type=BASE_TYPES[0x88], # float32 - def_num=5, - units='deg/s', - ), - 6: Field( # Calibrated gyro reading - name='calibrated_gyro_y', - type=BASE_TYPES[0x88], # float32 - def_num=6, - units='deg/s', - ), - 7: Field( # Calibrated gyro reading - name='calibrated_gyro_z', - type=BASE_TYPES[0x88], # float32 - def_num=7, - units='deg/s', - ), - 253: FIELD_TYPE_TIMESTAMP, # Whole second part of the timestamp - }, - ), - 165: MessageType( - name='accelerometer_data', - mesg_num=165, - fields={ - 0: Field( # Millisecond part of the timestamp. - name='timestamp_ms', - type=BASE_TYPES[0x84], # uint16 - def_num=0, - units='ms', - ), - 1: Field( # Each time in the array describes the time at which the accelerometer sample with the corrosponding index was taken. Limited to 30 samples in each message. The samples may span across seconds. Array size must match the number of samples in accel_x and accel_y and accel_z - name='sample_time_offset', - type=BASE_TYPES[0x84], # uint16 - def_num=1, - units='ms', - ), - 2: Field( # These are the raw ADC reading. Maximum number of samples is 30 in each message. The samples may span across seconds. A conversion will need to be done on this data once read. - name='accel_x', - type=BASE_TYPES[0x84], # uint16 - def_num=2, - units='counts', - ), - 3: Field( # These are the raw ADC reading. Maximum number of samples is 30 in each message. The samples may span across seconds. A conversion will need to be done on this data once read. - name='accel_y', - type=BASE_TYPES[0x84], # uint16 - def_num=3, - units='counts', - ), - 4: Field( # These are the raw ADC reading. Maximum number of samples is 30 in each message. The samples may span across seconds. A conversion will need to be done on this data once read. - name='accel_z', - type=BASE_TYPES[0x84], # uint16 - def_num=4, - units='counts', - ), - 5: Field( # Calibrated accel reading - name='calibrated_accel_x', - type=BASE_TYPES[0x88], # float32 - def_num=5, - units='g', - ), - 6: Field( # Calibrated accel reading - name='calibrated_accel_y', - type=BASE_TYPES[0x88], # float32 - def_num=6, - units='g', - ), - 7: Field( # Calibrated accel reading - name='calibrated_accel_z', - type=BASE_TYPES[0x88], # float32 - def_num=7, - units='g', - ), - 8: Field( # Calibrated accel reading - name='compressed_calibrated_accel_x', - type=BASE_TYPES[0x83], # sint16 - def_num=8, - units='mG', - ), - 9: Field( # Calibrated accel reading - name='compressed_calibrated_accel_y', - type=BASE_TYPES[0x83], # sint16 - def_num=9, - units='mG', - ), - 10: Field( # Calibrated accel reading - name='compressed_calibrated_accel_z', - type=BASE_TYPES[0x83], # sint16 - def_num=10, - units='mG', - ), - 253: FIELD_TYPE_TIMESTAMP, # Whole second part of the timestamp - }, - ), - 167: MessageType( - name='three_d_sensor_calibration', - mesg_num=167, - fields={ - 0: Field( # Indicates which sensor the calibration is for - name='sensor_type', - type=FIELD_TYPES['sensor_type'], - def_num=0, - ), - 1: Field( # Calibration factor used to convert from raw ADC value to degrees, g, etc. - name='calibration_factor', - type=BASE_TYPES[0x86], # uint32 - def_num=1, - subfields=( - SubField( # Accelerometer calibration factor - name='accel_cal_factor', - def_num=1, - type=BASE_TYPES[0x86], # uint32 - units='g', - ref_fields=( - ReferenceField( - name='sensor_type', - def_num=0, - value='accelerometer', - raw_value=0, - ), - ), - ), - SubField( # Gyro calibration factor - name='gyro_cal_factor', - def_num=1, - type=BASE_TYPES[0x86], # uint32 - units='deg/s', - ref_fields=( - ReferenceField( - name='sensor_type', - def_num=0, - value='gyroscope', - raw_value=1, - ), - ), - ), - ), - ), - 2: Field( # Calibration factor divisor - name='calibration_divisor', - type=BASE_TYPES[0x86], # uint32 - def_num=2, - units='counts', - ), - 3: Field( # Level shift value used to shift the ADC value back into range - name='level_shift', - type=BASE_TYPES[0x86], # uint32 - def_num=3, - ), - 4: Field( # Internal calibration factors, one for each: xy, yx, zx - name='offset_cal', - type=BASE_TYPES[0x85], # sint32 - def_num=4, - ), - 5: Field( # 3 x 3 rotation matrix (row major) - name='orientation_matrix', - type=BASE_TYPES[0x85], # sint32 - def_num=5, - scale=65535, - ), - 253: FIELD_TYPE_TIMESTAMP, # Whole second part of the timestamp - }, - ), - 169: MessageType( - name='video_frame', - mesg_num=169, - fields={ - 0: Field( # Millisecond part of the timestamp. - name='timestamp_ms', - type=BASE_TYPES[0x84], # uint16 - def_num=0, - units='ms', - ), - 1: Field( # Number of the frame that the timestamp and timestamp_ms correlate to - name='frame_number', - type=BASE_TYPES[0x86], # uint32 - def_num=1, - ), - 253: FIELD_TYPE_TIMESTAMP, # Whole second part of the timestamp - }, - ), - 174: MessageType( - name='obdii_data', - mesg_num=174, - fields={ - 0: Field( # Fractional part of timestamp, added to timestamp - name='timestamp_ms', - type=BASE_TYPES[0x84], # uint16 - def_num=0, - units='ms', - ), - 1: Field( # Offset of PID reading [i] from start_timestamp+start_timestamp_ms. Readings may span accross seconds. - name='time_offset', - type=BASE_TYPES[0x84], # uint16 - def_num=1, - units='ms', - ), - 2: Field( # Parameter ID - name='pid', - type=BASE_TYPES[0x0D], # byte - def_num=2, - ), - 3: Field( # Raw parameter data - name='raw_data', - type=BASE_TYPES[0x0D], # byte - def_num=3, - ), - 4: Field( # Optional, data size of PID[i]. If not specified refer to SAE J1979. - name='pid_data_size', - type=BASE_TYPES[0x02], # uint8 - def_num=4, - ), - 5: Field( # System time associated with sample expressed in ms, can be used instead of time_offset. There will be a system_time value for each raw_data element. For multibyte pids the system_time is repeated. - name='system_time', - type=BASE_TYPES[0x86], # uint32 - def_num=5, - ), - 6: Field( # Timestamp of first sample recorded in the message. Used with time_offset to generate time of each sample - name='start_timestamp', - type=FIELD_TYPES['date_time'], - def_num=6, - ), - 7: Field( # Fractional part of start_timestamp - name='start_timestamp_ms', - type=BASE_TYPES[0x84], # uint16 - def_num=7, - units='ms', - ), - 253: FIELD_TYPE_TIMESTAMP, # Timestamp message was output - }, - ), - 177: MessageType( - name='nmea_sentence', - mesg_num=177, - fields={ - 0: Field( # Fractional part of timestamp, added to timestamp - name='timestamp_ms', - type=BASE_TYPES[0x84], # uint16 - def_num=0, - units='ms', - ), - 1: Field( # NMEA sentence - name='sentence', - type=BASE_TYPES[0x07], # string - def_num=1, - ), - 253: FIELD_TYPE_TIMESTAMP, # Timestamp message was output - }, - ), - 178: MessageType( - name='aviation_attitude', - mesg_num=178, - fields={ - 0: Field( # Fractional part of timestamp, added to timestamp - name='timestamp_ms', - type=BASE_TYPES[0x84], # uint16 - def_num=0, - units='ms', - ), - 1: Field( # System time associated with sample expressed in ms. - name='system_time', - type=BASE_TYPES[0x86], # uint32 - def_num=1, - units='ms', - ), - 2: Field( # Range -PI/2 to +PI/2 - name='pitch', - type=BASE_TYPES[0x83], # sint16 - def_num=2, - scale=10430.38, - units='radians', - ), - 3: Field( # Range -PI to +PI - name='roll', - type=BASE_TYPES[0x83], # sint16 - def_num=3, - scale=10430.38, - units='radians', - ), - 4: Field( # Range -78.4 to +78.4 (-8 Gs to 8 Gs) - name='accel_lateral', - type=BASE_TYPES[0x83], # sint16 - def_num=4, - scale=100, - units='m/s^2', - ), - 5: Field( # Range -78.4 to +78.4 (-8 Gs to 8 Gs) - name='accel_normal', - type=BASE_TYPES[0x83], # sint16 - def_num=5, - scale=100, - units='m/s^2', - ), - 6: Field( # Range -8.727 to +8.727 (-500 degs/sec to +500 degs/sec) - name='turn_rate', - type=BASE_TYPES[0x83], # sint16 - def_num=6, - scale=1024, - units='radians/second', - ), - 7: Field( - name='stage', - type=FIELD_TYPES['attitude_stage'], - def_num=7, - ), - 8: Field( # The percent complete of the current attitude stage. Set to 0 for attitude stages 0, 1 and 2 and to 100 for attitude stage 3 by AHRS modules that do not support it. Range - 100 - name='attitude_stage_complete', - type=BASE_TYPES[0x02], # uint8 - def_num=8, - units='%', - ), - 9: Field( # Track Angle/Heading Range 0 - 2pi - name='track', - type=BASE_TYPES[0x84], # uint16 - def_num=9, - scale=10430.38, - units='radians', - ), - 10: Field( - name='validity', - type=FIELD_TYPES['attitude_validity'], - def_num=10, - ), - 253: FIELD_TYPE_TIMESTAMP, # Timestamp message was output - }, - ), - 184: MessageType( - name='video', - mesg_num=184, - fields={ - 0: Field( - name='url', - type=BASE_TYPES[0x07], # string - def_num=0, - ), - 1: Field( - name='hosting_provider', - type=BASE_TYPES[0x07], # string - def_num=1, - ), - 2: Field( # Playback time of video - name='duration', - type=BASE_TYPES[0x86], # uint32 - def_num=2, - units='ms', - ), - }, - ), - 185: MessageType( - name='video_title', - mesg_num=185, - fields={ - 0: Field( # Total number of title parts - name='message_count', - type=BASE_TYPES[0x84], # uint16 - def_num=0, - ), - 1: Field( - name='text', - type=BASE_TYPES[0x07], # string - def_num=1, - ), - 254: Field( # Long titles will be split into multiple parts - name='message_index', - type=FIELD_TYPES['message_index'], - def_num=254, - ), - }, - ), - 186: MessageType( - name='video_description', - mesg_num=186, - fields={ - 0: Field( # Total number of description parts - name='message_count', - type=BASE_TYPES[0x84], # uint16 - def_num=0, - ), - 1: Field( - name='text', - type=BASE_TYPES[0x07], # string - def_num=1, - ), - 254: Field( # Long descriptions will be split into multiple parts - name='message_index', - type=FIELD_TYPES['message_index'], - def_num=254, - ), - }, - ), - 187: MessageType( - name='video_clip', - mesg_num=187, - fields={ - 0: Field( - name='clip_number', - type=BASE_TYPES[0x84], # uint16 - def_num=0, - ), - 1: Field( - name='start_timestamp', - type=FIELD_TYPES['date_time'], - def_num=1, - ), - 2: Field( - name='start_timestamp_ms', - type=BASE_TYPES[0x84], # uint16 - def_num=2, - ), - 3: Field( - name='end_timestamp', - type=FIELD_TYPES['date_time'], - def_num=3, - ), - 4: Field( - name='end_timestamp_ms', - type=BASE_TYPES[0x84], # uint16 - def_num=4, - ), - 6: Field( # Start of clip in video time - name='clip_start', - type=BASE_TYPES[0x86], # uint32 - def_num=6, - units='ms', - ), - 7: Field( # End of clip in video time - name='clip_end', - type=BASE_TYPES[0x86], # uint32 - def_num=7, - units='ms', - ), - }, - ), - 188: MessageType( - name='ohr_settings', - mesg_num=188, - fields={ - 0: Field( - name='enabled', - type=FIELD_TYPES['switch'], - def_num=0, - ), - }, - ), - 200: MessageType( - name='exd_screen_configuration', - mesg_num=200, - fields={ - 0: Field( - name='screen_index', - type=BASE_TYPES[0x02], # uint8 - def_num=0, - ), - 1: Field( # number of fields in screen - name='field_count', - type=BASE_TYPES[0x02], # uint8 - def_num=1, - ), - 2: Field( - name='layout', - type=FIELD_TYPES['exd_layout'], - def_num=2, - ), - 3: Field( - name='screen_enabled', - type=FIELD_TYPES['bool'], - def_num=3, - ), - }, - ), - 201: MessageType( - name='exd_data_field_configuration', - mesg_num=201, - fields={ - 0: Field( - name='screen_index', - type=BASE_TYPES[0x02], # uint8 - def_num=0, - ), - 1: Field( - name='concept_field', - type=BASE_TYPES[0x0D], # byte - def_num=1, - components=( - ComponentField( - name='field_id', - def_num=2, - accumulate=False, - bits=4, - bit_offset=0, - ), - ComponentField( - name='concept_count', - def_num=3, - accumulate=False, - bits=4, - bit_offset=4, - ), - ), - ), - 2: Field( - name='field_id', - type=BASE_TYPES[0x02], # uint8 - def_num=2, - ), - 3: Field( - name='concept_count', - type=BASE_TYPES[0x02], # uint8 - def_num=3, - ), - 4: Field( - name='display_type', - type=FIELD_TYPES['exd_display_type'], - def_num=4, - ), - 5: Field( - name='title', - type=BASE_TYPES[0x07], # string - def_num=5, - ), - }, - ), - 202: MessageType( - name='exd_data_concept_configuration', - mesg_num=202, - fields={ - 0: Field( - name='screen_index', - type=BASE_TYPES[0x02], # uint8 - def_num=0, - ), - 1: Field( - name='concept_field', - type=BASE_TYPES[0x0D], # byte - def_num=1, - components=( - ComponentField( - name='field_id', - def_num=2, - accumulate=False, - bits=4, - bit_offset=0, - ), - ComponentField( - name='concept_index', - def_num=3, - accumulate=False, - bits=4, - bit_offset=4, - ), - ), - ), - 2: Field( - name='field_id', - type=BASE_TYPES[0x02], # uint8 - def_num=2, - ), - 3: Field( - name='concept_index', - type=BASE_TYPES[0x02], # uint8 - def_num=3, - ), - 4: Field( - name='data_page', - type=BASE_TYPES[0x02], # uint8 - def_num=4, - ), - 5: Field( - name='concept_key', - type=BASE_TYPES[0x02], # uint8 - def_num=5, - ), - 6: Field( - name='scaling', - type=BASE_TYPES[0x02], # uint8 - def_num=6, - ), - 8: Field( - name='data_units', - type=FIELD_TYPES['exd_data_units'], - def_num=8, - ), - 9: Field( - name='qualifier', - type=FIELD_TYPES['exd_qualifiers'], - def_num=9, - ), - 10: Field( - name='descriptor', - type=FIELD_TYPES['exd_descriptors'], - def_num=10, - ), - 11: Field( - name='is_signed', - type=FIELD_TYPES['bool'], - def_num=11, - ), - }, - ), - 206: MessageType( # Must be logged before developer field is used - name='field_description', - mesg_num=206, - fields={ - 0: Field( - name='developer_data_index', - type=BASE_TYPES[0x02], # uint8 - def_num=0, - ), - 1: Field( - name='field_definition_number', - type=BASE_TYPES[0x02], # uint8 - def_num=1, + def_num=63, + scale=2, + units='percent', ), - 2: Field( - name='fit_base_type_id', - type=FIELD_TYPES['fit_base_type'], - def_num=2, + 64: Field( + name='status', + type=FIELD_TYPES['segment_lap_status'], + def_num=64, ), - 3: Field( - name='field_name', + 65: Field( + name='uuid', type=BASE_TYPES[0x07], # string - def_num=3, + def_num=65, ), - 4: Field( - name='array', + 66: Field( # fractional part of the avg_cadence + name='avg_fractional_cadence', type=BASE_TYPES[0x02], # uint8 - def_num=4, + def_num=66, + scale=128, + units='rpm', ), - 5: Field( - name='components', - type=BASE_TYPES[0x07], # string - def_num=5, + 67: Field( # fractional part of the max_cadence + name='max_fractional_cadence', + type=BASE_TYPES[0x02], # uint8 + def_num=67, + scale=128, + units='rpm', ), - 6: Field( - name='scale', + 68: Field( # fractional part of the total_cycles + name='total_fractional_cycles', type=BASE_TYPES[0x02], # uint8 - def_num=6, + def_num=68, + scale=128, + units='cycles', ), - 7: Field( - name='offset', - type=BASE_TYPES[0x01], # sint8 - def_num=7, + 69: Field( + name='front_gear_shift_count', + type=BASE_TYPES[0x84], # uint16 + def_num=69, ), - 8: Field( - name='units', - type=BASE_TYPES[0x07], # string - def_num=8, + 70: Field( + name='rear_gear_shift_count', + type=BASE_TYPES[0x84], # uint16 + def_num=70, ), - 9: Field( - name='bits', - type=BASE_TYPES[0x07], # string - def_num=9, + 71: Field( # Total time spent in the standing position + name='time_standing', + type=BASE_TYPES[0x86], # uint32 + def_num=71, + scale=1000, + units='s', ), - 10: Field( - name='accumulate', - type=BASE_TYPES[0x07], # string - def_num=10, + 72: Field( # Number of transitions to the standing state + name='stand_count', + type=BASE_TYPES[0x84], # uint16 + def_num=72, ), - 13: Field( - name='fit_base_unit_id', - type=FIELD_TYPES['fit_base_unit'], - def_num=13, + 73: Field( # Average left platform center offset + name='avg_left_pco', + type=BASE_TYPES[0x01], # sint8 + def_num=73, + units='mm', ), - 14: Field( - name='native_mesg_num', - type=FIELD_TYPES['mesg_num'], - def_num=14, + 74: Field( # Average right platform center offset + name='avg_right_pco', + type=BASE_TYPES[0x01], # sint8 + def_num=74, + units='mm', ), - 15: Field( - name='native_field_num', + 75: Field( # Average left power phase angles. Data value indexes defined by power_phase_type. + name='avg_left_power_phase', type=BASE_TYPES[0x02], # uint8 - def_num=15, - ), - }, - ), - 207: MessageType( # Must be logged before field description - name='developer_data_id', - mesg_num=207, - fields={ - 0: Field( - name='developer_id', - type=BASE_TYPES[0x0D], # byte - def_num=0, - ), - 1: Field( - name='application_id', - type=BASE_TYPES[0x0D], # byte - def_num=1, + def_num=75, + scale=0.7111111, + units='degrees', ), - 2: Field( - name='manufacturer_id', - type=FIELD_TYPES['manufacturer'], - def_num=2, + 76: Field( # Average left power phase peak angles. Data value indexes defined by power_phase_type. + name='avg_left_power_phase_peak', + type=BASE_TYPES[0x02], # uint8 + def_num=76, + scale=0.7111111, + units='degrees', ), - 3: Field( - name='developer_data_index', + 77: Field( # Average right power phase angles. Data value indexes defined by power_phase_type. + name='avg_right_power_phase', type=BASE_TYPES[0x02], # uint8 - def_num=3, + def_num=77, + scale=0.7111111, + units='degrees', ), - 4: Field( - name='application_version', - type=BASE_TYPES[0x86], # uint32 - def_num=4, + 78: Field( # Average right power phase peak angles. Data value indexes defined by power_phase_type. + name='avg_right_power_phase_peak', + type=BASE_TYPES[0x02], # uint8 + def_num=78, + scale=0.7111111, + units='degrees', ), - }, - ), - 208: MessageType( - name='magnetometer_data', - mesg_num=208, - fields={ - 0: Field( # Millisecond part of the timestamp. - name='timestamp_ms', + 79: Field( # Average power by position. Data value indexes defined by rider_position_type. + name='avg_power_position', type=BASE_TYPES[0x84], # uint16 - def_num=0, - units='ms', + def_num=79, + units='watts', ), - 1: Field( # Each time in the array describes the time at which the compass sample with the corrosponding index was taken. Limited to 30 samples in each message. The samples may span across seconds. Array size must match the number of samples in cmps_x and cmps_y and cmps_z - name='sample_time_offset', + 80: Field( # Maximum power by position. Data value indexes defined by rider_position_type. + name='max_power_position', type=BASE_TYPES[0x84], # uint16 - def_num=1, - units='ms', + def_num=80, + units='watts', ), - 2: Field( # These are the raw ADC reading. Maximum number of samples is 30 in each message. The samples may span across seconds. A conversion will need to be done on this data once read. - name='mag_x', - type=BASE_TYPES[0x84], # uint16 - def_num=2, - units='counts', + 81: Field( # Average cadence by position. Data value indexes defined by rider_position_type. + name='avg_cadence_position', + type=BASE_TYPES[0x02], # uint8 + def_num=81, + units='rpm', ), - 3: Field( # These are the raw ADC reading. Maximum number of samples is 30 in each message. The samples may span across seconds. A conversion will need to be done on this data once read. - name='mag_y', - type=BASE_TYPES[0x84], # uint16 - def_num=3, - units='counts', + 82: Field( # Maximum cadence by position. Data value indexes defined by rider_position_type. + name='max_cadence_position', + type=BASE_TYPES[0x02], # uint8 + def_num=82, + units='rpm', ), - 4: Field( # These are the raw ADC reading. Maximum number of samples is 30 in each message. The samples may span across seconds. A conversion will need to be done on this data once read. - name='mag_z', - type=BASE_TYPES[0x84], # uint16 - def_num=4, - units='counts', + 83: Field( # Manufacturer that produced the segment + name='manufacturer', + type=FIELD_TYPES['manufacturer'], + def_num=83, ), - 5: Field( # Calibrated Magnetometer reading - name='calibrated_mag_x', + 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=5, - units='G', + def_num=84, + units='kGrit', ), - 6: Field( # Calibrated Magnetometer reading - name='calibrated_mag_y', + 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=6, - units='G', + def_num=85, + units='Flow', ), - 7: Field( # Calibrated Magnetometer reading - name='calibrated_mag_z', + 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=7, - units='G', + def_num=86, + units='kGrit', ), - 253: FIELD_TYPE_TIMESTAMP, # Whole second part of the timestamp - }, - ), - 209: MessageType( - name='barometer_data', - mesg_num=209, - fields={ - 0: Field( # Millisecond part of the timestamp. - name='timestamp_ms', - type=BASE_TYPES[0x84], # uint16 - def_num=0, - units='ms', + 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', ), - 1: Field( # Each time in the array describes the time at which the barometer sample with the corrosponding index was taken. The samples may span across seconds. Array size must match the number of samples in baro_cal - name='sample_time_offset', - type=BASE_TYPES[0x84], # uint16 - def_num=1, - units='ms', + 89: Field( # fractional part of total_ascent + name='total_fractional_ascent', + type=BASE_TYPES[0x02], # uint8 + def_num=89, + scale=100, + units='m', ), - 2: Field( # These are the raw ADC reading. The samples may span across seconds. A conversion will need to be done on this data once read. - name='baro_pres', - type=BASE_TYPES[0x86], # uint32 - def_num=2, - units='Pa', + 90: Field( # fractional part of total_descent + name='total_fractional_descent', + type=BASE_TYPES[0x02], # uint8 + def_num=90, + scale=100, + units='m', + ), + 253: FIELD_TYPE_TIMESTAMP, # Lap end time. + 254: Field( + name='message_index', + type=FIELD_TYPES['message_index'], + def_num=254, ), - 253: FIELD_TYPE_TIMESTAMP, # Whole second part of the timestamp }, - ), - 210: MessageType( - name='one_d_sensor_calibration', - mesg_num=210, + ), + 145: MessageType( + name='memo_glob', + mesg_num=145, fields={ - 0: Field( # Indicates which sensor the calibration is for - name='sensor_type', - type=FIELD_TYPES['sensor_type'], + 0: Field( # Block of utf8 bytes + name='memo', + type=BASE_TYPES[0x0D], # byte def_num=0, ), - 1: Field( # Calibration factor used to convert from raw ADC value to degrees, g, etc. - name='calibration_factor', - type=BASE_TYPES[0x86], # uint32 + 1: Field( # Allows relating glob to another mesg If used only required for first part of each memo_glob + name='message_number', + type=BASE_TYPES[0x84], # uint16 def_num=1, - subfields=( - SubField( # Barometer calibration factor - name='baro_cal_factor', - def_num=1, - type=BASE_TYPES[0x86], # uint32 - units='Pa', - ref_fields=( - ReferenceField( - name='sensor_type', - def_num=0, - value='barometer', - raw_value=3, - ), - ), - ), - ), ), - 2: Field( # Calibration factor divisor - name='calibration_divisor', - type=BASE_TYPES[0x86], # uint32 + 2: Field( # Index of external mesg + name='message_index', + type=FIELD_TYPES['message_index'], def_num=2, - units='counts', ), - 3: Field( # Level shift value used to shift the ADC value back into range - name='level_shift', + 250: Field( # Sequence number of memo blocks + name='part_index', type=BASE_TYPES[0x86], # uint32 - def_num=3, - ), - 4: Field( # Internal Calibration factor - name='offset_cal', - type=BASE_TYPES[0x85], # sint32 - def_num=4, + def_num=250, ), - 253: FIELD_TYPE_TIMESTAMP, # Whole second part of the timestamp }, ), - 225: MessageType( - name='set', - mesg_num=225, + 148: MessageType( # Unique Identification data for a segment file + name='segment_id', + mesg_num=148, fields={ - 0: Field( - name='duration', - type=BASE_TYPES[0x86], # uint32 + 0: Field( # Friendly name assigned to segment + name='name', + type=BASE_TYPES[0x07], # string def_num=0, - scale=1000, - units='s', ), - 3: Field( # # of repitions of the movement - name='repetitions', - type=BASE_TYPES[0x84], # uint16 + 1: Field( # UUID of the segment + name='uuid', + type=BASE_TYPES[0x07], # string + def_num=1, + ), + 2: Field( # Sport associated with the segment + name='sport', + type=FIELD_TYPES['sport'], + def_num=2, + ), + 3: Field( # Segment enabled for evaluation + name='enabled', + type=FIELD_TYPES['bool'], def_num=3, ), - 4: Field( # Amount of weight applied for the set - name='weight', - type=BASE_TYPES[0x84], # uint16 + 4: Field( # Primary key of the user that created the segment + name='user_profile_primary_key', + type=BASE_TYPES[0x86], # uint32 def_num=4, - scale=16, - units='kg', ), - 5: Field( - name='set_type', - type=FIELD_TYPES['set_type'], + 5: Field( # ID of the device that created the segment + name='device_id', + type=BASE_TYPES[0x86], # uint32 def_num=5, ), - 6: Field( # Start time of the set - name='start_time', - type=FIELD_TYPES['date_time'], + 6: Field( # Index for the Leader Board entry selected as the default race participant + name='default_race_leader', + type=BASE_TYPES[0x02], # uint8 def_num=6, ), - 7: Field( - name='category', - type=FIELD_TYPES['exercise_category'], + 7: Field( # Indicates if any segments should be deleted + name='delete_status', + type=FIELD_TYPES['segment_delete_status'], def_num=7, ), - 8: Field( # Based on the associated category, see [category]_exercise_names - name='category_subtype', - type=BASE_TYPES[0x84], # uint16 + 8: Field( # Indicates how the segment was selected to be sent to the device + name='selection_type', + type=FIELD_TYPES['segment_selection_type'], def_num=8, ), - 9: Field( - name='weight_display_unit', - type=FIELD_TYPES['fit_base_unit'], - def_num=9, - ), - 10: Field( - name='message_index', - type=FIELD_TYPES['message_index'], - def_num=10, - ), - 11: Field( - name='wkt_step_index', - type=FIELD_TYPES['message_index'], - def_num=11, - ), - 254: Field( # Timestamp of the set - name='timestamp', - type=FIELD_TYPES['date_time'], - def_num=254, - ), }, ), - 227: MessageType( # Value from 1 to 100 calculated by FirstBeat - name='stress_level', - mesg_num=227, + 149: MessageType( # Unique Identification data for an individual segment leader within a segment file + name='segment_leaderboard_entry', + mesg_num=149, fields={ - 0: Field( - name='stress_level_value', - type=BASE_TYPES[0x83], # sint16 + 0: Field( # Friendly name assigned to leader + name='name', + type=BASE_TYPES[0x07], # string def_num=0, ), - 1: Field( # Time stress score was calculated - name='stress_level_time', - type=FIELD_TYPES['date_time'], + 1: Field( # Leader classification + name='type', + type=FIELD_TYPES['segment_leaderboard_type'], def_num=1, + ), + 2: Field( # Primary user ID of this leader + name='group_primary_key', + type=BASE_TYPES[0x86], # uint32 + def_num=2, + ), + 3: Field( # ID of the activity associated with this leader time + name='activity_id', + type=BASE_TYPES[0x86], # uint32 + def_num=3, + ), + 4: Field( # Segment Time (includes pauses) + name='segment_time', + type=BASE_TYPES[0x86], # uint32 + def_num=4, + scale=1000, units='s', ), + 5: Field( # String version of the activity_id. 21 characters long, express in decimal + name='activity_id_string', + type=BASE_TYPES[0x07], # string + def_num=5, + ), + 254: Field( + name='message_index', + type=FIELD_TYPES['message_index'], + def_num=254, + ), }, ), - 258: MessageType( - name='dive_settings', - mesg_num=258, + 150: MessageType( # Navigation and race evaluation point for a segment decribing a point along the segment path and time it took each segment leader to reach that point + name='segment_point', + mesg_num=150, fields={ - 0: Field( - name='name', - type=BASE_TYPES[0x07], # string - def_num=0, - ), 1: Field( - name='model', - type=FIELD_TYPES['tissue_model_type'], + name='position_lat', + type=BASE_TYPES[0x85], # sint32 def_num=1, + units='semicircles', ), 2: Field( - name='gf_low', - type=BASE_TYPES[0x02], # uint8 + name='position_long', + type=BASE_TYPES[0x85], # sint32 def_num=2, - units='percent', + units='semicircles', ), - 3: Field( - name='gf_high', - type=BASE_TYPES[0x02], # uint8 + 3: Field( # Accumulated distance along the segment at the described point + name='distance', + type=BASE_TYPES[0x86], # uint32 def_num=3, - units='percent', + scale=100, + units='m', ), - 4: Field( - name='water_type', - type=FIELD_TYPES['water_type'], + 4: Field( # Accumulated altitude along the segment at the described point + name='altitude', + type=BASE_TYPES[0x84], # uint16 def_num=4, + scale=5, + offset=500, + units='m', ), - 5: Field( # Fresh water is usually 1000; salt water is usually 1025 - name='water_density', - type=BASE_TYPES[0x88], # float32 + 5: Field( # Accumualted time each leader board member required to reach the described point. This value is zero for all leader board members at the starting point of the segment. + name='leader_time', + type=BASE_TYPES[0x86], # uint32 def_num=5, - units='kg/m^3', + scale=1000, + units='s', ), - 6: Field( # Typically 1.40 - name='po2_warn', - type=BASE_TYPES[0x02], # uint8 - def_num=6, - scale=100, - units='percent', + 254: Field( + name='message_index', + type=FIELD_TYPES['message_index'], + def_num=254, + ), + }, + ), + 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( # Typically 1.60 - name='po2_critical', - type=BASE_TYPES[0x02], # uint8 + 7: Field( # Leader type of each leader in the segment file + name='leader_type', + type=FIELD_TYPES['segment_leaderboard_type'], def_num=7, - scale=100, - units='percent', ), - 8: Field( - name='po2_deco', - type=BASE_TYPES[0x02], # uint8 + 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, - scale=100, - units='percent', ), - 9: Field( - name='safety_stop_enabled', - type=FIELD_TYPES['bool'], + 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( - name='bottom_depth', - type=BASE_TYPES[0x88], # float32 + 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( - name='bottom_time', - type=BASE_TYPES[0x86], # uint32 + 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, ), - 12: Field( - name='apnea_countdown_enabled', - type=FIELD_TYPES['bool'], - def_num=12, - ), - 13: Field( - name='apnea_countdown_time', - type=BASE_TYPES[0x86], # uint32 - def_num=13, + 254: Field( + name='message_index', + type=FIELD_TYPES['message_index'], + def_num=254, ), - 14: Field( - name='backlight_mode', - type=FIELD_TYPES['dive_backlight_mode'], - def_num=14, + }, + ), + 158: MessageType( + name='workout_session', + mesg_num=158, + fields={ + 0: Field( + name='sport', + type=FIELD_TYPES['sport'], + def_num=0, ), - 15: Field( - name='backlight_brightness', - type=BASE_TYPES[0x02], # uint8 - def_num=15, + 1: Field( + name='sub_sport', + type=FIELD_TYPES['sub_sport'], + def_num=1, ), - 16: Field( - name='backlight_timeout', - type=FIELD_TYPES['backlight_timeout'], - def_num=16, + 2: Field( + name='num_valid_steps', + type=BASE_TYPES[0x84], # uint16 + def_num=2, ), - 17: Field( # Time between surfacing and ending the activity - name='repeat_dive_interval', + 3: Field( + name='first_step_index', type=BASE_TYPES[0x84], # uint16 - def_num=17, - units='s', + def_num=3, ), - 18: Field( # Time at safety stop (if enabled) - name='safety_stop_time', + 4: Field( + name='pool_length', type=BASE_TYPES[0x84], # uint16 - def_num=18, - units='s', + def_num=4, + scale=100, + units='m', ), - 19: Field( - name='heart_rate_source_type', - type=FIELD_TYPES['source_type'], - def_num=19, + 5: Field( + name='pool_length_unit', + type=FIELD_TYPES['display_measure'], + def_num=5, ), - 20: Field( - name='heart_rate_source', - type=BASE_TYPES[0x02], # uint8 - def_num=20, + 254: Field( + name='message_index', + type=FIELD_TYPES['message_index'], + def_num=254, + ), + }, + ), + 159: MessageType( + name='watchface_settings', + mesg_num=159, + fields={ + 0: Field( + name='mode', + type=FIELD_TYPES['watchface_mode'], + def_num=0, + ), + 1: Field( + name='layout', + type=BASE_TYPES[0x0D], # byte + def_num=1, subfields=( SubField( - name='heart_rate_antplus_device_type', - def_num=20, - type=FIELD_TYPES['antplus_device_type'], + name='analog_layout', + def_num=1, + type=FIELD_TYPES['analog_watchface_layout'], ref_fields=( ReferenceField( - name='heart_rate_source_type', - def_num=19, - value='antplus', + name='mode', + def_num=0, + value='analog', raw_value=1, ), ), ), SubField( - name='heart_rate_local_device_type', - def_num=20, - type=FIELD_TYPES['local_device_type'], + name='digital_layout', + def_num=1, + type=FIELD_TYPES['digital_watchface_layout'], ref_fields=( ReferenceField( - name='heart_rate_source_type', - def_num=19, - value='local', - raw_value=5, + name='mode', + def_num=0, + value='digital', + raw_value=0, ), ), ), @@ -10962,536 +11437,723 @@ ), }, ), - 259: MessageType( - name='dive_gas', - mesg_num=259, + 160: MessageType( + name='gps_metadata', + mesg_num=160, fields={ - 0: Field( - name='helium_content', - type=BASE_TYPES[0x02], # uint8 + 0: Field( # Millisecond part of the timestamp. + name='timestamp_ms', + type=BASE_TYPES[0x84], # uint16 def_num=0, - units='percent', + units='ms', ), 1: Field( - name='oxygen_content', - type=BASE_TYPES[0x02], # uint8 + name='position_lat', + type=BASE_TYPES[0x85], # sint32 def_num=1, - units='percent', + units='semicircles', ), 2: Field( - name='status', - type=FIELD_TYPES['dive_gas_status'], + name='position_long', + type=BASE_TYPES[0x85], # sint32 def_num=2, + units='semicircles', ), - 254: Field( - name='message_index', - type=FIELD_TYPES['message_index'], - def_num=254, + 3: Field( + name='enhanced_altitude', + type=BASE_TYPES[0x86], # uint32 + def_num=3, + scale=5, + offset=500, + units='m', + ), + 4: Field( + name='enhanced_speed', + type=BASE_TYPES[0x86], # uint32 + def_num=4, + scale=1000, + units='m/s', + ), + 5: Field( + name='heading', + type=BASE_TYPES[0x84], # uint16 + def_num=5, + scale=100, + units='degrees', + ), + 6: Field( # Used to correlate UTC to system time if the timestamp of the message is in system time. This UTC time is derived from the GPS data. + name='utc_timestamp', + type=FIELD_TYPES['date_time'], + def_num=6, + units='s', ), + 7: Field( # velocity[0] is lon velocity. Velocity[1] is lat velocity. Velocity[2] is altitude velocity. + name='velocity', + type=BASE_TYPES[0x83], # sint16 + def_num=7, + scale=100, + units='m/s', + ), + 253: FIELD_TYPE_TIMESTAMP, # Whole second part of the timestamp. }, ), - 262: MessageType( - name='dive_alarm', - mesg_num=262, + 161: MessageType( + name='camera_event', + mesg_num=161, fields={ - 0: Field( - name='depth', - type=BASE_TYPES[0x86], # uint32 + 0: Field( # Millisecond part of the timestamp. + name='timestamp_ms', + type=BASE_TYPES[0x84], # uint16 + def_num=0, + units='ms', + ), + 1: Field( + name='camera_event_type', + type=FIELD_TYPES['camera_event_type'], + def_num=1, + ), + 2: Field( + name='camera_file_uuid', + type=BASE_TYPES[0x07], # string + def_num=2, + ), + 3: Field( + name='camera_orientation', + type=FIELD_TYPES['camera_orientation_type'], + def_num=3, + ), + 253: FIELD_TYPE_TIMESTAMP, # Whole second part of the timestamp. + }, + ), + 162: MessageType( + name='timestamp_correlation', + mesg_num=162, + fields={ + 0: Field( # Fractional part of the UTC timestamp at the time the system timestamp was recorded. + name='fractional_timestamp', + type=BASE_TYPES[0x84], # uint16 def_num=0, - scale=1000, - units='m', + scale=32768, + units='s', ), - 1: Field( - name='time', - type=BASE_TYPES[0x85], # sint32 + 1: Field( # Whole second part of the system timestamp + name='system_timestamp', + type=FIELD_TYPES['date_time'], def_num=1, units='s', ), - 2: Field( - name='enabled', - type=FIELD_TYPES['bool'], + 2: Field( # Fractional part of the system timestamp + name='fractional_system_timestamp', + type=BASE_TYPES[0x84], # uint16 def_num=2, + scale=32768, + units='s', ), - 3: Field( - name='alarm_type', - type=FIELD_TYPES['dive_alarm_type'], + 3: Field( # timestamp epoch expressed in local time used to convert timestamps to local time + name='local_timestamp', + type=FIELD_TYPES['local_date_time'], def_num=3, + units='s', ), - 4: Field( - name='sound', - type=FIELD_TYPES['tone'], + 4: Field( # Millisecond part of the UTC timestamp at the time the system timestamp was recorded. + name='timestamp_ms', + type=BASE_TYPES[0x84], # uint16 def_num=4, + units='ms', ), - 5: Field( - name='dive_types', - type=FIELD_TYPES['sub_sport'], + 5: Field( # Millisecond part of the system timestamp + name='system_timestamp_ms', + type=BASE_TYPES[0x84], # uint16 def_num=5, + units='ms', ), - 254: Field( # Index of the alarm - name='message_index', - type=FIELD_TYPES['message_index'], - def_num=254, - ), + 253: FIELD_TYPE_TIMESTAMP, # Whole second part of UTC timestamp at the time the system timestamp was recorded. }, ), - 264: MessageType( - name='exercise_title', - mesg_num=264, + 164: MessageType( + name='gyroscope_data', + mesg_num=164, fields={ - 0: Field( - name='exercise_category', - type=FIELD_TYPES['exercise_category'], + 0: Field( # Millisecond part of the timestamp. + name='timestamp_ms', + type=BASE_TYPES[0x84], # uint16 def_num=0, + units='ms', ), - 1: Field( - name='exercise_name', + 1: Field( # Each time in the array describes the time at which the gyro sample with the corrosponding index was taken. Limited to 30 samples in each message. The samples may span across seconds. Array size must match the number of samples in gyro_x and gyro_y and gyro_z + name='sample_time_offset', type=BASE_TYPES[0x84], # uint16 def_num=1, + units='ms', ), - 2: Field( - name='wkt_step_name', - type=BASE_TYPES[0x07], # string + 2: Field( # These are the raw ADC reading. Maximum number of samples is 30 in each message. The samples may span across seconds. A conversion will need to be done on this data once read. + name='gyro_x', + type=BASE_TYPES[0x84], # uint16 def_num=2, + units='counts', ), - 254: Field( - name='message_index', - type=FIELD_TYPES['message_index'], - def_num=254, + 3: Field( # These are the raw ADC reading. Maximum number of samples is 30 in each message. The samples may span across seconds. A conversion will need to be done on this data once read. + name='gyro_y', + type=BASE_TYPES[0x84], # uint16 + def_num=3, + units='counts', + ), + 4: Field( # These are the raw ADC reading. Maximum number of samples is 30 in each message. The samples may span across seconds. A conversion will need to be done on this data once read. + name='gyro_z', + type=BASE_TYPES[0x84], # uint16 + def_num=4, + units='counts', + ), + 5: Field( # Calibrated gyro reading + name='calibrated_gyro_x', + type=BASE_TYPES[0x88], # float32 + def_num=5, + units='deg/s', + ), + 6: Field( # Calibrated gyro reading + name='calibrated_gyro_y', + type=BASE_TYPES[0x88], # float32 + def_num=6, + units='deg/s', + ), + 7: Field( # Calibrated gyro reading + name='calibrated_gyro_z', + type=BASE_TYPES[0x88], # float32 + def_num=7, + units='deg/s', ), + 253: FIELD_TYPE_TIMESTAMP, # Whole second part of the timestamp }, ), - 268: MessageType( - name='dive_summary', - mesg_num=268, + 165: MessageType( + name='accelerometer_data', + mesg_num=165, fields={ - 0: Field( - name='reference_mesg', - type=FIELD_TYPES['mesg_num'], + 0: Field( # Millisecond part of the timestamp. + name='timestamp_ms', + type=BASE_TYPES[0x84], # uint16 def_num=0, + units='ms', ), - 1: Field( - name='reference_index', - type=FIELD_TYPES['message_index'], + 1: Field( # Each time in the array describes the time at which the accelerometer sample with the corrosponding index was taken. Limited to 30 samples in each message. The samples may span across seconds. Array size must match the number of samples in accel_x and accel_y and accel_z + name='sample_time_offset', + type=BASE_TYPES[0x84], # uint16 def_num=1, + units='ms', ), - 2: Field( # 0 if above water - name='avg_depth', - type=BASE_TYPES[0x86], # uint32 + 2: Field( # These are the raw ADC reading. Maximum number of samples is 30 in each message. The samples may span across seconds. A conversion will need to be done on this data once read. + name='accel_x', + type=BASE_TYPES[0x84], # uint16 def_num=2, - scale=1000, - units='m', + units='counts', ), - 3: Field( # 0 if above water - name='max_depth', - type=BASE_TYPES[0x86], # uint32 + 3: Field( # These are the raw ADC reading. Maximum number of samples is 30 in each message. The samples may span across seconds. A conversion will need to be done on this data once read. + name='accel_y', + type=BASE_TYPES[0x84], # uint16 def_num=3, - scale=1000, - units='m', + units='counts', ), - 4: Field( # Time since end of last dive - name='surface_interval', - type=BASE_TYPES[0x86], # uint32 + 4: Field( # These are the raw ADC reading. Maximum number of samples is 30 in each message. The samples may span across seconds. A conversion will need to be done on this data once read. + name='accel_z', + type=BASE_TYPES[0x84], # uint16 def_num=4, - units='s', + units='counts', ), - 5: Field( - name='start_cns', - type=BASE_TYPES[0x02], # uint8 + 5: Field( # Calibrated accel reading + name='calibrated_accel_x', + type=BASE_TYPES[0x88], # float32 def_num=5, - units='percent', + units='g', ), - 6: Field( - name='end_cns', - type=BASE_TYPES[0x02], # uint8 + 6: Field( # Calibrated accel reading + name='calibrated_accel_y', + type=BASE_TYPES[0x88], # float32 def_num=6, - units='percent', + units='g', ), - 7: Field( - name='start_n2', - type=BASE_TYPES[0x84], # uint16 + 7: Field( # Calibrated accel reading + name='calibrated_accel_z', + type=BASE_TYPES[0x88], # float32 def_num=7, - units='percent', + units='g', ), - 8: Field( - name='end_n2', - type=BASE_TYPES[0x84], # uint16 + 8: Field( # Calibrated accel reading + name='compressed_calibrated_accel_x', + type=BASE_TYPES[0x83], # sint16 def_num=8, - units='percent', + units='mG', + ), + 9: Field( # Calibrated accel reading + name='compressed_calibrated_accel_y', + type=BASE_TYPES[0x83], # sint16 + def_num=9, + units='mG', + ), + 10: Field( # Calibrated accel reading + name='compressed_calibrated_accel_z', + type=BASE_TYPES[0x83], # sint16 + def_num=10, + units='mG', + ), + 253: FIELD_TYPE_TIMESTAMP, # Whole second part of the timestamp + }, + ), + 167: MessageType( + name='three_d_sensor_calibration', + mesg_num=167, + fields={ + 0: Field( # Indicates which sensor the calibration is for + name='sensor_type', + type=FIELD_TYPES['sensor_type'], + def_num=0, + ), + 1: Field( # Calibration factor used to convert from raw ADC value to degrees, g, etc. + name='calibration_factor', + type=BASE_TYPES[0x86], # uint32 + def_num=1, + subfields=( + SubField( # Accelerometer calibration factor + name='accel_cal_factor', + def_num=1, + type=BASE_TYPES[0x86], # uint32 + units='g', + ref_fields=( + ReferenceField( + name='sensor_type', + def_num=0, + value='accelerometer', + raw_value=0, + ), + ), + ), + SubField( # Gyro calibration factor + name='gyro_cal_factor', + def_num=1, + type=BASE_TYPES[0x86], # uint32 + units='deg/s', + ref_fields=( + ReferenceField( + name='sensor_type', + def_num=0, + value='gyroscope', + raw_value=1, + ), + ), + ), + ), + ), + 2: Field( # Calibration factor divisor + name='calibration_divisor', + type=BASE_TYPES[0x86], # uint32 + def_num=2, + units='counts', + ), + 3: Field( # Level shift value used to shift the ADC value back into range + name='level_shift', + type=BASE_TYPES[0x86], # uint32 + def_num=3, + ), + 4: Field( # Internal calibration factors, one for each: xy, yx, zx + name='offset_cal', + type=BASE_TYPES[0x85], # sint32 + def_num=4, ), - 9: Field( - name='o2_toxicity', - type=BASE_TYPES[0x84], # uint16 - def_num=9, - units='OTUs', + 5: Field( # 3 x 3 rotation matrix (row major) + name='orientation_matrix', + type=BASE_TYPES[0x85], # sint32 + def_num=5, + scale=65535, ), - 10: Field( - name='dive_number', - type=BASE_TYPES[0x86], # uint32 - def_num=10, + 253: FIELD_TYPE_TIMESTAMP, # Whole second part of the timestamp + }, + ), + 169: MessageType( + name='video_frame', + mesg_num=169, + fields={ + 0: Field( # Millisecond part of the timestamp. + name='timestamp_ms', + type=BASE_TYPES[0x84], # uint16 + def_num=0, + units='ms', ), - 11: Field( - name='bottom_time', + 1: Field( # Number of the frame that the timestamp and timestamp_ms correlate to + name='frame_number', type=BASE_TYPES[0x86], # uint32 - def_num=11, - scale=1000, - units='s', + def_num=1, ), - 253: FIELD_TYPE_TIMESTAMP, + 253: FIELD_TYPE_TIMESTAMP, # Whole second part of the timestamp }, ), - - - # ************************* Activity File Messages ************************* - 34: MessageType( - name='activity', - mesg_num=34, + 174: MessageType( + name='obdii_data', + mesg_num=174, fields={ - 0: Field( # Exclude pauses - name='total_timer_time', - type=BASE_TYPES[0x86], # uint32 + 0: Field( # Fractional part of timestamp, added to timestamp + name='timestamp_ms', + type=BASE_TYPES[0x84], # uint16 def_num=0, - scale=1000, - units='s', + units='ms', ), - 1: Field( - name='num_sessions', + 1: Field( # Offset of PID reading [i] from start_timestamp+start_timestamp_ms. Readings may span accross seconds. + name='time_offset', type=BASE_TYPES[0x84], # uint16 def_num=1, + units='ms', ), - 2: Field( - name='type', - type=FIELD_TYPES['activity'], + 2: Field( # Parameter ID + name='pid', + type=BASE_TYPES[0x0D], # byte def_num=2, ), - 3: Field( - name='event', - type=FIELD_TYPES['event'], + 3: Field( # Raw parameter data + name='raw_data', + type=BASE_TYPES[0x0D], # byte def_num=3, ), - 4: Field( - name='event_type', - type=FIELD_TYPES['event_type'], + 4: Field( # Optional, data size of PID[i]. If not specified refer to SAE J1979. + name='pid_data_size', + type=BASE_TYPES[0x02], # uint8 def_num=4, ), - 5: Field( # timestamp epoch expressed in local time, used to convert activity timestamps to local time - name='local_timestamp', - type=FIELD_TYPES['local_date_time'], + 5: Field( # System time associated with sample expressed in ms, can be used instead of time_offset. There will be a system_time value for each raw_data element. For multibyte pids the system_time is repeated. + name='system_time', + type=BASE_TYPES[0x86], # uint32 def_num=5, ), - 6: Field( - name='event_group', - type=BASE_TYPES[0x02], # uint8 + 6: Field( # Timestamp of first sample recorded in the message. Used with time_offset to generate time of each sample + name='start_timestamp', + type=FIELD_TYPES['date_time'], def_num=6, ), - 253: FIELD_TYPE_TIMESTAMP, + 7: Field( # Fractional part of start_timestamp + name='start_timestamp_ms', + type=BASE_TYPES[0x84], # uint16 + def_num=7, + units='ms', + ), + 253: FIELD_TYPE_TIMESTAMP, # Timestamp message was output }, ), - - - # ********************** Blood Pressure File Messages ********************** - 51: MessageType( - name='blood_pressure', - mesg_num=51, + 177: MessageType( + name='nmea_sentence', + mesg_num=177, fields={ - 0: Field( - name='systolic_pressure', + 0: Field( # Fractional part of timestamp, added to timestamp + name='timestamp_ms', type=BASE_TYPES[0x84], # uint16 def_num=0, - units='mmHg', + units='ms', ), - 1: Field( - name='diastolic_pressure', - type=BASE_TYPES[0x84], # uint16 + 1: Field( # NMEA sentence + name='sentence', + type=BASE_TYPES[0x07], # string def_num=1, - units='mmHg', ), - 2: Field( - name='mean_arterial_pressure', + 253: FIELD_TYPE_TIMESTAMP, # Timestamp message was output + }, + ), + 178: MessageType( + name='aviation_attitude', + mesg_num=178, + fields={ + 0: Field( # Fractional part of timestamp, added to timestamp + name='timestamp_ms', type=BASE_TYPES[0x84], # uint16 + def_num=0, + units='ms', + ), + 1: Field( # System time associated with sample expressed in ms. + name='system_time', + type=BASE_TYPES[0x86], # uint32 + def_num=1, + units='ms', + ), + 2: Field( # Range -PI/2 to +PI/2 + name='pitch', + type=BASE_TYPES[0x83], # sint16 def_num=2, - units='mmHg', + scale=10430.38, + units='radians', ), - 3: Field( - name='map_3_sample_mean', - type=BASE_TYPES[0x84], # uint16 + 3: Field( # Range -PI to +PI + name='roll', + type=BASE_TYPES[0x83], # sint16 def_num=3, - units='mmHg', + scale=10430.38, + units='radians', ), - 4: Field( - name='map_morning_values', - type=BASE_TYPES[0x84], # uint16 + 4: Field( # Range -78.4 to +78.4 (-8 Gs to 8 Gs) + name='accel_lateral', + type=BASE_TYPES[0x83], # sint16 def_num=4, - units='mmHg', + scale=100, + units='m/s^2', ), - 5: Field( - name='map_evening_values', - type=BASE_TYPES[0x84], # uint16 + 5: Field( # Range -78.4 to +78.4 (-8 Gs to 8 Gs) + name='accel_normal', + type=BASE_TYPES[0x83], # sint16 def_num=5, - units='mmHg', + scale=100, + units='m/s^2', ), - 6: Field( - name='heart_rate', - type=BASE_TYPES[0x02], # uint8 + 6: Field( # Range -8.727 to +8.727 (-500 degs/sec to +500 degs/sec) + name='turn_rate', + type=BASE_TYPES[0x83], # sint16 def_num=6, - units='bpm', + scale=1024, + units='radians/second', ), 7: Field( - name='heart_rate_type', - type=FIELD_TYPES['hr_type'], + name='stage', + type=FIELD_TYPES['attitude_stage'], def_num=7, ), - 8: Field( - name='status', - type=FIELD_TYPES['bp_status'], + 8: Field( # The percent complete of the current attitude stage. Set to 0 for attitude stages 0, 1 and 2 and to 100 for attitude stage 3 by AHRS modules that do not support it. Range - 100 + name='attitude_stage_complete', + type=BASE_TYPES[0x02], # uint8 def_num=8, + units='%', ), - 9: Field( # Associates this blood pressure message to a user. This corresponds to the index of the user profile message in the blood pressure file. - name='user_profile_index', - type=FIELD_TYPES['message_index'], + 9: Field( # Track Angle/Heading Range 0 - 2pi + name='track', + type=BASE_TYPES[0x84], # uint16 def_num=9, + scale=10430.38, + units='radians', ), - 253: FIELD_TYPE_TIMESTAMP, + 10: Field( + name='validity', + type=FIELD_TYPES['attitude_validity'], + def_num=10, + ), + 253: FIELD_TYPE_TIMESTAMP, # Timestamp message was output }, ), - - - # ************************** Course File Messages ************************** - 31: MessageType( - name='course', - mesg_num=31, + 184: MessageType( + name='video', + mesg_num=184, fields={ - 4: Field( - name='sport', - type=FIELD_TYPES['sport'], - def_num=4, + 0: Field( + name='url', + type=BASE_TYPES[0x07], # string + def_num=0, ), - 5: Field( - name='name', + 1: Field( + name='hosting_provider', type=BASE_TYPES[0x07], # string - def_num=5, + def_num=1, ), - 6: Field( - name='capabilities', - type=FIELD_TYPES['course_capabilities'], - def_num=6, + 2: Field( # Playback time of video + name='duration', + type=BASE_TYPES[0x86], # uint32 + def_num=2, + units='ms', ), - 7: Field( - name='sub_sport', - type=FIELD_TYPES['sub_sport'], - def_num=7, + }, + ), + 185: MessageType( + name='video_title', + mesg_num=185, + fields={ + 0: Field( # Total number of title parts + name='message_count', + type=BASE_TYPES[0x84], # uint16 + def_num=0, + ), + 1: Field( + name='text', + type=BASE_TYPES[0x07], # string + def_num=1, + ), + 254: Field( # Long titles will be split into multiple parts + name='message_index', + type=FIELD_TYPES['message_index'], + def_num=254, ), }, ), - - - # ************************** Device File Messages ************************** - 35: MessageType( - name='software', - mesg_num=35, + 186: MessageType( + name='video_description', + mesg_num=186, fields={ - 3: Field( - name='version', + 0: Field( # Total number of description parts + name='message_count', type=BASE_TYPES[0x84], # uint16 - def_num=3, - scale=100, + def_num=0, ), - 5: Field( - name='part_number', + 1: Field( + name='text', type=BASE_TYPES[0x07], # string - def_num=5, + def_num=1, ), - 254: Field( + 254: Field( # Long descriptions will be split into multiple parts name='message_index', type=FIELD_TYPES['message_index'], def_num=254, ), }, ), - - - # ************************** Goals File Messages *************************** - 15: MessageType( - name='goal', - mesg_num=15, + 187: MessageType( + name='video_clip', + mesg_num=187, fields={ 0: Field( - name='sport', - type=FIELD_TYPES['sport'], + name='clip_number', + type=BASE_TYPES[0x84], # uint16 def_num=0, ), 1: Field( - name='sub_sport', - type=FIELD_TYPES['sub_sport'], + name='start_timestamp', + type=FIELD_TYPES['date_time'], def_num=1, ), 2: Field( - name='start_date', - type=FIELD_TYPES['date_time'], + name='start_timestamp_ms', + type=BASE_TYPES[0x84], # uint16 def_num=2, ), 3: Field( - name='end_date', + name='end_timestamp', type=FIELD_TYPES['date_time'], def_num=3, ), 4: Field( - name='type', - type=FIELD_TYPES['goal'], + name='end_timestamp_ms', + type=BASE_TYPES[0x84], # uint16 def_num=4, ), - 5: Field( - name='value', + 6: Field( # Start of clip in video time + name='clip_start', type=BASE_TYPES[0x86], # uint32 - def_num=5, - ), - 6: Field( - name='repeat', - type=FIELD_TYPES['bool'], def_num=6, + units='ms', ), - 7: Field( - name='target_value', + 7: Field( # End of clip in video time + name='clip_end', type=BASE_TYPES[0x86], # uint32 def_num=7, + units='ms', ), - 8: Field( - name='recurrence', - type=FIELD_TYPES['goal_recurrence'], - def_num=8, - ), - 9: Field( - name='recurrence_value', - type=BASE_TYPES[0x84], # uint16 - def_num=9, - ), - 10: Field( + }, + ), + 188: MessageType( + name='ohr_settings', + mesg_num=188, + fields={ + 0: Field( name='enabled', - type=FIELD_TYPES['bool'], - def_num=10, - ), - 11: Field( - name='source', - type=FIELD_TYPES['goal_source'], - def_num=11, - ), - 254: Field( - name='message_index', - type=FIELD_TYPES['message_index'], - def_num=254, + type=FIELD_TYPES['switch'], + def_num=0, ), + 253: FIELD_TYPE_TIMESTAMP, }, ), - - - # ************************ Monitoring File Messages ************************ - 103: MessageType( - name='monitoring_info', - mesg_num=103, + 200: MessageType( + name='exd_screen_configuration', + mesg_num=200, fields={ - 0: Field( # Use to convert activity timestamps to local time if device does not support time zone and daylight savings time correction. - name='local_timestamp', - type=FIELD_TYPES['local_date_time'], + 0: Field( + name='screen_index', + type=BASE_TYPES[0x02], # uint8 def_num=0, - units='s', ), - 1: Field( - name='activity_type', - type=FIELD_TYPES['activity_type'], + 1: Field( # number of fields in screen + name='field_count', + type=BASE_TYPES[0x02], # uint8 def_num=1, ), - 3: Field( # Indexed by activity_type - name='cycles_to_distance', - type=BASE_TYPES[0x84], # uint16 - def_num=3, - scale=5000, - units='m/cycle', - ), - 4: Field( # Indexed by activity_type - name='cycles_to_calories', - type=BASE_TYPES[0x84], # uint16 - def_num=4, - scale=5000, - units='kcal/cycle', + 2: Field( + name='layout', + type=FIELD_TYPES['exd_layout'], + def_num=2, ), - 5: Field( - name='resting_metabolic_rate', - type=BASE_TYPES[0x84], # uint16 - def_num=5, - units='kcal/day', + 3: Field( + name='screen_enabled', + type=FIELD_TYPES['bool'], + def_num=3, ), - 253: FIELD_TYPE_TIMESTAMP, }, ), - - - # ***************************** Other Messages ***************************** - 145: MessageType( - name='memo_glob', - mesg_num=145, + 201: MessageType( + name='exd_data_field_configuration', + mesg_num=201, fields={ - 0: Field( # Block of utf8 bytes - name='memo', - type=BASE_TYPES[0x0D], # byte + 0: Field( + name='screen_index', + type=BASE_TYPES[0x02], # uint8 def_num=0, ), - 1: Field( # Allows relating glob to another mesg If used only required for first part of each memo_glob - name='message_number', - type=BASE_TYPES[0x84], # uint16 + 1: Field( + name='concept_field', + type=BASE_TYPES[0x0D], # byte def_num=1, + components=( + ComponentField( + name='field_id', + def_num=2, + accumulate=False, + bits=4, + bit_offset=0, + ), + ComponentField( + name='concept_count', + def_num=3, + accumulate=False, + bits=4, + bit_offset=4, + ), + ), ), - 2: Field( # Index of external mesg - name='message_index', - type=FIELD_TYPES['message_index'], + 2: Field( + name='field_id', + type=BASE_TYPES[0x02], # uint8 def_num=2, ), - 250: Field( # Sequence number of memo blocks - name='part_index', - type=BASE_TYPES[0x86], # uint32 - def_num=250, + 3: Field( + name='concept_count', + type=BASE_TYPES[0x02], # uint8 + def_num=3, + ), + 4: Field( + name='display_type', + type=FIELD_TYPES['exd_display_type'], + def_num=4, + ), + 5: Field( + name='title', + type=BASE_TYPES[0x07], # string + def_num=5, ), }, ), - - - # ************************* Schedule File Messages ************************* - 28: MessageType( - name='schedule', - mesg_num=28, + 202: MessageType( + name='exd_data_concept_configuration', + mesg_num=202, fields={ - 0: Field( # Corresponds to file_id of scheduled workout / course. - name='manufacturer', - type=FIELD_TYPES['manufacturer'], + 0: Field( + name='screen_index', + type=BASE_TYPES[0x02], # uint8 def_num=0, ), - 1: Field( # Corresponds to file_id of scheduled workout / course. - name='product', - type=BASE_TYPES[0x84], # uint16 + 1: Field( + name='concept_field', + type=BASE_TYPES[0x0D], # byte def_num=1, - subfields=( - SubField( - name='garmin_product', - def_num=1, - type=FIELD_TYPES['garmin_product'], - ref_fields=( - ReferenceField( - name='manufacturer', - def_num=0, - value='garmin', - raw_value=1, - ), - ReferenceField( - name='manufacturer', - def_num=0, - value='dynastream', - raw_value=15, - ), - ReferenceField( - name='manufacturer', - def_num=0, - value='dynastream_oem', - raw_value=13, - ), - ), + components=( + ComponentField( + name='field_id', + def_num=2, + accumulate=False, + bits=4, + bit_offset=0, + ), + ComponentField( + name='concept_index', + def_num=3, + accumulate=False, + bits=4, + bit_offset=4, ), SubField( name='strava_product', @@ -11508,426 +12170,546 @@ ), ), ), - 2: Field( # Corresponds to file_id of scheduled workout / course. - name='serial_number', - type=BASE_TYPES[0x8C], # uint32z + 2: Field( + name='field_id', + type=BASE_TYPES[0x02], # uint8 def_num=2, ), - 3: Field( # Corresponds to file_id of scheduled workout / course. - name='time_created', - type=FIELD_TYPES['date_time'], + 3: Field( + name='concept_index', + type=BASE_TYPES[0x02], # uint8 def_num=3, ), - 4: Field( # TRUE if this activity has been started - name='completed', - type=FIELD_TYPES['bool'], + 4: Field( + name='data_page', + type=BASE_TYPES[0x02], # uint8 def_num=4, ), 5: Field( - name='type', - type=FIELD_TYPES['schedule'], + name='concept_key', + type=BASE_TYPES[0x02], # uint8 def_num=5, ), 6: Field( - name='scheduled_time', - type=FIELD_TYPES['local_date_time'], + name='scaling', + type=BASE_TYPES[0x02], # uint8 def_num=6, ), + 8: Field( + name='data_units', + type=FIELD_TYPES['exd_data_units'], + def_num=8, + ), + 9: Field( + name='qualifier', + type=FIELD_TYPES['exd_qualifiers'], + def_num=9, + ), + 10: Field( + name='descriptor', + type=FIELD_TYPES['exd_descriptors'], + def_num=10, + ), + 11: Field( + name='is_signed', + type=FIELD_TYPES['bool'], + def_num=11, + ), }, ), - - - # ************************* Segment File Messages ************************** - 148: MessageType( # Unique Identification data for a segment file - name='segment_id', - mesg_num=148, + 206: MessageType( # Must be logged before developer field is used + name='field_description', + mesg_num=206, fields={ - 0: Field( # Friendly name assigned to segment - name='name', - type=BASE_TYPES[0x07], # string + 0: Field( + name='developer_data_index', + type=BASE_TYPES[0x02], # uint8 def_num=0, ), - 1: Field( # UUID of the segment - name='uuid', - type=BASE_TYPES[0x07], # string + 1: Field( + name='field_definition_number', + type=BASE_TYPES[0x02], # uint8 def_num=1, ), - 2: Field( # Sport associated with the segment - name='sport', - type=FIELD_TYPES['sport'], + 2: Field( + name='fit_base_type_id', + type=FIELD_TYPES['fit_base_type'], def_num=2, ), - 3: Field( # Segment enabled for evaluation - name='enabled', - type=FIELD_TYPES['bool'], + 3: Field( + name='field_name', + type=BASE_TYPES[0x07], # string def_num=3, ), - 4: Field( # Primary key of the user that created the segment - name='user_profile_primary_key', - type=BASE_TYPES[0x86], # uint32 + 4: Field( + name='array', + type=BASE_TYPES[0x02], # uint8 def_num=4, ), - 5: Field( # ID of the device that created the segment - name='device_id', - type=BASE_TYPES[0x86], # uint32 + 5: Field( + name='components', + type=BASE_TYPES[0x07], # string def_num=5, ), - 6: Field( # Index for the Leader Board entry selected as the default race participant - name='default_race_leader', + 6: Field( + name='scale', type=BASE_TYPES[0x02], # uint8 def_num=6, ), - 7: Field( # Indicates if any segments should be deleted - name='delete_status', - type=FIELD_TYPES['segment_delete_status'], + 7: Field( + name='offset', + type=BASE_TYPES[0x01], # sint8 def_num=7, ), - 8: Field( # Indicates how the segment was selected to be sent to the device - name='selection_type', - type=FIELD_TYPES['segment_selection_type'], + 8: Field( + name='units', + type=BASE_TYPES[0x07], # string def_num=8, ), + 9: Field( + name='bits', + type=BASE_TYPES[0x07], # string + def_num=9, + ), + 10: Field( + name='accumulate', + type=BASE_TYPES[0x07], # string + def_num=10, + ), + 13: Field( + name='fit_base_unit_id', + type=FIELD_TYPES['fit_base_unit'], + def_num=13, + ), + 14: Field( + name='native_mesg_num', + type=FIELD_TYPES['mesg_num'], + def_num=14, + ), + 15: Field( + name='native_field_num', + type=BASE_TYPES[0x02], # uint8 + def_num=15, + ), }, ), - - - # *********************** 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, + 207: MessageType( # Must be logged before field description + name='developer_data_id', + mesg_num=207, fields={ - 1: Field( # UUID of the segment file - name='file_uuid', - type=BASE_TYPES[0x07], # string + 0: Field( + name='developer_id', + type=BASE_TYPES[0x0D], # byte + def_num=0, + ), + 1: Field( + name='application_id', + type=BASE_TYPES[0x0D], # byte def_num=1, ), - 3: Field( # Enabled state of the segment file - name='enabled', - type=FIELD_TYPES['bool'], + 2: Field( + name='manufacturer_id', + type=FIELD_TYPES['manufacturer'], + def_num=2, + ), + 3: Field( + name='developer_data_index', + type=BASE_TYPES[0x02], # uint8 def_num=3, ), - 4: Field( # Primary key of the user that created the segment file - name='user_profile_primary_key', + 4: Field( + name='application_version', 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, + }, + ), + 208: MessageType( + name='magnetometer_data', + mesg_num=208, + fields={ + 0: Field( # Millisecond part of the timestamp. + name='timestamp_ms', + type=BASE_TYPES[0x84], # uint16 + def_num=0, + units='ms', ), - 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, + 1: Field( # Each time in the array describes the time at which the compass sample with the corrosponding index was taken. Limited to 30 samples in each message. The samples may span across seconds. Array size must match the number of samples in cmps_x and cmps_y and cmps_z + name='sample_time_offset', + type=BASE_TYPES[0x84], # uint16 + def_num=1, + units='ms', ), - 9: Field( # Activity ID of each leader in the segment file - name='leader_activity_id', - type=BASE_TYPES[0x86], # uint32 - def_num=9, + 2: Field( # These are the raw ADC reading. Maximum number of samples is 30 in each message. The samples may span across seconds. A conversion will need to be done on this data once read. + name='mag_x', + type=BASE_TYPES[0x84], # uint16 + def_num=2, + units='counts', ), - 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, + 3: Field( # These are the raw ADC reading. Maximum number of samples is 30 in each message. The samples may span across seconds. A conversion will need to be done on this data once read. + name='mag_y', + type=BASE_TYPES[0x84], # uint16 + def_num=3, + units='counts', + ), + 4: Field( # These are the raw ADC reading. Maximum number of samples is 30 in each message. The samples may span across seconds. A conversion will need to be done on this data once read. + name='mag_z', + type=BASE_TYPES[0x84], # uint16 + def_num=4, + units='counts', + ), + 5: Field( # Calibrated Magnetometer reading + name='calibrated_mag_x', + type=BASE_TYPES[0x88], # float32 + def_num=5, + units='G', + ), + 6: Field( # Calibrated Magnetometer reading + name='calibrated_mag_y', + type=BASE_TYPES[0x88], # float32 + def_num=6, + units='G', + ), + 7: Field( # Calibrated Magnetometer reading + name='calibrated_mag_z', + type=BASE_TYPES[0x88], # float32 + def_num=7, + units='G', + ), + 253: FIELD_TYPE_TIMESTAMP, # Whole second part of the timestamp + }, + ), + 209: MessageType( + name='barometer_data', + mesg_num=209, + fields={ + 0: Field( # Millisecond part of the timestamp. + name='timestamp_ms', + type=BASE_TYPES[0x84], # uint16 + def_num=0, + units='ms', ), - 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, + 1: Field( # Each time in the array describes the time at which the barometer sample with the corrosponding index was taken. The samples may span across seconds. Array size must match the number of samples in baro_cal + name='sample_time_offset', + type=BASE_TYPES[0x84], # uint16 + def_num=1, + units='ms', ), - 254: Field( - name='message_index', - type=FIELD_TYPES['message_index'], - def_num=254, + 2: Field( # These are the raw ADC reading. The samples may span across seconds. A conversion will need to be done on this data once read. + name='baro_pres', + type=BASE_TYPES[0x86], # uint32 + def_num=2, + units='Pa', ), + 253: FIELD_TYPE_TIMESTAMP, # Whole second part of the timestamp }, ), - - - # ************************* Settings File Messages ************************* - 2: MessageType( - name='device_settings', - mesg_num=2, + 210: MessageType( + name='one_d_sensor_calibration', + mesg_num=210, fields={ - 0: Field( # Index into time zone arrays. - name='active_time_zone', - type=BASE_TYPES[0x02], # uint8 + 0: Field( # Indicates which sensor the calibration is for + name='sensor_type', + type=FIELD_TYPES['sensor_type'], def_num=0, ), - 1: Field( # Offset from system time. Required to convert timestamp from system time to UTC. - name='utc_offset', + 1: Field( # Calibration factor used to convert from raw ADC value to degrees, g, etc. + name='calibration_factor', type=BASE_TYPES[0x86], # uint32 def_num=1, + subfields=( + SubField( # Barometer calibration factor + name='baro_cal_factor', + def_num=1, + type=BASE_TYPES[0x86], # uint32 + units='Pa', + ref_fields=( + ReferenceField( + name='sensor_type', + def_num=0, + value='barometer', + raw_value=3, + ), + ), + ), + ), ), - 2: Field( # Offset from system time. - name='time_offset', + 2: Field( # Calibration factor divisor + name='calibration_divisor', type=BASE_TYPES[0x86], # uint32 def_num=2, - units='s', - ), - 4: Field( # Display mode for the time - name='time_mode', - type=FIELD_TYPES['time_mode'], - def_num=4, - ), - 5: Field( # timezone offset in 1/4 hour increments - name='time_zone_offset', - type=BASE_TYPES[0x01], # sint8 - def_num=5, - scale=4, - units='hr', + units='counts', ), - 12: Field( # Mode for backlight - name='backlight_mode', - type=FIELD_TYPES['backlight_mode'], - def_num=12, + 3: Field( # Level shift value used to shift the ADC value back into range + name='level_shift', + type=BASE_TYPES[0x86], # uint32 + def_num=3, ), - 36: Field( # Enabled state of the activity tracker functionality - name='activity_tracker_enabled', - type=FIELD_TYPES['bool'], - def_num=36, + 4: Field( # Internal Calibration factor + name='offset_cal', + type=BASE_TYPES[0x85], # sint32 + def_num=4, ), - 39: Field( # UTC timestamp used to set the devices clock and date - name='clock_time', - type=FIELD_TYPES['date_time'], - def_num=39, + 253: FIELD_TYPE_TIMESTAMP, # Whole second part of the timestamp + }, + ), + 225: MessageType( + name='set', + mesg_num=225, + fields={ + 0: Field( + name='duration', + type=BASE_TYPES[0x86], # uint32 + def_num=0, + scale=1000, + units='s', ), - 40: Field( # Bitfield to configure enabled screens for each supported loop - name='pages_enabled', + 3: Field( # # of repitions of the movement + name='repetitions', type=BASE_TYPES[0x84], # uint16 - def_num=40, - ), - 46: Field( # Enabled state of the move alert - name='move_alert_enabled', - type=FIELD_TYPES['bool'], - def_num=46, - ), - 47: Field( # Display mode for the date - name='date_mode', - type=FIELD_TYPES['date_mode'], - def_num=47, + def_num=3, ), - 55: Field( - name='display_orientation', - type=FIELD_TYPES['display_orientation'], - def_num=55, + 4: Field( # Amount of weight applied for the set + name='weight', + type=BASE_TYPES[0x84], # uint16 + def_num=4, + scale=16, + units='kg', ), - 56: Field( - name='mounting_side', - type=FIELD_TYPES['side'], - def_num=56, + 5: Field( + name='set_type', + type=FIELD_TYPES['set_type'], + def_num=5, ), - 57: Field( # Bitfield to indicate one page as default for each supported loop - name='default_page', - type=BASE_TYPES[0x84], # uint16 - def_num=57, + 6: Field( # Start time of the set + name='start_time', + type=FIELD_TYPES['date_time'], + def_num=6, ), - 58: Field( # Minimum steps before an autosync can occur - name='autosync_min_steps', - type=BASE_TYPES[0x84], # uint16 - def_num=58, - units='steps', + 7: Field( + name='category', + type=FIELD_TYPES['exercise_category'], + def_num=7, ), - 59: Field( # Minimum minutes before an autosync can occur - name='autosync_min_time', + 8: Field( # Based on the associated category, see [category]_exercise_names + name='category_subtype', type=BASE_TYPES[0x84], # uint16 - def_num=59, - units='minutes', - ), - 80: Field( # Enable auto-detect setting for the lactate threshold feature. - name='lactate_threshold_autodetect_enabled', - type=FIELD_TYPES['bool'], - def_num=80, + def_num=8, ), - 86: Field( # Automatically upload using BLE - name='ble_auto_upload_enabled', - type=FIELD_TYPES['bool'], - def_num=86, + 9: Field( + name='weight_display_unit', + type=FIELD_TYPES['fit_base_unit'], + def_num=9, ), - 89: Field( # Helps to conserve battery by changing modes - name='auto_sync_frequency', - type=FIELD_TYPES['auto_sync_frequency'], - def_num=89, + 10: Field( + name='message_index', + type=FIELD_TYPES['message_index'], + def_num=10, ), - 90: Field( # Allows setting specific activities auto-activity detect enabled/disabled settings - name='auto_activity_detect', - type=FIELD_TYPES['auto_activity_detect'], - def_num=90, + 11: Field( + name='wkt_step_index', + type=FIELD_TYPES['message_index'], + def_num=11, ), - 94: Field( # Number of screens configured to display - name='number_of_screens', - type=BASE_TYPES[0x02], # uint8 - def_num=94, + 254: Field( # Timestamp of the set + name='timestamp', + type=FIELD_TYPES['date_time'], + def_num=254, ), - 95: Field( # Smart Notification display orientation - name='smart_notification_display_orientation', - type=FIELD_TYPES['display_orientation'], - def_num=95, + }, + ), + 227: MessageType( # Value from 1 to 100 calculated by FirstBeat + name='stress_level', + mesg_num=227, + fields={ + 0: Field( + name='stress_level_value', + type=BASE_TYPES[0x83], # sint16 + def_num=0, ), - 134: Field( - name='tap_interface', - type=FIELD_TYPES['switch'], - def_num=134, + 1: Field( # Time stress score was calculated + name='stress_level_time', + type=FIELD_TYPES['date_time'], + def_num=1, + units='s', ), }, ), - 3: MessageType( - name='user_profile', - mesg_num=3, + 258: MessageType( + name='dive_settings', + mesg_num=258, fields={ 0: Field( - name='friendly_name', + name='name', type=BASE_TYPES[0x07], # string def_num=0, ), 1: Field( - name='gender', - type=FIELD_TYPES['gender'], + name='model', + type=FIELD_TYPES['tissue_model_type'], def_num=1, ), 2: Field( - name='age', + name='gf_low', type=BASE_TYPES[0x02], # uint8 def_num=2, - units='years', + units='percent', ), 3: Field( - name='height', + name='gf_high', type=BASE_TYPES[0x02], # uint8 def_num=3, - scale=100, - units='m', + units='percent', ), 4: Field( - name='weight', - type=BASE_TYPES[0x84], # uint16 + name='water_type', + type=FIELD_TYPES['water_type'], def_num=4, - scale=10, - units='kg', ), - 5: Field( - name='language', - type=FIELD_TYPES['language'], + 5: Field( # Fresh water is usually 1000; salt water is usually 1025 + name='water_density', + type=BASE_TYPES[0x88], # float32 def_num=5, + units='kg/m^3', ), - 6: Field( - name='elev_setting', - type=FIELD_TYPES['display_measure'], + 6: Field( # Typically 1.40 + name='po2_warn', + type=BASE_TYPES[0x02], # uint8 def_num=6, + scale=100, + units='percent', ), - 7: Field( - name='weight_setting', - type=FIELD_TYPES['display_measure'], + 7: Field( # Typically 1.60 + name='po2_critical', + type=BASE_TYPES[0x02], # uint8 def_num=7, + scale=100, + units='percent', ), 8: Field( - name='resting_heart_rate', + name='po2_deco', type=BASE_TYPES[0x02], # uint8 def_num=8, - units='bpm', + scale=100, + units='percent', ), 9: Field( - name='default_max_running_heart_rate', - type=BASE_TYPES[0x02], # uint8 + name='safety_stop_enabled', + type=FIELD_TYPES['bool'], def_num=9, - units='bpm', ), 10: Field( - name='default_max_biking_heart_rate', - type=BASE_TYPES[0x02], # uint8 + name='bottom_depth', + type=BASE_TYPES[0x88], # float32 def_num=10, - units='bpm', ), 11: Field( - name='default_max_heart_rate', - type=BASE_TYPES[0x02], # uint8 + name='bottom_time', + type=BASE_TYPES[0x86], # uint32 def_num=11, - units='bpm', ), 12: Field( - name='hr_setting', - type=FIELD_TYPES['display_heart'], + name='apnea_countdown_enabled', + type=FIELD_TYPES['bool'], def_num=12, ), 13: Field( - name='speed_setting', - type=FIELD_TYPES['display_measure'], + name='apnea_countdown_time', + type=BASE_TYPES[0x86], # uint32 def_num=13, ), 14: Field( - name='dist_setting', - type=FIELD_TYPES['display_measure'], + name='backlight_mode', + type=FIELD_TYPES['dive_backlight_mode'], def_num=14, ), + 15: Field( + name='backlight_brightness', + type=BASE_TYPES[0x02], # uint8 + def_num=15, + ), 16: Field( - name='power_setting', - type=FIELD_TYPES['display_power'], + name='backlight_timeout', + type=FIELD_TYPES['backlight_timeout'], def_num=16, ), - 17: Field( - name='activity_class', - type=FIELD_TYPES['activity_class'], + 17: Field( # Time between surfacing and ending the activity + name='repeat_dive_interval', + type=BASE_TYPES[0x84], # uint16 def_num=17, + units='s', ), - 18: Field( - name='position_setting', - type=FIELD_TYPES['display_position'], + 18: Field( # Time at safety stop (if enabled) + name='safety_stop_time', + type=BASE_TYPES[0x84], # uint16 def_num=18, + units='s', ), - 21: Field( - name='temperature_setting', - type=FIELD_TYPES['display_measure'], - def_num=21, - ), - 22: Field( - name='local_id', - type=FIELD_TYPES['user_local_id'], - def_num=22, - ), - 23: Field( - name='global_id', - type=BASE_TYPES[0x0D], # byte - def_num=23, - ), - 28: Field( # Typical wake time - name='wake_time', - type=FIELD_TYPES['localtime_into_day'], - def_num=28, - ), - 29: Field( # Typical bed time - name='sleep_time', - type=FIELD_TYPES['localtime_into_day'], - def_num=29, + 19: Field( + name='heart_rate_source_type', + type=FIELD_TYPES['source_type'], + def_num=19, ), - 30: Field( - name='height_setting', - type=FIELD_TYPES['display_measure'], - def_num=30, + 20: Field( + name='heart_rate_source', + type=BASE_TYPES[0x02], # uint8 + def_num=20, + subfields=( + SubField( + name='heart_rate_antplus_device_type', + def_num=20, + type=FIELD_TYPES['antplus_device_type'], + ref_fields=( + ReferenceField( + name='heart_rate_source_type', + def_num=19, + value='antplus', + raw_value=1, + ), + ), + ), + SubField( + name='heart_rate_local_device_type', + def_num=20, + type=FIELD_TYPES['local_device_type'], + ref_fields=( + ReferenceField( + name='heart_rate_source_type', + def_num=19, + value='local', + raw_value=5, + ), + ), + ), + ), ), - 31: Field( # User defined running step length set to 0 for auto length - name='user_running_step_length', - type=BASE_TYPES[0x84], # uint16 - def_num=31, - scale=1000, - units='m', + 254: Field( + name='message_index', + type=FIELD_TYPES['message_index'], + def_num=254, ), - 32: Field( # User defined walking step length set to 0 for auto length - name='user_walking_step_length', - type=BASE_TYPES[0x84], # uint16 - def_num=32, - scale=1000, - units='m', + }, + ), + 259: MessageType( + name='dive_gas', + mesg_num=259, + fields={ + 0: Field( + name='helium_content', + type=BASE_TYPES[0x02], # uint8 + def_num=0, + units='percent', ), - 47: Field( - name='depth_setting', - type=FIELD_TYPES['display_measure'], - def_num=47, + 1: Field( + name='oxygen_content', + type=BASE_TYPES[0x02], # uint8 + def_num=1, + units='percent', ), - 49: Field( - name='dive_count', - type=BASE_TYPES[0x86], # uint32 - def_num=49, + 2: Field( + name='status', + type=FIELD_TYPES['dive_gas_status'], + def_num=2, ), 254: Field( name='message_index', @@ -11936,231 +12718,300 @@ ), }, ), - - - # ********************** Sport Settings File Messages ********************** - 7: MessageType( - name='zones_target', - mesg_num=7, + 262: MessageType( + name='dive_alarm', + mesg_num=262, fields={ + 0: Field( + name='depth', + type=BASE_TYPES[0x86], # uint32 + def_num=0, + scale=1000, + units='m', + ), 1: Field( - name='max_heart_rate', - type=BASE_TYPES[0x02], # uint8 + name='time', + type=BASE_TYPES[0x85], # sint32 def_num=1, + units='s', ), 2: Field( - name='threshold_heart_rate', - type=BASE_TYPES[0x02], # uint8 + name='enabled', + type=FIELD_TYPES['bool'], def_num=2, ), 3: Field( - name='functional_threshold_power', - type=BASE_TYPES[0x84], # uint16 + name='alarm_type', + type=FIELD_TYPES['dive_alarm_type'], def_num=3, ), + 4: Field( + name='sound', + type=FIELD_TYPES['tone'], + def_num=4, + ), 5: Field( - name='hr_calc_type', - type=FIELD_TYPES['hr_zone_calc'], + name='dive_types', + type=FIELD_TYPES['sub_sport'], def_num=5, ), - 7: Field( - name='pwr_calc_type', - type=FIELD_TYPES['pwr_zone_calc'], - def_num=7, + 254: Field( # Index of the alarm + name='message_index', + type=FIELD_TYPES['message_index'], + def_num=254, ), }, ), - - - # ************************** Totals File Messages ************************** - 33: MessageType( - name='totals', - mesg_num=33, + 264: MessageType( + name='exercise_title', + mesg_num=264, + fields={ + 0: Field( + name='exercise_category', + type=FIELD_TYPES['exercise_category'], + def_num=0, + ), + 1: Field( + name='exercise_name', + type=BASE_TYPES[0x84], # uint16 + def_num=1, + ), + 2: Field( + name='wkt_step_name', + type=BASE_TYPES[0x07], # string + def_num=2, + ), + 254: Field( + name='message_index', + type=FIELD_TYPES['message_index'], + def_num=254, + ), + }, + ), + 268: MessageType( + name='dive_summary', + mesg_num=268, fields={ - 0: Field( # Excludes pauses - name='timer_time', - type=BASE_TYPES[0x86], # uint32 + 0: Field( + name='reference_mesg', + type=FIELD_TYPES['mesg_num'], def_num=0, - units='s', ), 1: Field( - name='distance', - type=BASE_TYPES[0x86], # uint32 + name='reference_index', + type=FIELD_TYPES['message_index'], def_num=1, - units='m', ), - 2: Field( - name='calories', + 2: Field( # 0 if above water + name='avg_depth', type=BASE_TYPES[0x86], # uint32 def_num=2, - units='kcal', + scale=1000, + units='m', ), - 3: Field( - name='sport', - type=FIELD_TYPES['sport'], + 3: Field( # 0 if above water + name='max_depth', + type=BASE_TYPES[0x86], # uint32 def_num=3, + scale=1000, + units='m', ), - 4: Field( # Includes pauses - name='elapsed_time', + 4: Field( # Time since end of last dive + name='surface_interval', type=BASE_TYPES[0x86], # uint32 def_num=4, units='s', ), 5: Field( - name='sessions', - type=BASE_TYPES[0x84], # uint16 + name='start_cns', + type=BASE_TYPES[0x02], # uint8 def_num=5, + units='percent', ), 6: Field( - name='active_time', - type=BASE_TYPES[0x86], # uint32 + name='end_cns', + type=BASE_TYPES[0x02], # uint8 def_num=6, - units='s', + units='percent', + ), + 7: Field( + name='start_n2', + type=BASE_TYPES[0x84], # uint16 + def_num=7, + units='percent', + ), + 8: Field( + name='end_n2', + type=BASE_TYPES[0x84], # uint16 + def_num=8, + units='percent', ), 9: Field( - name='sport_index', - type=BASE_TYPES[0x02], # uint8 + name='o2_toxicity', + type=BASE_TYPES[0x84], # uint16 def_num=9, + units='OTUs', ), - 253: FIELD_TYPE_TIMESTAMP, - 254: Field( - name='message_index', - type=FIELD_TYPES['message_index'], - def_num=254, + 10: Field( + name='dive_number', + type=BASE_TYPES[0x86], # uint32 + def_num=10, + ), + 11: Field( + name='bottom_time', + type=BASE_TYPES[0x86], # uint32 + def_num=11, + scale=1000, + units='s', + ), + 17: Field( # Average ascent rate, not including descents or stops + name='avg_ascent_rate', + type=BASE_TYPES[0x85], # sint32 + def_num=17, + scale=1000, + units='m/s', + ), + 22: Field( # Average descent rate, not including ascents or stops + name='avg_descent_rate', + type=BASE_TYPES[0x86], # uint32 + def_num=22, + scale=1000, + units='m/s', + ), + 23: Field( # Maximum ascent rate + name='max_ascent_rate', + type=BASE_TYPES[0x86], # uint32 + def_num=23, + scale=1000, + units='m/s', + ), + 24: Field( # Maximum descent rate + name='max_descent_rate', + type=BASE_TYPES[0x86], # uint32 + def_num=24, + scale=1000, + units='m/s', + ), + 25: Field( # Time spent neither ascending nor descending + name='hang_time', + type=BASE_TYPES[0x86], # uint32 + def_num=25, + scale=1000, + units='s', ), + 253: FIELD_TYPE_TIMESTAMP, }, ), - - - # *********************** Weight Scale File Messages *********************** - 30: MessageType( - name='weight_scale', - mesg_num=30, + 285: MessageType( + name='jump', + mesg_num=285, fields={ 0: Field( - name='weight', - type=FIELD_TYPES['weight'], + name='distance', + type=BASE_TYPES[0x88], # float32 def_num=0, - scale=100, - units='kg', + units='m', ), 1: Field( - name='percent_fat', - type=BASE_TYPES[0x84], # uint16 + name='height', + type=BASE_TYPES[0x88], # float32 def_num=1, - scale=100, - units='%', + units='m', ), 2: Field( - name='percent_hydration', - type=BASE_TYPES[0x84], # uint16 + name='rotations', + type=BASE_TYPES[0x02], # uint8 def_num=2, - scale=100, - units='%', ), 3: Field( - name='visceral_fat_mass', - type=BASE_TYPES[0x84], # uint16 + name='hang_time', + type=BASE_TYPES[0x88], # float32 def_num=3, - scale=100, - units='kg', + units='s', ), - 4: Field( - name='bone_mass', - type=BASE_TYPES[0x84], # uint16 + 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, - scale=100, - units='kg', ), 5: Field( - name='muscle_mass', - type=BASE_TYPES[0x84], # uint16 + name='position_lat', + type=BASE_TYPES[0x85], # sint32 def_num=5, - scale=100, - units='kg', + units='semicircles', + ), + 6: Field( + name='position_long', + type=BASE_TYPES[0x85], # sint32 + def_num=6, + units='semicircles', ), 7: Field( - name='basal_met', + name='speed', type=BASE_TYPES[0x84], # uint16 def_num=7, - scale=4, - units='kcal/day', + 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='physique_rating', - type=BASE_TYPES[0x02], # uint8 + name='enhanced_speed', + type=BASE_TYPES[0x86], # uint32 def_num=8, - ), - 9: Field( # ~4kJ per kcal, 0.25 allows max 16384 kcal - name='active_met', - type=BASE_TYPES[0x84], # uint16 - def_num=9, - scale=4, - units='kcal/day', - ), - 10: Field( - name='metabolic_age', - type=BASE_TYPES[0x02], # uint8 - def_num=10, - units='years', - ), - 11: Field( - name='visceral_fat_rating', - type=BASE_TYPES[0x02], # uint8 - def_num=11, - ), - 12: Field( # Associates this weight scale message to a user. This corresponds to the index of the user profile message in the weight scale file. - name='user_profile_index', - type=FIELD_TYPES['message_index'], - def_num=12, + scale=1000, + units='m/s', ), 253: FIELD_TYPE_TIMESTAMP, }, ), - - - # ************************* Workout File Messages ************************** - 26: MessageType( - name='workout', - mesg_num=26, + 317: MessageType( + name='climb_pro', + mesg_num=317, fields={ - 4: Field( - name='sport', - type=FIELD_TYPES['sport'], - def_num=4, + 0: Field( + name='position_lat', + type=BASE_TYPES[0x85], # sint32 + def_num=0, + units='semicircles', ), - 5: Field( - name='capabilities', - type=FIELD_TYPES['workout_capabilities'], - def_num=5, + 1: Field( + name='position_long', + type=BASE_TYPES[0x85], # sint32 + def_num=1, + units='semicircles', ), - 6: Field( # number of valid steps - name='num_valid_steps', - type=BASE_TYPES[0x84], # uint16 - def_num=6, + 2: Field( + name='climb_pro_event', + type=FIELD_TYPES['climb_pro_event'], + def_num=2, ), - 8: Field( - name='wkt_name', - type=BASE_TYPES[0x07], # string - def_num=8, + 3: Field( + name='climb_number', + type=BASE_TYPES[0x84], # uint16 + def_num=3, ), - 11: Field( - name='sub_sport', - type=FIELD_TYPES['sub_sport'], - def_num=11, + 4: Field( + name='climb_category', + type=BASE_TYPES[0x02], # uint8 + def_num=4, ), - 14: Field( - name='pool_length', - type=BASE_TYPES[0x84], # uint16 - def_num=14, - scale=100, + 5: Field( + name='current_dist', + type=BASE_TYPES[0x88], # float32 + def_num=5, units='m', ), - 15: Field( - name='pool_length_unit', - type=FIELD_TYPES['display_measure'], - def_num=15, - ), + 253: FIELD_TYPE_TIMESTAMP, }, ), } diff --git a/scripts/generate_profile.py b/scripts/generate_profile.py index 5d5a5fb..2b3027d 100755 --- a/scripts/generate_profile.py +++ b/scripts/generate_profile.py @@ -16,9 +16,9 @@ import re import sys import zipfile +from itertools import islice -import xlrd # Dev requirement for parsing Excel spreadsheet - +import openpyxl # Dev requirement for parsing Excel spreadsheet FIELD_NUM_TIMESTAMP = 253 @@ -60,7 +60,8 @@ def scrub_symbol_name(symbol_name): # E.g. 'hr.event_timestamp' -> FIELD_NUM_HR_EVENT_TIMESTAMP = 9 FIELD_NUM_DECLARATIONS = () -SPECIAL_FIELD_DECLARATIONS = "FIELD_TYPE_TIMESTAMP = Field(name='timestamp', type=FIELD_TYPES['date_time'], def_num=" + str(FIELD_NUM_TIMESTAMP) + ", units='s')" +SPECIAL_FIELD_DECLARATIONS = "FIELD_TYPE_TIMESTAMP = Field(name='timestamp', type=FIELD_TYPES['date_time'], def_num=" + str( + FIELD_NUM_TIMESTAMP) + ", units='s')" IGNORE_TYPE_VALUES = ( # of the form 'type_name:value_name' @@ -158,11 +159,11 @@ def __str__(self): s = 'MESSAGE_TYPES = {\n' last_group_name = None for message in sorted( - self.messages, - key=lambda mi: ( - 0 if mi.group_name.lower().startswith('common') else 1, - mi.group_name.lower(), mi.num, - ), + self.messages, + key=lambda mi: ( + 0 if mi.group_name.lower().startswith('common') else 1, + mi.group_name.lower(), mi.num, + ), ): # Group name comment if message.group_name != last_group_name: @@ -211,7 +212,8 @@ def __str__(self): return s -class FieldInfo(namedtuple('FieldInfo', ('name', 'type', 'num', 'scale', 'offset', 'units', 'components', 'subfields', 'comment'))): +class FieldInfo( + namedtuple('FieldInfo', ('name', 'type', 'num', 'scale', 'offset', 'units', 'components', 'subfields', 'comment'))): def __str__(self): if self.num == FIELD_NUM_TIMESTAMP: # Add trailing comma here because of comment @@ -242,7 +244,8 @@ def __str__(self): return s -class ComponentFieldInfo(namedtuple('ComponentFieldInfo', ('name', 'num', 'scale', 'offset', 'units', 'bits', 'bit_offset', 'accumulate'))): +class ComponentFieldInfo( + namedtuple('ComponentFieldInfo', ('name', 'num', 'scale', 'offset', 'units', 'bits', 'bit_offset', 'accumulate'))): def __str__(self): s = "ComponentField(\n" s += " name='%s',\n" % self.name @@ -260,7 +263,8 @@ def __str__(self): return s -class SubFieldInfo(namedtuple('SubFieldInfo', ('name', 'num', 'type', 'scale', 'offset', 'units', 'ref_fields', 'components', 'comment'))): +class SubFieldInfo(namedtuple('SubFieldInfo', ( +'name', 'num', 'type', 'scale', 'offset', 'units', 'ref_fields', 'components', 'comment'))): def __str__(self): s = "SubField(%s\n" % render_comment(self.comment) s += " name='%s',\n" % self.name @@ -333,24 +337,24 @@ def parse_csv_fields(data, num_expected): def parse_spreadsheet(xls_file, *sheet_names): - if isinstance(xls_file, str): - workbook = xlrd.open_workbook(xls_file) - else: - workbook = xlrd.open_workbook(file_contents=xls_file.read()) + workbook = openpyxl.load_workbook(xls_file) for sheet_name in sheet_names: - sheet = workbook.sheet_by_name(sheet_name) + sheet = workbook[sheet_name] parsed_values = [] # Strip sheet header - for n in range(1, sheet.nrows): + for row in islice(sheet.rows, 1, None): + row_values = [cell.value for cell in row] values = [] - row_values = sheet.row_values(n) if sheet_name.lower() == 'messages': # Only care about the first 14 rows for Messages row_values = row_values[:14] + # Skip the blocking information + if is_metadata_row(row_values): + continue for value in row_values: if isinstance(value, str): @@ -372,14 +376,20 @@ def parse_spreadsheet(xls_file, *sheet_names): yield parsed_values +def is_metadata_row(row_values): + label_index = 3 + return row_values[label_index] and all(v is None for v in row_values[0:label_index]) and \ + all(v is None for v in row_values[label_index + 1:]) + + def parse_types(types_rows): type_list = TypeList([]) for row in types_rows: if row[0]: - # First column means new type + # First column means new type - allow for no comments type = TypeInfo( - name=row[0].decode(), base_type=row[1].decode(), values=[], comment=row[4].decode(), + name=row[0].decode(), base_type=row[1].decode(), values=[], comment=default_comment(row[4]), ) type_list.types.append(type) assert type.name @@ -387,7 +397,7 @@ def parse_types(types_rows): else: # No first column means a value for this type - value = TypeValueInfo(name=row[2].decode(), value=maybe_decode(row[3]), comment=row[4].decode()) + value = TypeValueInfo(name=row[2].decode(), value=maybe_decode(row[3]), comment=default_comment(row[4])) if value.name and value.value is not None: # Don't add ignore keyed types @@ -407,6 +417,10 @@ def maybe_decode(o): return o +def default_comment(x): + return (x or b'').decode() + + def parse_messages(messages_rows, type_list): message_list = MessageList([]) @@ -420,13 +434,13 @@ def parse_messages(messages_rows, type_list): name = row[0].decode() message = MessageInfo( name=name, num=type_list.get_mesg_num(name), - group_name=group_name, fields=[], comment=row[13].decode(), + group_name=group_name, fields=[], comment=default_comment(row[13]), ) message_list.messages.append(message) else: # Get components if they exist components = [] - component_names = parse_csv_fields(row[5].decode(), 0) + component_names = parse_csv_fields(default_comment(row[5]), 0) if component_names and (len(component_names) != 1 or component_names[0] != ''): num_components = len(component_names) components = [ @@ -437,10 +451,10 @@ def parse_messages(messages_rows, type_list): ) for cmp_name, cmp_scale, cmp_offset, cmp_units, cmp_bits, cmp_accumulate in zip( component_names, # name - parse_csv_fields(maybe_decode(row[6]), num_components), # scale - parse_csv_fields(maybe_decode(row[7]), num_components), # offset - parse_csv_fields(maybe_decode(row[8]), num_components), # units - parse_csv_fields(maybe_decode(row[9]), num_components), # bits + parse_csv_fields(maybe_decode(row[6]), num_components), # scale + parse_csv_fields(maybe_decode(row[7]), num_components), # offset + parse_csv_fields(maybe_decode(row[8]), num_components), # units + parse_csv_fields(maybe_decode(row[9]), num_components), # bits parse_csv_fields(maybe_decode(row[10]), num_components), # accumulate ) ] @@ -455,8 +469,8 @@ def parse_messages(messages_rows, type_list): if row[1] is not None and row[1] != b'': field = FieldInfo( name=row[2].decode(), type=row[3].decode(), num=maybe_decode(row[1]), scale=fix_scale(row[6]), - offset=maybe_decode(row[7]), units=fix_units(row[8].decode()), components=[], - subfields=[], comment=row[13].decode(), + offset=maybe_decode(row[7]), units=fix_units(default_comment(row[8])), components=[], + subfields=[], comment=default_comment(row[13]), ) assert field.name @@ -475,8 +489,8 @@ def parse_messages(messages_rows, type_list): # Sub fields subfield = SubFieldInfo( name=row[2].decode(), num=field.num, type=row[3].decode(), scale=fix_scale(row[6]), - offset=maybe_decode(row[7]), units=fix_units(row[8].decode()), ref_fields=[], - components=[], comment=row[13].decode(), + offset=maybe_decode(row[7]), units=fix_units(default_comment(row[8])), ref_fields=[], + components=[], comment=default_comment(row[13]), ) ref_field_names = parse_csv_fields(row[11].decode(), 0)