From 713662e13ce2e7766bbcdc26a3c01c74d2a9a1c3 Mon Sep 17 00:00:00 2001 From: Liam Murphy Date: Sun, 25 Jun 2017 17:10:12 +0200 Subject: [PATCH 01/69] CSV tests for fenix 5 and edge 820 samples --- tests/test.py | 29 +++++++++++++++++++++++++++-- 1 file changed, 27 insertions(+), 2 deletions(-) diff --git a/tests/test.py b/tests/test.py index 6d2def7..41df2b1 100755 --- a/tests/test.py +++ b/tests/test.py @@ -230,11 +230,36 @@ def test_subfield_components(self): self.assertEqual(gear_change.get_value(field), 20) def test_parsing_edge_500_fit_file(self): - csv_fp = open(testfile('garmin-edge-500-activity-records.csv'), 'r') + self._csv_test_helper( + 'garmin-edge-500-activity.fit', + 'garmin-edge-500-activity-records.csv') + + def test_parsing_edge_500_fit_file(self): + self._csv_test_helper( + 'garmin-fenix-5-bike.fit', + 'garmin-fenix-5-bike-records.csv') + + def test_parsing_edge_500_fit_file(self): + self._csv_test_helper( + 'garmin-fenix-5-run.fit', + 'garmin-fenix-5-run-records.csv') + + def test_parsing_edge_500_fit_file(self): + self._csv_test_helper( + 'garmin-fenix-5-run.fit', + 'garmin-fenix-5-run-records.csv') + + def test_parsing_edge_500_fit_file(self): + self._csv_test_helper( + 'garmin-edge-820-bike.fit', + 'garmin-edge-820-bike-records.csv') + + def _csv_test_helper(self, fit_file, csv_file): + csv_fp = open(testfile(csv_file), 'r') csv_messages = csv.reader(csv_fp) field_names = next(csv_messages) # Consume header - f = FitFile(testfile('garmin-edge-500-activity.fit')) + f = FitFile(testfile(fit_file)) messages = f.get_messages(name='record') # For fixups From 7490cf15ef33c4c8551149eb4b9fb4d8db815004 Mon Sep 17 00:00:00 2001 From: Liam Murphy Date: Sun, 25 Jun 2017 17:41:38 +0200 Subject: [PATCH 02/69] get fenix 5 and edge 820 tests working --- tests/files/garmin-edge-820-bike-records.csv | 16 ++++++++++++++ tests/files/garmin-fenix-5-bike-records.csv | 20 ++++++++++++++++++ tests/files/garmin-fenix-5-run-records.csv | 22 ++++++++++++++++++++ tests/files/garmin-fenix-5-walk-records.csv | 18 ++++++++++++++++ tests/test.py | 17 ++++++++------- 5 files changed, 86 insertions(+), 7 deletions(-) create mode 100644 tests/files/garmin-edge-820-bike-records.csv create mode 100644 tests/files/garmin-fenix-5-bike-records.csv create mode 100644 tests/files/garmin-fenix-5-run-records.csv create mode 100644 tests/files/garmin-fenix-5-walk-records.csv diff --git a/tests/files/garmin-edge-820-bike-records.csv b/tests/files/garmin-edge-820-bike-records.csv new file mode 100644 index 0000000..e95e9f8 --- /dev/null +++ b/tests/files/garmin-edge-820-bike-records.csv @@ -0,0 +1,16 @@ +timestamp,heart_rate,cadence,speed,distance,position_lat,position_long,altitude,temperature +Mon Jun 12 09:10:15 PDT 2017,101,69,6.951,6.95,446375435,-1456338541,-17.600000000000023,13 +Mon Jun 12 09:10:20 PDT 2017,104,68,6.867,41.58,446379221,-1456338592,-17.80000000000001,13 +Mon Jun 12 09:10:22 PDT 2017,108,68,6.793,55.26,446380702,-1456338600,-17.80000000000001,13 +Mon Jun 12 09:10:23 PDT 2017,111,67,6.858,62.11,446381439,-1456338509,-17.600000000000023,13 +Mon Jun 12 09:10:24 PDT 2017,114,68,6.839,68.95,446382175,-1456338439,-17.600000000000023,13 +Mon Jun 12 09:10:25 PDT 2017,114,67,6.821,75.77,446382913,-1456338404,-17.80000000000001,13 +Mon Jun 12 09:10:34 PDT 2017,115,68,6.979,137.8,446389555,-1456338298,-17.399999999999977,13 +Mon Jun 12 09:10:43 PDT 2017,118,70,7.101,200.84,446396367,-1456338184,-17.19999999999999,13 +Mon Jun 12 09:10:44 PDT 2017,118,70,7.194,208.04,446397136,-1456338169,-17.19999999999999,13 +Mon Jun 12 09:10:53 PDT 2017,119,68,6.961,270.99,446403989,-1456338084,-17.19999999999999,13 +Mon Jun 12 09:11:02 PDT 2017,119,68,6.895,333.88,446410804,-1456338040,-17.19999999999999,13 +Mon Jun 12 09:11:11 PDT 2017,121,69,6.961,395.95,446417518,-1456338079,-17.600000000000023,13 +Mon Jun 12 09:11:13 PDT 2017,118,69,6.914,409.82,446419029,-1456338102,-17.80000000000001,13 +Mon Jun 12 09:11:16 PDT 2017,115,68,6.849,430.39,446421280,-1456338109,-17.80000000000001,13 +Mon Jun 12 09:11:20 PDT 2017,115,66,6.653,457.12,446424211,-1456338151,-17.80000000000001,13 diff --git a/tests/files/garmin-fenix-5-bike-records.csv b/tests/files/garmin-fenix-5-bike-records.csv new file mode 100644 index 0000000..26f2990 --- /dev/null +++ b/tests/files/garmin-fenix-5-bike-records.csv @@ -0,0 +1,20 @@ +timestamp,heart_rate,cadence,speed,distance,position_lat,position_long,altitude,temperature +Mon Jun 12 09:09:22 PDT 2017,77,,8.258,0.0,446332520,-1456340701,0.0,19 +Mon Jun 12 09:09:23 PDT 2017,83,,8.024,16.15,446334253,-1456340838,-1.8000000000000114,19 +Mon Jun 12 09:09:25 PDT 2017,86,,8.108,24.27,446335124,-1456340910,-2.8000000000000114,19 +Mon Jun 12 09:09:26 PDT 2017,88,,7.894,32.32,446335985,-1456341014,-2.8000000000000114,19 +Mon Jun 12 09:09:28 PDT 2017,90,,7.931,48.37,446337704,-1456341206,-4.199999999999989,19 +Mon Jun 12 09:09:30 PDT 2017,94,,8.015,64.28,446339412,-1456341307,-3.8000000000000114,19 +Mon Jun 12 09:09:33 PDT 2017,98,,7.847,89.5,446342123,-1456341329,-3.8000000000000114,19 +Mon Jun 12 09:09:38 PDT 2017,98,,8.286,131.5,446346636,-1456341447,-4.0,19 +Mon Jun 12 09:09:43 PDT 2017,101,,7.707,171.56,446350896,-1456340670,-4.399999999999977,19 +Mon Jun 12 09:09:49 PDT 2017,104,,7.586,216.12,446355537,-1456339187,-4.199999999999989,19 +Mon Jun 12 09:09:50 PDT 2017,104,,7.819,224.94,446356415,-1456338722,-4.399999999999977,19 +Mon Jun 12 09:09:52 PDT 2017,105,,6.989,240.69,446358082,-1456338322,-4.600000000000023,19 +Mon Jun 12 09:10:01 PDT 2017,106,,7.651,305.71,446365050,-1456338687,-3.6000000000000227,19 +Mon Jun 12 09:10:08 PDT 2017,103,,6.877,355.41,446370388,-1456338400,-4.199999999999989,19 +Mon Jun 12 09:10:11 PDT 2017,100,,6.83,375.67,446372566,-1456338386,-4.199999999999989,19 +Mon Jun 12 09:10:17 PDT 2017,103,,6.606,418.02,446377116,-1456338248,-3.8000000000000114,19 +Mon Jun 12 09:10:21 PDT 2017,108,,6.811,445.73,446380093,-1456338315,-4.199999999999989,19 +Mon Jun 12 09:10:22 PDT 2017,111,,6.578,452.59,446380831,-1456338298,-4.600000000000023,19 +Mon Jun 12 09:10:23 PDT 2017,114,,6.662,459.52,446381573,-1456338223,-4.600000000000023,19 diff --git a/tests/files/garmin-fenix-5-run-records.csv b/tests/files/garmin-fenix-5-run-records.csv new file mode 100644 index 0000000..29ae26d --- /dev/null +++ b/tests/files/garmin-fenix-5-run-records.csv @@ -0,0 +1,22 @@ +timestamp,heart_rate,cadence,speed,distance,position_lat,position_long,altitude,temperature +Sun Jun 11 07:34:09 PDT 2017,61,0,0.0,0.0,456099128,-1463077077,2.1999999999999886,25 +Sun Jun 11 07:34:10 PDT 2017,61,0,0.0,0.5,456099059,-1463077109,2.3999999999999773,25 +Sun Jun 11 07:34:11 PDT 2017,58,0,0.0,0.88,456099079,-1463077607,2.1999999999999886,25 +Sun Jun 11 07:34:13 PDT 2017,56,78,1.166,7.93,456098414,-1463078075,3.3999999999999773,25 +Sun Jun 11 07:34:14 PDT 2017,59,90,1.624,10.94,456098127,-1463078262,3.1999999999999886,25 +Sun Jun 11 07:34:16 PDT 2017,63,89,3.378,17.97,456097397,-1463078534,3.1999999999999886,25 +Sun Jun 11 07:34:23 PDT 2017,71,91,3.144,36.76,456095506,-1463079425,4.0,25 +Sun Jun 11 07:34:25 PDT 2017,77,90,2.986,40.84,456095112,-1463079672,3.6000000000000227,25 +Sun Jun 11 07:34:26 PDT 2017,77,95,2.911,43.29,456094880,-1463079835,3.1999999999999886,25 +Sun Jun 11 07:34:31 PDT 2017,80,90,3.126,60.74,456093205,-1463080896,2.3999999999999773,24 +Sun Jun 11 07:34:32 PDT 2017,82,90,3.144,63.67,456092911,-1463081037,2.0,24 +Sun Jun 11 07:34:34 PDT 2017,87,89,3.107,69.79,456092311,-1463081382,2.1999999999999886,24 +Sun Jun 11 07:34:36 PDT 2017,92,89,3.042,75.8,456091727,-1463081734,2.3999999999999773,24 +Sun Jun 11 07:34:38 PDT 2017,100,89,3.023,82.77,456091091,-1463082235,2.8000000000000114,24 +Sun Jun 11 07:34:39 PDT 2017,103,90,3.042,86.31,456090774,-1463082503,3.1999999999999886,24 +Sun Jun 11 07:34:42 PDT 2017,106,90,3.042,95.43,456089922,-1463083113,3.3999999999999773,24 +Sun Jun 11 07:34:45 PDT 2017,107,89,2.986,102.55,456089242,-1463083563,4.199999999999989,24 +Sun Jun 11 07:34:54 PDT 2017,110,73,2.725,122.86,456087277,-1463084768,4.399999999999977,24 +Sun Jun 11 07:34:56 PDT 2017,111,54,2.351,128.95,456086647,-1463085005,4.399999999999977,24 +Sun Jun 11 07:35:01 PDT 2017,111,95,2.379,142.1,456085522,-1463086065,5.399999999999977,24 +Sun Jun 11 07:35:06 PDT 2017,112,88,2.865,157.56,456084072,-1463087093,4.199999999999989,24 diff --git a/tests/files/garmin-fenix-5-walk-records.csv b/tests/files/garmin-fenix-5-walk-records.csv new file mode 100644 index 0000000..3442c09 --- /dev/null +++ b/tests/files/garmin-fenix-5-walk-records.csv @@ -0,0 +1,18 @@ +timestamp,heart_rate,cadence,speed,distance,position_lat,position_long,altitude,temperature +Sun Jun 11 07:32:51 PDT 2017,71,53,1.204,0.0,456107865,-1463072519,-0.8000000000000114,26 +Sun Jun 11 07:32:52 PDT 2017,71,53,1.409,1.6,456107693,-1463072572,-0.6000000000000227,26 +Sun Jun 11 07:32:56 PDT 2017,69,56,1.166,5.8,456107243,-1463072697,-0.6000000000000227,26 +Sun Jun 11 07:32:58 PDT 2017,66,58,1.054,8.28,456106976,-1463072755,-0.19999999999998863,26 +Sun Jun 11 07:33:02 PDT 2017,72,63,1.474,14.19,456106356,-1463072939,-0.19999999999998863,26 +Sun Jun 11 07:33:04 PDT 2017,76,62,1.456,16.95,456106074,-1463073060,-0.19999999999998863,26 +Sun Jun 11 07:33:06 PDT 2017,80,61,1.456,20.48,456105715,-1463073219,0.0,26 +Sun Jun 11 07:33:07 PDT 2017,81,61,1.502,22.29,456105524,-1463073261,0.0,26 +Sun Jun 11 07:33:08 PDT 2017,82,68,1.521,23.99,456105345,-1463073308,0.19999999999998863,26 +Sun Jun 11 07:33:11 PDT 2017,80,65,1.568,29.04,456104835,-1463073550,0.6000000000000227,26 +Sun Jun 11 07:33:13 PDT 2017,77,61,1.605,32.48,456104480,-1463073677,0.6000000000000227,26 +Sun Jun 11 07:33:15 PDT 2017,75,60,1.596,35.34,456104192,-1463073814,0.6000000000000227,26 +Sun Jun 11 07:33:16 PDT 2017,74,61,1.558,36.99,456104020,-1463073871,0.6000000000000227,26 +Sun Jun 11 07:33:19 PDT 2017,77,61,1.53,41.28,456103603,-1463074119,0.8000000000000114,26 +Sun Jun 11 07:33:20 PDT 2017,78,61,1.512,42.56,456103478,-1463074191,0.6000000000000227,26 +Sun Jun 11 07:33:23 PDT 2017,77,62,1.456,46.19,456103110,-1463074371,0.6000000000000227,26 +Sun Jun 11 07:33:37 PDT 2017,75,60,1.381,67.85,456100917,-1463075331,0.8000000000000114,26 diff --git a/tests/test.py b/tests/test.py index 41df2b1..76e2cf4 100755 --- a/tests/test.py +++ b/tests/test.py @@ -234,22 +234,22 @@ def test_parsing_edge_500_fit_file(self): 'garmin-edge-500-activity.fit', 'garmin-edge-500-activity-records.csv') - def test_parsing_edge_500_fit_file(self): + def test_parsing_fenix_5_bike_fit_file(self): self._csv_test_helper( 'garmin-fenix-5-bike.fit', 'garmin-fenix-5-bike-records.csv') - def test_parsing_edge_500_fit_file(self): + def test_parsing_fenix_5_run_fit_file(self): self._csv_test_helper( 'garmin-fenix-5-run.fit', 'garmin-fenix-5-run-records.csv') - def test_parsing_edge_500_fit_file(self): + def test_parsing_fenix_5_walk_fit_file(self): self._csv_test_helper( - 'garmin-fenix-5-run.fit', - 'garmin-fenix-5-run-records.csv') + 'garmin-fenix-5-walk.fit', + 'garmin-fenix-5-walk-records.csv') - def test_parsing_edge_500_fit_file(self): + def test_parsing_edge_820_fit_file(self): self._csv_test_helper( 'garmin-edge-820-bike.fit', 'garmin-edge-820-bike-records.csv') @@ -293,12 +293,15 @@ def _csv_test_helper(self, fit_file, csv_file): if isinstance(fit_value, int): csv_value = int(fit_value) + if csv_value == '': + csv_value = None if isinstance(fit_value, float): # Float comparison self.assertAlmostEqual(fit_value, float(csv_value)) else: - self.assertEqual(fit_value, csv_value) + self.assertEqual(fit_value, csv_value, + msg="For %s, FIT value '%s' did not match CSV value '%s'" % (field_name, fit_value, csv_value)) try: next(messages) From e1944f0ff4e16c0541a0a4c0a3f9a159f163a60b Mon Sep 17 00:00:00 2001 From: Carey Metcalfe Date: Sat, 1 Jul 2017 12:37:11 -0400 Subject: [PATCH 03/69] Fix issues with FitFile input type checking The previous check had some issues with specific filenames where it would think the filename was the actual content of the file. This commit reworks the type checking logic and should work consistently for file contents, file pointers, and file names for both Python2 and 3. Fixes #29 --- fitparse/base.py | 17 +++++++++++++---- tests/test.py | 12 ++++++++++++ 2 files changed, 25 insertions(+), 4 deletions(-) diff --git a/fitparse/base.py b/fitparse/base.py index 375ed5e..f08eacb 100644 --- a/fitparse/base.py +++ b/fitparse/base.py @@ -5,6 +5,7 @@ # Python 2 compat try: num_types = (int, float, long) + str = basestring except NameError: num_types = (int, float) @@ -20,11 +21,18 @@ class FitFile(object): def __init__(self, fileish, check_crc=True, data_processor=None): if hasattr(fileish, 'read'): + # BytesIO-like object self._file = fileish - elif isinstance(fileish, bytes) and fileish[8:12] == b'.FIT': - self._file = io.BytesIO(fileish) + elif isinstance(fileish, str): + # Python2 - file path, file contents in the case of a TypeError + # Python3 - file path + try: + self._file = open(fileish, 'rb') + except TypeError: + self._file = io.BytesIO(fileish) else: - self._file = open(fileish, 'rb') + # Python 3 - file contents + self._file = io.BytesIO(fileish) self.check_crc = check_crc self._processor = data_processor or FitFileDataProcessor() @@ -41,7 +49,7 @@ def __del__(self): self.close() def close(self): - if self._file and hasattr(self._file, "close"): + if hasattr(self, "_file") and self._file and hasattr(self._file, "close"): self._file.close() self._file = None @@ -416,6 +424,7 @@ def get_messages(self, name=None, with_definitions=False, as_dict=False): names = [name] # Convert any string numbers in names to ints + # TODO: Revisit Python2/3 str/bytes typecheck issues names = set([ int(n) if (isinstance(n, str) and n.isdigit()) else n for n in names diff --git a/tests/test.py b/tests/test.py index 76e2cf4..45c41f2 100755 --- a/tests/test.py +++ b/tests/test.py @@ -2,6 +2,7 @@ import csv import datetime +import io import os from struct import pack import sys @@ -397,6 +398,17 @@ def test_int_long(self): with FitFile(testfile('event_timestamp.fit')) as f: assert f.messages[-1].fields[1].raw_value == 1739.486328125 + def test_fileish_types(self): + """Test the constructor does the right thing when given different types""" + with FitFile(testfile('Settings.FIT')): + pass + with FitFile(open(testfile("Settings.fit"), 'rb')): + pass + with FitFile(open(testfile("Settings.fit"), 'rb').read()): + pass + with FitFile(io.BytesIO(open(testfile("Settings.fit"), 'rb').read())): + pass + # TODO: # * Test Processors: # - process_type_<>, process_field_<>, process_units_<>, process_message_<> From cb6b02d3ec64b111849f077b00eb47911b767369 Mon Sep 17 00:00:00 2001 From: Florian Klink Date: Tue, 15 Aug 2017 11:52:10 +0200 Subject: [PATCH 04/69] REAMDE: fix PyPi package name --- docs/index.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/index.rst b/docs/index.rst index 0220a5b..ccaa8fe 100644 --- a/docs/index.rst +++ b/docs/index.rst @@ -37,7 +37,7 @@ The easiest way to grab :mod:`fitparse` is using ``pip``, :: - $ pip install python-fitparse + $ pip install fitparse From github From 075c9a374bf1179b74068cfc2fffe6e79da34842 Mon Sep 17 00:00:00 2001 From: Florian Klink Date: Tue, 15 Aug 2017 11:52:43 +0200 Subject: [PATCH 05/69] README: use print() with parenthesis in example --- docs/index.rst | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/docs/index.rst b/docs/index.rst index ccaa8fe..78400e9 100644 --- a/docs/index.rst +++ b/docs/index.rst @@ -96,12 +96,12 @@ Here's a simple program to print all the record fields in an activity file:: # Print the records name and value (and units if it has any) if record_data.units: - print " * %s: %s %s" % ( + print(" * %s: %s %s" % ( record_data.name, record_data.value, record_data.units, - ) + )) else: - print " * %s: %s" % (record_data.name, record_data.value) - print + print(" * %s: %s" % (record_data.name, record_data.value)) + print() License From 0d6a748f71857ed28367722df55c3444c50dc13d Mon Sep 17 00:00:00 2001 From: Florian Klink Date: Mon, 21 Aug 2017 11:05:49 +0200 Subject: [PATCH 06/69] add test file for files without application id inside developer data as seen on ELEMNT BOLT (firmware version WB09-1507) --- ...o-application-id-inside-developer-data-id.fit | Bin 0 -> 5094 bytes tests/test.py | 5 +++++ 2 files changed, 5 insertions(+) create mode 100644 tests/files/elemnt-bolt-no-application-id-inside-developer-data-id.fit diff --git a/tests/files/elemnt-bolt-no-application-id-inside-developer-data-id.fit b/tests/files/elemnt-bolt-no-application-id-inside-developer-data-id.fit new file mode 100644 index 0000000000000000000000000000000000000000..810004b3d91e48602c3518a6c0e198eb6140497c GIT binary patch literal 5094 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 literal 0 HcmV?d00001 diff --git a/tests/test.py b/tests/test.py index 45c41f2..8d36db7 100755 --- a/tests/test.py +++ b/tests/test.py @@ -409,6 +409,11 @@ def test_fileish_types(self): with FitFile(io.BytesIO(open(testfile("Settings.fit"), 'rb').read())): pass + def test_elemnt_bolt_developer_data_id_without_application_id(self): + """Test that a file without application id set inside developer_data_id is parsed + (as seen on ELEMNT BOLT with firmware version WB09-1507)""" + FitFile(testfile('elemnt-bolt-no-application-id-inside-developer-data-id.fit')).parse() + # TODO: # * Test Processors: # - process_type_<>, process_field_<>, process_units_<>, process_message_<> From bb54ac80e54f47f9535136846634612dd3ab1181 Mon Sep 17 00:00:00 2001 From: Florian Klink Date: Tue, 15 Aug 2017 12:03:17 +0200 Subject: [PATCH 07/69] records: add_dev_data_id: allow developer_data_id messages without set application_id It seems like the ELEMNT bolt writes messages without application_id set. In that case, store None there. fixes #35. --- fitparse/records.py | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/fitparse/records.py b/fitparse/records.py index b6603f5..9924e68 100644 --- a/fitparse/records.py +++ b/fitparse/records.py @@ -363,7 +363,10 @@ def parse_string(string): def add_dev_data_id(message): global DEV_TYPES dev_data_index = message.get('developer_data_index').raw_value - application_id = message.get('application_id').raw_value + if message.get('application_id'): + application_id = message.get('application_id').raw_value + else: + application_id = None # Note that nothing in the spec says overwriting an existing type is invalid DEV_TYPES[dev_data_index] = {'dev_data_index': dev_data_index, 'application_id': application_id, 'fields': {}} From f97fc38932e4396435cb13c54ca2ad12ac4d7b8b Mon Sep 17 00:00:00 2001 From: Florian Klink Date: Mon, 21 Aug 2017 11:12:19 +0200 Subject: [PATCH 08/69] test: clarify test_fileish_types There was a naming problem on case-insensitive filesystems, which is why the tests refered to both 'Settings.FIT' and 'Settings.FIT', with the latter not inside git, and tests failing on all case-sensitive filesystems. Fix this by duplicating 'Settings.fit' to 'nametest.FIT', and using it inside `test_fileish_types(self)`. Also improve test documentation a bit, while adding a link to the underlying issue. --- tests/files/nametest.FIT | Bin 0 -> 1287 bytes tests/test.py | 14 +++++++++----- 2 files changed, 9 insertions(+), 5 deletions(-) create mode 100644 tests/files/nametest.FIT diff --git a/tests/files/nametest.FIT b/tests/files/nametest.FIT new file mode 100644 index 0000000000000000000000000000000000000000..13cd3334c8a33d6426f72d227db8ab4cfe77d676 GIT binary patch literal 1287 zcma)+yNeT16vn^r%$+=LvPm}CM^uCbSL0?yb{FFVETRxaSaorOh>e8?Sp-W98!d)3 z<9{GnTiQu1M6mTw*xt%cuuD95HW_Ef6!R7Hxc8jjdE7^(w&edYz{Oj4`al<|oM+w{ zGo%C}fiD3F{AwTmoT!KsxyeM-ZW{s#NI{?wv;JKljWjYp3S1oqW~_V(wQP@8=O2Bii=D%|#`esxW$Z@T zs*#bb}L9PN49 zP1*~ZQ19V=RKEeAaHvTD!H1EwI>733qrO-P_sUb;e1hfsv;gY`=8C$8&+NzD|L=H}2iu@An>HnqlKd9ciF0VWg*R2YhlI z=yp~z!@DTHO_uCDJFVj-dl3#ec%1=w^Weo`O?#G9Iz!$3Q~eKw+jy$DhY|4d(ctWv z2KuuJWCdP{J)(~^Fc(i}1zwFk<^uEabXMTC*kdkGmv*YGz{ELpp6QZ{GhT)sc7Zo2 hdd<9Ur|8;=Zv+$xy@JrwlfRZc`ZKz_(p2v^{{jjSp?&}W literal 0 HcmV?d00001 diff --git a/tests/test.py b/tests/test.py index 8d36db7..d592cbe 100755 --- a/tests/test.py +++ b/tests/test.py @@ -399,14 +399,18 @@ def test_int_long(self): assert f.messages[-1].fields[1].raw_value == 1739.486328125 def test_fileish_types(self): - """Test the constructor does the right thing when given different types""" - with FitFile(testfile('Settings.FIT')): + """Test the constructor does the right thing when given different types + (specifically, test files with 8 characters, followed by an uppercase.FIT + extension), which confused the fileish check on Python 2, see + https://github.com/dtcooper/python-fitparse/issues/29#issuecomment-312436350 + for details""" + with FitFile(testfile('nametest.FIT')): pass - with FitFile(open(testfile("Settings.fit"), 'rb')): + with FitFile(open(testfile("nametest.FIT"), 'rb')): pass - with FitFile(open(testfile("Settings.fit"), 'rb').read()): + with FitFile(open(testfile("nametest.FIT"), 'rb').read()): pass - with FitFile(io.BytesIO(open(testfile("Settings.fit"), 'rb').read())): + with FitFile(io.BytesIO(open(testfile("nametest.FIT"), 'rb').read())): pass def test_elemnt_bolt_developer_data_id_without_application_id(self): From 1636660672de4532c5b8820b4dc00da681e043f4 Mon Sep 17 00:00:00 2001 From: Florian Klink Date: Mon, 21 Aug 2017 11:21:40 +0200 Subject: [PATCH 09/69] =?UTF-8?q?test:=20fix=20ResourceWarning:=20unclosed?= =?UTF-8?q?=20file=20=E2=80=A6=20warnings?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- tests/test.py | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/tests/test.py b/tests/test.py index d592cbe..2b97af8 100755 --- a/tests/test.py +++ b/tests/test.py @@ -406,12 +406,12 @@ def test_fileish_types(self): for details""" with FitFile(testfile('nametest.FIT')): pass - with FitFile(open(testfile("nametest.FIT"), 'rb')): - pass - with FitFile(open(testfile("nametest.FIT"), 'rb').read()): - pass - with FitFile(io.BytesIO(open(testfile("nametest.FIT"), 'rb').read())): - pass + with open(testfile("nametest.FIT"), 'rb') as f: + FitFile(f) + with open(testfile("nametest.FIT"), 'rb') as f: + FitFile(f.read()) + with open(testfile("nametest.FIT"), 'rb') as f: + FitFile(io.BytesIO(f.read())) def test_elemnt_bolt_developer_data_id_without_application_id(self): """Test that a file without application id set inside developer_data_id is parsed From 2e764765fb9819bb5b2683f0b15bd91812083396 Mon Sep 17 00:00:00 2001 From: Carey Metcalfe Date: Fri, 6 Oct 2017 10:04:24 -0400 Subject: [PATCH 10/69] Only accumulate non-null values Adds a test file with null 'compressed_speed_distance' fields (the 'distance' component of them accumulates). Fixes #38 --- fitparse/base.py | 2 +- tests/files/null_compressed_speed_dist.fit | Bin 0 -> 67518 bytes tests/test.py | 2 +- 3 files changed, 2 insertions(+), 2 deletions(-) create mode 100644 tests/files/null_compressed_speed_dist.fit diff --git a/fitparse/base.py b/fitparse/base.py index f08eacb..4bcd494 100644 --- a/fitparse/base.py +++ b/fitparse/base.py @@ -334,7 +334,7 @@ def _parse_data_message(self, header): cmp_raw_value = component.render(raw_value) # Apply accumulated value - if component.accumulate: + if component.accumulate and cmp_raw_value is not None: accumulator = self._accumulators[def_mesg.mesg_num] cmp_raw_value = self._apply_compressed_accumulation( cmp_raw_value, accumulator[component.def_num], component.bits, diff --git a/tests/files/null_compressed_speed_dist.fit b/tests/files/null_compressed_speed_dist.fit new file mode 100644 index 0000000000000000000000000000000000000000..910f6d75de9fdcba18442736b28359eae3f46cac GIT binary patch literal 67518 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 rOcqlRN^kO;;qN!Y$2ZB>$CS&*%sp6W#H;c literal 0 HcmV?d00001 diff --git a/tests/test.py b/tests/test.py index 2b97af8..0149d25 100755 --- a/tests/test.py +++ b/tests/test.py @@ -376,7 +376,7 @@ def test_valid_files(self): 'antfs-dump.63.fit', 'sample-activity-indoor-trainer.fit', 'sample-activity.fit', 'garmin-fenix-5-bike.fit', 'garmin-fenix-5-run.fit', 'garmin-fenix-5-walk.fit', - 'garmin-edge-820-bike.fit'): + 'garmin-edge-820-bike.fit', 'null_compressed_speed_dist.fit'): FitFile(testfile(x)).parse() def test_units_processor(self): From 3303ab35011779b58e28a16eda268ea82e811dad Mon Sep 17 00:00:00 2001 From: Carey Metcalfe Date: Fri, 13 Oct 2017 15:17:10 -0400 Subject: [PATCH 11/69] Bump version to v1.0.1 --- fitparse/__init__.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/fitparse/__init__.py b/fitparse/__init__.py index bbe3a45..49951b3 100644 --- a/fitparse/__init__.py +++ b/fitparse/__init__.py @@ -2,7 +2,7 @@ from fitparse.processors import FitFileDataProcessor, StandardUnitsDataProcessor -__version__ = '0.0.1-dev' +__version__ = '1.0.1' __all__ = [ 'FitFileDataProcessor', 'FitFile', 'FitParseError', 'StandardUnitsDataProcessor', From 777a69376e980313c77126a6ce5491103d4b6a50 Mon Sep 17 00:00:00 2001 From: Liam Murphy Date: Mon, 8 Jan 2018 16:29:55 -0800 Subject: [PATCH 12/69] doc to explain how to update profile (#48) --- README.md | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/README.md b/README.md index 7a21e23..e4239da 100644 --- a/README.md +++ b/README.md @@ -51,6 +51,16 @@ Major Changes From Original Version implementation yet. +Updating to new FIT SDK versions +-------------------------------- +Download the latest SDK from http://www.thisisant.com/pages/products/fit-sdk + +Update the profile: +``` +python3 scripts/generate_profile.py /path/to/fit_sdk.zip fitparse/profile.py +``` + + License ------- From 654218c5a78bdac899d098b8ff125c7f4950b6c9 Mon Sep 17 00:00:00 2001 From: David Cooper Date: Tue, 23 Jan 2018 10:11:44 -0800 Subject: [PATCH 13/69] License year bump --- LICENSE | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/LICENSE b/LICENSE index a9c8da5..1f1d607 100644 --- a/LICENSE +++ b/LICENSE @@ -1,7 +1,7 @@ MIT License -Copyright (c) 2011-2017, David Cooper -Copyright (c) 2017, Carey Metcalfe +Copyright (c) 2011-2018, David Cooper +Copyright (c) 2017-2018, Carey Metcalfe Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal From 087b80b5f9e5668b5ae718f3069f2af020141828 Mon Sep 17 00:00:00 2001 From: Ondrej Medek Date: Sun, 25 Feb 2018 08:13:03 +0100 Subject: [PATCH 14/69] Add PyCharm .idea dir to .gitignore (#50) --- .gitignore | 3 +++ 1 file changed, 3 insertions(+) diff --git a/.gitignore b/.gitignore index 1786a2f..749a4c4 100644 --- a/.gitignore +++ b/.gitignore @@ -53,5 +53,8 @@ docs/_build/ # PyBuilder target/ +# Various IDEs +/.idea + # python-fitparse specific FitSDK* From 03e29619c3dc1d0f7d77fc596def1f1539124cb8 Mon Sep 17 00:00:00 2001 From: Ondrej Medek Date: Sun, 25 Feb 2018 22:35:51 +0100 Subject: [PATCH 15/69] Update README.md - FIT doc, ANT SDK link (#51) --- README.md | 28 ++++++++++++++++++---------- 1 file changed, 18 insertions(+), 10 deletions(-) diff --git a/README.md b/README.md index e4239da..b221c59 100644 --- a/README.md +++ b/README.md @@ -3,17 +3,26 @@ python-fitparse Here's a Python library to parse ANT/Garmin `.FIT` files. -Welcome to python-fitparse! After a few years of laying dormant we are back to -active development! The old version is archived as -[`v1-archive`](https://github.com/dtcooper/python-fitparse/releases/tag/v1-archive). - -The FIT (Flexible and Interoperable Data Transfer) file protocol is specified by -ANT (http://www.thisisant.com/) and an SDK is available for download at -http://www.thisisant.com/pages/products/fit-sdk. +Install from [![PyPI](https://img.shields.io/pypi/v/fitparse.svg)](https://pypi.python.org/pypi/fitparse/): +``` +pip install fitparse +``` +FIT files +------------ +- FIT files contain data stored in a binary file format. +- The FIT (Flexible and Interoperable Data Transfer) file protocol is specified + by [ANT](http://www.thisisant.com/). +- The SDK, code examples, and detailed documentation can be found in the + [ANT FIT SDK](http://www.thisisant.com/resources/fit). + Major Changes From Original Version ----------------------------------- +After a few years of laying dormant we are back to active development! +The old version is archived as +[`v1-archive`](https://github.com/dtcooper/python-fitparse/releases/tag/v1-archive). + * New, hopefully cleaner public API with a clear division between accessible and internal parts. (Still unstable and partially complete.) @@ -53,9 +62,8 @@ Major Changes From Original Version Updating to new FIT SDK versions -------------------------------- -Download the latest SDK from http://www.thisisant.com/pages/products/fit-sdk - -Update the profile: +- Download the latest [ANT FIT SDK](http://www.thisisant.com/resources/fit). +- Update the profile: ``` python3 scripts/generate_profile.py /path/to/fit_sdk.zip fitparse/profile.py ``` From 490e885c8092512acb8f2de3c1c65e219fcd4991 Mon Sep 17 00:00:00 2001 From: Carey Metcalfe Date: Sun, 25 Feb 2018 23:46:57 -0500 Subject: [PATCH 16/69] Add JSON output option to fitdump script (#45) Other minor things: - Removed non-implemented output formats - Removed the restrction on dumping non-readable formats to stdout - Allow Python to buffer the output for faster execution Fixes #41 --- fitparse/__init__.py | 3 +- scripts/fitdump | 75 ++++++++++++++++++++++++++++++-------------- 2 files changed, 53 insertions(+), 25 deletions(-) diff --git a/fitparse/__init__.py b/fitparse/__init__.py index 49951b3..1bbc49e 100644 --- a/fitparse/__init__.py +++ b/fitparse/__init__.py @@ -1,9 +1,10 @@ from fitparse.base import FitFile, FitParseError +from fitparse.records import DataMessage from fitparse.processors import FitFileDataProcessor, StandardUnitsDataProcessor __version__ = '1.0.1' __all__ = [ 'FitFileDataProcessor', 'FitFile', 'FitParseError', - 'StandardUnitsDataProcessor', + 'StandardUnitsDataProcessor', 'DataMessage' ] diff --git a/scripts/fitdump b/scripts/fitdump index 95a7e76..5068456 100755 --- a/scripts/fitdump +++ b/scripts/fitdump @@ -1,7 +1,12 @@ #!/usr/bin/env python +from __future__ import print_function import argparse +import codecs +import datetime +import json import sys +import types # Python 2 compat try: @@ -13,20 +18,21 @@ except NameError: import fitparse -def format_message(message, options): - s = message.name +def format_message(num, message, options): + s = ["{}. {}".format(num, message.name)] if options.with_defs: - s += ' [%s]' % message.type - s += '\n' + s.append(' [{}]'.format(message.type)) + s.append('\n') if message.type == 'data': for field_data in message: - s += ' * %s: %s' % (field_data.name, field_data.value) + s.append(' * {}: {}'.format(field_data.name, field_data.value)) if field_data.units: - s += ' [%s]' % field_data.units - s += '\n' + s.append(' [{}]'.format(field_data.units)) + s.append('\n') - return s + s.append('\n') + return "".join(s) def parse_args(args=None): @@ -36,11 +42,12 @@ def parse_args(args=None): ) parser.add_argument('-v', '--verbose', action='count', default=0) parser.add_argument( - '-o', '--output', type=argparse.FileType(mode='wb'), - help='File to output to.', + '-o', '--output', type=argparse.FileType(mode='w'), default="-", + help='File to output data into (defaults to stdout)', ) parser.add_argument( - '-t', '--type', choices=('csv', 'excel', 'readable'), default='readable', + # TODO: csv + '-t', '--type', choices=('readable', 'json'), default='readable', help='File type to output. (DEFAULT: %(default)s)', ) parser.add_argument( @@ -56,20 +63,36 @@ def parse_args(args=None): options = parser.parse_args(args) - if (options.type != 'readable') and not options.output: - parser.error('Please specify an output file (-o) or set --type readable') + # Work around argparse.FileType not accepting an `encoding` kwarg in + # Python < 3.4 by closing and reopening the file (unless it's stdout) + if options.output is not sys.stdout: + options.output.close() + options.output = codecs.open(options.output.name, 'w', encoding='UTF-8') - options.with_defs = (options.verbose >= 1) - options.print_messages = (options.type == 'readable') - options.print_stream = (options.output or sys.stdout) - - if not options.print_messages and (options.verbose >= 1): - options.print_messages = True - options.print_stream = sys.stdout + options.verbose = options.verbose >= 1 + options.with_defs = (options.type == "readable" and options.verbose) + options.as_dict = (options.type != "readable" and options.verbose) return options +class RecordJSONEncoder(json.JSONEncoder): + def default(self, obj): + if isinstance(obj, types.GeneratorType): + return list(obj) + if isinstance(obj, datetime.datetime): + return obj.isoformat() + if isinstance(obj, fitparse.DataMessage): + return { + "type": obj.name, + "data": { + data.name: data.value for data in obj + } + } + # Fall back to original to raise a TypeError + return super(RecordJSONEncoder, self).default(obj) + + def main(args=None): options = parse_args(args) @@ -78,14 +101,18 @@ def main(args=None): data_processor=fitparse.StandardUnitsDataProcessor(), check_crc = not(options.ignore_crc), ) - messages = fitfile.get_messages( + records = fitfile.get_messages( name=options.name, with_definitions=options.with_defs, + as_dict=options.as_dict ) - for n, message in enumerate(messages, 1): - if options.print_messages: - print('{}. {}'.format(n, format_message(message, options), file=options.print_stream)) + if options.type == "json": + json.dump(records, fp=options.output, cls=RecordJSONEncoder) + elif options.type == "readable": + options.output.writelines(format_message(n, record, options) + for n, record in enumerate(records, 1)) + if __name__ == '__main__': try: From acd54348da6fa9ffc90241c391c4246e55ea6fc5 Mon Sep 17 00:00:00 2001 From: Ondra Medek Date: Tue, 27 Feb 2018 20:29:59 +0100 Subject: [PATCH 17/69] RFCT utils.fileish_open with a write possibility --- fitparse/base.py | 17 +++--------- fitparse/utils.py | 28 +++++++++++++++++++ tests/test.py | 15 ----------- tests/test_utils.py | 66 +++++++++++++++++++++++++++++++++++++++++++++ 4 files changed, 97 insertions(+), 29 deletions(-) create mode 100644 tests/test_utils.py diff --git a/fitparse/base.py b/fitparse/base.py index 4bcd494..a37d9e0 100644 --- a/fitparse/base.py +++ b/fitparse/base.py @@ -16,23 +16,12 @@ BASE_TYPES, BASE_TYPE_BYTE, DevField, add_dev_data_id, add_dev_field_description, get_dev_type ) -from fitparse.utils import calc_crc, FitParseError, FitEOFError, FitCRCError, FitHeaderError +from fitparse.utils import calc_crc, fileish_open, FitParseError, FitEOFError, FitCRCError, FitHeaderError + class FitFile(object): def __init__(self, fileish, check_crc=True, data_processor=None): - if hasattr(fileish, 'read'): - # BytesIO-like object - self._file = fileish - elif isinstance(fileish, str): - # Python2 - file path, file contents in the case of a TypeError - # Python3 - file path - try: - self._file = open(fileish, 'rb') - except TypeError: - self._file = io.BytesIO(fileish) - else: - # Python 3 - file contents - self._file = io.BytesIO(fileish) + self._file = fileish_open(fileish, 'rb') self.check_crc = check_crc self._processor = data_processor or FitFileDataProcessor() diff --git a/fitparse/utils.py b/fitparse/utils.py index 9ff2b73..caed865 100644 --- a/fitparse/utils.py +++ b/fitparse/utils.py @@ -1,5 +1,7 @@ import re +import io + class FitParseError(ValueError): pass @@ -47,3 +49,29 @@ def scrub_method_name(method_name, convert_units=False): replace_from, '%s' % replace_to, ) return METHOD_NAME_SCRUBBER.sub('_', method_name) + + +def fileish_open(fileish, mode): + """ + Convert file-ish object to BytesIO like object. + :param fileish: the file-ihs object (str, BytesIO, bytes, file contents) + :param str mode: mode for the open function. + :rtype: BytesIO + """ + if mode is not None and any(m in mode for m in ['+', 'w', 'a', 'x']): + attr = 'write' + else: + attr = 'read' + if hasattr(fileish, attr) and hasattr(fileish, 'seek'): + # BytesIO-like object + return fileish + elif isinstance(fileish, str): + # Python2 - file path, file contents in the case of a TypeError + # Python3 - file path + try: + return open(fileish, mode) + except TypeError: + return io.BytesIO(fileish) + else: + # Python 3 - file contents + return io.BytesIO(fileish) diff --git a/tests/test.py b/tests/test.py index 0149d25..8b34082 100755 --- a/tests/test.py +++ b/tests/test.py @@ -398,21 +398,6 @@ def test_int_long(self): with FitFile(testfile('event_timestamp.fit')) as f: assert f.messages[-1].fields[1].raw_value == 1739.486328125 - def test_fileish_types(self): - """Test the constructor does the right thing when given different types - (specifically, test files with 8 characters, followed by an uppercase.FIT - extension), which confused the fileish check on Python 2, see - https://github.com/dtcooper/python-fitparse/issues/29#issuecomment-312436350 - for details""" - with FitFile(testfile('nametest.FIT')): - pass - with open(testfile("nametest.FIT"), 'rb') as f: - FitFile(f) - with open(testfile("nametest.FIT"), 'rb') as f: - FitFile(f.read()) - with open(testfile("nametest.FIT"), 'rb') as f: - FitFile(io.BytesIO(f.read())) - def test_elemnt_bolt_developer_data_id_without_application_id(self): """Test that a file without application id set inside developer_data_id is parsed (as seen on ELEMNT BOLT with firmware version WB09-1507)""" diff --git a/tests/test_utils.py b/tests/test_utils.py new file mode 100644 index 0000000..e0b6547 --- /dev/null +++ b/tests/test_utils.py @@ -0,0 +1,66 @@ +#!/usr/bin/env python + +import io +import os +import sys +import tempfile + +from fitparse.utils import fileish_open + +if sys.version_info >= (2, 7): + import unittest +else: + import unittest2 as unittest + + +def testfile(filename): + return os.path.join(os.path.dirname(os.path.realpath(__file__)), 'files', filename) + + +class UtilsTestCase(unittest.TestCase): + + def test_fileish_open_read(self): + """Test the constructor does the right thing when given different types + (specifically, test files with 8 characters, followed by an uppercase.FIT + extension), which confused the fileish check on Python 2, see + https://github.com/dtcooper/python-fitparse/issues/29#issuecomment-312436350 + for details""" + + def test_fopen(fileish): + with fileish_open(fileish, 'rb') as f: + self.assertIsNotNone(f.read(1)) + f.seek(0, os.SEEK_SET) + + test_fopen(testfile('nametest.FIT')) + with open(testfile("nametest.FIT"), 'rb') as f: + test_fopen(f) + with open(testfile("nametest.FIT"), 'rb') as f: + test_fopen(f.read()) + with open(testfile("nametest.FIT"), 'rb') as f: + test_fopen(io.BytesIO(f.read())) + + def test_fileish_open_write(self): + + def test_fopen(fileish): + with fileish_open(fileish, 'wb') as f: + f.write(b'\x12') + f.seek(0, os.SEEK_SET) + + tmpfile = tempfile.NamedTemporaryFile(prefix='fitparse-test', suffix='.FIT', delete=False) + filename = tmpfile.name + tmpfile.close() + try: + test_fopen(filename) + with open(filename, 'wb') as f: + test_fopen(f) + test_fopen(io.BytesIO()) + finally: + # remove silently + try: + os.remove(filename) + except OSError: + pass + + +if __name__ == '__main__': + unittest.main() From 5d8bb3a1a2f6a36d9bf645af3e6bf93cc62b9908 Mon Sep 17 00:00:00 2001 From: Ondra Medek Date: Wed, 7 Mar 2018 08:18:47 +0100 Subject: [PATCH 18/69] RFCT move crc computation to records.Crc, add test --- fitparse/base.py | 37 +++++++++++++++++++-------------- fitparse/records.py | 48 +++++++++++++++++++++++++++++++++++++++++++ fitparse/utils.py | 19 ----------------- tests/test.py | 9 ++++---- tests/test_records.py | 29 ++++++++++++++++++++++++++ 5 files changed, 103 insertions(+), 39 deletions(-) create mode 100644 tests/test_records.py diff --git a/fitparse/base.py b/fitparse/base.py index a37d9e0..a829735 100644 --- a/fitparse/base.py +++ b/fitparse/base.py @@ -12,11 +12,11 @@ from fitparse.processors import FitFileDataProcessor from fitparse.profile import FIELD_TYPE_TIMESTAMP, MESSAGE_TYPES from fitparse.records import ( - DataMessage, FieldData, FieldDefinition, DevFieldDefinition, DefinitionMessage, MessageHeader, - BASE_TYPES, BASE_TYPE_BYTE, DevField, + Crc, DataMessage, FieldData, FieldDefinition, DevFieldDefinition, DefinitionMessage, MessageHeader, + BASE_TYPES, BASE_TYPE_BYTE, add_dev_data_id, add_dev_field_description, get_dev_type ) -from fitparse.utils import calc_crc, fileish_open, FitParseError, FitEOFError, FitCRCError, FitHeaderError +from fitparse.utils import fileish_open, FitParseError, FitEOFError, FitCRCError, FitHeaderError class FitFile(object): @@ -24,6 +24,7 @@ def __init__(self, fileish, check_crc=True, data_processor=None): self._file = fileish_open(fileish, 'rb') self.check_crc = check_crc + self._crc = None self._processor = data_processor or FitFileDataProcessor() # Get total filesize @@ -55,12 +56,20 @@ def _read(self, size): if size <= 0: return None data = self._file.read(size) - self._crc = calc_crc(data, self._crc) + if size != len(data): + raise FitEOFError("Tried to read %d bytes from .FIT file but got %d" % (size, len(data))) + + if self.check_crc: + self._crc.update(data) self._bytes_left -= len(data) return data def _read_struct(self, fmt, endian='<', data=None, always_tuple=False): - fmt_with_endian = "%s%s" % (endian, fmt) + if fmt.startswith('<') or fmt.startswith('>'): + # fmt contains endian + fmt_with_endian = fmt + else: + fmt_with_endian = "%s%s" % (endian, fmt) size = struct.calcsize(fmt_with_endian) if size <= 0: raise FitParseError("Invalid struct format: %s" % fmt_with_endian) @@ -68,21 +77,19 @@ def _read_struct(self, fmt, endian='<', data=None, always_tuple=False): if data is None: data = self._read(size) - if size != len(data): - raise FitEOFError("Tried to read %d bytes from .FIT file but got %d" % (size, len(data))) - unpacked = struct.unpack(fmt_with_endian, data) # Flatten tuple if it's got only one value return unpacked if (len(unpacked) > 1) or always_tuple else unpacked[0] def _read_and_assert_crc(self, allow_zero=False): # CRC Calculation is little endian from SDK - crc_expected, crc_actual = self._crc, self._read_struct('H') - - if (crc_actual != crc_expected) and not (allow_zero and (crc_actual == 0)): - if self.check_crc: - raise FitCRCError('CRC Mismatch [expected = 0x%04X, actual = 0x%04X]' % ( - crc_expected, crc_actual)) + crc_computed, crc_read = self._crc.value, self._read_struct(Crc.FMT) + if not self.check_crc: + return + if crc_computed == crc_read or (allow_zero and crc_read == 0): + return + raise FitCRCError('CRC Mismatch [computed: %s, read: %s]' % ( + Crc.format(crc_computed), Crc.format(crc_read))) ########## # Private Data Parsing Methods @@ -94,7 +101,7 @@ def _parse_file_header(self): self._bytes_left = -1 self._complete = False self._compressed_ts_accumulator = 0 - self._crc = 0 + self._crc = Crc() self._local_mesgs = {} self._messages = [] diff --git a/fitparse/records.py b/fitparse/records.py index 9924e68..96f3dfb 100644 --- a/fitparse/records.py +++ b/fitparse/records.py @@ -4,8 +4,10 @@ # Python 2 compat try: int_types = (int, long,) + byte_iter = bytearray except NameError: int_types = (int,) + byte_iter = lambda x: x try: from itertools import zip_longest @@ -331,6 +333,52 @@ def render(self, raw_value): return raw_value +class Crc(object): + """FIT file CRC computation.""" + + CRC_TABLE = ( + 0x0000, 0xCC01, 0xD801, 0x1400, 0xF001, 0x3C00, 0x2800, 0xE401, + 0xA001, 0x6C00, 0x7800, 0xB401, 0x5000, 0x9C01, 0x8801, 0x4400, + ) + + FMT = '' % (self.__class__.__name__, self.value or "-") + + def __str__(self): + return self.format(self.value) + + def update(self, byte_arr): + """Read bytes and update the CRC computed.""" + if byte_arr: + self.value = self.calculate(byte_arr, self.value) + + @staticmethod + def format(value): + """Format CRC value to string.""" + return '0x%04X' % value + + @classmethod + def calculate(cls, byte_arr, crc=0): + """Compute CRC for input bytes.""" + for byte in byte_iter(byte_arr): + # Taken verbatim from FIT SDK docs + tmp = cls.CRC_TABLE[crc & 0xF] + crc = (crc >> 4) & 0x0FFF + crc = crc ^ tmp ^ cls.CRC_TABLE[byte & 0xF] + + tmp = cls.CRC_TABLE[crc & 0xF] + crc = (crc >> 4) & 0x0FFF + crc = crc ^ tmp ^ cls.CRC_TABLE[(byte >> 4) & 0xF] + return crc + + def parse_string(string): try: end = string.index(0x00) diff --git a/fitparse/utils.py b/fitparse/utils.py index caed865..9f4a367 100644 --- a/fitparse/utils.py +++ b/fitparse/utils.py @@ -16,25 +16,6 @@ class FitHeaderError(FitParseError): pass -CRC_TABLE = ( - 0x0000, 0xCC01, 0xD801, 0x1400, 0xF001, 0x3C00, 0x2800, 0xE401, - 0xA001, 0x6C00, 0x7800, 0xB401, 0x5000, 0x9C01, 0x8801, 0x4400, -) - - -def calc_crc(byte_arr, crc=0): - for byte in bytearray(byte_arr): - # Taken verbatim from FIT SDK docs - tmp = CRC_TABLE[crc & 0xF] - crc = (crc >> 4) & 0x0FFF - crc = crc ^ tmp ^ CRC_TABLE[byte & 0xF] - - tmp = CRC_TABLE[crc & 0xF] - crc = (crc >> 4) & 0x0FFF - crc = crc ^ tmp ^ CRC_TABLE[(byte >> 4) & 0xF] - return crc - - METHOD_NAME_SCRUBBER = re.compile(r'\W|^(?=\d)') UNIT_NAME_TO_FUNC_REPLACEMENTS = ( ('/', ' per '), diff --git a/tests/test.py b/tests/test.py index 8b34082..8711e8d 100755 --- a/tests/test.py +++ b/tests/test.py @@ -2,15 +2,14 @@ import csv import datetime -import io import os from struct import pack import sys from fitparse import FitFile from fitparse.processors import UTC_REFERENCE, StandardUnitsDataProcessor -from fitparse.records import BASE_TYPES -from fitparse.utils import calc_crc, FitEOFError, FitCRCError, FitHeaderError +from fitparse.records import BASE_TYPES, Crc +from fitparse.utils import FitEOFError, FitCRCError, FitHeaderError if sys.version_info >= (2, 7): import unittest @@ -65,8 +64,8 @@ def generate_fitfile(data=None, endian='<'): # Prototcol version 1.0, profile version 1.52 header = pack('<2BHI4s', 14, 16, 152, len(fit_data), b'.FIT') - file_data = header + pack('= (2, 7): + import unittest +else: + import unittest2 as unittest + + +class RecordsTestCase(unittest.TestCase): + def test_crc(self): + crc = Crc() + self.assertEqual(0, crc.value) + crc.update(b'\x0e\x10\x98\x00(\x00\x00\x00.FIT') + self.assertEqual(0xace7, crc.value) + # 0 must not change the crc + crc.update(0) + self.assertEqual(0xace7, crc.value) + + def test_crc_format(self): + self.assertEqual('0x0000', Crc.format(0)) + self.assertEqual('0x12AB', Crc.format(0x12AB)) + + +if __name__ == '__main__': + unittest.main() From bef76231a1c8dddfafc23070b43684e7d0c6e916 Mon Sep 17 00:00:00 2001 From: Ondra Medek Date: Thu, 12 Apr 2018 21:56:26 +0200 Subject: [PATCH 19/69] FitFile._read_struct does not allow endian in fmt Like before 5d8bb3a1a2 And microoptimization for string concat --- fitparse/base.py | 11 ++--------- fitparse/records.py | 2 +- tests/test.py | 4 ++-- 3 files changed, 5 insertions(+), 12 deletions(-) diff --git a/fitparse/base.py b/fitparse/base.py index a829735..0e6abbe 100644 --- a/fitparse/base.py +++ b/fitparse/base.py @@ -65,11 +65,7 @@ def _read(self, size): return data def _read_struct(self, fmt, endian='<', data=None, always_tuple=False): - if fmt.startswith('<') or fmt.startswith('>'): - # fmt contains endian - fmt_with_endian = fmt - else: - fmt_with_endian = "%s%s" % (endian, fmt) + fmt_with_endian = endian + fmt size = struct.calcsize(fmt_with_endian) if size <= 0: raise FitParseError("Invalid struct format: %s" % fmt_with_endian) @@ -247,10 +243,7 @@ def _parse_raw_values_from_data_message(self, def_mesg): base_type = field_def.base_type is_byte = base_type.name == 'byte' # Struct to read n base types (field def size / base type size) - struct_fmt = '%d%s' % ( - field_def.size / base_type.size, - base_type.fmt, - ) + struct_fmt = str(int(field_def.size / base_type.size)) + base_type.fmt # Extract the raw value, ask for a tuple if it's a byte type raw_value = self._read_struct( diff --git a/fitparse/records.py b/fitparse/records.py index 96f3dfb..71edc93 100644 --- a/fitparse/records.py +++ b/fitparse/records.py @@ -341,7 +341,7 @@ class Crc(object): 0xA001, 0x6C00, 0x7800, 0xB401, 0x5000, 0x9C01, 0x8801, 0x4400, ) - FMT = ' Date: Wed, 25 Apr 2018 09:15:40 +0200 Subject: [PATCH 20/69] FitFile.get_messages remove parsing names to int, remove Python 2 str shim Use utils.is_iterable and use set for quicker in test --- fitparse/base.py | 16 ++++------------ fitparse/utils.py | 11 +++++++++-- tests/test_utils.py | 12 +++++++++++- 3 files changed, 24 insertions(+), 15 deletions(-) diff --git a/fitparse/base.py b/fitparse/base.py index 0e6abbe..125d620 100644 --- a/fitparse/base.py +++ b/fitparse/base.py @@ -5,7 +5,6 @@ # Python 2 compat try: num_types = (int, float, long) - str = basestring except NameError: num_types = (int, float) @@ -16,7 +15,7 @@ BASE_TYPES, BASE_TYPE_BYTE, add_dev_data_id, add_dev_field_description, get_dev_type ) -from fitparse.utils import fileish_open, FitParseError, FitEOFError, FitCRCError, FitHeaderError +from fitparse.utils import fileish_open, is_iterable, FitParseError, FitEOFError, FitCRCError, FitHeaderError class FitFile(object): @@ -407,17 +406,10 @@ def get_messages(self, name=None, with_definitions=False, as_dict=False): as_dict = False if name is not None: - if isinstance(name, (tuple, list)): - names = name + if is_iterable(name): + names = set(name) else: - names = [name] - - # Convert any string numbers in names to ints - # TODO: Revisit Python2/3 str/bytes typecheck issues - names = set([ - int(n) if (isinstance(n, str) and n.isdigit()) else n - for n in names - ]) + names = set((name,)) def should_yield(message): if with_definitions or message.type == 'data': diff --git a/fitparse/utils.py b/fitparse/utils.py index 9f4a367..d3e427a 100644 --- a/fitparse/utils.py +++ b/fitparse/utils.py @@ -1,6 +1,6 @@ -import re - import io +import re +from collections import Iterable class FitParseError(ValueError): @@ -56,3 +56,10 @@ def fileish_open(fileish, mode): else: # Python 3 - file contents return io.BytesIO(fileish) + + +def is_iterable(obj): + """Check, if the obj is iterable but not string or bytes. + :rtype bool""" + # Speed: do not use iter() although it's more robust, see also https://stackoverflow.com/questions/1952464/ + return isinstance(obj, Iterable) and not isinstance(obj, (str, bytes)) diff --git a/tests/test_utils.py b/tests/test_utils.py index e0b6547..966548c 100644 --- a/tests/test_utils.py +++ b/tests/test_utils.py @@ -5,7 +5,7 @@ import sys import tempfile -from fitparse.utils import fileish_open +from fitparse.utils import fileish_open, is_iterable if sys.version_info >= (2, 7): import unittest @@ -61,6 +61,16 @@ def test_fopen(fileish): except OSError: pass + def test_is_iterable(self): + self.assertFalse(is_iterable(None)) + self.assertFalse(is_iterable(1)) + self.assertFalse(is_iterable('1')) + self.assertFalse(is_iterable(b'1')) + + self.assertTrue(is_iterable((1, 2))) + self.assertTrue(is_iterable([1, 2])) + self.assertTrue(is_iterable(range(2))) + if __name__ == '__main__': unittest.main() From e1e6fd46bf51ad76a62eeb7c66a90f73a314eaf4 Mon Sep 17 00:00:00 2001 From: Jean-Charles Lefebvre Date: Wed, 18 Jul 2018 11:23:38 +0200 Subject: [PATCH 21/69] should fix #69 --- fitparse/base.py | 5 ++++- fitparse/records.py | 10 +++++++++- 2 files changed, 13 insertions(+), 2 deletions(-) diff --git a/fitparse/base.py b/fitparse/base.py index 125d620..937d021 100644 --- a/fitparse/base.py +++ b/fitparse/base.py @@ -319,7 +319,10 @@ def _parse_data_message(self, header): if field.components: for component in field.components: # Render its raw value - cmp_raw_value = component.render(raw_value) + try: + cmp_raw_value = component.render(raw_value) + except ValueError: + continue # Apply accumulated value if component.accumulate and cmp_raw_value is not None: diff --git a/fitparse/records.py b/fitparse/records.py index 71edc93..46a3d99 100644 --- a/fitparse/records.py +++ b/fitparse/records.py @@ -299,7 +299,7 @@ class SubField(FieldAndSubFieldBase): class DevField(FieldAndSubFieldBase): __slots__ = ('dev_data_index', 'def_num', 'type', 'name', 'units', 'native_field_num', # The rest of these are just to be compatible with Field objects. They're always None - 'scale', 'offset', 'components', 'subfields') + 'scale', 'offset', 'components', 'subfields') field_type = 'devfield' @@ -318,6 +318,14 @@ def render(self, raw_value): # If it's a tuple, then it's a byte array and unpack it as such # (only type that uses this is compressed speed/distance) if isinstance(raw_value, tuple): + # Profile.xls sometimes contains more components than the read raw + # value is able to hold (typically the *event_timestamp_12* field in + # *hr* messages). + # This test allows to ensure *unpacked_num* is not right-shifted + # more than necessary. + if self.bit_offset and self.bit_offset >= len(raw_value) << 3: + raise ValueError() + unpacked_num = 0 # Unpack byte array as little endian From 90e27771e40ac7c18cd8603ea991e94b4a1abab4 Mon Sep 17 00:00:00 2001 From: Jean-Charles Lefebvre Date: Wed, 18 Jul 2018 11:26:20 +0200 Subject: [PATCH 22/69] FIT strings are not always null-terminated --- fitparse/records.py | 22 +++++++++++++++++----- 1 file changed, 17 insertions(+), 5 deletions(-) diff --git a/fitparse/records.py b/fitparse/records.py index 46a3d99..56a3b4c 100644 --- a/fitparse/records.py +++ b/fitparse/records.py @@ -389,11 +389,23 @@ def calculate(cls, byte_arr, crc=0): def parse_string(string): try: - end = string.index(0x00) - except TypeError: # Python 2 compat - end = string.index('\x00') - - return string[:end].decode('utf-8', errors='replace') or None + try: + s = string[:string.index(0x00)] + except TypeError: # Python 2 compat + s = string[:string.index('\x00')] + except ValueError: + # FIT specification defines the 'string' type as follows: "Null + # terminated string encoded in UTF-8 format". + # + # However 'string' values are not always null-terminated when encoded, + # according to FIT files created by Garmin devices (e.g. DEVICE.FIT file + # from a fenix3). + # + # So in order to be more flexible, in case index() could not find any + # null byte, we just decode the whole bytes-like object. + s = string + + return s.decode(encoding='utf-8', errors='replace') or None # The default base type BASE_TYPE_BYTE = BaseType(name='byte', identifier=0x0D, fmt='B', parse=lambda x: None if all(b == 0xFF for b in x) else x) From 1df75d676b8e4409d6e7c917708076a58cae0aa2 Mon Sep 17 00:00:00 2001 From: Jean-Charles Lefebvre Date: Wed, 18 Jul 2018 11:29:11 +0200 Subject: [PATCH 23/69] added support of new int64 types --- fitparse/records.py | 3 +++ scripts/generate_profile.py | 21 +++++++++++++++++---- 2 files changed, 20 insertions(+), 4 deletions(-) diff --git a/fitparse/records.py b/fitparse/records.py index 56a3b4c..d007f0a 100644 --- a/fitparse/records.py +++ b/fitparse/records.py @@ -425,6 +425,9 @@ def parse_string(string): 0x8B: BaseType(name='uint16z', identifier=0x8B, fmt='H', parse=lambda x: None if x == 0x0 else x), 0x8C: BaseType(name='uint32z', identifier=0x8C, fmt='I', parse=lambda x: None if x == 0x0 else x), 0x0D: BASE_TYPE_BYTE, + 0x8E: BaseType(name='sint64', identifier=0x8E, fmt='q', parse=lambda x: None if x == 0x7FFFFFFFFFFFFFFF else x), + 0x8F: BaseType(name='uint64', identifier=0x8F, fmt='Q', parse=lambda x: None if x == 0xFFFFFFFFFFFFFFFF else x), + 0x90: BaseType(name='uint64z', identifier=0x90, fmt='Q', parse=lambda x: None if x == 0 else x), } diff --git a/scripts/generate_profile.py b/scripts/generate_profile.py index 52e5c00..b50065c 100755 --- a/scripts/generate_profile.py +++ b/scripts/generate_profile.py @@ -52,10 +52,23 @@ def header(header, indent=0): ) BASE_TYPES = { - 'enum': '0x00', 'sint8': '0x01', 'uint8': '0x02', 'sint16': '0x83', - 'uint16': '0x84', 'sint32': '0x85', 'uint32': '0x86', 'string': '0x07', - 'float32': '0x88', 'float64': '0x89', 'uint8z': '0x0A', 'uint16z': '0x8B', - 'uint32z': '0x8C', 'byte': '0x0D', + 'enum': '0x00', + 'sint8': '0x01', + 'uint8': '0x02', + 'sint16': '0x83', + 'uint16': '0x84', + 'sint32': '0x85', + 'uint32': '0x86', + 'string': '0x07', + 'float32': '0x88', + 'float64': '0x89', + 'uint8z': '0x0A', + 'uint16z': '0x8B', + 'uint32z': '0x8C', + 'byte': '0x0D', + 'sint64': '0x8E', + 'uint64': '0x8F', + 'uint64z': '0x90', } From f64d7b4c27b52fbaed9906ac3c4c90591b58b4d4 Mon Sep 17 00:00:00 2001 From: Jean-Charles Lefebvre Date: Wed, 18 Jul 2018 11:33:44 +0200 Subject: [PATCH 24/69] generate_profile: minor improvements and cleanup --- scripts/generate_profile.py | 36 +++++++++++++++++++----------------- 1 file changed, 19 insertions(+), 17 deletions(-) diff --git a/scripts/generate_profile.py b/scripts/generate_profile.py index b50065c..b11e900 100755 --- a/scripts/generate_profile.py +++ b/scripts/generate_profile.py @@ -20,6 +20,8 @@ import xlrd # Dev requirement for parsing Excel spreadsheet +FIELD_NUM_TIMESTAMP = 253 + XLS_HEADER_MAGIC = b'\xD0\xCF\x11\xE0\xA1\xB1\x1A\xE1' @@ -42,7 +44,7 @@ def header(header, indent=0): BASE_TYPES, )''' -SPECIAL_FIELD_DECLARTIONS = "FIELD_TYPE_TIMESTAMP = Field(name='timestamp', type=FIELD_TYPES['date_time'], def_num=253, 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' @@ -179,7 +181,7 @@ def __str__(self): class FieldInfo(namedtuple('FieldInfo', ('name', 'type', 'num', 'scale', 'offset', 'units', 'components', 'subfields', 'comment'))): def __str__(self): - if self.num == 253: + if self.num == FIELD_NUM_TIMESTAMP: # Add trailing comma here because of comment assert not self.components and not self.subfields return 'FIELD_TYPE_TIMESTAMP,%s' % render_comment(self.comment) @@ -372,6 +374,7 @@ def maybe_decode(o): return o.decode() return o + def parse_messages(messages_rows, type_list): message_list = MessageList([]) @@ -402,10 +405,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 ) ] @@ -415,12 +418,12 @@ def parse_messages(messages_rows, type_list): assert component.name assert component.bits - # Otherwise a field + # Otherwise a field # Not a subfield if first row has definition num 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=row[7], units=fix_units(row[8].decode()), components=[], + offset=maybe_decode(row[7]), units=fix_units(row[8].decode()), components=[], subfields=[], comment=row[13].decode(), ) @@ -438,7 +441,7 @@ 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=row[7], units=fix_units(row[8].decode()), ref_fields=[], + offset=maybe_decode(row[7]), units=fix_units(row[8].decode()), ref_fields=[], components=[], comment=row[13].decode(), ) @@ -460,7 +463,7 @@ def parse_messages(messages_rows, type_list): ) assert len(subfield.ref_fields) == len(ref_field_names) - if not "alert_type" in ref_field_names: + if "alert_type" not in ref_field_names: field.subfields.append(subfield) # Resolve reference fields for subfields and components @@ -524,9 +527,9 @@ def main(input_xls_or_zip, output_py_path=None): output = '\n'.join([ "\n%s" % PROFILE_HEADER_FIRST_PART, - header('EXPORTED PROFILE FROM %s AT %s' % ( + header('EXPORTED PROFILE FROM %s ON %s' % ( ('SDK VERSION %s' % profile_version) if profile_version else 'SPREADSHEET', - datetime.datetime.now().strftime("%Y-%m-%d %H:%M:%S"), + datetime.datetime.now().strftime('%Y-%m-%d'), )), header('PARSED %d TYPES (%d VALUES), %d MESSAGES (%d FIELDS)' % ( len(type_list.types), sum(len(ti.values) for ti in type_list.types), @@ -543,17 +546,16 @@ def main(input_xls_or_zip, output_py_path=None): if output_py_path: open(output_py_path, 'w').write(output) - print("Profile%s written to %s", - ' version %s' % profile_version if profile_version else '', - output_py_path - ) + print('Profile version %s written to %s' % ( + profile_version if profile_version else '', + output_py_path)) else: print(output.strip()) if __name__ == '__main__': if len(sys.argv) < 2: - print("Usage: %s [profile.py]", os.path.basename(__file__)) + print("Usage: %s [profile.py]" % os.path.basename(__file__)) sys.exit(0) xls = sys.argv[1] From 512096251caecd118cb755497b570ab50482bb38 Mon Sep 17 00:00:00 2001 From: Jean-Charles Lefebvre Date: Wed, 18 Jul 2018 11:35:15 +0200 Subject: [PATCH 25/69] generate_profile: MESSAGE_NUM_DECLARATIONS and FIELD_NUM_DECLARATIONS features --- scripts/generate_profile.py | 67 +++++++++++++++++++++++++++++++++++-- 1 file changed, 64 insertions(+), 3 deletions(-) diff --git a/scripts/generate_profile.py b/scripts/generate_profile.py index b11e900..d4f72be 100755 --- a/scripts/generate_profile.py +++ b/scripts/generate_profile.py @@ -24,9 +24,15 @@ XLS_HEADER_MAGIC = b'\xD0\xCF\x11\xE0\xA1\xB1\x1A\xE1' +SYMBOL_NAME_SCRUBBER = re.compile(r'\W|^(?=\d)') + def header(header, indent=0): - return '%s%s' % (' ' * indent, (' %s ' % header).center(78 - indent, '#')) + return '%s# %s' % (' ' * indent, (' %s ' % header).center(78 - indent, '*')) + + +def scrub_symbol_name(symbol_name): + return SYMBOL_NAME_SCRUBBER.sub('_', symbol_name) PROFILE_HEADER_FIRST_PART = "%s\n%s" % ( @@ -44,6 +50,16 @@ def header(header, indent=0): BASE_TYPES, )''' +# This allows to prepend the declaration of some message numbers to the +# generated file. +# E.g. 'hr' -> MESG_NUM_HR = 132 +MESSAGE_NUM_DECLARATIONS = () + +# This allows to prepend the declaration of some field numbers of specific +# messages to the generated file. +# 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')" IGNORE_TYPE_VALUES = ( @@ -158,6 +174,22 @@ def __str__(self): s += '}' return s + def get_by_name(self, mesg_name): + for mesg in self.messages: + if mesg.name == mesg_name: + return mesg + + raise ValueError('message "%s" not found' % mesg_name) + + def get_field_by_name(self, mesg_name, field_name): + mesg = self.get_by_name(mesg_name) + + for field in mesg.fields: + if field.name == field_name: + return mesg, field + + raise ValueError('field "%s" not found in message "%s"' % (field_name, mesg_name)) + class MessageInfo(namedtuple('MessageInfo', ('name', 'num', 'group_name', 'fields', 'comment'))): def get(self, field_name): @@ -525,6 +557,27 @@ def main(input_xls_or_zip, output_py_path=None): type_list = parse_types(types_rows) message_list = parse_messages(messages_rows, type_list) + mesg_num_declarations = [] + for mesg_name in MESSAGE_NUM_DECLARATIONS: + mesg_info = message_list.get_by_name(mesg_name) + + mesg_num_declarations.append('MESG_NUM_%s = %s' % ( + scrub_symbol_name(mesg_name).upper(), + str(mesg_info.num) if mesg_info else 'None')) + + field_num_declarations = [ + 'FIELD_NUM_TIMESTAMP = ' + str(FIELD_NUM_TIMESTAMP)] + for field_fqn in FIELD_NUM_DECLARATIONS: + mesg_name, field_name = field_fqn.split('.', maxsplit=1) + mesg_info, field_info = message_list.get_field_by_name(mesg_name, field_name) + + field_decl = 'FIELD_NUM_%s_%s = %s' % ( + scrub_symbol_name(mesg_name).upper(), + scrub_symbol_name(field_name).upper(), + str(field_info.num)) + + field_num_declarations.append(field_decl) + output = '\n'.join([ "\n%s" % PROFILE_HEADER_FIRST_PART, header('EXPORTED PROFILE FROM %s ON %s' % ( @@ -535,9 +588,17 @@ def main(input_xls_or_zip, output_py_path=None): len(type_list.types), sum(len(ti.values) for ti in type_list.types), len(message_list.messages), sum(len(mi.fields) for mi in message_list.messages), )), - '', IMPORT_HEADER, '\n', + '', IMPORT_HEADER + ]) + '\n' + + if mesg_num_declarations: + output += '\n\n' + '\n'.join(mesg_num_declarations) + '\n' + if field_num_declarations: + output += '\n\n' + '\n'.join(field_num_declarations) + '\n' + + output += '\n\n' + '\n'.join([ str(type_list), '\n', - SPECIAL_FIELD_DECLARTIONS, '\n', + SPECIAL_FIELD_DECLARATIONS, '\n', str(message_list), '' ]) From 5c374cec40376a3aa6dff848715384bb424392f5 Mon Sep 17 00:00:00 2001 From: Jean-Charles Lefebvre Date: Wed, 18 Jul 2018 11:36:41 +0200 Subject: [PATCH 26/69] upgraded FIT profile from v20.33 to v20.66 --- fitparse/profile.py | 22045 +++++++++++++++++++++++------------------- 1 file changed, 12074 insertions(+), 9971 deletions(-) diff --git a/fitparse/profile.py b/fitparse/profile.py index 3e59617..ad4fe6b 100644 --- a/fitparse/profile.py +++ b/fitparse/profile.py @@ -1,9971 +1,12074 @@ -################# BEGIN AUTOMATICALLY GENERATED FIT PROFILE ################## -########################### DO NOT EDIT THIS FILE ############################ -####### EXPORTED PROFILE FROM SDK VERSION 20.33 AT 2017-05-17 22:36:12 ####### -########## PARSED 118 TYPES (1699 VALUES), 76 MESSAGES (950 FIELDS) ########## - -from fitparse.records import ( - ComponentField, - Field, - FieldType, - MessageType, - ReferenceField, - SubField, - BASE_TYPES, -) - - -FIELD_TYPES = { - 'activity': FieldType( - name='activity', - base_type=BASE_TYPES[0x00], # enum - values={ - 0: 'manual', - 1: 'auto_multi_sport', - }, - ), - 'activity_class': FieldType( - name='activity_class', - base_type=BASE_TYPES[0x00], # enum - values={ - 100: 'level_max', - 0x7F: 'level', # 0 to 100 - 0x80: 'athlete', - }, - ), - 'activity_level': FieldType( - name='activity_level', - base_type=BASE_TYPES[0x00], # enum - values={ - 0: 'low', - 1: 'medium', - 2: 'high', - }, - ), - 'activity_subtype': FieldType( - name='activity_subtype', - base_type=BASE_TYPES[0x00], # enum - values={ - 0: 'generic', - 1: 'treadmill', # Run - 2: 'street', # Run - 3: 'trail', # Run - 4: 'track', # Run - 5: 'spin', # Cycling - 6: 'indoor_cycling', # Cycling - 7: 'road', # Cycling - 8: 'mountain', # Cycling - 9: 'downhill', # Cycling - 10: 'recumbent', # Cycling - 11: 'cyclocross', # Cycling - 12: 'hand_cycling', # Cycling - 13: 'track_cycling', # Cycling - 14: 'indoor_rowing', # Fitness Equipment - 15: 'elliptical', # Fitness Equipment - 16: 'stair_climbing', # Fitness Equipment - 17: 'lap_swimming', # Swimming - 18: 'open_water', # Swimming - 254: 'all', - }, - ), - 'activity_type': FieldType( - name='activity_type', - base_type=BASE_TYPES[0x00], # enum - values={ - 0: 'generic', - 1: 'running', - 2: 'cycling', - 3: 'transition', # Mulitsport transition - 4: 'fitness_equipment', - 5: 'swimming', - 6: 'walking', - 8: 'sedentary', - 254: 'all', # All is for goals only to include all sports. - }, - ), - 'analog_watchface_layout': FieldType( - name='analog_watchface_layout', - base_type=BASE_TYPES[0x00], # enum - values={ - 0: 'minimal', - 1: 'traditional', - 2: 'modern', - }, - ), - 'ant_network': FieldType( - name='ant_network', - base_type=BASE_TYPES[0x00], # enum - values={ - 0: 'public', - 1: 'antplus', - 2: 'antfs', - 3: 'private', - }, - ), - 'antplus_device_type': FieldType( - name='antplus_device_type', - base_type=BASE_TYPES[0x02], # uint8 - values={ - 1: 'antfs', - 11: 'bike_power', - 12: 'environment_sensor_legacy', - 15: 'multi_sport_speed_distance', - 16: 'control', - 17: 'fitness_equipment', - 18: 'blood_pressure', - 19: 'geocache_node', - 20: 'light_electric_vehicle', - 25: 'env_sensor', - 26: 'racquet', - 27: 'control_hub', - 31: 'muscle_oxygen', - 35: 'bike_light_main', - 36: 'bike_light_shared', - 38: 'exd', - 40: 'bike_radar', - 119: 'weight_scale', - 120: 'heart_rate', - 121: 'bike_speed_cadence', - 122: 'bike_cadence', - 123: 'bike_speed', - 124: 'stride_speed_distance', - }, - ), - 'attitude_stage': FieldType( - name='attitude_stage', - base_type=BASE_TYPES[0x00], # enum - values={ - 0: 'failed', - 1: 'aligning', - 2: 'degraded', - 3: 'valid', - }, - ), - 'attitude_validity': FieldType( - name='attitude_validity', - base_type=BASE_TYPES[0x84], # uint16 - values={ - 0x0001: 'track_angle_heading_valid', - 0x0002: 'pitch_valid', - 0x0004: 'roll_valid', - 0x0008: 'lateral_body_accel_valid', - 0x0010: 'normal_body_accel_valid', - 0x0020: 'turn_rate_valid', - 0x0040: 'hw_fail', - 0x0080: 'mag_invalid', - 0x0100: 'no_gps', - 0x0200: 'gps_invalid', - 0x0400: 'solution_coasting', - 0x0800: 'true_track_angle', - 0x1000: 'magnetic_heading', - }, - ), - 'auto_activity_detect': FieldType( - name='auto_activity_detect', - base_type=BASE_TYPES[0x86], # uint32 - values={ - 0x00000000: 'none', - 0x00000001: 'running', - 0x00000002: 'cycling', - 0x00000004: 'swimming', - 0x00000008: 'walking', - 0x00000020: 'elliptical', - 0x00000400: 'sedentary', - }, - ), - 'auto_sync_frequency': FieldType( - name='auto_sync_frequency', - base_type=BASE_TYPES[0x00], # enum - values={ - 0: 'never', - 1: 'occasionally', - 2: 'frequent', - 3: 'once_a_day', - 4: 'remote', - }, - ), - 'autolap_trigger': FieldType( - name='autolap_trigger', - base_type=BASE_TYPES[0x00], # enum - values={ - 0: 'time', - 1: 'distance', - 2: 'position_start', - 3: 'position_lap', - 4: 'position_waypoint', - 5: 'position_marked', - 6: 'off', - }, - ), - 'autoscroll': FieldType( - name='autoscroll', - base_type=BASE_TYPES[0x00], # enum - values={ - 0: 'none', - 1: 'slow', - 2: 'medium', - 3: 'fast', - }, - ), - 'backlight_mode': FieldType( - name='backlight_mode', - base_type=BASE_TYPES[0x00], # enum - values={ - 0: 'off', - 1: 'manual', - 2: 'key_and_messages', - 3: 'auto_brightness', - 4: 'smart_notifications', - 5: 'key_and_messages_night', - 6: 'key_and_messages_and_smart_notifications', - }, - ), - 'battery_status': FieldType( - name='battery_status', - base_type=BASE_TYPES[0x02], # uint8 - values={ - 1: 'new', - 2: 'good', - 3: 'ok', - 4: 'low', - 5: 'critical', - 6: 'charging', - 7: 'unknown', - }, - ), - 'bike_light_beam_angle_mode': FieldType( - name='bike_light_beam_angle_mode', - base_type=BASE_TYPES[0x02], # uint8 - values={ - 0: 'manual', - 1: 'auto', - }, - ), - 'bike_light_network_config_type': FieldType( - name='bike_light_network_config_type', - base_type=BASE_TYPES[0x00], # enum - values={ - 0: 'auto', - 4: 'individual', - 5: 'high_visibility', - 6: 'trail', - }, - ), - 'body_location': FieldType( - name='body_location', - base_type=BASE_TYPES[0x00], # enum - values={ - 0: 'left_leg', - 1: 'left_calf', - 2: 'left_shin', - 3: 'left_hamstring', - 4: 'left_quad', - 5: 'left_glute', - 6: 'right_leg', - 7: 'right_calf', - 8: 'right_shin', - 9: 'right_hamstring', - 10: 'right_quad', - 11: 'right_glute', - 12: 'torso_back', - 13: 'left_lower_back', - 14: 'left_upper_back', - 15: 'right_lower_back', - 16: 'right_upper_back', - 17: 'torso_front', - 18: 'left_abdomen', - 19: 'left_chest', - 20: 'right_abdomen', - 21: 'right_chest', - 22: 'left_arm', - 23: 'left_shoulder', - 24: 'left_bicep', - 25: 'left_tricep', - 26: 'left_brachioradialis', # Left anterior forearm - 27: 'left_forearm_extensors', # Left posterior forearm - 28: 'right_arm', - 29: 'right_shoulder', - 30: 'right_bicep', - 31: 'right_tricep', - 32: 'right_brachioradialis', # Right anterior forearm - 33: 'right_forearm_extensors', # Right posterior forearm - 34: 'neck', - 35: 'throat', - 36: 'waist_mid_back', - 37: 'waist_front', - 38: 'waist_left', - 39: 'waist_right', - }, - ), - 'bool': FieldType( - name='bool', - base_type=BASE_TYPES[0x00], # enum - ), - 'bp_status': FieldType( - name='bp_status', - base_type=BASE_TYPES[0x00], # enum - values={ - 0: 'no_error', - 1: 'error_incomplete_data', - 2: 'error_no_measurement', - 3: 'error_data_out_of_range', - 4: 'error_irregular_heart_rate', - }, - ), - 'camera_event_type': FieldType( - name='camera_event_type', - base_type=BASE_TYPES[0x00], # enum - values={ - 0: 'video_start', # Start of video recording - 1: 'video_split', # Mark of video file split (end of one file, beginning of the other) - 2: 'video_end', # End of video recording - 3: 'photo_taken', # Still photo taken - 4: 'video_second_stream_start', - 5: 'video_second_stream_split', - 6: 'video_second_stream_end', - 7: 'video_split_start', # Mark of video file split start - 8: 'video_second_stream_split_start', - 11: 'video_pause', # Mark when a video recording has been paused - 12: 'video_second_stream_pause', - 13: 'video_resume', # Mark when a video recording has been resumed - 14: 'video_second_stream_resume', - }, - ), - 'camera_orientation_type': FieldType( - name='camera_orientation_type', - base_type=BASE_TYPES[0x00], # enum - values={ - 0: 'camera_orientation_0', - 1: 'camera_orientation_90', - 2: 'camera_orientation_180', - 3: 'camera_orientation_270', - }, - ), - 'checksum': FieldType( - name='checksum', - base_type=BASE_TYPES[0x02], # uint8 - values={ - 0: 'clear', # Allows clear of checksum for flash memory where can only write 1 to 0 without erasing sector. - 1: 'ok', # Set to mark checksum as valid if computes to invalid values 0 or 0xFF. Checksum can also be set to ok to save encoding computation time. - }, - ), - 'comm_timeout_type': FieldType( - name='comm_timeout_type', - base_type=BASE_TYPES[0x84], # uint16 - values={ - 0: 'wildcard_pairing_timeout', # Timeout pairing to any device - 1: 'pairing_timeout', # Timeout pairing to previously paired device - 2: 'connection_lost', # Temporary loss of communications - 3: 'connection_timeout', # Connection closed due to extended bad communications - }, - ), - 'connectivity_capabilities': FieldType( - name='connectivity_capabilities', - base_type=BASE_TYPES[0x8C], # uint32z - values={ - 0x00000001: 'bluetooth', - 0x00000002: 'bluetooth_le', - 0x00000004: 'ant', - 0x00000008: 'activity_upload', - 0x00000010: 'course_download', - 0x00000020: 'workout_download', - 0x00000040: 'live_track', - 0x00000080: 'weather_conditions', - 0x00000100: 'weather_alerts', - 0x00000200: 'gps_ephemeris_download', - 0x00000400: 'explicit_archive', - 0x00000800: 'setup_incomplete', - 0x00001000: 'continue_sync_after_software_update', - 0x00002000: 'connect_iq_app_download', - 0x00004000: 'golf_course_download', - 0x00008000: 'device_initiates_sync', # Indicates device is in control of initiating all syncs - 0x00010000: 'connect_iq_watch_app_download', - 0x00020000: 'connect_iq_widget_download', - 0x00040000: 'connect_iq_watch_face_download', - 0x00080000: 'connect_iq_data_field_download', - 0x00100000: 'connect_iq_app_managment', # Device supports delete and reorder of apps via GCM - 0x00200000: 'swing_sensor', - 0x00400000: 'swing_sensor_remote', - 0x00800000: 'incident_detection', # Device supports incident detection - 0x01000000: 'audio_prompts', - 0x02000000: 'wifi_verification', # Device supports reporting wifi verification via GCM - 0x04000000: 'true_up', # Device supports True Up - 0x08000000: 'find_my_watch', # Device supports Find My Watch - 0x10000000: 'remote_manual_sync', - 0x20000000: 'live_track_auto_start', # Device supports LiveTrack auto start - 0x40000000: 'live_track_messaging', # Device supports LiveTrack Messaging - 0x80000000: 'instant_input', # Device supports instant input feature - }, - ), - 'course_capabilities': FieldType( - name='course_capabilities', - base_type=BASE_TYPES[0x8C], # uint32z - values={ - 0x00000001: 'processed', - 0x00000002: 'valid', - 0x00000004: 'time', - 0x00000008: 'distance', - 0x00000010: 'position', - 0x00000020: 'heart_rate', - 0x00000040: 'power', - 0x00000080: 'cadence', - 0x00000100: 'training', - 0x00000200: 'navigation', - 0x00000400: 'bikeway', - }, - ), - 'course_point': FieldType( - name='course_point', - base_type=BASE_TYPES[0x00], # enum - values={ - 0: 'generic', - 1: 'summit', - 2: 'valley', - 3: 'water', - 4: 'food', - 5: 'danger', - 6: 'left', - 7: 'right', - 8: 'straight', - 9: 'first_aid', - 10: 'fourth_category', - 11: 'third_category', - 12: 'second_category', - 13: 'first_category', - 14: 'hors_category', - 15: 'sprint', - 16: 'left_fork', - 17: 'right_fork', - 18: 'middle_fork', - 19: 'slight_left', - 20: 'sharp_left', - 21: 'slight_right', - 22: 'sharp_right', - 23: 'u_turn', - 24: 'segment_start', - 25: 'segment_end', - }, - ), - 'date_mode': FieldType( - name='date_mode', - base_type=BASE_TYPES[0x00], # enum - values={ - 0: 'day_month', - 1: 'month_day', - }, - ), - 'date_time': FieldType( # seconds since UTC 00:00 Dec 31 1989 - name='date_time', - base_type=BASE_TYPES[0x86], # uint32 - ), - 'day_of_week': FieldType( - name='day_of_week', - base_type=BASE_TYPES[0x00], # enum - values={ - 0: 'sunday', - 1: 'monday', - 2: 'tuesday', - 3: 'wednesday', - 4: 'thursday', - 5: 'friday', - 6: 'saturday', - }, - ), - 'device_index': FieldType( - name='device_index', - base_type=BASE_TYPES[0x02], # uint8 - values={ - 0: 'creator', # Creator of the file is always device index 0. - }, - ), - 'digital_watchface_layout': FieldType( - name='digital_watchface_layout', - base_type=BASE_TYPES[0x00], # enum - values={ - 0: 'traditional', - 1: 'modern', - 2: 'bold', - }, - ), - 'display_heart': FieldType( - name='display_heart', - base_type=BASE_TYPES[0x00], # enum - values={ - 0: 'bpm', - 1: 'max', - 2: 'reserve', - }, - ), - 'display_measure': FieldType( - name='display_measure', - base_type=BASE_TYPES[0x00], # enum - values={ - 0: 'metric', - 1: 'statute', - 2: 'nautical', - }, - ), - 'display_orientation': FieldType( - name='display_orientation', - base_type=BASE_TYPES[0x00], # enum - values={ - 0: 'auto', # automatic if the device supports it - 1: 'portrait', - 2: 'landscape', - 3: 'portrait_flipped', # portrait mode but rotated 180 degrees - 4: 'landscape_flipped', # landscape mode but rotated 180 degrees - }, - ), - 'display_position': FieldType( - name='display_position', - base_type=BASE_TYPES[0x00], # enum - values={ - 0: 'degree', # dd.dddddd - 1: 'degree_minute', # dddmm.mmm - 2: 'degree_minute_second', # dddmmss - 3: 'austrian_grid', # Austrian Grid (BMN) - 4: 'british_grid', # British National Grid - 5: 'dutch_grid', # Dutch grid system - 6: 'hungarian_grid', # Hungarian grid system - 7: 'finnish_grid', # Finnish grid system Zone3 KKJ27 - 8: 'german_grid', # Gausss Krueger (German) - 9: 'icelandic_grid', # Icelandic Grid - 10: 'indonesian_equatorial', # Indonesian Equatorial LCO - 11: 'indonesian_irian', # Indonesian Irian LCO - 12: 'indonesian_southern', # Indonesian Southern LCO - 13: 'india_zone_0', # India zone 0 - 14: 'india_zone_IA', # India zone IA - 15: 'india_zone_IB', # India zone IB - 16: 'india_zone_IIA', # India zone IIA - 17: 'india_zone_IIB', # India zone IIB - 18: 'india_zone_IIIA', # India zone IIIA - 19: 'india_zone_IIIB', # India zone IIIB - 20: 'india_zone_IVA', # India zone IVA - 21: 'india_zone_IVB', # India zone IVB - 22: 'irish_transverse', # Irish Transverse Mercator - 23: 'irish_grid', # Irish Grid - 24: 'loran', # Loran TD - 25: 'maidenhead_grid', # Maidenhead grid system - 26: 'mgrs_grid', # MGRS grid system - 27: 'new_zealand_grid', # New Zealand grid system - 28: 'new_zealand_transverse', # New Zealand Transverse Mercator - 29: 'qatar_grid', # Qatar National Grid - 30: 'modified_swedish_grid', # Modified RT-90 (Sweden) - 31: 'swedish_grid', # RT-90 (Sweden) - 32: 'south_african_grid', # South African Grid - 33: 'swiss_grid', # Swiss CH-1903 grid - 34: 'taiwan_grid', # Taiwan Grid - 35: 'united_states_grid', # United States National Grid - 36: 'utm_ups_grid', # UTM/UPS grid system - 37: 'west_malayan', # West Malayan RSO - 38: 'borneo_rso', # Borneo RSO - 39: 'estonian_grid', # Estonian grid system - 40: 'latvian_grid', # Latvian Transverse Mercator - 41: 'swedish_ref_99_grid', # Reference Grid 99 TM (Swedish) - }, - ), - 'display_power': FieldType( - name='display_power', - base_type=BASE_TYPES[0x00], # enum - values={ - 0: 'watts', - 1: 'percent_ftp', - }, - ), - 'event': FieldType( - name='event', - base_type=BASE_TYPES[0x00], # enum - values={ - 0: 'timer', # Group 0. Start / stop_all - 3: 'workout', # start / stop - 4: 'workout_step', # Start at beginning of workout. Stop at end of each step. - 5: 'power_down', # stop_all group 0 - 6: 'power_up', # stop_all group 0 - 7: 'off_course', # start / stop group 0 - 8: 'session', # Stop at end of each session. - 9: 'lap', # Stop at end of each lap. - 10: 'course_point', # marker - 11: 'battery', # marker - 12: 'virtual_partner_pace', # Group 1. Start at beginning of activity if VP enabled, when VP pace is changed during activity or VP enabled mid activity. stop_disable when VP disabled. - 13: 'hr_high_alert', # Group 0. Start / stop when in alert condition. - 14: 'hr_low_alert', # Group 0. Start / stop when in alert condition. - 15: 'speed_high_alert', # Group 0. Start / stop when in alert condition. - 16: 'speed_low_alert', # Group 0. Start / stop when in alert condition. - 17: 'cad_high_alert', # Group 0. Start / stop when in alert condition. - 18: 'cad_low_alert', # Group 0. Start / stop when in alert condition. - 19: 'power_high_alert', # Group 0. Start / stop when in alert condition. - 20: 'power_low_alert', # Group 0. Start / stop when in alert condition. - 21: 'recovery_hr', # marker - 22: 'battery_low', # marker - 23: 'time_duration_alert', # Group 1. Start if enabled mid activity (not required at start of activity). Stop when duration is reached. stop_disable if disabled. - 24: 'distance_duration_alert', # Group 1. Start if enabled mid activity (not required at start of activity). Stop when duration is reached. stop_disable if disabled. - 25: 'calorie_duration_alert', # Group 1. Start if enabled mid activity (not required at start of activity). Stop when duration is reached. stop_disable if disabled. - 26: 'activity', # Group 1.. Stop at end of activity. - 27: 'fitness_equipment', # marker - 28: 'length', # Stop at end of each length. - 32: 'user_marker', # marker - 33: 'sport_point', # marker - 36: 'calibration', # start/stop/marker - 42: 'front_gear_change', # marker - 43: 'rear_gear_change', # marker - 44: 'rider_position_change', # marker - 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 - }, - ), - 'event_type': FieldType( - name='event_type', - base_type=BASE_TYPES[0x00], # enum - values={ - 0: 'start', - 1: 'stop', - 2: 'consecutive_depreciated', - 3: 'marker', - 4: 'stop_all', - 5: 'begin_depreciated', - 6: 'end_depreciated', - 7: 'end_all_depreciated', - 8: 'stop_disable', - 9: 'stop_disable_all', - }, - ), - 'exd_data_units': FieldType( - name='exd_data_units', - base_type=BASE_TYPES[0x00], # enum - values={ - 0: 'no_units', - 1: 'laps', - 2: 'miles_per_hour', - 3: 'kilometers_per_hour', - 4: 'feet_per_hour', - 5: 'meters_per_hour', - 6: 'degrees_celsius', - 7: 'degrees_farenheit', - 8: 'zone', - 9: 'gear', - 10: 'rpm', - 11: 'bpm', - 12: 'degrees', - 13: 'millimeters', - 14: 'meters', - 15: 'kilometers', - 16: 'feet', - 17: 'yards', - 18: 'kilofeet', - 19: 'miles', - 20: 'time', - 21: 'enum_turn_type', - 22: 'percent', - 23: 'watts', - 24: 'watts_per_kilogram', - 25: 'enum_battery_status', - 26: 'enum_bike_light_beam_angle_mode', - 27: 'enum_bike_light_battery_status', - 28: 'enum_bike_light_network_config_type', - 29: 'lights', - 30: 'seconds', - 31: 'minutes', - 32: 'hours', - 33: 'calories', - 34: 'kilojoules', - 35: 'milliseconds', - 36: 'second_per_mile', - 37: 'second_per_kilometer', - 38: 'centimeter', - 39: 'enum_course_point', - 40: 'bradians', - 41: 'enum_sport', - 42: 'inches_hg', - 43: 'mm_hg', - 44: 'mbars', - 45: 'hecto_pascals', - 46: 'feet_per_min', - 47: 'meters_per_min', - 48: 'meters_per_sec', - 49: 'eight_cardinal', - }, - ), - 'exd_descriptors': FieldType( - name='exd_descriptors', - base_type=BASE_TYPES[0x00], # enum - values={ - 0: 'bike_light_battery_status', - 1: 'beam_angle_status', - 2: 'batery_level', - 3: 'light_network_mode', - 4: 'number_lights_connected', - 5: 'cadence', - 6: 'distance', - 7: 'estimated_time_of_arrival', - 8: 'heading', - 9: 'time', - 10: 'battery_level', - 11: 'trainer_resistance', - 12: 'trainer_target_power', - 13: 'time_seated', - 14: 'time_standing', - 15: 'elevation', - 16: 'grade', - 17: 'ascent', - 18: 'descent', - 19: 'vertical_speed', - 20: 'di2_battery_level', - 21: 'front_gear', - 22: 'rear_gear', - 23: 'gear_ratio', - 24: 'heart_rate', - 25: 'heart_rate_zone', - 26: 'time_in_heart_rate_zone', - 27: 'heart_rate_reserve', - 28: 'calories', - 29: 'gps_accuracy', - 30: 'gps_signal_strength', - 31: 'temperature', - 32: 'time_of_day', - 33: 'balance', - 34: 'pedal_smoothness', - 35: 'power', - 36: 'functional_threshold_power', - 37: 'intensity_factor', - 38: 'work', - 39: 'power_ratio', - 40: 'normalized_power', - 41: 'training_stress_Score', - 42: 'time_on_zone', - 43: 'speed', - 44: 'laps', - 45: 'reps', - 46: 'workout_step', - 47: 'course_distance', - 48: 'navigation_distance', - 49: 'course_estimated_time_of_arrival', - 50: 'navigation_estimated_time_of_arrival', - 51: 'course_time', - 52: 'navigation_time', - 53: 'course_heading', - 54: 'navigation_heading', - 55: 'power_zone', - 56: 'torque_effectiveness', - 57: 'timer_time', - 58: 'power_weight_ratio', - 59: 'left_platform_center_offset', - 60: 'right_platform_center_offset', - 61: 'left_power_phase_start_angle', - 62: 'right_power_phase_start_angle', - 63: 'left_power_phase_finish_angle', - 64: 'right_power_phase_finish_angle', - 65: 'gears', # Combined gear information - 66: 'pace', - 67: 'training_effect', - 68: 'vertical_oscillation', - 69: 'vertical_ratio', - 70: 'ground_contact_time', - 71: 'left_ground_contact_time_balance', - 72: 'right_ground_contact_time_balance', - 73: 'stride_length', - 74: 'running_cadence', - 75: 'performance_condition', - 76: 'course_type', - 77: 'time_in_power_zone', - 78: 'navigation_turn', - 79: 'course_location', - 80: 'navigation_location', - 81: 'compass', - 82: 'gear_combo', - 83: 'muscle_oxygen', - 84: 'icon', - 85: 'compass_heading', - 86: 'gps_heading', - 87: 'gps_elevation', - 88: 'anaerobic_training_effect', - 89: 'course', - 90: 'off_course', - 91: 'glide_ratio', - 92: 'vertical_distance', - 93: 'vmg', - 94: 'ambient_pressure', - 95: 'pressure', - }, - ), - 'exd_display_type': FieldType( - name='exd_display_type', - base_type=BASE_TYPES[0x00], # enum - values={ - 0: 'numerical', - 1: 'simple', - 2: 'graph', - 3: 'bar', - 4: 'circle_graph', - 5: 'virtual_partner', - 6: 'balance', - 7: 'string_list', - 8: 'string', - 9: 'simple_dynamic_icon', - 10: 'gauge', - }, - ), - 'exd_layout': FieldType( - name='exd_layout', - base_type=BASE_TYPES[0x00], # enum - values={ - 0: 'full_screen', - 1: 'half_vertical', - 2: 'half_horizontal', - 3: 'half_vertical_right_split', - 4: 'half_horizontal_bottom_split', - 5: 'full_quarter_split', - 6: 'half_vertical_left_split', - 7: 'half_horizontal_top_split', - }, - ), - 'exd_qualifiers': FieldType( - name='exd_qualifiers', - base_type=BASE_TYPES[0x00], # enum - values={ - 0: 'no_qualifier', - 1: 'instantaneous', - 2: 'average', - 3: 'lap', - 4: 'maximum', - 5: 'maximum_average', - 6: 'maximum_lap', - 7: 'last_lap', - 8: 'average_lap', - 9: 'to_destination', - 10: 'to_go', - 11: 'to_next', - 12: 'next_course_point', - 13: 'total', - 14: 'three_second_average', - 15: 'ten_second_average', - 16: 'thirty_second_average', - 17: 'percent_maximum', - 18: 'percent_maximum_average', - 19: 'lap_percent_maximum', - 20: 'elapsed', - 21: 'sunrise', - 22: 'sunset', - 23: 'compared_to_virtual_partner', - 24: 'maximum_24h', - 25: 'minimum_24h', - 26: 'minimum', - 27: 'first', - 28: 'second', - 29: 'third', - 30: 'shifter', - 31: 'last_sport', - 32: 'moving', - 33: 'stopped', - 242: 'zone_9', - 243: 'zone_8', - 244: 'zone_7', - 245: 'zone_6', - 246: 'zone_5', - 247: 'zone_4', - 248: 'zone_3', - 249: 'zone_2', - 250: 'zone_1', - }, - ), - 'file': FieldType( - name='file', - base_type=BASE_TYPES[0x00], # enum - values={ - 1: 'device', # Read only, single file. Must be in root directory. - 2: 'settings', # Read/write, single file. Directory=Settings - 3: 'sport', # Read/write, multiple files, file number = sport type. Directory=Sports - 4: 'activity', # Read/erase, multiple files. Directory=Activities - 5: 'workout', # Read/write/erase, multiple files. Directory=Workouts - 6: 'course', # Read/write/erase, multiple files. Directory=Courses - 7: 'schedules', # Read/write, single file. Directory=Schedules - 9: 'weight', # Read only, single file. Circular buffer. All message definitions at start of file. Directory=Weight - 10: 'totals', # Read only, single file. Directory=Totals - 11: 'goals', # Read/write, single file. Directory=Goals - 14: 'blood_pressure', # Read only. Directory=Blood Pressure - 15: 'monitoring_a', # Read only. Directory=Monitoring. File number=sub type. - 20: 'activity_summary', # Read/erase, multiple files. Directory=Activities - 28: 'monitoring_daily', - 32: 'monitoring_b', # Read only. Directory=Monitoring. File number=identifier - 34: 'segment', # Read/write/erase. Multiple Files. Directory=Segments - 35: 'segment_list', # Read/write/erase. Single File. Directory=Segments - 40: 'exd_configuration', # Read/write/erase. Single File. Directory=Settings - 0xF7: 'mfg_range_min', # 0xF7 - 0xFE reserved for manufacturer specific file types - 0xFE: 'mfg_range_max', # 0xF7 - 0xFE reserved for manufacturer specific file types - }, - ), - 'file_flags': FieldType( - name='file_flags', - base_type=BASE_TYPES[0x0A], # uint8z - values={ - 0x02: 'read', - 0x04: 'write', - 0x08: 'erase', - }, - ), - 'fit_base_type': FieldType( - name='fit_base_type', - base_type=BASE_TYPES[0x02], # uint8 - values={ - 0: 'enum', - 1: 'sint8', - 2: 'uint8', - 7: 'string', - 10: 'uint8z', - 13: 'byte', - 131: 'sint16', - 132: 'uint16', - 133: 'sint32', - 134: 'uint32', - 136: 'float32', - 137: 'float64', - 139: 'uint16z', - 140: 'uint32z', - 142: 'sint64', - 143: 'uint64', - 144: 'uint64z', - }, - ), - 'fit_base_unit': FieldType( - name='fit_base_unit', - base_type=BASE_TYPES[0x84], # uint16 - values={ - 0: 'other', - 1: 'kilogram', - 2: 'pound', - }, - ), - 'fitness_equipment_state': FieldType( # fitness equipment event data - name='fitness_equipment_state', - base_type=BASE_TYPES[0x00], # enum - values={ - 0: 'ready', - 1: 'in_use', - 2: 'paused', - 3: 'unknown', # lost connection to fitness equipment - }, - ), - 'garmin_product': FieldType( - name='garmin_product', - base_type=BASE_TYPES[0x84], # uint16 - values={ - 1: 'hrm1', - 2: 'axh01', # AXH01 HRM chipset - 3: 'axb01', - 4: 'axb02', - 5: 'hrm2ss', - 6: 'dsi_alf02', - 7: 'hrm3ss', - 8: 'hrm_run_single_byte_product_id', # hrm_run model for HRM ANT+ messaging - 9: 'bsm', # BSM model for ANT+ messaging - 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 - 14: 'fr225_single_byte_product_id', # fr225 model for HRM ANT+ messaging - 473: 'fr301_china', - 474: 'fr301_japan', - 475: 'fr301_korea', - 494: 'fr301_taiwan', - 717: 'fr405', # Forerunner 405 - 782: 'fr50', # Forerunner 50 - 987: 'fr405_japan', - 988: 'fr60', # Forerunner 60 - 1011: 'dsi_alf01', - 1018: 'fr310xt', # Forerunner 310 - 1036: 'edge500', - 1124: 'fr110', # Forerunner 110 - 1169: 'edge800', - 1199: 'edge500_taiwan', - 1213: 'edge500_japan', - 1253: 'chirp', - 1274: 'fr110_japan', - 1325: 'edge200', - 1328: 'fr910xt', - 1333: 'edge800_taiwan', - 1334: 'edge800_japan', - 1341: 'alf04', - 1345: 'fr610', - 1360: 'fr210_japan', - 1380: 'vector_ss', - 1381: 'vector_cp', - 1386: 'edge800_china', - 1387: 'edge500_china', - 1410: 'fr610_japan', - 1422: 'edge500_korea', - 1436: 'fr70', - 1446: 'fr310xt_4t', - 1461: 'amx', - 1482: 'fr10', - 1497: 'edge800_korea', - 1499: 'swim', - 1537: 'fr910xt_china', - 1551: 'fenix', - 1555: 'edge200_taiwan', - 1561: 'edge510', - 1567: 'edge810', - 1570: 'tempe', - 1600: 'fr910xt_japan', - 1623: 'fr620', - 1632: 'fr220', - 1664: 'fr910xt_korea', - 1688: 'fr10_japan', - 1721: 'edge810_japan', - 1735: 'virb_elite', - 1736: 'edge_touring', # Also Edge Touring Plus - 1742: 'edge510_japan', - 1743: 'hrm_tri', - 1752: 'hrm_run', - 1765: 'fr920xt', - 1821: 'edge510_asia', - 1822: 'edge810_china', - 1823: 'edge810_taiwan', - 1836: 'edge1000', - 1837: 'vivo_fit', - 1853: 'virb_remote', - 1885: 'vivo_ki', - 1903: 'fr15', - 1907: 'vivo_active', - 1918: 'edge510_korea', - 1928: 'fr620_japan', - 1929: 'fr620_china', - 1930: 'fr220_japan', - 1931: 'fr220_china', - 1936: 'approach_s6', - 1956: 'vivo_smart', - 1967: 'fenix2', - 1988: 'epix', - 2050: 'fenix3', - 2052: 'edge1000_taiwan', - 2053: 'edge1000_japan', - 2061: 'fr15_japan', - 2067: 'edge520', - 2070: 'edge1000_china', - 2072: 'fr620_russia', - 2073: 'fr220_russia', - 2079: 'vector_s', - 2100: 'edge1000_korea', - 2130: 'fr920xt_taiwan', - 2131: 'fr920xt_china', - 2132: 'fr920xt_japan', - 2134: 'virbx', - 2135: 'vivo_smart_apac', - 2140: 'etrex_touch', - 2147: 'edge25', - 2148: 'fr25', - 2150: 'vivo_fit2', - 2153: 'fr225', - 2156: 'fr630', - 2157: 'fr230', - 2160: 'vivo_active_apac', - 2161: 'vector_2', - 2162: 'vector_2s', - 2172: 'virbxe', - 2173: 'fr620_taiwan', - 2174: 'fr220_taiwan', - 2175: 'truswing', - 2188: 'fenix3_china', - 2189: 'fenix3_twn', - 2192: 'varia_headlight', - 2193: 'varia_taillight_old', - 2204: 'edge_explore_1000', - 2219: 'fr225_asia', - 2225: 'varia_radar_taillight', - 2226: 'varia_radar_display', - 2238: 'edge20', - 2262: 'd2_bravo', - 2266: 'approach_s20', - 2276: 'varia_remote', - 2327: 'hrm4_run', - 2337: 'vivo_active_hr', - 2347: 'vivo_smart_gps_hr', - 2348: 'vivo_smart_hr', - 2368: 'vivo_move', - 2398: 'varia_vision', - 2406: 'vivo_fit3', - 2413: 'fenix3_hr', - 2417: 'virb_ultra_30', - 2429: 'index_smart_scale', - 2431: 'fr235', - 2432: 'fenix3_chronos', - 2441: 'oregon7xx', - 2444: 'rino7xx', - 2496: 'nautix', - 2530: 'edge_820', - 2531: 'edge_explore_820', - 2544: 'fenix5s', - 2547: 'd2_bravo_titanium', - 2593: 'running_dynamics_pod', - 2604: 'fenix5x', - 2606: 'vivo_fit_jr', - 2691: 'fr935', - 2697: 'fenix5', - 10007: 'sdm4', # SDM4 footpod - 10014: 'edge_remote', - 20119: 'training_center', - 65531: 'connectiq_simulator', - 65532: 'android_antplus_plugin', - 65534: 'connect', # Garmin Connect website - }, - ), - 'gender': FieldType( - name='gender', - base_type=BASE_TYPES[0x00], # enum - values={ - 0: 'female', - 1: 'male', - }, - ), - 'goal': FieldType( - name='goal', - base_type=BASE_TYPES[0x00], # enum - values={ - 0: 'time', - 1: 'distance', - 2: 'calories', - 3: 'frequency', - 4: 'steps', - 5: 'ascent', - 6: 'active_minutes', - }, - ), - 'goal_recurrence': FieldType( - name='goal_recurrence', - base_type=BASE_TYPES[0x00], # enum - values={ - 0: 'off', - 1: 'daily', - 2: 'weekly', - 3: 'monthly', - 4: 'yearly', - 5: 'custom', - }, - ), - 'goal_source': FieldType( - name='goal_source', - base_type=BASE_TYPES[0x00], # enum - values={ - 0: 'auto', # Device generated - 1: 'community', # Social network sourced goal - 2: 'user', # Manually generated - }, - ), - 'hr_type': FieldType( - name='hr_type', - base_type=BASE_TYPES[0x00], # enum - values={ - 0: 'normal', - 1: 'irregular', - }, - ), - 'hr_zone_calc': FieldType( - name='hr_zone_calc', - base_type=BASE_TYPES[0x00], # enum - values={ - 0: 'custom', - 1: 'percent_max_hr', - 2: 'percent_hrr', - }, - ), - 'intensity': FieldType( - name='intensity', - base_type=BASE_TYPES[0x00], # enum - values={ - 0: 'active', - 1: 'rest', - 2: 'warmup', - 3: 'cooldown', - }, - ), - 'language': FieldType( - name='language', - base_type=BASE_TYPES[0x00], # enum - values={ - 0: 'english', - 1: 'french', - 2: 'italian', - 3: 'german', - 4: 'spanish', - 5: 'croatian', - 6: 'czech', - 7: 'danish', - 8: 'dutch', - 9: 'finnish', - 10: 'greek', - 11: 'hungarian', - 12: 'norwegian', - 13: 'polish', - 14: 'portuguese', - 15: 'slovakian', - 16: 'slovenian', - 17: 'swedish', - 18: 'russian', - 19: 'turkish', - 20: 'latvian', - 21: 'ukrainian', - 22: 'arabic', - 23: 'farsi', - 24: 'bulgarian', - 25: 'romanian', - 26: 'chinese', - 27: 'japanese', - 28: 'korean', - 29: 'taiwanese', - 30: 'thai', - 31: 'hebrew', - 32: 'brazilian_portuguese', - 33: 'indonesian', - 34: 'malaysian', - 35: 'vietnamese', - 36: 'burmese', - 37: 'mongolian', - 254: 'custom', - }, - ), - 'language_bits_0': FieldType( # Bit field corresponding to language enum type (1 << language). - name='language_bits_0', - base_type=BASE_TYPES[0x0A], # uint8z - values={ - 0x01: 'english', - 0x02: 'french', - 0x04: 'italian', - 0x08: 'german', - 0x10: 'spanish', - 0x20: 'croatian', - 0x40: 'czech', - 0x80: 'danish', - }, - ), - 'language_bits_1': FieldType( - name='language_bits_1', - base_type=BASE_TYPES[0x0A], # uint8z - values={ - 0x01: 'dutch', - 0x02: 'finnish', - 0x04: 'greek', - 0x08: 'hungarian', - 0x10: 'norwegian', - 0x20: 'polish', - 0x40: 'portuguese', - 0x80: 'slovakian', - }, - ), - 'language_bits_2': FieldType( - name='language_bits_2', - base_type=BASE_TYPES[0x0A], # uint8z - values={ - 0x01: 'slovenian', - 0x02: 'swedish', - 0x04: 'russian', - 0x08: 'turkish', - 0x10: 'latvian', - 0x20: 'ukrainian', - 0x40: 'arabic', - 0x80: 'farsi', - }, - ), - 'language_bits_3': FieldType( - name='language_bits_3', - base_type=BASE_TYPES[0x0A], # uint8z - values={ - 0x01: 'bulgarian', - 0x02: 'romanian', - 0x04: 'chinese', - 0x08: 'japanese', - 0x10: 'korean', - 0x20: 'taiwanese', - 0x40: 'thai', - 0x80: 'hebrew', - }, - ), - 'language_bits_4': FieldType( - name='language_bits_4', - base_type=BASE_TYPES[0x0A], # uint8z - values={ - 0x01: 'brazilian_portuguese', - 0x02: 'indonesian', - 0x04: 'malaysian', - 0x08: 'vietnamese', - 0x10: 'burmese', - 0x20: 'mongolian', - }, - ), - 'lap_trigger': FieldType( - name='lap_trigger', - base_type=BASE_TYPES[0x00], # enum - values={ - 0: 'manual', - 1: 'time', - 2: 'distance', - 3: 'position_start', - 4: 'position_lap', - 5: 'position_waypoint', - 6: 'position_marked', - 7: 'session_end', - 8: 'fitness_equipment', - }, - ), - 'left_right_balance': FieldType( - name='left_right_balance', - base_type=BASE_TYPES[0x02], # uint8 - values={ - 0x7F: 'mask', # % contribution - 0x80: 'right', # data corresponds to right if set, otherwise unknown - }, - ), - 'left_right_balance_100': FieldType( - name='left_right_balance_100', - base_type=BASE_TYPES[0x84], # uint16 - values={ - 0x3FFF: 'mask', # % contribution scaled by 100 - 0x8000: 'right', # data corresponds to right if set, otherwise unknown - }, - ), - 'length_type': FieldType( - name='length_type', - base_type=BASE_TYPES[0x00], # enum - values={ - 0: 'idle', # Rest period. Length with no strokes - 1: 'active', # Length with strokes. - }, - ), - 'local_date_time': FieldType( # seconds since 00:00 Dec 31 1989 in local time zone - name='local_date_time', - base_type=BASE_TYPES[0x86], # uint32 - values={ - 0x10000000: 'min', # if date_time is < 0x10000000 then it is system time (seconds from device power on) - }, - ), - 'localtime_into_day': FieldType( # number of seconds into the day since local 00:00:00 - name='localtime_into_day', - base_type=BASE_TYPES[0x86], # uint32 - ), - 'manufacturer': FieldType( - name='manufacturer', - base_type=BASE_TYPES[0x84], # uint16 - values={ - 1: 'garmin', - 2: 'garmin_fr405_antfs', # Do not use. Used by FR405 for ANTFS man id. - 3: 'zephyr', - 4: 'dayton', - 5: 'idt', - 6: 'srm', - 7: 'quarq', - 8: 'ibike', - 9: 'saris', - 10: 'spark_hk', - 11: 'tanita', - 12: 'echowell', - 13: 'dynastream_oem', - 14: 'nautilus', - 15: 'dynastream', - 16: 'timex', - 17: 'metrigear', - 18: 'xelic', - 19: 'beurer', - 20: 'cardiosport', - 21: 'a_and_d', - 22: 'hmm', - 23: 'suunto', - 24: 'thita_elektronik', - 25: 'gpulse', - 26: 'clean_mobile', - 27: 'pedal_brain', - 28: 'peaksware', - 29: 'saxonar', - 30: 'lemond_fitness', - 31: 'dexcom', - 32: 'wahoo_fitness', - 33: 'octane_fitness', - 34: 'archinoetics', - 35: 'the_hurt_box', - 36: 'citizen_systems', - 37: 'magellan', - 38: 'osynce', - 39: 'holux', - 40: 'concept2', - 42: 'one_giant_leap', - 43: 'ace_sensor', - 44: 'brim_brothers', - 45: 'xplova', - 46: 'perception_digital', - 47: 'bf1systems', - 48: 'pioneer', - 49: 'spantec', - 50: 'metalogics', - 51: '4iiiis', - 52: 'seiko_epson', - 53: 'seiko_epson_oem', - 54: 'ifor_powell', - 55: 'maxwell_guider', - 56: 'star_trac', - 57: 'breakaway', - 58: 'alatech_technology_ltd', - 59: 'mio_technology_europe', - 60: 'rotor', - 61: 'geonaute', - 62: 'id_bike', - 63: 'specialized', - 64: 'wtek', - 65: 'physical_enterprises', - 66: 'north_pole_engineering', - 67: 'bkool', - 68: 'cateye', - 69: 'stages_cycling', - 70: 'sigmasport', - 71: 'tomtom', - 72: 'peripedal', - 73: 'wattbike', - 76: 'moxy', - 77: 'ciclosport', - 78: 'powerbahn', - 79: 'acorn_projects_aps', - 80: 'lifebeam', - 81: 'bontrager', - 82: 'wellgo', - 83: 'scosche', - 84: 'magura', - 85: 'woodway', - 86: 'elite', - 87: 'nielsen_kellerman', - 88: 'dk_city', - 89: 'tacx', - 90: 'direction_technology', - 91: 'magtonic', - 92: '1partcarbon', - 93: 'inside_ride_technologies', - 94: 'sound_of_motion', - 95: 'stryd', - 96: 'icg', # Indoorcycling Group - 97: 'MiPulse', - 98: 'bsx_athletics', - 99: 'look', - 100: 'campagnolo_srl', - 101: 'body_bike_smart', - 102: 'praxisworks', - 103: 'limits_technology', # Limits Technology Ltd. - 104: 'topaction_technology', # TopAction Technology Inc. - 105: 'cosinuss', - 106: 'fitcare', - 107: 'magene', - 108: 'giant_manufacturing_co', - 109: 'tigrasport', # Tigrasport - 110: 'salutron', - 111: 'technogym', - 112: 'bryton_sensors', - 255: 'development', - 257: 'healthandlife', - 258: 'lezyne', - 259: 'scribe_labs', - 260: 'zwift', - 261: 'watteam', - 262: 'recon', - 263: 'favero_electronics', - 264: 'dynovelo', - 265: 'strava', - 266: 'precor', # Amer Sports - 267: 'bryton', - 268: 'sram', - 269: 'navman', # MiTAC Global Corporation (Mio Technology) - 270: 'cobi', # COBI GmbH - 271: 'spivi', - 272: 'mio_magellan', - 273: 'evesports', - 274: 'sensitivus_gauge', - 275: 'podoon', - 276: 'life_time_fitness', - 277: 'falco_e_motors', # Falco eMotors Inc. - 5759: 'actigraphcorp', - }, - ), - 'mesg_count': FieldType( - name='mesg_count', - base_type=BASE_TYPES[0x00], # enum - values={ - 0: 'num_per_file', - 1: 'max_per_file', - 2: 'max_per_file_type', - }, - ), - 'mesg_num': FieldType( - name='mesg_num', - base_type=BASE_TYPES[0x84], # uint16 - values={ - 0: 'file_id', - 1: 'capabilities', - 2: 'device_settings', - 3: 'user_profile', - 4: 'hrm_profile', - 5: 'sdm_profile', - 6: 'bike_profile', - 7: 'zones_target', - 8: 'hr_zone', - 9: 'power_zone', - 10: 'met_zone', - 12: 'sport', - 15: 'goal', - 18: 'session', - 19: 'lap', - 20: 'record', - 21: 'event', - 23: 'device_info', - 26: 'workout', - 27: 'workout_step', - 28: 'schedule', - 30: 'weight_scale', - 31: 'course', - 32: 'course_point', - 33: 'totals', - 34: 'activity', - 35: 'software', - 37: 'file_capabilities', - 38: 'mesg_capabilities', - 39: 'field_capabilities', - 49: 'file_creator', - 51: 'blood_pressure', - 53: 'speed_zone', - 55: 'monitoring', - 72: 'training_file', - 78: 'hrv', - 80: 'ant_rx', - 81: 'ant_tx', - 82: 'ant_channel_id', - 101: 'length', - 103: 'monitoring_info', - 105: 'pad', - 106: 'slave_device', - 127: 'connectivity', - 128: 'weather_conditions', - 129: 'weather_alert', - 131: 'cadence_zone', - 132: 'hr', - 142: 'segment_lap', - 145: 'memo_glob', - 148: 'segment_id', - 149: 'segment_leaderboard_entry', - 150: 'segment_point', - 151: 'segment_file', - 158: 'workout_session', - 159: 'watchface_settings', - 160: 'gps_metadata', - 161: 'camera_event', - 162: 'timestamp_correlation', - 164: 'gyroscope_data', - 165: 'accelerometer_data', - 167: 'three_d_sensor_calibration', - 169: 'video_frame', - 174: 'obdii_data', - 177: 'nmea_sentence', - 178: 'aviation_attitude', - 184: 'video', - 185: 'video_title', - 186: 'video_description', - 187: 'video_clip', - 188: 'ohr_settings', - 200: 'exd_screen_configuration', - 201: 'exd_data_field_configuration', - 202: 'exd_data_concept_configuration', - 206: 'field_description', - 207: 'developer_data_id', - 208: 'magnetometer_data', - }, - ), - 'message_index': FieldType( - name='message_index', - base_type=BASE_TYPES[0x84], # uint16 - values={ - 0x0FFF: 'mask', # index - 0x7000: 'reserved', # reserved (default 0) - 0x8000: 'selected', # message is selected if set - }, - ), - 'power_phase_type': FieldType( - name='power_phase_type', - base_type=BASE_TYPES[0x00], # enum - values={ - 0: 'power_phase_start_angle', - 1: 'power_phase_end_angle', - 2: 'power_phase_arc_length', - 3: 'power_phase_center', - }, - ), - 'pwr_zone_calc': FieldType( - name='pwr_zone_calc', - base_type=BASE_TYPES[0x00], # enum - values={ - 0: 'custom', - 1: 'percent_ftp', - }, - ), - 'rider_position_type': FieldType( - name='rider_position_type', - base_type=BASE_TYPES[0x00], # enum - values={ - 0: 'seated', - 1: 'standing', - 2: 'transition_to_seated', - 3: 'transition_to_standing', - }, - ), - 'schedule': FieldType( - name='schedule', - base_type=BASE_TYPES[0x00], # enum - values={ - 0: 'workout', - 1: 'course', - }, - ), - 'segment_delete_status': FieldType( - name='segment_delete_status', - base_type=BASE_TYPES[0x00], # enum - values={ - 0: 'do_not_delete', - 1: 'delete_one', - 2: 'delete_all', - }, - ), - 'segment_lap_status': FieldType( - name='segment_lap_status', - base_type=BASE_TYPES[0x00], # enum - values={ - 0: 'end', - 1: 'fail', - }, - ), - 'segment_leaderboard_type': FieldType( - name='segment_leaderboard_type', - base_type=BASE_TYPES[0x00], # enum - values={ - 0: 'overall', - 1: 'personal_best', - 2: 'connections', - 3: 'group', - 4: 'challenger', - 5: 'kom', - 6: 'qom', - 7: 'pr', - 8: 'goal', - 9: 'rival', - 10: 'club_leader', - }, - ), - 'segment_selection_type': FieldType( - name='segment_selection_type', - base_type=BASE_TYPES[0x00], # enum - values={ - 0: 'starred', - 1: 'suggested', - }, - ), - 'sensor_type': FieldType( - name='sensor_type', - base_type=BASE_TYPES[0x00], # enum - values={ - 0: 'accelerometer', - 1: 'gyroscope', - 2: 'compass', # Magnetometer - }, - ), - 'session_trigger': FieldType( - name='session_trigger', - base_type=BASE_TYPES[0x00], # enum - values={ - 0: 'activity_end', - 1: 'manual', # User changed sport. - 2: 'auto_multi_sport', # Auto multi-sport feature is enabled and user pressed lap button to advance session. - 3: 'fitness_equipment', # Auto sport change caused by user linking to fitness equipment. - }, - ), - 'side': FieldType( - name='side', - base_type=BASE_TYPES[0x00], # enum - values={ - 0: 'right', - 1: 'left', - }, - ), - 'source_type': FieldType( - name='source_type', - base_type=BASE_TYPES[0x00], # enum - values={ - 0: 'ant', # External device connected with ANT - 1: 'antplus', # External device connected with ANT+ - 2: 'bluetooth', # External device connected with BT - 3: 'bluetooth_low_energy', # External device connected with BLE - 4: 'wifi', # External device connected with Wifi - 5: 'local', # Onboard device - }, - ), - 'sport': FieldType( - name='sport', - base_type=BASE_TYPES[0x00], # enum - values={ - 0: 'generic', - 1: 'running', - 2: 'cycling', - 3: 'transition', # Mulitsport transition - 4: 'fitness_equipment', - 5: 'swimming', - 6: 'basketball', - 7: 'soccer', - 8: 'tennis', - 9: 'american_football', - 10: 'training', - 11: 'walking', - 12: 'cross_country_skiing', - 13: 'alpine_skiing', - 14: 'snowboarding', - 15: 'rowing', - 16: 'mountaineering', - 17: 'hiking', - 18: 'multisport', - 19: 'paddling', - 20: 'flying', - 21: 'e_biking', - 22: 'motorcycling', - 23: 'boating', - 24: 'driving', - 25: 'golf', - 26: 'hang_gliding', - 27: 'horseback_riding', - 28: 'hunting', - 29: 'fishing', - 30: 'inline_skating', - 31: 'rock_climbing', - 32: 'sailing', - 33: 'ice_skating', - 34: 'sky_diving', - 35: 'snowshoeing', - 36: 'snowmobiling', - 37: 'stand_up_paddleboarding', - 38: 'surfing', - 39: 'wakeboarding', - 40: 'water_skiing', - 41: 'kayaking', - 42: 'rafting', - 43: 'windsurfing', - 44: 'kitesurfing', - 45: 'tactical', - 46: 'jumpmaster', - 47: 'boxing', - 48: 'floor_climbing', - 254: 'all', # All is for goals only to include all sports. - }, - ), - 'sport_bits_0': FieldType( # Bit field corresponding to sport enum type (1 << sport). - name='sport_bits_0', - base_type=BASE_TYPES[0x0A], # uint8z - values={ - 0x01: 'generic', - 0x02: 'running', - 0x04: 'cycling', - 0x08: 'transition', # Mulitsport transition - 0x10: 'fitness_equipment', - 0x20: 'swimming', - 0x40: 'basketball', - 0x80: 'soccer', - }, - ), - 'sport_bits_1': FieldType( # Bit field corresponding to sport enum type (1 << (sport-8)). - name='sport_bits_1', - base_type=BASE_TYPES[0x0A], # uint8z - values={ - 0x01: 'tennis', - 0x02: 'american_football', - 0x04: 'training', - 0x08: 'walking', - 0x10: 'cross_country_skiing', - 0x20: 'alpine_skiing', - 0x40: 'snowboarding', - 0x80: 'rowing', - }, - ), - 'sport_bits_2': FieldType( # Bit field corresponding to sport enum type (1 << (sport-16)). - name='sport_bits_2', - base_type=BASE_TYPES[0x0A], # uint8z - values={ - 0x01: 'mountaineering', - 0x02: 'hiking', - 0x04: 'multisport', - 0x08: 'paddling', - 0x10: 'flying', - 0x20: 'e_biking', - 0x40: 'motorcycling', - 0x80: 'boating', - }, - ), - 'sport_bits_3': FieldType( # Bit field corresponding to sport enum type (1 << (sport-24)). - name='sport_bits_3', - base_type=BASE_TYPES[0x0A], # uint8z - values={ - 0x01: 'driving', - 0x02: 'golf', - 0x04: 'hang_gliding', - 0x08: 'horseback_riding', - 0x10: 'hunting', - 0x20: 'fishing', - 0x40: 'inline_skating', - 0x80: 'rock_climbing', - }, - ), - 'sport_bits_4': FieldType( # Bit field corresponding to sport enum type (1 << (sport-32)). - name='sport_bits_4', - base_type=BASE_TYPES[0x0A], # uint8z - values={ - 0x01: 'sailing', - 0x02: 'ice_skating', - 0x04: 'sky_diving', - 0x08: 'snowshoeing', - 0x10: 'snowmobiling', - 0x20: 'stand_up_paddleboarding', - 0x40: 'surfing', - 0x80: 'wakeboarding', - }, - ), - 'sport_bits_5': FieldType( # Bit field corresponding to sport enum type (1 << (sport-40)). - name='sport_bits_5', - base_type=BASE_TYPES[0x0A], # uint8z - values={ - 0x01: 'water_skiing', - 0x02: 'kayaking', - 0x04: 'rafting', - 0x08: 'windsurfing', - 0x10: 'kitesurfing', - 0x20: 'tactical', - 0x40: 'jumpmaster', - 0x80: 'boxing', - }, - ), - 'sport_bits_6': FieldType( # Bit field corresponding to sport enum type (1 << (sport-48)). - name='sport_bits_6', - base_type=BASE_TYPES[0x0A], # uint8z - values={ - 0x01: 'floor_climbing', - }, - ), - 'sport_event': FieldType( - name='sport_event', - base_type=BASE_TYPES[0x00], # enum - values={ - 0: 'uncategorized', - 1: 'geocaching', - 2: 'fitness', - 3: 'recreation', - 4: 'race', - 5: 'special_event', - 6: 'training', - 7: 'transportation', - 8: 'touring', - }, - ), - 'stroke_type': FieldType( - name='stroke_type', - base_type=BASE_TYPES[0x00], # enum - values={ - 0: 'no_event', - 1: 'other', # stroke was detected but cannot be identified - 2: 'serve', - 3: 'forehand', - 4: 'backhand', - 5: 'smash', - }, - ), - 'sub_sport': FieldType( - name='sub_sport', - base_type=BASE_TYPES[0x00], # enum - values={ - 0: 'generic', - 1: 'treadmill', # Run/Fitness Equipment - 2: 'street', # Run - 3: 'trail', # Run - 4: 'track', # Run - 5: 'spin', # Cycling - 6: 'indoor_cycling', # Cycling/Fitness Equipment - 7: 'road', # Cycling - 8: 'mountain', # Cycling - 9: 'downhill', # Cycling - 10: 'recumbent', # Cycling - 11: 'cyclocross', # Cycling - 12: 'hand_cycling', # Cycling - 13: 'track_cycling', # Cycling - 14: 'indoor_rowing', # Fitness Equipment - 15: 'elliptical', # Fitness Equipment - 16: 'stair_climbing', # Fitness Equipment - 17: 'lap_swimming', # Swimming - 18: 'open_water', # Swimming - 19: 'flexibility_training', # Training - 20: 'strength_training', # Training - 21: 'warm_up', # Tennis - 22: 'match', # Tennis - 23: 'exercise', # Tennis - 24: 'challenge', # Tennis - 25: 'indoor_skiing', # Fitness Equipment - 26: 'cardio_training', # Training - 27: 'indoor_walking', # Walking/Fitness Equipment - 28: 'e_bike_fitness', # E-Biking - 29: 'bmx', # Cycling - 30: 'casual_walking', # Walking - 31: 'speed_walking', # Walking - 32: 'bike_to_run_transition', # Transition - 33: 'run_to_bike_transition', # Transition - 34: 'swim_to_bike_transition', # Transition - 35: 'atv', # Motorcycling - 36: 'motocross', # Motorcycling - 37: 'backcountry', # Alpine Skiing/Snowboarding - 38: 'resort', # Alpine Skiing/Snowboarding - 39: 'rc_drone', # Flying - 40: 'wingsuit', # Flying - 41: 'whitewater', # Kayaking/Rafting - 42: 'skate_skiing', # Cross Country Skiing - 43: 'yoga', # Training - 44: 'pilates', # Training - 45: 'indoor_running', # Run - 46: 'gravel_cycling', # Cycling - 47: 'e_bike_mountain', # Cycling - 48: 'commuting', # Cycling - 49: 'mixed_surface', # Cycling - 50: 'navigate', - 51: 'track_me', - 52: 'map', - 254: 'all', - }, - ), - 'supported_exd_screen_layouts': FieldType( - name='supported_exd_screen_layouts', - base_type=BASE_TYPES[0x8C], # uint32z - values={ - 0x00000001: 'full_screen', - 0x00000002: 'half_vertical', - 0x00000004: 'half_horizontal', - 0x00000008: 'half_vertical_right_split', - 0x00000010: 'half_horizontal_bottom_split', - 0x00000020: 'full_quarter_split', - 0x00000040: 'half_vertical_left_split', - 0x00000080: 'half_horizontal_top_split', - }, - ), - 'swim_stroke': FieldType( - name='swim_stroke', - base_type=BASE_TYPES[0x00], # enum - values={ - 0: 'freestyle', - 1: 'backstroke', - 2: 'breaststroke', - 3: 'butterfly', - 4: 'drill', - 5: 'mixed', - 6: 'im', # IM is a mixed interval containing the same number of lengths for each of: Butterfly, Backstroke, Breaststroke, Freestyle, swam in that order. - }, - ), - 'switch': FieldType( - name='switch', - base_type=BASE_TYPES[0x00], # enum - values={ - 0: 'off', - 1: 'on', - 2: 'auto', - }, - ), - '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 - ), - 'time_mode': FieldType( - name='time_mode', - base_type=BASE_TYPES[0x00], # enum - values={ - 0: 'hour12', - 1: 'hour24', # Does not use a leading zero and has a colon - 2: 'military', # Uses a leading zero and does not have a colon - 3: 'hour_12_with_seconds', - 4: 'hour_24_with_seconds', - 5: 'utc', - }, - ), - 'time_zone': FieldType( - name='time_zone', - base_type=BASE_TYPES[0x00], # enum - values={ - 0: 'almaty', - 1: 'bangkok', - 2: 'bombay', - 3: 'brasilia', - 4: 'cairo', - 5: 'cape_verde_is', - 6: 'darwin', - 7: 'eniwetok', - 8: 'fiji', - 9: 'hong_kong', - 10: 'islamabad', - 11: 'kabul', - 12: 'magadan', - 13: 'mid_atlantic', - 14: 'moscow', - 15: 'muscat', - 16: 'newfoundland', - 17: 'samoa', - 18: 'sydney', - 19: 'tehran', - 20: 'tokyo', - 21: 'us_alaska', - 22: 'us_atlantic', - 23: 'us_central', - 24: 'us_eastern', - 25: 'us_hawaii', - 26: 'us_mountain', - 27: 'us_pacific', - 28: 'other', - 29: 'auckland', - 30: 'kathmandu', - 31: 'europe_western_wet', - 32: 'europe_central_cet', - 33: 'europe_eastern_eet', - 34: 'jakarta', - 35: 'perth', - 36: 'adelaide', - 37: 'brisbane', - 38: 'tasmania', - 39: 'iceland', - 40: 'amsterdam', - 41: 'athens', - 42: 'barcelona', - 43: 'berlin', - 44: 'brussels', - 45: 'budapest', - 46: 'copenhagen', - 47: 'dublin', - 48: 'helsinki', - 49: 'lisbon', - 50: 'london', - 51: 'madrid', - 52: 'munich', - 53: 'oslo', - 54: 'paris', - 55: 'prague', - 56: 'reykjavik', - 57: 'rome', - 58: 'stockholm', - 59: 'vienna', - 60: 'warsaw', - 61: 'zurich', - 62: 'quebec', - 63: 'ontario', - 64: 'manitoba', - 65: 'saskatchewan', - 66: 'alberta', - 67: 'british_columbia', - 68: 'boise', - 69: 'boston', - 70: 'chicago', - 71: 'dallas', - 72: 'denver', - 73: 'kansas_city', - 74: 'las_vegas', - 75: 'los_angeles', - 76: 'miami', - 77: 'minneapolis', - 78: 'new_york', - 79: 'new_orleans', - 80: 'phoenix', - 81: 'santa_fe', - 82: 'seattle', - 83: 'washington_dc', - 84: 'us_arizona', - 85: 'chita', - 86: 'ekaterinburg', - 87: 'irkutsk', - 88: 'kaliningrad', - 89: 'krasnoyarsk', - 90: 'novosibirsk', - 91: 'petropavlovsk_kamchatskiy', - 92: 'samara', - 93: 'vladivostok', - 94: 'mexico_central', - 95: 'mexico_mountain', - 96: 'mexico_pacific', - 97: 'cape_town', - 98: 'winkhoek', - 99: 'lagos', - 100: 'riyahd', - 101: 'venezuela', - 102: 'australia_lh', - 103: 'santiago', - 253: 'manual', - 254: 'automatic', - }, - ), - 'timer_trigger': FieldType( # timer event data - name='timer_trigger', - base_type=BASE_TYPES[0x00], # enum - values={ - 0: 'manual', - 1: 'auto', - 2: 'fitness_equipment', - }, - ), - 'turn_type': FieldType( - name='turn_type', - base_type=BASE_TYPES[0x00], # enum - values={ - 0: 'arriving_idx', - 1: 'arriving_left_idx', - 2: 'arriving_right_idx', - 3: 'arriving_via_idx', - 4: 'arriving_via_left_idx', - 5: 'arriving_via_right_idx', - 6: 'bear_keep_left_idx', - 7: 'bear_keep_right_idx', - 8: 'continue_idx', - 9: 'exit_left_idx', - 10: 'exit_right_idx', - 11: 'ferry_idx', - 12: 'roundabout_45_idx', - 13: 'roundabout_90_idx', - 14: 'roundabout_135_idx', - 15: 'roundabout_180_idx', - 16: 'roundabout_225_idx', - 17: 'roundabout_270_idx', - 18: 'roundabout_315_idx', - 19: 'roundabout_360_idx', - 20: 'roundabout_neg_45_idx', - 21: 'roundabout_neg_90_idx', - 22: 'roundabout_neg_135_idx', - 23: 'roundabout_neg_180_idx', - 24: 'roundabout_neg_225_idx', - 25: 'roundabout_neg_270_idx', - 26: 'roundabout_neg_315_idx', - 27: 'roundabout_neg_360_idx', - 28: 'roundabout_generic_idx', - 29: 'roundabout_neg_generic_idx', - 30: 'sharp_turn_left_idx', - 31: 'sharp_turn_right_idx', - 32: 'turn_left_idx', - 33: 'turn_right_idx', - 34: 'uturn_left_idx', - 35: 'uturn_right_idx', - 36: 'icon_inv_idx', - 37: 'icon_idx_cnt', - }, - ), - 'user_local_id': FieldType( - name='user_local_id', - base_type=BASE_TYPES[0x84], # uint16 - values={ - 0x0000: 'local_min', - 0x000F: 'local_max', - 0x0010: 'stationary_min', - 0x00FF: 'stationary_max', - 0x0100: 'portable_min', - 0xFFFE: 'portable_max', - }, - ), - 'watchface_mode': FieldType( - name='watchface_mode', - base_type=BASE_TYPES[0x00], # enum - values={ - 0: 'digital', - 1: 'analog', - 2: 'connect_iq', - 3: 'disabled', - }, - ), - 'weather_report': FieldType( - name='weather_report', - base_type=BASE_TYPES[0x00], # enum - values={ - 0: 'current', - 1: 'forecast', # Deprecated use hourly_forecast instead - 1: 'hourly_forecast', - 2: 'daily_forecast', - }, - ), - 'weather_severe_type': FieldType( - name='weather_severe_type', - base_type=BASE_TYPES[0x00], # enum - values={ - 0: 'unspecified', - 1: 'tornado', - 2: 'tsunami', - 3: 'hurricane', - 4: 'extreme_wind', - 5: 'typhoon', - 6: 'inland_hurricane', - 7: 'hurricane_force_wind', - 8: 'waterspout', - 9: 'severe_thunderstorm', - 10: 'wreckhouse_winds', - 11: 'les_suetes_wind', - 12: 'avalanche', - 13: 'flash_flood', - 14: 'tropical_storm', - 15: 'inland_tropical_storm', - 16: 'blizzard', - 17: 'ice_storm', - 18: 'freezing_rain', - 19: 'debris_flow', - 20: 'flash_freeze', - 21: 'dust_storm', - 22: 'high_wind', - 23: 'winter_storm', - 24: 'heavy_freezing_spray', - 25: 'extreme_cold', - 26: 'wind_chill', - 27: 'cold_wave', - 28: 'heavy_snow_alert', - 29: 'lake_effect_blowing_snow', - 30: 'snow_squall', - 31: 'lake_effect_snow', - 32: 'winter_weather', - 33: 'sleet', - 34: 'snowfall', - 35: 'snow_and_blowing_snow', - 36: 'blowing_snow', - 37: 'snow_alert', - 38: 'arctic_outflow', - 39: 'freezing_drizzle', - 40: 'storm', - 41: 'storm_surge', - 42: 'rainfall', - 43: 'areal_flood', - 44: 'coastal_flood', - 45: 'lakeshore_flood', - 46: 'excessive_heat', - 47: 'heat', - 48: 'weather', - 49: 'high_heat_and_humidity', - 50: 'humidex_and_health', - 51: 'humidex', - 52: 'gale', - 53: 'freezing_spray', - 54: 'special_marine', - 55: 'squall', - 56: 'strong_wind', - 57: 'lake_wind', - 58: 'marine_weather', - 59: 'wind', - 60: 'small_craft_hazardous_seas', - 61: 'hazardous_seas', - 62: 'small_craft', - 63: 'small_craft_winds', - 64: 'small_craft_rough_bar', - 65: 'high_water_level', - 66: 'ashfall', - 67: 'freezing_fog', - 68: 'dense_fog', - 69: 'dense_smoke', - 70: 'blowing_dust', - 71: 'hard_freeze', - 72: 'freeze', - 73: 'frost', - 74: 'fire_weather', - 75: 'flood', - 76: 'rip_tide', - 77: 'high_surf', - 78: 'smog', - 79: 'air_quality', - 80: 'brisk_wind', - 81: 'air_stagnation', - 82: 'low_water', - 83: 'hydrological', - 84: 'special_weather', - }, - ), - 'weather_severity': FieldType( - name='weather_severity', - base_type=BASE_TYPES[0x00], # enum - values={ - 0: 'unknown', - 1: 'warning', - 2: 'watch', - 3: 'advisory', - 4: 'statement', - }, - ), - 'weather_status': FieldType( - name='weather_status', - base_type=BASE_TYPES[0x00], # enum - values={ - 0: 'clear', - 1: 'partly_cloudy', - 2: 'mostly_cloudy', - 3: 'rain', - 4: 'snow', - 5: 'windy', - 6: 'thunderstorms', - 7: 'wintry_mix', - 8: 'fog', - 11: 'hazy', - 12: 'hail', - 13: 'scattered_showers', - 14: 'scattered_thunderstorms', - 15: 'unknown_precipitation', - 16: 'light_rain', - 17: 'heavy_rain', - 18: 'light_snow', - 19: 'heavy_snow', - 20: 'light_rain_snow', - 21: 'heavy_rain_snow', - 22: 'cloudy', - }, - ), - 'weight': FieldType( - name='weight', - base_type=BASE_TYPES[0x84], # uint16 - values={ - 0xFFFE: 'calculating', - }, - ), - 'wkt_step_duration': FieldType( - name='wkt_step_duration', - base_type=BASE_TYPES[0x00], # enum - values={ - 0: 'time', - 1: 'distance', - 2: 'hr_less_than', - 3: 'hr_greater_than', - 4: 'calories', - 5: 'open', - 6: 'repeat_until_steps_cmplt', - 7: 'repeat_until_time', - 8: 'repeat_until_distance', - 9: 'repeat_until_calories', - 10: 'repeat_until_hr_less_than', - 11: 'repeat_until_hr_greater_than', - 12: 'repeat_until_power_less_than', - 13: 'repeat_until_power_greater_than', - 14: 'power_less_than', - 15: 'power_greater_than', - 16: 'training_peaks_tss', - 17: 'repeat_until_power_last_lap_less_than', - 18: 'repeat_until_max_power_last_lap_less_than', - 19: 'power_3s_less_than', - 20: 'power_10s_less_than', - 21: 'power_30s_less_than', - 22: 'power_3s_greater_than', - 23: 'power_10s_greater_than', - 24: 'power_30s_greater_than', - 25: 'power_lap_less_than', - 26: 'power_lap_greater_than', - 27: 'repeat_until_training_peaks_tss', - 28: 'repetition_time', - }, - ), - 'wkt_step_target': FieldType( - name='wkt_step_target', - base_type=BASE_TYPES[0x00], # enum - values={ - 0: 'speed', - 1: 'heart_rate', - 2: 'open', - 3: 'cadence', - 4: 'power', - 5: 'grade', - 6: 'resistance', - 7: 'power_3s', - 8: 'power_10s', - 9: 'power_30s', - 10: 'power_lap', - 11: 'swim_stroke', - 12: 'speed_lap', - 13: 'heart_rate_lap', - }, - ), - 'workout_capabilities': FieldType( - name='workout_capabilities', - base_type=BASE_TYPES[0x8C], # uint32z - values={ - 0x00000001: 'interval', - 0x00000002: 'custom', - 0x00000004: 'fitness_equipment', - 0x00000008: 'firstbeat', - 0x00000010: 'new_leaf', - 0x00000020: 'tcx', # For backwards compatibility. Watch should add missing id fields then clear flag. - 0x00000080: 'speed', # Speed source required for workout step. - 0x00000100: 'heart_rate', # Heart rate source required for workout step. - 0x00000200: 'distance', # Distance source required for workout step. - 0x00000400: 'cadence', # Cadence source required for workout step. - 0x00000800: 'power', # Power source required for workout step. - 0x00001000: 'grade', # Grade source required for workout step. - 0x00002000: 'resistance', # Resistance source required for workout step. - 0x00004000: 'protected', - }, - ), - 'workout_equipment': FieldType( - name='workout_equipment', - base_type=BASE_TYPES[0x00], # enum - values={ - 0: 'none', - 1: 'swim_fins', - 2: 'swim_kickboard', - 3: 'swim_paddles', - 4: 'swim_pull_buoy', - 5: 'swim_snorkel', - }, - ), - 'workout_hr': FieldType( # 0 - 100 indicates% of max hr; >100 indicates bpm (255 max) plus 100 - name='workout_hr', - base_type=BASE_TYPES[0x86], # uint32 - values={ - 100: 'bpm_offset', - }, - ), - 'workout_power': FieldType( # 0 - 1000 indicates % of functional threshold power; >1000 indicates watts plus 1000. - name='workout_power', - base_type=BASE_TYPES[0x86], # uint32 - values={ - 1000: 'watts_offset', - }, - ), -} - - -FIELD_TYPE_TIMESTAMP = Field(name='timestamp', type=FIELD_TYPES['date_time'], def_num=253, units='s') - - -MESSAGE_TYPES = { - ############################ Common Messages ############################# - 0: MessageType( # Must be first message in file. - name='file_id', - mesg_num=0, - fields={ - 0: Field( - name='type', - type=FIELD_TYPES['file'], - def_num=0, - ), - 1: Field( - name='manufacturer', - type=FIELD_TYPES['manufacturer'], - def_num=1, - ), - 2: Field( - name='product', - type=BASE_TYPES[0x84], # uint16 - def_num=2, - subfields=( - SubField( - name='garmin_product', - def_num=2, - type=FIELD_TYPES['garmin_product'], - ref_fields=( - ReferenceField( - name='manufacturer', - def_num=1, - value='garmin', - raw_value=1, - ), - ReferenceField( - name='manufacturer', - def_num=1, - value='dynastream', - raw_value=15, - ), - ReferenceField( - name='manufacturer', - def_num=1, - value='dynastream_oem', - raw_value=13, - ), - ), - ), - ), - ), - 3: Field( - name='serial_number', - type=BASE_TYPES[0x8C], # uint32z - def_num=3, - ), - 4: Field( # Only set for files that are can be created/erased. - name='time_created', - type=FIELD_TYPES['date_time'], - def_num=4, - ), - 5: Field( # Only set for files that are not created/erased. - name='number', - type=BASE_TYPES[0x84], # uint16 - def_num=5, - ), - 8: Field( # Optional free form string to indicate the devices name or model - name='product_name', - type=BASE_TYPES[0x07], # string - def_num=8, - ), - }, - ), - - - #################################### #################################### - 1: MessageType( - name='capabilities', - mesg_num=1, - fields={ - 0: Field( # Use language_bits_x types where x is index of array. - name='languages', - type=BASE_TYPES[0x0A], # uint8z - def_num=0, - ), - 1: Field( # Use sport_bits_x types where x is index of array. - name='sports', - type=FIELD_TYPES['sport_bits_0'], - def_num=1, - ), - 21: Field( - name='workouts_supported', - type=FIELD_TYPES['workout_capabilities'], - def_num=21, - ), - 23: Field( - name='connectivity_supported', - type=FIELD_TYPES['connectivity_capabilities'], - def_num=23, - ), - }, - ), - 3: MessageType( - name='user_profile', - mesg_num=3, - fields={ - 0: Field( - name='friendly_name', - type=BASE_TYPES[0x07], # string - def_num=0, - ), - 1: Field( - name='gender', - type=FIELD_TYPES['gender'], - def_num=1, - ), - 2: Field( - name='age', - type=BASE_TYPES[0x02], # uint8 - def_num=2, - units='years', - ), - 3: Field( - name='height', - type=BASE_TYPES[0x02], # uint8 - def_num=3, - scale=100, - units='m', - ), - 4: Field( - name='weight', - type=BASE_TYPES[0x84], # uint16 - def_num=4, - scale=10, - units='kg', - ), - 5: Field( - name='language', - type=FIELD_TYPES['language'], - def_num=5, - ), - 6: Field( - name='elev_setting', - type=FIELD_TYPES['display_measure'], - def_num=6, - ), - 7: Field( - name='weight_setting', - type=FIELD_TYPES['display_measure'], - def_num=7, - ), - 8: Field( - name='resting_heart_rate', - type=BASE_TYPES[0x02], # uint8 - def_num=8, - units='bpm', - ), - 9: Field( - name='default_max_running_heart_rate', - type=BASE_TYPES[0x02], # uint8 - def_num=9, - units='bpm', - ), - 10: Field( - name='default_max_biking_heart_rate', - type=BASE_TYPES[0x02], # uint8 - def_num=10, - 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', - ), - 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', - type=BASE_TYPES[0x84], # uint16 - def_num=11, - scale=10, - units='%', - ), - 12: Field( - name='auto_wheel_cal', - type=FIELD_TYPES['bool'], - def_num=12, - ), - 13: Field( - name='auto_power_zero', - type=FIELD_TYPES['bool'], - def_num=13, - ), - 14: Field( - name='id', - type=BASE_TYPES[0x02], # uint8 - def_num=14, - ), - 15: Field( - name='spd_enabled', - type=FIELD_TYPES['bool'], - def_num=15, - ), - 16: Field( - name='cad_enabled', - type=FIELD_TYPES['bool'], - def_num=16, - ), - 17: Field( - name='spdcad_enabled', - type=FIELD_TYPES['bool'], - def_num=17, - ), - 18: Field( - name='power_enabled', - type=FIELD_TYPES['bool'], - def_num=18, - ), - 19: Field( - name='crank_length', - type=BASE_TYPES[0x02], # uint8 - def_num=19, - scale=2, - offset=-110, - units='mm', - ), - 20: Field( - name='enabled', - type=FIELD_TYPES['bool'], - def_num=20, - ), - 21: Field( - name='bike_spd_ant_id_trans_type', - type=BASE_TYPES[0x0A], # uint8z - def_num=21, - ), - 22: Field( - name='bike_cad_ant_id_trans_type', - type=BASE_TYPES[0x0A], # uint8z - def_num=22, - ), - 23: Field( - name='bike_spdcad_ant_id_trans_type', - type=BASE_TYPES[0x0A], # uint8z - def_num=23, - ), - 24: Field( - name='bike_power_ant_id_trans_type', - type=BASE_TYPES[0x0A], # uint8z - def_num=24, - ), - 37: Field( # Rollover counter that can be used to extend the odometer - name='odometer_rollover', - type=BASE_TYPES[0x02], # uint8 - def_num=37, - ), - 38: Field( # Number of front gears - name='front_gear_num', - type=BASE_TYPES[0x0A], # uint8z - def_num=38, - ), - 39: Field( # Number of teeth on each gear 0 is innermost - name='front_gear', - type=BASE_TYPES[0x0A], # uint8z - def_num=39, - ), - 40: Field( # Number of rear gears - name='rear_gear_num', - type=BASE_TYPES[0x0A], # uint8z - def_num=40, - ), - 41: Field( # Number of teeth on each gear 0 is innermost - name='rear_gear', - type=BASE_TYPES[0x0A], # uint8z - def_num=41, - ), - 44: Field( - name='shimano_di2_enabled', - type=FIELD_TYPES['bool'], - def_num=44, - ), - 254: Field( - name='message_index', - type=FIELD_TYPES['message_index'], - def_num=254, - ), - }, - ), - 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( - name='message_index', - type=FIELD_TYPES['message_index'], - def_num=254, - ), - }, - ), - 9: MessageType( - name='power_zone', - mesg_num=9, - fields={ - 1: Field( - name='high_value', - type=BASE_TYPES[0x84], # uint16 - def_num=1, - units='watts', - ), - 2: Field( - name='name', - type=BASE_TYPES[0x07], # string - def_num=2, - ), - 254: Field( - name='message_index', - type=FIELD_TYPES['message_index'], - def_num=254, - ), - }, - ), - 10: MessageType( - name='met_zone', - mesg_num=10, - fields={ - 1: Field( - name='high_bpm', - type=BASE_TYPES[0x02], # uint8 - def_num=1, - ), - 2: Field( - name='calories', - type=BASE_TYPES[0x84], # uint16 - def_num=2, - scale=10, - units='kcal/min', - ), - 3: Field( - name='fat_calories', - type=BASE_TYPES[0x02], # uint8 - def_num=3, - scale=10, - units='kcal/min', - ), - 254: Field( - name='message_index', - type=FIELD_TYPES['message_index'], - def_num=254, - ), - }, - ), - 12: MessageType( - name='sport', - mesg_num=12, - 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, - ), - 3: Field( - name='name', - type=BASE_TYPES[0x07], # string - def_num=3, - ), - }, - ), - 18: MessageType( - name='session', - mesg_num=18, - fields={ - 0: Field( # session - name='event', - type=FIELD_TYPES['event'], - def_num=0, - ), - 1: Field( # stop - name='event_type', - type=FIELD_TYPES['event_type'], - def_num=1, - ), - 2: Field( - name='start_time', - type=FIELD_TYPES['date_time'], - def_num=2, - ), - 3: Field( - name='start_position_lat', - type=BASE_TYPES[0x85], # sint32 - def_num=3, - units='semicircles', - ), - 4: Field( - name='start_position_long', - type=BASE_TYPES[0x85], # sint32 - def_num=4, - units='semicircles', - ), - 5: Field( - name='sport', - type=FIELD_TYPES['sport'], - def_num=5, - ), - 6: Field( - name='sub_sport', - type=FIELD_TYPES['sub_sport'], - def_num=6, - ), - 7: Field( # Time (includes pauses) - name='total_elapsed_time', - type=BASE_TYPES[0x86], # uint32 - def_num=7, - scale=1000, - units='s', - ), - 8: Field( # Timer Time (excludes pauses) - name='total_timer_time', - type=BASE_TYPES[0x86], # uint32 - def_num=8, - scale=1000, - units='s', - ), - 9: Field( - name='total_distance', - type=BASE_TYPES[0x86], # uint32 - def_num=9, - scale=100, - units='m', - ), - 10: Field( - name='total_cycles', - type=BASE_TYPES[0x86], # uint32 - def_num=10, - units='cycles', - subfields=( - SubField( - name='total_strides', - def_num=10, - type=BASE_TYPES[0x86], # uint32 - units='strides', - ref_fields=( - ReferenceField( - name='sport', - def_num=5, - value='running', - raw_value=1, - ), - ReferenceField( - name='sport', - def_num=5, - value='walking', - raw_value=11, - ), - ), - ), - ), - ), - 11: Field( - name='total_calories', - type=BASE_TYPES[0x84], # uint16 - def_num=11, - units='kcal', - ), - 13: Field( # If New Leaf - name='total_fat_calories', - type=BASE_TYPES[0x84], # uint16 - def_num=13, - units='kcal', - ), - 14: Field( # total_distance / total_timer_time - name='avg_speed', - type=BASE_TYPES[0x84], # uint16 - def_num=14, - scale=1000, - units='m/s', - components=( - ComponentField( - name='enhanced_avg_speed', - def_num=124, - scale=1000, - units='m/s', - accumulate=False, - bits=16, - bit_offset=0, - ), - ), - ), - 15: Field( - name='max_speed', - type=BASE_TYPES[0x84], # uint16 - def_num=15, - scale=1000, - units='m/s', - components=( - ComponentField( - name='enhanced_max_speed', - def_num=125, - scale=1000, - units='m/s', - accumulate=False, - bits=16, - bit_offset=0, - ), - ), - ), - 16: Field( # average heart rate (excludes pause time) - name='avg_heart_rate', - type=BASE_TYPES[0x02], # uint8 - def_num=16, - units='bpm', - ), - 17: Field( - name='max_heart_rate', - type=BASE_TYPES[0x02], # uint8 - def_num=17, - units='bpm', - ), - 18: Field( # total_cycles / total_timer_time if non_zero_avg_cadence otherwise total_cycles / total_elapsed_time - name='avg_cadence', - type=BASE_TYPES[0x02], # uint8 - def_num=18, - units='rpm', - subfields=( - SubField( - name='avg_running_cadence', - def_num=18, - type=BASE_TYPES[0x02], # uint8 - units='strides/min', - ref_fields=( - ReferenceField( - name='sport', - def_num=5, - value='running', - raw_value=1, - ), - ), - ), - ), - ), - 19: Field( - name='max_cadence', - type=BASE_TYPES[0x02], # uint8 - def_num=19, - units='rpm', - subfields=( - SubField( - name='max_running_cadence', - def_num=19, - type=BASE_TYPES[0x02], # uint8 - units='strides/min', - ref_fields=( - ReferenceField( - name='sport', - def_num=5, - value='running', - raw_value=1, - ), - ), - ), - ), - ), - 20: Field( # total_power / total_timer_time if non_zero_avg_power otherwise total_power / total_elapsed_time - name='avg_power', - type=BASE_TYPES[0x84], # uint16 - def_num=20, - units='watts', - ), - 21: Field( - name='max_power', - type=BASE_TYPES[0x84], # uint16 - def_num=21, - units='watts', - ), - 22: Field( - name='total_ascent', - type=BASE_TYPES[0x84], # uint16 - def_num=22, - units='m', - ), - 23: Field( - name='total_descent', - type=BASE_TYPES[0x84], # uint16 - def_num=23, - units='m', - ), - 24: Field( - name='total_training_effect', - type=BASE_TYPES[0x02], # uint8 - def_num=24, - scale=10, - ), - 25: Field( - name='first_lap_index', - type=BASE_TYPES[0x84], # uint16 - def_num=25, - ), - 26: Field( - name='num_laps', - type=BASE_TYPES[0x84], # uint16 - def_num=26, - ), - 27: Field( - name='event_group', - type=BASE_TYPES[0x02], # uint8 - def_num=27, - ), - 28: Field( - name='trigger', - type=FIELD_TYPES['session_trigger'], - def_num=28, - ), - 29: Field( - name='nec_lat', - type=BASE_TYPES[0x85], # sint32 - def_num=29, - units='semicircles', - ), - 30: Field( - name='nec_long', - type=BASE_TYPES[0x85], # sint32 - def_num=30, - units='semicircles', - ), - 31: Field( - name='swc_lat', - type=BASE_TYPES[0x85], # sint32 - def_num=31, - units='semicircles', - ), - 32: Field( - name='swc_long', - type=BASE_TYPES[0x85], # sint32 - def_num=32, - units='semicircles', - ), - 34: Field( - name='normalized_power', - type=BASE_TYPES[0x84], # uint16 - def_num=34, - units='watts', - ), - 35: Field( - name='training_stress_score', - type=BASE_TYPES[0x84], # uint16 - def_num=35, - scale=10, - units='tss', - ), - 36: Field( - name='intensity_factor', - type=BASE_TYPES[0x84], # uint16 - def_num=36, - scale=1000, - units='if', - ), - 37: Field( - name='left_right_balance', - type=FIELD_TYPES['left_right_balance_100'], - def_num=37, - ), - 41: Field( - name='avg_stroke_count', - type=BASE_TYPES[0x86], # uint32 - def_num=41, - scale=10, - units='strokes/lap', - ), - 42: Field( - name='avg_stroke_distance', - type=BASE_TYPES[0x84], # uint16 - def_num=42, - scale=100, - units='m', - ), - 43: Field( - name='swim_stroke', - type=FIELD_TYPES['swim_stroke'], - def_num=43, - units='swim_stroke', - ), - 44: Field( - name='pool_length', - type=BASE_TYPES[0x84], # uint16 - def_num=44, - scale=100, - units='m', - ), - 45: Field( - name='threshold_power', - type=BASE_TYPES[0x84], # uint16 - def_num=45, - units='watts', - ), - 46: Field( - name='pool_length_unit', - type=FIELD_TYPES['display_measure'], - def_num=46, - ), - 47: Field( # # of active lengths of swim pool - name='num_active_lengths', - type=BASE_TYPES[0x84], # uint16 - def_num=47, - units='lengths', - ), - 48: Field( - name='total_work', - type=BASE_TYPES[0x86], # uint32 - def_num=48, - units='J', - ), - 49: Field( - name='avg_altitude', - type=BASE_TYPES[0x84], # uint16 - def_num=49, - scale=5, - offset=500, - units='m', - components=( - ComponentField( - name='enhanced_avg_altitude', - def_num=126, - scale=5, - offset=500, - units='m', - accumulate=False, - bits=16, - bit_offset=0, - ), - ), - ), - 50: Field( - name='max_altitude', - type=BASE_TYPES[0x84], # uint16 - def_num=50, - scale=5, - offset=500, - units='m', - components=( - ComponentField( - name='enhanced_max_altitude', - def_num=128, - scale=5, - offset=500, - units='m', - accumulate=False, - bits=16, - bit_offset=0, - ), - ), - ), - 51: Field( - name='gps_accuracy', - type=BASE_TYPES[0x02], # uint8 - def_num=51, - units='m', - ), - 52: Field( - name='avg_grade', - type=BASE_TYPES[0x83], # sint16 - def_num=52, - scale=100, - units='%', - ), - 53: Field( - name='avg_pos_grade', - type=BASE_TYPES[0x83], # sint16 - def_num=53, - scale=100, - units='%', - ), - 54: Field( - name='avg_neg_grade', - type=BASE_TYPES[0x83], # sint16 - def_num=54, - scale=100, - units='%', - ), - 55: Field( - name='max_pos_grade', - type=BASE_TYPES[0x83], # sint16 - def_num=55, - scale=100, - units='%', - ), - 56: Field( - name='max_neg_grade', - type=BASE_TYPES[0x83], # sint16 - def_num=56, - scale=100, - units='%', - ), - 57: Field( - name='avg_temperature', - type=BASE_TYPES[0x01], # sint8 - def_num=57, - units='C', - ), - 58: Field( - name='max_temperature', - type=BASE_TYPES[0x01], # sint8 - def_num=58, - units='C', - ), - 59: Field( - name='total_moving_time', - type=BASE_TYPES[0x86], # uint32 - def_num=59, - scale=1000, - units='s', - ), - 60: Field( - name='avg_pos_vertical_speed', - type=BASE_TYPES[0x83], # sint16 - def_num=60, - scale=1000, - units='m/s', - ), - 61: Field( - name='avg_neg_vertical_speed', - type=BASE_TYPES[0x83], # sint16 - def_num=61, - scale=1000, - units='m/s', - ), - 62: Field( - name='max_pos_vertical_speed', - type=BASE_TYPES[0x83], # sint16 - def_num=62, - scale=1000, - units='m/s', - ), - 63: Field( - name='max_neg_vertical_speed', - type=BASE_TYPES[0x83], # sint16 - def_num=63, - scale=1000, - units='m/s', - ), - 64: Field( - name='min_heart_rate', - type=BASE_TYPES[0x02], # uint8 - def_num=64, - units='bpm', - ), - 65: Field( - name='time_in_hr_zone', - type=BASE_TYPES[0x86], # uint32 - def_num=65, - scale=1000, - units='s', - ), - 66: Field( - name='time_in_speed_zone', - type=BASE_TYPES[0x86], # uint32 - def_num=66, - scale=1000, - units='s', - ), - 67: Field( - name='time_in_cadence_zone', - type=BASE_TYPES[0x86], # uint32 - def_num=67, - scale=1000, - units='s', - ), - 68: Field( - name='time_in_power_zone', - type=BASE_TYPES[0x86], # uint32 - def_num=68, - scale=1000, - units='s', - ), - 69: Field( - name='avg_lap_time', - type=BASE_TYPES[0x86], # uint32 - def_num=69, - scale=1000, - units='s', - ), - 70: Field( - name='best_lap_index', - type=BASE_TYPES[0x84], # uint16 - def_num=70, - ), - 71: Field( - name='min_altitude', - type=BASE_TYPES[0x84], # uint16 - def_num=71, - scale=5, - offset=500, - units='m', - components=( - ComponentField( - name='enhanced_min_altitude', - def_num=127, - scale=5, - offset=500, - units='m', - accumulate=False, - bits=16, - bit_offset=0, - ), - ), - ), - 82: Field( - name='player_score', - type=BASE_TYPES[0x84], # uint16 - def_num=82, - ), - 83: Field( - name='opponent_score', - type=BASE_TYPES[0x84], # uint16 - def_num=83, - ), - 84: Field( - name='opponent_name', - type=BASE_TYPES[0x07], # string - def_num=84, - ), - 85: Field( # stroke_type enum used as the index - name='stroke_count', - type=BASE_TYPES[0x84], # uint16 - def_num=85, - units='counts', - ), - 86: Field( # zone number used as the index - name='zone_count', - type=BASE_TYPES[0x84], # uint16 - def_num=86, - units='counts', - ), - 87: Field( - name='max_ball_speed', - type=BASE_TYPES[0x84], # uint16 - def_num=87, - scale=100, - units='m/s', - ), - 88: Field( - name='avg_ball_speed', - type=BASE_TYPES[0x84], # uint16 - def_num=88, - scale=100, - units='m/s', - ), - 89: Field( - name='avg_vertical_oscillation', - type=BASE_TYPES[0x84], # uint16 - def_num=89, - scale=10, - units='mm', - ), - 90: Field( - name='avg_stance_time_percent', - type=BASE_TYPES[0x84], # uint16 - def_num=90, - scale=100, - units='percent', - ), - 91: Field( - name='avg_stance_time', - type=BASE_TYPES[0x84], # uint16 - def_num=91, - scale=10, - units='ms', - ), - 92: Field( # fractional part of the avg_cadence - name='avg_fractional_cadence', - type=BASE_TYPES[0x02], # uint8 - def_num=92, - scale=128, - units='rpm', - ), - 93: Field( # fractional part of the max_cadence - name='max_fractional_cadence', - type=BASE_TYPES[0x02], # uint8 - def_num=93, - scale=128, - units='rpm', - ), - 94: Field( # fractional part of the total_cycles - name='total_fractional_cycles', - type=BASE_TYPES[0x02], # uint8 - def_num=94, - scale=128, - units='cycles', - ), - 95: Field( # Avg saturated and unsaturated hemoglobin - name='avg_total_hemoglobin_conc', - type=BASE_TYPES[0x84], # uint16 - def_num=95, - scale=100, - units='g/dL', - ), - 96: Field( # Min saturated and unsaturated hemoglobin - name='min_total_hemoglobin_conc', - type=BASE_TYPES[0x84], # uint16 - def_num=96, - scale=100, - units='g/dL', - ), - 97: Field( # Max saturated and unsaturated hemoglobin - name='max_total_hemoglobin_conc', - type=BASE_TYPES[0x84], # uint16 - def_num=97, - scale=100, - units='g/dL', - ), - 98: Field( # Avg percentage of hemoglobin saturated with oxygen - name='avg_saturated_hemoglobin_percent', - type=BASE_TYPES[0x84], # uint16 - def_num=98, - scale=10, - units='%', - ), - 99: Field( # Min percentage of hemoglobin saturated with oxygen - name='min_saturated_hemoglobin_percent', - type=BASE_TYPES[0x84], # uint16 - def_num=99, - scale=10, - units='%', - ), - 100: Field( # Max percentage of hemoglobin saturated with oxygen - name='max_saturated_hemoglobin_percent', - type=BASE_TYPES[0x84], # uint16 - def_num=100, - scale=10, - units='%', - ), - 101: Field( - name='avg_left_torque_effectiveness', - type=BASE_TYPES[0x02], # uint8 - def_num=101, - scale=2, - units='percent', - ), - 102: Field( - name='avg_right_torque_effectiveness', - type=BASE_TYPES[0x02], # uint8 - def_num=102, - scale=2, - units='percent', - ), - 103: Field( - name='avg_left_pedal_smoothness', - type=BASE_TYPES[0x02], # uint8 - def_num=103, - scale=2, - units='percent', - ), - 104: Field( - name='avg_right_pedal_smoothness', - type=BASE_TYPES[0x02], # uint8 - def_num=104, - scale=2, - units='percent', - ), - 105: Field( - name='avg_combined_pedal_smoothness', - type=BASE_TYPES[0x02], # uint8 - def_num=105, - scale=2, - units='percent', - ), - 111: Field( - name='sport_index', - type=BASE_TYPES[0x02], # uint8 - def_num=111, - ), - 112: Field( # Total time spend in the standing position - name='time_standing', - type=BASE_TYPES[0x86], # uint32 - def_num=112, - scale=1000, - units='s', - ), - 113: Field( # Number of transitions to the standing state - name='stand_count', - type=BASE_TYPES[0x84], # uint16 - def_num=113, - ), - 114: Field( # Average platform center offset Left - name='avg_left_pco', - type=BASE_TYPES[0x01], # sint8 - def_num=114, - units='mm', - ), - 115: Field( # Average platform center offset Right - name='avg_right_pco', - type=BASE_TYPES[0x01], # sint8 - def_num=115, - units='mm', - ), - 116: Field( # Average left power phase angles. Indexes defined by power_phase_type. - name='avg_left_power_phase', - type=BASE_TYPES[0x02], # uint8 - def_num=116, - scale=0.7111111, - units='degrees', - ), - 117: 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=117, - scale=0.7111111, - units='degrees', - ), - 118: 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=118, - scale=0.7111111, - units='degrees', - ), - 119: 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=119, - scale=0.7111111, - units='degrees', - ), - 120: Field( # Average power by position. Data value indexes defined by rider_position_type. - name='avg_power_position', - type=BASE_TYPES[0x84], # uint16 - def_num=120, - units='watts', - ), - 121: Field( # Maximum power by position. Data value indexes defined by rider_position_type. - name='max_power_position', - type=BASE_TYPES[0x84], # uint16 - def_num=121, - units='watts', - ), - 122: Field( # Average cadence by position. Data value indexes defined by rider_position_type. - name='avg_cadence_position', - type=BASE_TYPES[0x02], # uint8 - def_num=122, - units='rpm', - ), - 123: Field( # Maximum cadence by position. Data value indexes defined by rider_position_type. - name='max_cadence_position', - type=BASE_TYPES[0x02], # uint8 - def_num=123, - units='rpm', - ), - 124: Field( # total_distance / total_timer_time - name='enhanced_avg_speed', - type=BASE_TYPES[0x86], # uint32 - def_num=124, - scale=1000, - units='m/s', - ), - 125: Field( - name='enhanced_max_speed', - type=BASE_TYPES[0x86], # uint32 - def_num=125, - scale=1000, - units='m/s', - ), - 126: Field( - name='enhanced_avg_altitude', - type=BASE_TYPES[0x86], # uint32 - def_num=126, - scale=5, - offset=500, - units='m', - ), - 127: Field( - name='enhanced_min_altitude', - type=BASE_TYPES[0x86], # uint32 - def_num=127, - scale=5, - offset=500, - units='m', - ), - 128: Field( - name='enhanced_max_altitude', - type=BASE_TYPES[0x86], # uint32 - def_num=128, - scale=5, - offset=500, - units='m', - ), - 129: Field( # lev average motor power during session - name='avg_lev_motor_power', - type=BASE_TYPES[0x84], # uint16 - def_num=129, - units='watts', - ), - 130: Field( # lev maximum motor power during session - name='max_lev_motor_power', - type=BASE_TYPES[0x84], # uint16 - def_num=130, - units='watts', - ), - 131: Field( # lev battery consumption during session - name='lev_battery_consumption', - type=BASE_TYPES[0x02], # uint8 - def_num=131, - scale=2, - units='percent', - ), - 132: Field( - name='avg_vertical_ratio', - type=BASE_TYPES[0x84], # uint16 - def_num=132, - scale=100, - units='percent', - ), - 133: Field( - name='avg_stance_time_balance', - type=BASE_TYPES[0x84], # uint16 - def_num=133, - scale=100, - units='percent', - ), - 134: Field( - name='avg_step_length', - type=BASE_TYPES[0x84], # uint16 - def_num=134, - scale=10, - units='mm', - ), - 137: Field( - name='total_anaerobic_training_effect', - type=BASE_TYPES[0x02], # uint8 - def_num=137, - scale=10, - ), - 139: Field( - name='avg_vam', - type=BASE_TYPES[0x84], # uint16 - def_num=139, - scale=1000, - units='m/s', - ), - 253: FIELD_TYPE_TIMESTAMP, # Sesson end time. - 254: Field( # Selected bit is set for the current session. - name='message_index', - type=FIELD_TYPES['message_index'], - def_num=254, - ), - }, - ), - 19: MessageType( - name='lap', - mesg_num=19, - 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='start_time', - type=FIELD_TYPES['date_time'], - def_num=2, - ), - 3: Field( - name='start_position_lat', - type=BASE_TYPES[0x85], # sint32 - def_num=3, - units='semicircles', - ), - 4: Field( - name='start_position_long', - type=BASE_TYPES[0x85], # sint32 - def_num=4, - units='semicircles', - ), - 5: Field( - name='end_position_lat', - type=BASE_TYPES[0x85], # sint32 - def_num=5, - units='semicircles', - ), - 6: Field( - name='end_position_long', - type=BASE_TYPES[0x85], # sint32 - def_num=6, - units='semicircles', - ), - 7: Field( # Time (includes pauses) - name='total_elapsed_time', - type=BASE_TYPES[0x86], # uint32 - def_num=7, - scale=1000, - units='s', - ), - 8: Field( # Timer Time (excludes pauses) - name='total_timer_time', - type=BASE_TYPES[0x86], # uint32 - def_num=8, - scale=1000, - units='s', - ), - 9: Field( - name='total_distance', - type=BASE_TYPES[0x86], # uint32 - def_num=9, - scale=100, - units='m', - ), - 10: Field( - name='total_cycles', - type=BASE_TYPES[0x86], # uint32 - def_num=10, - units='cycles', - subfields=( - SubField( - name='total_strides', - def_num=10, - type=BASE_TYPES[0x86], # uint32 - units='strides', - ref_fields=( - ReferenceField( - name='sport', - def_num=25, - value='running', - raw_value=1, - ), - ReferenceField( - name='sport', - def_num=25, - value='walking', - raw_value=11, - ), - ), - ), - ), - ), - 11: Field( - name='total_calories', - type=BASE_TYPES[0x84], # uint16 - def_num=11, - units='kcal', - ), - 12: Field( # If New Leaf - name='total_fat_calories', - type=BASE_TYPES[0x84], # uint16 - def_num=12, - units='kcal', - ), - 13: Field( - name='avg_speed', - type=BASE_TYPES[0x84], # uint16 - def_num=13, - scale=1000, - units='m/s', - components=( - ComponentField( - name='enhanced_avg_speed', - def_num=110, - scale=1000, - units='m/s', - accumulate=False, - bits=16, - bit_offset=0, - ), - ), - ), - 14: Field( - name='max_speed', - type=BASE_TYPES[0x84], # uint16 - def_num=14, - scale=1000, - units='m/s', - components=( - ComponentField( - name='enhanced_max_speed', - def_num=111, - scale=1000, - units='m/s', - accumulate=False, - bits=16, - bit_offset=0, - ), - ), - ), - 15: Field( - name='avg_heart_rate', - type=BASE_TYPES[0x02], # uint8 - def_num=15, - units='bpm', - ), - 16: Field( - name='max_heart_rate', - type=BASE_TYPES[0x02], # uint8 - def_num=16, - units='bpm', - ), - 17: Field( # total_cycles / total_timer_time if non_zero_avg_cadence otherwise total_cycles / total_elapsed_time - name='avg_cadence', - type=BASE_TYPES[0x02], # uint8 - def_num=17, - units='rpm', - subfields=( - SubField( - name='avg_running_cadence', - def_num=17, - type=BASE_TYPES[0x02], # uint8 - units='strides/min', - ref_fields=( - ReferenceField( - name='sport', - def_num=25, - value='running', - raw_value=1, - ), - ), - ), - ), - ), - 18: Field( - name='max_cadence', - type=BASE_TYPES[0x02], # uint8 - def_num=18, - units='rpm', - subfields=( - SubField( - name='max_running_cadence', - def_num=18, - type=BASE_TYPES[0x02], # uint8 - units='strides/min', - ref_fields=( - ReferenceField( - name='sport', - def_num=25, - value='running', - raw_value=1, - ), - ), - ), - ), - ), - 19: Field( # total_power / total_timer_time if non_zero_avg_power otherwise total_power / total_elapsed_time - name='avg_power', - type=BASE_TYPES[0x84], # uint16 - def_num=19, - units='watts', - ), - 20: Field( - name='max_power', - type=BASE_TYPES[0x84], # uint16 - def_num=20, - units='watts', - ), - 21: Field( - name='total_ascent', - type=BASE_TYPES[0x84], # uint16 - def_num=21, - units='m', - ), - 22: Field( - name='total_descent', - type=BASE_TYPES[0x84], # uint16 - def_num=22, - units='m', - ), - 23: Field( - name='intensity', - type=FIELD_TYPES['intensity'], - def_num=23, - ), - 24: Field( - name='lap_trigger', - type=FIELD_TYPES['lap_trigger'], - def_num=24, - ), - 25: Field( - name='sport', - type=FIELD_TYPES['sport'], - def_num=25, - ), - 26: Field( - name='event_group', - type=BASE_TYPES[0x02], # uint8 - def_num=26, - ), - 32: Field( # # of lengths of swim pool - name='num_lengths', - type=BASE_TYPES[0x84], # uint16 - def_num=32, - units='lengths', - ), - 33: Field( - name='normalized_power', - type=BASE_TYPES[0x84], # uint16 - def_num=33, - units='watts', - ), - 34: Field( - name='left_right_balance', - type=FIELD_TYPES['left_right_balance_100'], - def_num=34, - ), - 35: Field( - name='first_length_index', - type=BASE_TYPES[0x84], # uint16 - def_num=35, - ), - 37: Field( - name='avg_stroke_distance', - type=BASE_TYPES[0x84], # uint16 - def_num=37, - scale=100, - units='m', - ), - 38: Field( - name='swim_stroke', - type=FIELD_TYPES['swim_stroke'], - def_num=38, - ), - 39: Field( - name='sub_sport', - type=FIELD_TYPES['sub_sport'], - def_num=39, - ), - 40: Field( # # of active lengths of swim pool - name='num_active_lengths', - type=BASE_TYPES[0x84], # uint16 - def_num=40, - units='lengths', - ), - 41: Field( - name='total_work', - type=BASE_TYPES[0x86], # uint32 - def_num=41, - units='J', - ), - 42: Field( - name='avg_altitude', - type=BASE_TYPES[0x84], # uint16 - def_num=42, - scale=5, - offset=500, - units='m', - components=( - ComponentField( - name='enhanced_avg_altitude', - def_num=112, - scale=5, - offset=500, - units='m', - accumulate=False, - bits=16, - bit_offset=0, - ), - ), - ), - 43: Field( - name='max_altitude', - type=BASE_TYPES[0x84], # uint16 - def_num=43, - scale=5, - offset=500, - units='m', - components=( - ComponentField( - name='enhanced_max_altitude', - def_num=114, - scale=5, - offset=500, - units='m', - accumulate=False, - bits=16, - bit_offset=0, - ), - ), - ), - 44: Field( - name='gps_accuracy', - type=BASE_TYPES[0x02], # uint8 - def_num=44, - units='m', - ), - 45: Field( - name='avg_grade', - type=BASE_TYPES[0x83], # sint16 - def_num=45, - scale=100, - units='%', - ), - 46: Field( - name='avg_pos_grade', - type=BASE_TYPES[0x83], # sint16 - def_num=46, - scale=100, - units='%', - ), - 47: Field( - name='avg_neg_grade', - type=BASE_TYPES[0x83], # sint16 - def_num=47, - scale=100, - units='%', - ), - 48: Field( - name='max_pos_grade', - type=BASE_TYPES[0x83], # sint16 - def_num=48, - scale=100, - units='%', - ), - 49: Field( - name='max_neg_grade', - type=BASE_TYPES[0x83], # sint16 - def_num=49, - scale=100, - units='%', - ), - 50: Field( - name='avg_temperature', - type=BASE_TYPES[0x01], # sint8 - def_num=50, - units='C', - ), - 51: Field( - name='max_temperature', - type=BASE_TYPES[0x01], # sint8 - def_num=51, - units='C', - ), - 52: Field( - name='total_moving_time', - type=BASE_TYPES[0x86], # uint32 - def_num=52, - scale=1000, - units='s', - ), - 53: Field( - name='avg_pos_vertical_speed', - type=BASE_TYPES[0x83], # sint16 - def_num=53, - scale=1000, - units='m/s', - ), - 54: Field( - name='avg_neg_vertical_speed', - type=BASE_TYPES[0x83], # sint16 - def_num=54, - scale=1000, - units='m/s', - ), - 55: Field( - name='max_pos_vertical_speed', - type=BASE_TYPES[0x83], # sint16 - def_num=55, - scale=1000, - units='m/s', - ), - 56: Field( - name='max_neg_vertical_speed', - type=BASE_TYPES[0x83], # sint16 - def_num=56, - scale=1000, - units='m/s', - ), - 57: Field( - name='time_in_hr_zone', - type=BASE_TYPES[0x86], # uint32 - def_num=57, - scale=1000, - units='s', - ), - 58: Field( - name='time_in_speed_zone', - type=BASE_TYPES[0x86], # uint32 - def_num=58, - scale=1000, - units='s', - ), - 59: Field( - name='time_in_cadence_zone', - type=BASE_TYPES[0x86], # uint32 - def_num=59, - scale=1000, - units='s', - ), - 60: Field( - name='time_in_power_zone', - type=BASE_TYPES[0x86], # uint32 - def_num=60, - scale=1000, - units='s', - ), - 61: Field( - name='repetition_num', - type=BASE_TYPES[0x84], # uint16 - def_num=61, - ), - 62: Field( - name='min_altitude', - type=BASE_TYPES[0x84], # uint16 - def_num=62, - scale=5, - offset=500, - units='m', - components=( - ComponentField( - name='enhanced_min_altitude', - def_num=113, - scale=5, - offset=500, - units='m', - accumulate=False, - bits=16, - bit_offset=0, - ), - ), - ), - 63: Field( - name='min_heart_rate', - type=BASE_TYPES[0x02], # uint8 - def_num=63, - units='bpm', - ), - 71: Field( - name='wkt_step_index', - type=FIELD_TYPES['message_index'], - def_num=71, - ), - 74: Field( - name='opponent_score', - type=BASE_TYPES[0x84], # uint16 - def_num=74, - ), - 75: Field( # stroke_type enum used as the index - name='stroke_count', - type=BASE_TYPES[0x84], # uint16 - def_num=75, - units='counts', - ), - 76: Field( # zone number used as the index - name='zone_count', - type=BASE_TYPES[0x84], # uint16 - def_num=76, - units='counts', - ), - 77: Field( - name='avg_vertical_oscillation', - type=BASE_TYPES[0x84], # uint16 - def_num=77, - scale=10, - units='mm', - ), - 78: Field( - name='avg_stance_time_percent', - type=BASE_TYPES[0x84], # uint16 - def_num=78, - scale=100, - units='percent', - ), - 79: Field( - name='avg_stance_time', - type=BASE_TYPES[0x84], # uint16 - def_num=79, - scale=10, - units='ms', - ), - 80: Field( # fractional part of the avg_cadence - name='avg_fractional_cadence', - type=BASE_TYPES[0x02], # uint8 - def_num=80, - scale=128, - units='rpm', - ), - 81: Field( # fractional part of the max_cadence - name='max_fractional_cadence', - type=BASE_TYPES[0x02], # uint8 - def_num=81, - scale=128, - units='rpm', - ), - 82: Field( # fractional part of the total_cycles - name='total_fractional_cycles', - type=BASE_TYPES[0x02], # uint8 - def_num=82, - scale=128, - units='cycles', - ), - 83: Field( - name='player_score', - type=BASE_TYPES[0x84], # uint16 - def_num=83, - ), - 84: Field( # Avg saturated and unsaturated hemoglobin - name='avg_total_hemoglobin_conc', - type=BASE_TYPES[0x84], # uint16 - def_num=84, - scale=100, - units='g/dL', - ), - 85: Field( # Min saturated and unsaturated hemoglobin - name='min_total_hemoglobin_conc', - type=BASE_TYPES[0x84], # uint16 - def_num=85, - scale=100, - units='g/dL', - ), - 86: Field( # Max saturated and unsaturated hemoglobin - name='max_total_hemoglobin_conc', - type=BASE_TYPES[0x84], # uint16 - def_num=86, - scale=100, - units='g/dL', - ), - 87: Field( # Avg percentage of hemoglobin saturated with oxygen - name='avg_saturated_hemoglobin_percent', - type=BASE_TYPES[0x84], # uint16 - def_num=87, - scale=10, - units='%', - ), - 88: Field( # Min percentage of hemoglobin saturated with oxygen - name='min_saturated_hemoglobin_percent', - type=BASE_TYPES[0x84], # uint16 - def_num=88, - scale=10, - units='%', - ), - 89: Field( # Max percentage of hemoglobin saturated with oxygen - name='max_saturated_hemoglobin_percent', - type=BASE_TYPES[0x84], # uint16 - def_num=89, - scale=10, - units='%', - ), - 91: Field( - name='avg_left_torque_effectiveness', - type=BASE_TYPES[0x02], # uint8 - def_num=91, - scale=2, - units='percent', - ), - 92: Field( - name='avg_right_torque_effectiveness', - type=BASE_TYPES[0x02], # uint8 - def_num=92, - scale=2, - units='percent', - ), - 93: Field( - name='avg_left_pedal_smoothness', - type=BASE_TYPES[0x02], # uint8 - def_num=93, - scale=2, - units='percent', - ), - 94: Field( - name='avg_right_pedal_smoothness', - type=BASE_TYPES[0x02], # uint8 - def_num=94, - scale=2, - units='percent', - ), - 95: Field( - name='avg_combined_pedal_smoothness', - type=BASE_TYPES[0x02], # uint8 - def_num=95, - scale=2, - units='percent', - ), - 98: Field( # Total time spent in the standing position - name='time_standing', - type=BASE_TYPES[0x86], # uint32 - def_num=98, - scale=1000, - units='s', - ), - 99: Field( # Number of transitions to the standing state - name='stand_count', - type=BASE_TYPES[0x84], # uint16 - def_num=99, - ), - 100: Field( # Average left platform center offset - name='avg_left_pco', - type=BASE_TYPES[0x01], # sint8 - def_num=100, - units='mm', - ), - 101: Field( # Average right platform center offset - name='avg_right_pco', - type=BASE_TYPES[0x01], # sint8 - def_num=101, - units='mm', - ), - 102: 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=102, - scale=0.7111111, - units='degrees', - ), - 103: 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=103, - scale=0.7111111, - units='degrees', - ), - 104: 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=104, - scale=0.7111111, - units='degrees', - ), - 105: 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=105, - scale=0.7111111, - units='degrees', - ), - 106: Field( # Average power by position. Data value indexes defined by rider_position_type. - name='avg_power_position', - type=BASE_TYPES[0x84], # uint16 - def_num=106, - units='watts', - ), - 107: Field( # Maximum power by position. Data value indexes defined by rider_position_type. - name='max_power_position', - type=BASE_TYPES[0x84], # uint16 - def_num=107, - units='watts', - ), - 108: Field( # Average cadence by position. Data value indexes defined by rider_position_type. - name='avg_cadence_position', - type=BASE_TYPES[0x02], # uint8 - def_num=108, - units='rpm', - ), - 109: Field( # Maximum cadence by position. Data value indexes defined by rider_position_type. - name='max_cadence_position', - type=BASE_TYPES[0x02], # uint8 - def_num=109, - units='rpm', - ), - 110: Field( - name='enhanced_avg_speed', - type=BASE_TYPES[0x86], # uint32 - def_num=110, - scale=1000, - units='m/s', - ), - 111: Field( - name='enhanced_max_speed', - type=BASE_TYPES[0x86], # uint32 - def_num=111, - scale=1000, - units='m/s', - ), - 112: Field( - name='enhanced_avg_altitude', - type=BASE_TYPES[0x86], # uint32 - def_num=112, - scale=5, - offset=500, - units='m', - ), - 113: Field( - name='enhanced_min_altitude', - type=BASE_TYPES[0x86], # uint32 - def_num=113, - scale=5, - offset=500, - units='m', - ), - 114: Field( - name='enhanced_max_altitude', - type=BASE_TYPES[0x86], # uint32 - def_num=114, - scale=5, - offset=500, - units='m', - ), - 115: Field( # lev average motor power during lap - name='avg_lev_motor_power', - type=BASE_TYPES[0x84], # uint16 - def_num=115, - units='watts', - ), - 116: Field( # lev maximum motor power during lap - name='max_lev_motor_power', - type=BASE_TYPES[0x84], # uint16 - def_num=116, - units='watts', - ), - 117: Field( # lev battery consumption during lap - name='lev_battery_consumption', - type=BASE_TYPES[0x02], # uint8 - def_num=117, - scale=2, - units='percent', - ), - 118: Field( - name='avg_vertical_ratio', - type=BASE_TYPES[0x84], # uint16 - def_num=118, - scale=100, - units='percent', - ), - 119: Field( - name='avg_stance_time_balance', - type=BASE_TYPES[0x84], # uint16 - def_num=119, - scale=100, - units='percent', - ), - 120: Field( - name='avg_step_length', - type=BASE_TYPES[0x84], # uint16 - def_num=120, - scale=10, - units='mm', - ), - 121: Field( - name='avg_vam', - type=BASE_TYPES[0x84], # uint16 - def_num=121, - scale=1000, - units='m/s', - ), - 253: FIELD_TYPE_TIMESTAMP, # Lap end time. - 254: Field( - name='message_index', - type=FIELD_TYPES['message_index'], - def_num=254, - ), - }, - ), - 20: MessageType( - name='record', - mesg_num=20, - fields={ - 0: Field( - name='position_lat', - type=BASE_TYPES[0x85], # sint32 - def_num=0, - units='semicircles', - ), - 1: Field( - name='position_long', - type=BASE_TYPES[0x85], # sint32 - def_num=1, - units='semicircles', - ), - 2: Field( - name='altitude', - type=BASE_TYPES[0x84], # uint16 - def_num=2, - scale=5, - offset=500, - units='m', - components=( - ComponentField( - name='enhanced_altitude', - def_num=78, - scale=5, - offset=500, - units='m', - accumulate=False, - bits=16, - bit_offset=0, - ), - ), - ), - 3: Field( - name='heart_rate', - type=BASE_TYPES[0x02], # uint8 - def_num=3, - units='bpm', - ), - 4: Field( - name='cadence', - type=BASE_TYPES[0x02], # uint8 - def_num=4, - units='rpm', - ), - 5: Field( - name='distance', - type=BASE_TYPES[0x86], # uint32 - def_num=5, - scale=100, - units='m', - ), - 6: Field( - name='speed', - type=BASE_TYPES[0x84], # uint16 - def_num=6, - scale=1000, - units='m/s', - components=( - ComponentField( - name='enhanced_speed', - def_num=73, - scale=1000, - units='m/s', - accumulate=False, - bits=16, - bit_offset=0, - ), - ), - ), - 7: Field( - name='power', - type=BASE_TYPES[0x84], # uint16 - def_num=7, - units='watts', - ), - 8: Field( - name='compressed_speed_distance', - type=BASE_TYPES[0x0D], # byte - def_num=8, - components=( - ComponentField( - name='speed', - def_num=6, - scale=100, - units='m/s', - accumulate=False, - bits=12, - bit_offset=0, - ), - ComponentField( - name='distance', - def_num=5, - scale=16, - units='m', - accumulate=True, - bits=12, - bit_offset=12, - ), - ), - ), - 9: Field( - name='grade', - type=BASE_TYPES[0x83], # sint16 - def_num=9, - scale=100, - units='%', - ), - 10: Field( # Relative. 0 is none 254 is Max. - name='resistance', - type=BASE_TYPES[0x02], # uint8 - def_num=10, - ), - 11: Field( - name='time_from_course', - type=BASE_TYPES[0x85], # sint32 - def_num=11, - scale=1000, - units='s', - ), - 12: Field( - name='cycle_length', - type=BASE_TYPES[0x02], # uint8 - def_num=12, - scale=100, - units='m', - ), - 13: Field( - name='temperature', - type=BASE_TYPES[0x01], # sint8 - def_num=13, - units='C', - ), - 17: Field( # Speed at 1s intervals. Timestamp field indicates time of last array element. - name='speed_1s', - type=BASE_TYPES[0x02], # uint8 - def_num=17, - scale=16, - units='m/s', - ), - 18: Field( - name='cycles', - type=BASE_TYPES[0x02], # uint8 - def_num=18, - components=( - ComponentField( - name='total_cycles', - def_num=19, - units='cycles', - accumulate=True, - bits=8, - bit_offset=0, - ), - ), - ), - 19: Field( - name='total_cycles', - type=BASE_TYPES[0x86], # uint32 - def_num=19, - units='cycles', - ), - 28: Field( - name='compressed_accumulated_power', - type=BASE_TYPES[0x84], # uint16 - def_num=28, - components=( - ComponentField( - name='accumulated_power', - def_num=29, - units='watts', - accumulate=True, - bits=16, - bit_offset=0, - ), - ), - ), - 29: Field( - name='accumulated_power', - type=BASE_TYPES[0x86], # uint32 - def_num=29, - units='watts', - ), - 30: Field( - name='left_right_balance', - type=FIELD_TYPES['left_right_balance'], - def_num=30, - ), - 31: Field( - name='gps_accuracy', - type=BASE_TYPES[0x02], # uint8 - def_num=31, - units='m', - ), - 32: Field( - name='vertical_speed', - type=BASE_TYPES[0x83], # sint16 - def_num=32, - scale=1000, - units='m/s', - ), - 33: Field( - name='calories', - type=BASE_TYPES[0x84], # uint16 - def_num=33, - units='kcal', - ), - 39: Field( - name='vertical_oscillation', - type=BASE_TYPES[0x84], # uint16 - def_num=39, - scale=10, - units='mm', - ), - 40: Field( - name='stance_time_percent', - type=BASE_TYPES[0x84], # uint16 - def_num=40, - scale=100, - units='percent', - ), - 41: Field( - name='stance_time', - type=BASE_TYPES[0x84], # uint16 - def_num=41, - scale=10, - units='ms', - ), - 42: Field( - name='activity_type', - type=FIELD_TYPES['activity_type'], - def_num=42, - ), - 43: Field( - name='left_torque_effectiveness', - type=BASE_TYPES[0x02], # uint8 - def_num=43, - scale=2, - units='percent', - ), - 44: Field( - name='right_torque_effectiveness', - type=BASE_TYPES[0x02], # uint8 - def_num=44, - scale=2, - units='percent', - ), - 45: Field( - name='left_pedal_smoothness', - type=BASE_TYPES[0x02], # uint8 - def_num=45, - scale=2, - units='percent', - ), - 46: Field( - name='right_pedal_smoothness', - type=BASE_TYPES[0x02], # uint8 - def_num=46, - scale=2, - units='percent', - ), - 47: Field( - name='combined_pedal_smoothness', - type=BASE_TYPES[0x02], # uint8 - def_num=47, - scale=2, - units='percent', - ), - 48: Field( - name='time128', - type=BASE_TYPES[0x02], # uint8 - def_num=48, - scale=128, - units='s', - ), - 49: Field( - name='stroke_type', - type=FIELD_TYPES['stroke_type'], - def_num=49, - ), - 50: Field( - name='zone', - type=BASE_TYPES[0x02], # uint8 - def_num=50, - ), - 51: Field( - name='ball_speed', - type=BASE_TYPES[0x84], # uint16 - def_num=51, - scale=100, - units='m/s', - ), - 52: Field( # Log cadence and fractional cadence for backwards compatability - name='cadence256', - type=BASE_TYPES[0x84], # uint16 - def_num=52, - scale=256, - units='rpm', - ), - 53: Field( - name='fractional_cadence', - type=BASE_TYPES[0x02], # uint8 - def_num=53, - scale=128, - units='rpm', - ), - 54: Field( # Total saturated and unsaturated hemoglobin - name='total_hemoglobin_conc', - type=BASE_TYPES[0x84], # uint16 - def_num=54, - scale=100, - units='g/dL', - ), - 55: Field( # Min saturated and unsaturated hemoglobin - name='total_hemoglobin_conc_min', - type=BASE_TYPES[0x84], # uint16 - def_num=55, - scale=100, - units='g/dL', - ), - 56: Field( # Max saturated and unsaturated hemoglobin - name='total_hemoglobin_conc_max', - type=BASE_TYPES[0x84], # uint16 - def_num=56, - scale=100, - units='g/dL', - ), - 57: Field( # Percentage of hemoglobin saturated with oxygen - name='saturated_hemoglobin_percent', - type=BASE_TYPES[0x84], # uint16 - def_num=57, - scale=10, - units='%', - ), - 58: Field( # Min percentage of hemoglobin saturated with oxygen - name='saturated_hemoglobin_percent_min', - type=BASE_TYPES[0x84], # uint16 - def_num=58, - scale=10, - units='%', - ), - 59: Field( # Max percentage of hemoglobin saturated with oxygen - name='saturated_hemoglobin_percent_max', - type=BASE_TYPES[0x84], # uint16 - def_num=59, - scale=10, - units='%', - ), - 62: Field( - name='device_index', - type=FIELD_TYPES['device_index'], - def_num=62, - ), - 67: Field( # Left platform center offset - name='left_pco', - type=BASE_TYPES[0x01], # sint8 - def_num=67, - units='mm', - ), - 68: Field( # Right platform center offset - name='right_pco', - type=BASE_TYPES[0x01], # sint8 - def_num=68, - units='mm', - ), - 69: Field( # Left power phase angles. Data value indexes defined by power_phase_type. - name='left_power_phase', - type=BASE_TYPES[0x02], # uint8 - def_num=69, - scale=0.7111111, - units='degrees', - ), - 70: Field( # Left power phase peak angles. Data value indexes defined by power_phase_type. - name='left_power_phase_peak', - type=BASE_TYPES[0x02], # uint8 - def_num=70, - scale=0.7111111, - units='degrees', - ), - 71: Field( # Right power phase angles. Data value indexes defined by power_phase_type. - name='right_power_phase', - type=BASE_TYPES[0x02], # uint8 - def_num=71, - scale=0.7111111, - units='degrees', - ), - 72: Field( # Right power phase peak angles. Data value indexes defined by power_phase_type. - name='right_power_phase_peak', - type=BASE_TYPES[0x02], # uint8 - def_num=72, - scale=0.7111111, - units='degrees', - ), - 73: Field( - name='enhanced_speed', - type=BASE_TYPES[0x86], # uint32 - def_num=73, - scale=1000, - units='m/s', - ), - 78: Field( - name='enhanced_altitude', - type=BASE_TYPES[0x86], # uint32 - def_num=78, - scale=5, - offset=500, - units='m', - ), - 81: Field( # lev battery state of charge - name='battery_soc', - type=BASE_TYPES[0x02], # uint8 - def_num=81, - scale=2, - units='percent', - ), - 82: Field( # lev motor power - name='motor_power', - type=BASE_TYPES[0x84], # uint16 - def_num=82, - units='watts', - ), - 83: Field( - name='vertical_ratio', - type=BASE_TYPES[0x84], # uint16 - def_num=83, - scale=100, - units='percent', - ), - 84: Field( - name='stance_time_balance', - type=BASE_TYPES[0x84], # uint16 - def_num=84, - scale=100, - units='percent', - ), - 85: Field( - name='step_length', - type=BASE_TYPES[0x84], # uint16 - def_num=85, - scale=10, - units='mm', - ), - 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, - bits=16, - bit_offset=0, - ), - ), - ), - 3: Field( - name='data', - type=BASE_TYPES[0x86], # uint32 - def_num=3, - subfields=( - SubField( - name='battery_level', - def_num=3, - type=BASE_TYPES[0x84], # uint16 - scale=1000, - units='V', - ref_fields=( - ReferenceField( - name='event', - def_num=0, - value='battery', - raw_value=11, - ), - ), - ), - SubField( - name='cad_high_alert', - def_num=3, - type=BASE_TYPES[0x84], # uint16 - units='rpm', - ref_fields=( - ReferenceField( - name='event', - def_num=0, - value='cad_high_alert', - raw_value=17, - ), - ), - ), - SubField( - name='cad_low_alert', - def_num=3, - type=BASE_TYPES[0x84], # uint16 - units='rpm', - ref_fields=( - ReferenceField( - name='event', - def_num=0, - value='cad_low_alert', - raw_value=18, - ), - ), - ), - SubField( - name='calorie_duration_alert', - def_num=3, - type=BASE_TYPES[0x86], # uint32 - units='calories', - ref_fields=( - ReferenceField( - name='event', - def_num=0, - value='calorie_duration_alert', - raw_value=25, - ), - ), - ), - SubField( - name='comm_timeout', - def_num=3, - type=FIELD_TYPES['comm_timeout_type'], - ref_fields=( - ReferenceField( - name='event', - def_num=0, - value='comm_timeout', - raw_value=47, - ), - ), - ), - SubField( - name='course_point_index', - def_num=3, - type=FIELD_TYPES['message_index'], - ref_fields=( - ReferenceField( - name='event', - def_num=0, - value='course_point', - raw_value=10, - ), - ), - ), - SubField( - name='distance_duration_alert', - def_num=3, - type=BASE_TYPES[0x86], # uint32 - scale=100, - units='m', - ref_fields=( - ReferenceField( - name='event', - def_num=0, - value='distance_duration_alert', - raw_value=24, - ), - ), - ), - SubField( - name='fitness_equipment_state', - def_num=3, - type=FIELD_TYPES['fitness_equipment_state'], - ref_fields=( - ReferenceField( - name='event', - def_num=0, - value='fitness_equipment', - raw_value=27, - ), - ), - ), - SubField( - name='gear_change_data', - def_num=3, - type=BASE_TYPES[0x86], # uint32 - ref_fields=( - ReferenceField( - name='event', - def_num=0, - value='front_gear_change', - raw_value=42, - ), - ReferenceField( - name='event', - def_num=0, - value='rear_gear_change', - raw_value=43, - ), - ), - components=( - ComponentField( - name='rear_gear_num', - def_num=11, - accumulate=False, - bits=8, - bit_offset=0, - ), - ComponentField( - name='rear_gear', - def_num=12, - accumulate=False, - bits=8, - bit_offset=8, - ), - ComponentField( - name='front_gear_num', - def_num=9, - accumulate=False, - bits=8, - bit_offset=16, - ), - ComponentField( - name='front_gear', - def_num=10, - accumulate=False, - bits=8, - bit_offset=24, - ), - ), - ), - SubField( - name='hr_high_alert', - def_num=3, - type=BASE_TYPES[0x02], # uint8 - units='bpm', - ref_fields=( - ReferenceField( - name='event', - def_num=0, - value='hr_high_alert', - raw_value=13, - ), - ), - ), - SubField( - name='hr_low_alert', - def_num=3, - type=BASE_TYPES[0x02], # uint8 - units='bpm', - ref_fields=( - ReferenceField( - name='event', - def_num=0, - value='hr_low_alert', - raw_value=14, - ), - ), - ), - SubField( - name='power_high_alert', - def_num=3, - type=BASE_TYPES[0x84], # uint16 - units='watts', - ref_fields=( - ReferenceField( - name='event', - def_num=0, - value='power_high_alert', - raw_value=19, - ), - ), - ), - SubField( - name='power_low_alert', - def_num=3, - type=BASE_TYPES[0x84], # uint16 - units='watts', - ref_fields=( - ReferenceField( - name='event', - def_num=0, - value='power_low_alert', - raw_value=20, - ), - ), - ), - SubField( # Indicates the rider position value. - name='rider_position', - def_num=3, - type=FIELD_TYPES['rider_position_type'], - ref_fields=( - ReferenceField( - name='event', - def_num=0, - value='rider_position_change', - raw_value=44, - ), - ), - ), - SubField( - name='speed_high_alert', - def_num=3, - type=BASE_TYPES[0x86], # uint32 - scale=1000, - units='m/s', - ref_fields=( - ReferenceField( - name='event', - def_num=0, - value='speed_high_alert', - raw_value=15, - ), - ), - ), - SubField( - name='speed_low_alert', - def_num=3, - type=BASE_TYPES[0x86], # uint32 - scale=1000, - units='m/s', - ref_fields=( - ReferenceField( - name='event', - def_num=0, - value='speed_low_alert', - raw_value=16, - ), - ), - ), - SubField( - name='sport_point', - def_num=3, - type=BASE_TYPES[0x86], # uint32 - ref_fields=( - ReferenceField( - name='event', - def_num=0, - value='sport_point', - raw_value=33, - ), - ), - components=( - ComponentField( - name='score', - def_num=7, - accumulate=False, - bits=16, - bit_offset=0, - ), - ComponentField( - name='opponent_score', - def_num=8, - accumulate=False, - bits=16, - bit_offset=16, - ), - ), - ), - SubField( - name='time_duration_alert', - def_num=3, - type=BASE_TYPES[0x86], # uint32 - scale=1000, - units='s', - ref_fields=( - ReferenceField( - name='event', - def_num=0, - value='time_duration_alert', - raw_value=23, - ), - ), - ), - SubField( - name='timer_trigger', - def_num=3, - type=FIELD_TYPES['timer_trigger'], - ref_fields=( - ReferenceField( - name='event', - def_num=0, - value='timer', - raw_value=0, - ), - ), - ), - SubField( - name='virtual_partner_speed', - def_num=3, - type=BASE_TYPES[0x84], # uint16 - scale=1000, - units='m/s', - ref_fields=( - ReferenceField( - name='event', - def_num=0, - value='virtual_partner_pace', - raw_value=12, - ), - ), - ), - ), - ), - 4: Field( - name='event_group', - type=BASE_TYPES[0x02], # uint8 - def_num=4, - ), - 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 - 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. - 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. - 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. - 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. - name='rear_gear', - type=BASE_TYPES[0x0A], # uint8z - def_num=12, - ), - 13: Field( - name='device_index', - type=FIELD_TYPES['device_index'], - def_num=13, - ), - 253: FIELD_TYPE_TIMESTAMP, - }, - ), - 23: MessageType( - name='device_info', - mesg_num=23, - fields={ - 0: Field( - name='device_index', - type=FIELD_TYPES['device_index'], - def_num=0, - ), - 1: Field( - name='device_type', - type=FIELD_TYPES['antplus_device_type'], # uint8 - def_num=1, - subfields=( - SubField( - name='ant_device_type', - def_num=1, - type=BASE_TYPES[0x02], # uint8 - ref_fields=( - ReferenceField( - name='source_type', - def_num=25, - value='ant', - raw_value=0, - ), - ), - ), - SubField( - name='antplus_device_type', - def_num=1, - type=FIELD_TYPES['antplus_device_type'], - ref_fields=( - ReferenceField( - name='source_type', - def_num=25, - value='antplus', - raw_value=1, - ), - ), - ), - ), - ), - 2: Field( - name='manufacturer', - type=FIELD_TYPES['manufacturer'], - def_num=2, - ), - 3: Field( - name='serial_number', - type=BASE_TYPES[0x8C], # uint32z - def_num=3, - ), - 4: Field( - name='product', - type=BASE_TYPES[0x84], # uint16 - def_num=4, - subfields=( - SubField( - name='garmin_product', - def_num=4, - type=FIELD_TYPES['garmin_product'], - ref_fields=( - ReferenceField( - name='manufacturer', - def_num=2, - value='garmin', - raw_value=1, - ), - ReferenceField( - name='manufacturer', - def_num=2, - value='dynastream', - raw_value=15, - ), - ReferenceField( - name='manufacturer', - def_num=2, - value='dynastream_oem', - raw_value=13, - ), - ), - ), - ), - ), - 5: Field( - name='software_version', - type=BASE_TYPES[0x84], # uint16 - def_num=5, - scale=100, - ), - 6: Field( - name='hardware_version', - type=BASE_TYPES[0x02], # uint8 - def_num=6, - ), - 7: Field( # Reset by new battery or charge. - name='cum_operating_time', - type=BASE_TYPES[0x86], # uint32 - def_num=7, - units='s', - ), - 10: Field( - name='battery_voltage', - type=BASE_TYPES[0x84], # uint16 - def_num=10, - scale=256, - units='V', - ), - 11: Field( - name='battery_status', - type=FIELD_TYPES['battery_status'], - def_num=11, - ), - 18: Field( # Indicates the location of the sensor - name='sensor_position', - type=FIELD_TYPES['body_location'], - def_num=18, - ), - 19: Field( # Used to describe the sensor or location - name='descriptor', - type=BASE_TYPES[0x07], # string - def_num=19, - ), - 20: Field( - name='ant_transmission_type', - type=BASE_TYPES[0x0A], # uint8z - def_num=20, - ), - 21: Field( - name='ant_device_number', - type=BASE_TYPES[0x8B], # uint16z - def_num=21, - ), - 22: Field( - name='ant_network', - type=FIELD_TYPES['ant_network'], - def_num=22, - ), - 25: Field( - name='source_type', - type=FIELD_TYPES['source_type'], - def_num=25, - ), - 27: Field( # Optional free form string to indicate the devices name or model - name='product_name', - type=BASE_TYPES[0x07], # string - def_num=27, - ), - 253: FIELD_TYPE_TIMESTAMP, - }, - ), - 27: MessageType( - name='workout_step', - mesg_num=27, - fields={ - 0: Field( - name='wkt_step_name', - type=BASE_TYPES[0x07], # string - def_num=0, - ), - 1: Field( - name='duration_type', - type=FIELD_TYPES['wkt_step_duration'], - def_num=1, - ), - 2: Field( - name='duration_value', - type=BASE_TYPES[0x86], # uint32 - def_num=2, - subfields=( - SubField( - name='duration_calories', - def_num=2, - type=BASE_TYPES[0x86], # uint32 - units='calories', - ref_fields=( - ReferenceField( - name='duration_type', - def_num=1, - value='calories', - raw_value=4, - ), - ), - ), - SubField( - name='duration_distance', - def_num=2, - type=BASE_TYPES[0x86], # uint32 - scale=100, - units='m', - ref_fields=( - ReferenceField( - name='duration_type', - def_num=1, - value='distance', - raw_value=1, - ), - ), - ), - SubField( - name='duration_hr', - def_num=2, - type=FIELD_TYPES['workout_hr'], - units='% or bpm', - ref_fields=( - ReferenceField( - name='duration_type', - def_num=1, - value='hr_less_than', - raw_value=2, - ), - ReferenceField( - name='duration_type', - def_num=1, - value='hr_greater_than', - raw_value=3, - ), - ), - ), - SubField( - name='duration_power', - def_num=2, - type=FIELD_TYPES['workout_power'], - units='% or watts', - ref_fields=( - ReferenceField( - name='duration_type', - def_num=1, - value='power_less_than', - raw_value=14, - ), - ReferenceField( - name='duration_type', - def_num=1, - value='power_greater_than', - raw_value=15, - ), - ), - ), - SubField( # message_index of step to loop back to. Steps are assumed to be in the order by message_index. custom_name and intensity members are undefined for this duration type. - name='duration_step', - def_num=2, - type=BASE_TYPES[0x86], # uint32 - ref_fields=( - ReferenceField( - name='duration_type', - def_num=1, - value='repeat_until_steps_cmplt', - raw_value=6, - ), - ReferenceField( - name='duration_type', - def_num=1, - value='repeat_until_time', - raw_value=7, - ), - ReferenceField( - name='duration_type', - def_num=1, - value='repeat_until_distance', - raw_value=8, - ), - ReferenceField( - name='duration_type', - def_num=1, - value='repeat_until_calories', - raw_value=9, - ), - ReferenceField( - name='duration_type', - def_num=1, - value='repeat_until_hr_less_than', - raw_value=10, - ), - ReferenceField( - name='duration_type', - def_num=1, - value='repeat_until_hr_greater_than', - raw_value=11, - ), - ReferenceField( - name='duration_type', - def_num=1, - value='repeat_until_power_less_than', - raw_value=12, - ), - ReferenceField( - name='duration_type', - def_num=1, - value='repeat_until_power_greater_than', - raw_value=13, - ), - ), - ), - SubField( - name='duration_time', - def_num=2, - type=BASE_TYPES[0x86], # uint32 - scale=1000, - units='s', - ref_fields=( - ReferenceField( - name='duration_type', - def_num=1, - value='time', - raw_value=0, - ), - ReferenceField( - name='duration_type', - def_num=1, - value='repetition_time', - raw_value=28, - ), - ), - ), - ), - ), - 3: Field( - name='target_type', - type=FIELD_TYPES['wkt_step_target'], - def_num=3, - ), - 4: Field( - name='target_value', - type=BASE_TYPES[0x86], # uint32 - def_num=4, - subfields=( - SubField( - name='repeat_calories', - def_num=4, - type=BASE_TYPES[0x86], # uint32 - units='calories', - ref_fields=( - ReferenceField( - name='duration_type', - def_num=1, - value='repeat_until_calories', - raw_value=9, - ), - ), - ), - SubField( - name='repeat_distance', - def_num=4, - type=BASE_TYPES[0x86], # uint32 - scale=100, - units='m', - ref_fields=( - ReferenceField( - name='duration_type', - def_num=1, - value='repeat_until_distance', - raw_value=8, - ), - ), - ), - SubField( - name='repeat_hr', - def_num=4, - type=FIELD_TYPES['workout_hr'], - units='% or bpm', - ref_fields=( - ReferenceField( - name='duration_type', - def_num=1, - value='repeat_until_hr_less_than', - raw_value=10, - ), - ReferenceField( - name='duration_type', - def_num=1, - value='repeat_until_hr_greater_than', - raw_value=11, - ), - ), - ), - SubField( - name='repeat_power', - def_num=4, - type=FIELD_TYPES['workout_power'], - units='% or watts', - ref_fields=( - ReferenceField( - name='duration_type', - def_num=1, - value='repeat_until_power_less_than', - raw_value=12, - ), - ReferenceField( - name='duration_type', - def_num=1, - value='repeat_until_power_greater_than', - raw_value=13, - ), - ), - ), - SubField( # # of repetitions - name='repeat_steps', - def_num=4, - type=BASE_TYPES[0x86], # uint32 - ref_fields=( - ReferenceField( - name='duration_type', - def_num=1, - value='repeat_until_steps_cmplt', - raw_value=6, - ), - ), - ), - SubField( - name='repeat_time', - def_num=4, - type=BASE_TYPES[0x86], # uint32 - scale=1000, - units='s', - ref_fields=( - ReferenceField( - name='duration_type', - def_num=1, - value='repeat_until_time', - raw_value=7, - ), - ), - ), - SubField( # Zone (1-?); Custom = 0; - name='target_cadence_zone', - def_num=4, - type=BASE_TYPES[0x86], # uint32 - ref_fields=( - ReferenceField( - name='target_type', - def_num=3, - value='cadence', - raw_value=3, - ), - ), - ), - SubField( # hr zone (1-5);Custom =0; - name='target_hr_zone', - def_num=4, - type=BASE_TYPES[0x86], # uint32 - ref_fields=( - ReferenceField( - name='target_type', - def_num=3, - value='heart_rate', - raw_value=1, - ), - ), - ), - SubField( # Power Zone ( 1-7); Custom = 0; - name='target_power_zone', - def_num=4, - type=BASE_TYPES[0x86], # uint32 - ref_fields=( - ReferenceField( - name='target_type', - def_num=3, - value='power', - raw_value=4, - ), - ), - ), - SubField( # speed zone (1-10);Custom =0; - name='target_speed_zone', - def_num=4, - type=BASE_TYPES[0x86], # uint32 - ref_fields=( - ReferenceField( - name='target_type', - def_num=3, - value='speed', - raw_value=0, - ), - ), - ), - SubField( - name='target_stroke_type', - def_num=4, - type=FIELD_TYPES['swim_stroke'], - ref_fields=( - ReferenceField( - name='target_type', - def_num=3, - value='swim_stroke', - raw_value=11, - ), - ), - ), - ), - ), - 5: Field( - name='custom_target_value_low', - type=BASE_TYPES[0x86], # uint32 - def_num=5, - subfields=( - SubField( - name='custom_target_cadence_low', - def_num=5, - type=BASE_TYPES[0x86], # uint32 - units='rpm', - ref_fields=( - ReferenceField( - name='target_type', - def_num=3, - value='cadence', - raw_value=3, - ), - ), - ), - SubField( - name='custom_target_heart_rate_low', - def_num=5, - type=FIELD_TYPES['workout_hr'], - units='% or bpm', - ref_fields=( - ReferenceField( - name='target_type', - def_num=3, - value='heart_rate', - raw_value=1, - ), - ), - ), - SubField( - name='custom_target_power_low', - def_num=5, - type=FIELD_TYPES['workout_power'], - units='% or watts', - ref_fields=( - ReferenceField( - name='target_type', - def_num=3, - value='power', - raw_value=4, - ), - ), - ), - SubField( - name='custom_target_speed_low', - def_num=5, - type=BASE_TYPES[0x86], # uint32 - scale=1000, - units='m/s', - ref_fields=( - ReferenceField( - name='target_type', - def_num=3, - value='speed', - raw_value=0, - ), - ), - ), - ), - ), - 6: Field( - name='custom_target_value_high', - type=BASE_TYPES[0x86], # uint32 - def_num=6, - subfields=( - SubField( - name='custom_target_cadence_high', - def_num=6, - type=BASE_TYPES[0x86], # uint32 - units='rpm', - ref_fields=( - ReferenceField( - name='target_type', - def_num=3, - value='cadence', - raw_value=3, - ), - ), - ), - SubField( - name='custom_target_heart_rate_high', - def_num=6, - type=FIELD_TYPES['workout_hr'], - units='% or bpm', - ref_fields=( - ReferenceField( - name='target_type', - def_num=3, - value='heart_rate', - raw_value=1, - ), - ), - ), - SubField( - name='custom_target_power_high', - def_num=6, - type=FIELD_TYPES['workout_power'], - units='% or watts', - ref_fields=( - ReferenceField( - name='target_type', - def_num=3, - value='power', - raw_value=4, - ), - ), - ), - SubField( - name='custom_target_speed_high', - def_num=6, - type=BASE_TYPES[0x86], # uint32 - scale=1000, - units='m/s', - ref_fields=( - ReferenceField( - name='target_type', - def_num=3, - value='speed', - raw_value=0, - ), - ), - ), - ), - ), - 7: Field( - name='intensity', - type=FIELD_TYPES['intensity'], - def_num=7, - ), - 8: Field( - name='notes', - type=BASE_TYPES[0x07], # string - def_num=8, - ), - 9: Field( - name='equipment', - type=FIELD_TYPES['workout_equipment'], - def_num=9, - ), - 254: Field( - name='message_index', - type=FIELD_TYPES['message_index'], - def_num=254, - ), - }, - ), - 32: MessageType( - name='course_point', - mesg_num=32, - fields={ - 1: Field( - name='timestamp', - type=FIELD_TYPES['date_time'], - def_num=1, - ), - 2: Field( - name='position_lat', - type=BASE_TYPES[0x85], # sint32 - def_num=2, - units='semicircles', - ), - 3: Field( - name='position_long', - type=BASE_TYPES[0x85], # sint32 - def_num=3, - 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', - 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, - 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, - ), - ), - ), - ), - ), - 254: Field( - name='message_index', - type=FIELD_TYPES['message_index'], - def_num=254, - ), - }, - ), - 39: MessageType( - name='field_capabilities', - mesg_num=39, - 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='field_num', - type=BASE_TYPES[0x02], # uint8 - def_num=2, - ), - 3: Field( - name='count', - type=BASE_TYPES[0x84], # uint16 - def_num=3, - ), - 254: Field( - name='message_index', - type=FIELD_TYPES['message_index'], - def_num=254, - ), - }, - ), - 49: MessageType( - name='file_creator', - mesg_num=49, - fields={ - 0: Field( - name='software_version', - type=BASE_TYPES[0x84], # uint16 - def_num=0, - ), - 1: Field( - name='hardware_version', - type=BASE_TYPES[0x02], # uint8 - def_num=1, - ), - }, - ), - 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', - ), - 15: Field( # Max temperature during the logging interval ended at timestamp - name='temperature_max', - type=BASE_TYPES[0x83], # sint16 - def_num=15, - scale=100, - units='C', - ), - 16: Field( # Indexed using minute_activity_level enum - name='activity_time', - type=BASE_TYPES[0x84], # uint16 - def_num=16, - units='minutes', - ), - 19: Field( - name='active_calories', - type=BASE_TYPES[0x84], # uint16 - def_num=19, - units='kcal', - ), - 24: Field( # Indicates single type / intensity for duration since last monitoring message. - name='current_activity_type_intensity', - type=BASE_TYPES[0x0D], # byte - def_num=24, - components=( - ComponentField( - name='activity_type', - def_num=5, - accumulate=False, - bits=5, - bit_offset=0, - ), - ComponentField( - name='intensity', - def_num=28, - accumulate=False, - bits=3, - bit_offset=5, - ), - ), - ), - 25: Field( - name='timestamp_min_8', - type=BASE_TYPES[0x02], # uint8 - def_num=25, - units='min', - ), - 26: Field( - name='timestamp_16', - type=BASE_TYPES[0x84], # uint16 - def_num=26, - units='s', - ), - 27: Field( - name='heart_rate', - type=BASE_TYPES[0x02], # uint8 - def_num=27, - units='bpm', - ), - 28: Field( - name='intensity', - type=BASE_TYPES[0x02], # uint8 - def_num=28, - scale=10, - ), - 29: Field( - name='duration_min', - type=BASE_TYPES[0x84], # uint16 - def_num=29, - units='min', - ), - 30: Field( - name='duration', - type=BASE_TYPES[0x86], # uint32 - def_num=30, - units='s', - ), - 31: Field( - name='ascent', - type=BASE_TYPES[0x86], # uint32 - def_num=31, - scale=1000, - units='m', - ), - 32: Field( - name='descent', - type=BASE_TYPES[0x86], # uint32 - def_num=32, - scale=1000, - units='m', - ), - 33: Field( - name='moderate_activity_minutes', - type=BASE_TYPES[0x84], # uint16 - def_num=33, - units='minutes', - ), - 34: Field( - name='vigorous_activity_minutes', - type=BASE_TYPES[0x84], # uint16 - def_num=34, - units='minutes', - ), - 253: FIELD_TYPE_TIMESTAMP, # Must align to logging interval, for example, time must be 00:00:00 for daily log. - }, - ), - 72: MessageType( # Corresponds to file_id of workout or course. - name='training_file', - mesg_num=72, - fields={ - 0: Field( - name='type', - type=FIELD_TYPES['file'], - def_num=0, - ), - 1: Field( - name='manufacturer', - type=FIELD_TYPES['manufacturer'], - def_num=1, - ), - 2: Field( - name='product', - type=BASE_TYPES[0x84], # uint16 - def_num=2, - subfields=( - SubField( - name='garmin_product', - def_num=2, - type=FIELD_TYPES['garmin_product'], - ref_fields=( - ReferenceField( - name='manufacturer', - def_num=1, - value='garmin', - raw_value=1, - ), - ReferenceField( - name='manufacturer', - def_num=1, - value='dynastream', - raw_value=15, - ), - ReferenceField( - name='manufacturer', - def_num=1, - value='dynastream_oem', - raw_value=13, - ), - ), - ), - ), - ), - 3: Field( - name='serial_number', - type=BASE_TYPES[0x8C], # uint32z - def_num=3, - ), - 4: Field( - name='time_created', - type=FIELD_TYPES['date_time'], - def_num=4, - ), - 253: FIELD_TYPE_TIMESTAMP, - }, - ), - 78: MessageType( # Heart rate variability - name='hrv', - mesg_num=78, - fields={ - 0: Field( # Time between beats - name='time', - type=BASE_TYPES[0x84], # uint16 - def_num=0, - scale=1000, - units='s', - ), - }, - ), - 80: MessageType( - name='ant_rx', - mesg_num=80, - fields={ - 0: Field( - name='fractional_timestamp', - type=BASE_TYPES[0x84], # uint16 - def_num=0, - scale=32768, - units='s', - ), - 1: Field( - name='mesg_id', - type=BASE_TYPES[0x0D], # byte - def_num=1, - ), - 2: Field( - name='mesg_data', - type=BASE_TYPES[0x0D], # byte - def_num=2, - components=( - ComponentField( - name='channel_number', - def_num=3, - accumulate=False, - bits=8, - bit_offset=0, - ), - ComponentField( - name='data', - def_num=4, - accumulate=False, - bits=8, - bit_offset=8, - ), - ComponentField( - name='data', - def_num=4, - accumulate=False, - bits=8, - bit_offset=16, - ), - ComponentField( - name='data', - def_num=4, - accumulate=False, - bits=8, - bit_offset=24, - ), - ComponentField( - name='data', - def_num=4, - accumulate=False, - bits=8, - bit_offset=32, - ), - ComponentField( - name='data', - def_num=4, - accumulate=False, - bits=8, - bit_offset=40, - ), - ComponentField( - name='data', - def_num=4, - accumulate=False, - bits=8, - bit_offset=48, - ), - ComponentField( - name='data', - def_num=4, - accumulate=False, - bits=8, - bit_offset=56, - ), - ComponentField( - name='data', - def_num=4, - accumulate=False, - bits=8, - bit_offset=64, - ), - ), - ), - 3: Field( - name='channel_number', - type=BASE_TYPES[0x02], # uint8 - def_num=3, - ), - 4: Field( - name='data', - type=BASE_TYPES[0x0D], # byte - def_num=4, - ), - 253: FIELD_TYPE_TIMESTAMP, - }, - ), - 81: MessageType( - name='ant_tx', - mesg_num=81, - fields={ - 0: Field( - name='fractional_timestamp', - type=BASE_TYPES[0x84], # uint16 - def_num=0, - scale=32768, - units='s', - ), - 1: Field( - name='mesg_id', - type=BASE_TYPES[0x0D], # byte - def_num=1, - ), - 2: Field( - name='mesg_data', - type=BASE_TYPES[0x0D], # byte - def_num=2, - components=( - ComponentField( - name='channel_number', - def_num=3, - accumulate=False, - bits=8, - bit_offset=0, - ), - ComponentField( - name='data', - def_num=4, - accumulate=False, - bits=8, - bit_offset=8, - ), - ComponentField( - name='data', - def_num=4, - accumulate=False, - bits=8, - bit_offset=16, - ), - ComponentField( - name='data', - def_num=4, - accumulate=False, - bits=8, - bit_offset=24, - ), - ComponentField( - name='data', - def_num=4, - accumulate=False, - bits=8, - bit_offset=32, - ), - ComponentField( - name='data', - def_num=4, - accumulate=False, - bits=8, - bit_offset=40, - ), - ComponentField( - name='data', - def_num=4, - accumulate=False, - bits=8, - bit_offset=48, - ), - ComponentField( - name='data', - def_num=4, - accumulate=False, - bits=8, - bit_offset=56, - ), - ComponentField( - name='data', - def_num=4, - accumulate=False, - bits=8, - bit_offset=64, - ), - ), - ), - 3: Field( - name='channel_number', - type=BASE_TYPES[0x02], # uint8 - def_num=3, - ), - 4: Field( - name='data', - type=BASE_TYPES[0x0D], # byte - def_num=4, - ), - 253: FIELD_TYPE_TIMESTAMP, - }, - ), - 82: MessageType( - name='ant_channel_id', - mesg_num=82, - fields={ - 0: Field( - name='channel_number', - type=BASE_TYPES[0x02], # uint8 - def_num=0, - ), - 1: Field( - name='device_type', - type=BASE_TYPES[0x0A], # uint8z - def_num=1, - ), - 2: Field( - name='device_number', - type=BASE_TYPES[0x8B], # uint16z - def_num=2, - ), - 3: Field( - name='transmission_type', - type=BASE_TYPES[0x0A], # uint8z - def_num=3, - ), - 4: Field( - name='device_index', - type=FIELD_TYPES['device_index'], - def_num=4, - ), - }, - ), - 101: MessageType( - name='length', - mesg_num=101, - 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='start_time', - type=FIELD_TYPES['date_time'], - def_num=2, - ), - 3: Field( - name='total_elapsed_time', - type=BASE_TYPES[0x86], # uint32 - def_num=3, - scale=1000, - units='s', - ), - 4: Field( - name='total_timer_time', - type=BASE_TYPES[0x86], # uint32 - def_num=4, - scale=1000, - units='s', - ), - 5: Field( - name='total_strokes', - type=BASE_TYPES[0x84], # uint16 - def_num=5, - units='strokes', - ), - 6: Field( - name='avg_speed', - type=BASE_TYPES[0x84], # uint16 - def_num=6, - scale=1000, - units='m/s', - ), - 7: Field( - name='swim_stroke', - type=FIELD_TYPES['swim_stroke'], - def_num=7, - units='swim_stroke', - ), - 9: Field( - name='avg_swimming_cadence', - type=BASE_TYPES[0x02], # uint8 - def_num=9, - units='strokes/min', - ), - 10: Field( - name='event_group', - type=BASE_TYPES[0x02], # uint8 - def_num=10, - ), - 11: Field( - name='total_calories', - type=BASE_TYPES[0x84], # uint16 - def_num=11, - units='kcal', - ), - 12: Field( - name='length_type', - type=FIELD_TYPES['length_type'], - def_num=12, - ), - 18: Field( - name='player_score', - type=BASE_TYPES[0x84], # uint16 - def_num=18, - ), - 19: Field( - name='opponent_score', - type=BASE_TYPES[0x84], # uint16 - def_num=19, - ), - 20: Field( # stroke_type enum used as the index - name='stroke_count', - type=BASE_TYPES[0x84], # uint16 - def_num=20, - units='counts', - ), - 21: Field( # zone number used as the index - name='zone_count', - type=BASE_TYPES[0x84], # uint16 - def_num=21, - units='counts', - ), - 253: FIELD_TYPE_TIMESTAMP, - 254: Field( - name='message_index', - type=FIELD_TYPES['message_index'], - def_num=254, - ), - }, - ), - 106: MessageType( - name='slave_device', - mesg_num=106, - fields={ - 0: Field( - name='manufacturer', - type=FIELD_TYPES['manufacturer'], - def_num=0, - ), - 1: Field( - name='product', - type=BASE_TYPES[0x84], # uint16 - 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, - ), - ), - ), - ), - ), - }, - ), - 127: MessageType( - name='connectivity', - mesg_num=127, - fields={ - 0: Field( # Use Bluetooth for connectivity features - name='bluetooth_enabled', - type=FIELD_TYPES['bool'], - def_num=0, - ), - 1: Field( # Use Bluetooth Low Energy for connectivity features - name='bluetooth_le_enabled', - type=FIELD_TYPES['bool'], - def_num=1, - ), - 2: Field( # Use ANT for connectivity features - name='ant_enabled', - type=FIELD_TYPES['bool'], - def_num=2, - ), - 3: Field( - name='name', - type=BASE_TYPES[0x07], # string - def_num=3, - ), - 4: Field( - name='live_tracking_enabled', - type=FIELD_TYPES['bool'], - def_num=4, - ), - 5: Field( - name='weather_conditions_enabled', - type=FIELD_TYPES['bool'], - def_num=5, - ), - 6: Field( - name='weather_alerts_enabled', - type=FIELD_TYPES['bool'], - def_num=6, - ), - 7: Field( - name='auto_activity_upload_enabled', - type=FIELD_TYPES['bool'], - def_num=7, - ), - 8: Field( - name='course_download_enabled', - type=FIELD_TYPES['bool'], - def_num=8, - ), - 9: Field( - name='workout_download_enabled', - type=FIELD_TYPES['bool'], - def_num=9, - ), - 10: Field( - name='gps_ephemeris_download_enabled', - type=FIELD_TYPES['bool'], - def_num=10, - ), - 11: Field( - name='incident_detection_enabled', - type=FIELD_TYPES['bool'], - def_num=11, - ), - 12: Field( - name='grouptrack_enabled', - type=FIELD_TYPES['bool'], - def_num=12, - ), - }, - ), - 128: MessageType( - name='weather_conditions', - mesg_num=128, - fields={ - 0: Field( # Current or forecast - name='weather_report', - type=FIELD_TYPES['weather_report'], - def_num=0, - ), - 1: Field( - name='temperature', - type=BASE_TYPES[0x01], # sint8 - def_num=1, - units='C', - ), - 2: Field( # Corresponds to GSC Response weatherIcon field - name='condition', - type=FIELD_TYPES['weather_status'], - def_num=2, - ), - 3: Field( - name='wind_direction', - type=BASE_TYPES[0x84], # uint16 - def_num=3, - units='degrees', - ), - 4: Field( - name='wind_speed', - type=BASE_TYPES[0x84], # uint16 - def_num=4, - scale=1000, - units='m/s', - ), - 5: Field( # range 0-100 - name='precipitation_probability', - type=BASE_TYPES[0x02], # uint8 - def_num=5, - ), - 6: Field( # Heat Index if GCS heatIdx above or equal to 90F or wind chill if GCS windChill below or equal to 32F - name='temperature_feels_like', - type=BASE_TYPES[0x01], # sint8 - def_num=6, - units='C', - ), - 7: Field( - name='relative_humidity', - type=BASE_TYPES[0x02], # uint8 - def_num=7, - ), - 8: Field( # string corresponding to GCS response location string - name='location', - type=BASE_TYPES[0x07], # string - def_num=8, - ), - 9: Field( - name='observed_at_time', - type=FIELD_TYPES['date_time'], - def_num=9, - ), - 10: Field( - name='observed_location_lat', - type=BASE_TYPES[0x85], # sint32 - def_num=10, - units='semicircles', - ), - 11: Field( - name='observed_location_long', - type=BASE_TYPES[0x85], # sint32 - def_num=11, - units='semicircles', - ), - 12: Field( - name='day_of_week', - type=FIELD_TYPES['day_of_week'], - def_num=12, - ), - 13: Field( - name='high_temperature', - type=BASE_TYPES[0x01], # sint8 - def_num=13, - units='C', - ), - 14: Field( - name='low_temperature', - type=BASE_TYPES[0x01], # sint8 - def_num=14, - units='C', - ), - 253: FIELD_TYPE_TIMESTAMP, # time of update for current conditions, else forecast time - }, - ), - 129: MessageType( - name='weather_alert', - mesg_num=129, - fields={ - 0: Field( # Unique identifier from GCS report ID string, length is 12 - name='report_id', - type=BASE_TYPES[0x07], # string - def_num=0, - ), - 1: Field( # Time alert was issued - name='issue_time', - type=FIELD_TYPES['date_time'], - def_num=1, - ), - 2: Field( # Time alert expires - name='expire_time', - type=FIELD_TYPES['date_time'], - def_num=2, - ), - 3: Field( # Warning, Watch, Advisory, Statement - name='severity', - type=FIELD_TYPES['weather_severity'], - def_num=3, - ), - 4: Field( # Tornado, Severe Thunderstorm, etc. - name='type', - type=FIELD_TYPES['weather_severe_type'], - def_num=4, - ), - 253: FIELD_TYPE_TIMESTAMP, - }, - ), - 131: MessageType( - name='cadence_zone', - mesg_num=131, - fields={ - 0: Field( - name='high_value', - type=BASE_TYPES[0x02], # uint8 - def_num=0, - units='rpm', - ), - 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, - ), - }, - ), - 132: MessageType( - name='hr', - mesg_num=132, - fields={ - 0: Field( - name='fractional_timestamp', - type=BASE_TYPES[0x84], # uint16 - def_num=0, - scale=32768, - units='s', - ), - 1: Field( - name='time256', - type=BASE_TYPES[0x02], # uint8 - def_num=1, - components=( - ComponentField( - name='fractional_timestamp', - def_num=0, - scale=256, - units='s', - accumulate=False, - bits=8, - bit_offset=0, - ), - ), - ), - 6: Field( - name='filtered_bpm', - type=BASE_TYPES[0x02], # uint8 - def_num=6, - units='bpm', - ), - 9: Field( - name='event_timestamp', - type=BASE_TYPES[0x86], # uint32 - def_num=9, - scale=1024, - units='s', - ), - 10: Field( - name='event_timestamp_12', - type=BASE_TYPES[0x0D], # byte - def_num=10, - components=( - ComponentField( - name='event_timestamp', - def_num=9, - scale=1024, - units='s', - accumulate=True, - bits=12, - bit_offset=0, - ), - ComponentField( - name='event_timestamp', - def_num=9, - scale=1024, - units='s', - accumulate=True, - bits=12, - bit_offset=12, - ), - ComponentField( - name='event_timestamp', - def_num=9, - scale=1024, - units='s', - accumulate=True, - bits=12, - bit_offset=24, - ), - ComponentField( - name='event_timestamp', - def_num=9, - scale=1024, - units='s', - accumulate=True, - bits=12, - bit_offset=36, - ), - ComponentField( - name='event_timestamp', - def_num=9, - scale=1024, - units='s', - accumulate=True, - bits=12, - bit_offset=48, - ), - ComponentField( - name='event_timestamp', - def_num=9, - scale=1024, - units='s', - accumulate=True, - bits=12, - bit_offset=60, - ), - ComponentField( - name='event_timestamp', - def_num=9, - scale=1024, - units='s', - accumulate=True, - bits=12, - bit_offset=72, - ), - ComponentField( - name='event_timestamp', - def_num=9, - scale=1024, - units='s', - accumulate=True, - bits=12, - bit_offset=84, - ), - ComponentField( - name='event_timestamp', - def_num=9, - scale=1024, - units='s', - accumulate=True, - bits=12, - bit_offset=96, - ), - ComponentField( - name='event_timestamp', - def_num=9, - scale=1024, - units='s', - accumulate=True, - bits=12, - bit_offset=108, - ), - ), - ), - 253: FIELD_TYPE_TIMESTAMP, - }, - ), - 142: MessageType( - name='segment_lap', - mesg_num=142, - 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='start_time', - type=FIELD_TYPES['date_time'], - def_num=2, - ), - 3: Field( - name='start_position_lat', - type=BASE_TYPES[0x85], # sint32 - def_num=3, - units='semicircles', - ), - 4: Field( - name='start_position_long', - type=BASE_TYPES[0x85], # sint32 - def_num=4, - units='semicircles', - ), - 5: Field( - name='end_position_lat', - type=BASE_TYPES[0x85], # sint32 - def_num=5, - units='semicircles', - ), - 6: Field( - name='end_position_long', - type=BASE_TYPES[0x85], # sint32 - def_num=6, - units='semicircles', - ), - 7: Field( # Time (includes pauses) - name='total_elapsed_time', - type=BASE_TYPES[0x86], # uint32 - def_num=7, - scale=1000, - units='s', - ), - 8: Field( # Timer Time (excludes pauses) - name='total_timer_time', - type=BASE_TYPES[0x86], # uint32 - def_num=8, - scale=1000, - units='s', - ), - 9: Field( - name='total_distance', - type=BASE_TYPES[0x86], # uint32 - def_num=9, - scale=100, - units='m', - ), - 10: Field( - name='total_cycles', - type=BASE_TYPES[0x86], # uint32 - def_num=10, - units='cycles', - subfields=( - SubField( - name='total_strokes', - def_num=10, - type=BASE_TYPES[0x86], # uint32 - units='strokes', - ref_fields=( - ReferenceField( - name='sport', - def_num=23, - value='cycling', - raw_value=2, - ), - ), - ), - ), - ), - 11: Field( - name='total_calories', - type=BASE_TYPES[0x84], # uint16 - def_num=11, - units='kcal', - ), - 12: Field( # If New Leaf - name='total_fat_calories', - type=BASE_TYPES[0x84], # uint16 - def_num=12, - units='kcal', - ), - 13: Field( - name='avg_speed', - type=BASE_TYPES[0x84], # uint16 - def_num=13, - scale=1000, - units='m/s', - ), - 14: Field( - name='max_speed', - type=BASE_TYPES[0x84], # uint16 - def_num=14, - scale=1000, - units='m/s', - ), - 15: Field( - name='avg_heart_rate', - type=BASE_TYPES[0x02], # uint8 - def_num=15, - units='bpm', - ), - 16: Field( - name='max_heart_rate', - type=BASE_TYPES[0x02], # uint8 - def_num=16, - units='bpm', - ), - 17: Field( # total_cycles / total_timer_time if non_zero_avg_cadence otherwise total_cycles / total_elapsed_time - name='avg_cadence', - type=BASE_TYPES[0x02], # uint8 - def_num=17, - units='rpm', - ), - 18: Field( - name='max_cadence', - type=BASE_TYPES[0x02], # uint8 - def_num=18, - units='rpm', - ), - 19: Field( # total_power / total_timer_time if non_zero_avg_power otherwise total_power / total_elapsed_time - name='avg_power', - type=BASE_TYPES[0x84], # uint16 - def_num=19, - units='watts', - ), - 20: Field( - name='max_power', - type=BASE_TYPES[0x84], # uint16 - def_num=20, - units='watts', - ), - 21: Field( - name='total_ascent', - type=BASE_TYPES[0x84], # uint16 - def_num=21, - units='m', - ), - 22: Field( - name='total_descent', - type=BASE_TYPES[0x84], # uint16 - def_num=22, - units='m', - ), - 23: Field( - name='sport', - type=FIELD_TYPES['sport'], - def_num=23, - ), - 24: Field( - name='event_group', - type=BASE_TYPES[0x02], # uint8 - def_num=24, - ), - 25: Field( # North east corner latitude. - name='nec_lat', - type=BASE_TYPES[0x85], # sint32 - def_num=25, - units='semicircles', - ), - 26: Field( # North east corner longitude. - name='nec_long', - type=BASE_TYPES[0x85], # sint32 - def_num=26, - units='semicircles', - ), - 27: Field( # South west corner latitude. - name='swc_lat', - type=BASE_TYPES[0x85], # sint32 - def_num=27, - units='semicircles', - ), - 28: Field( # South west corner latitude. - name='swc_long', - type=BASE_TYPES[0x85], # sint32 - def_num=28, - units='semicircles', - ), - 29: Field( - name='name', - type=BASE_TYPES[0x07], # string - def_num=29, - ), - 30: Field( - name='normalized_power', - type=BASE_TYPES[0x84], # uint16 - def_num=30, - units='watts', - ), - 31: Field( - name='left_right_balance', - type=FIELD_TYPES['left_right_balance_100'], - def_num=31, - ), - 32: Field( - name='sub_sport', - type=FIELD_TYPES['sub_sport'], - def_num=32, - ), - 33: Field( - name='total_work', - type=BASE_TYPES[0x86], # uint32 - def_num=33, - units='J', - ), - 34: Field( - name='avg_altitude', - type=BASE_TYPES[0x84], # uint16 - def_num=34, - scale=5, - offset=500, - units='m', - ), - 35: Field( - name='max_altitude', - type=BASE_TYPES[0x84], # uint16 - def_num=35, - scale=5, - offset=500, - units='m', - ), - 36: Field( - name='gps_accuracy', - type=BASE_TYPES[0x02], # uint8 - def_num=36, - units='m', - ), - 37: Field( - name='avg_grade', - type=BASE_TYPES[0x83], # sint16 - def_num=37, - scale=100, - units='%', - ), - 38: Field( - name='avg_pos_grade', - type=BASE_TYPES[0x83], # sint16 - def_num=38, - scale=100, - units='%', - ), - 39: Field( - name='avg_neg_grade', - type=BASE_TYPES[0x83], # sint16 - def_num=39, - scale=100, - units='%', - ), - 40: Field( - name='max_pos_grade', - type=BASE_TYPES[0x83], # sint16 - def_num=40, - scale=100, - units='%', - ), - 41: Field( - name='max_neg_grade', - type=BASE_TYPES[0x83], # sint16 - def_num=41, - scale=100, - units='%', - ), - 42: Field( - name='avg_temperature', - type=BASE_TYPES[0x01], # sint8 - def_num=42, - units='C', - ), - 43: Field( - name='max_temperature', - type=BASE_TYPES[0x01], # sint8 - def_num=43, - units='C', - ), - 44: Field( - name='total_moving_time', - type=BASE_TYPES[0x86], # uint32 - def_num=44, - scale=1000, - units='s', - ), - 45: Field( - name='avg_pos_vertical_speed', - type=BASE_TYPES[0x83], # sint16 - def_num=45, - scale=1000, - units='m/s', - ), - 46: Field( - name='avg_neg_vertical_speed', - type=BASE_TYPES[0x83], # sint16 - def_num=46, - scale=1000, - units='m/s', - ), - 47: Field( - name='max_pos_vertical_speed', - type=BASE_TYPES[0x83], # sint16 - def_num=47, - scale=1000, - units='m/s', - ), - 48: Field( - name='max_neg_vertical_speed', - type=BASE_TYPES[0x83], # sint16 - def_num=48, - scale=1000, - units='m/s', - ), - 49: Field( - name='time_in_hr_zone', - type=BASE_TYPES[0x86], # uint32 - def_num=49, - scale=1000, - units='s', - ), - 50: Field( - name='time_in_speed_zone', - type=BASE_TYPES[0x86], # uint32 - def_num=50, - scale=1000, - units='s', - ), - 51: Field( - name='time_in_cadence_zone', - type=BASE_TYPES[0x86], # uint32 - def_num=51, - scale=1000, - units='s', - ), - 52: Field( - name='time_in_power_zone', - type=BASE_TYPES[0x86], # uint32 - def_num=52, - scale=1000, - units='s', - ), - 53: Field( - name='repetition_num', - type=BASE_TYPES[0x84], # uint16 - def_num=53, - ), - 54: Field( - name='min_altitude', - type=BASE_TYPES[0x84], # uint16 - def_num=54, - scale=5, - offset=500, - units='m', - ), - 55: Field( - name='min_heart_rate', - type=BASE_TYPES[0x02], # uint8 - def_num=55, - units='bpm', - ), - 56: Field( - name='active_time', - type=BASE_TYPES[0x86], # uint32 - def_num=56, - scale=1000, - units='s', - ), - 57: Field( - name='wkt_step_index', - type=FIELD_TYPES['message_index'], - def_num=57, - ), - 58: Field( - name='sport_event', - type=FIELD_TYPES['sport_event'], - def_num=58, - ), - 59: Field( - name='avg_left_torque_effectiveness', - type=BASE_TYPES[0x02], # uint8 - def_num=59, - scale=2, - units='percent', - ), - 60: Field( - name='avg_right_torque_effectiveness', - type=BASE_TYPES[0x02], # uint8 - def_num=60, - scale=2, - units='percent', - ), - 61: Field( - name='avg_left_pedal_smoothness', - type=BASE_TYPES[0x02], # uint8 - def_num=61, - scale=2, - units='percent', - ), - 62: Field( - name='avg_right_pedal_smoothness', - type=BASE_TYPES[0x02], # uint8 - def_num=62, - scale=2, - units='percent', - ), - 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, - ), - 2: Field( - name='fit_base_type_id', - type=FIELD_TYPES['fit_base_type'], - def_num=2, - ), - 3: Field( - name='field_name', - type=BASE_TYPES[0x07], # string - def_num=3, - ), - 4: Field( - name='array', - type=BASE_TYPES[0x02], # uint8 - def_num=4, - ), - 5: Field( - name='components', - type=BASE_TYPES[0x07], # string - def_num=5, - ), - 6: Field( - name='scale', - type=BASE_TYPES[0x02], # uint8 - def_num=6, - ), - 7: Field( - name='offset', - type=BASE_TYPES[0x01], # sint8 - def_num=7, - ), - 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, - ), - }, - ), - 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, - ), - 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( - name='application_version', - type=BASE_TYPES[0x86], # uint32 - def_num=4, - ), - }, - ), - 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', - ), - 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', - ), - 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', - ), - 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 - }, - ), - - - ######################### Activity File Messages ######################### - 34: MessageType( - name='activity', - mesg_num=34, - fields={ - 0: Field( # Exclude pauses - name='total_timer_time', - type=BASE_TYPES[0x86], # uint32 - def_num=0, - scale=1000, - units='s', - ), - 1: Field( - name='num_sessions', - type=BASE_TYPES[0x84], # uint16 - def_num=1, - ), - 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, - }, - ), - - - ###################### Blood Pressure File Messages ###################### - 51: MessageType( - name='blood_pressure', - mesg_num=51, - fields={ - 0: Field( - name='systolic_pressure', - type=BASE_TYPES[0x84], # uint16 - def_num=0, - units='mmHg', - ), - 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, - }, - ), - - - ########################## Course File Messages ########################## - 31: MessageType( - name='course', - mesg_num=31, - fields={ - 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, - ), - }, - ), - - - ########################## Device File Messages ########################## - 35: MessageType( - name='software', - mesg_num=35, - fields={ - 3: Field( - name='version', - type=BASE_TYPES[0x84], # uint16 - def_num=3, - scale=100, - ), - 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, - ), - }, - ), - - - ########################## Goals File Messages ########################### - 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, - ), - }, - ), - - - ######################## Monitoring File Messages ######################## - 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, - }, - ), - - - ############################# Other Messages ############################# - 145: MessageType( - name='memo_glob', - mesg_num=145, - fields={ - 0: Field( # Block of utf8 bytes - name='memo', - type=BASE_TYPES[0x0D], # byte - 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 - def_num=1, - ), - 2: Field( # Index of external mesg - name='message_index', - type=FIELD_TYPES['message_index'], - def_num=2, - ), - 250: Field( # Sequence number of memo blocks - name='part_index', - type=BASE_TYPES[0x86], # uint32 - def_num=250, - ), - }, - ), - - - ######################### Schedule File Messages ######################### - 28: MessageType( - name='schedule', - mesg_num=28, - fields={ - 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='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, - ), - ), - ), - ), - ), - 2: Field( # Corresponds to file_id of scheduled workout / course. - name='serial_number', - type=BASE_TYPES[0x8C], # uint32z - def_num=2, - ), - 3: Field( # Corresponds to file_id of scheduled workout / course. - name='time_created', - type=FIELD_TYPES['date_time'], - def_num=3, - ), - 4: Field( # TRUE if this activity has been started - name='completed', - type=FIELD_TYPES['bool'], - def_num=4, - ), - 5: Field( - name='type', - type=FIELD_TYPES['schedule'], - def_num=5, - ), - 6: Field( - name='scheduled_time', - type=FIELD_TYPES['local_date_time'], - def_num=6, - ), - }, - ), - - - ######################### Segment File Messages ########################## - 148: MessageType( # Unique Identification data for a segment file - name='segment_id', - mesg_num=148, - fields={ - 0: Field( # Friendly name assigned to segment - name='name', - type=BASE_TYPES[0x07], # string - def_num=0, - ), - 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( # Primary key of the user that created the segment - name='user_profile_primary_key', - type=BASE_TYPES[0x86], # uint32 - def_num=4, - ), - 5: Field( # ID of the device that created the segment - name='device_id', - type=BASE_TYPES[0x86], # uint32 - def_num=5, - ), - 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( # Indicates if any segments should be deleted - name='delete_status', - type=FIELD_TYPES['segment_delete_status'], - 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'], - def_num=8, - ), - }, - ), - - - ####################### Segment List File Messages ####################### - 151: MessageType( # Summary of the unique segment and leaderboard information associated with a segment file. This message is used to compile a segment list file describing all segment files on a device. The segment list file is used when refreshing the contents of a segment file with the latest available leaderboard information. - name='segment_file', - mesg_num=151, - fields={ - 1: Field( # UUID of the segment file - name='file_uuid', - type=BASE_TYPES[0x07], # string - def_num=1, - ), - 3: Field( # Enabled state of the segment file - name='enabled', - type=FIELD_TYPES['bool'], - def_num=3, - ), - 4: Field( # Primary key of the user that created the segment file - name='user_profile_primary_key', - type=BASE_TYPES[0x86], # uint32 - def_num=4, - ), - 7: Field( # Leader type of each leader in the segment file - name='leader_type', - type=FIELD_TYPES['segment_leaderboard_type'], - def_num=7, - ), - 8: Field( # Group primary key of each leader in the segment file - name='leader_group_primary_key', - type=BASE_TYPES[0x86], # uint32 - def_num=8, - ), - 9: Field( # Activity ID of each leader in the segment file - name='leader_activity_id', - type=BASE_TYPES[0x86], # uint32 - def_num=9, - ), - 10: Field( # String version of the activity ID of each leader in the segment file. 21 characters long for each ID, express in decimal - name='leader_activity_id_string', - type=BASE_TYPES[0x07], # string - def_num=10, - ), - 11: Field( # Index for the Leader Board entry selected as the default race participant - name='default_race_leader', - type=BASE_TYPES[0x02], # uint8 - def_num=11, - ), - 254: Field( - name='message_index', - type=FIELD_TYPES['message_index'], - def_num=254, - ), - }, - ), - - - ######################### Settings File Messages ######################### - 2: MessageType( - name='device_settings', - mesg_num=2, - fields={ - 0: Field( # Index into time zone arrays. - name='active_time_zone', - type=BASE_TYPES[0x02], # uint8 - def_num=0, - ), - 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( # Offset from system time. - name='time_offset', - 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', - ), - 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=36, - ), - 39: Field( # UTC timestamp used to set the devices clock and date - name='clock_time', - type=FIELD_TYPES['date_time'], - def_num=39, - ), - 40: Field( # Bitfield to configure enabled screens for each supported loop - name='pages_enabled', - 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, - ), - 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=80, - ), - 86: Field( # Automatically upload using BLE - name='ble_auto_upload_enabled', - type=FIELD_TYPES['bool'], - def_num=86, - ), - 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=94, - ), - 95: Field( # Smart Notification display orientation - name='smart_notification_display_orientation', - type=FIELD_TYPES['display_orientation'], - def_num=95, - ), - }, - ), - - - ###################### Sport Settings File Messages ###################### - 7: MessageType( - name='zones_target', - mesg_num=7, - fields={ - 1: Field( - name='max_heart_rate', - type=BASE_TYPES[0x02], # uint8 - def_num=1, - ), - 2: Field( - 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, - ), - }, - ), - - - ########################## Totals File Messages ########################## - 33: MessageType( - name='totals', - mesg_num=33, - fields={ - 0: Field( # Excludes pauses - name='timer_time', - type=BASE_TYPES[0x86], # uint32 - def_num=0, - units='s', - ), - 1: Field( - name='distance', - type=BASE_TYPES[0x86], # uint32 - def_num=1, - units='m', - ), - 2: Field( - name='calories', - type=BASE_TYPES[0x86], # uint32 - def_num=2, - units='kcal', - ), - 3: Field( - name='sport', - type=FIELD_TYPES['sport'], - def_num=3, - ), - 4: Field( # Includes pauses - name='elapsed_time', - type=BASE_TYPES[0x86], # uint32 - def_num=4, - units='s', - ), - 5: Field( - name='sessions', - type=BASE_TYPES[0x84], # uint16 - def_num=5, - ), - 6: Field( - name='active_time', - type=BASE_TYPES[0x86], # uint32 - def_num=6, - units='s', - ), - 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'], - def_num=254, - ), - }, - ), - - - ####################### Weight Scale File Messages ####################### - 30: MessageType( - name='weight_scale', - mesg_num=30, - fields={ - 0: Field( - name='weight', - type=FIELD_TYPES['weight'], - def_num=0, - scale=100, - units='kg', - ), - 1: Field( - name='percent_fat', - type=BASE_TYPES[0x84], # uint16 - def_num=1, - scale=100, - units='%', - ), - 2: Field( - name='percent_hydration', - type=BASE_TYPES[0x84], # uint16 - def_num=2, - scale=100, - units='%', - ), - 3: Field( - name='visceral_fat_mass', - type=BASE_TYPES[0x84], # uint16 - def_num=3, - scale=100, - units='kg', - ), - 4: Field( - name='bone_mass', - type=BASE_TYPES[0x84], # uint16 - def_num=4, - 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=12, - ), - 253: FIELD_TYPE_TIMESTAMP, - }, - ), - - - ######################### Workout File Messages ########################## - 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, - ), - }, - ), -} + +# ***************** BEGIN AUTOMATICALLY GENERATED FIT PROFILE ****************** +# *************************** DO NOT EDIT THIS FILE **************************** +# *********** EXPORTED PROFILE FROM SDK VERSION 20.66 ON 2018-07-18 ************ +# ********* PARSED 161 TYPES (2985 VALUES), 85 MESSAGES (1038 FIELDS) ********** + +from fitparse.records import ( + ComponentField, + Field, + FieldType, + MessageType, + ReferenceField, + SubField, + BASE_TYPES, +) + + +FIELD_NUM_TIMESTAMP = 253 + + +FIELD_TYPES = { + 'activity': FieldType( + name='activity', + base_type=BASE_TYPES[0x00], # enum + values={ + 0: 'manual', + 1: 'auto_multi_sport', + }, + ), + 'activity_class': FieldType( + name='activity_class', + base_type=BASE_TYPES[0x00], # enum + values={ + 100: 'level_max', + 0x7F: 'level', # 0 to 100 + 0x80: 'athlete', + }, + ), + 'activity_level': FieldType( + name='activity_level', + base_type=BASE_TYPES[0x00], # enum + values={ + 0: 'low', + 1: 'medium', + 2: 'high', + }, + ), + 'activity_subtype': FieldType( + name='activity_subtype', + base_type=BASE_TYPES[0x00], # enum + values={ + 0: 'generic', + 1: 'treadmill', # Run + 2: 'street', # Run + 3: 'trail', # Run + 4: 'track', # Run + 5: 'spin', # Cycling + 6: 'indoor_cycling', # Cycling + 7: 'road', # Cycling + 8: 'mountain', # Cycling + 9: 'downhill', # Cycling + 10: 'recumbent', # Cycling + 11: 'cyclocross', # Cycling + 12: 'hand_cycling', # Cycling + 13: 'track_cycling', # Cycling + 14: 'indoor_rowing', # Fitness Equipment + 15: 'elliptical', # Fitness Equipment + 16: 'stair_climbing', # Fitness Equipment + 17: 'lap_swimming', # Swimming + 18: 'open_water', # Swimming + 254: 'all', + }, + ), + 'activity_type': FieldType( + name='activity_type', + base_type=BASE_TYPES[0x00], # enum + values={ + 0: 'generic', + 1: 'running', + 2: 'cycling', + 3: 'transition', # Mulitsport transition + 4: 'fitness_equipment', + 5: 'swimming', + 6: 'walking', + 8: 'sedentary', + 254: 'all', # All is for goals only to include all sports. + }, + ), + 'analog_watchface_layout': FieldType( + name='analog_watchface_layout', + base_type=BASE_TYPES[0x00], # enum + values={ + 0: 'minimal', + 1: 'traditional', + 2: 'modern', + }, + ), + 'ant_network': FieldType( + name='ant_network', + base_type=BASE_TYPES[0x00], # enum + values={ + 0: 'public', + 1: 'antplus', + 2: 'antfs', + 3: 'private', + }, + ), + 'antplus_device_type': FieldType( + name='antplus_device_type', + base_type=BASE_TYPES[0x02], # uint8 + values={ + 1: 'antfs', + 11: 'bike_power', + 12: 'environment_sensor_legacy', + 15: 'multi_sport_speed_distance', + 16: 'control', + 17: 'fitness_equipment', + 18: 'blood_pressure', + 19: 'geocache_node', + 20: 'light_electric_vehicle', + 25: 'env_sensor', + 26: 'racquet', + 27: 'control_hub', + 31: 'muscle_oxygen', + 35: 'bike_light_main', + 36: 'bike_light_shared', + 38: 'exd', + 40: 'bike_radar', + 119: 'weight_scale', + 120: 'heart_rate', + 121: 'bike_speed_cadence', + 122: 'bike_cadence', + 123: 'bike_speed', + 124: 'stride_speed_distance', + }, + ), + 'attitude_stage': FieldType( + name='attitude_stage', + base_type=BASE_TYPES[0x00], # enum + values={ + 0: 'failed', + 1: 'aligning', + 2: 'degraded', + 3: 'valid', + }, + ), + 'attitude_validity': FieldType( + name='attitude_validity', + base_type=BASE_TYPES[0x84], # uint16 + values={ + 0x0001: 'track_angle_heading_valid', + 0x0002: 'pitch_valid', + 0x0004: 'roll_valid', + 0x0008: 'lateral_body_accel_valid', + 0x0010: 'normal_body_accel_valid', + 0x0020: 'turn_rate_valid', + 0x0040: 'hw_fail', + 0x0080: 'mag_invalid', + 0x0100: 'no_gps', + 0x0200: 'gps_invalid', + 0x0400: 'solution_coasting', + 0x0800: 'true_track_angle', + 0x1000: 'magnetic_heading', + }, + ), + 'auto_activity_detect': FieldType( + name='auto_activity_detect', + base_type=BASE_TYPES[0x86], # uint32 + values={ + 0x00000000: 'none', + 0x00000001: 'running', + 0x00000002: 'cycling', + 0x00000004: 'swimming', + 0x00000008: 'walking', + 0x00000020: 'elliptical', + 0x00000400: 'sedentary', + }, + ), + 'auto_sync_frequency': FieldType( + name='auto_sync_frequency', + base_type=BASE_TYPES[0x00], # enum + values={ + 0: 'never', + 1: 'occasionally', + 2: 'frequent', + 3: 'once_a_day', + 4: 'remote', + }, + ), + 'autolap_trigger': FieldType( + name='autolap_trigger', + base_type=BASE_TYPES[0x00], # enum + values={ + 0: 'time', + 1: 'distance', + 2: 'position_start', + 3: 'position_lap', + 4: 'position_waypoint', + 5: 'position_marked', + 6: 'off', + }, + ), + 'autoscroll': FieldType( + name='autoscroll', + base_type=BASE_TYPES[0x00], # enum + values={ + 0: 'none', + 1: 'slow', + 2: 'medium', + 3: 'fast', + }, + ), + 'backlight_mode': FieldType( + name='backlight_mode', + base_type=BASE_TYPES[0x00], # enum + values={ + 0: 'off', + 1: 'manual', + 2: 'key_and_messages', + 3: 'auto_brightness', + 4: 'smart_notifications', + 5: 'key_and_messages_night', + 6: 'key_and_messages_and_smart_notifications', + }, + ), + 'backlight_timeout': FieldType( # Timeout in seconds. + name='backlight_timeout', + base_type=BASE_TYPES[0x02], # uint8 + values={ + 0: 'infinite', # Backlight stays on forever. + }, + ), + 'battery_status': FieldType( + name='battery_status', + base_type=BASE_TYPES[0x02], # uint8 + values={ + 1: 'new', + 2: 'good', + 3: 'ok', + 4: 'low', + 5: 'critical', + 6: 'charging', + 7: 'unknown', + }, + ), + 'bench_press_exercise_name': FieldType( + name='bench_press_exercise_name', + base_type=BASE_TYPES[0x84], # uint16 + values={ + 0: 'alternating_dumbbell_chest_press_on_swiss_ball', + 1: 'barbell_bench_press', + 2: 'barbell_board_bench_press', + 3: 'barbell_floor_press', + 4: 'close_grip_barbell_bench_press', + 5: 'decline_dumbbell_bench_press', + 6: 'dumbbell_bench_press', + 7: 'dumbbell_floor_press', + 8: 'incline_barbell_bench_press', + 9: 'incline_dumbbell_bench_press', + 10: 'incline_smith_machine_bench_press', + 11: 'isometric_barbell_bench_press', + 12: 'kettlebell_chest_press', + 13: 'neutral_grip_dumbbell_bench_press', + 14: 'neutral_grip_dumbbell_incline_bench_press', + 15: 'one_arm_floor_press', + 16: 'weighted_one_arm_floor_press', + 17: 'partial_lockout', + 18: 'reverse_grip_barbell_bench_press', + 19: 'reverse_grip_incline_bench_press', + 20: 'single_arm_cable_chest_press', + 21: 'single_arm_dumbbell_bench_press', + 22: 'smith_machine_bench_press', + 23: 'swiss_ball_dumbbell_chest_press', + 24: 'triple_stop_barbell_bench_press', + 25: 'wide_grip_barbell_bench_press', + 26: 'alternating_dumbbell_chest_press', + }, + ), + 'bike_light_beam_angle_mode': FieldType( + name='bike_light_beam_angle_mode', + base_type=BASE_TYPES[0x02], # uint8 + values={ + 0: 'manual', + 1: 'auto', + }, + ), + 'bike_light_network_config_type': FieldType( + name='bike_light_network_config_type', + base_type=BASE_TYPES[0x00], # enum + values={ + 0: 'auto', + 4: 'individual', + 5: 'high_visibility', + 6: 'trail', + }, + ), + 'body_location': FieldType( + name='body_location', + base_type=BASE_TYPES[0x00], # enum + values={ + 0: 'left_leg', + 1: 'left_calf', + 2: 'left_shin', + 3: 'left_hamstring', + 4: 'left_quad', + 5: 'left_glute', + 6: 'right_leg', + 7: 'right_calf', + 8: 'right_shin', + 9: 'right_hamstring', + 10: 'right_quad', + 11: 'right_glute', + 12: 'torso_back', + 13: 'left_lower_back', + 14: 'left_upper_back', + 15: 'right_lower_back', + 16: 'right_upper_back', + 17: 'torso_front', + 18: 'left_abdomen', + 19: 'left_chest', + 20: 'right_abdomen', + 21: 'right_chest', + 22: 'left_arm', + 23: 'left_shoulder', + 24: 'left_bicep', + 25: 'left_tricep', + 26: 'left_brachioradialis', # Left anterior forearm + 27: 'left_forearm_extensors', # Left posterior forearm + 28: 'right_arm', + 29: 'right_shoulder', + 30: 'right_bicep', + 31: 'right_tricep', + 32: 'right_brachioradialis', # Right anterior forearm + 33: 'right_forearm_extensors', # Right posterior forearm + 34: 'neck', + 35: 'throat', + 36: 'waist_mid_back', + 37: 'waist_front', + 38: 'waist_left', + 39: 'waist_right', + }, + ), + 'bool': FieldType( + name='bool', + base_type=BASE_TYPES[0x00], # enum + ), + 'bp_status': FieldType( + name='bp_status', + base_type=BASE_TYPES[0x00], # enum + values={ + 0: 'no_error', + 1: 'error_incomplete_data', + 2: 'error_no_measurement', + 3: 'error_data_out_of_range', + 4: 'error_irregular_heart_rate', + }, + ), + 'calf_raise_exercise_name': FieldType( + name='calf_raise_exercise_name', + base_type=BASE_TYPES[0x84], # uint16 + values={ + 0: '3_way_calf_raise', + 1: '3_way_weighted_calf_raise', + 2: '3_way_single_leg_calf_raise', + 3: '3_way_weighted_single_leg_calf_raise', + 4: 'donkey_calf_raise', + 5: 'weighted_donkey_calf_raise', + 6: 'seated_calf_raise', + 7: 'weighted_seated_calf_raise', + 8: 'seated_dumbbell_toe_raise', + 9: 'single_leg_bent_knee_calf_raise', + 10: 'weighted_single_leg_bent_knee_calf_raise', + 11: 'single_leg_decline_push_up', + 12: 'single_leg_donkey_calf_raise', + 13: 'weighted_single_leg_donkey_calf_raise', + 14: 'single_leg_hip_raise_with_knee_hold', + 15: 'single_leg_standing_calf_raise', + 16: 'single_leg_standing_dumbbell_calf_raise', + 17: 'standing_barbell_calf_raise', + 18: 'standing_calf_raise', + 19: 'weighted_standing_calf_raise', + 20: 'standing_dumbbell_calf_raise', + }, + ), + 'camera_event_type': FieldType( + name='camera_event_type', + base_type=BASE_TYPES[0x00], # enum + values={ + 0: 'video_start', # Start of video recording + 1: 'video_split', # Mark of video file split (end of one file, beginning of the other) + 2: 'video_end', # End of video recording + 3: 'photo_taken', # Still photo taken + 4: 'video_second_stream_start', + 5: 'video_second_stream_split', + 6: 'video_second_stream_end', + 7: 'video_split_start', # Mark of video file split start + 8: 'video_second_stream_split_start', + 11: 'video_pause', # Mark when a video recording has been paused + 12: 'video_second_stream_pause', + 13: 'video_resume', # Mark when a video recording has been resumed + 14: 'video_second_stream_resume', + }, + ), + 'camera_orientation_type': FieldType( + name='camera_orientation_type', + base_type=BASE_TYPES[0x00], # enum + values={ + 0: 'camera_orientation_0', + 1: 'camera_orientation_90', + 2: 'camera_orientation_180', + 3: 'camera_orientation_270', + }, + ), + 'cardio_exercise_name': FieldType( + name='cardio_exercise_name', + base_type=BASE_TYPES[0x84], # uint16 + values={ + 0: 'bob_and_weave_circle', + 1: 'weighted_bob_and_weave_circle', + 2: 'cardio_core_crawl', + 3: 'weighted_cardio_core_crawl', + 4: 'double_under', + 5: 'weighted_double_under', + 6: 'jump_rope', + 7: 'weighted_jump_rope', + 8: 'jump_rope_crossover', + 9: 'weighted_jump_rope_crossover', + 10: 'jump_rope_jog', + 11: 'weighted_jump_rope_jog', + 12: 'jumping_jacks', + 13: 'weighted_jumping_jacks', + 14: 'ski_moguls', + 15: 'weighted_ski_moguls', + 16: 'split_jacks', + 17: 'weighted_split_jacks', + 18: 'squat_jacks', + 19: 'weighted_squat_jacks', + 20: 'triple_under', + 21: 'weighted_triple_under', + }, + ), + 'carry_exercise_name': FieldType( + name='carry_exercise_name', + base_type=BASE_TYPES[0x84], # uint16 + values={ + 0: 'bar_holds', + 1: 'farmers_walk', + 2: 'farmers_walk_on_toes', + 3: 'hex_dumbbell_hold', + 4: 'overhead_carry', + }, + ), + 'checksum': FieldType( + name='checksum', + base_type=BASE_TYPES[0x02], # uint8 + values={ + 0: 'clear', # Allows clear of checksum for flash memory where can only write 1 to 0 without erasing sector. + 1: 'ok', # Set to mark checksum as valid if computes to invalid values 0 or 0xFF. Checksum can also be set to ok to save encoding computation time. + }, + ), + 'chop_exercise_name': FieldType( + name='chop_exercise_name', + base_type=BASE_TYPES[0x84], # uint16 + values={ + 0: 'cable_pull_through', + 1: 'cable_rotational_lift', + 2: 'cable_woodchop', + 3: 'cross_chop_to_knee', + 4: 'weighted_cross_chop_to_knee', + 5: 'dumbbell_chop', + 6: 'half_kneeling_rotation', + 7: 'weighted_half_kneeling_rotation', + 8: 'half_kneeling_rotational_chop', + 9: 'half_kneeling_rotational_reverse_chop', + 10: 'half_kneeling_stability_chop', + 11: 'half_kneeling_stability_reverse_chop', + 12: 'kneeling_rotational_chop', + 13: 'kneeling_rotational_reverse_chop', + 14: 'kneeling_stability_chop', + 15: 'kneeling_woodchopper', + 16: 'medicine_ball_wood_chops', + 17: 'power_squat_chops', + 18: 'weighted_power_squat_chops', + 19: 'standing_rotational_chop', + 20: 'standing_split_rotational_chop', + 21: 'standing_split_rotational_reverse_chop', + 22: 'standing_stability_reverse_chop', + }, + ), + 'comm_timeout_type': FieldType( + name='comm_timeout_type', + base_type=BASE_TYPES[0x84], # uint16 + values={ + 0: 'wildcard_pairing_timeout', # Timeout pairing to any device + 1: 'pairing_timeout', # Timeout pairing to previously paired device + 2: 'connection_lost', # Temporary loss of communications + 3: 'connection_timeout', # Connection closed due to extended bad communications + }, + ), + 'connectivity_capabilities': FieldType( + name='connectivity_capabilities', + base_type=BASE_TYPES[0x8C], # uint32z + values={ + 0x00000001: 'bluetooth', + 0x00000002: 'bluetooth_le', + 0x00000004: 'ant', + 0x00000008: 'activity_upload', + 0x00000010: 'course_download', + 0x00000020: 'workout_download', + 0x00000040: 'live_track', + 0x00000080: 'weather_conditions', + 0x00000100: 'weather_alerts', + 0x00000200: 'gps_ephemeris_download', + 0x00000400: 'explicit_archive', + 0x00000800: 'setup_incomplete', + 0x00001000: 'continue_sync_after_software_update', + 0x00002000: 'connect_iq_app_download', + 0x00004000: 'golf_course_download', + 0x00008000: 'device_initiates_sync', # Indicates device is in control of initiating all syncs + 0x00010000: 'connect_iq_watch_app_download', + 0x00020000: 'connect_iq_widget_download', + 0x00040000: 'connect_iq_watch_face_download', + 0x00080000: 'connect_iq_data_field_download', + 0x00100000: 'connect_iq_app_managment', # Device supports delete and reorder of apps via GCM + 0x00200000: 'swing_sensor', + 0x00400000: 'swing_sensor_remote', + 0x00800000: 'incident_detection', # Device supports incident detection + 0x01000000: 'audio_prompts', + 0x02000000: 'wifi_verification', # Device supports reporting wifi verification via GCM + 0x04000000: 'true_up', # Device supports True Up + 0x08000000: 'find_my_watch', # Device supports Find My Watch + 0x10000000: 'remote_manual_sync', + 0x20000000: 'live_track_auto_start', # Device supports LiveTrack auto start + 0x40000000: 'live_track_messaging', # Device supports LiveTrack Messaging + 0x80000000: 'instant_input', # Device supports instant input feature + }, + ), + 'core_exercise_name': FieldType( + name='core_exercise_name', + base_type=BASE_TYPES[0x84], # uint16 + values={ + 0: 'abs_jabs', + 1: 'weighted_abs_jabs', + 2: 'alternating_plate_reach', + 3: 'barbell_rollout', + 4: 'weighted_barbell_rollout', + 5: 'body_bar_oblique_twist', + 6: 'cable_core_press', + 7: 'cable_side_bend', + 8: 'side_bend', + 9: 'weighted_side_bend', + 10: 'crescent_circle', + 11: 'weighted_crescent_circle', + 12: 'cycling_russian_twist', + 13: 'weighted_cycling_russian_twist', + 14: 'elevated_feet_russian_twist', + 15: 'weighted_elevated_feet_russian_twist', + 16: 'half_turkish_get_up', + 17: 'kettlebell_windmill', + 18: 'kneeling_ab_wheel', + 19: 'weighted_kneeling_ab_wheel', + 20: 'modified_front_lever', + 21: 'open_knee_tucks', + 22: 'weighted_open_knee_tucks', + 23: 'side_abs_leg_lift', + 24: 'weighted_side_abs_leg_lift', + 25: 'swiss_ball_jackknife', + 26: 'weighted_swiss_ball_jackknife', + 27: 'swiss_ball_pike', + 28: 'weighted_swiss_ball_pike', + 29: 'swiss_ball_rollout', + 30: 'weighted_swiss_ball_rollout', + 31: 'triangle_hip_press', + 32: 'weighted_triangle_hip_press', + 33: 'trx_suspended_jackknife', + 34: 'weighted_trx_suspended_jackknife', + 35: 'u_boat', + 36: 'weighted_u_boat', + 37: 'windmill_switches', + 38: 'weighted_windmill_switches', + 39: 'alternating_slide_out', + 40: 'weighted_alternating_slide_out', + 41: 'ghd_back_extensions', + 42: 'weighted_ghd_back_extensions', + 43: 'overhead_walk', + 44: 'inchworm', + 45: 'weighted_modified_front_lever', + }, + ), + 'course_capabilities': FieldType( + name='course_capabilities', + base_type=BASE_TYPES[0x8C], # uint32z + values={ + 0x00000001: 'processed', + 0x00000002: 'valid', + 0x00000004: 'time', + 0x00000008: 'distance', + 0x00000010: 'position', + 0x00000020: 'heart_rate', + 0x00000040: 'power', + 0x00000080: 'cadence', + 0x00000100: 'training', + 0x00000200: 'navigation', + 0x00000400: 'bikeway', + }, + ), + 'course_point': FieldType( + name='course_point', + base_type=BASE_TYPES[0x00], # enum + values={ + 0: 'generic', + 1: 'summit', + 2: 'valley', + 3: 'water', + 4: 'food', + 5: 'danger', + 6: 'left', + 7: 'right', + 8: 'straight', + 9: 'first_aid', + 10: 'fourth_category', + 11: 'third_category', + 12: 'second_category', + 13: 'first_category', + 14: 'hors_category', + 15: 'sprint', + 16: 'left_fork', + 17: 'right_fork', + 18: 'middle_fork', + 19: 'slight_left', + 20: 'sharp_left', + 21: 'slight_right', + 22: 'sharp_right', + 23: 'u_turn', + 24: 'segment_start', + 25: 'segment_end', + }, + ), + 'crunch_exercise_name': FieldType( + name='crunch_exercise_name', + base_type=BASE_TYPES[0x84], # uint16 + values={ + 0: 'bicycle_crunch', + 1: 'cable_crunch', + 2: 'circular_arm_crunch', + 3: 'crossed_arms_crunch', + 4: 'weighted_crossed_arms_crunch', + 5: 'cross_leg_reverse_crunch', + 6: 'weighted_cross_leg_reverse_crunch', + 7: 'crunch_chop', + 8: 'weighted_crunch_chop', + 9: 'double_crunch', + 10: 'weighted_double_crunch', + 11: 'elbow_to_knee_crunch', + 12: 'weighted_elbow_to_knee_crunch', + 13: 'flutter_kicks', + 14: 'weighted_flutter_kicks', + 15: 'foam_roller_reverse_crunch_on_bench', + 16: 'weighted_foam_roller_reverse_crunch_on_bench', + 17: 'foam_roller_reverse_crunch_with_dumbbell', + 18: 'foam_roller_reverse_crunch_with_medicine_ball', + 19: 'frog_press', + 20: 'hanging_knee_raise_oblique_crunch', + 21: 'weighted_hanging_knee_raise_oblique_crunch', + 22: 'hip_crossover', + 23: 'weighted_hip_crossover', + 24: 'hollow_rock', + 25: 'weighted_hollow_rock', + 26: 'incline_reverse_crunch', + 27: 'weighted_incline_reverse_crunch', + 28: 'kneeling_cable_crunch', + 29: 'kneeling_cross_crunch', + 30: 'weighted_kneeling_cross_crunch', + 31: 'kneeling_oblique_cable_crunch', + 32: 'knees_to_elbow', + 33: 'leg_extensions', + 34: 'weighted_leg_extensions', + 35: 'leg_levers', + 36: 'mcgill_curl_up', + 37: 'weighted_mcgill_curl_up', + 38: 'modified_pilates_roll_up_with_ball', + 39: 'weighted_modified_pilates_roll_up_with_ball', + 40: 'pilates_crunch', + 41: 'weighted_pilates_crunch', + 42: 'pilates_roll_up_with_ball', + 43: 'weighted_pilates_roll_up_with_ball', + 44: 'raised_legs_crunch', + 45: 'weighted_raised_legs_crunch', + 46: 'reverse_crunch', + 47: 'weighted_reverse_crunch', + 48: 'reverse_crunch_on_a_bench', + 49: 'weighted_reverse_crunch_on_a_bench', + 50: 'reverse_curl_and_lift', + 51: 'weighted_reverse_curl_and_lift', + 52: 'rotational_lift', + 53: 'weighted_rotational_lift', + 54: 'seated_alternating_reverse_crunch', + 55: 'weighted_seated_alternating_reverse_crunch', + 56: 'seated_leg_u', + 57: 'weighted_seated_leg_u', + 58: 'side_to_side_crunch_and_weave', + 59: 'weighted_side_to_side_crunch_and_weave', + 60: 'single_leg_reverse_crunch', + 61: 'weighted_single_leg_reverse_crunch', + 62: 'skater_crunch_cross', + 63: 'weighted_skater_crunch_cross', + 64: 'standing_cable_crunch', + 65: 'standing_side_crunch', + 66: 'step_climb', + 67: 'weighted_step_climb', + 68: 'swiss_ball_crunch', + 69: 'swiss_ball_reverse_crunch', + 70: 'weighted_swiss_ball_reverse_crunch', + 71: 'swiss_ball_russian_twist', + 72: 'weighted_swiss_ball_russian_twist', + 73: 'swiss_ball_side_crunch', + 74: 'weighted_swiss_ball_side_crunch', + 75: 'thoracic_crunches_on_foam_roller', + 76: 'weighted_thoracic_crunches_on_foam_roller', + 77: 'triceps_crunch', + 78: 'weighted_bicycle_crunch', + 79: 'weighted_crunch', + 80: 'weighted_swiss_ball_crunch', + 81: 'toes_to_bar', + 82: 'weighted_toes_to_bar', + 83: 'crunch', + }, + ), + 'curl_exercise_name': FieldType( + name='curl_exercise_name', + base_type=BASE_TYPES[0x84], # uint16 + values={ + 0: 'alternating_dumbbell_biceps_curl', + 1: 'alternating_dumbbell_biceps_curl_on_swiss_ball', + 2: 'alternating_incline_dumbbell_biceps_curl', + 3: 'barbell_biceps_curl', + 4: 'barbell_reverse_wrist_curl', + 5: 'barbell_wrist_curl', + 6: 'behind_the_back_barbell_reverse_wrist_curl', + 7: 'behind_the_back_one_arm_cable_curl', + 8: 'cable_biceps_curl', + 9: 'cable_hammer_curl', + 10: 'cheating_barbell_biceps_curl', + 11: 'close_grip_ez_bar_biceps_curl', + 12: 'cross_body_dumbbell_hammer_curl', + 13: 'dead_hang_biceps_curl', + 14: 'decline_hammer_curl', + 15: 'dumbbell_biceps_curl_with_static_hold', + 16: 'dumbbell_hammer_curl', + 17: 'dumbbell_reverse_wrist_curl', + 18: 'dumbbell_wrist_curl', + 19: 'ez_bar_preacher_curl', + 20: 'forward_bend_biceps_curl', + 21: 'hammer_curl_to_press', + 22: 'incline_dumbbell_biceps_curl', + 23: 'incline_offset_thumb_dumbbell_curl', + 24: 'kettlebell_biceps_curl', + 25: 'lying_concentration_cable_curl', + 26: 'one_arm_preacher_curl', + 27: 'plate_pinch_curl', + 28: 'preacher_curl_with_cable', + 29: 'reverse_ez_bar_curl', + 30: 'reverse_grip_wrist_curl', + 31: 'reverse_grip_barbell_biceps_curl', + 32: 'seated_alternating_dumbbell_biceps_curl', + 33: 'seated_dumbbell_biceps_curl', + 34: 'seated_reverse_dumbbell_curl', + 35: 'split_stance_offset_pinky_dumbbell_curl', + 36: 'standing_alternating_dumbbell_curls', + 37: 'standing_dumbbell_biceps_curl', + 38: 'standing_ez_bar_biceps_curl', + 39: 'static_curl', + 40: 'swiss_ball_dumbbell_overhead_triceps_extension', + 41: 'swiss_ball_ez_bar_preacher_curl', + 42: 'twisting_standing_dumbbell_biceps_curl', + 43: 'wide_grip_ez_bar_biceps_curl', + }, + ), + 'date_mode': FieldType( + name='date_mode', + base_type=BASE_TYPES[0x00], # enum + values={ + 0: 'day_month', + 1: 'month_day', + }, + ), + 'date_time': FieldType( # seconds since UTC 00:00 Dec 31 1989 + name='date_time', + base_type=BASE_TYPES[0x86], # uint32 + ), + 'day_of_week': FieldType( + name='day_of_week', + base_type=BASE_TYPES[0x00], # enum + values={ + 0: 'sunday', + 1: 'monday', + 2: 'tuesday', + 3: 'wednesday', + 4: 'thursday', + 5: 'friday', + 6: 'saturday', + }, + ), + 'deadlift_exercise_name': FieldType( + name='deadlift_exercise_name', + base_type=BASE_TYPES[0x84], # uint16 + values={ + 0: 'barbell_deadlift', + 1: 'barbell_straight_leg_deadlift', + 2: 'dumbbell_deadlift', + 3: 'dumbbell_single_leg_deadlift_to_row', + 4: 'dumbbell_straight_leg_deadlift', + 5: 'kettlebell_floor_to_shelf', + 6: 'one_arm_one_leg_deadlift', + 7: 'rack_pull', + 8: 'rotational_dumbbell_straight_leg_deadlift', + 9: 'single_arm_deadlift', + 10: 'single_leg_barbell_deadlift', + 11: 'single_leg_barbell_straight_leg_deadlift', + 12: 'single_leg_deadlift_with_barbell', + 13: 'single_leg_rdl_circuit', + 14: 'single_leg_romanian_deadlift_with_dumbbell', + 15: 'sumo_deadlift', + 16: 'sumo_deadlift_high_pull', + 17: 'trap_bar_deadlift', + 18: 'wide_grip_barbell_deadlift', + }, + ), + 'device_index': FieldType( + name='device_index', + base_type=BASE_TYPES[0x02], # uint8 + values={ + 0: 'creator', # Creator of the file is always device index 0. + }, + ), + 'digital_watchface_layout': FieldType( + name='digital_watchface_layout', + base_type=BASE_TYPES[0x00], # enum + values={ + 0: 'traditional', + 1: 'modern', + 2: 'bold', + }, + ), + 'display_heart': FieldType( + name='display_heart', + base_type=BASE_TYPES[0x00], # enum + values={ + 0: 'bpm', + 1: 'max', + 2: 'reserve', + }, + ), + 'display_measure': FieldType( + name='display_measure', + base_type=BASE_TYPES[0x00], # enum + values={ + 0: 'metric', + 1: 'statute', + 2: 'nautical', + }, + ), + 'display_orientation': FieldType( + name='display_orientation', + base_type=BASE_TYPES[0x00], # enum + values={ + 0: 'auto', # automatic if the device supports it + 1: 'portrait', + 2: 'landscape', + 3: 'portrait_flipped', # portrait mode but rotated 180 degrees + 4: 'landscape_flipped', # landscape mode but rotated 180 degrees + }, + ), + 'display_position': FieldType( + name='display_position', + base_type=BASE_TYPES[0x00], # enum + values={ + 0: 'degree', # dd.dddddd + 1: 'degree_minute', # dddmm.mmm + 2: 'degree_minute_second', # dddmmss + 3: 'austrian_grid', # Austrian Grid (BMN) + 4: 'british_grid', # British National Grid + 5: 'dutch_grid', # Dutch grid system + 6: 'hungarian_grid', # Hungarian grid system + 7: 'finnish_grid', # Finnish grid system Zone3 KKJ27 + 8: 'german_grid', # Gausss Krueger (German) + 9: 'icelandic_grid', # Icelandic Grid + 10: 'indonesian_equatorial', # Indonesian Equatorial LCO + 11: 'indonesian_irian', # Indonesian Irian LCO + 12: 'indonesian_southern', # Indonesian Southern LCO + 13: 'india_zone_0', # India zone 0 + 14: 'india_zone_IA', # India zone IA + 15: 'india_zone_IB', # India zone IB + 16: 'india_zone_IIA', # India zone IIA + 17: 'india_zone_IIB', # India zone IIB + 18: 'india_zone_IIIA', # India zone IIIA + 19: 'india_zone_IIIB', # India zone IIIB + 20: 'india_zone_IVA', # India zone IVA + 21: 'india_zone_IVB', # India zone IVB + 22: 'irish_transverse', # Irish Transverse Mercator + 23: 'irish_grid', # Irish Grid + 24: 'loran', # Loran TD + 25: 'maidenhead_grid', # Maidenhead grid system + 26: 'mgrs_grid', # MGRS grid system + 27: 'new_zealand_grid', # New Zealand grid system + 28: 'new_zealand_transverse', # New Zealand Transverse Mercator + 29: 'qatar_grid', # Qatar National Grid + 30: 'modified_swedish_grid', # Modified RT-90 (Sweden) + 31: 'swedish_grid', # RT-90 (Sweden) + 32: 'south_african_grid', # South African Grid + 33: 'swiss_grid', # Swiss CH-1903 grid + 34: 'taiwan_grid', # Taiwan Grid + 35: 'united_states_grid', # United States National Grid + 36: 'utm_ups_grid', # UTM/UPS grid system + 37: 'west_malayan', # West Malayan RSO + 38: 'borneo_rso', # Borneo RSO + 39: 'estonian_grid', # Estonian grid system + 40: 'latvian_grid', # Latvian Transverse Mercator + 41: 'swedish_ref_99_grid', # Reference Grid 99 TM (Swedish) + }, + ), + 'display_power': FieldType( + name='display_power', + base_type=BASE_TYPES[0x00], # enum + values={ + 0: 'watts', + 1: 'percent_ftp', + }, + ), + 'dive_alarm_type': FieldType( + name='dive_alarm_type', + base_type=BASE_TYPES[0x00], # enum + values={ + 0: 'depth', + 1: 'time', + }, + ), + 'dive_backlight_mode': FieldType( + name='dive_backlight_mode', + base_type=BASE_TYPES[0x00], # enum + values={ + 0: 'at_depth', + 1: 'always_on', + }, + ), + 'dive_gas_status': FieldType( + name='dive_gas_status', + base_type=BASE_TYPES[0x00], # enum + values={ + 0: 'disabled', + 1: 'enabled', + 2: 'backup_only', + }, + ), + 'event': FieldType( + name='event', + base_type=BASE_TYPES[0x00], # enum + values={ + 0: 'timer', # Group 0. Start / stop_all + 3: 'workout', # start / stop + 4: 'workout_step', # Start at beginning of workout. Stop at end of each step. + 5: 'power_down', # stop_all group 0 + 6: 'power_up', # stop_all group 0 + 7: 'off_course', # start / stop group 0 + 8: 'session', # Stop at end of each session. + 9: 'lap', # Stop at end of each lap. + 10: 'course_point', # marker + 11: 'battery', # marker + 12: 'virtual_partner_pace', # Group 1. Start at beginning of activity if VP enabled, when VP pace is changed during activity or VP enabled mid activity. stop_disable when VP disabled. + 13: 'hr_high_alert', # Group 0. Start / stop when in alert condition. + 14: 'hr_low_alert', # Group 0. Start / stop when in alert condition. + 15: 'speed_high_alert', # Group 0. Start / stop when in alert condition. + 16: 'speed_low_alert', # Group 0. Start / stop when in alert condition. + 17: 'cad_high_alert', # Group 0. Start / stop when in alert condition. + 18: 'cad_low_alert', # Group 0. Start / stop when in alert condition. + 19: 'power_high_alert', # Group 0. Start / stop when in alert condition. + 20: 'power_low_alert', # Group 0. Start / stop when in alert condition. + 21: 'recovery_hr', # marker + 22: 'battery_low', # marker + 23: 'time_duration_alert', # Group 1. Start if enabled mid activity (not required at start of activity). Stop when duration is reached. stop_disable if disabled. + 24: 'distance_duration_alert', # Group 1. Start if enabled mid activity (not required at start of activity). Stop when duration is reached. stop_disable if disabled. + 25: 'calorie_duration_alert', # Group 1. Start if enabled mid activity (not required at start of activity). Stop when duration is reached. stop_disable if disabled. + 26: 'activity', # Group 1.. Stop at end of activity. + 27: 'fitness_equipment', # marker + 28: 'length', # Stop at end of each length. + 32: 'user_marker', # marker + 33: 'sport_point', # marker + 36: 'calibration', # start/stop/marker + 42: 'front_gear_change', # marker + 43: 'rear_gear_change', # marker + 44: 'rider_position_change', # marker + 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 + }, + ), + 'event_type': FieldType( + name='event_type', + base_type=BASE_TYPES[0x00], # enum + values={ + 0: 'start', + 1: 'stop', + 2: 'consecutive_depreciated', + 3: 'marker', + 4: 'stop_all', + 5: 'begin_depreciated', + 6: 'end_depreciated', + 7: 'end_all_depreciated', + 8: 'stop_disable', + 9: 'stop_disable_all', + }, + ), + 'exd_data_units': FieldType( + name='exd_data_units', + base_type=BASE_TYPES[0x00], # enum + values={ + 0: 'no_units', + 1: 'laps', + 2: 'miles_per_hour', + 3: 'kilometers_per_hour', + 4: 'feet_per_hour', + 5: 'meters_per_hour', + 6: 'degrees_celsius', + 7: 'degrees_farenheit', + 8: 'zone', + 9: 'gear', + 10: 'rpm', + 11: 'bpm', + 12: 'degrees', + 13: 'millimeters', + 14: 'meters', + 15: 'kilometers', + 16: 'feet', + 17: 'yards', + 18: 'kilofeet', + 19: 'miles', + 20: 'time', + 21: 'enum_turn_type', + 22: 'percent', + 23: 'watts', + 24: 'watts_per_kilogram', + 25: 'enum_battery_status', + 26: 'enum_bike_light_beam_angle_mode', + 27: 'enum_bike_light_battery_status', + 28: 'enum_bike_light_network_config_type', + 29: 'lights', + 30: 'seconds', + 31: 'minutes', + 32: 'hours', + 33: 'calories', + 34: 'kilojoules', + 35: 'milliseconds', + 36: 'second_per_mile', + 37: 'second_per_kilometer', + 38: 'centimeter', + 39: 'enum_course_point', + 40: 'bradians', + 41: 'enum_sport', + 42: 'inches_hg', + 43: 'mm_hg', + 44: 'mbars', + 45: 'hecto_pascals', + 46: 'feet_per_min', + 47: 'meters_per_min', + 48: 'meters_per_sec', + 49: 'eight_cardinal', + }, + ), + 'exd_descriptors': FieldType( + name='exd_descriptors', + base_type=BASE_TYPES[0x00], # enum + values={ + 0: 'bike_light_battery_status', + 1: 'beam_angle_status', + 2: 'batery_level', + 3: 'light_network_mode', + 4: 'number_lights_connected', + 5: 'cadence', + 6: 'distance', + 7: 'estimated_time_of_arrival', + 8: 'heading', + 9: 'time', + 10: 'battery_level', + 11: 'trainer_resistance', + 12: 'trainer_target_power', + 13: 'time_seated', + 14: 'time_standing', + 15: 'elevation', + 16: 'grade', + 17: 'ascent', + 18: 'descent', + 19: 'vertical_speed', + 20: 'di2_battery_level', + 21: 'front_gear', + 22: 'rear_gear', + 23: 'gear_ratio', + 24: 'heart_rate', + 25: 'heart_rate_zone', + 26: 'time_in_heart_rate_zone', + 27: 'heart_rate_reserve', + 28: 'calories', + 29: 'gps_accuracy', + 30: 'gps_signal_strength', + 31: 'temperature', + 32: 'time_of_day', + 33: 'balance', + 34: 'pedal_smoothness', + 35: 'power', + 36: 'functional_threshold_power', + 37: 'intensity_factor', + 38: 'work', + 39: 'power_ratio', + 40: 'normalized_power', + 41: 'training_stress_Score', + 42: 'time_on_zone', + 43: 'speed', + 44: 'laps', + 45: 'reps', + 46: 'workout_step', + 47: 'course_distance', + 48: 'navigation_distance', + 49: 'course_estimated_time_of_arrival', + 50: 'navigation_estimated_time_of_arrival', + 51: 'course_time', + 52: 'navigation_time', + 53: 'course_heading', + 54: 'navigation_heading', + 55: 'power_zone', + 56: 'torque_effectiveness', + 57: 'timer_time', + 58: 'power_weight_ratio', + 59: 'left_platform_center_offset', + 60: 'right_platform_center_offset', + 61: 'left_power_phase_start_angle', + 62: 'right_power_phase_start_angle', + 63: 'left_power_phase_finish_angle', + 64: 'right_power_phase_finish_angle', + 65: 'gears', # Combined gear information + 66: 'pace', + 67: 'training_effect', + 68: 'vertical_oscillation', + 69: 'vertical_ratio', + 70: 'ground_contact_time', + 71: 'left_ground_contact_time_balance', + 72: 'right_ground_contact_time_balance', + 73: 'stride_length', + 74: 'running_cadence', + 75: 'performance_condition', + 76: 'course_type', + 77: 'time_in_power_zone', + 78: 'navigation_turn', + 79: 'course_location', + 80: 'navigation_location', + 81: 'compass', + 82: 'gear_combo', + 83: 'muscle_oxygen', + 84: 'icon', + 85: 'compass_heading', + 86: 'gps_heading', + 87: 'gps_elevation', + 88: 'anaerobic_training_effect', + 89: 'course', + 90: 'off_course', + 91: 'glide_ratio', + 92: 'vertical_distance', + 93: 'vmg', + 94: 'ambient_pressure', + 95: 'pressure', + 96: 'vam', + }, + ), + 'exd_display_type': FieldType( + name='exd_display_type', + base_type=BASE_TYPES[0x00], # enum + values={ + 0: 'numerical', + 1: 'simple', + 2: 'graph', + 3: 'bar', + 4: 'circle_graph', + 5: 'virtual_partner', + 6: 'balance', + 7: 'string_list', + 8: 'string', + 9: 'simple_dynamic_icon', + 10: 'gauge', + }, + ), + 'exd_layout': FieldType( + name='exd_layout', + base_type=BASE_TYPES[0x00], # enum + values={ + 0: 'full_screen', + 1: 'half_vertical', + 2: 'half_horizontal', + 3: 'half_vertical_right_split', + 4: 'half_horizontal_bottom_split', + 5: 'full_quarter_split', + 6: 'half_vertical_left_split', + 7: 'half_horizontal_top_split', + }, + ), + 'exd_qualifiers': FieldType( + name='exd_qualifiers', + base_type=BASE_TYPES[0x00], # enum + values={ + 0: 'no_qualifier', + 1: 'instantaneous', + 2: 'average', + 3: 'lap', + 4: 'maximum', + 5: 'maximum_average', + 6: 'maximum_lap', + 7: 'last_lap', + 8: 'average_lap', + 9: 'to_destination', + 10: 'to_go', + 11: 'to_next', + 12: 'next_course_point', + 13: 'total', + 14: 'three_second_average', + 15: 'ten_second_average', + 16: 'thirty_second_average', + 17: 'percent_maximum', + 18: 'percent_maximum_average', + 19: 'lap_percent_maximum', + 20: 'elapsed', + 21: 'sunrise', + 22: 'sunset', + 23: 'compared_to_virtual_partner', + 24: 'maximum_24h', + 25: 'minimum_24h', + 26: 'minimum', + 27: 'first', + 28: 'second', + 29: 'third', + 30: 'shifter', + 31: 'last_sport', + 32: 'moving', + 33: 'stopped', + 34: 'estimated_total', + 242: 'zone_9', + 243: 'zone_8', + 244: 'zone_7', + 245: 'zone_6', + 246: 'zone_5', + 247: 'zone_4', + 248: 'zone_3', + 249: 'zone_2', + 250: 'zone_1', + }, + ), + 'exercise_category': FieldType( + name='exercise_category', + base_type=BASE_TYPES[0x84], # uint16 + values={ + 0: 'bench_press', + 1: 'calf_raise', + 2: 'cardio', + 3: 'carry', + 4: 'chop', + 5: 'core', + 6: 'crunch', + 7: 'curl', + 8: 'deadlift', + 9: 'flye', + 10: 'hip_raise', + 11: 'hip_stability', + 12: 'hip_swing', + 13: 'hyperextension', + 14: 'lateral_raise', + 15: 'leg_curl', + 16: 'leg_raise', + 17: 'lunge', + 18: 'olympic_lift', + 19: 'plank', + 20: 'plyo', + 21: 'pull_up', + 22: 'push_up', + 23: 'row', + 24: 'shoulder_press', + 25: 'shoulder_stability', + 26: 'shrug', + 27: 'sit_up', + 28: 'squat', + 29: 'total_body', + 30: 'triceps_extension', + 31: 'warm_up', + 32: 'run', + 65534: 'unknown', + }, + ), + 'file': FieldType( + name='file', + base_type=BASE_TYPES[0x00], # enum + values={ + 1: 'device', # Read only, single file. Must be in root directory. + 2: 'settings', # Read/write, single file. Directory=Settings + 3: 'sport', # Read/write, multiple files, file number = sport type. Directory=Sports + 4: 'activity', # Read/erase, multiple files. Directory=Activities + 5: 'workout', # Read/write/erase, multiple files. Directory=Workouts + 6: 'course', # Read/write/erase, multiple files. Directory=Courses + 7: 'schedules', # Read/write, single file. Directory=Schedules + 9: 'weight', # Read only, single file. Circular buffer. All message definitions at start of file. Directory=Weight + 10: 'totals', # Read only, single file. Directory=Totals + 11: 'goals', # Read/write, single file. Directory=Goals + 14: 'blood_pressure', # Read only. Directory=Blood Pressure + 15: 'monitoring_a', # Read only. Directory=Monitoring. File number=sub type. + 20: 'activity_summary', # Read/erase, multiple files. Directory=Activities + 28: 'monitoring_daily', + 32: 'monitoring_b', # Read only. Directory=Monitoring. File number=identifier + 34: 'segment', # Read/write/erase. Multiple Files. Directory=Segments + 35: 'segment_list', # Read/write/erase. Single File. Directory=Segments + 40: 'exd_configuration', # Read/write/erase. Single File. Directory=Settings + 0xF7: 'mfg_range_min', # 0xF7 - 0xFE reserved for manufacturer specific file types + 0xFE: 'mfg_range_max', # 0xF7 - 0xFE reserved for manufacturer specific file types + }, + ), + 'file_flags': FieldType( + name='file_flags', + base_type=BASE_TYPES[0x0A], # uint8z + values={ + 0x02: 'read', + 0x04: 'write', + 0x08: 'erase', + }, + ), + 'fit_base_type': FieldType( + name='fit_base_type', + base_type=BASE_TYPES[0x02], # uint8 + values={ + 0: 'enum', + 1: 'sint8', + 2: 'uint8', + 7: 'string', + 10: 'uint8z', + 13: 'byte', + 131: 'sint16', + 132: 'uint16', + 133: 'sint32', + 134: 'uint32', + 136: 'float32', + 137: 'float64', + 139: 'uint16z', + 140: 'uint32z', + 142: 'sint64', + 143: 'uint64', + 144: 'uint64z', + }, + ), + 'fit_base_unit': FieldType( + name='fit_base_unit', + base_type=BASE_TYPES[0x84], # uint16 + values={ + 0: 'other', + 1: 'kilogram', + 2: 'pound', + }, + ), + 'fitness_equipment_state': FieldType( # fitness equipment event data + name='fitness_equipment_state', + base_type=BASE_TYPES[0x00], # enum + values={ + 0: 'ready', + 1: 'in_use', + 2: 'paused', + 3: 'unknown', # lost connection to fitness equipment + }, + ), + 'flye_exercise_name': FieldType( + name='flye_exercise_name', + base_type=BASE_TYPES[0x84], # uint16 + values={ + 0: 'cable_crossover', + 1: 'decline_dumbbell_flye', + 2: 'dumbbell_flye', + 3: 'incline_dumbbell_flye', + 4: 'kettlebell_flye', + 5: 'kneeling_rear_flye', + 6: 'single_arm_standing_cable_reverse_flye', + 7: 'swiss_ball_dumbbell_flye', + }, + ), + 'garmin_product': FieldType( + name='garmin_product', + base_type=BASE_TYPES[0x84], # uint16 + values={ + 1: 'hrm1', + 2: 'axh01', # AXH01 HRM chipset + 3: 'axb01', + 4: 'axb02', + 5: 'hrm2ss', + 6: 'dsi_alf02', + 7: 'hrm3ss', + 8: 'hrm_run_single_byte_product_id', # hrm_run model for HRM ANT+ messaging + 9: 'bsm', # BSM model for ANT+ messaging + 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 + 14: 'fr225_single_byte_product_id', # fr225 model for HRM ANT+ messaging + 473: 'fr301_china', + 474: 'fr301_japan', + 475: 'fr301_korea', + 494: 'fr301_taiwan', + 717: 'fr405', # Forerunner 405 + 782: 'fr50', # Forerunner 50 + 987: 'fr405_japan', + 988: 'fr60', # Forerunner 60 + 1011: 'dsi_alf01', + 1018: 'fr310xt', # Forerunner 310 + 1036: 'edge500', + 1124: 'fr110', # Forerunner 110 + 1169: 'edge800', + 1199: 'edge500_taiwan', + 1213: 'edge500_japan', + 1253: 'chirp', + 1274: 'fr110_japan', + 1325: 'edge200', + 1328: 'fr910xt', + 1333: 'edge800_taiwan', + 1334: 'edge800_japan', + 1341: 'alf04', + 1345: 'fr610', + 1360: 'fr210_japan', + 1380: 'vector_ss', + 1381: 'vector_cp', + 1386: 'edge800_china', + 1387: 'edge500_china', + 1410: 'fr610_japan', + 1422: 'edge500_korea', + 1436: 'fr70', + 1446: 'fr310xt_4t', + 1461: 'amx', + 1482: 'fr10', + 1497: 'edge800_korea', + 1499: 'swim', + 1537: 'fr910xt_china', + 1551: 'fenix', + 1555: 'edge200_taiwan', + 1561: 'edge510', + 1567: 'edge810', + 1570: 'tempe', + 1600: 'fr910xt_japan', + 1623: 'fr620', + 1632: 'fr220', + 1664: 'fr910xt_korea', + 1688: 'fr10_japan', + 1721: 'edge810_japan', + 1735: 'virb_elite', + 1736: 'edge_touring', # Also Edge Touring Plus + 1742: 'edge510_japan', + 1743: 'hrm_tri', + 1752: 'hrm_run', + 1765: 'fr920xt', + 1821: 'edge510_asia', + 1822: 'edge810_china', + 1823: 'edge810_taiwan', + 1836: 'edge1000', + 1837: 'vivo_fit', + 1853: 'virb_remote', + 1885: 'vivo_ki', + 1903: 'fr15', + 1907: 'vivo_active', + 1918: 'edge510_korea', + 1928: 'fr620_japan', + 1929: 'fr620_china', + 1930: 'fr220_japan', + 1931: 'fr220_china', + 1936: 'approach_s6', + 1956: 'vivo_smart', + 1967: 'fenix2', + 1988: 'epix', + 2050: 'fenix3', + 2052: 'edge1000_taiwan', + 2053: 'edge1000_japan', + 2061: 'fr15_japan', + 2067: 'edge520', + 2070: 'edge1000_china', + 2072: 'fr620_russia', + 2073: 'fr220_russia', + 2079: 'vector_s', + 2100: 'edge1000_korea', + 2130: 'fr920xt_taiwan', + 2131: 'fr920xt_china', + 2132: 'fr920xt_japan', + 2134: 'virbx', + 2135: 'vivo_smart_apac', + 2140: 'etrex_touch', + 2147: 'edge25', + 2148: 'fr25', + 2150: 'vivo_fit2', + 2153: 'fr225', + 2156: 'fr630', + 2157: 'fr230', + 2160: 'vivo_active_apac', + 2161: 'vector_2', + 2162: 'vector_2s', + 2172: 'virbxe', + 2173: 'fr620_taiwan', + 2174: 'fr220_taiwan', + 2175: 'truswing', + 2188: 'fenix3_china', + 2189: 'fenix3_twn', + 2192: 'varia_headlight', + 2193: 'varia_taillight_old', + 2204: 'edge_explore_1000', + 2219: 'fr225_asia', + 2225: 'varia_radar_taillight', + 2226: 'varia_radar_display', + 2238: 'edge20', + 2262: 'd2_bravo', + 2266: 'approach_s20', + 2276: 'varia_remote', + 2327: 'hrm4_run', + 2337: 'vivo_active_hr', + 2347: 'vivo_smart_gps_hr', + 2348: 'vivo_smart_hr', + 2368: 'vivo_move', + 2398: 'varia_vision', + 2406: 'vivo_fit3', + 2413: 'fenix3_hr', + 2417: 'virb_ultra_30', + 2429: 'index_smart_scale', + 2431: 'fr235', + 2432: 'fenix3_chronos', + 2441: 'oregon7xx', + 2444: 'rino7xx', + 2496: 'nautix', + 2530: 'edge_820', + 2531: 'edge_explore_820', + 2544: 'fenix5s', + 2547: 'd2_bravo_titanium', + 2567: 'varia_ut800', # Varia UT 800 SW + 2593: 'running_dynamics_pod', + 2604: 'fenix5x', + 2606: 'vivo_fit_jr', + 2691: 'fr935', + 2697: 'fenix5', + 10007: 'sdm4', # SDM4 footpod + 10014: 'edge_remote', + 20119: 'training_center', + 65531: 'connectiq_simulator', + 65532: 'android_antplus_plugin', + 65534: 'connect', # Garmin Connect website + }, + ), + 'gender': FieldType( + name='gender', + base_type=BASE_TYPES[0x00], # enum + values={ + 0: 'female', + 1: 'male', + }, + ), + 'goal': FieldType( + name='goal', + base_type=BASE_TYPES[0x00], # enum + values={ + 0: 'time', + 1: 'distance', + 2: 'calories', + 3: 'frequency', + 4: 'steps', + 5: 'ascent', + 6: 'active_minutes', + }, + ), + 'goal_recurrence': FieldType( + name='goal_recurrence', + base_type=BASE_TYPES[0x00], # enum + values={ + 0: 'off', + 1: 'daily', + 2: 'weekly', + 3: 'monthly', + 4: 'yearly', + 5: 'custom', + }, + ), + 'goal_source': FieldType( + name='goal_source', + base_type=BASE_TYPES[0x00], # enum + values={ + 0: 'auto', # Device generated + 1: 'community', # Social network sourced goal + 2: 'user', # Manually generated + }, + ), + 'hip_raise_exercise_name': FieldType( + name='hip_raise_exercise_name', + base_type=BASE_TYPES[0x84], # uint16 + values={ + 0: 'barbell_hip_thrust_on_floor', + 1: 'barbell_hip_thrust_with_bench', + 2: 'bent_knee_swiss_ball_reverse_hip_raise', + 3: 'weighted_bent_knee_swiss_ball_reverse_hip_raise', + 4: 'bridge_with_leg_extension', + 5: 'weighted_bridge_with_leg_extension', + 6: 'clam_bridge', + 7: 'front_kick_tabletop', + 8: 'weighted_front_kick_tabletop', + 9: 'hip_extension_and_cross', + 10: 'weighted_hip_extension_and_cross', + 11: 'hip_raise', + 12: 'weighted_hip_raise', + 13: 'hip_raise_with_feet_on_swiss_ball', + 14: 'weighted_hip_raise_with_feet_on_swiss_ball', + 15: 'hip_raise_with_head_on_bosu_ball', + 16: 'weighted_hip_raise_with_head_on_bosu_ball', + 17: 'hip_raise_with_head_on_swiss_ball', + 18: 'weighted_hip_raise_with_head_on_swiss_ball', + 19: 'hip_raise_with_knee_squeeze', + 20: 'weighted_hip_raise_with_knee_squeeze', + 21: 'incline_rear_leg_extension', + 22: 'weighted_incline_rear_leg_extension', + 23: 'kettlebell_swing', + 24: 'marching_hip_raise', + 25: 'weighted_marching_hip_raise', + 26: 'marching_hip_raise_with_feet_on_a_swiss_ball', + 27: 'weighted_marching_hip_raise_with_feet_on_a_swiss_ball', + 28: 'reverse_hip_raise', + 29: 'weighted_reverse_hip_raise', + 30: 'single_leg_hip_raise', + 31: 'weighted_single_leg_hip_raise', + 32: 'single_leg_hip_raise_with_foot_on_bench', + 33: 'weighted_single_leg_hip_raise_with_foot_on_bench', + 34: 'single_leg_hip_raise_with_foot_on_bosu_ball', + 35: 'weighted_single_leg_hip_raise_with_foot_on_bosu_ball', + 36: 'single_leg_hip_raise_with_foot_on_foam_roller', + 37: 'weighted_single_leg_hip_raise_with_foot_on_foam_roller', + 38: 'single_leg_hip_raise_with_foot_on_medicine_ball', + 39: 'weighted_single_leg_hip_raise_with_foot_on_medicine_ball', + 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', + }, + ), + 'hip_stability_exercise_name': FieldType( + name='hip_stability_exercise_name', + base_type=BASE_TYPES[0x84], # uint16 + values={ + 0: 'band_side_lying_leg_raise', + 1: 'dead_bug', + 2: 'weighted_dead_bug', + 3: 'external_hip_raise', + 4: 'weighted_external_hip_raise', + 5: 'fire_hydrant_kicks', + 6: 'weighted_fire_hydrant_kicks', + 7: 'hip_circles', + 8: 'weighted_hip_circles', + 9: 'inner_thigh_lift', + 10: 'weighted_inner_thigh_lift', + 11: 'lateral_walks_with_band_at_ankles', + 12: 'pretzel_side_kick', + 13: 'weighted_pretzel_side_kick', + 14: 'prone_hip_internal_rotation', + 15: 'weighted_prone_hip_internal_rotation', + 16: 'quadruped', + 17: 'quadruped_hip_extension', + 18: 'weighted_quadruped_hip_extension', + 19: 'quadruped_with_leg_lift', + 20: 'weighted_quadruped_with_leg_lift', + 21: 'side_lying_leg_raise', + 22: 'weighted_side_lying_leg_raise', + 23: 'sliding_hip_adduction', + 24: 'weighted_sliding_hip_adduction', + 25: 'standing_adduction', + 26: 'weighted_standing_adduction', + 27: 'standing_cable_hip_abduction', + 28: 'standing_hip_abduction', + 29: 'weighted_standing_hip_abduction', + 30: 'standing_rear_leg_raise', + 31: 'weighted_standing_rear_leg_raise', + 32: 'supine_hip_internal_rotation', + 33: 'weighted_supine_hip_internal_rotation', + }, + ), + 'hip_swing_exercise_name': FieldType( + name='hip_swing_exercise_name', + base_type=BASE_TYPES[0x84], # uint16 + values={ + 0: 'single_arm_kettlebell_swing', + 1: 'single_arm_dumbbell_swing', + 2: 'step_out_swing', + }, + ), + 'hr_type': FieldType( + name='hr_type', + base_type=BASE_TYPES[0x00], # enum + values={ + 0: 'normal', + 1: 'irregular', + }, + ), + 'hr_zone_calc': FieldType( + name='hr_zone_calc', + base_type=BASE_TYPES[0x00], # enum + values={ + 0: 'custom', + 1: 'percent_max_hr', + 2: 'percent_hrr', + }, + ), + 'hyperextension_exercise_name': FieldType( + name='hyperextension_exercise_name', + base_type=BASE_TYPES[0x84], # uint16 + values={ + 0: 'back_extension_with_opposite_arm_and_leg_reach', + 1: 'weighted_back_extension_with_opposite_arm_and_leg_reach', + 2: 'base_rotations', + 3: 'weighted_base_rotations', + 4: 'bent_knee_reverse_hyperextension', + 5: 'weighted_bent_knee_reverse_hyperextension', + 6: 'hollow_hold_and_roll', + 7: 'weighted_hollow_hold_and_roll', + 8: 'kicks', + 9: 'weighted_kicks', + 10: 'knee_raises', + 11: 'weighted_knee_raises', + 12: 'kneeling_superman', + 13: 'weighted_kneeling_superman', + 14: 'lat_pull_down_with_row', + 15: 'medicine_ball_deadlift_to_reach', + 16: 'one_arm_one_leg_row', + 17: 'one_arm_row_with_band', + 18: 'overhead_lunge_with_medicine_ball', + 19: 'plank_knee_tucks', + 20: 'weighted_plank_knee_tucks', + 21: 'side_step', + 22: 'weighted_side_step', + 23: 'single_leg_back_extension', + 24: 'weighted_single_leg_back_extension', + 25: 'spine_extension', + 26: 'weighted_spine_extension', + 27: 'static_back_extension', + 28: 'weighted_static_back_extension', + 29: 'superman_from_floor', + 30: 'weighted_superman_from_floor', + 31: 'swiss_ball_back_extension', + 32: 'weighted_swiss_ball_back_extension', + 33: 'swiss_ball_hyperextension', + 34: 'weighted_swiss_ball_hyperextension', + 35: 'swiss_ball_opposite_arm_and_leg_lift', + 36: 'weighted_swiss_ball_opposite_arm_and_leg_lift', + }, + ), + 'intensity': FieldType( + name='intensity', + base_type=BASE_TYPES[0x00], # enum + values={ + 0: 'active', + 1: 'rest', + 2: 'warmup', + 3: 'cooldown', + }, + ), + 'language': FieldType( + name='language', + base_type=BASE_TYPES[0x00], # enum + values={ + 0: 'english', + 1: 'french', + 2: 'italian', + 3: 'german', + 4: 'spanish', + 5: 'croatian', + 6: 'czech', + 7: 'danish', + 8: 'dutch', + 9: 'finnish', + 10: 'greek', + 11: 'hungarian', + 12: 'norwegian', + 13: 'polish', + 14: 'portuguese', + 15: 'slovakian', + 16: 'slovenian', + 17: 'swedish', + 18: 'russian', + 19: 'turkish', + 20: 'latvian', + 21: 'ukrainian', + 22: 'arabic', + 23: 'farsi', + 24: 'bulgarian', + 25: 'romanian', + 26: 'chinese', + 27: 'japanese', + 28: 'korean', + 29: 'taiwanese', + 30: 'thai', + 31: 'hebrew', + 32: 'brazilian_portuguese', + 33: 'indonesian', + 34: 'malaysian', + 35: 'vietnamese', + 36: 'burmese', + 37: 'mongolian', + 254: 'custom', + }, + ), + 'language_bits_0': FieldType( # Bit field corresponding to language enum type (1 << language). + name='language_bits_0', + base_type=BASE_TYPES[0x0A], # uint8z + values={ + 0x01: 'english', + 0x02: 'french', + 0x04: 'italian', + 0x08: 'german', + 0x10: 'spanish', + 0x20: 'croatian', + 0x40: 'czech', + 0x80: 'danish', + }, + ), + 'language_bits_1': FieldType( + name='language_bits_1', + base_type=BASE_TYPES[0x0A], # uint8z + values={ + 0x01: 'dutch', + 0x02: 'finnish', + 0x04: 'greek', + 0x08: 'hungarian', + 0x10: 'norwegian', + 0x20: 'polish', + 0x40: 'portuguese', + 0x80: 'slovakian', + }, + ), + 'language_bits_2': FieldType( + name='language_bits_2', + base_type=BASE_TYPES[0x0A], # uint8z + values={ + 0x01: 'slovenian', + 0x02: 'swedish', + 0x04: 'russian', + 0x08: 'turkish', + 0x10: 'latvian', + 0x20: 'ukrainian', + 0x40: 'arabic', + 0x80: 'farsi', + }, + ), + 'language_bits_3': FieldType( + name='language_bits_3', + base_type=BASE_TYPES[0x0A], # uint8z + values={ + 0x01: 'bulgarian', + 0x02: 'romanian', + 0x04: 'chinese', + 0x08: 'japanese', + 0x10: 'korean', + 0x20: 'taiwanese', + 0x40: 'thai', + 0x80: 'hebrew', + }, + ), + 'language_bits_4': FieldType( + name='language_bits_4', + base_type=BASE_TYPES[0x0A], # uint8z + values={ + 0x01: 'brazilian_portuguese', + 0x02: 'indonesian', + 0x04: 'malaysian', + 0x08: 'vietnamese', + 0x10: 'burmese', + 0x20: 'mongolian', + }, + ), + 'lap_trigger': FieldType( + name='lap_trigger', + base_type=BASE_TYPES[0x00], # enum + values={ + 0: 'manual', + 1: 'time', + 2: 'distance', + 3: 'position_start', + 4: 'position_lap', + 5: 'position_waypoint', + 6: 'position_marked', + 7: 'session_end', + 8: 'fitness_equipment', + }, + ), + 'lateral_raise_exercise_name': FieldType( + name='lateral_raise_exercise_name', + base_type=BASE_TYPES[0x84], # uint16 + values={ + 0: '45_degree_cable_external_rotation', + 1: 'alternating_lateral_raise_with_static_hold', + 2: 'bar_muscle_up', + 3: 'bent_over_lateral_raise', + 4: 'cable_diagonal_raise', + 5: 'cable_front_raise', + 6: 'calorie_row', + 7: 'combo_shoulder_raise', + 8: 'dumbbell_diagonal_raise', + 9: 'dumbbell_v_raise', + 10: 'front_raise', + 11: 'leaning_dumbbell_lateral_raise', + 12: 'lying_dumbbell_raise', + 13: 'muscle_up', + 14: 'one_arm_cable_lateral_raise', + 15: 'overhand_grip_rear_lateral_raise', + 16: 'plate_raises', + 17: 'ring_dip', + 18: 'weighted_ring_dip', + 19: 'ring_muscle_up', + 20: 'weighted_ring_muscle_up', + 21: 'rope_climb', + 22: 'weighted_rope_climb', + 23: 'scaption', + 24: 'seated_lateral_raise', + 25: 'seated_rear_lateral_raise', + 26: 'side_lying_lateral_raise', + 27: 'standing_lift', + 28: 'suspended_row', + 29: 'underhand_grip_rear_lateral_raise', + 30: 'wall_slide', + 31: 'weighted_wall_slide', + }, + ), + 'left_right_balance': FieldType( + name='left_right_balance', + base_type=BASE_TYPES[0x02], # uint8 + values={ + 0x7F: 'mask', # % contribution + 0x80: 'right', # data corresponds to right if set, otherwise unknown + }, + ), + 'left_right_balance_100': FieldType( + name='left_right_balance_100', + base_type=BASE_TYPES[0x84], # uint16 + values={ + 0x3FFF: 'mask', # % contribution scaled by 100 + 0x8000: 'right', # data corresponds to right if set, otherwise unknown + }, + ), + 'leg_curl_exercise_name': FieldType( + name='leg_curl_exercise_name', + base_type=BASE_TYPES[0x84], # uint16 + values={ + 0: 'leg_curl', + 1: 'weighted_leg_curl', + 2: 'good_morning', + 3: 'seated_barbell_good_morning', + 4: 'single_leg_barbell_good_morning', + 5: 'single_leg_sliding_leg_curl', + 6: 'sliding_leg_curl', + 7: 'split_barbell_good_morning', + 8: 'split_stance_extension', + 9: 'staggered_stance_good_morning', + 10: 'swiss_ball_hip_raise_and_leg_curl', + 11: 'zercher_good_morning', + }, + ), + 'leg_raise_exercise_name': FieldType( + name='leg_raise_exercise_name', + base_type=BASE_TYPES[0x84], # uint16 + values={ + 0: 'hanging_knee_raise', + 1: 'hanging_leg_raise', + 2: 'weighted_hanging_leg_raise', + 3: 'hanging_single_leg_raise', + 4: 'weighted_hanging_single_leg_raise', + 5: 'kettlebell_leg_raises', + 6: 'leg_lowering_drill', + 7: 'weighted_leg_lowering_drill', + 8: 'lying_straight_leg_raise', + 9: 'weighted_lying_straight_leg_raise', + 10: 'medicine_ball_leg_drops', + 11: 'quadruped_leg_raise', + 12: 'weighted_quadruped_leg_raise', + 13: 'reverse_leg_raise', + 14: 'weighted_reverse_leg_raise', + 15: 'reverse_leg_raise_on_swiss_ball', + 16: 'weighted_reverse_leg_raise_on_swiss_ball', + 17: 'single_leg_lowering_drill', + 18: 'weighted_single_leg_lowering_drill', + 19: 'weighted_hanging_knee_raise', + 20: 'lateral_stepover', + 21: 'weighted_lateral_stepover', + }, + ), + 'length_type': FieldType( + name='length_type', + base_type=BASE_TYPES[0x00], # enum + values={ + 0: 'idle', # Rest period. Length with no strokes + 1: 'active', # Length with strokes. + }, + ), + 'local_date_time': FieldType( # seconds since 00:00 Dec 31 1989 in local time zone + name='local_date_time', + base_type=BASE_TYPES[0x86], # uint32 + values={ + 0x10000000: 'min', # if date_time is < 0x10000000 then it is system time (seconds from device power on) + }, + ), + 'local_device_type': FieldType( + name='local_device_type', + base_type=BASE_TYPES[0x02], # uint8 + ), + 'localtime_into_day': FieldType( # number of seconds into the day since local 00:00:00 + name='localtime_into_day', + base_type=BASE_TYPES[0x86], # uint32 + ), + 'lunge_exercise_name': FieldType( + name='lunge_exercise_name', + base_type=BASE_TYPES[0x84], # uint16 + values={ + 0: 'overhead_lunge', + 1: 'lunge_matrix', + 2: 'weighted_lunge_matrix', + 3: 'alternating_barbell_forward_lunge', + 4: 'alternating_dumbbell_lunge_with_reach', + 5: 'back_foot_elevated_dumbbell_split_squat', + 6: 'barbell_box_lunge', + 7: 'barbell_bulgarian_split_squat', + 8: 'barbell_crossover_lunge', + 9: 'barbell_front_split_squat', + 10: 'barbell_lunge', + 11: 'barbell_reverse_lunge', + 12: 'barbell_side_lunge', + 13: 'barbell_split_squat', + 14: 'core_control_rear_lunge', + 15: 'diagonal_lunge', + 16: 'drop_lunge', + 17: 'dumbbell_box_lunge', + 18: 'dumbbell_bulgarian_split_squat', + 19: 'dumbbell_crossover_lunge', + 20: 'dumbbell_diagonal_lunge', + 21: 'dumbbell_lunge', + 22: 'dumbbell_lunge_and_rotation', + 23: 'dumbbell_overhead_bulgarian_split_squat', + 24: 'dumbbell_reverse_lunge_to_high_knee_and_press', + 25: 'dumbbell_side_lunge', + 26: 'elevated_front_foot_barbell_split_squat', + 27: 'front_foot_elevated_dumbbell_split_squat', + 28: 'gunslinger_lunge', + 29: 'lawnmower_lunge', + 30: 'low_lunge_with_isometric_adduction', + 31: 'low_side_to_side_lunge', + 32: 'lunge', + 33: 'weighted_lunge', + 34: 'lunge_with_arm_reach', + 35: 'lunge_with_diagonal_reach', + 36: 'lunge_with_side_bend', + 37: 'offset_dumbbell_lunge', + 38: 'offset_dumbbell_reverse_lunge', + 39: 'overhead_bulgarian_split_squat', + 40: 'overhead_dumbbell_reverse_lunge', + 41: 'overhead_dumbbell_split_squat', + 42: 'overhead_lunge_with_rotation', + 43: 'reverse_barbell_box_lunge', + 44: 'reverse_box_lunge', + 45: 'reverse_dumbbell_box_lunge', + 46: 'reverse_dumbbell_crossover_lunge', + 47: 'reverse_dumbbell_diagonal_lunge', + 48: 'reverse_lunge_with_reach_back', + 49: 'weighted_reverse_lunge_with_reach_back', + 50: 'reverse_lunge_with_twist_and_overhead_reach', + 51: 'weighted_reverse_lunge_with_twist_and_overhead_reach', + 52: 'reverse_sliding_box_lunge', + 53: 'weighted_reverse_sliding_box_lunge', + 54: 'reverse_sliding_lunge', + 55: 'weighted_reverse_sliding_lunge', + 56: 'runners_lunge_to_balance', + 57: 'weighted_runners_lunge_to_balance', + 58: 'shifting_side_lunge', + 59: 'side_and_crossover_lunge', + 60: 'weighted_side_and_crossover_lunge', + 61: 'side_lunge', + 62: 'weighted_side_lunge', + 63: 'side_lunge_and_press', + 64: 'side_lunge_jump_off', + 65: 'side_lunge_sweep', + 66: 'weighted_side_lunge_sweep', + 67: 'side_lunge_to_crossover_tap', + 68: 'weighted_side_lunge_to_crossover_tap', + 69: 'side_to_side_lunge_chops', + 70: 'weighted_side_to_side_lunge_chops', + 71: 'siff_jump_lunge', + 72: 'weighted_siff_jump_lunge', + 73: 'single_arm_reverse_lunge_and_press', + 74: 'sliding_lateral_lunge', + 75: 'weighted_sliding_lateral_lunge', + 76: 'walking_barbell_lunge', + 77: 'walking_dumbbell_lunge', + 78: 'walking_lunge', + 79: 'weighted_walking_lunge', + 80: 'wide_grip_overhead_barbell_split_squat', + }, + ), + 'manufacturer': FieldType( + name='manufacturer', + base_type=BASE_TYPES[0x84], # uint16 + values={ + 1: 'garmin', + 2: 'garmin_fr405_antfs', # Do not use. Used by FR405 for ANTFS man id. + 3: 'zephyr', + 4: 'dayton', + 5: 'idt', + 6: 'srm', + 7: 'quarq', + 8: 'ibike', + 9: 'saris', + 10: 'spark_hk', + 11: 'tanita', + 12: 'echowell', + 13: 'dynastream_oem', + 14: 'nautilus', + 15: 'dynastream', + 16: 'timex', + 17: 'metrigear', + 18: 'xelic', + 19: 'beurer', + 20: 'cardiosport', + 21: 'a_and_d', + 22: 'hmm', + 23: 'suunto', + 24: 'thita_elektronik', + 25: 'gpulse', + 26: 'clean_mobile', + 27: 'pedal_brain', + 28: 'peaksware', + 29: 'saxonar', + 30: 'lemond_fitness', + 31: 'dexcom', + 32: 'wahoo_fitness', + 33: 'octane_fitness', + 34: 'archinoetics', + 35: 'the_hurt_box', + 36: 'citizen_systems', + 37: 'magellan', + 38: 'osynce', + 39: 'holux', + 40: 'concept2', + 42: 'one_giant_leap', + 43: 'ace_sensor', + 44: 'brim_brothers', + 45: 'xplova', + 46: 'perception_digital', + 47: 'bf1systems', + 48: 'pioneer', + 49: 'spantec', + 50: 'metalogics', + 51: '4iiiis', + 52: 'seiko_epson', + 53: 'seiko_epson_oem', + 54: 'ifor_powell', + 55: 'maxwell_guider', + 56: 'star_trac', + 57: 'breakaway', + 58: 'alatech_technology_ltd', + 59: 'mio_technology_europe', + 60: 'rotor', + 61: 'geonaute', + 62: 'id_bike', + 63: 'specialized', + 64: 'wtek', + 65: 'physical_enterprises', + 66: 'north_pole_engineering', + 67: 'bkool', + 68: 'cateye', + 69: 'stages_cycling', + 70: 'sigmasport', + 71: 'tomtom', + 72: 'peripedal', + 73: 'wattbike', + 76: 'moxy', + 77: 'ciclosport', + 78: 'powerbahn', + 79: 'acorn_projects_aps', + 80: 'lifebeam', + 81: 'bontrager', + 82: 'wellgo', + 83: 'scosche', + 84: 'magura', + 85: 'woodway', + 86: 'elite', + 87: 'nielsen_kellerman', + 88: 'dk_city', + 89: 'tacx', + 90: 'direction_technology', + 91: 'magtonic', + 92: '1partcarbon', + 93: 'inside_ride_technologies', + 94: 'sound_of_motion', + 95: 'stryd', + 96: 'icg', # Indoorcycling Group + 97: 'MiPulse', + 98: 'bsx_athletics', + 99: 'look', + 100: 'campagnolo_srl', + 101: 'body_bike_smart', + 102: 'praxisworks', + 103: 'limits_technology', # Limits Technology Ltd. + 104: 'topaction_technology', # TopAction Technology Inc. + 105: 'cosinuss', + 106: 'fitcare', + 107: 'magene', + 108: 'giant_manufacturing_co', + 109: 'tigrasport', # Tigrasport + 110: 'salutron', + 111: 'technogym', + 112: 'bryton_sensors', + 113: 'latitude_limited', + 114: 'soaring_technology', + 115: 'igpsport', + 116: 'thinkrider', + 117: 'gopher_sport', + 118: 'waterrower', + 119: 'orangetheory', + 120: 'inpeak', + 121: 'kinetic', + 122: 'johnson_health_tech', + 123: 'polar_electro', + 124: 'seesense', + 255: 'development', + 257: 'healthandlife', + 258: 'lezyne', + 259: 'scribe_labs', + 260: 'zwift', + 261: 'watteam', + 262: 'recon', + 263: 'favero_electronics', + 264: 'dynovelo', + 265: 'strava', + 266: 'precor', # Amer Sports + 267: 'bryton', + 268: 'sram', + 269: 'navman', # MiTAC Global Corporation (Mio Technology) + 270: 'cobi', # COBI GmbH + 271: 'spivi', + 272: 'mio_magellan', + 273: 'evesports', + 274: 'sensitivus_gauge', + 275: 'podoon', + 276: 'life_time_fitness', + 277: 'falco_e_motors', # Falco eMotors Inc. + 278: 'minoura', + 279: 'cycliq', + 280: 'luxottica', + 281: 'trainer_road', + 282: 'the_sufferfest', + 283: 'fullspeedahead', + 284: 'virtualtraining', + 285: 'feedbacksports', + 286: 'omata', + 287: 'vdo', + 288: 'magneticdays', + 289: 'hammerhead', + 290: 'kinetic_by_kurt', + 291: 'shapelog', + 292: 'dabuziduo', + 293: 'jetblack', + 5759: 'actigraphcorp', + }, + ), + 'mesg_count': FieldType( + name='mesg_count', + base_type=BASE_TYPES[0x00], # enum + values={ + 0: 'num_per_file', + 1: 'max_per_file', + 2: 'max_per_file_type', + }, + ), + 'mesg_num': FieldType( + name='mesg_num', + base_type=BASE_TYPES[0x84], # uint16 + values={ + 0: 'file_id', + 1: 'capabilities', + 2: 'device_settings', + 3: 'user_profile', + 4: 'hrm_profile', + 5: 'sdm_profile', + 6: 'bike_profile', + 7: 'zones_target', + 8: 'hr_zone', + 9: 'power_zone', + 10: 'met_zone', + 12: 'sport', + 15: 'goal', + 18: 'session', + 19: 'lap', + 20: 'record', + 21: 'event', + 23: 'device_info', + 26: 'workout', + 27: 'workout_step', + 28: 'schedule', + 30: 'weight_scale', + 31: 'course', + 32: 'course_point', + 33: 'totals', + 34: 'activity', + 35: 'software', + 37: 'file_capabilities', + 38: 'mesg_capabilities', + 39: 'field_capabilities', + 49: 'file_creator', + 51: 'blood_pressure', + 53: 'speed_zone', + 55: 'monitoring', + 72: 'training_file', + 78: 'hrv', + 80: 'ant_rx', + 81: 'ant_tx', + 82: 'ant_channel_id', + 101: 'length', + 103: 'monitoring_info', + 105: 'pad', + 106: 'slave_device', + 127: 'connectivity', + 128: 'weather_conditions', + 129: 'weather_alert', + 131: 'cadence_zone', + 132: 'hr', + 142: 'segment_lap', + 145: 'memo_glob', + 148: 'segment_id', + 149: 'segment_leaderboard_entry', + 150: 'segment_point', + 151: 'segment_file', + 158: 'workout_session', + 159: 'watchface_settings', + 160: 'gps_metadata', + 161: 'camera_event', + 162: 'timestamp_correlation', + 164: 'gyroscope_data', + 165: 'accelerometer_data', + 167: 'three_d_sensor_calibration', + 169: 'video_frame', + 174: 'obdii_data', + 177: 'nmea_sentence', + 178: 'aviation_attitude', + 184: 'video', + 185: 'video_title', + 186: 'video_description', + 187: 'video_clip', + 188: 'ohr_settings', + 200: 'exd_screen_configuration', + 201: 'exd_data_field_configuration', + 202: 'exd_data_concept_configuration', + 206: 'field_description', + 207: 'developer_data_id', + 208: 'magnetometer_data', + 209: 'barometer_data', + 210: 'one_d_sensor_calibration', + 225: 'set', + 227: 'stress_level', + 258: 'dive_settings', + 259: 'dive_gas', + 262: 'dive_alarm', + 264: 'exercise_title', + 268: 'dive_summary', + }, + ), + 'message_index': FieldType( + name='message_index', + base_type=BASE_TYPES[0x84], # uint16 + values={ + 0x0FFF: 'mask', # index + 0x7000: 'reserved', # reserved (default 0) + 0x8000: 'selected', # message is selected if set + }, + ), + 'olympic_lift_exercise_name': FieldType( + name='olympic_lift_exercise_name', + base_type=BASE_TYPES[0x84], # uint16 + values={ + 0: 'barbell_hang_power_clean', + 1: 'barbell_hang_squat_clean', + 2: 'barbell_power_clean', + 3: 'barbell_power_snatch', + 4: 'barbell_squat_clean', + 5: 'clean_and_jerk', + 6: 'barbell_hang_power_snatch', + 7: 'barbell_hang_pull', + 8: 'barbell_high_pull', + 9: 'barbell_snatch', + 10: 'barbell_split_jerk', + 11: 'clean', + 12: 'dumbbell_clean', + 13: 'dumbbell_hang_pull', + 14: 'one_hand_dumbbell_split_snatch', + 15: 'push_jerk', + 16: 'single_arm_dumbbell_snatch', + 17: 'single_arm_hang_snatch', + 18: 'single_arm_kettlebell_snatch', + 19: 'split_jerk', + 20: 'squat_clean_and_jerk', + }, + ), + 'plank_exercise_name': FieldType( + name='plank_exercise_name', + base_type=BASE_TYPES[0x84], # uint16 + values={ + 0: '45_degree_plank', + 1: 'weighted_45_degree_plank', + 2: '90_degree_static_hold', + 3: 'weighted_90_degree_static_hold', + 4: 'bear_crawl', + 5: 'weighted_bear_crawl', + 6: 'cross_body_mountain_climber', + 7: 'weighted_cross_body_mountain_climber', + 8: 'elbow_plank_pike_jacks', + 9: 'weighted_elbow_plank_pike_jacks', + 10: 'elevated_feet_plank', + 11: 'weighted_elevated_feet_plank', + 12: 'elevator_abs', + 13: 'weighted_elevator_abs', + 14: 'extended_plank', + 15: 'weighted_extended_plank', + 16: 'full_plank_passe_twist', + 17: 'weighted_full_plank_passe_twist', + 18: 'inching_elbow_plank', + 19: 'weighted_inching_elbow_plank', + 20: 'inchworm_to_side_plank', + 21: 'weighted_inchworm_to_side_plank', + 22: 'kneeling_plank', + 23: 'weighted_kneeling_plank', + 24: 'kneeling_side_plank_with_leg_lift', + 25: 'weighted_kneeling_side_plank_with_leg_lift', + 26: 'lateral_roll', + 27: 'weighted_lateral_roll', + 28: 'lying_reverse_plank', + 29: 'weighted_lying_reverse_plank', + 30: 'medicine_ball_mountain_climber', + 31: 'weighted_medicine_ball_mountain_climber', + 32: 'modified_mountain_climber_and_extension', + 33: 'weighted_modified_mountain_climber_and_extension', + 34: 'mountain_climber', + 35: 'weighted_mountain_climber', + 36: 'mountain_climber_on_sliding_discs', + 37: 'weighted_mountain_climber_on_sliding_discs', + 38: 'mountain_climber_with_feet_on_bosu_ball', + 39: 'weighted_mountain_climber_with_feet_on_bosu_ball', + 40: 'mountain_climber_with_hands_on_bench', + 41: 'mountain_climber_with_hands_on_swiss_ball', + 42: 'weighted_mountain_climber_with_hands_on_swiss_ball', + 43: 'plank', + 44: 'plank_jacks_with_feet_on_sliding_discs', + 45: 'weighted_plank_jacks_with_feet_on_sliding_discs', + 46: 'plank_knee_twist', + 47: 'weighted_plank_knee_twist', + 48: 'plank_pike_jumps', + 49: 'weighted_plank_pike_jumps', + 50: 'plank_pikes', + 51: 'weighted_plank_pikes', + 52: 'plank_to_stand_up', + 53: 'weighted_plank_to_stand_up', + 54: 'plank_with_arm_raise', + 55: 'weighted_plank_with_arm_raise', + 56: 'plank_with_knee_to_elbow', + 57: 'weighted_plank_with_knee_to_elbow', + 58: 'plank_with_oblique_crunch', + 59: 'weighted_plank_with_oblique_crunch', + 60: 'plyometric_side_plank', + 61: 'weighted_plyometric_side_plank', + 62: 'rolling_side_plank', + 63: 'weighted_rolling_side_plank', + 64: 'side_kick_plank', + 65: 'weighted_side_kick_plank', + 66: 'side_plank', + 67: 'weighted_side_plank', + 68: 'side_plank_and_row', + 69: 'weighted_side_plank_and_row', + 70: 'side_plank_lift', + 71: 'weighted_side_plank_lift', + 72: 'side_plank_with_elbow_on_bosu_ball', + 73: 'weighted_side_plank_with_elbow_on_bosu_ball', + 74: 'side_plank_with_feet_on_bench', + 75: 'weighted_side_plank_with_feet_on_bench', + 76: 'side_plank_with_knee_circle', + 77: 'weighted_side_plank_with_knee_circle', + 78: 'side_plank_with_knee_tuck', + 79: 'weighted_side_plank_with_knee_tuck', + 80: 'side_plank_with_leg_lift', + 81: 'weighted_side_plank_with_leg_lift', + 82: 'side_plank_with_reach_under', + 83: 'weighted_side_plank_with_reach_under', + 84: 'single_leg_elevated_feet_plank', + 85: 'weighted_single_leg_elevated_feet_plank', + 86: 'single_leg_flex_and_extend', + 87: 'weighted_single_leg_flex_and_extend', + 88: 'single_leg_side_plank', + 89: 'weighted_single_leg_side_plank', + 90: 'spiderman_plank', + 91: 'weighted_spiderman_plank', + 92: 'straight_arm_plank', + 93: 'weighted_straight_arm_plank', + 94: 'straight_arm_plank_with_shoulder_touch', + 95: 'weighted_straight_arm_plank_with_shoulder_touch', + 96: 'swiss_ball_plank', + 97: 'weighted_swiss_ball_plank', + 98: 'swiss_ball_plank_leg_lift', + 99: 'weighted_swiss_ball_plank_leg_lift', + 100: 'swiss_ball_plank_leg_lift_and_hold', + 101: 'swiss_ball_plank_with_feet_on_bench', + 102: 'weighted_swiss_ball_plank_with_feet_on_bench', + 103: 'swiss_ball_prone_jackknife', + 104: 'weighted_swiss_ball_prone_jackknife', + 105: 'swiss_ball_side_plank', + 106: 'weighted_swiss_ball_side_plank', + 107: 'three_way_plank', + 108: 'weighted_three_way_plank', + 109: 'towel_plank_and_knee_in', + 110: 'weighted_towel_plank_and_knee_in', + 111: 't_stabilization', + 112: 'weighted_t_stabilization', + 113: 'turkish_get_up_to_side_plank', + 114: 'weighted_turkish_get_up_to_side_plank', + 115: 'two_point_plank', + 116: 'weighted_two_point_plank', + 117: 'weighted_plank', + 118: 'wide_stance_plank_with_diagonal_arm_lift', + 119: 'weighted_wide_stance_plank_with_diagonal_arm_lift', + 120: 'wide_stance_plank_with_diagonal_leg_lift', + 121: 'weighted_wide_stance_plank_with_diagonal_leg_lift', + 122: 'wide_stance_plank_with_leg_lift', + 123: 'weighted_wide_stance_plank_with_leg_lift', + 124: 'wide_stance_plank_with_opposite_arm_and_leg_lift', + 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', + }, + ), + 'plyo_exercise_name': FieldType( + name='plyo_exercise_name', + base_type=BASE_TYPES[0x84], # uint16 + values={ + 0: 'alternating_jump_lunge', + 1: 'weighted_alternating_jump_lunge', + 2: 'barbell_jump_squat', + 3: 'body_weight_jump_squat', + 4: 'weighted_jump_squat', + 5: 'cross_knee_strike', + 6: 'weighted_cross_knee_strike', + 7: 'depth_jump', + 8: 'weighted_depth_jump', + 9: 'dumbbell_jump_squat', + 10: 'dumbbell_split_jump', + 11: 'front_knee_strike', + 12: 'weighted_front_knee_strike', + 13: 'high_box_jump', + 14: 'weighted_high_box_jump', + 15: 'isometric_explosive_body_weight_jump_squat', + 16: 'weighted_isometric_explosive_jump_squat', + 17: 'lateral_leap_and_hop', + 18: 'weighted_lateral_leap_and_hop', + 19: 'lateral_plyo_squats', + 20: 'weighted_lateral_plyo_squats', + 21: 'lateral_slide', + 22: 'weighted_lateral_slide', + 23: 'medicine_ball_overhead_throws', + 24: 'medicine_ball_side_throw', + 25: 'medicine_ball_slam', + 26: 'side_to_side_medicine_ball_throws', + 27: 'side_to_side_shuffle_jump', + 28: 'weighted_side_to_side_shuffle_jump', + 29: 'squat_jump_onto_box', + 30: 'weighted_squat_jump_onto_box', + 31: 'squat_jumps_in_and_out', + 32: 'weighted_squat_jumps_in_and_out', + }, + ), + 'power_phase_type': FieldType( + name='power_phase_type', + base_type=BASE_TYPES[0x00], # enum + values={ + 0: 'power_phase_start_angle', + 1: 'power_phase_end_angle', + 2: 'power_phase_arc_length', + 3: 'power_phase_center', + }, + ), + 'pull_up_exercise_name': FieldType( + name='pull_up_exercise_name', + base_type=BASE_TYPES[0x84], # uint16 + values={ + 0: 'banded_pull_ups', + 1: '30_degree_lat_pulldown', + 2: 'band_assisted_chin_up', + 3: 'close_grip_chin_up', + 4: 'weighted_close_grip_chin_up', + 5: 'close_grip_lat_pulldown', + 6: 'crossover_chin_up', + 7: 'weighted_crossover_chin_up', + 8: 'ez_bar_pullover', + 9: 'hanging_hurdle', + 10: 'weighted_hanging_hurdle', + 11: 'kneeling_lat_pulldown', + 12: 'kneeling_underhand_grip_lat_pulldown', + 13: 'lat_pulldown', + 14: 'mixed_grip_chin_up', + 15: 'weighted_mixed_grip_chin_up', + 16: 'mixed_grip_pull_up', + 17: 'weighted_mixed_grip_pull_up', + 18: 'reverse_grip_pulldown', + 19: 'standing_cable_pullover', + 20: 'straight_arm_pulldown', + 21: 'swiss_ball_ez_bar_pullover', + 22: 'towel_pull_up', + 23: 'weighted_towel_pull_up', + 24: 'weighted_pull_up', + 25: 'wide_grip_lat_pulldown', + 26: 'wide_grip_pull_up', + 27: 'weighted_wide_grip_pull_up', + 28: 'burpee_pull_up', + 29: 'weighted_burpee_pull_up', + 30: 'jumping_pull_ups', + 31: 'weighted_jumping_pull_ups', + 32: 'kipping_pull_up', + 33: 'weighted_kipping_pull_up', + 34: 'l_pull_up', + 35: 'weighted_l_pull_up', + 36: 'suspended_chin_up', + 37: 'weighted_suspended_chin_up', + 38: 'pull_up', + }, + ), + 'push_up_exercise_name': FieldType( + name='push_up_exercise_name', + base_type=BASE_TYPES[0x84], # uint16 + values={ + 0: 'chest_press_with_band', + 1: 'alternating_staggered_push_up', + 2: 'weighted_alternating_staggered_push_up', + 3: 'alternating_hands_medicine_ball_push_up', + 4: 'weighted_alternating_hands_medicine_ball_push_up', + 5: 'bosu_ball_push_up', + 6: 'weighted_bosu_ball_push_up', + 7: 'clapping_push_up', + 8: 'weighted_clapping_push_up', + 9: 'close_grip_medicine_ball_push_up', + 10: 'weighted_close_grip_medicine_ball_push_up', + 11: 'close_hands_push_up', + 12: 'weighted_close_hands_push_up', + 13: 'decline_push_up', + 14: 'weighted_decline_push_up', + 15: 'diamond_push_up', + 16: 'weighted_diamond_push_up', + 17: 'explosive_crossover_push_up', + 18: 'weighted_explosive_crossover_push_up', + 19: 'explosive_push_up', + 20: 'weighted_explosive_push_up', + 21: 'feet_elevated_side_to_side_push_up', + 22: 'weighted_feet_elevated_side_to_side_push_up', + 23: 'hand_release_push_up', + 24: 'weighted_hand_release_push_up', + 25: 'handstand_push_up', + 26: 'weighted_handstand_push_up', + 27: 'incline_push_up', + 28: 'weighted_incline_push_up', + 29: 'isometric_explosive_push_up', + 30: 'weighted_isometric_explosive_push_up', + 31: 'judo_push_up', + 32: 'weighted_judo_push_up', + 33: 'kneeling_push_up', + 34: 'weighted_kneeling_push_up', + 35: 'medicine_ball_chest_pass', + 36: 'medicine_ball_push_up', + 37: 'weighted_medicine_ball_push_up', + 38: 'one_arm_push_up', + 39: 'weighted_one_arm_push_up', + 40: 'weighted_push_up', + 41: 'push_up_and_row', + 42: 'weighted_push_up_and_row', + 43: 'push_up_plus', + 44: 'weighted_push_up_plus', + 45: 'push_up_with_feet_on_swiss_ball', + 46: 'weighted_push_up_with_feet_on_swiss_ball', + 47: 'push_up_with_one_hand_on_medicine_ball', + 48: 'weighted_push_up_with_one_hand_on_medicine_ball', + 49: 'shoulder_push_up', + 50: 'weighted_shoulder_push_up', + 51: 'single_arm_medicine_ball_push_up', + 52: 'weighted_single_arm_medicine_ball_push_up', + 53: 'spiderman_push_up', + 54: 'weighted_spiderman_push_up', + 55: 'stacked_feet_push_up', + 56: 'weighted_stacked_feet_push_up', + 57: 'staggered_hands_push_up', + 58: 'weighted_staggered_hands_push_up', + 59: 'suspended_push_up', + 60: 'weighted_suspended_push_up', + 61: 'swiss_ball_push_up', + 62: 'weighted_swiss_ball_push_up', + 63: 'swiss_ball_push_up_plus', + 64: 'weighted_swiss_ball_push_up_plus', + 65: 't_push_up', + 66: 'weighted_t_push_up', + 67: 'triple_stop_push_up', + 68: 'weighted_triple_stop_push_up', + 69: 'wide_hands_push_up', + 70: 'weighted_wide_hands_push_up', + 71: 'parallette_handstand_push_up', + 72: 'weighted_parallette_handstand_push_up', + 73: 'ring_handstand_push_up', + 74: 'weighted_ring_handstand_push_up', + 75: 'ring_push_up', + 76: 'weighted_ring_push_up', + 77: 'push_up', + }, + ), + 'pwr_zone_calc': FieldType( + name='pwr_zone_calc', + base_type=BASE_TYPES[0x00], # enum + values={ + 0: 'custom', + 1: 'percent_ftp', + }, + ), + 'rider_position_type': FieldType( + name='rider_position_type', + base_type=BASE_TYPES[0x00], # enum + values={ + 0: 'seated', + 1: 'standing', + 2: 'transition_to_seated', + 3: 'transition_to_standing', + }, + ), + 'row_exercise_name': FieldType( + name='row_exercise_name', + base_type=BASE_TYPES[0x84], # uint16 + values={ + 0: 'barbell_straight_leg_deadlift_to_row', + 1: 'cable_row_standing', + 2: 'dumbbell_row', + 3: 'elevated_feet_inverted_row', + 4: 'weighted_elevated_feet_inverted_row', + 5: 'face_pull', + 6: 'face_pull_with_external_rotation', + 7: 'inverted_row_with_feet_on_swiss_ball', + 8: 'weighted_inverted_row_with_feet_on_swiss_ball', + 9: 'kettlebell_row', + 10: 'modified_inverted_row', + 11: 'weighted_modified_inverted_row', + 12: 'neutral_grip_alternating_dumbbell_row', + 13: 'one_arm_bent_over_row', + 14: 'one_legged_dumbbell_row', + 15: 'renegade_row', + 16: 'reverse_grip_barbell_row', + 17: 'rope_handle_cable_row', + 18: 'seated_cable_row', + 19: 'seated_dumbbell_row', + 20: 'single_arm_cable_row', + 21: 'single_arm_cable_row_and_rotation', + 22: 'single_arm_inverted_row', + 23: 'weighted_single_arm_inverted_row', + 24: 'single_arm_neutral_grip_dumbbell_row', + 25: 'single_arm_neutral_grip_dumbbell_row_and_rotation', + 26: 'suspended_inverted_row', + 27: 'weighted_suspended_inverted_row', + 28: 't_bar_row', + 29: 'towel_grip_inverted_row', + 30: 'weighted_towel_grip_inverted_row', + 31: 'underhand_grip_cable_row', + 32: 'v_grip_cable_row', + 33: 'wide_grip_seated_cable_row', + }, + ), + 'run_exercise_name': FieldType( + name='run_exercise_name', + base_type=BASE_TYPES[0x84], # uint16 + values={ + 0: 'run', + 1: 'walk', + 2: 'jog', + 3: 'sprint', + }, + ), + 'schedule': FieldType( + name='schedule', + base_type=BASE_TYPES[0x00], # enum + values={ + 0: 'workout', + 1: 'course', + }, + ), + 'segment_delete_status': FieldType( + name='segment_delete_status', + base_type=BASE_TYPES[0x00], # enum + values={ + 0: 'do_not_delete', + 1: 'delete_one', + 2: 'delete_all', + }, + ), + 'segment_lap_status': FieldType( + name='segment_lap_status', + base_type=BASE_TYPES[0x00], # enum + values={ + 0: 'end', + 1: 'fail', + }, + ), + 'segment_leaderboard_type': FieldType( + name='segment_leaderboard_type', + base_type=BASE_TYPES[0x00], # enum + values={ + 0: 'overall', + 1: 'personal_best', + 2: 'connections', + 3: 'group', + 4: 'challenger', + 5: 'kom', + 6: 'qom', + 7: 'pr', + 8: 'goal', + 9: 'rival', + 10: 'club_leader', + }, + ), + 'segment_selection_type': FieldType( + name='segment_selection_type', + base_type=BASE_TYPES[0x00], # enum + values={ + 0: 'starred', + 1: 'suggested', + }, + ), + 'sensor_type': FieldType( + name='sensor_type', + base_type=BASE_TYPES[0x00], # enum + values={ + 0: 'accelerometer', + 1: 'gyroscope', + 2: 'compass', # Magnetometer + 3: 'barometer', + }, + ), + 'session_trigger': FieldType( + name='session_trigger', + base_type=BASE_TYPES[0x00], # enum + values={ + 0: 'activity_end', + 1: 'manual', # User changed sport. + 2: 'auto_multi_sport', # Auto multi-sport feature is enabled and user pressed lap button to advance session. + 3: 'fitness_equipment', # Auto sport change caused by user linking to fitness equipment. + }, + ), + 'set_type': FieldType( + name='set_type', + base_type=BASE_TYPES[0x02], # uint8 + values={ + 0: 'rest', + 1: 'active', + }, + ), + 'shoulder_press_exercise_name': FieldType( + name='shoulder_press_exercise_name', + base_type=BASE_TYPES[0x84], # uint16 + values={ + 0: 'alternating_dumbbell_shoulder_press', + 1: 'arnold_press', + 2: 'barbell_front_squat_to_push_press', + 3: 'barbell_push_press', + 4: 'barbell_shoulder_press', + 5: 'dead_curl_press', + 6: 'dumbbell_alternating_shoulder_press_and_twist', + 7: 'dumbbell_hammer_curl_to_lunge_to_press', + 8: 'dumbbell_push_press', + 9: 'floor_inverted_shoulder_press', + 10: 'weighted_floor_inverted_shoulder_press', + 11: 'inverted_shoulder_press', + 12: 'weighted_inverted_shoulder_press', + 13: 'one_arm_push_press', + 14: 'overhead_barbell_press', + 15: 'overhead_dumbbell_press', + 16: 'seated_barbell_shoulder_press', + 17: 'seated_dumbbell_shoulder_press', + 18: 'single_arm_dumbbell_shoulder_press', + 19: 'single_arm_step_up_and_press', + 20: 'smith_machine_overhead_press', + 21: 'split_stance_hammer_curl_to_press', + 22: 'swiss_ball_dumbbell_shoulder_press', + 23: 'weight_plate_front_raise', + }, + ), + 'shoulder_stability_exercise_name': FieldType( + name='shoulder_stability_exercise_name', + base_type=BASE_TYPES[0x84], # uint16 + values={ + 0: '90_degree_cable_external_rotation', + 1: 'band_external_rotation', + 2: 'band_internal_rotation', + 3: 'bent_arm_lateral_raise_and_external_rotation', + 4: 'cable_external_rotation', + 5: 'dumbbell_face_pull_with_external_rotation', + 6: 'floor_i_raise', + 7: 'weighted_floor_i_raise', + 8: 'floor_t_raise', + 9: 'weighted_floor_t_raise', + 10: 'floor_y_raise', + 11: 'weighted_floor_y_raise', + 12: 'incline_i_raise', + 13: 'weighted_incline_i_raise', + 14: 'incline_l_raise', + 15: 'weighted_incline_l_raise', + 16: 'incline_t_raise', + 17: 'weighted_incline_t_raise', + 18: 'incline_w_raise', + 19: 'weighted_incline_w_raise', + 20: 'incline_y_raise', + 21: 'weighted_incline_y_raise', + 22: 'lying_external_rotation', + 23: 'seated_dumbbell_external_rotation', + 24: 'standing_l_raise', + 25: 'swiss_ball_i_raise', + 26: 'weighted_swiss_ball_i_raise', + 27: 'swiss_ball_t_raise', + 28: 'weighted_swiss_ball_t_raise', + 29: 'swiss_ball_w_raise', + 30: 'weighted_swiss_ball_w_raise', + 31: 'swiss_ball_y_raise', + 32: 'weighted_swiss_ball_y_raise', + }, + ), + 'shrug_exercise_name': FieldType( + name='shrug_exercise_name', + base_type=BASE_TYPES[0x84], # uint16 + values={ + 0: 'barbell_jump_shrug', + 1: 'barbell_shrug', + 2: 'barbell_upright_row', + 3: 'behind_the_back_smith_machine_shrug', + 4: 'dumbbell_jump_shrug', + 5: 'dumbbell_shrug', + 6: 'dumbbell_upright_row', + 7: 'incline_dumbbell_shrug', + 8: 'overhead_barbell_shrug', + 9: 'overhead_dumbbell_shrug', + 10: 'scaption_and_shrug', + 11: 'scapular_retraction', + 12: 'serratus_chair_shrug', + 13: 'weighted_serratus_chair_shrug', + 14: 'serratus_shrug', + 15: 'weighted_serratus_shrug', + 16: 'wide_grip_jump_shrug', + }, + ), + 'side': FieldType( + name='side', + base_type=BASE_TYPES[0x00], # enum + values={ + 0: 'right', + 1: 'left', + }, + ), + 'sit_up_exercise_name': FieldType( + name='sit_up_exercise_name', + base_type=BASE_TYPES[0x84], # uint16 + values={ + 0: 'alternating_sit_up', + 1: 'weighted_alternating_sit_up', + 2: 'bent_knee_v_up', + 3: 'weighted_bent_knee_v_up', + 4: 'butterfly_sit_up', + 5: 'weighted_butterfly_situp', + 6: 'cross_punch_roll_up', + 7: 'weighted_cross_punch_roll_up', + 8: 'crossed_arms_sit_up', + 9: 'weighted_crossed_arms_sit_up', + 10: 'get_up_sit_up', + 11: 'weighted_get_up_sit_up', + 12: 'hovering_sit_up', + 13: 'weighted_hovering_sit_up', + 14: 'kettlebell_sit_up', + 15: 'medicine_ball_alternating_v_up', + 16: 'medicine_ball_sit_up', + 17: 'medicine_ball_v_up', + 18: 'modified_sit_up', + 19: 'negative_sit_up', + 20: 'one_arm_full_sit_up', + 21: 'reclining_circle', + 22: 'weighted_reclining_circle', + 23: 'reverse_curl_up', + 24: 'weighted_reverse_curl_up', + 25: 'single_leg_swiss_ball_jackknife', + 26: 'weighted_single_leg_swiss_ball_jackknife', + 27: 'the_teaser', + 28: 'the_teaser_weighted', + 29: 'three_part_roll_down', + 30: 'weighted_three_part_roll_down', + 31: 'v_up', + 32: 'weighted_v_up', + 33: 'weighted_russian_twist_on_swiss_ball', + 34: 'weighted_sit_up', + 35: 'x_abs', + 36: 'weighted_x_abs', + 37: 'sit_up', + }, + ), + 'source_type': FieldType( + name='source_type', + base_type=BASE_TYPES[0x00], # enum + values={ + 0: 'ant', # External device connected with ANT + 1: 'antplus', # External device connected with ANT+ + 2: 'bluetooth', # External device connected with BT + 3: 'bluetooth_low_energy', # External device connected with BLE + 4: 'wifi', # External device connected with Wifi + 5: 'local', # Onboard device + }, + ), + 'sport': FieldType( + name='sport', + base_type=BASE_TYPES[0x00], # enum + values={ + 0: 'generic', + 1: 'running', + 2: 'cycling', + 3: 'transition', # Mulitsport transition + 4: 'fitness_equipment', + 5: 'swimming', + 6: 'basketball', + 7: 'soccer', + 8: 'tennis', + 9: 'american_football', + 10: 'training', + 11: 'walking', + 12: 'cross_country_skiing', + 13: 'alpine_skiing', + 14: 'snowboarding', + 15: 'rowing', + 16: 'mountaineering', + 17: 'hiking', + 18: 'multisport', + 19: 'paddling', + 20: 'flying', + 21: 'e_biking', + 22: 'motorcycling', + 23: 'boating', + 24: 'driving', + 25: 'golf', + 26: 'hang_gliding', + 27: 'horseback_riding', + 28: 'hunting', + 29: 'fishing', + 30: 'inline_skating', + 31: 'rock_climbing', + 32: 'sailing', + 33: 'ice_skating', + 34: 'sky_diving', + 35: 'snowshoeing', + 36: 'snowmobiling', + 37: 'stand_up_paddleboarding', + 38: 'surfing', + 39: 'wakeboarding', + 40: 'water_skiing', + 41: 'kayaking', + 42: 'rafting', + 43: 'windsurfing', + 44: 'kitesurfing', + 45: 'tactical', + 46: 'jumpmaster', + 47: 'boxing', + 48: 'floor_climbing', + 254: 'all', # All is for goals only to include all sports. + }, + ), + 'sport_bits_0': FieldType( # Bit field corresponding to sport enum type (1 << sport). + name='sport_bits_0', + base_type=BASE_TYPES[0x0A], # uint8z + values={ + 0x01: 'generic', + 0x02: 'running', + 0x04: 'cycling', + 0x08: 'transition', # Mulitsport transition + 0x10: 'fitness_equipment', + 0x20: 'swimming', + 0x40: 'basketball', + 0x80: 'soccer', + }, + ), + 'sport_bits_1': FieldType( # Bit field corresponding to sport enum type (1 << (sport-8)). + name='sport_bits_1', + base_type=BASE_TYPES[0x0A], # uint8z + values={ + 0x01: 'tennis', + 0x02: 'american_football', + 0x04: 'training', + 0x08: 'walking', + 0x10: 'cross_country_skiing', + 0x20: 'alpine_skiing', + 0x40: 'snowboarding', + 0x80: 'rowing', + }, + ), + 'sport_bits_2': FieldType( # Bit field corresponding to sport enum type (1 << (sport-16)). + name='sport_bits_2', + base_type=BASE_TYPES[0x0A], # uint8z + values={ + 0x01: 'mountaineering', + 0x02: 'hiking', + 0x04: 'multisport', + 0x08: 'paddling', + 0x10: 'flying', + 0x20: 'e_biking', + 0x40: 'motorcycling', + 0x80: 'boating', + }, + ), + 'sport_bits_3': FieldType( # Bit field corresponding to sport enum type (1 << (sport-24)). + name='sport_bits_3', + base_type=BASE_TYPES[0x0A], # uint8z + values={ + 0x01: 'driving', + 0x02: 'golf', + 0x04: 'hang_gliding', + 0x08: 'horseback_riding', + 0x10: 'hunting', + 0x20: 'fishing', + 0x40: 'inline_skating', + 0x80: 'rock_climbing', + }, + ), + 'sport_bits_4': FieldType( # Bit field corresponding to sport enum type (1 << (sport-32)). + name='sport_bits_4', + base_type=BASE_TYPES[0x0A], # uint8z + values={ + 0x01: 'sailing', + 0x02: 'ice_skating', + 0x04: 'sky_diving', + 0x08: 'snowshoeing', + 0x10: 'snowmobiling', + 0x20: 'stand_up_paddleboarding', + 0x40: 'surfing', + 0x80: 'wakeboarding', + }, + ), + 'sport_bits_5': FieldType( # Bit field corresponding to sport enum type (1 << (sport-40)). + name='sport_bits_5', + base_type=BASE_TYPES[0x0A], # uint8z + values={ + 0x01: 'water_skiing', + 0x02: 'kayaking', + 0x04: 'rafting', + 0x08: 'windsurfing', + 0x10: 'kitesurfing', + 0x20: 'tactical', + 0x40: 'jumpmaster', + 0x80: 'boxing', + }, + ), + 'sport_bits_6': FieldType( # Bit field corresponding to sport enum type (1 << (sport-48)). + name='sport_bits_6', + base_type=BASE_TYPES[0x0A], # uint8z + values={ + 0x01: 'floor_climbing', + }, + ), + 'sport_event': FieldType( + name='sport_event', + base_type=BASE_TYPES[0x00], # enum + values={ + 0: 'uncategorized', + 1: 'geocaching', + 2: 'fitness', + 3: 'recreation', + 4: 'race', + 5: 'special_event', + 6: 'training', + 7: 'transportation', + 8: 'touring', + }, + ), + 'squat_exercise_name': FieldType( + name='squat_exercise_name', + base_type=BASE_TYPES[0x84], # uint16 + values={ + 0: 'leg_press', + 1: 'back_squat_with_body_bar', + 2: 'back_squats', + 3: 'weighted_back_squats', + 4: 'balancing_squat', + 5: 'weighted_balancing_squat', + 6: 'barbell_back_squat', + 7: 'barbell_box_squat', + 8: 'barbell_front_squat', + 9: 'barbell_hack_squat', + 10: 'barbell_hang_squat_snatch', + 11: 'barbell_lateral_step_up', + 12: 'barbell_quarter_squat', + 13: 'barbell_siff_squat', + 14: 'barbell_squat_snatch', + 15: 'barbell_squat_with_heels_raised', + 16: 'barbell_stepover', + 17: 'barbell_step_up', + 18: 'bench_squat_with_rotational_chop', + 19: 'weighted_bench_squat_with_rotational_chop', + 20: 'body_weight_wall_squat', + 21: 'weighted_wall_squat', + 22: 'box_step_squat', + 23: 'weighted_box_step_squat', + 24: 'braced_squat', + 25: 'crossed_arm_barbell_front_squat', + 26: 'crossover_dumbbell_step_up', + 27: 'dumbbell_front_squat', + 28: 'dumbbell_split_squat', + 29: 'dumbbell_squat', + 30: 'dumbbell_squat_clean', + 31: 'dumbbell_stepover', + 32: 'dumbbell_step_up', + 33: 'elevated_single_leg_squat', + 34: 'weighted_elevated_single_leg_squat', + 35: 'figure_four_squats', + 36: 'weighted_figure_four_squats', + 37: 'goblet_squat', + 38: 'kettlebell_squat', + 39: 'kettlebell_swing_overhead', + 40: 'kettlebell_swing_with_flip_to_squat', + 41: 'lateral_dumbbell_step_up', + 42: 'one_legged_squat', + 43: 'overhead_dumbbell_squat', + 44: 'overhead_squat', + 45: 'partial_single_leg_squat', + 46: 'weighted_partial_single_leg_squat', + 47: 'pistol_squat', + 48: 'weighted_pistol_squat', + 49: 'plie_slides', + 50: 'weighted_plie_slides', + 51: 'plie_squat', + 52: 'weighted_plie_squat', + 53: 'prisoner_squat', + 54: 'weighted_prisoner_squat', + 55: 'single_leg_bench_get_up', + 56: 'weighted_single_leg_bench_get_up', + 57: 'single_leg_bench_squat', + 58: 'weighted_single_leg_bench_squat', + 59: 'single_leg_squat_on_swiss_ball', + 60: 'weighted_single_leg_squat_on_swiss_ball', + 61: 'squat', + 62: 'weighted_squat', + 63: 'squats_with_band', + 64: 'staggered_squat', + 65: 'weighted_staggered_squat', + 66: 'step_up', + 67: 'weighted_step_up', + 68: 'suitcase_squats', + 69: 'sumo_squat', + 70: 'sumo_squat_slide_in', + 71: 'weighted_sumo_squat_slide_in', + 72: 'sumo_squat_to_high_pull', + 73: 'sumo_squat_to_stand', + 74: 'weighted_sumo_squat_to_stand', + 75: 'sumo_squat_with_rotation', + 76: 'weighted_sumo_squat_with_rotation', + 77: 'swiss_ball_body_weight_wall_squat', + 78: 'weighted_swiss_ball_wall_squat', + 79: 'thrusters', + 80: 'uneven_squat', + 81: 'weighted_uneven_squat', + 82: 'waist_slimming_squat', + 83: 'wall_ball', + 84: 'wide_stance_barbell_squat', + 85: 'wide_stance_goblet_squat', + 86: 'zercher_squat', + }, + ), + 'stroke_type': FieldType( + name='stroke_type', + base_type=BASE_TYPES[0x00], # enum + values={ + 0: 'no_event', + 1: 'other', # stroke was detected but cannot be identified + 2: 'serve', + 3: 'forehand', + 4: 'backhand', + 5: 'smash', + }, + ), + 'sub_sport': FieldType( + name='sub_sport', + base_type=BASE_TYPES[0x00], # enum + values={ + 0: 'generic', + 1: 'treadmill', # Run/Fitness Equipment + 2: 'street', # Run + 3: 'trail', # Run + 4: 'track', # Run + 5: 'spin', # Cycling + 6: 'indoor_cycling', # Cycling/Fitness Equipment + 7: 'road', # Cycling + 8: 'mountain', # Cycling + 9: 'downhill', # Cycling + 10: 'recumbent', # Cycling + 11: 'cyclocross', # Cycling + 12: 'hand_cycling', # Cycling + 13: 'track_cycling', # Cycling + 14: 'indoor_rowing', # Fitness Equipment + 15: 'elliptical', # Fitness Equipment + 16: 'stair_climbing', # Fitness Equipment + 17: 'lap_swimming', # Swimming + 18: 'open_water', # Swimming + 19: 'flexibility_training', # Training + 20: 'strength_training', # Training + 21: 'warm_up', # Tennis + 22: 'match', # Tennis + 23: 'exercise', # Tennis + 24: 'challenge', + 25: 'indoor_skiing', # Fitness Equipment + 26: 'cardio_training', # Training + 27: 'indoor_walking', # Walking/Fitness Equipment + 28: 'e_bike_fitness', # E-Biking + 29: 'bmx', # Cycling + 30: 'casual_walking', # Walking + 31: 'speed_walking', # Walking + 32: 'bike_to_run_transition', # Transition + 33: 'run_to_bike_transition', # Transition + 34: 'swim_to_bike_transition', # Transition + 35: 'atv', # Motorcycling + 36: 'motocross', # Motorcycling + 37: 'backcountry', # Alpine Skiing/Snowboarding + 38: 'resort', # Alpine Skiing/Snowboarding + 39: 'rc_drone', # Flying + 40: 'wingsuit', # Flying + 41: 'whitewater', # Kayaking/Rafting + 42: 'skate_skiing', # Cross Country Skiing + 43: 'yoga', # Training + 44: 'pilates', # Training + 45: 'indoor_running', # Run + 46: 'gravel_cycling', # Cycling + 47: 'e_bike_mountain', # Cycling + 48: 'commuting', # Cycling + 49: 'mixed_surface', # Cycling + 50: 'navigate', + 51: 'track_me', + 52: 'map', + 53: 'single_gas_diving', # Diving + 54: 'multi_gas_diving', # Diving + 55: 'gauge_diving', # Diving + 56: 'apnea_diving', # Diving + 57: 'apnea_hunting', # Diving + 58: 'virtual_activity', + 59: 'obstacle', # Used for events where participants run, crawl through mud, climb over walls, etc. + 254: 'all', + }, + ), + 'supported_exd_screen_layouts': FieldType( + name='supported_exd_screen_layouts', + base_type=BASE_TYPES[0x8C], # uint32z + values={ + 0x00000001: 'full_screen', + 0x00000002: 'half_vertical', + 0x00000004: 'half_horizontal', + 0x00000008: 'half_vertical_right_split', + 0x00000010: 'half_horizontal_bottom_split', + 0x00000020: 'full_quarter_split', + 0x00000040: 'half_vertical_left_split', + 0x00000080: 'half_horizontal_top_split', + }, + ), + 'swim_stroke': FieldType( + name='swim_stroke', + base_type=BASE_TYPES[0x00], # enum + values={ + 0: 'freestyle', + 1: 'backstroke', + 2: 'breaststroke', + 3: 'butterfly', + 4: 'drill', + 5: 'mixed', + 6: 'im', # IM is a mixed interval containing the same number of lengths for each of: Butterfly, Backstroke, Breaststroke, Freestyle, swam in that order. + }, + ), + 'switch': FieldType( + name='switch', + base_type=BASE_TYPES[0x00], # enum + values={ + 0: 'off', + 1: 'on', + 2: 'auto', + }, + ), + '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 + ), + 'time_mode': FieldType( + name='time_mode', + base_type=BASE_TYPES[0x00], # enum + values={ + 0: 'hour12', + 1: 'hour24', # Does not use a leading zero and has a colon + 2: 'military', # Uses a leading zero and does not have a colon + 3: 'hour_12_with_seconds', + 4: 'hour_24_with_seconds', + 5: 'utc', + }, + ), + 'time_zone': FieldType( + name='time_zone', + base_type=BASE_TYPES[0x00], # enum + values={ + 0: 'almaty', + 1: 'bangkok', + 2: 'bombay', + 3: 'brasilia', + 4: 'cairo', + 5: 'cape_verde_is', + 6: 'darwin', + 7: 'eniwetok', + 8: 'fiji', + 9: 'hong_kong', + 10: 'islamabad', + 11: 'kabul', + 12: 'magadan', + 13: 'mid_atlantic', + 14: 'moscow', + 15: 'muscat', + 16: 'newfoundland', + 17: 'samoa', + 18: 'sydney', + 19: 'tehran', + 20: 'tokyo', + 21: 'us_alaska', + 22: 'us_atlantic', + 23: 'us_central', + 24: 'us_eastern', + 25: 'us_hawaii', + 26: 'us_mountain', + 27: 'us_pacific', + 28: 'other', + 29: 'auckland', + 30: 'kathmandu', + 31: 'europe_western_wet', + 32: 'europe_central_cet', + 33: 'europe_eastern_eet', + 34: 'jakarta', + 35: 'perth', + 36: 'adelaide', + 37: 'brisbane', + 38: 'tasmania', + 39: 'iceland', + 40: 'amsterdam', + 41: 'athens', + 42: 'barcelona', + 43: 'berlin', + 44: 'brussels', + 45: 'budapest', + 46: 'copenhagen', + 47: 'dublin', + 48: 'helsinki', + 49: 'lisbon', + 50: 'london', + 51: 'madrid', + 52: 'munich', + 53: 'oslo', + 54: 'paris', + 55: 'prague', + 56: 'reykjavik', + 57: 'rome', + 58: 'stockholm', + 59: 'vienna', + 60: 'warsaw', + 61: 'zurich', + 62: 'quebec', + 63: 'ontario', + 64: 'manitoba', + 65: 'saskatchewan', + 66: 'alberta', + 67: 'british_columbia', + 68: 'boise', + 69: 'boston', + 70: 'chicago', + 71: 'dallas', + 72: 'denver', + 73: 'kansas_city', + 74: 'las_vegas', + 75: 'los_angeles', + 76: 'miami', + 77: 'minneapolis', + 78: 'new_york', + 79: 'new_orleans', + 80: 'phoenix', + 81: 'santa_fe', + 82: 'seattle', + 83: 'washington_dc', + 84: 'us_arizona', + 85: 'chita', + 86: 'ekaterinburg', + 87: 'irkutsk', + 88: 'kaliningrad', + 89: 'krasnoyarsk', + 90: 'novosibirsk', + 91: 'petropavlovsk_kamchatskiy', + 92: 'samara', + 93: 'vladivostok', + 94: 'mexico_central', + 95: 'mexico_mountain', + 96: 'mexico_pacific', + 97: 'cape_town', + 98: 'winkhoek', + 99: 'lagos', + 100: 'riyahd', + 101: 'venezuela', + 102: 'australia_lh', + 103: 'santiago', + 253: 'manual', + 254: 'automatic', + }, + ), + 'timer_trigger': FieldType( # timer event data + name='timer_trigger', + base_type=BASE_TYPES[0x00], # enum + values={ + 0: 'manual', + 1: 'auto', + 2: 'fitness_equipment', + }, + ), + 'tissue_model_type': FieldType( + name='tissue_model_type', + base_type=BASE_TYPES[0x00], # enum + values={ + 0: 'zhl_16c', # Buhlmann's decompression algorithm, version C + }, + ), + 'tone': FieldType( + name='tone', + base_type=BASE_TYPES[0x00], # enum + values={ + 0: 'off', + 1: 'tone', + 2: 'vibrate', + 3: 'tone_and_vibrate', + }, + ), + 'total_body_exercise_name': FieldType( + name='total_body_exercise_name', + base_type=BASE_TYPES[0x84], # uint16 + values={ + 0: 'burpee', + 1: 'weighted_burpee', + 2: 'burpee_box_jump', + 3: 'weighted_burpee_box_jump', + 4: 'high_pull_burpee', + 5: 'man_makers', + 6: 'one_arm_burpee', + 7: 'squat_thrusts', + 8: 'weighted_squat_thrusts', + 9: 'squat_plank_push_up', + 10: 'weighted_squat_plank_push_up', + 11: 'standing_t_rotation_balance', + 12: 'weighted_standing_t_rotation_balance', + }, + ), + 'triceps_extension_exercise_name': FieldType( + name='triceps_extension_exercise_name', + base_type=BASE_TYPES[0x84], # uint16 + values={ + 0: 'bench_dip', + 1: 'weighted_bench_dip', + 2: 'body_weight_dip', + 3: 'cable_kickback', + 4: 'cable_lying_triceps_extension', + 5: 'cable_overhead_triceps_extension', + 6: 'dumbbell_kickback', + 7: 'dumbbell_lying_triceps_extension', + 8: 'ez_bar_overhead_triceps_extension', + 9: 'incline_dip', + 10: 'weighted_incline_dip', + 11: 'incline_ez_bar_lying_triceps_extension', + 12: 'lying_dumbbell_pullover_to_extension', + 13: 'lying_ez_bar_triceps_extension', + 14: 'lying_triceps_extension_to_close_grip_bench_press', + 15: 'overhead_dumbbell_triceps_extension', + 16: 'reclining_triceps_press', + 17: 'reverse_grip_pressdown', + 18: 'reverse_grip_triceps_pressdown', + 19: 'rope_pressdown', + 20: 'seated_barbell_overhead_triceps_extension', + 21: 'seated_dumbbell_overhead_triceps_extension', + 22: 'seated_ez_bar_overhead_triceps_extension', + 23: 'seated_single_arm_overhead_dumbbell_extension', + 24: 'single_arm_dumbbell_overhead_triceps_extension', + 25: 'single_dumbbell_seated_overhead_triceps_extension', + 26: 'single_leg_bench_dip_and_kick', + 27: 'weighted_single_leg_bench_dip_and_kick', + 28: 'single_leg_dip', + 29: 'weighted_single_leg_dip', + 30: 'static_lying_triceps_extension', + 31: 'suspended_dip', + 32: 'weighted_suspended_dip', + 33: 'swiss_ball_dumbbell_lying_triceps_extension', + 34: 'swiss_ball_ez_bar_lying_triceps_extension', + 35: 'swiss_ball_ez_bar_overhead_triceps_extension', + 36: 'tabletop_dip', + 37: 'weighted_tabletop_dip', + 38: 'triceps_extension_on_floor', + 39: 'triceps_pressdown', + 40: 'weighted_dip', + }, + ), + 'turn_type': FieldType( + name='turn_type', + base_type=BASE_TYPES[0x00], # enum + values={ + 0: 'arriving_idx', + 1: 'arriving_left_idx', + 2: 'arriving_right_idx', + 3: 'arriving_via_idx', + 4: 'arriving_via_left_idx', + 5: 'arriving_via_right_idx', + 6: 'bear_keep_left_idx', + 7: 'bear_keep_right_idx', + 8: 'continue_idx', + 9: 'exit_left_idx', + 10: 'exit_right_idx', + 11: 'ferry_idx', + 12: 'roundabout_45_idx', + 13: 'roundabout_90_idx', + 14: 'roundabout_135_idx', + 15: 'roundabout_180_idx', + 16: 'roundabout_225_idx', + 17: 'roundabout_270_idx', + 18: 'roundabout_315_idx', + 19: 'roundabout_360_idx', + 20: 'roundabout_neg_45_idx', + 21: 'roundabout_neg_90_idx', + 22: 'roundabout_neg_135_idx', + 23: 'roundabout_neg_180_idx', + 24: 'roundabout_neg_225_idx', + 25: 'roundabout_neg_270_idx', + 26: 'roundabout_neg_315_idx', + 27: 'roundabout_neg_360_idx', + 28: 'roundabout_generic_idx', + 29: 'roundabout_neg_generic_idx', + 30: 'sharp_turn_left_idx', + 31: 'sharp_turn_right_idx', + 32: 'turn_left_idx', + 33: 'turn_right_idx', + 34: 'uturn_left_idx', + 35: 'uturn_right_idx', + 36: 'icon_inv_idx', + 37: 'icon_idx_cnt', + }, + ), + 'user_local_id': FieldType( + name='user_local_id', + base_type=BASE_TYPES[0x84], # uint16 + values={ + 0x0000: 'local_min', + 0x000F: 'local_max', + 0x0010: 'stationary_min', + 0x00FF: 'stationary_max', + 0x0100: 'portable_min', + 0xFFFE: 'portable_max', + }, + ), + 'warm_up_exercise_name': FieldType( + name='warm_up_exercise_name', + base_type=BASE_TYPES[0x84], # uint16 + values={ + 0: 'quadruped_rocking', + 1: 'neck_tilts', + 2: 'ankle_circles', + 3: 'ankle_dorsiflexion_with_band', + 4: 'ankle_internal_rotation', + 5: 'arm_circles', + 6: 'bent_over_reach_to_sky', + 7: 'cat_camel', + 8: 'elbow_to_foot_lunge', + 9: 'forward_and_backward_leg_swings', + 10: 'groiners', + 11: 'inverted_hamstring_stretch', + 12: 'lateral_duck_under', + 13: 'neck_rotations', + 14: 'opposite_arm_and_leg_balance', + 15: 'reach_roll_and_lift', + 16: 'scorpion', + 17: 'shoulder_circles', + 18: 'side_to_side_leg_swings', + 19: 'sleeper_stretch', + 20: 'slide_out', + 21: 'swiss_ball_hip_crossover', + 22: 'swiss_ball_reach_roll_and_lift', + 23: 'swiss_ball_windshield_wipers', + 24: 'thoracic_rotation', + 25: 'walking_high_kicks', + 26: 'walking_high_knees', + 27: 'walking_knee_hugs', + 28: 'walking_leg_cradles', + 29: 'walkout', + 30: 'walkout_from_push_up_position', + }, + ), + 'watchface_mode': FieldType( + name='watchface_mode', + base_type=BASE_TYPES[0x00], # enum + values={ + 0: 'digital', + 1: 'analog', + 2: 'connect_iq', + 3: 'disabled', + }, + ), + 'water_type': FieldType( + name='water_type', + base_type=BASE_TYPES[0x00], # enum + values={ + 0: 'fresh', + 1: 'salt', + 2: 'en13319', + 3: 'custom', + }, + ), + 'weather_report': FieldType( + name='weather_report', + base_type=BASE_TYPES[0x00], # enum + values={ + 0: 'current', + 1: 'forecast', # Deprecated use hourly_forecast instead + 1: 'hourly_forecast', + 2: 'daily_forecast', + }, + ), + 'weather_severe_type': FieldType( + name='weather_severe_type', + base_type=BASE_TYPES[0x00], # enum + values={ + 0: 'unspecified', + 1: 'tornado', + 2: 'tsunami', + 3: 'hurricane', + 4: 'extreme_wind', + 5: 'typhoon', + 6: 'inland_hurricane', + 7: 'hurricane_force_wind', + 8: 'waterspout', + 9: 'severe_thunderstorm', + 10: 'wreckhouse_winds', + 11: 'les_suetes_wind', + 12: 'avalanche', + 13: 'flash_flood', + 14: 'tropical_storm', + 15: 'inland_tropical_storm', + 16: 'blizzard', + 17: 'ice_storm', + 18: 'freezing_rain', + 19: 'debris_flow', + 20: 'flash_freeze', + 21: 'dust_storm', + 22: 'high_wind', + 23: 'winter_storm', + 24: 'heavy_freezing_spray', + 25: 'extreme_cold', + 26: 'wind_chill', + 27: 'cold_wave', + 28: 'heavy_snow_alert', + 29: 'lake_effect_blowing_snow', + 30: 'snow_squall', + 31: 'lake_effect_snow', + 32: 'winter_weather', + 33: 'sleet', + 34: 'snowfall', + 35: 'snow_and_blowing_snow', + 36: 'blowing_snow', + 37: 'snow_alert', + 38: 'arctic_outflow', + 39: 'freezing_drizzle', + 40: 'storm', + 41: 'storm_surge', + 42: 'rainfall', + 43: 'areal_flood', + 44: 'coastal_flood', + 45: 'lakeshore_flood', + 46: 'excessive_heat', + 47: 'heat', + 48: 'weather', + 49: 'high_heat_and_humidity', + 50: 'humidex_and_health', + 51: 'humidex', + 52: 'gale', + 53: 'freezing_spray', + 54: 'special_marine', + 55: 'squall', + 56: 'strong_wind', + 57: 'lake_wind', + 58: 'marine_weather', + 59: 'wind', + 60: 'small_craft_hazardous_seas', + 61: 'hazardous_seas', + 62: 'small_craft', + 63: 'small_craft_winds', + 64: 'small_craft_rough_bar', + 65: 'high_water_level', + 66: 'ashfall', + 67: 'freezing_fog', + 68: 'dense_fog', + 69: 'dense_smoke', + 70: 'blowing_dust', + 71: 'hard_freeze', + 72: 'freeze', + 73: 'frost', + 74: 'fire_weather', + 75: 'flood', + 76: 'rip_tide', + 77: 'high_surf', + 78: 'smog', + 79: 'air_quality', + 80: 'brisk_wind', + 81: 'air_stagnation', + 82: 'low_water', + 83: 'hydrological', + 84: 'special_weather', + }, + ), + 'weather_severity': FieldType( + name='weather_severity', + base_type=BASE_TYPES[0x00], # enum + values={ + 0: 'unknown', + 1: 'warning', + 2: 'watch', + 3: 'advisory', + 4: 'statement', + }, + ), + 'weather_status': FieldType( + name='weather_status', + base_type=BASE_TYPES[0x00], # enum + values={ + 0: 'clear', + 1: 'partly_cloudy', + 2: 'mostly_cloudy', + 3: 'rain', + 4: 'snow', + 5: 'windy', + 6: 'thunderstorms', + 7: 'wintry_mix', + 8: 'fog', + 11: 'hazy', + 12: 'hail', + 13: 'scattered_showers', + 14: 'scattered_thunderstorms', + 15: 'unknown_precipitation', + 16: 'light_rain', + 17: 'heavy_rain', + 18: 'light_snow', + 19: 'heavy_snow', + 20: 'light_rain_snow', + 21: 'heavy_rain_snow', + 22: 'cloudy', + }, + ), + 'weight': FieldType( + name='weight', + base_type=BASE_TYPES[0x84], # uint16 + values={ + 0xFFFE: 'calculating', + }, + ), + 'wkt_step_duration': FieldType( + name='wkt_step_duration', + base_type=BASE_TYPES[0x00], # enum + values={ + 0: 'time', + 1: 'distance', + 2: 'hr_less_than', + 3: 'hr_greater_than', + 4: 'calories', + 5: 'open', + 6: 'repeat_until_steps_cmplt', + 7: 'repeat_until_time', + 8: 'repeat_until_distance', + 9: 'repeat_until_calories', + 10: 'repeat_until_hr_less_than', + 11: 'repeat_until_hr_greater_than', + 12: 'repeat_until_power_less_than', + 13: 'repeat_until_power_greater_than', + 14: 'power_less_than', + 15: 'power_greater_than', + 16: 'training_peaks_tss', + 17: 'repeat_until_power_last_lap_less_than', + 18: 'repeat_until_max_power_last_lap_less_than', + 19: 'power_3s_less_than', + 20: 'power_10s_less_than', + 21: 'power_30s_less_than', + 22: 'power_3s_greater_than', + 23: 'power_10s_greater_than', + 24: 'power_30s_greater_than', + 25: 'power_lap_less_than', + 26: 'power_lap_greater_than', + 27: 'repeat_until_training_peaks_tss', + 28: 'repetition_time', + 29: 'reps', + }, + ), + 'wkt_step_target': FieldType( + name='wkt_step_target', + base_type=BASE_TYPES[0x00], # enum + values={ + 0: 'speed', + 1: 'heart_rate', + 2: 'open', + 3: 'cadence', + 4: 'power', + 5: 'grade', + 6: 'resistance', + 7: 'power_3s', + 8: 'power_10s', + 9: 'power_30s', + 10: 'power_lap', + 11: 'swim_stroke', + 12: 'speed_lap', + 13: 'heart_rate_lap', + }, + ), + 'workout_capabilities': FieldType( + name='workout_capabilities', + base_type=BASE_TYPES[0x8C], # uint32z + values={ + 0x00000001: 'interval', + 0x00000002: 'custom', + 0x00000004: 'fitness_equipment', + 0x00000008: 'firstbeat', + 0x00000010: 'new_leaf', + 0x00000020: 'tcx', # For backwards compatibility. Watch should add missing id fields then clear flag. + 0x00000080: 'speed', # Speed source required for workout step. + 0x00000100: 'heart_rate', # Heart rate source required for workout step. + 0x00000200: 'distance', # Distance source required for workout step. + 0x00000400: 'cadence', # Cadence source required for workout step. + 0x00000800: 'power', # Power source required for workout step. + 0x00001000: 'grade', # Grade source required for workout step. + 0x00002000: 'resistance', # Resistance source required for workout step. + 0x00004000: 'protected', + }, + ), + 'workout_equipment': FieldType( + name='workout_equipment', + base_type=BASE_TYPES[0x00], # enum + values={ + 0: 'none', + 1: 'swim_fins', + 2: 'swim_kickboard', + 3: 'swim_paddles', + 4: 'swim_pull_buoy', + 5: 'swim_snorkel', + }, + ), + 'workout_hr': FieldType( # 0 - 100 indicates% of max hr; >100 indicates bpm (255 max) plus 100 + name='workout_hr', + base_type=BASE_TYPES[0x86], # uint32 + values={ + 100: 'bpm_offset', + }, + ), + 'workout_power': FieldType( # 0 - 1000 indicates % of functional threshold power; >1000 indicates watts plus 1000. + name='workout_power', + base_type=BASE_TYPES[0x86], # uint32 + values={ + 1000: 'watts_offset', + }, + ), +} + + +FIELD_TYPE_TIMESTAMP = Field(name='timestamp', type=FIELD_TYPES['date_time'], def_num=253, units='s') + + +MESSAGE_TYPES = { + # **************************** Common Messages ***************************** + 0: MessageType( # Must be first message in file. + name='file_id', + mesg_num=0, + fields={ + 0: Field( + name='type', + type=FIELD_TYPES['file'], + def_num=0, + ), + 1: Field( + name='manufacturer', + type=FIELD_TYPES['manufacturer'], + def_num=1, + ), + 2: Field( + name='product', + type=BASE_TYPES[0x84], # uint16 + def_num=2, + subfields=( + SubField( + name='garmin_product', + def_num=2, + type=FIELD_TYPES['garmin_product'], + ref_fields=( + ReferenceField( + name='manufacturer', + def_num=1, + value='garmin', + raw_value=1, + ), + ReferenceField( + name='manufacturer', + def_num=1, + value='dynastream', + raw_value=15, + ), + ReferenceField( + name='manufacturer', + def_num=1, + value='dynastream_oem', + raw_value=13, + ), + ), + ), + ), + ), + 3: Field( + name='serial_number', + type=BASE_TYPES[0x8C], # uint32z + def_num=3, + ), + 4: Field( # Only set for files that are can be created/erased. + name='time_created', + type=FIELD_TYPES['date_time'], + def_num=4, + ), + 5: Field( # Only set for files that are not created/erased. + name='number', + type=BASE_TYPES[0x84], # uint16 + def_num=5, + ), + 8: Field( # Optional free form string to indicate the devices name or model + name='product_name', + type=BASE_TYPES[0x07], # string + def_num=8, + ), + }, + ), + + + # ************************************ ************************************ + 1: MessageType( + name='capabilities', + mesg_num=1, + fields={ + 0: Field( # Use language_bits_x types where x is index of array. + name='languages', + type=BASE_TYPES[0x0A], # uint8z + def_num=0, + ), + 1: Field( # Use sport_bits_x types where x is index of array. + name='sports', + type=FIELD_TYPES['sport_bits_0'], + def_num=1, + ), + 21: Field( + name='workouts_supported', + type=FIELD_TYPES['workout_capabilities'], + def_num=21, + ), + 23: Field( + name='connectivity_supported', + type=FIELD_TYPES['connectivity_capabilities'], + def_num=23, + ), + }, + ), + 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', + type=BASE_TYPES[0x84], # uint16 + def_num=11, + scale=10, + units='%', + ), + 12: Field( + name='auto_wheel_cal', + type=FIELD_TYPES['bool'], + def_num=12, + ), + 13: Field( + name='auto_power_zero', + type=FIELD_TYPES['bool'], + def_num=13, + ), + 14: Field( + name='id', + type=BASE_TYPES[0x02], # uint8 + def_num=14, + ), + 15: Field( + name='spd_enabled', + type=FIELD_TYPES['bool'], + def_num=15, + ), + 16: Field( + name='cad_enabled', + type=FIELD_TYPES['bool'], + def_num=16, + ), + 17: Field( + name='spdcad_enabled', + type=FIELD_TYPES['bool'], + def_num=17, + ), + 18: Field( + name='power_enabled', + type=FIELD_TYPES['bool'], + def_num=18, + ), + 19: Field( + name='crank_length', + type=BASE_TYPES[0x02], # uint8 + def_num=19, + scale=2, + offset=-110, + units='mm', + ), + 20: Field( + name='enabled', + type=FIELD_TYPES['bool'], + def_num=20, + ), + 21: Field( + name='bike_spd_ant_id_trans_type', + type=BASE_TYPES[0x0A], # uint8z + def_num=21, + ), + 22: Field( + name='bike_cad_ant_id_trans_type', + type=BASE_TYPES[0x0A], # uint8z + def_num=22, + ), + 23: Field( + name='bike_spdcad_ant_id_trans_type', + type=BASE_TYPES[0x0A], # uint8z + def_num=23, + ), + 24: Field( + name='bike_power_ant_id_trans_type', + type=BASE_TYPES[0x0A], # uint8z + def_num=24, + ), + 37: Field( # Rollover counter that can be used to extend the odometer + name='odometer_rollover', + type=BASE_TYPES[0x02], # uint8 + def_num=37, + ), + 38: Field( # Number of front gears + name='front_gear_num', + type=BASE_TYPES[0x0A], # uint8z + def_num=38, + ), + 39: Field( # Number of teeth on each gear 0 is innermost + name='front_gear', + type=BASE_TYPES[0x0A], # uint8z + def_num=39, + ), + 40: Field( # Number of rear gears + name='rear_gear_num', + type=BASE_TYPES[0x0A], # uint8z + def_num=40, + ), + 41: Field( # Number of teeth on each gear 0 is innermost + name='rear_gear', + type=BASE_TYPES[0x0A], # uint8z + def_num=41, + ), + 44: Field( + name='shimano_di2_enabled', + type=FIELD_TYPES['bool'], + def_num=44, + ), + 254: Field( + name='message_index', + type=FIELD_TYPES['message_index'], + def_num=254, + ), + }, + ), + 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( + name='message_index', + type=FIELD_TYPES['message_index'], + def_num=254, + ), + }, + ), + 9: MessageType( + name='power_zone', + mesg_num=9, + fields={ + 1: Field( + name='high_value', + type=BASE_TYPES[0x84], # uint16 + def_num=1, + units='watts', + ), + 2: Field( + name='name', + type=BASE_TYPES[0x07], # string + def_num=2, + ), + 254: Field( + name='message_index', + type=FIELD_TYPES['message_index'], + def_num=254, + ), + }, + ), + 10: MessageType( + name='met_zone', + mesg_num=10, + fields={ + 1: Field( + name='high_bpm', + type=BASE_TYPES[0x02], # uint8 + def_num=1, + ), + 2: Field( + name='calories', + type=BASE_TYPES[0x84], # uint16 + def_num=2, + scale=10, + units='kcal/min', + ), + 3: Field( + name='fat_calories', + type=BASE_TYPES[0x02], # uint8 + def_num=3, + scale=10, + units='kcal/min', + ), + 254: Field( + name='message_index', + type=FIELD_TYPES['message_index'], + def_num=254, + ), + }, + ), + 12: MessageType( + name='sport', + mesg_num=12, + 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, + ), + 3: Field( + name='name', + type=BASE_TYPES[0x07], # string + def_num=3, + ), + }, + ), + 18: MessageType( + name='session', + mesg_num=18, + fields={ + 0: Field( # session + name='event', + type=FIELD_TYPES['event'], + def_num=0, + ), + 1: Field( # stop + name='event_type', + type=FIELD_TYPES['event_type'], + def_num=1, + ), + 2: Field( + name='start_time', + type=FIELD_TYPES['date_time'], + def_num=2, + ), + 3: Field( + name='start_position_lat', + type=BASE_TYPES[0x85], # sint32 + def_num=3, + units='semicircles', + ), + 4: Field( + name='start_position_long', + type=BASE_TYPES[0x85], # sint32 + def_num=4, + units='semicircles', + ), + 5: Field( + name='sport', + type=FIELD_TYPES['sport'], + def_num=5, + ), + 6: Field( + name='sub_sport', + type=FIELD_TYPES['sub_sport'], + def_num=6, + ), + 7: Field( # Time (includes pauses) + name='total_elapsed_time', + type=BASE_TYPES[0x86], # uint32 + def_num=7, + scale=1000, + units='s', + ), + 8: Field( # Timer Time (excludes pauses) + name='total_timer_time', + type=BASE_TYPES[0x86], # uint32 + def_num=8, + scale=1000, + units='s', + ), + 9: Field( + name='total_distance', + type=BASE_TYPES[0x86], # uint32 + def_num=9, + scale=100, + units='m', + ), + 10: Field( + name='total_cycles', + type=BASE_TYPES[0x86], # uint32 + def_num=10, + units='cycles', + subfields=( + SubField( + name='total_strides', + def_num=10, + type=BASE_TYPES[0x86], # uint32 + units='strides', + ref_fields=( + ReferenceField( + name='sport', + def_num=5, + value='running', + raw_value=1, + ), + ReferenceField( + name='sport', + def_num=5, + value='walking', + raw_value=11, + ), + ), + ), + ), + ), + 11: Field( + name='total_calories', + type=BASE_TYPES[0x84], # uint16 + def_num=11, + units='kcal', + ), + 13: Field( + name='total_fat_calories', + type=BASE_TYPES[0x84], # uint16 + def_num=13, + units='kcal', + ), + 14: Field( # total_distance / total_timer_time + name='avg_speed', + type=BASE_TYPES[0x84], # uint16 + def_num=14, + components=( + ComponentField( + name='enhanced_avg_speed', + def_num=124, + scale=1000, + units='m/s', + accumulate=False, + bits=16, + bit_offset=0, + ), + ), + ), + 15: Field( + name='max_speed', + type=BASE_TYPES[0x84], # uint16 + def_num=15, + components=( + ComponentField( + name='enhanced_max_speed', + def_num=125, + scale=1000, + units='m/s', + accumulate=False, + bits=16, + bit_offset=0, + ), + ), + ), + 16: Field( # average heart rate (excludes pause time) + name='avg_heart_rate', + type=BASE_TYPES[0x02], # uint8 + def_num=16, + units='bpm', + ), + 17: Field( + name='max_heart_rate', + type=BASE_TYPES[0x02], # uint8 + def_num=17, + units='bpm', + ), + 18: Field( # total_cycles / total_timer_time if non_zero_avg_cadence otherwise total_cycles / total_elapsed_time + name='avg_cadence', + type=BASE_TYPES[0x02], # uint8 + def_num=18, + units='rpm', + subfields=( + SubField( + name='avg_running_cadence', + def_num=18, + type=BASE_TYPES[0x02], # uint8 + units='strides/min', + ref_fields=( + ReferenceField( + name='sport', + def_num=5, + value='running', + raw_value=1, + ), + ), + ), + ), + ), + 19: Field( + name='max_cadence', + type=BASE_TYPES[0x02], # uint8 + def_num=19, + units='rpm', + subfields=( + SubField( + name='max_running_cadence', + def_num=19, + type=BASE_TYPES[0x02], # uint8 + units='strides/min', + ref_fields=( + ReferenceField( + name='sport', + def_num=5, + value='running', + raw_value=1, + ), + ), + ), + ), + ), + 20: Field( # total_power / total_timer_time if non_zero_avg_power otherwise total_power / total_elapsed_time + name='avg_power', + type=BASE_TYPES[0x84], # uint16 + def_num=20, + units='watts', + ), + 21: Field( + name='max_power', + type=BASE_TYPES[0x84], # uint16 + def_num=21, + units='watts', + ), + 22: Field( + name='total_ascent', + type=BASE_TYPES[0x84], # uint16 + def_num=22, + units='m', + ), + 23: Field( + name='total_descent', + type=BASE_TYPES[0x84], # uint16 + def_num=23, + units='m', + ), + 24: Field( + name='total_training_effect', + type=BASE_TYPES[0x02], # uint8 + def_num=24, + scale=10, + ), + 25: Field( + name='first_lap_index', + type=BASE_TYPES[0x84], # uint16 + def_num=25, + ), + 26: Field( + name='num_laps', + type=BASE_TYPES[0x84], # uint16 + def_num=26, + ), + 27: Field( + name='event_group', + type=BASE_TYPES[0x02], # uint8 + def_num=27, + ), + 28: Field( + name='trigger', + type=FIELD_TYPES['session_trigger'], + def_num=28, + ), + 29: Field( + name='nec_lat', + type=BASE_TYPES[0x85], # sint32 + def_num=29, + units='semicircles', + ), + 30: Field( + name='nec_long', + type=BASE_TYPES[0x85], # sint32 + def_num=30, + units='semicircles', + ), + 31: Field( + name='swc_lat', + type=BASE_TYPES[0x85], # sint32 + def_num=31, + units='semicircles', + ), + 32: Field( + name='swc_long', + type=BASE_TYPES[0x85], # sint32 + def_num=32, + units='semicircles', + ), + 34: Field( + name='normalized_power', + type=BASE_TYPES[0x84], # uint16 + def_num=34, + units='watts', + ), + 35: Field( + name='training_stress_score', + type=BASE_TYPES[0x84], # uint16 + def_num=35, + scale=10, + units='tss', + ), + 36: Field( + name='intensity_factor', + type=BASE_TYPES[0x84], # uint16 + def_num=36, + scale=1000, + units='if', + ), + 37: Field( + name='left_right_balance', + type=FIELD_TYPES['left_right_balance_100'], + def_num=37, + ), + 41: Field( + name='avg_stroke_count', + type=BASE_TYPES[0x86], # uint32 + def_num=41, + scale=10, + units='strokes/lap', + ), + 42: Field( + name='avg_stroke_distance', + type=BASE_TYPES[0x84], # uint16 + def_num=42, + scale=100, + units='m', + ), + 43: Field( + name='swim_stroke', + type=FIELD_TYPES['swim_stroke'], + def_num=43, + units='swim_stroke', + ), + 44: Field( + name='pool_length', + type=BASE_TYPES[0x84], # uint16 + def_num=44, + scale=100, + units='m', + ), + 45: Field( + name='threshold_power', + type=BASE_TYPES[0x84], # uint16 + def_num=45, + units='watts', + ), + 46: Field( + name='pool_length_unit', + type=FIELD_TYPES['display_measure'], + def_num=46, + ), + 47: Field( # # of active lengths of swim pool + name='num_active_lengths', + type=BASE_TYPES[0x84], # uint16 + def_num=47, + units='lengths', + ), + 48: Field( + name='total_work', + type=BASE_TYPES[0x86], # uint32 + def_num=48, + units='J', + ), + 49: Field( + name='avg_altitude', + type=BASE_TYPES[0x84], # uint16 + def_num=49, + components=( + ComponentField( + name='enhanced_avg_altitude', + def_num=126, + scale=5, + offset=500, + units='m', + accumulate=False, + bits=16, + bit_offset=0, + ), + ), + ), + 50: Field( + name='max_altitude', + type=BASE_TYPES[0x84], # uint16 + def_num=50, + components=( + ComponentField( + name='enhanced_max_altitude', + def_num=128, + scale=5, + offset=500, + units='m', + accumulate=False, + bits=16, + bit_offset=0, + ), + ), + ), + 51: Field( + name='gps_accuracy', + type=BASE_TYPES[0x02], # uint8 + def_num=51, + units='m', + ), + 52: Field( + name='avg_grade', + type=BASE_TYPES[0x83], # sint16 + def_num=52, + scale=100, + units='%', + ), + 53: Field( + name='avg_pos_grade', + type=BASE_TYPES[0x83], # sint16 + def_num=53, + scale=100, + units='%', + ), + 54: Field( + name='avg_neg_grade', + type=BASE_TYPES[0x83], # sint16 + def_num=54, + scale=100, + units='%', + ), + 55: Field( + name='max_pos_grade', + type=BASE_TYPES[0x83], # sint16 + def_num=55, + scale=100, + units='%', + ), + 56: Field( + name='max_neg_grade', + type=BASE_TYPES[0x83], # sint16 + def_num=56, + scale=100, + units='%', + ), + 57: Field( + name='avg_temperature', + type=BASE_TYPES[0x01], # sint8 + def_num=57, + units='C', + ), + 58: Field( + name='max_temperature', + type=BASE_TYPES[0x01], # sint8 + def_num=58, + units='C', + ), + 59: Field( + name='total_moving_time', + type=BASE_TYPES[0x86], # uint32 + def_num=59, + scale=1000, + units='s', + ), + 60: Field( + name='avg_pos_vertical_speed', + type=BASE_TYPES[0x83], # sint16 + def_num=60, + scale=1000, + units='m/s', + ), + 61: Field( + name='avg_neg_vertical_speed', + type=BASE_TYPES[0x83], # sint16 + def_num=61, + scale=1000, + units='m/s', + ), + 62: Field( + name='max_pos_vertical_speed', + type=BASE_TYPES[0x83], # sint16 + def_num=62, + scale=1000, + units='m/s', + ), + 63: Field( + name='max_neg_vertical_speed', + type=BASE_TYPES[0x83], # sint16 + def_num=63, + scale=1000, + units='m/s', + ), + 64: Field( + name='min_heart_rate', + type=BASE_TYPES[0x02], # uint8 + def_num=64, + units='bpm', + ), + 65: Field( + name='time_in_hr_zone', + type=BASE_TYPES[0x86], # uint32 + def_num=65, + scale=1000, + units='s', + ), + 66: Field( + name='time_in_speed_zone', + type=BASE_TYPES[0x86], # uint32 + def_num=66, + scale=1000, + units='s', + ), + 67: Field( + name='time_in_cadence_zone', + type=BASE_TYPES[0x86], # uint32 + def_num=67, + scale=1000, + units='s', + ), + 68: Field( + name='time_in_power_zone', + type=BASE_TYPES[0x86], # uint32 + def_num=68, + scale=1000, + units='s', + ), + 69: Field( + name='avg_lap_time', + type=BASE_TYPES[0x86], # uint32 + def_num=69, + scale=1000, + units='s', + ), + 70: Field( + name='best_lap_index', + type=BASE_TYPES[0x84], # uint16 + def_num=70, + ), + 71: Field( + name='min_altitude', + type=BASE_TYPES[0x84], # uint16 + def_num=71, + components=( + ComponentField( + name='enhanced_min_altitude', + def_num=127, + scale=5, + offset=500, + units='m', + accumulate=False, + bits=16, + bit_offset=0, + ), + ), + ), + 82: Field( + name='player_score', + type=BASE_TYPES[0x84], # uint16 + def_num=82, + ), + 83: Field( + name='opponent_score', + type=BASE_TYPES[0x84], # uint16 + def_num=83, + ), + 84: Field( + name='opponent_name', + type=BASE_TYPES[0x07], # string + def_num=84, + ), + 85: Field( # stroke_type enum used as the index + name='stroke_count', + type=BASE_TYPES[0x84], # uint16 + def_num=85, + units='counts', + ), + 86: Field( # zone number used as the index + name='zone_count', + type=BASE_TYPES[0x84], # uint16 + def_num=86, + units='counts', + ), + 87: Field( + name='max_ball_speed', + type=BASE_TYPES[0x84], # uint16 + def_num=87, + scale=100, + units='m/s', + ), + 88: Field( + name='avg_ball_speed', + type=BASE_TYPES[0x84], # uint16 + def_num=88, + scale=100, + units='m/s', + ), + 89: Field( + name='avg_vertical_oscillation', + type=BASE_TYPES[0x84], # uint16 + def_num=89, + scale=10, + units='mm', + ), + 90: Field( + name='avg_stance_time_percent', + type=BASE_TYPES[0x84], # uint16 + def_num=90, + scale=100, + units='percent', + ), + 91: Field( + name='avg_stance_time', + type=BASE_TYPES[0x84], # uint16 + def_num=91, + scale=10, + units='ms', + ), + 92: Field( # fractional part of the avg_cadence + name='avg_fractional_cadence', + type=BASE_TYPES[0x02], # uint8 + def_num=92, + scale=128, + units='rpm', + ), + 93: Field( # fractional part of the max_cadence + name='max_fractional_cadence', + type=BASE_TYPES[0x02], # uint8 + def_num=93, + scale=128, + units='rpm', + ), + 94: Field( # fractional part of the total_cycles + name='total_fractional_cycles', + type=BASE_TYPES[0x02], # uint8 + def_num=94, + scale=128, + units='cycles', + ), + 95: Field( # Avg saturated and unsaturated hemoglobin + name='avg_total_hemoglobin_conc', + type=BASE_TYPES[0x84], # uint16 + def_num=95, + scale=100, + units='g/dL', + ), + 96: Field( # Min saturated and unsaturated hemoglobin + name='min_total_hemoglobin_conc', + type=BASE_TYPES[0x84], # uint16 + def_num=96, + scale=100, + units='g/dL', + ), + 97: Field( # Max saturated and unsaturated hemoglobin + name='max_total_hemoglobin_conc', + type=BASE_TYPES[0x84], # uint16 + def_num=97, + scale=100, + units='g/dL', + ), + 98: Field( # Avg percentage of hemoglobin saturated with oxygen + name='avg_saturated_hemoglobin_percent', + type=BASE_TYPES[0x84], # uint16 + def_num=98, + scale=10, + units='%', + ), + 99: Field( # Min percentage of hemoglobin saturated with oxygen + name='min_saturated_hemoglobin_percent', + type=BASE_TYPES[0x84], # uint16 + def_num=99, + scale=10, + units='%', + ), + 100: Field( # Max percentage of hemoglobin saturated with oxygen + name='max_saturated_hemoglobin_percent', + type=BASE_TYPES[0x84], # uint16 + def_num=100, + scale=10, + units='%', + ), + 101: Field( + name='avg_left_torque_effectiveness', + type=BASE_TYPES[0x02], # uint8 + def_num=101, + scale=2, + units='percent', + ), + 102: Field( + name='avg_right_torque_effectiveness', + type=BASE_TYPES[0x02], # uint8 + def_num=102, + scale=2, + units='percent', + ), + 103: Field( + name='avg_left_pedal_smoothness', + type=BASE_TYPES[0x02], # uint8 + def_num=103, + scale=2, + units='percent', + ), + 104: Field( + name='avg_right_pedal_smoothness', + type=BASE_TYPES[0x02], # uint8 + def_num=104, + scale=2, + units='percent', + ), + 105: Field( + name='avg_combined_pedal_smoothness', + type=BASE_TYPES[0x02], # uint8 + def_num=105, + scale=2, + units='percent', + ), + 111: Field( + name='sport_index', + type=BASE_TYPES[0x02], # uint8 + def_num=111, + ), + 112: Field( # Total time spend in the standing position + name='time_standing', + type=BASE_TYPES[0x86], # uint32 + def_num=112, + scale=1000, + units='s', + ), + 113: Field( # Number of transitions to the standing state + name='stand_count', + type=BASE_TYPES[0x84], # uint16 + def_num=113, + ), + 114: Field( # Average platform center offset Left + name='avg_left_pco', + type=BASE_TYPES[0x01], # sint8 + def_num=114, + units='mm', + ), + 115: Field( # Average platform center offset Right + name='avg_right_pco', + type=BASE_TYPES[0x01], # sint8 + def_num=115, + units='mm', + ), + 116: Field( # Average left power phase angles. Indexes defined by power_phase_type. + name='avg_left_power_phase', + type=BASE_TYPES[0x02], # uint8 + def_num=116, + scale=0.7111111, + units='degrees', + ), + 117: 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=117, + scale=0.7111111, + units='degrees', + ), + 118: 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=118, + scale=0.7111111, + units='degrees', + ), + 119: 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=119, + scale=0.7111111, + units='degrees', + ), + 120: Field( # Average power by position. Data value indexes defined by rider_position_type. + name='avg_power_position', + type=BASE_TYPES[0x84], # uint16 + def_num=120, + units='watts', + ), + 121: Field( # Maximum power by position. Data value indexes defined by rider_position_type. + name='max_power_position', + type=BASE_TYPES[0x84], # uint16 + def_num=121, + units='watts', + ), + 122: Field( # Average cadence by position. Data value indexes defined by rider_position_type. + name='avg_cadence_position', + type=BASE_TYPES[0x02], # uint8 + def_num=122, + units='rpm', + ), + 123: Field( # Maximum cadence by position. Data value indexes defined by rider_position_type. + name='max_cadence_position', + type=BASE_TYPES[0x02], # uint8 + def_num=123, + units='rpm', + ), + 124: Field( # total_distance / total_timer_time + name='enhanced_avg_speed', + type=BASE_TYPES[0x86], # uint32 + def_num=124, + scale=1000, + units='m/s', + ), + 125: Field( + name='enhanced_max_speed', + type=BASE_TYPES[0x86], # uint32 + def_num=125, + scale=1000, + units='m/s', + ), + 126: Field( + name='enhanced_avg_altitude', + type=BASE_TYPES[0x86], # uint32 + def_num=126, + scale=5, + offset=500, + units='m', + ), + 127: Field( + name='enhanced_min_altitude', + type=BASE_TYPES[0x86], # uint32 + def_num=127, + scale=5, + offset=500, + units='m', + ), + 128: Field( + name='enhanced_max_altitude', + type=BASE_TYPES[0x86], # uint32 + def_num=128, + scale=5, + offset=500, + units='m', + ), + 129: Field( # lev average motor power during session + name='avg_lev_motor_power', + type=BASE_TYPES[0x84], # uint16 + def_num=129, + units='watts', + ), + 130: Field( # lev maximum motor power during session + name='max_lev_motor_power', + type=BASE_TYPES[0x84], # uint16 + def_num=130, + units='watts', + ), + 131: Field( # lev battery consumption during session + name='lev_battery_consumption', + type=BASE_TYPES[0x02], # uint8 + def_num=131, + scale=2, + units='percent', + ), + 132: Field( + name='avg_vertical_ratio', + type=BASE_TYPES[0x84], # uint16 + def_num=132, + scale=100, + units='percent', + ), + 133: Field( + name='avg_stance_time_balance', + type=BASE_TYPES[0x84], # uint16 + def_num=133, + scale=100, + units='percent', + ), + 134: Field( + name='avg_step_length', + type=BASE_TYPES[0x84], # uint16 + def_num=134, + scale=10, + units='mm', + ), + 137: Field( + name='total_anaerobic_training_effect', + type=BASE_TYPES[0x02], # uint8 + def_num=137, + scale=10, + ), + 139: Field( + name='avg_vam', + type=BASE_TYPES[0x84], # uint16 + def_num=139, + scale=1000, + units='m/s', + ), + 253: FIELD_TYPE_TIMESTAMP, # Sesson end time. + 254: Field( # Selected bit is set for the current session. + name='message_index', + type=FIELD_TYPES['message_index'], + def_num=254, + ), + }, + ), + 19: MessageType( + name='lap', + mesg_num=19, + 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='start_time', + type=FIELD_TYPES['date_time'], + def_num=2, + ), + 3: Field( + name='start_position_lat', + type=BASE_TYPES[0x85], # sint32 + def_num=3, + units='semicircles', + ), + 4: Field( + name='start_position_long', + type=BASE_TYPES[0x85], # sint32 + def_num=4, + units='semicircles', + ), + 5: Field( + name='end_position_lat', + type=BASE_TYPES[0x85], # sint32 + def_num=5, + units='semicircles', + ), + 6: Field( + name='end_position_long', + type=BASE_TYPES[0x85], # sint32 + def_num=6, + units='semicircles', + ), + 7: Field( # Time (includes pauses) + name='total_elapsed_time', + type=BASE_TYPES[0x86], # uint32 + def_num=7, + scale=1000, + units='s', + ), + 8: Field( # Timer Time (excludes pauses) + name='total_timer_time', + type=BASE_TYPES[0x86], # uint32 + def_num=8, + scale=1000, + units='s', + ), + 9: Field( + name='total_distance', + type=BASE_TYPES[0x86], # uint32 + def_num=9, + scale=100, + units='m', + ), + 10: Field( + name='total_cycles', + type=BASE_TYPES[0x86], # uint32 + def_num=10, + units='cycles', + subfields=( + SubField( + name='total_strides', + def_num=10, + type=BASE_TYPES[0x86], # uint32 + units='strides', + ref_fields=( + ReferenceField( + name='sport', + def_num=25, + value='running', + raw_value=1, + ), + ReferenceField( + name='sport', + def_num=25, + value='walking', + raw_value=11, + ), + ), + ), + ), + ), + 11: Field( + name='total_calories', + type=BASE_TYPES[0x84], # uint16 + def_num=11, + units='kcal', + ), + 12: Field( # If New Leaf + name='total_fat_calories', + type=BASE_TYPES[0x84], # uint16 + def_num=12, + units='kcal', + ), + 13: Field( + name='avg_speed', + type=BASE_TYPES[0x84], # uint16 + def_num=13, + components=( + ComponentField( + name='enhanced_avg_speed', + def_num=110, + scale=1000, + units='m/s', + accumulate=False, + bits=16, + bit_offset=0, + ), + ), + ), + 14: Field( + name='max_speed', + type=BASE_TYPES[0x84], # uint16 + def_num=14, + components=( + ComponentField( + name='enhanced_max_speed', + def_num=111, + scale=1000, + units='m/s', + accumulate=False, + bits=16, + bit_offset=0, + ), + ), + ), + 15: Field( + name='avg_heart_rate', + type=BASE_TYPES[0x02], # uint8 + def_num=15, + units='bpm', + ), + 16: Field( + name='max_heart_rate', + type=BASE_TYPES[0x02], # uint8 + def_num=16, + units='bpm', + ), + 17: Field( # total_cycles / total_timer_time if non_zero_avg_cadence otherwise total_cycles / total_elapsed_time + name='avg_cadence', + type=BASE_TYPES[0x02], # uint8 + def_num=17, + units='rpm', + subfields=( + SubField( + name='avg_running_cadence', + def_num=17, + type=BASE_TYPES[0x02], # uint8 + units='strides/min', + ref_fields=( + ReferenceField( + name='sport', + def_num=25, + value='running', + raw_value=1, + ), + ), + ), + ), + ), + 18: Field( + name='max_cadence', + type=BASE_TYPES[0x02], # uint8 + def_num=18, + units='rpm', + subfields=( + SubField( + name='max_running_cadence', + def_num=18, + type=BASE_TYPES[0x02], # uint8 + units='strides/min', + ref_fields=( + ReferenceField( + name='sport', + def_num=25, + value='running', + raw_value=1, + ), + ), + ), + ), + ), + 19: Field( # total_power / total_timer_time if non_zero_avg_power otherwise total_power / total_elapsed_time + name='avg_power', + type=BASE_TYPES[0x84], # uint16 + def_num=19, + units='watts', + ), + 20: Field( + name='max_power', + type=BASE_TYPES[0x84], # uint16 + def_num=20, + units='watts', + ), + 21: Field( + name='total_ascent', + type=BASE_TYPES[0x84], # uint16 + def_num=21, + units='m', + ), + 22: Field( + name='total_descent', + type=BASE_TYPES[0x84], # uint16 + def_num=22, + units='m', + ), + 23: Field( + name='intensity', + type=FIELD_TYPES['intensity'], + def_num=23, + ), + 24: Field( + name='lap_trigger', + type=FIELD_TYPES['lap_trigger'], + def_num=24, + ), + 25: Field( + name='sport', + type=FIELD_TYPES['sport'], + def_num=25, + ), + 26: Field( + name='event_group', + type=BASE_TYPES[0x02], # uint8 + def_num=26, + ), + 32: Field( # # of lengths of swim pool + name='num_lengths', + type=BASE_TYPES[0x84], # uint16 + def_num=32, + units='lengths', + ), + 33: Field( + name='normalized_power', + type=BASE_TYPES[0x84], # uint16 + def_num=33, + units='watts', + ), + 34: Field( + name='left_right_balance', + type=FIELD_TYPES['left_right_balance_100'], + def_num=34, + ), + 35: Field( + name='first_length_index', + type=BASE_TYPES[0x84], # uint16 + def_num=35, + ), + 37: Field( + name='avg_stroke_distance', + type=BASE_TYPES[0x84], # uint16 + def_num=37, + scale=100, + units='m', + ), + 38: Field( + name='swim_stroke', + type=FIELD_TYPES['swim_stroke'], + def_num=38, + ), + 39: Field( + name='sub_sport', + type=FIELD_TYPES['sub_sport'], + def_num=39, + ), + 40: Field( # # of active lengths of swim pool + name='num_active_lengths', + type=BASE_TYPES[0x84], # uint16 + def_num=40, + units='lengths', + ), + 41: Field( + name='total_work', + type=BASE_TYPES[0x86], # uint32 + def_num=41, + units='J', + ), + 42: Field( + name='avg_altitude', + type=BASE_TYPES[0x84], # uint16 + def_num=42, + components=( + ComponentField( + name='enhanced_avg_altitude', + def_num=112, + scale=5, + offset=500, + units='m', + accumulate=False, + bits=16, + bit_offset=0, + ), + ), + ), + 43: Field( + name='max_altitude', + type=BASE_TYPES[0x84], # uint16 + def_num=43, + components=( + ComponentField( + name='enhanced_max_altitude', + def_num=114, + scale=5, + offset=500, + units='m', + accumulate=False, + bits=16, + bit_offset=0, + ), + ), + ), + 44: Field( + name='gps_accuracy', + type=BASE_TYPES[0x02], # uint8 + def_num=44, + units='m', + ), + 45: Field( + name='avg_grade', + type=BASE_TYPES[0x83], # sint16 + def_num=45, + scale=100, + units='%', + ), + 46: Field( + name='avg_pos_grade', + type=BASE_TYPES[0x83], # sint16 + def_num=46, + scale=100, + units='%', + ), + 47: Field( + name='avg_neg_grade', + type=BASE_TYPES[0x83], # sint16 + def_num=47, + scale=100, + units='%', + ), + 48: Field( + name='max_pos_grade', + type=BASE_TYPES[0x83], # sint16 + def_num=48, + scale=100, + units='%', + ), + 49: Field( + name='max_neg_grade', + type=BASE_TYPES[0x83], # sint16 + def_num=49, + scale=100, + units='%', + ), + 50: Field( + name='avg_temperature', + type=BASE_TYPES[0x01], # sint8 + def_num=50, + units='C', + ), + 51: Field( + name='max_temperature', + type=BASE_TYPES[0x01], # sint8 + def_num=51, + units='C', + ), + 52: Field( + name='total_moving_time', + type=BASE_TYPES[0x86], # uint32 + def_num=52, + scale=1000, + units='s', + ), + 53: Field( + name='avg_pos_vertical_speed', + type=BASE_TYPES[0x83], # sint16 + def_num=53, + scale=1000, + units='m/s', + ), + 54: Field( + name='avg_neg_vertical_speed', + type=BASE_TYPES[0x83], # sint16 + def_num=54, + scale=1000, + units='m/s', + ), + 55: Field( + name='max_pos_vertical_speed', + type=BASE_TYPES[0x83], # sint16 + def_num=55, + scale=1000, + units='m/s', + ), + 56: Field( + name='max_neg_vertical_speed', + type=BASE_TYPES[0x83], # sint16 + def_num=56, + scale=1000, + units='m/s', + ), + 57: Field( + name='time_in_hr_zone', + type=BASE_TYPES[0x86], # uint32 + def_num=57, + scale=1000, + units='s', + ), + 58: Field( + name='time_in_speed_zone', + type=BASE_TYPES[0x86], # uint32 + def_num=58, + scale=1000, + units='s', + ), + 59: Field( + name='time_in_cadence_zone', + type=BASE_TYPES[0x86], # uint32 + def_num=59, + scale=1000, + units='s', + ), + 60: Field( + name='time_in_power_zone', + type=BASE_TYPES[0x86], # uint32 + def_num=60, + scale=1000, + units='s', + ), + 61: Field( + name='repetition_num', + type=BASE_TYPES[0x84], # uint16 + def_num=61, + ), + 62: Field( + name='min_altitude', + type=BASE_TYPES[0x84], # uint16 + def_num=62, + components=( + ComponentField( + name='enhanced_min_altitude', + def_num=113, + scale=5, + offset=500, + units='m', + accumulate=False, + bits=16, + bit_offset=0, + ), + ), + ), + 63: Field( + name='min_heart_rate', + type=BASE_TYPES[0x02], # uint8 + def_num=63, + units='bpm', + ), + 71: Field( + name='wkt_step_index', + type=FIELD_TYPES['message_index'], + def_num=71, + ), + 74: Field( + name='opponent_score', + type=BASE_TYPES[0x84], # uint16 + def_num=74, + ), + 75: Field( # stroke_type enum used as the index + name='stroke_count', + type=BASE_TYPES[0x84], # uint16 + def_num=75, + units='counts', + ), + 76: Field( # zone number used as the index + name='zone_count', + type=BASE_TYPES[0x84], # uint16 + def_num=76, + units='counts', + ), + 77: Field( + name='avg_vertical_oscillation', + type=BASE_TYPES[0x84], # uint16 + def_num=77, + scale=10, + units='mm', + ), + 78: Field( + name='avg_stance_time_percent', + type=BASE_TYPES[0x84], # uint16 + def_num=78, + scale=100, + units='percent', + ), + 79: Field( + name='avg_stance_time', + type=BASE_TYPES[0x84], # uint16 + def_num=79, + scale=10, + units='ms', + ), + 80: Field( # fractional part of the avg_cadence + name='avg_fractional_cadence', + type=BASE_TYPES[0x02], # uint8 + def_num=80, + scale=128, + units='rpm', + ), + 81: Field( # fractional part of the max_cadence + name='max_fractional_cadence', + type=BASE_TYPES[0x02], # uint8 + def_num=81, + scale=128, + units='rpm', + ), + 82: Field( # fractional part of the total_cycles + name='total_fractional_cycles', + type=BASE_TYPES[0x02], # uint8 + def_num=82, + scale=128, + units='cycles', + ), + 83: Field( + name='player_score', + type=BASE_TYPES[0x84], # uint16 + def_num=83, + ), + 84: Field( # Avg saturated and unsaturated hemoglobin + name='avg_total_hemoglobin_conc', + type=BASE_TYPES[0x84], # uint16 + def_num=84, + scale=100, + units='g/dL', + ), + 85: Field( # Min saturated and unsaturated hemoglobin + name='min_total_hemoglobin_conc', + type=BASE_TYPES[0x84], # uint16 + def_num=85, + scale=100, + units='g/dL', + ), + 86: Field( # Max saturated and unsaturated hemoglobin + name='max_total_hemoglobin_conc', + type=BASE_TYPES[0x84], # uint16 + def_num=86, + scale=100, + units='g/dL', + ), + 87: Field( # Avg percentage of hemoglobin saturated with oxygen + name='avg_saturated_hemoglobin_percent', + type=BASE_TYPES[0x84], # uint16 + def_num=87, + scale=10, + units='%', + ), + 88: Field( # Min percentage of hemoglobin saturated with oxygen + name='min_saturated_hemoglobin_percent', + type=BASE_TYPES[0x84], # uint16 + def_num=88, + scale=10, + units='%', + ), + 89: Field( # Max percentage of hemoglobin saturated with oxygen + name='max_saturated_hemoglobin_percent', + type=BASE_TYPES[0x84], # uint16 + def_num=89, + scale=10, + units='%', + ), + 91: Field( + name='avg_left_torque_effectiveness', + type=BASE_TYPES[0x02], # uint8 + def_num=91, + scale=2, + units='percent', + ), + 92: Field( + name='avg_right_torque_effectiveness', + type=BASE_TYPES[0x02], # uint8 + def_num=92, + scale=2, + units='percent', + ), + 93: Field( + name='avg_left_pedal_smoothness', + type=BASE_TYPES[0x02], # uint8 + def_num=93, + scale=2, + units='percent', + ), + 94: Field( + name='avg_right_pedal_smoothness', + type=BASE_TYPES[0x02], # uint8 + def_num=94, + scale=2, + units='percent', + ), + 95: Field( + name='avg_combined_pedal_smoothness', + type=BASE_TYPES[0x02], # uint8 + def_num=95, + scale=2, + units='percent', + ), + 98: Field( # Total time spent in the standing position + name='time_standing', + type=BASE_TYPES[0x86], # uint32 + def_num=98, + scale=1000, + units='s', + ), + 99: Field( # Number of transitions to the standing state + name='stand_count', + type=BASE_TYPES[0x84], # uint16 + def_num=99, + ), + 100: Field( # Average left platform center offset + name='avg_left_pco', + type=BASE_TYPES[0x01], # sint8 + def_num=100, + units='mm', + ), + 101: Field( # Average right platform center offset + name='avg_right_pco', + type=BASE_TYPES[0x01], # sint8 + def_num=101, + units='mm', + ), + 102: 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=102, + scale=0.7111111, + units='degrees', + ), + 103: 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=103, + scale=0.7111111, + units='degrees', + ), + 104: 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=104, + scale=0.7111111, + units='degrees', + ), + 105: 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=105, + scale=0.7111111, + units='degrees', + ), + 106: Field( # Average power by position. Data value indexes defined by rider_position_type. + name='avg_power_position', + type=BASE_TYPES[0x84], # uint16 + def_num=106, + units='watts', + ), + 107: Field( # Maximum power by position. Data value indexes defined by rider_position_type. + name='max_power_position', + type=BASE_TYPES[0x84], # uint16 + def_num=107, + units='watts', + ), + 108: Field( # Average cadence by position. Data value indexes defined by rider_position_type. + name='avg_cadence_position', + type=BASE_TYPES[0x02], # uint8 + def_num=108, + units='rpm', + ), + 109: Field( # Maximum cadence by position. Data value indexes defined by rider_position_type. + name='max_cadence_position', + type=BASE_TYPES[0x02], # uint8 + def_num=109, + units='rpm', + ), + 110: Field( + name='enhanced_avg_speed', + type=BASE_TYPES[0x86], # uint32 + def_num=110, + scale=1000, + units='m/s', + ), + 111: Field( + name='enhanced_max_speed', + type=BASE_TYPES[0x86], # uint32 + def_num=111, + scale=1000, + units='m/s', + ), + 112: Field( + name='enhanced_avg_altitude', + type=BASE_TYPES[0x86], # uint32 + def_num=112, + scale=5, + offset=500, + units='m', + ), + 113: Field( + name='enhanced_min_altitude', + type=BASE_TYPES[0x86], # uint32 + def_num=113, + scale=5, + offset=500, + units='m', + ), + 114: Field( + name='enhanced_max_altitude', + type=BASE_TYPES[0x86], # uint32 + def_num=114, + scale=5, + offset=500, + units='m', + ), + 115: Field( # lev average motor power during lap + name='avg_lev_motor_power', + type=BASE_TYPES[0x84], # uint16 + def_num=115, + units='watts', + ), + 116: Field( # lev maximum motor power during lap + name='max_lev_motor_power', + type=BASE_TYPES[0x84], # uint16 + def_num=116, + units='watts', + ), + 117: Field( # lev battery consumption during lap + name='lev_battery_consumption', + type=BASE_TYPES[0x02], # uint8 + def_num=117, + scale=2, + units='percent', + ), + 118: Field( + name='avg_vertical_ratio', + type=BASE_TYPES[0x84], # uint16 + def_num=118, + scale=100, + units='percent', + ), + 119: Field( + name='avg_stance_time_balance', + type=BASE_TYPES[0x84], # uint16 + def_num=119, + scale=100, + units='percent', + ), + 120: Field( + name='avg_step_length', + type=BASE_TYPES[0x84], # uint16 + def_num=120, + scale=10, + units='mm', + ), + 121: Field( + name='avg_vam', + type=BASE_TYPES[0x84], # uint16 + def_num=121, + scale=1000, + units='m/s', + ), + 253: FIELD_TYPE_TIMESTAMP, # Lap end time. + 254: Field( + name='message_index', + type=FIELD_TYPES['message_index'], + def_num=254, + ), + }, + ), + 20: MessageType( + name='record', + mesg_num=20, + fields={ + 0: Field( + name='position_lat', + type=BASE_TYPES[0x85], # sint32 + def_num=0, + units='semicircles', + ), + 1: Field( + name='position_long', + type=BASE_TYPES[0x85], # sint32 + def_num=1, + units='semicircles', + ), + 2: Field( + name='altitude', + type=BASE_TYPES[0x84], # uint16 + def_num=2, + components=( + ComponentField( + name='enhanced_altitude', + def_num=78, + scale=5, + offset=500, + units='m', + accumulate=False, + bits=16, + bit_offset=0, + ), + ), + ), + 3: Field( + name='heart_rate', + type=BASE_TYPES[0x02], # uint8 + def_num=3, + units='bpm', + ), + 4: Field( + name='cadence', + type=BASE_TYPES[0x02], # uint8 + def_num=4, + units='rpm', + ), + 5: Field( + name='distance', + type=BASE_TYPES[0x86], # uint32 + def_num=5, + scale=100, + units='m', + ), + 6: Field( + name='speed', + type=BASE_TYPES[0x84], # uint16 + def_num=6, + components=( + ComponentField( + name='enhanced_speed', + def_num=73, + scale=1000, + units='m/s', + accumulate=False, + bits=16, + bit_offset=0, + ), + ), + ), + 7: Field( + name='power', + type=BASE_TYPES[0x84], # uint16 + def_num=7, + units='watts', + ), + 8: Field( + name='compressed_speed_distance', + type=BASE_TYPES[0x0D], # byte + def_num=8, + components=( + ComponentField( + name='speed', + def_num=6, + scale=100, + units='m/s', + accumulate=False, + bits=12, + bit_offset=0, + ), + ComponentField( + name='distance', + def_num=5, + scale=16, + units='m', + accumulate=True, + bits=12, + bit_offset=12, + ), + ), + ), + 9: Field( + name='grade', + type=BASE_TYPES[0x83], # sint16 + def_num=9, + scale=100, + units='%', + ), + 10: Field( # Relative. 0 is none 254 is Max. + name='resistance', + type=BASE_TYPES[0x02], # uint8 + def_num=10, + ), + 11: Field( + name='time_from_course', + type=BASE_TYPES[0x85], # sint32 + def_num=11, + scale=1000, + units='s', + ), + 12: Field( + name='cycle_length', + type=BASE_TYPES[0x02], # uint8 + def_num=12, + scale=100, + units='m', + ), + 13: Field( + name='temperature', + type=BASE_TYPES[0x01], # sint8 + def_num=13, + units='C', + ), + 17: Field( # Speed at 1s intervals. Timestamp field indicates time of last array element. + name='speed_1s', + type=BASE_TYPES[0x02], # uint8 + def_num=17, + scale=16, + units='m/s', + ), + 18: Field( + name='cycles', + type=BASE_TYPES[0x02], # uint8 + def_num=18, + components=( + ComponentField( + name='total_cycles', + def_num=19, + units='cycles', + accumulate=True, + bits=8, + bit_offset=0, + ), + ), + ), + 19: Field( + name='total_cycles', + type=BASE_TYPES[0x86], # uint32 + def_num=19, + units='cycles', + ), + 28: Field( + name='compressed_accumulated_power', + type=BASE_TYPES[0x84], # uint16 + def_num=28, + components=( + ComponentField( + name='accumulated_power', + def_num=29, + units='watts', + accumulate=True, + bits=16, + bit_offset=0, + ), + ), + ), + 29: Field( + name='accumulated_power', + type=BASE_TYPES[0x86], # uint32 + def_num=29, + units='watts', + ), + 30: Field( + name='left_right_balance', + type=FIELD_TYPES['left_right_balance'], + def_num=30, + ), + 31: Field( + name='gps_accuracy', + type=BASE_TYPES[0x02], # uint8 + def_num=31, + units='m', + ), + 32: Field( + name='vertical_speed', + type=BASE_TYPES[0x83], # sint16 + def_num=32, + scale=1000, + units='m/s', + ), + 33: Field( + name='calories', + type=BASE_TYPES[0x84], # uint16 + def_num=33, + units='kcal', + ), + 39: Field( + name='vertical_oscillation', + type=BASE_TYPES[0x84], # uint16 + def_num=39, + scale=10, + units='mm', + ), + 40: Field( + name='stance_time_percent', + type=BASE_TYPES[0x84], # uint16 + def_num=40, + scale=100, + units='percent', + ), + 41: Field( + name='stance_time', + type=BASE_TYPES[0x84], # uint16 + def_num=41, + scale=10, + units='ms', + ), + 42: Field( + name='activity_type', + type=FIELD_TYPES['activity_type'], + def_num=42, + ), + 43: Field( + name='left_torque_effectiveness', + type=BASE_TYPES[0x02], # uint8 + def_num=43, + scale=2, + units='percent', + ), + 44: Field( + name='right_torque_effectiveness', + type=BASE_TYPES[0x02], # uint8 + def_num=44, + scale=2, + units='percent', + ), + 45: Field( + name='left_pedal_smoothness', + type=BASE_TYPES[0x02], # uint8 + def_num=45, + scale=2, + units='percent', + ), + 46: Field( + name='right_pedal_smoothness', + type=BASE_TYPES[0x02], # uint8 + def_num=46, + scale=2, + units='percent', + ), + 47: Field( + name='combined_pedal_smoothness', + type=BASE_TYPES[0x02], # uint8 + def_num=47, + scale=2, + units='percent', + ), + 48: Field( + name='time128', + type=BASE_TYPES[0x02], # uint8 + def_num=48, + scale=128, + units='s', + ), + 49: Field( + name='stroke_type', + type=FIELD_TYPES['stroke_type'], + def_num=49, + ), + 50: Field( + name='zone', + type=BASE_TYPES[0x02], # uint8 + def_num=50, + ), + 51: Field( + name='ball_speed', + type=BASE_TYPES[0x84], # uint16 + def_num=51, + scale=100, + units='m/s', + ), + 52: Field( # Log cadence and fractional cadence for backwards compatability + name='cadence256', + type=BASE_TYPES[0x84], # uint16 + def_num=52, + scale=256, + units='rpm', + ), + 53: Field( + name='fractional_cadence', + type=BASE_TYPES[0x02], # uint8 + def_num=53, + scale=128, + units='rpm', + ), + 54: Field( # Total saturated and unsaturated hemoglobin + name='total_hemoglobin_conc', + type=BASE_TYPES[0x84], # uint16 + def_num=54, + scale=100, + units='g/dL', + ), + 55: Field( # Min saturated and unsaturated hemoglobin + name='total_hemoglobin_conc_min', + type=BASE_TYPES[0x84], # uint16 + def_num=55, + scale=100, + units='g/dL', + ), + 56: Field( # Max saturated and unsaturated hemoglobin + name='total_hemoglobin_conc_max', + type=BASE_TYPES[0x84], # uint16 + def_num=56, + scale=100, + units='g/dL', + ), + 57: Field( # Percentage of hemoglobin saturated with oxygen + name='saturated_hemoglobin_percent', + type=BASE_TYPES[0x84], # uint16 + def_num=57, + scale=10, + units='%', + ), + 58: Field( # Min percentage of hemoglobin saturated with oxygen + name='saturated_hemoglobin_percent_min', + type=BASE_TYPES[0x84], # uint16 + def_num=58, + scale=10, + units='%', + ), + 59: Field( # Max percentage of hemoglobin saturated with oxygen + name='saturated_hemoglobin_percent_max', + type=BASE_TYPES[0x84], # uint16 + def_num=59, + scale=10, + units='%', + ), + 62: Field( + name='device_index', + type=FIELD_TYPES['device_index'], + def_num=62, + ), + 67: Field( # Left platform center offset + name='left_pco', + type=BASE_TYPES[0x01], # sint8 + def_num=67, + units='mm', + ), + 68: Field( # Right platform center offset + name='right_pco', + type=BASE_TYPES[0x01], # sint8 + def_num=68, + units='mm', + ), + 69: Field( # Left power phase angles. Data value indexes defined by power_phase_type. + name='left_power_phase', + type=BASE_TYPES[0x02], # uint8 + def_num=69, + scale=0.7111111, + units='degrees', + ), + 70: Field( # Left power phase peak angles. Data value indexes defined by power_phase_type. + name='left_power_phase_peak', + type=BASE_TYPES[0x02], # uint8 + def_num=70, + scale=0.7111111, + units='degrees', + ), + 71: Field( # Right power phase angles. Data value indexes defined by power_phase_type. + name='right_power_phase', + type=BASE_TYPES[0x02], # uint8 + def_num=71, + scale=0.7111111, + units='degrees', + ), + 72: Field( # Right power phase peak angles. Data value indexes defined by power_phase_type. + name='right_power_phase_peak', + type=BASE_TYPES[0x02], # uint8 + def_num=72, + scale=0.7111111, + units='degrees', + ), + 73: Field( + name='enhanced_speed', + type=BASE_TYPES[0x86], # uint32 + def_num=73, + scale=1000, + units='m/s', + ), + 78: Field( + name='enhanced_altitude', + type=BASE_TYPES[0x86], # uint32 + def_num=78, + scale=5, + offset=500, + units='m', + ), + 81: Field( # lev battery state of charge + name='battery_soc', + type=BASE_TYPES[0x02], # uint8 + def_num=81, + scale=2, + units='percent', + ), + 82: Field( # lev motor power + name='motor_power', + type=BASE_TYPES[0x84], # uint16 + def_num=82, + units='watts', + ), + 83: Field( + name='vertical_ratio', + type=BASE_TYPES[0x84], # uint16 + def_num=83, + scale=100, + units='percent', + ), + 84: Field( + name='stance_time_balance', + type=BASE_TYPES[0x84], # uint16 + def_num=84, + scale=100, + units='percent', + ), + 85: Field( + name='step_length', + type=BASE_TYPES[0x84], # uint16 + def_num=85, + scale=10, + units='mm', + ), + 91: Field( # Includes atmospheric pressure + name='absolute_pressure', + type=BASE_TYPES[0x86], # uint32 + def_num=91, + units='Pa', + ), + 92: Field( # 0 if above water + name='depth', + type=BASE_TYPES[0x86], # uint32 + def_num=92, + scale=1000, + units='m', + ), + 93: Field( # 0 if above water + name='next_stop_depth', + type=BASE_TYPES[0x86], # uint32 + def_num=93, + scale=1000, + units='m', + ), + 94: Field( + name='next_stop_time', + type=BASE_TYPES[0x86], # uint32 + def_num=94, + units='s', + ), + 95: Field( + name='time_to_surface', + type=BASE_TYPES[0x86], # uint32 + def_num=95, + units='s', + ), + 96: Field( + name='ndl_time', + type=BASE_TYPES[0x86], # uint32 + def_num=96, + units='s', + ), + 97: Field( + name='cns_load', + type=BASE_TYPES[0x02], # uint8 + def_num=97, + units='percent', + ), + 98: Field( + name='n2_load', + type=BASE_TYPES[0x84], # uint16 + 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, + ), + 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, + bits=16, + bit_offset=0, + ), + ), + ), + 3: Field( + name='data', + type=BASE_TYPES[0x86], # uint32 + def_num=3, + subfields=( + SubField( + name='battery_level', + def_num=3, + type=BASE_TYPES[0x84], # uint16 + scale=1000, + units='V', + ref_fields=( + ReferenceField( + name='event', + def_num=0, + value='battery', + raw_value=11, + ), + ), + ), + SubField( + name='cad_high_alert', + def_num=3, + type=BASE_TYPES[0x84], # uint16 + units='rpm', + ref_fields=( + ReferenceField( + name='event', + def_num=0, + value='cad_high_alert', + raw_value=17, + ), + ), + ), + SubField( + name='cad_low_alert', + def_num=3, + type=BASE_TYPES[0x84], # uint16 + units='rpm', + ref_fields=( + ReferenceField( + name='event', + def_num=0, + value='cad_low_alert', + raw_value=18, + ), + ), + ), + SubField( + name='calorie_duration_alert', + def_num=3, + type=BASE_TYPES[0x86], # uint32 + units='calories', + ref_fields=( + ReferenceField( + name='event', + def_num=0, + value='calorie_duration_alert', + raw_value=25, + ), + ), + ), + SubField( + name='comm_timeout', + def_num=3, + type=FIELD_TYPES['comm_timeout_type'], + ref_fields=( + ReferenceField( + name='event', + def_num=0, + value='comm_timeout', + raw_value=47, + ), + ), + ), + SubField( + name='course_point_index', + def_num=3, + type=FIELD_TYPES['message_index'], + ref_fields=( + ReferenceField( + name='event', + def_num=0, + value='course_point', + raw_value=10, + ), + ), + ), + SubField( + name='distance_duration_alert', + def_num=3, + type=BASE_TYPES[0x86], # uint32 + scale=100, + units='m', + ref_fields=( + ReferenceField( + name='event', + def_num=0, + value='distance_duration_alert', + raw_value=24, + ), + ), + ), + SubField( + name='fitness_equipment_state', + def_num=3, + type=FIELD_TYPES['fitness_equipment_state'], + ref_fields=( + ReferenceField( + name='event', + def_num=0, + value='fitness_equipment', + raw_value=27, + ), + ), + ), + SubField( + name='gear_change_data', + def_num=3, + type=BASE_TYPES[0x86], # uint32 + ref_fields=( + ReferenceField( + name='event', + def_num=0, + value='front_gear_change', + raw_value=42, + ), + ReferenceField( + name='event', + def_num=0, + value='rear_gear_change', + raw_value=43, + ), + ), + components=( + ComponentField( + name='rear_gear_num', + def_num=11, + accumulate=False, + bits=8, + bit_offset=0, + ), + ComponentField( + name='rear_gear', + def_num=12, + accumulate=False, + bits=8, + bit_offset=8, + ), + ComponentField( + name='front_gear_num', + def_num=9, + accumulate=False, + bits=8, + bit_offset=16, + ), + ComponentField( + name='front_gear', + def_num=10, + accumulate=False, + bits=8, + bit_offset=24, + ), + ), + ), + SubField( + name='hr_high_alert', + def_num=3, + type=BASE_TYPES[0x02], # uint8 + units='bpm', + ref_fields=( + ReferenceField( + name='event', + def_num=0, + value='hr_high_alert', + raw_value=13, + ), + ), + ), + SubField( + name='hr_low_alert', + def_num=3, + type=BASE_TYPES[0x02], # uint8 + units='bpm', + ref_fields=( + ReferenceField( + name='event', + def_num=0, + value='hr_low_alert', + raw_value=14, + ), + ), + ), + SubField( + name='power_high_alert', + def_num=3, + type=BASE_TYPES[0x84], # uint16 + units='watts', + ref_fields=( + ReferenceField( + name='event', + def_num=0, + value='power_high_alert', + raw_value=19, + ), + ), + ), + SubField( + name='power_low_alert', + def_num=3, + type=BASE_TYPES[0x84], # uint16 + units='watts', + ref_fields=( + ReferenceField( + name='event', + def_num=0, + value='power_low_alert', + raw_value=20, + ), + ), + ), + SubField( # Indicates the rider position value. + name='rider_position', + def_num=3, + type=FIELD_TYPES['rider_position_type'], + ref_fields=( + ReferenceField( + name='event', + def_num=0, + value='rider_position_change', + raw_value=44, + ), + ), + ), + SubField( + name='speed_high_alert', + def_num=3, + type=BASE_TYPES[0x86], # uint32 + scale=1000, + units='m/s', + ref_fields=( + ReferenceField( + name='event', + def_num=0, + value='speed_high_alert', + raw_value=15, + ), + ), + ), + SubField( + name='speed_low_alert', + def_num=3, + type=BASE_TYPES[0x86], # uint32 + scale=1000, + units='m/s', + ref_fields=( + ReferenceField( + name='event', + def_num=0, + value='speed_low_alert', + raw_value=16, + ), + ), + ), + SubField( + name='sport_point', + def_num=3, + type=BASE_TYPES[0x86], # uint32 + ref_fields=( + ReferenceField( + name='event', + def_num=0, + value='sport_point', + raw_value=33, + ), + ), + components=( + ComponentField( + name='score', + def_num=7, + accumulate=False, + bits=16, + bit_offset=0, + ), + ComponentField( + name='opponent_score', + def_num=8, + accumulate=False, + bits=16, + bit_offset=16, + ), + ), + ), + SubField( + name='time_duration_alert', + def_num=3, + type=BASE_TYPES[0x86], # uint32 + scale=1000, + units='s', + ref_fields=( + ReferenceField( + name='event', + def_num=0, + value='time_duration_alert', + raw_value=23, + ), + ), + ), + SubField( + name='timer_trigger', + def_num=3, + type=FIELD_TYPES['timer_trigger'], + ref_fields=( + ReferenceField( + name='event', + def_num=0, + value='timer', + raw_value=0, + ), + ), + ), + SubField( + name='virtual_partner_speed', + def_num=3, + type=BASE_TYPES[0x84], # uint16 + scale=1000, + units='m/s', + ref_fields=( + ReferenceField( + name='event', + def_num=0, + value='virtual_partner_pace', + raw_value=12, + ), + ), + ), + ), + ), + 4: Field( + name='event_group', + type=BASE_TYPES[0x02], # uint8 + def_num=4, + ), + 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 + 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. + 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. + 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. + 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. + name='rear_gear', + type=BASE_TYPES[0x0A], # uint8z + def_num=12, + ), + 13: Field( + name='device_index', + type=FIELD_TYPES['device_index'], + def_num=13, + ), + 253: FIELD_TYPE_TIMESTAMP, + }, + ), + 23: MessageType( + name='device_info', + mesg_num=23, + fields={ + 0: Field( + name='device_index', + type=FIELD_TYPES['device_index'], + def_num=0, + ), + 1: Field( + name='device_type', + type=BASE_TYPES[0x02], # uint8 + def_num=1, + subfields=( + SubField( + name='ant_device_type', + def_num=1, + type=BASE_TYPES[0x02], # uint8 + ref_fields=( + ReferenceField( + name='source_type', + def_num=25, + value='ant', + raw_value=0, + ), + ), + ), + SubField( + name='antplus_device_type', + def_num=1, + type=FIELD_TYPES['antplus_device_type'], + ref_fields=( + ReferenceField( + name='source_type', + def_num=25, + value='antplus', + raw_value=1, + ), + ), + ), + ), + ), + 2: Field( + name='manufacturer', + type=FIELD_TYPES['manufacturer'], + def_num=2, + ), + 3: Field( + name='serial_number', + type=BASE_TYPES[0x8C], # uint32z + def_num=3, + ), + 4: Field( + name='product', + type=BASE_TYPES[0x84], # uint16 + def_num=4, + subfields=( + SubField( + name='garmin_product', + def_num=4, + type=FIELD_TYPES['garmin_product'], + ref_fields=( + ReferenceField( + name='manufacturer', + def_num=2, + value='garmin', + raw_value=1, + ), + ReferenceField( + name='manufacturer', + def_num=2, + value='dynastream', + raw_value=15, + ), + ReferenceField( + name='manufacturer', + def_num=2, + value='dynastream_oem', + raw_value=13, + ), + ), + ), + ), + ), + 5: Field( + name='software_version', + type=BASE_TYPES[0x84], # uint16 + def_num=5, + scale=100, + ), + 6: Field( + name='hardware_version', + type=BASE_TYPES[0x02], # uint8 + def_num=6, + ), + 7: Field( # Reset by new battery or charge. + name='cum_operating_time', + type=BASE_TYPES[0x86], # uint32 + def_num=7, + units='s', + ), + 10: Field( + name='battery_voltage', + type=BASE_TYPES[0x84], # uint16 + def_num=10, + scale=256, + units='V', + ), + 11: Field( + name='battery_status', + type=FIELD_TYPES['battery_status'], + def_num=11, + ), + 18: Field( # Indicates the location of the sensor + name='sensor_position', + type=FIELD_TYPES['body_location'], + def_num=18, + ), + 19: Field( # Used to describe the sensor or location + name='descriptor', + type=BASE_TYPES[0x07], # string + def_num=19, + ), + 20: Field( + name='ant_transmission_type', + type=BASE_TYPES[0x0A], # uint8z + def_num=20, + ), + 21: Field( + name='ant_device_number', + type=BASE_TYPES[0x8B], # uint16z + def_num=21, + ), + 22: Field( + name='ant_network', + type=FIELD_TYPES['ant_network'], + def_num=22, + ), + 25: Field( + name='source_type', + type=FIELD_TYPES['source_type'], + def_num=25, + ), + 27: Field( # Optional free form string to indicate the devices name or model + name='product_name', + type=BASE_TYPES[0x07], # string + def_num=27, + ), + 253: FIELD_TYPE_TIMESTAMP, + }, + ), + 27: MessageType( + name='workout_step', + mesg_num=27, + fields={ + 0: Field( + name='wkt_step_name', + type=BASE_TYPES[0x07], # string + def_num=0, + ), + 1: Field( + name='duration_type', + type=FIELD_TYPES['wkt_step_duration'], + def_num=1, + ), + 2: Field( + name='duration_value', + type=BASE_TYPES[0x86], # uint32 + def_num=2, + subfields=( + SubField( + name='duration_calories', + def_num=2, + type=BASE_TYPES[0x86], # uint32 + units='calories', + ref_fields=( + ReferenceField( + name='duration_type', + def_num=1, + value='calories', + raw_value=4, + ), + ), + ), + SubField( + name='duration_distance', + def_num=2, + type=BASE_TYPES[0x86], # uint32 + scale=100, + units='m', + ref_fields=( + ReferenceField( + name='duration_type', + def_num=1, + value='distance', + raw_value=1, + ), + ), + ), + SubField( + name='duration_hr', + def_num=2, + type=FIELD_TYPES['workout_hr'], + units='% or bpm', + ref_fields=( + ReferenceField( + name='duration_type', + def_num=1, + value='hr_less_than', + raw_value=2, + ), + ReferenceField( + name='duration_type', + def_num=1, + value='hr_greater_than', + raw_value=3, + ), + ), + ), + SubField( + name='duration_power', + def_num=2, + type=FIELD_TYPES['workout_power'], + units='% or watts', + ref_fields=( + ReferenceField( + name='duration_type', + def_num=1, + value='power_less_than', + raw_value=14, + ), + ReferenceField( + name='duration_type', + def_num=1, + value='power_greater_than', + raw_value=15, + ), + ), + ), + SubField( + name='duration_reps', + def_num=2, + type=BASE_TYPES[0x86], # uint32 + ref_fields=( + ReferenceField( + name='duration_type', + def_num=1, + value='reps', + raw_value=29, + ), + ), + ), + SubField( # message_index of step to loop back to. Steps are assumed to be in the order by message_index. custom_name and intensity members are undefined for this duration type. + name='duration_step', + def_num=2, + type=BASE_TYPES[0x86], # uint32 + ref_fields=( + ReferenceField( + name='duration_type', + def_num=1, + value='repeat_until_steps_cmplt', + raw_value=6, + ), + ReferenceField( + name='duration_type', + def_num=1, + value='repeat_until_time', + raw_value=7, + ), + ReferenceField( + name='duration_type', + def_num=1, + value='repeat_until_distance', + raw_value=8, + ), + ReferenceField( + name='duration_type', + def_num=1, + value='repeat_until_calories', + raw_value=9, + ), + ReferenceField( + name='duration_type', + def_num=1, + value='repeat_until_hr_less_than', + raw_value=10, + ), + ReferenceField( + name='duration_type', + def_num=1, + value='repeat_until_hr_greater_than', + raw_value=11, + ), + ReferenceField( + name='duration_type', + def_num=1, + value='repeat_until_power_less_than', + raw_value=12, + ), + ReferenceField( + name='duration_type', + def_num=1, + value='repeat_until_power_greater_than', + raw_value=13, + ), + ), + ), + SubField( + name='duration_time', + def_num=2, + type=BASE_TYPES[0x86], # uint32 + scale=1000, + units='s', + ref_fields=( + ReferenceField( + name='duration_type', + def_num=1, + value='time', + raw_value=0, + ), + ReferenceField( + name='duration_type', + def_num=1, + value='repetition_time', + raw_value=28, + ), + ), + ), + ), + ), + 3: Field( + name='target_type', + type=FIELD_TYPES['wkt_step_target'], + def_num=3, + ), + 4: Field( + name='target_value', + type=BASE_TYPES[0x86], # uint32 + def_num=4, + subfields=( + SubField( + name='repeat_calories', + def_num=4, + type=BASE_TYPES[0x86], # uint32 + units='calories', + ref_fields=( + ReferenceField( + name='duration_type', + def_num=1, + value='repeat_until_calories', + raw_value=9, + ), + ), + ), + SubField( + name='repeat_distance', + def_num=4, + type=BASE_TYPES[0x86], # uint32 + scale=100, + units='m', + ref_fields=( + ReferenceField( + name='duration_type', + def_num=1, + value='repeat_until_distance', + raw_value=8, + ), + ), + ), + SubField( + name='repeat_hr', + def_num=4, + type=FIELD_TYPES['workout_hr'], + units='% or bpm', + ref_fields=( + ReferenceField( + name='duration_type', + def_num=1, + value='repeat_until_hr_less_than', + raw_value=10, + ), + ReferenceField( + name='duration_type', + def_num=1, + value='repeat_until_hr_greater_than', + raw_value=11, + ), + ), + ), + SubField( + name='repeat_power', + def_num=4, + type=FIELD_TYPES['workout_power'], + units='% or watts', + ref_fields=( + ReferenceField( + name='duration_type', + def_num=1, + value='repeat_until_power_less_than', + raw_value=12, + ), + ReferenceField( + name='duration_type', + def_num=1, + value='repeat_until_power_greater_than', + raw_value=13, + ), + ), + ), + SubField( # # of repetitions + name='repeat_steps', + def_num=4, + type=BASE_TYPES[0x86], # uint32 + ref_fields=( + ReferenceField( + name='duration_type', + def_num=1, + value='repeat_until_steps_cmplt', + raw_value=6, + ), + ), + ), + SubField( + name='repeat_time', + def_num=4, + type=BASE_TYPES[0x86], # uint32 + scale=1000, + units='s', + ref_fields=( + ReferenceField( + name='duration_type', + def_num=1, + value='repeat_until_time', + raw_value=7, + ), + ), + ), + SubField( # Zone (1-?); Custom = 0; + name='target_cadence_zone', + def_num=4, + type=BASE_TYPES[0x86], # uint32 + ref_fields=( + ReferenceField( + name='target_type', + def_num=3, + value='cadence', + raw_value=3, + ), + ), + ), + SubField( # hr zone (1-5);Custom =0; + name='target_hr_zone', + def_num=4, + type=BASE_TYPES[0x86], # uint32 + ref_fields=( + ReferenceField( + name='target_type', + def_num=3, + value='heart_rate', + raw_value=1, + ), + ), + ), + SubField( # Power Zone ( 1-7); Custom = 0; + name='target_power_zone', + def_num=4, + type=BASE_TYPES[0x86], # uint32 + ref_fields=( + ReferenceField( + name='target_type', + def_num=3, + value='power', + raw_value=4, + ), + ), + ), + SubField( # speed zone (1-10);Custom =0; + name='target_speed_zone', + def_num=4, + type=BASE_TYPES[0x86], # uint32 + ref_fields=( + ReferenceField( + name='target_type', + def_num=3, + value='speed', + raw_value=0, + ), + ), + ), + SubField( + name='target_stroke_type', + def_num=4, + type=FIELD_TYPES['swim_stroke'], + ref_fields=( + ReferenceField( + name='target_type', + def_num=3, + value='swim_stroke', + raw_value=11, + ), + ), + ), + ), + ), + 5: Field( + name='custom_target_value_low', + type=BASE_TYPES[0x86], # uint32 + def_num=5, + subfields=( + SubField( + name='custom_target_cadence_low', + def_num=5, + type=BASE_TYPES[0x86], # uint32 + units='rpm', + ref_fields=( + ReferenceField( + name='target_type', + def_num=3, + value='cadence', + raw_value=3, + ), + ), + ), + SubField( + name='custom_target_heart_rate_low', + def_num=5, + type=FIELD_TYPES['workout_hr'], + units='% or bpm', + ref_fields=( + ReferenceField( + name='target_type', + def_num=3, + value='heart_rate', + raw_value=1, + ), + ), + ), + SubField( + name='custom_target_power_low', + def_num=5, + type=FIELD_TYPES['workout_power'], + units='% or watts', + ref_fields=( + ReferenceField( + name='target_type', + def_num=3, + value='power', + raw_value=4, + ), + ), + ), + SubField( + name='custom_target_speed_low', + def_num=5, + type=BASE_TYPES[0x86], # uint32 + scale=1000, + units='m/s', + ref_fields=( + ReferenceField( + name='target_type', + def_num=3, + value='speed', + raw_value=0, + ), + ), + ), + ), + ), + 6: Field( + name='custom_target_value_high', + type=BASE_TYPES[0x86], # uint32 + def_num=6, + subfields=( + SubField( + name='custom_target_cadence_high', + def_num=6, + type=BASE_TYPES[0x86], # uint32 + units='rpm', + ref_fields=( + ReferenceField( + name='target_type', + def_num=3, + value='cadence', + raw_value=3, + ), + ), + ), + SubField( + name='custom_target_heart_rate_high', + def_num=6, + type=FIELD_TYPES['workout_hr'], + units='% or bpm', + ref_fields=( + ReferenceField( + name='target_type', + def_num=3, + value='heart_rate', + raw_value=1, + ), + ), + ), + SubField( + name='custom_target_power_high', + def_num=6, + type=FIELD_TYPES['workout_power'], + units='% or watts', + ref_fields=( + ReferenceField( + name='target_type', + def_num=3, + value='power', + raw_value=4, + ), + ), + ), + SubField( + name='custom_target_speed_high', + def_num=6, + type=BASE_TYPES[0x86], # uint32 + scale=1000, + units='m/s', + ref_fields=( + ReferenceField( + name='target_type', + def_num=3, + value='speed', + raw_value=0, + ), + ), + ), + ), + ), + 7: Field( + name='intensity', + type=FIELD_TYPES['intensity'], + def_num=7, + ), + 8: Field( + name='notes', + type=BASE_TYPES[0x07], # string + def_num=8, + ), + 9: Field( + name='equipment', + type=FIELD_TYPES['workout_equipment'], + def_num=9, + ), + 10: Field( + name='exercise_category', + type=FIELD_TYPES['exercise_category'], + def_num=10, + ), + 11: Field( + name='exercise_name', + type=BASE_TYPES[0x84], # uint16 + def_num=11, + ), + 12: Field( + name='exercise_weight', + type=BASE_TYPES[0x84], # uint16 + def_num=12, + scale=100, + units='kg', + ), + 13: Field( + name='weight_display_unit', + type=FIELD_TYPES['fit_base_unit'], + def_num=13, + ), + 254: Field( + name='message_index', + type=FIELD_TYPES['message_index'], + def_num=254, + ), + }, + ), + 32: MessageType( + name='course_point', + mesg_num=32, + fields={ + 1: Field( + name='timestamp', + type=FIELD_TYPES['date_time'], + def_num=1, + ), + 2: Field( + name='position_lat', + type=BASE_TYPES[0x85], # sint32 + def_num=2, + units='semicircles', + ), + 3: Field( + name='position_long', + type=BASE_TYPES[0x85], # sint32 + def_num=3, + 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', + 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, + 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, + ), + ), + ), + ), + ), + 254: Field( + name='message_index', + type=FIELD_TYPES['message_index'], + def_num=254, + ), + }, + ), + 39: MessageType( + name='field_capabilities', + mesg_num=39, + 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='field_num', + type=BASE_TYPES[0x02], # uint8 + def_num=2, + ), + 3: Field( + name='count', + type=BASE_TYPES[0x84], # uint16 + def_num=3, + ), + 254: Field( + name='message_index', + type=FIELD_TYPES['message_index'], + def_num=254, + ), + }, + ), + 49: MessageType( + name='file_creator', + mesg_num=49, + fields={ + 0: Field( + name='software_version', + type=BASE_TYPES[0x84], # uint16 + def_num=0, + ), + 1: Field( + name='hardware_version', + type=BASE_TYPES[0x02], # uint8 + def_num=1, + ), + }, + ), + 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', + ), + 15: Field( # Max temperature during the logging interval ended at timestamp + name='temperature_max', + type=BASE_TYPES[0x83], # sint16 + def_num=15, + scale=100, + units='C', + ), + 16: Field( # Indexed using minute_activity_level enum + name='activity_time', + type=BASE_TYPES[0x84], # uint16 + def_num=16, + units='minutes', + ), + 19: Field( + name='active_calories', + type=BASE_TYPES[0x84], # uint16 + def_num=19, + units='kcal', + ), + 24: Field( # Indicates single type / intensity for duration since last monitoring message. + name='current_activity_type_intensity', + type=BASE_TYPES[0x0D], # byte + def_num=24, + components=( + ComponentField( + name='activity_type', + def_num=5, + accumulate=False, + bits=5, + bit_offset=0, + ), + ComponentField( + name='intensity', + def_num=28, + accumulate=False, + bits=3, + bit_offset=5, + ), + ), + ), + 25: Field( + name='timestamp_min_8', + type=BASE_TYPES[0x02], # uint8 + def_num=25, + units='min', + ), + 26: Field( + name='timestamp_16', + type=BASE_TYPES[0x84], # uint16 + def_num=26, + units='s', + ), + 27: Field( + name='heart_rate', + type=BASE_TYPES[0x02], # uint8 + def_num=27, + units='bpm', + ), + 28: Field( + name='intensity', + type=BASE_TYPES[0x02], # uint8 + def_num=28, + scale=10, + ), + 29: Field( + name='duration_min', + type=BASE_TYPES[0x84], # uint16 + def_num=29, + units='min', + ), + 30: Field( + name='duration', + type=BASE_TYPES[0x86], # uint32 + def_num=30, + units='s', + ), + 31: Field( + name='ascent', + type=BASE_TYPES[0x86], # uint32 + def_num=31, + scale=1000, + units='m', + ), + 32: Field( + name='descent', + type=BASE_TYPES[0x86], # uint32 + def_num=32, + scale=1000, + units='m', + ), + 33: Field( + name='moderate_activity_minutes', + type=BASE_TYPES[0x84], # uint16 + def_num=33, + units='minutes', + ), + 34: Field( + name='vigorous_activity_minutes', + type=BASE_TYPES[0x84], # uint16 + def_num=34, + units='minutes', + ), + 253: FIELD_TYPE_TIMESTAMP, # Must align to logging interval, for example, time must be 00:00:00 for daily log. + }, + ), + 72: MessageType( # Corresponds to file_id of workout or course. + name='training_file', + mesg_num=72, + fields={ + 0: Field( + name='type', + type=FIELD_TYPES['file'], + def_num=0, + ), + 1: Field( + name='manufacturer', + type=FIELD_TYPES['manufacturer'], + def_num=1, + ), + 2: Field( + name='product', + type=BASE_TYPES[0x84], # uint16 + def_num=2, + subfields=( + SubField( + name='garmin_product', + def_num=2, + type=FIELD_TYPES['garmin_product'], + ref_fields=( + ReferenceField( + name='manufacturer', + def_num=1, + value='garmin', + raw_value=1, + ), + ReferenceField( + name='manufacturer', + def_num=1, + value='dynastream', + raw_value=15, + ), + ReferenceField( + name='manufacturer', + def_num=1, + value='dynastream_oem', + raw_value=13, + ), + ), + ), + ), + ), + 3: Field( + name='serial_number', + type=BASE_TYPES[0x8C], # uint32z + def_num=3, + ), + 4: Field( + name='time_created', + type=FIELD_TYPES['date_time'], + def_num=4, + ), + 253: FIELD_TYPE_TIMESTAMP, + }, + ), + 78: MessageType( # Heart rate variability + name='hrv', + mesg_num=78, + fields={ + 0: Field( # Time between beats + name='time', + type=BASE_TYPES[0x84], # uint16 + def_num=0, + scale=1000, + units='s', + ), + }, + ), + 80: MessageType( + name='ant_rx', + mesg_num=80, + fields={ + 0: Field( + name='fractional_timestamp', + type=BASE_TYPES[0x84], # uint16 + def_num=0, + scale=32768, + units='s', + ), + 1: Field( + name='mesg_id', + type=BASE_TYPES[0x0D], # byte + def_num=1, + ), + 2: Field( + name='mesg_data', + type=BASE_TYPES[0x0D], # byte + def_num=2, + components=( + ComponentField( + name='channel_number', + def_num=3, + accumulate=False, + bits=8, + bit_offset=0, + ), + ComponentField( + name='data', + def_num=4, + accumulate=False, + bits=8, + bit_offset=8, + ), + ComponentField( + name='data', + def_num=4, + accumulate=False, + bits=8, + bit_offset=16, + ), + ComponentField( + name='data', + def_num=4, + accumulate=False, + bits=8, + bit_offset=24, + ), + ComponentField( + name='data', + def_num=4, + accumulate=False, + bits=8, + bit_offset=32, + ), + ComponentField( + name='data', + def_num=4, + accumulate=False, + bits=8, + bit_offset=40, + ), + ComponentField( + name='data', + def_num=4, + accumulate=False, + bits=8, + bit_offset=48, + ), + ComponentField( + name='data', + def_num=4, + accumulate=False, + bits=8, + bit_offset=56, + ), + ComponentField( + name='data', + def_num=4, + accumulate=False, + bits=8, + bit_offset=64, + ), + ), + ), + 3: Field( + name='channel_number', + type=BASE_TYPES[0x02], # uint8 + def_num=3, + ), + 4: Field( + name='data', + type=BASE_TYPES[0x0D], # byte + def_num=4, + ), + 253: FIELD_TYPE_TIMESTAMP, + }, + ), + 81: MessageType( + name='ant_tx', + mesg_num=81, + fields={ + 0: Field( + name='fractional_timestamp', + type=BASE_TYPES[0x84], # uint16 + def_num=0, + scale=32768, + units='s', + ), + 1: Field( + name='mesg_id', + type=BASE_TYPES[0x0D], # byte + def_num=1, + ), + 2: Field( + name='mesg_data', + type=BASE_TYPES[0x0D], # byte + def_num=2, + components=( + ComponentField( + name='channel_number', + def_num=3, + accumulate=False, + bits=8, + bit_offset=0, + ), + ComponentField( + name='data', + def_num=4, + accumulate=False, + bits=8, + bit_offset=8, + ), + ComponentField( + name='data', + def_num=4, + accumulate=False, + bits=8, + bit_offset=16, + ), + ComponentField( + name='data', + def_num=4, + accumulate=False, + bits=8, + bit_offset=24, + ), + ComponentField( + name='data', + def_num=4, + accumulate=False, + bits=8, + bit_offset=32, + ), + ComponentField( + name='data', + def_num=4, + accumulate=False, + bits=8, + bit_offset=40, + ), + ComponentField( + name='data', + def_num=4, + accumulate=False, + bits=8, + bit_offset=48, + ), + ComponentField( + name='data', + def_num=4, + accumulate=False, + bits=8, + bit_offset=56, + ), + ComponentField( + name='data', + def_num=4, + accumulate=False, + bits=8, + bit_offset=64, + ), + ), + ), + 3: Field( + name='channel_number', + type=BASE_TYPES[0x02], # uint8 + def_num=3, + ), + 4: Field( + name='data', + type=BASE_TYPES[0x0D], # byte + def_num=4, + ), + 253: FIELD_TYPE_TIMESTAMP, + }, + ), + 82: MessageType( + name='ant_channel_id', + mesg_num=82, + fields={ + 0: Field( + name='channel_number', + type=BASE_TYPES[0x02], # uint8 + def_num=0, + ), + 1: Field( + name='device_type', + type=BASE_TYPES[0x0A], # uint8z + def_num=1, + ), + 2: Field( + name='device_number', + type=BASE_TYPES[0x8B], # uint16z + def_num=2, + ), + 3: Field( + name='transmission_type', + type=BASE_TYPES[0x0A], # uint8z + def_num=3, + ), + 4: Field( + name='device_index', + type=FIELD_TYPES['device_index'], + def_num=4, + ), + }, + ), + 101: MessageType( + name='length', + mesg_num=101, + 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='start_time', + type=FIELD_TYPES['date_time'], + def_num=2, + ), + 3: Field( + name='total_elapsed_time', + type=BASE_TYPES[0x86], # uint32 + def_num=3, + scale=1000, + units='s', + ), + 4: Field( + name='total_timer_time', + type=BASE_TYPES[0x86], # uint32 + def_num=4, + scale=1000, + units='s', + ), + 5: Field( + name='total_strokes', + type=BASE_TYPES[0x84], # uint16 + def_num=5, + units='strokes', + ), + 6: Field( + name='avg_speed', + type=BASE_TYPES[0x84], # uint16 + def_num=6, + scale=1000, + units='m/s', + ), + 7: Field( + name='swim_stroke', + type=FIELD_TYPES['swim_stroke'], + def_num=7, + units='swim_stroke', + ), + 9: Field( + name='avg_swimming_cadence', + type=BASE_TYPES[0x02], # uint8 + def_num=9, + units='strokes/min', + ), + 10: Field( + name='event_group', + type=BASE_TYPES[0x02], # uint8 + def_num=10, + ), + 11: Field( + name='total_calories', + type=BASE_TYPES[0x84], # uint16 + def_num=11, + units='kcal', + ), + 12: Field( + name='length_type', + type=FIELD_TYPES['length_type'], + def_num=12, + ), + 18: Field( + name='player_score', + type=BASE_TYPES[0x84], # uint16 + def_num=18, + ), + 19: Field( + name='opponent_score', + type=BASE_TYPES[0x84], # uint16 + def_num=19, + ), + 20: Field( # stroke_type enum used as the index + name='stroke_count', + type=BASE_TYPES[0x84], # uint16 + def_num=20, + units='counts', + ), + 21: Field( # zone number used as the index + name='zone_count', + type=BASE_TYPES[0x84], # uint16 + def_num=21, + units='counts', + ), + 253: FIELD_TYPE_TIMESTAMP, + 254: Field( + name='message_index', + type=FIELD_TYPES['message_index'], + def_num=254, + ), + }, + ), + 106: MessageType( + name='slave_device', + mesg_num=106, + fields={ + 0: Field( + name='manufacturer', + type=FIELD_TYPES['manufacturer'], + def_num=0, + ), + 1: Field( + name='product', + type=BASE_TYPES[0x84], # uint16 + 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, + ), + ), + ), + ), + ), + }, + ), + 127: MessageType( + name='connectivity', + mesg_num=127, + fields={ + 0: Field( # Use Bluetooth for connectivity features + name='bluetooth_enabled', + type=FIELD_TYPES['bool'], + def_num=0, + ), + 1: Field( # Use Bluetooth Low Energy for connectivity features + name='bluetooth_le_enabled', + type=FIELD_TYPES['bool'], + def_num=1, + ), + 2: Field( # Use ANT for connectivity features + name='ant_enabled', + type=FIELD_TYPES['bool'], + def_num=2, + ), + 3: Field( + name='name', + type=BASE_TYPES[0x07], # string + def_num=3, + ), + 4: Field( + name='live_tracking_enabled', + type=FIELD_TYPES['bool'], + def_num=4, + ), + 5: Field( + name='weather_conditions_enabled', + type=FIELD_TYPES['bool'], + def_num=5, + ), + 6: Field( + name='weather_alerts_enabled', + type=FIELD_TYPES['bool'], + def_num=6, + ), + 7: Field( + name='auto_activity_upload_enabled', + type=FIELD_TYPES['bool'], + def_num=7, + ), + 8: Field( + name='course_download_enabled', + type=FIELD_TYPES['bool'], + def_num=8, + ), + 9: Field( + name='workout_download_enabled', + type=FIELD_TYPES['bool'], + def_num=9, + ), + 10: Field( + name='gps_ephemeris_download_enabled', + type=FIELD_TYPES['bool'], + def_num=10, + ), + 11: Field( + name='incident_detection_enabled', + type=FIELD_TYPES['bool'], + def_num=11, + ), + 12: Field( + name='grouptrack_enabled', + type=FIELD_TYPES['bool'], + def_num=12, + ), + }, + ), + 128: MessageType( + name='weather_conditions', + mesg_num=128, + fields={ + 0: Field( # Current or forecast + name='weather_report', + type=FIELD_TYPES['weather_report'], + def_num=0, + ), + 1: Field( + name='temperature', + type=BASE_TYPES[0x01], # sint8 + def_num=1, + units='C', + ), + 2: Field( # Corresponds to GSC Response weatherIcon field + name='condition', + type=FIELD_TYPES['weather_status'], + def_num=2, + ), + 3: Field( + name='wind_direction', + type=BASE_TYPES[0x84], # uint16 + def_num=3, + units='degrees', + ), + 4: Field( + name='wind_speed', + type=BASE_TYPES[0x84], # uint16 + def_num=4, + scale=1000, + units='m/s', + ), + 5: Field( # range 0-100 + name='precipitation_probability', + type=BASE_TYPES[0x02], # uint8 + def_num=5, + ), + 6: Field( # Heat Index if GCS heatIdx above or equal to 90F or wind chill if GCS windChill below or equal to 32F + name='temperature_feels_like', + type=BASE_TYPES[0x01], # sint8 + def_num=6, + units='C', + ), + 7: Field( + name='relative_humidity', + type=BASE_TYPES[0x02], # uint8 + def_num=7, + ), + 8: Field( # string corresponding to GCS response location string + name='location', + type=BASE_TYPES[0x07], # string + def_num=8, + ), + 9: Field( + name='observed_at_time', + type=FIELD_TYPES['date_time'], + def_num=9, + ), + 10: Field( + name='observed_location_lat', + type=BASE_TYPES[0x85], # sint32 + def_num=10, + units='semicircles', + ), + 11: Field( + name='observed_location_long', + type=BASE_TYPES[0x85], # sint32 + def_num=11, + units='semicircles', + ), + 12: Field( + name='day_of_week', + type=FIELD_TYPES['day_of_week'], + def_num=12, + ), + 13: Field( + name='high_temperature', + type=BASE_TYPES[0x01], # sint8 + def_num=13, + units='C', + ), + 14: Field( + name='low_temperature', + type=BASE_TYPES[0x01], # sint8 + def_num=14, + units='C', + ), + 253: FIELD_TYPE_TIMESTAMP, # time of update for current conditions, else forecast time + }, + ), + 129: MessageType( + name='weather_alert', + mesg_num=129, + fields={ + 0: Field( # Unique identifier from GCS report ID string, length is 12 + name='report_id', + type=BASE_TYPES[0x07], # string + def_num=0, + ), + 1: Field( # Time alert was issued + name='issue_time', + type=FIELD_TYPES['date_time'], + def_num=1, + ), + 2: Field( # Time alert expires + name='expire_time', + type=FIELD_TYPES['date_time'], + def_num=2, + ), + 3: Field( # Warning, Watch, Advisory, Statement + name='severity', + type=FIELD_TYPES['weather_severity'], + def_num=3, + ), + 4: Field( # Tornado, Severe Thunderstorm, etc. + name='type', + type=FIELD_TYPES['weather_severe_type'], + def_num=4, + ), + 253: FIELD_TYPE_TIMESTAMP, + }, + ), + 131: MessageType( + name='cadence_zone', + mesg_num=131, + fields={ + 0: Field( + name='high_value', + type=BASE_TYPES[0x02], # uint8 + def_num=0, + units='rpm', + ), + 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, + ), + }, + ), + 132: MessageType( + name='hr', + mesg_num=132, + fields={ + 0: Field( + name='fractional_timestamp', + type=BASE_TYPES[0x84], # uint16 + def_num=0, + scale=32768, + units='s', + ), + 1: Field( + name='time256', + type=BASE_TYPES[0x02], # uint8 + def_num=1, + components=( + ComponentField( + name='fractional_timestamp', + def_num=0, + scale=256, + units='s', + accumulate=False, + bits=8, + bit_offset=0, + ), + ), + ), + 6: Field( + name='filtered_bpm', + type=BASE_TYPES[0x02], # uint8 + def_num=6, + units='bpm', + ), + 9: Field( + name='event_timestamp', + type=BASE_TYPES[0x86], # uint32 + def_num=9, + scale=1024, + units='s', + ), + 10: Field( + name='event_timestamp_12', + type=BASE_TYPES[0x0D], # byte + def_num=10, + components=( + ComponentField( + name='event_timestamp', + def_num=9, + scale=1024, + units='s', + accumulate=True, + bits=12, + bit_offset=0, + ), + ComponentField( + name='event_timestamp', + def_num=9, + scale=1024, + units='s', + accumulate=True, + bits=12, + bit_offset=12, + ), + ComponentField( + name='event_timestamp', + def_num=9, + scale=1024, + units='s', + accumulate=True, + bits=12, + bit_offset=24, + ), + ComponentField( + name='event_timestamp', + def_num=9, + scale=1024, + units='s', + accumulate=True, + bits=12, + bit_offset=36, + ), + ComponentField( + name='event_timestamp', + def_num=9, + scale=1024, + units='s', + accumulate=True, + bits=12, + bit_offset=48, + ), + ComponentField( + name='event_timestamp', + def_num=9, + scale=1024, + units='s', + accumulate=True, + bits=12, + bit_offset=60, + ), + ComponentField( + name='event_timestamp', + def_num=9, + scale=1024, + units='s', + accumulate=True, + bits=12, + bit_offset=72, + ), + ComponentField( + name='event_timestamp', + def_num=9, + scale=1024, + units='s', + accumulate=True, + bits=12, + bit_offset=84, + ), + ComponentField( + name='event_timestamp', + def_num=9, + scale=1024, + units='s', + accumulate=True, + bits=12, + bit_offset=96, + ), + ComponentField( + name='event_timestamp', + def_num=9, + scale=1024, + units='s', + accumulate=True, + bits=12, + bit_offset=108, + ), + ), + ), + 253: FIELD_TYPE_TIMESTAMP, + }, + ), + 142: MessageType( + name='segment_lap', + mesg_num=142, + 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='start_time', + type=FIELD_TYPES['date_time'], + def_num=2, + ), + 3: Field( + name='start_position_lat', + type=BASE_TYPES[0x85], # sint32 + def_num=3, + units='semicircles', + ), + 4: Field( + name='start_position_long', + type=BASE_TYPES[0x85], # sint32 + def_num=4, + units='semicircles', + ), + 5: Field( + name='end_position_lat', + type=BASE_TYPES[0x85], # sint32 + def_num=5, + units='semicircles', + ), + 6: Field( + name='end_position_long', + type=BASE_TYPES[0x85], # sint32 + def_num=6, + units='semicircles', + ), + 7: Field( # Time (includes pauses) + name='total_elapsed_time', + type=BASE_TYPES[0x86], # uint32 + def_num=7, + scale=1000, + units='s', + ), + 8: Field( # Timer Time (excludes pauses) + name='total_timer_time', + type=BASE_TYPES[0x86], # uint32 + def_num=8, + scale=1000, + units='s', + ), + 9: Field( + name='total_distance', + type=BASE_TYPES[0x86], # uint32 + def_num=9, + scale=100, + units='m', + ), + 10: Field( + name='total_cycles', + type=BASE_TYPES[0x86], # uint32 + def_num=10, + units='cycles', + subfields=( + SubField( + name='total_strokes', + def_num=10, + type=BASE_TYPES[0x86], # uint32 + units='strokes', + ref_fields=( + ReferenceField( + name='sport', + def_num=23, + value='cycling', + raw_value=2, + ), + ), + ), + ), + ), + 11: Field( + name='total_calories', + type=BASE_TYPES[0x84], # uint16 + def_num=11, + units='kcal', + ), + 12: Field( # If New Leaf + name='total_fat_calories', + type=BASE_TYPES[0x84], # uint16 + def_num=12, + units='kcal', + ), + 13: Field( + name='avg_speed', + type=BASE_TYPES[0x84], # uint16 + def_num=13, + scale=1000, + units='m/s', + ), + 14: Field( + name='max_speed', + type=BASE_TYPES[0x84], # uint16 + def_num=14, + scale=1000, + units='m/s', + ), + 15: Field( + name='avg_heart_rate', + type=BASE_TYPES[0x02], # uint8 + def_num=15, + units='bpm', + ), + 16: Field( + name='max_heart_rate', + type=BASE_TYPES[0x02], # uint8 + def_num=16, + units='bpm', + ), + 17: Field( # total_cycles / total_timer_time if non_zero_avg_cadence otherwise total_cycles / total_elapsed_time + name='avg_cadence', + type=BASE_TYPES[0x02], # uint8 + def_num=17, + units='rpm', + ), + 18: Field( + name='max_cadence', + type=BASE_TYPES[0x02], # uint8 + def_num=18, + units='rpm', + ), + 19: Field( # total_power / total_timer_time if non_zero_avg_power otherwise total_power / total_elapsed_time + name='avg_power', + type=BASE_TYPES[0x84], # uint16 + def_num=19, + units='watts', + ), + 20: Field( + name='max_power', + type=BASE_TYPES[0x84], # uint16 + def_num=20, + units='watts', + ), + 21: Field( + name='total_ascent', + type=BASE_TYPES[0x84], # uint16 + def_num=21, + units='m', + ), + 22: Field( + name='total_descent', + type=BASE_TYPES[0x84], # uint16 + def_num=22, + units='m', + ), + 23: Field( + name='sport', + type=FIELD_TYPES['sport'], + def_num=23, + ), + 24: Field( + name='event_group', + type=BASE_TYPES[0x02], # uint8 + def_num=24, + ), + 25: Field( # North east corner latitude. + name='nec_lat', + type=BASE_TYPES[0x85], # sint32 + def_num=25, + units='semicircles', + ), + 26: Field( # North east corner longitude. + name='nec_long', + type=BASE_TYPES[0x85], # sint32 + def_num=26, + units='semicircles', + ), + 27: Field( # South west corner latitude. + name='swc_lat', + type=BASE_TYPES[0x85], # sint32 + def_num=27, + units='semicircles', + ), + 28: Field( # South west corner latitude. + name='swc_long', + type=BASE_TYPES[0x85], # sint32 + def_num=28, + units='semicircles', + ), + 29: Field( + name='name', + type=BASE_TYPES[0x07], # string + def_num=29, + ), + 30: Field( + name='normalized_power', + type=BASE_TYPES[0x84], # uint16 + def_num=30, + units='watts', + ), + 31: Field( + name='left_right_balance', + type=FIELD_TYPES['left_right_balance_100'], + def_num=31, + ), + 32: Field( + name='sub_sport', + type=FIELD_TYPES['sub_sport'], + def_num=32, + ), + 33: Field( + name='total_work', + type=BASE_TYPES[0x86], # uint32 + def_num=33, + units='J', + ), + 34: Field( + name='avg_altitude', + type=BASE_TYPES[0x84], # uint16 + def_num=34, + scale=5, + offset=500, + units='m', + ), + 35: Field( + name='max_altitude', + type=BASE_TYPES[0x84], # uint16 + def_num=35, + scale=5, + offset=500, + units='m', + ), + 36: Field( + name='gps_accuracy', + type=BASE_TYPES[0x02], # uint8 + def_num=36, + units='m', + ), + 37: Field( + name='avg_grade', + type=BASE_TYPES[0x83], # sint16 + def_num=37, + scale=100, + units='%', + ), + 38: Field( + name='avg_pos_grade', + type=BASE_TYPES[0x83], # sint16 + def_num=38, + scale=100, + units='%', + ), + 39: Field( + name='avg_neg_grade', + type=BASE_TYPES[0x83], # sint16 + def_num=39, + scale=100, + units='%', + ), + 40: Field( + name='max_pos_grade', + type=BASE_TYPES[0x83], # sint16 + def_num=40, + scale=100, + units='%', + ), + 41: Field( + name='max_neg_grade', + type=BASE_TYPES[0x83], # sint16 + def_num=41, + scale=100, + units='%', + ), + 42: Field( + name='avg_temperature', + type=BASE_TYPES[0x01], # sint8 + def_num=42, + units='C', + ), + 43: Field( + name='max_temperature', + type=BASE_TYPES[0x01], # sint8 + def_num=43, + units='C', + ), + 44: Field( + name='total_moving_time', + type=BASE_TYPES[0x86], # uint32 + def_num=44, + scale=1000, + units='s', + ), + 45: Field( + name='avg_pos_vertical_speed', + type=BASE_TYPES[0x83], # sint16 + def_num=45, + scale=1000, + units='m/s', + ), + 46: Field( + name='avg_neg_vertical_speed', + type=BASE_TYPES[0x83], # sint16 + def_num=46, + scale=1000, + units='m/s', + ), + 47: Field( + name='max_pos_vertical_speed', + type=BASE_TYPES[0x83], # sint16 + def_num=47, + scale=1000, + units='m/s', + ), + 48: Field( + name='max_neg_vertical_speed', + type=BASE_TYPES[0x83], # sint16 + def_num=48, + scale=1000, + units='m/s', + ), + 49: Field( + name='time_in_hr_zone', + type=BASE_TYPES[0x86], # uint32 + def_num=49, + scale=1000, + units='s', + ), + 50: Field( + name='time_in_speed_zone', + type=BASE_TYPES[0x86], # uint32 + def_num=50, + scale=1000, + units='s', + ), + 51: Field( + name='time_in_cadence_zone', + type=BASE_TYPES[0x86], # uint32 + def_num=51, + scale=1000, + units='s', + ), + 52: Field( + name='time_in_power_zone', + type=BASE_TYPES[0x86], # uint32 + def_num=52, + scale=1000, + units='s', + ), + 53: Field( + name='repetition_num', + type=BASE_TYPES[0x84], # uint16 + def_num=53, + ), + 54: Field( + name='min_altitude', + type=BASE_TYPES[0x84], # uint16 + def_num=54, + scale=5, + offset=500, + units='m', + ), + 55: Field( + name='min_heart_rate', + type=BASE_TYPES[0x02], # uint8 + def_num=55, + units='bpm', + ), + 56: Field( + name='active_time', + type=BASE_TYPES[0x86], # uint32 + def_num=56, + scale=1000, + units='s', + ), + 57: Field( + name='wkt_step_index', + type=FIELD_TYPES['message_index'], + def_num=57, + ), + 58: Field( + name='sport_event', + type=FIELD_TYPES['sport_event'], + def_num=58, + ), + 59: Field( + name='avg_left_torque_effectiveness', + type=BASE_TYPES[0x02], # uint8 + def_num=59, + scale=2, + units='percent', + ), + 60: Field( + name='avg_right_torque_effectiveness', + type=BASE_TYPES[0x02], # uint8 + def_num=60, + scale=2, + units='percent', + ), + 61: Field( + name='avg_left_pedal_smoothness', + type=BASE_TYPES[0x02], # uint8 + def_num=61, + scale=2, + units='percent', + ), + 62: Field( + name='avg_right_pedal_smoothness', + type=BASE_TYPES[0x02], # uint8 + def_num=62, + scale=2, + units='percent', + ), + 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, + ), + 2: Field( + name='fit_base_type_id', + type=FIELD_TYPES['fit_base_type'], + def_num=2, + ), + 3: Field( + name='field_name', + type=BASE_TYPES[0x07], # string + def_num=3, + ), + 4: Field( + name='array', + type=BASE_TYPES[0x02], # uint8 + def_num=4, + ), + 5: Field( + name='components', + type=BASE_TYPES[0x07], # string + def_num=5, + ), + 6: Field( + name='scale', + type=BASE_TYPES[0x02], # uint8 + def_num=6, + ), + 7: Field( + name='offset', + type=BASE_TYPES[0x01], # sint8 + def_num=7, + ), + 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, + ), + }, + ), + 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, + ), + 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( + name='application_version', + type=BASE_TYPES[0x86], # uint32 + def_num=4, + ), + }, + ), + 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', + ), + 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', + ), + 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', + ), + 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', + ), + 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', + ), + 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 + }, + ), + 210: MessageType( + name='one_d_sensor_calibration', + mesg_num=210, + 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( # 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 + 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 factor + name='offset_cal', + type=BASE_TYPES[0x85], # sint32 + def_num=4, + ), + 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', + ), + 3: Field( # # of repitions of the movement + name='repetitions', + type=BASE_TYPES[0x84], # uint16 + def_num=3, + ), + 4: Field( # Amount of weight applied for the set + name='weight', + type=BASE_TYPES[0x84], # uint16 + def_num=4, + scale=16, + units='kg', + ), + 5: Field( + name='set_type', + type=FIELD_TYPES['set_type'], + def_num=5, + ), + 6: Field( # Start time of the set + name='start_time', + type=FIELD_TYPES['date_time'], + def_num=6, + ), + 7: Field( + name='category', + type=FIELD_TYPES['exercise_category'], + def_num=7, + ), + 8: Field( # Based on the associated category, see [category]_exercise_names + name='category_subtype', + type=BASE_TYPES[0x84], # uint16 + 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, + fields={ + 0: Field( + name='stress_level_value', + type=BASE_TYPES[0x83], # sint16 + def_num=0, + ), + 1: Field( # Time stress score was calculated + name='stress_level_time', + type=FIELD_TYPES['date_time'], + def_num=1, + units='s', + ), + }, + ), + 258: MessageType( + name='dive_settings', + mesg_num=258, + fields={ + 0: Field( + name='name', + type=BASE_TYPES[0x07], # string + def_num=0, + ), + 1: Field( + name='model', + type=FIELD_TYPES['tissue_model_type'], + def_num=1, + ), + 2: Field( + name='gf_low', + type=BASE_TYPES[0x02], # uint8 + def_num=2, + units='percent', + ), + 3: Field( + name='gf_high', + type=BASE_TYPES[0x02], # uint8 + def_num=3, + units='percent', + ), + 4: Field( + name='water_type', + type=FIELD_TYPES['water_type'], + def_num=4, + ), + 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( # Typically 1.40 + name='po2_warn', + type=BASE_TYPES[0x02], # uint8 + def_num=6, + scale=100, + units='percent', + ), + 7: Field( # Typically 1.60 + name='po2_critical', + type=BASE_TYPES[0x02], # uint8 + def_num=7, + scale=100, + units='percent', + ), + 8: Field( + name='po2_deco', + type=BASE_TYPES[0x02], # uint8 + def_num=8, + scale=100, + units='percent', + ), + 9: Field( + name='safety_stop_enabled', + type=FIELD_TYPES['bool'], + def_num=9, + ), + 10: Field( + name='bottom_depth', + type=BASE_TYPES[0x88], # float32 + def_num=10, + ), + 11: Field( + name='bottom_time', + type=BASE_TYPES[0x86], # uint32 + 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, + ), + 14: Field( + 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='backlight_timeout', + type=FIELD_TYPES['backlight_timeout'], + def_num=16, + ), + 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( # Time at safety stop (if enabled) + name='safety_stop_time', + type=BASE_TYPES[0x84], # uint16 + def_num=18, + units='s', + ), + 19: Field( + name='heart_rate_source_type', + type=FIELD_TYPES['source_type'], + def_num=19, + ), + 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, + ), + ), + ), + ), + ), + 254: Field( + name='message_index', + type=FIELD_TYPES['message_index'], + def_num=254, + ), + }, + ), + 259: MessageType( + name='dive_gas', + mesg_num=259, + fields={ + 0: Field( + name='helium_content', + type=BASE_TYPES[0x02], # uint8 + def_num=0, + units='percent', + ), + 1: Field( + name='oxygen_content', + type=BASE_TYPES[0x02], # uint8 + def_num=1, + units='percent', + ), + 2: Field( + name='status', + type=FIELD_TYPES['dive_gas_status'], + def_num=2, + ), + 254: Field( + name='message_index', + type=FIELD_TYPES['message_index'], + def_num=254, + ), + }, + ), + 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='time', + type=BASE_TYPES[0x85], # sint32 + def_num=1, + units='s', + ), + 2: Field( + name='enabled', + type=FIELD_TYPES['bool'], + def_num=2, + ), + 3: Field( + 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='dive_types', + type=FIELD_TYPES['sub_sport'], + def_num=5, + ), + 254: Field( # Index of the alarm + name='message_index', + type=FIELD_TYPES['message_index'], + def_num=254, + ), + }, + ), + 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( + name='reference_mesg', + type=FIELD_TYPES['mesg_num'], + def_num=0, + ), + 1: Field( + name='reference_index', + type=FIELD_TYPES['message_index'], + def_num=1, + ), + 2: Field( # 0 if above water + name='avg_depth', + type=BASE_TYPES[0x86], # uint32 + def_num=2, + scale=1000, + units='m', + ), + 3: Field( # 0 if above water + name='max_depth', + type=BASE_TYPES[0x86], # uint32 + def_num=3, + scale=1000, + units='m', + ), + 4: Field( # Time since end of last dive + name='surface_interval', + type=BASE_TYPES[0x86], # uint32 + def_num=4, + units='s', + ), + 5: Field( + name='start_cns', + type=BASE_TYPES[0x02], # uint8 + def_num=5, + units='percent', + ), + 6: Field( + name='end_cns', + type=BASE_TYPES[0x02], # uint8 + def_num=6, + 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='o2_toxicity', + type=BASE_TYPES[0x84], # uint16 + def_num=9, + units='OTUs', + ), + 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', + ), + 253: FIELD_TYPE_TIMESTAMP, + }, + ), + + + # ************************* Activity File Messages ************************* + 34: MessageType( + name='activity', + mesg_num=34, + fields={ + 0: Field( # Exclude pauses + name='total_timer_time', + type=BASE_TYPES[0x86], # uint32 + def_num=0, + scale=1000, + units='s', + ), + 1: Field( + name='num_sessions', + type=BASE_TYPES[0x84], # uint16 + def_num=1, + ), + 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, + }, + ), + + + # ********************** Blood Pressure File Messages ********************** + 51: MessageType( + name='blood_pressure', + mesg_num=51, + fields={ + 0: Field( + name='systolic_pressure', + type=BASE_TYPES[0x84], # uint16 + def_num=0, + units='mmHg', + ), + 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, + }, + ), + + + # ************************** Course File Messages ************************** + 31: MessageType( + name='course', + mesg_num=31, + fields={ + 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, + ), + }, + ), + + + # ************************** Device File Messages ************************** + 35: MessageType( + name='software', + mesg_num=35, + fields={ + 3: Field( + name='version', + type=BASE_TYPES[0x84], # uint16 + def_num=3, + scale=100, + ), + 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, + ), + }, + ), + + + # ************************** Goals File Messages *************************** + 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, + ), + }, + ), + + + # ************************ Monitoring File Messages ************************ + 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, + }, + ), + + + # ***************************** Other Messages ***************************** + 145: MessageType( + name='memo_glob', + mesg_num=145, + fields={ + 0: Field( # Block of utf8 bytes + name='memo', + type=BASE_TYPES[0x0D], # byte + 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 + def_num=1, + ), + 2: Field( # Index of external mesg + name='message_index', + type=FIELD_TYPES['message_index'], + def_num=2, + ), + 250: Field( # Sequence number of memo blocks + name='part_index', + type=BASE_TYPES[0x86], # uint32 + def_num=250, + ), + }, + ), + + + # ************************* Schedule File Messages ************************* + 28: MessageType( + name='schedule', + mesg_num=28, + fields={ + 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='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, + ), + ), + ), + ), + ), + 2: Field( # Corresponds to file_id of scheduled workout / course. + name='serial_number', + type=BASE_TYPES[0x8C], # uint32z + def_num=2, + ), + 3: Field( # Corresponds to file_id of scheduled workout / course. + name='time_created', + type=FIELD_TYPES['date_time'], + def_num=3, + ), + 4: Field( # TRUE if this activity has been started + name='completed', + type=FIELD_TYPES['bool'], + def_num=4, + ), + 5: Field( + name='type', + type=FIELD_TYPES['schedule'], + def_num=5, + ), + 6: Field( + name='scheduled_time', + type=FIELD_TYPES['local_date_time'], + def_num=6, + ), + }, + ), + + + # ************************* Segment File Messages ************************** + 148: MessageType( # Unique Identification data for a segment file + name='segment_id', + mesg_num=148, + fields={ + 0: Field( # Friendly name assigned to segment + name='name', + type=BASE_TYPES[0x07], # string + def_num=0, + ), + 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( # Primary key of the user that created the segment + name='user_profile_primary_key', + type=BASE_TYPES[0x86], # uint32 + def_num=4, + ), + 5: Field( # ID of the device that created the segment + name='device_id', + type=BASE_TYPES[0x86], # uint32 + def_num=5, + ), + 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( # Indicates if any segments should be deleted + name='delete_status', + type=FIELD_TYPES['segment_delete_status'], + 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'], + def_num=8, + ), + }, + ), + + + # *********************** Segment List File Messages *********************** + 151: MessageType( # Summary of the unique segment and leaderboard information associated with a segment file. This message is used to compile a segment list file describing all segment files on a device. The segment list file is used when refreshing the contents of a segment file with the latest available leaderboard information. + name='segment_file', + mesg_num=151, + fields={ + 1: Field( # UUID of the segment file + name='file_uuid', + type=BASE_TYPES[0x07], # string + def_num=1, + ), + 3: Field( # Enabled state of the segment file + name='enabled', + type=FIELD_TYPES['bool'], + def_num=3, + ), + 4: Field( # Primary key of the user that created the segment file + name='user_profile_primary_key', + type=BASE_TYPES[0x86], # uint32 + def_num=4, + ), + 7: Field( # Leader type of each leader in the segment file + name='leader_type', + type=FIELD_TYPES['segment_leaderboard_type'], + def_num=7, + ), + 8: Field( # Group primary key of each leader in the segment file + name='leader_group_primary_key', + type=BASE_TYPES[0x86], # uint32 + def_num=8, + ), + 9: Field( # Activity ID of each leader in the segment file + name='leader_activity_id', + type=BASE_TYPES[0x86], # uint32 + def_num=9, + ), + 10: Field( # String version of the activity ID of each leader in the segment file. 21 characters long for each ID, express in decimal + name='leader_activity_id_string', + type=BASE_TYPES[0x07], # string + def_num=10, + ), + 11: Field( # Index for the Leader Board entry selected as the default race participant + name='default_race_leader', + type=BASE_TYPES[0x02], # uint8 + def_num=11, + ), + 254: Field( + name='message_index', + type=FIELD_TYPES['message_index'], + def_num=254, + ), + }, + ), + + + # ************************* Settings File Messages ************************* + 2: MessageType( + name='device_settings', + mesg_num=2, + fields={ + 0: Field( # Index into time zone arrays. + name='active_time_zone', + type=BASE_TYPES[0x02], # uint8 + def_num=0, + ), + 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( # Offset from system time. + name='time_offset', + 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', + ), + 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=36, + ), + 39: Field( # UTC timestamp used to set the devices clock and date + name='clock_time', + type=FIELD_TYPES['date_time'], + def_num=39, + ), + 40: Field( # Bitfield to configure enabled screens for each supported loop + name='pages_enabled', + 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, + ), + 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=80, + ), + 86: Field( # Automatically upload using BLE + name='ble_auto_upload_enabled', + type=FIELD_TYPES['bool'], + def_num=86, + ), + 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=94, + ), + 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, + ), + }, + ), + 3: MessageType( + name='user_profile', + mesg_num=3, + fields={ + 0: Field( + name='friendly_name', + type=BASE_TYPES[0x07], # string + def_num=0, + ), + 1: Field( + name='gender', + type=FIELD_TYPES['gender'], + def_num=1, + ), + 2: Field( + name='age', + type=BASE_TYPES[0x02], # uint8 + def_num=2, + units='years', + ), + 3: Field( + name='height', + type=BASE_TYPES[0x02], # uint8 + def_num=3, + scale=100, + units='m', + ), + 4: Field( + name='weight', + type=BASE_TYPES[0x84], # uint16 + def_num=4, + scale=10, + units='kg', + ), + 5: Field( + name='language', + type=FIELD_TYPES['language'], + def_num=5, + ), + 6: Field( + name='elev_setting', + type=FIELD_TYPES['display_measure'], + def_num=6, + ), + 7: Field( + name='weight_setting', + type=FIELD_TYPES['display_measure'], + def_num=7, + ), + 8: Field( + name='resting_heart_rate', + type=BASE_TYPES[0x02], # uint8 + def_num=8, + units='bpm', + ), + 9: Field( + name='default_max_running_heart_rate', + type=BASE_TYPES[0x02], # uint8 + def_num=9, + units='bpm', + ), + 10: Field( + name='default_max_biking_heart_rate', + type=BASE_TYPES[0x02], # uint8 + def_num=10, + 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, + ), + }, + ), + + + # ********************** Sport Settings File Messages ********************** + 7: MessageType( + name='zones_target', + mesg_num=7, + fields={ + 1: Field( + name='max_heart_rate', + type=BASE_TYPES[0x02], # uint8 + def_num=1, + ), + 2: Field( + 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, + ), + }, + ), + + + # ************************** Totals File Messages ************************** + 33: MessageType( + name='totals', + mesg_num=33, + fields={ + 0: Field( # Excludes pauses + name='timer_time', + type=BASE_TYPES[0x86], # uint32 + def_num=0, + units='s', + ), + 1: Field( + name='distance', + type=BASE_TYPES[0x86], # uint32 + def_num=1, + units='m', + ), + 2: Field( + name='calories', + type=BASE_TYPES[0x86], # uint32 + def_num=2, + units='kcal', + ), + 3: Field( + name='sport', + type=FIELD_TYPES['sport'], + def_num=3, + ), + 4: Field( # Includes pauses + name='elapsed_time', + type=BASE_TYPES[0x86], # uint32 + def_num=4, + units='s', + ), + 5: Field( + name='sessions', + type=BASE_TYPES[0x84], # uint16 + def_num=5, + ), + 6: Field( + name='active_time', + type=BASE_TYPES[0x86], # uint32 + def_num=6, + units='s', + ), + 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'], + def_num=254, + ), + }, + ), + + + # *********************** Weight Scale File Messages *********************** + 30: MessageType( + name='weight_scale', + mesg_num=30, + fields={ + 0: Field( + name='weight', + type=FIELD_TYPES['weight'], + def_num=0, + scale=100, + units='kg', + ), + 1: Field( + name='percent_fat', + type=BASE_TYPES[0x84], # uint16 + def_num=1, + scale=100, + units='%', + ), + 2: Field( + name='percent_hydration', + type=BASE_TYPES[0x84], # uint16 + def_num=2, + scale=100, + units='%', + ), + 3: Field( + name='visceral_fat_mass', + type=BASE_TYPES[0x84], # uint16 + def_num=3, + scale=100, + units='kg', + ), + 4: Field( + name='bone_mass', + type=BASE_TYPES[0x84], # uint16 + def_num=4, + 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=12, + ), + 253: FIELD_TYPE_TIMESTAMP, + }, + ), + + + # ************************* Workout File Messages ************************** + 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, + ), + }, + ), +} From 798035875da1692e3165cc15319380967fa6b812 Mon Sep 17 00:00:00 2001 From: Patrick Dura Date: Mon, 28 May 2018 13:25:07 +0200 Subject: [PATCH 27/69] fix messages cache when multiple headers --- fitparse/base.py | 2 +- tests/files/sample_mulitple_header.fit | Bin 0 -> 80854 bytes tests/test.py | 5 +++++ 3 files changed, 6 insertions(+), 1 deletion(-) create mode 100644 tests/files/sample_mulitple_header.fit diff --git a/fitparse/base.py b/fitparse/base.py index 937d021..d3370b4 100644 --- a/fitparse/base.py +++ b/fitparse/base.py @@ -30,6 +30,7 @@ def __init__(self, fileish, check_crc=True, data_processor=None): self._file.seek(0, os.SEEK_END) self._filesize = self._file.tell() self._file.seek(0, os.SEEK_SET) + self._messages = [] # Start off by parsing the file header (sets initial attribute values) self._parse_file_header() @@ -98,7 +99,6 @@ def _parse_file_header(self): self._compressed_ts_accumulator = 0 self._crc = Crc() self._local_mesgs = {} - self._messages = [] header_data = self._read(12) if header_data[8:12] != b'.FIT': diff --git a/tests/files/sample_mulitple_header.fit b/tests/files/sample_mulitple_header.fit new file mode 100644 index 0000000000000000000000000000000000000000..f8d2d84beff61db95857ec52e21298e65225edb1 GIT binary patch literal 80854 zcmbrn2V50b*Y>?k+8g%0DtxMoYu{?m^B{cl@E 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

kLfu*X#Z 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, process_field_<>, process_units_<>, process_message_<> From 762c590fae429ca82d47d1f0ecf7d43d1c4dd86f Mon Sep 17 00:00:00 2001 From: David Cooper Date: Tue, 29 Jan 2019 15:43:06 -0800 Subject: [PATCH 28/69] License year bump. Happy new year! --- LICENSE | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/LICENSE b/LICENSE index 1f1d607..0e5daff 100644 --- a/LICENSE +++ b/LICENSE @@ -1,7 +1,7 @@ MIT License -Copyright (c) 2011-2018, David Cooper -Copyright (c) 2017-2018, Carey Metcalfe +Copyright (c) 2011-2019, David Cooper +Copyright (c) 2017-2019, Carey Metcalfe Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal From 8f83dd0368c137832f4e28dcc51460cc9bbda20d Mon Sep 17 00:00:00 2001 From: Bill Booth Date: Thu, 27 Dec 2018 10:50:05 -0800 Subject: [PATCH 29/69] Add coverage and a pip-compile generated test reqirements file - Add a CONTRIBUTING.md so you have a single place to read up on testing and developing within this project. - Add coverage.py so it is easy to see code coverage after running `coverage run run_tests.py`. - Add a requirements-test.txt to indicate the coverage package is a requirement of testing/coverage report generation. This was generated using pip-compile so dependency sources can be tracked. If tox is ever implemented, for example, this would be a useful way of showing requirements and then specifically where they're coming from. --- CONTRIBUTING.md | 18 ++++++++++++++++++ etc/requirements-test.in | 2 ++ requirements-test.txt | 11 +++++++++++ 3 files changed, 31 insertions(+) create mode 100644 CONTRIBUTING.md create mode 100644 etc/requirements-test.in create mode 100644 requirements-test.txt diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md new file mode 100644 index 0000000..7489c37 --- /dev/null +++ b/CONTRIBUTING.md @@ -0,0 +1,18 @@ +# Installing Test Dependencies + +`pip install -r requirements-test.txt` + +# Generating Test Requirements +Test requirements are shown in requirements-test.txt which is generated by pip-compile. You must first install pip-compile with `pip install pip-tools`. Then generate the final requirements file. + +`pip-compile --output-file requirements-test.txt etc/requirements-test.in` + +# Testing With Code Coverage + +To run unit tests with coverage: + +`coverage run run_tests.py` + +To get a report: + +`coverage report` diff --git a/etc/requirements-test.in b/etc/requirements-test.in new file mode 100644 index 0000000..5c90533 --- /dev/null +++ b/etc/requirements-test.in @@ -0,0 +1,2 @@ +pip-tools +coverage diff --git a/requirements-test.txt b/requirements-test.txt new file mode 100644 index 0000000..020c014 --- /dev/null +++ b/requirements-test.txt @@ -0,0 +1,11 @@ +# +# This file is autogenerated by pip-compile +# To update, run: +# +# pip-compile --output-file requirements-test.txt etc/requirements-test.in +# + +click==7.0 # via pip-tools +coverage==4.5.2 +pip-tools==3.2.0 +six==1.12.0 # via pip-tools From 470ff2995c789b5bce3f7fab5bc15bf21848b810 Mon Sep 17 00:00:00 2001 From: Carey Metcalfe Date: Wed, 27 Feb 2019 11:47:40 -0500 Subject: [PATCH 30/69] Bump version to v1.1.0 --- fitparse/__init__.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/fitparse/__init__.py b/fitparse/__init__.py index 1bbc49e..9053f66 100644 --- a/fitparse/__init__.py +++ b/fitparse/__init__.py @@ -3,7 +3,7 @@ from fitparse.processors import FitFileDataProcessor, StandardUnitsDataProcessor -__version__ = '1.0.1' +__version__ = '1.1.0' __all__ = [ 'FitFileDataProcessor', 'FitFile', 'FitParseError', 'StandardUnitsDataProcessor', 'DataMessage' From 99ea8450ee8abcfacd60a562d1e68f4460a58ba7 Mon Sep 17 00:00:00 2001 From: twain young Date: Tue, 5 Mar 2019 14:19:35 +0800 Subject: [PATCH 31/69] fix Wipe out scale, units, offset problem --- fitparse/profile.py | 24181 ++++++++-------- scripts/generate_profile.py | 6 +- .../2019-02-17-062644-ELEMNT-297E-195-0.fit | Bin 0 -> 715726 bytes tests/test.py | 4 + 4 files changed, 12115 insertions(+), 12076 deletions(-) create mode 100644 tests/files/2019-02-17-062644-ELEMNT-297E-195-0.fit diff --git a/fitparse/profile.py b/fitparse/profile.py index ad4fe6b..aa6ddbd 100644 --- a/fitparse/profile.py +++ b/fitparse/profile.py @@ -1,12074 +1,12107 @@ - -# ***************** BEGIN AUTOMATICALLY GENERATED FIT PROFILE ****************** -# *************************** DO NOT EDIT THIS FILE **************************** -# *********** EXPORTED PROFILE FROM SDK VERSION 20.66 ON 2018-07-18 ************ -# ********* PARSED 161 TYPES (2985 VALUES), 85 MESSAGES (1038 FIELDS) ********** - -from fitparse.records import ( - ComponentField, - Field, - FieldType, - MessageType, - ReferenceField, - SubField, - BASE_TYPES, -) - - -FIELD_NUM_TIMESTAMP = 253 - - -FIELD_TYPES = { - 'activity': FieldType( - name='activity', - base_type=BASE_TYPES[0x00], # enum - values={ - 0: 'manual', - 1: 'auto_multi_sport', - }, - ), - 'activity_class': FieldType( - name='activity_class', - base_type=BASE_TYPES[0x00], # enum - values={ - 100: 'level_max', - 0x7F: 'level', # 0 to 100 - 0x80: 'athlete', - }, - ), - 'activity_level': FieldType( - name='activity_level', - base_type=BASE_TYPES[0x00], # enum - values={ - 0: 'low', - 1: 'medium', - 2: 'high', - }, - ), - 'activity_subtype': FieldType( - name='activity_subtype', - base_type=BASE_TYPES[0x00], # enum - values={ - 0: 'generic', - 1: 'treadmill', # Run - 2: 'street', # Run - 3: 'trail', # Run - 4: 'track', # Run - 5: 'spin', # Cycling - 6: 'indoor_cycling', # Cycling - 7: 'road', # Cycling - 8: 'mountain', # Cycling - 9: 'downhill', # Cycling - 10: 'recumbent', # Cycling - 11: 'cyclocross', # Cycling - 12: 'hand_cycling', # Cycling - 13: 'track_cycling', # Cycling - 14: 'indoor_rowing', # Fitness Equipment - 15: 'elliptical', # Fitness Equipment - 16: 'stair_climbing', # Fitness Equipment - 17: 'lap_swimming', # Swimming - 18: 'open_water', # Swimming - 254: 'all', - }, - ), - 'activity_type': FieldType( - name='activity_type', - base_type=BASE_TYPES[0x00], # enum - values={ - 0: 'generic', - 1: 'running', - 2: 'cycling', - 3: 'transition', # Mulitsport transition - 4: 'fitness_equipment', - 5: 'swimming', - 6: 'walking', - 8: 'sedentary', - 254: 'all', # All is for goals only to include all sports. - }, - ), - 'analog_watchface_layout': FieldType( - name='analog_watchface_layout', - base_type=BASE_TYPES[0x00], # enum - values={ - 0: 'minimal', - 1: 'traditional', - 2: 'modern', - }, - ), - 'ant_network': FieldType( - name='ant_network', - base_type=BASE_TYPES[0x00], # enum - values={ - 0: 'public', - 1: 'antplus', - 2: 'antfs', - 3: 'private', - }, - ), - 'antplus_device_type': FieldType( - name='antplus_device_type', - base_type=BASE_TYPES[0x02], # uint8 - values={ - 1: 'antfs', - 11: 'bike_power', - 12: 'environment_sensor_legacy', - 15: 'multi_sport_speed_distance', - 16: 'control', - 17: 'fitness_equipment', - 18: 'blood_pressure', - 19: 'geocache_node', - 20: 'light_electric_vehicle', - 25: 'env_sensor', - 26: 'racquet', - 27: 'control_hub', - 31: 'muscle_oxygen', - 35: 'bike_light_main', - 36: 'bike_light_shared', - 38: 'exd', - 40: 'bike_radar', - 119: 'weight_scale', - 120: 'heart_rate', - 121: 'bike_speed_cadence', - 122: 'bike_cadence', - 123: 'bike_speed', - 124: 'stride_speed_distance', - }, - ), - 'attitude_stage': FieldType( - name='attitude_stage', - base_type=BASE_TYPES[0x00], # enum - values={ - 0: 'failed', - 1: 'aligning', - 2: 'degraded', - 3: 'valid', - }, - ), - 'attitude_validity': FieldType( - name='attitude_validity', - base_type=BASE_TYPES[0x84], # uint16 - values={ - 0x0001: 'track_angle_heading_valid', - 0x0002: 'pitch_valid', - 0x0004: 'roll_valid', - 0x0008: 'lateral_body_accel_valid', - 0x0010: 'normal_body_accel_valid', - 0x0020: 'turn_rate_valid', - 0x0040: 'hw_fail', - 0x0080: 'mag_invalid', - 0x0100: 'no_gps', - 0x0200: 'gps_invalid', - 0x0400: 'solution_coasting', - 0x0800: 'true_track_angle', - 0x1000: 'magnetic_heading', - }, - ), - 'auto_activity_detect': FieldType( - name='auto_activity_detect', - base_type=BASE_TYPES[0x86], # uint32 - values={ - 0x00000000: 'none', - 0x00000001: 'running', - 0x00000002: 'cycling', - 0x00000004: 'swimming', - 0x00000008: 'walking', - 0x00000020: 'elliptical', - 0x00000400: 'sedentary', - }, - ), - 'auto_sync_frequency': FieldType( - name='auto_sync_frequency', - base_type=BASE_TYPES[0x00], # enum - values={ - 0: 'never', - 1: 'occasionally', - 2: 'frequent', - 3: 'once_a_day', - 4: 'remote', - }, - ), - 'autolap_trigger': FieldType( - name='autolap_trigger', - base_type=BASE_TYPES[0x00], # enum - values={ - 0: 'time', - 1: 'distance', - 2: 'position_start', - 3: 'position_lap', - 4: 'position_waypoint', - 5: 'position_marked', - 6: 'off', - }, - ), - 'autoscroll': FieldType( - name='autoscroll', - base_type=BASE_TYPES[0x00], # enum - values={ - 0: 'none', - 1: 'slow', - 2: 'medium', - 3: 'fast', - }, - ), - 'backlight_mode': FieldType( - name='backlight_mode', - base_type=BASE_TYPES[0x00], # enum - values={ - 0: 'off', - 1: 'manual', - 2: 'key_and_messages', - 3: 'auto_brightness', - 4: 'smart_notifications', - 5: 'key_and_messages_night', - 6: 'key_and_messages_and_smart_notifications', - }, - ), - 'backlight_timeout': FieldType( # Timeout in seconds. - name='backlight_timeout', - base_type=BASE_TYPES[0x02], # uint8 - values={ - 0: 'infinite', # Backlight stays on forever. - }, - ), - 'battery_status': FieldType( - name='battery_status', - base_type=BASE_TYPES[0x02], # uint8 - values={ - 1: 'new', - 2: 'good', - 3: 'ok', - 4: 'low', - 5: 'critical', - 6: 'charging', - 7: 'unknown', - }, - ), - 'bench_press_exercise_name': FieldType( - name='bench_press_exercise_name', - base_type=BASE_TYPES[0x84], # uint16 - values={ - 0: 'alternating_dumbbell_chest_press_on_swiss_ball', - 1: 'barbell_bench_press', - 2: 'barbell_board_bench_press', - 3: 'barbell_floor_press', - 4: 'close_grip_barbell_bench_press', - 5: 'decline_dumbbell_bench_press', - 6: 'dumbbell_bench_press', - 7: 'dumbbell_floor_press', - 8: 'incline_barbell_bench_press', - 9: 'incline_dumbbell_bench_press', - 10: 'incline_smith_machine_bench_press', - 11: 'isometric_barbell_bench_press', - 12: 'kettlebell_chest_press', - 13: 'neutral_grip_dumbbell_bench_press', - 14: 'neutral_grip_dumbbell_incline_bench_press', - 15: 'one_arm_floor_press', - 16: 'weighted_one_arm_floor_press', - 17: 'partial_lockout', - 18: 'reverse_grip_barbell_bench_press', - 19: 'reverse_grip_incline_bench_press', - 20: 'single_arm_cable_chest_press', - 21: 'single_arm_dumbbell_bench_press', - 22: 'smith_machine_bench_press', - 23: 'swiss_ball_dumbbell_chest_press', - 24: 'triple_stop_barbell_bench_press', - 25: 'wide_grip_barbell_bench_press', - 26: 'alternating_dumbbell_chest_press', - }, - ), - 'bike_light_beam_angle_mode': FieldType( - name='bike_light_beam_angle_mode', - base_type=BASE_TYPES[0x02], # uint8 - values={ - 0: 'manual', - 1: 'auto', - }, - ), - 'bike_light_network_config_type': FieldType( - name='bike_light_network_config_type', - base_type=BASE_TYPES[0x00], # enum - values={ - 0: 'auto', - 4: 'individual', - 5: 'high_visibility', - 6: 'trail', - }, - ), - 'body_location': FieldType( - name='body_location', - base_type=BASE_TYPES[0x00], # enum - values={ - 0: 'left_leg', - 1: 'left_calf', - 2: 'left_shin', - 3: 'left_hamstring', - 4: 'left_quad', - 5: 'left_glute', - 6: 'right_leg', - 7: 'right_calf', - 8: 'right_shin', - 9: 'right_hamstring', - 10: 'right_quad', - 11: 'right_glute', - 12: 'torso_back', - 13: 'left_lower_back', - 14: 'left_upper_back', - 15: 'right_lower_back', - 16: 'right_upper_back', - 17: 'torso_front', - 18: 'left_abdomen', - 19: 'left_chest', - 20: 'right_abdomen', - 21: 'right_chest', - 22: 'left_arm', - 23: 'left_shoulder', - 24: 'left_bicep', - 25: 'left_tricep', - 26: 'left_brachioradialis', # Left anterior forearm - 27: 'left_forearm_extensors', # Left posterior forearm - 28: 'right_arm', - 29: 'right_shoulder', - 30: 'right_bicep', - 31: 'right_tricep', - 32: 'right_brachioradialis', # Right anterior forearm - 33: 'right_forearm_extensors', # Right posterior forearm - 34: 'neck', - 35: 'throat', - 36: 'waist_mid_back', - 37: 'waist_front', - 38: 'waist_left', - 39: 'waist_right', - }, - ), - 'bool': FieldType( - name='bool', - base_type=BASE_TYPES[0x00], # enum - ), - 'bp_status': FieldType( - name='bp_status', - base_type=BASE_TYPES[0x00], # enum - values={ - 0: 'no_error', - 1: 'error_incomplete_data', - 2: 'error_no_measurement', - 3: 'error_data_out_of_range', - 4: 'error_irregular_heart_rate', - }, - ), - 'calf_raise_exercise_name': FieldType( - name='calf_raise_exercise_name', - base_type=BASE_TYPES[0x84], # uint16 - values={ - 0: '3_way_calf_raise', - 1: '3_way_weighted_calf_raise', - 2: '3_way_single_leg_calf_raise', - 3: '3_way_weighted_single_leg_calf_raise', - 4: 'donkey_calf_raise', - 5: 'weighted_donkey_calf_raise', - 6: 'seated_calf_raise', - 7: 'weighted_seated_calf_raise', - 8: 'seated_dumbbell_toe_raise', - 9: 'single_leg_bent_knee_calf_raise', - 10: 'weighted_single_leg_bent_knee_calf_raise', - 11: 'single_leg_decline_push_up', - 12: 'single_leg_donkey_calf_raise', - 13: 'weighted_single_leg_donkey_calf_raise', - 14: 'single_leg_hip_raise_with_knee_hold', - 15: 'single_leg_standing_calf_raise', - 16: 'single_leg_standing_dumbbell_calf_raise', - 17: 'standing_barbell_calf_raise', - 18: 'standing_calf_raise', - 19: 'weighted_standing_calf_raise', - 20: 'standing_dumbbell_calf_raise', - }, - ), - 'camera_event_type': FieldType( - name='camera_event_type', - base_type=BASE_TYPES[0x00], # enum - values={ - 0: 'video_start', # Start of video recording - 1: 'video_split', # Mark of video file split (end of one file, beginning of the other) - 2: 'video_end', # End of video recording - 3: 'photo_taken', # Still photo taken - 4: 'video_second_stream_start', - 5: 'video_second_stream_split', - 6: 'video_second_stream_end', - 7: 'video_split_start', # Mark of video file split start - 8: 'video_second_stream_split_start', - 11: 'video_pause', # Mark when a video recording has been paused - 12: 'video_second_stream_pause', - 13: 'video_resume', # Mark when a video recording has been resumed - 14: 'video_second_stream_resume', - }, - ), - 'camera_orientation_type': FieldType( - name='camera_orientation_type', - base_type=BASE_TYPES[0x00], # enum - values={ - 0: 'camera_orientation_0', - 1: 'camera_orientation_90', - 2: 'camera_orientation_180', - 3: 'camera_orientation_270', - }, - ), - 'cardio_exercise_name': FieldType( - name='cardio_exercise_name', - base_type=BASE_TYPES[0x84], # uint16 - values={ - 0: 'bob_and_weave_circle', - 1: 'weighted_bob_and_weave_circle', - 2: 'cardio_core_crawl', - 3: 'weighted_cardio_core_crawl', - 4: 'double_under', - 5: 'weighted_double_under', - 6: 'jump_rope', - 7: 'weighted_jump_rope', - 8: 'jump_rope_crossover', - 9: 'weighted_jump_rope_crossover', - 10: 'jump_rope_jog', - 11: 'weighted_jump_rope_jog', - 12: 'jumping_jacks', - 13: 'weighted_jumping_jacks', - 14: 'ski_moguls', - 15: 'weighted_ski_moguls', - 16: 'split_jacks', - 17: 'weighted_split_jacks', - 18: 'squat_jacks', - 19: 'weighted_squat_jacks', - 20: 'triple_under', - 21: 'weighted_triple_under', - }, - ), - 'carry_exercise_name': FieldType( - name='carry_exercise_name', - base_type=BASE_TYPES[0x84], # uint16 - values={ - 0: 'bar_holds', - 1: 'farmers_walk', - 2: 'farmers_walk_on_toes', - 3: 'hex_dumbbell_hold', - 4: 'overhead_carry', - }, - ), - 'checksum': FieldType( - name='checksum', - base_type=BASE_TYPES[0x02], # uint8 - values={ - 0: 'clear', # Allows clear of checksum for flash memory where can only write 1 to 0 without erasing sector. - 1: 'ok', # Set to mark checksum as valid if computes to invalid values 0 or 0xFF. Checksum can also be set to ok to save encoding computation time. - }, - ), - 'chop_exercise_name': FieldType( - name='chop_exercise_name', - base_type=BASE_TYPES[0x84], # uint16 - values={ - 0: 'cable_pull_through', - 1: 'cable_rotational_lift', - 2: 'cable_woodchop', - 3: 'cross_chop_to_knee', - 4: 'weighted_cross_chop_to_knee', - 5: 'dumbbell_chop', - 6: 'half_kneeling_rotation', - 7: 'weighted_half_kneeling_rotation', - 8: 'half_kneeling_rotational_chop', - 9: 'half_kneeling_rotational_reverse_chop', - 10: 'half_kneeling_stability_chop', - 11: 'half_kneeling_stability_reverse_chop', - 12: 'kneeling_rotational_chop', - 13: 'kneeling_rotational_reverse_chop', - 14: 'kneeling_stability_chop', - 15: 'kneeling_woodchopper', - 16: 'medicine_ball_wood_chops', - 17: 'power_squat_chops', - 18: 'weighted_power_squat_chops', - 19: 'standing_rotational_chop', - 20: 'standing_split_rotational_chop', - 21: 'standing_split_rotational_reverse_chop', - 22: 'standing_stability_reverse_chop', - }, - ), - 'comm_timeout_type': FieldType( - name='comm_timeout_type', - base_type=BASE_TYPES[0x84], # uint16 - values={ - 0: 'wildcard_pairing_timeout', # Timeout pairing to any device - 1: 'pairing_timeout', # Timeout pairing to previously paired device - 2: 'connection_lost', # Temporary loss of communications - 3: 'connection_timeout', # Connection closed due to extended bad communications - }, - ), - 'connectivity_capabilities': FieldType( - name='connectivity_capabilities', - base_type=BASE_TYPES[0x8C], # uint32z - values={ - 0x00000001: 'bluetooth', - 0x00000002: 'bluetooth_le', - 0x00000004: 'ant', - 0x00000008: 'activity_upload', - 0x00000010: 'course_download', - 0x00000020: 'workout_download', - 0x00000040: 'live_track', - 0x00000080: 'weather_conditions', - 0x00000100: 'weather_alerts', - 0x00000200: 'gps_ephemeris_download', - 0x00000400: 'explicit_archive', - 0x00000800: 'setup_incomplete', - 0x00001000: 'continue_sync_after_software_update', - 0x00002000: 'connect_iq_app_download', - 0x00004000: 'golf_course_download', - 0x00008000: 'device_initiates_sync', # Indicates device is in control of initiating all syncs - 0x00010000: 'connect_iq_watch_app_download', - 0x00020000: 'connect_iq_widget_download', - 0x00040000: 'connect_iq_watch_face_download', - 0x00080000: 'connect_iq_data_field_download', - 0x00100000: 'connect_iq_app_managment', # Device supports delete and reorder of apps via GCM - 0x00200000: 'swing_sensor', - 0x00400000: 'swing_sensor_remote', - 0x00800000: 'incident_detection', # Device supports incident detection - 0x01000000: 'audio_prompts', - 0x02000000: 'wifi_verification', # Device supports reporting wifi verification via GCM - 0x04000000: 'true_up', # Device supports True Up - 0x08000000: 'find_my_watch', # Device supports Find My Watch - 0x10000000: 'remote_manual_sync', - 0x20000000: 'live_track_auto_start', # Device supports LiveTrack auto start - 0x40000000: 'live_track_messaging', # Device supports LiveTrack Messaging - 0x80000000: 'instant_input', # Device supports instant input feature - }, - ), - 'core_exercise_name': FieldType( - name='core_exercise_name', - base_type=BASE_TYPES[0x84], # uint16 - values={ - 0: 'abs_jabs', - 1: 'weighted_abs_jabs', - 2: 'alternating_plate_reach', - 3: 'barbell_rollout', - 4: 'weighted_barbell_rollout', - 5: 'body_bar_oblique_twist', - 6: 'cable_core_press', - 7: 'cable_side_bend', - 8: 'side_bend', - 9: 'weighted_side_bend', - 10: 'crescent_circle', - 11: 'weighted_crescent_circle', - 12: 'cycling_russian_twist', - 13: 'weighted_cycling_russian_twist', - 14: 'elevated_feet_russian_twist', - 15: 'weighted_elevated_feet_russian_twist', - 16: 'half_turkish_get_up', - 17: 'kettlebell_windmill', - 18: 'kneeling_ab_wheel', - 19: 'weighted_kneeling_ab_wheel', - 20: 'modified_front_lever', - 21: 'open_knee_tucks', - 22: 'weighted_open_knee_tucks', - 23: 'side_abs_leg_lift', - 24: 'weighted_side_abs_leg_lift', - 25: 'swiss_ball_jackknife', - 26: 'weighted_swiss_ball_jackknife', - 27: 'swiss_ball_pike', - 28: 'weighted_swiss_ball_pike', - 29: 'swiss_ball_rollout', - 30: 'weighted_swiss_ball_rollout', - 31: 'triangle_hip_press', - 32: 'weighted_triangle_hip_press', - 33: 'trx_suspended_jackknife', - 34: 'weighted_trx_suspended_jackknife', - 35: 'u_boat', - 36: 'weighted_u_boat', - 37: 'windmill_switches', - 38: 'weighted_windmill_switches', - 39: 'alternating_slide_out', - 40: 'weighted_alternating_slide_out', - 41: 'ghd_back_extensions', - 42: 'weighted_ghd_back_extensions', - 43: 'overhead_walk', - 44: 'inchworm', - 45: 'weighted_modified_front_lever', - }, - ), - 'course_capabilities': FieldType( - name='course_capabilities', - base_type=BASE_TYPES[0x8C], # uint32z - values={ - 0x00000001: 'processed', - 0x00000002: 'valid', - 0x00000004: 'time', - 0x00000008: 'distance', - 0x00000010: 'position', - 0x00000020: 'heart_rate', - 0x00000040: 'power', - 0x00000080: 'cadence', - 0x00000100: 'training', - 0x00000200: 'navigation', - 0x00000400: 'bikeway', - }, - ), - 'course_point': FieldType( - name='course_point', - base_type=BASE_TYPES[0x00], # enum - values={ - 0: 'generic', - 1: 'summit', - 2: 'valley', - 3: 'water', - 4: 'food', - 5: 'danger', - 6: 'left', - 7: 'right', - 8: 'straight', - 9: 'first_aid', - 10: 'fourth_category', - 11: 'third_category', - 12: 'second_category', - 13: 'first_category', - 14: 'hors_category', - 15: 'sprint', - 16: 'left_fork', - 17: 'right_fork', - 18: 'middle_fork', - 19: 'slight_left', - 20: 'sharp_left', - 21: 'slight_right', - 22: 'sharp_right', - 23: 'u_turn', - 24: 'segment_start', - 25: 'segment_end', - }, - ), - 'crunch_exercise_name': FieldType( - name='crunch_exercise_name', - base_type=BASE_TYPES[0x84], # uint16 - values={ - 0: 'bicycle_crunch', - 1: 'cable_crunch', - 2: 'circular_arm_crunch', - 3: 'crossed_arms_crunch', - 4: 'weighted_crossed_arms_crunch', - 5: 'cross_leg_reverse_crunch', - 6: 'weighted_cross_leg_reverse_crunch', - 7: 'crunch_chop', - 8: 'weighted_crunch_chop', - 9: 'double_crunch', - 10: 'weighted_double_crunch', - 11: 'elbow_to_knee_crunch', - 12: 'weighted_elbow_to_knee_crunch', - 13: 'flutter_kicks', - 14: 'weighted_flutter_kicks', - 15: 'foam_roller_reverse_crunch_on_bench', - 16: 'weighted_foam_roller_reverse_crunch_on_bench', - 17: 'foam_roller_reverse_crunch_with_dumbbell', - 18: 'foam_roller_reverse_crunch_with_medicine_ball', - 19: 'frog_press', - 20: 'hanging_knee_raise_oblique_crunch', - 21: 'weighted_hanging_knee_raise_oblique_crunch', - 22: 'hip_crossover', - 23: 'weighted_hip_crossover', - 24: 'hollow_rock', - 25: 'weighted_hollow_rock', - 26: 'incline_reverse_crunch', - 27: 'weighted_incline_reverse_crunch', - 28: 'kneeling_cable_crunch', - 29: 'kneeling_cross_crunch', - 30: 'weighted_kneeling_cross_crunch', - 31: 'kneeling_oblique_cable_crunch', - 32: 'knees_to_elbow', - 33: 'leg_extensions', - 34: 'weighted_leg_extensions', - 35: 'leg_levers', - 36: 'mcgill_curl_up', - 37: 'weighted_mcgill_curl_up', - 38: 'modified_pilates_roll_up_with_ball', - 39: 'weighted_modified_pilates_roll_up_with_ball', - 40: 'pilates_crunch', - 41: 'weighted_pilates_crunch', - 42: 'pilates_roll_up_with_ball', - 43: 'weighted_pilates_roll_up_with_ball', - 44: 'raised_legs_crunch', - 45: 'weighted_raised_legs_crunch', - 46: 'reverse_crunch', - 47: 'weighted_reverse_crunch', - 48: 'reverse_crunch_on_a_bench', - 49: 'weighted_reverse_crunch_on_a_bench', - 50: 'reverse_curl_and_lift', - 51: 'weighted_reverse_curl_and_lift', - 52: 'rotational_lift', - 53: 'weighted_rotational_lift', - 54: 'seated_alternating_reverse_crunch', - 55: 'weighted_seated_alternating_reverse_crunch', - 56: 'seated_leg_u', - 57: 'weighted_seated_leg_u', - 58: 'side_to_side_crunch_and_weave', - 59: 'weighted_side_to_side_crunch_and_weave', - 60: 'single_leg_reverse_crunch', - 61: 'weighted_single_leg_reverse_crunch', - 62: 'skater_crunch_cross', - 63: 'weighted_skater_crunch_cross', - 64: 'standing_cable_crunch', - 65: 'standing_side_crunch', - 66: 'step_climb', - 67: 'weighted_step_climb', - 68: 'swiss_ball_crunch', - 69: 'swiss_ball_reverse_crunch', - 70: 'weighted_swiss_ball_reverse_crunch', - 71: 'swiss_ball_russian_twist', - 72: 'weighted_swiss_ball_russian_twist', - 73: 'swiss_ball_side_crunch', - 74: 'weighted_swiss_ball_side_crunch', - 75: 'thoracic_crunches_on_foam_roller', - 76: 'weighted_thoracic_crunches_on_foam_roller', - 77: 'triceps_crunch', - 78: 'weighted_bicycle_crunch', - 79: 'weighted_crunch', - 80: 'weighted_swiss_ball_crunch', - 81: 'toes_to_bar', - 82: 'weighted_toes_to_bar', - 83: 'crunch', - }, - ), - 'curl_exercise_name': FieldType( - name='curl_exercise_name', - base_type=BASE_TYPES[0x84], # uint16 - values={ - 0: 'alternating_dumbbell_biceps_curl', - 1: 'alternating_dumbbell_biceps_curl_on_swiss_ball', - 2: 'alternating_incline_dumbbell_biceps_curl', - 3: 'barbell_biceps_curl', - 4: 'barbell_reverse_wrist_curl', - 5: 'barbell_wrist_curl', - 6: 'behind_the_back_barbell_reverse_wrist_curl', - 7: 'behind_the_back_one_arm_cable_curl', - 8: 'cable_biceps_curl', - 9: 'cable_hammer_curl', - 10: 'cheating_barbell_biceps_curl', - 11: 'close_grip_ez_bar_biceps_curl', - 12: 'cross_body_dumbbell_hammer_curl', - 13: 'dead_hang_biceps_curl', - 14: 'decline_hammer_curl', - 15: 'dumbbell_biceps_curl_with_static_hold', - 16: 'dumbbell_hammer_curl', - 17: 'dumbbell_reverse_wrist_curl', - 18: 'dumbbell_wrist_curl', - 19: 'ez_bar_preacher_curl', - 20: 'forward_bend_biceps_curl', - 21: 'hammer_curl_to_press', - 22: 'incline_dumbbell_biceps_curl', - 23: 'incline_offset_thumb_dumbbell_curl', - 24: 'kettlebell_biceps_curl', - 25: 'lying_concentration_cable_curl', - 26: 'one_arm_preacher_curl', - 27: 'plate_pinch_curl', - 28: 'preacher_curl_with_cable', - 29: 'reverse_ez_bar_curl', - 30: 'reverse_grip_wrist_curl', - 31: 'reverse_grip_barbell_biceps_curl', - 32: 'seated_alternating_dumbbell_biceps_curl', - 33: 'seated_dumbbell_biceps_curl', - 34: 'seated_reverse_dumbbell_curl', - 35: 'split_stance_offset_pinky_dumbbell_curl', - 36: 'standing_alternating_dumbbell_curls', - 37: 'standing_dumbbell_biceps_curl', - 38: 'standing_ez_bar_biceps_curl', - 39: 'static_curl', - 40: 'swiss_ball_dumbbell_overhead_triceps_extension', - 41: 'swiss_ball_ez_bar_preacher_curl', - 42: 'twisting_standing_dumbbell_biceps_curl', - 43: 'wide_grip_ez_bar_biceps_curl', - }, - ), - 'date_mode': FieldType( - name='date_mode', - base_type=BASE_TYPES[0x00], # enum - values={ - 0: 'day_month', - 1: 'month_day', - }, - ), - 'date_time': FieldType( # seconds since UTC 00:00 Dec 31 1989 - name='date_time', - base_type=BASE_TYPES[0x86], # uint32 - ), - 'day_of_week': FieldType( - name='day_of_week', - base_type=BASE_TYPES[0x00], # enum - values={ - 0: 'sunday', - 1: 'monday', - 2: 'tuesday', - 3: 'wednesday', - 4: 'thursday', - 5: 'friday', - 6: 'saturday', - }, - ), - 'deadlift_exercise_name': FieldType( - name='deadlift_exercise_name', - base_type=BASE_TYPES[0x84], # uint16 - values={ - 0: 'barbell_deadlift', - 1: 'barbell_straight_leg_deadlift', - 2: 'dumbbell_deadlift', - 3: 'dumbbell_single_leg_deadlift_to_row', - 4: 'dumbbell_straight_leg_deadlift', - 5: 'kettlebell_floor_to_shelf', - 6: 'one_arm_one_leg_deadlift', - 7: 'rack_pull', - 8: 'rotational_dumbbell_straight_leg_deadlift', - 9: 'single_arm_deadlift', - 10: 'single_leg_barbell_deadlift', - 11: 'single_leg_barbell_straight_leg_deadlift', - 12: 'single_leg_deadlift_with_barbell', - 13: 'single_leg_rdl_circuit', - 14: 'single_leg_romanian_deadlift_with_dumbbell', - 15: 'sumo_deadlift', - 16: 'sumo_deadlift_high_pull', - 17: 'trap_bar_deadlift', - 18: 'wide_grip_barbell_deadlift', - }, - ), - 'device_index': FieldType( - name='device_index', - base_type=BASE_TYPES[0x02], # uint8 - values={ - 0: 'creator', # Creator of the file is always device index 0. - }, - ), - 'digital_watchface_layout': FieldType( - name='digital_watchface_layout', - base_type=BASE_TYPES[0x00], # enum - values={ - 0: 'traditional', - 1: 'modern', - 2: 'bold', - }, - ), - 'display_heart': FieldType( - name='display_heart', - base_type=BASE_TYPES[0x00], # enum - values={ - 0: 'bpm', - 1: 'max', - 2: 'reserve', - }, - ), - 'display_measure': FieldType( - name='display_measure', - base_type=BASE_TYPES[0x00], # enum - values={ - 0: 'metric', - 1: 'statute', - 2: 'nautical', - }, - ), - 'display_orientation': FieldType( - name='display_orientation', - base_type=BASE_TYPES[0x00], # enum - values={ - 0: 'auto', # automatic if the device supports it - 1: 'portrait', - 2: 'landscape', - 3: 'portrait_flipped', # portrait mode but rotated 180 degrees - 4: 'landscape_flipped', # landscape mode but rotated 180 degrees - }, - ), - 'display_position': FieldType( - name='display_position', - base_type=BASE_TYPES[0x00], # enum - values={ - 0: 'degree', # dd.dddddd - 1: 'degree_minute', # dddmm.mmm - 2: 'degree_minute_second', # dddmmss - 3: 'austrian_grid', # Austrian Grid (BMN) - 4: 'british_grid', # British National Grid - 5: 'dutch_grid', # Dutch grid system - 6: 'hungarian_grid', # Hungarian grid system - 7: 'finnish_grid', # Finnish grid system Zone3 KKJ27 - 8: 'german_grid', # Gausss Krueger (German) - 9: 'icelandic_grid', # Icelandic Grid - 10: 'indonesian_equatorial', # Indonesian Equatorial LCO - 11: 'indonesian_irian', # Indonesian Irian LCO - 12: 'indonesian_southern', # Indonesian Southern LCO - 13: 'india_zone_0', # India zone 0 - 14: 'india_zone_IA', # India zone IA - 15: 'india_zone_IB', # India zone IB - 16: 'india_zone_IIA', # India zone IIA - 17: 'india_zone_IIB', # India zone IIB - 18: 'india_zone_IIIA', # India zone IIIA - 19: 'india_zone_IIIB', # India zone IIIB - 20: 'india_zone_IVA', # India zone IVA - 21: 'india_zone_IVB', # India zone IVB - 22: 'irish_transverse', # Irish Transverse Mercator - 23: 'irish_grid', # Irish Grid - 24: 'loran', # Loran TD - 25: 'maidenhead_grid', # Maidenhead grid system - 26: 'mgrs_grid', # MGRS grid system - 27: 'new_zealand_grid', # New Zealand grid system - 28: 'new_zealand_transverse', # New Zealand Transverse Mercator - 29: 'qatar_grid', # Qatar National Grid - 30: 'modified_swedish_grid', # Modified RT-90 (Sweden) - 31: 'swedish_grid', # RT-90 (Sweden) - 32: 'south_african_grid', # South African Grid - 33: 'swiss_grid', # Swiss CH-1903 grid - 34: 'taiwan_grid', # Taiwan Grid - 35: 'united_states_grid', # United States National Grid - 36: 'utm_ups_grid', # UTM/UPS grid system - 37: 'west_malayan', # West Malayan RSO - 38: 'borneo_rso', # Borneo RSO - 39: 'estonian_grid', # Estonian grid system - 40: 'latvian_grid', # Latvian Transverse Mercator - 41: 'swedish_ref_99_grid', # Reference Grid 99 TM (Swedish) - }, - ), - 'display_power': FieldType( - name='display_power', - base_type=BASE_TYPES[0x00], # enum - values={ - 0: 'watts', - 1: 'percent_ftp', - }, - ), - 'dive_alarm_type': FieldType( - name='dive_alarm_type', - base_type=BASE_TYPES[0x00], # enum - values={ - 0: 'depth', - 1: 'time', - }, - ), - 'dive_backlight_mode': FieldType( - name='dive_backlight_mode', - base_type=BASE_TYPES[0x00], # enum - values={ - 0: 'at_depth', - 1: 'always_on', - }, - ), - 'dive_gas_status': FieldType( - name='dive_gas_status', - base_type=BASE_TYPES[0x00], # enum - values={ - 0: 'disabled', - 1: 'enabled', - 2: 'backup_only', - }, - ), - 'event': FieldType( - name='event', - base_type=BASE_TYPES[0x00], # enum - values={ - 0: 'timer', # Group 0. Start / stop_all - 3: 'workout', # start / stop - 4: 'workout_step', # Start at beginning of workout. Stop at end of each step. - 5: 'power_down', # stop_all group 0 - 6: 'power_up', # stop_all group 0 - 7: 'off_course', # start / stop group 0 - 8: 'session', # Stop at end of each session. - 9: 'lap', # Stop at end of each lap. - 10: 'course_point', # marker - 11: 'battery', # marker - 12: 'virtual_partner_pace', # Group 1. Start at beginning of activity if VP enabled, when VP pace is changed during activity or VP enabled mid activity. stop_disable when VP disabled. - 13: 'hr_high_alert', # Group 0. Start / stop when in alert condition. - 14: 'hr_low_alert', # Group 0. Start / stop when in alert condition. - 15: 'speed_high_alert', # Group 0. Start / stop when in alert condition. - 16: 'speed_low_alert', # Group 0. Start / stop when in alert condition. - 17: 'cad_high_alert', # Group 0. Start / stop when in alert condition. - 18: 'cad_low_alert', # Group 0. Start / stop when in alert condition. - 19: 'power_high_alert', # Group 0. Start / stop when in alert condition. - 20: 'power_low_alert', # Group 0. Start / stop when in alert condition. - 21: 'recovery_hr', # marker - 22: 'battery_low', # marker - 23: 'time_duration_alert', # Group 1. Start if enabled mid activity (not required at start of activity). Stop when duration is reached. stop_disable if disabled. - 24: 'distance_duration_alert', # Group 1. Start if enabled mid activity (not required at start of activity). Stop when duration is reached. stop_disable if disabled. - 25: 'calorie_duration_alert', # Group 1. Start if enabled mid activity (not required at start of activity). Stop when duration is reached. stop_disable if disabled. - 26: 'activity', # Group 1.. Stop at end of activity. - 27: 'fitness_equipment', # marker - 28: 'length', # Stop at end of each length. - 32: 'user_marker', # marker - 33: 'sport_point', # marker - 36: 'calibration', # start/stop/marker - 42: 'front_gear_change', # marker - 43: 'rear_gear_change', # marker - 44: 'rider_position_change', # marker - 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 - }, - ), - 'event_type': FieldType( - name='event_type', - base_type=BASE_TYPES[0x00], # enum - values={ - 0: 'start', - 1: 'stop', - 2: 'consecutive_depreciated', - 3: 'marker', - 4: 'stop_all', - 5: 'begin_depreciated', - 6: 'end_depreciated', - 7: 'end_all_depreciated', - 8: 'stop_disable', - 9: 'stop_disable_all', - }, - ), - 'exd_data_units': FieldType( - name='exd_data_units', - base_type=BASE_TYPES[0x00], # enum - values={ - 0: 'no_units', - 1: 'laps', - 2: 'miles_per_hour', - 3: 'kilometers_per_hour', - 4: 'feet_per_hour', - 5: 'meters_per_hour', - 6: 'degrees_celsius', - 7: 'degrees_farenheit', - 8: 'zone', - 9: 'gear', - 10: 'rpm', - 11: 'bpm', - 12: 'degrees', - 13: 'millimeters', - 14: 'meters', - 15: 'kilometers', - 16: 'feet', - 17: 'yards', - 18: 'kilofeet', - 19: 'miles', - 20: 'time', - 21: 'enum_turn_type', - 22: 'percent', - 23: 'watts', - 24: 'watts_per_kilogram', - 25: 'enum_battery_status', - 26: 'enum_bike_light_beam_angle_mode', - 27: 'enum_bike_light_battery_status', - 28: 'enum_bike_light_network_config_type', - 29: 'lights', - 30: 'seconds', - 31: 'minutes', - 32: 'hours', - 33: 'calories', - 34: 'kilojoules', - 35: 'milliseconds', - 36: 'second_per_mile', - 37: 'second_per_kilometer', - 38: 'centimeter', - 39: 'enum_course_point', - 40: 'bradians', - 41: 'enum_sport', - 42: 'inches_hg', - 43: 'mm_hg', - 44: 'mbars', - 45: 'hecto_pascals', - 46: 'feet_per_min', - 47: 'meters_per_min', - 48: 'meters_per_sec', - 49: 'eight_cardinal', - }, - ), - 'exd_descriptors': FieldType( - name='exd_descriptors', - base_type=BASE_TYPES[0x00], # enum - values={ - 0: 'bike_light_battery_status', - 1: 'beam_angle_status', - 2: 'batery_level', - 3: 'light_network_mode', - 4: 'number_lights_connected', - 5: 'cadence', - 6: 'distance', - 7: 'estimated_time_of_arrival', - 8: 'heading', - 9: 'time', - 10: 'battery_level', - 11: 'trainer_resistance', - 12: 'trainer_target_power', - 13: 'time_seated', - 14: 'time_standing', - 15: 'elevation', - 16: 'grade', - 17: 'ascent', - 18: 'descent', - 19: 'vertical_speed', - 20: 'di2_battery_level', - 21: 'front_gear', - 22: 'rear_gear', - 23: 'gear_ratio', - 24: 'heart_rate', - 25: 'heart_rate_zone', - 26: 'time_in_heart_rate_zone', - 27: 'heart_rate_reserve', - 28: 'calories', - 29: 'gps_accuracy', - 30: 'gps_signal_strength', - 31: 'temperature', - 32: 'time_of_day', - 33: 'balance', - 34: 'pedal_smoothness', - 35: 'power', - 36: 'functional_threshold_power', - 37: 'intensity_factor', - 38: 'work', - 39: 'power_ratio', - 40: 'normalized_power', - 41: 'training_stress_Score', - 42: 'time_on_zone', - 43: 'speed', - 44: 'laps', - 45: 'reps', - 46: 'workout_step', - 47: 'course_distance', - 48: 'navigation_distance', - 49: 'course_estimated_time_of_arrival', - 50: 'navigation_estimated_time_of_arrival', - 51: 'course_time', - 52: 'navigation_time', - 53: 'course_heading', - 54: 'navigation_heading', - 55: 'power_zone', - 56: 'torque_effectiveness', - 57: 'timer_time', - 58: 'power_weight_ratio', - 59: 'left_platform_center_offset', - 60: 'right_platform_center_offset', - 61: 'left_power_phase_start_angle', - 62: 'right_power_phase_start_angle', - 63: 'left_power_phase_finish_angle', - 64: 'right_power_phase_finish_angle', - 65: 'gears', # Combined gear information - 66: 'pace', - 67: 'training_effect', - 68: 'vertical_oscillation', - 69: 'vertical_ratio', - 70: 'ground_contact_time', - 71: 'left_ground_contact_time_balance', - 72: 'right_ground_contact_time_balance', - 73: 'stride_length', - 74: 'running_cadence', - 75: 'performance_condition', - 76: 'course_type', - 77: 'time_in_power_zone', - 78: 'navigation_turn', - 79: 'course_location', - 80: 'navigation_location', - 81: 'compass', - 82: 'gear_combo', - 83: 'muscle_oxygen', - 84: 'icon', - 85: 'compass_heading', - 86: 'gps_heading', - 87: 'gps_elevation', - 88: 'anaerobic_training_effect', - 89: 'course', - 90: 'off_course', - 91: 'glide_ratio', - 92: 'vertical_distance', - 93: 'vmg', - 94: 'ambient_pressure', - 95: 'pressure', - 96: 'vam', - }, - ), - 'exd_display_type': FieldType( - name='exd_display_type', - base_type=BASE_TYPES[0x00], # enum - values={ - 0: 'numerical', - 1: 'simple', - 2: 'graph', - 3: 'bar', - 4: 'circle_graph', - 5: 'virtual_partner', - 6: 'balance', - 7: 'string_list', - 8: 'string', - 9: 'simple_dynamic_icon', - 10: 'gauge', - }, - ), - 'exd_layout': FieldType( - name='exd_layout', - base_type=BASE_TYPES[0x00], # enum - values={ - 0: 'full_screen', - 1: 'half_vertical', - 2: 'half_horizontal', - 3: 'half_vertical_right_split', - 4: 'half_horizontal_bottom_split', - 5: 'full_quarter_split', - 6: 'half_vertical_left_split', - 7: 'half_horizontal_top_split', - }, - ), - 'exd_qualifiers': FieldType( - name='exd_qualifiers', - base_type=BASE_TYPES[0x00], # enum - values={ - 0: 'no_qualifier', - 1: 'instantaneous', - 2: 'average', - 3: 'lap', - 4: 'maximum', - 5: 'maximum_average', - 6: 'maximum_lap', - 7: 'last_lap', - 8: 'average_lap', - 9: 'to_destination', - 10: 'to_go', - 11: 'to_next', - 12: 'next_course_point', - 13: 'total', - 14: 'three_second_average', - 15: 'ten_second_average', - 16: 'thirty_second_average', - 17: 'percent_maximum', - 18: 'percent_maximum_average', - 19: 'lap_percent_maximum', - 20: 'elapsed', - 21: 'sunrise', - 22: 'sunset', - 23: 'compared_to_virtual_partner', - 24: 'maximum_24h', - 25: 'minimum_24h', - 26: 'minimum', - 27: 'first', - 28: 'second', - 29: 'third', - 30: 'shifter', - 31: 'last_sport', - 32: 'moving', - 33: 'stopped', - 34: 'estimated_total', - 242: 'zone_9', - 243: 'zone_8', - 244: 'zone_7', - 245: 'zone_6', - 246: 'zone_5', - 247: 'zone_4', - 248: 'zone_3', - 249: 'zone_2', - 250: 'zone_1', - }, - ), - 'exercise_category': FieldType( - name='exercise_category', - base_type=BASE_TYPES[0x84], # uint16 - values={ - 0: 'bench_press', - 1: 'calf_raise', - 2: 'cardio', - 3: 'carry', - 4: 'chop', - 5: 'core', - 6: 'crunch', - 7: 'curl', - 8: 'deadlift', - 9: 'flye', - 10: 'hip_raise', - 11: 'hip_stability', - 12: 'hip_swing', - 13: 'hyperextension', - 14: 'lateral_raise', - 15: 'leg_curl', - 16: 'leg_raise', - 17: 'lunge', - 18: 'olympic_lift', - 19: 'plank', - 20: 'plyo', - 21: 'pull_up', - 22: 'push_up', - 23: 'row', - 24: 'shoulder_press', - 25: 'shoulder_stability', - 26: 'shrug', - 27: 'sit_up', - 28: 'squat', - 29: 'total_body', - 30: 'triceps_extension', - 31: 'warm_up', - 32: 'run', - 65534: 'unknown', - }, - ), - 'file': FieldType( - name='file', - base_type=BASE_TYPES[0x00], # enum - values={ - 1: 'device', # Read only, single file. Must be in root directory. - 2: 'settings', # Read/write, single file. Directory=Settings - 3: 'sport', # Read/write, multiple files, file number = sport type. Directory=Sports - 4: 'activity', # Read/erase, multiple files. Directory=Activities - 5: 'workout', # Read/write/erase, multiple files. Directory=Workouts - 6: 'course', # Read/write/erase, multiple files. Directory=Courses - 7: 'schedules', # Read/write, single file. Directory=Schedules - 9: 'weight', # Read only, single file. Circular buffer. All message definitions at start of file. Directory=Weight - 10: 'totals', # Read only, single file. Directory=Totals - 11: 'goals', # Read/write, single file. Directory=Goals - 14: 'blood_pressure', # Read only. Directory=Blood Pressure - 15: 'monitoring_a', # Read only. Directory=Monitoring. File number=sub type. - 20: 'activity_summary', # Read/erase, multiple files. Directory=Activities - 28: 'monitoring_daily', - 32: 'monitoring_b', # Read only. Directory=Monitoring. File number=identifier - 34: 'segment', # Read/write/erase. Multiple Files. Directory=Segments - 35: 'segment_list', # Read/write/erase. Single File. Directory=Segments - 40: 'exd_configuration', # Read/write/erase. Single File. Directory=Settings - 0xF7: 'mfg_range_min', # 0xF7 - 0xFE reserved for manufacturer specific file types - 0xFE: 'mfg_range_max', # 0xF7 - 0xFE reserved for manufacturer specific file types - }, - ), - 'file_flags': FieldType( - name='file_flags', - base_type=BASE_TYPES[0x0A], # uint8z - values={ - 0x02: 'read', - 0x04: 'write', - 0x08: 'erase', - }, - ), - 'fit_base_type': FieldType( - name='fit_base_type', - base_type=BASE_TYPES[0x02], # uint8 - values={ - 0: 'enum', - 1: 'sint8', - 2: 'uint8', - 7: 'string', - 10: 'uint8z', - 13: 'byte', - 131: 'sint16', - 132: 'uint16', - 133: 'sint32', - 134: 'uint32', - 136: 'float32', - 137: 'float64', - 139: 'uint16z', - 140: 'uint32z', - 142: 'sint64', - 143: 'uint64', - 144: 'uint64z', - }, - ), - 'fit_base_unit': FieldType( - name='fit_base_unit', - base_type=BASE_TYPES[0x84], # uint16 - values={ - 0: 'other', - 1: 'kilogram', - 2: 'pound', - }, - ), - 'fitness_equipment_state': FieldType( # fitness equipment event data - name='fitness_equipment_state', - base_type=BASE_TYPES[0x00], # enum - values={ - 0: 'ready', - 1: 'in_use', - 2: 'paused', - 3: 'unknown', # lost connection to fitness equipment - }, - ), - 'flye_exercise_name': FieldType( - name='flye_exercise_name', - base_type=BASE_TYPES[0x84], # uint16 - values={ - 0: 'cable_crossover', - 1: 'decline_dumbbell_flye', - 2: 'dumbbell_flye', - 3: 'incline_dumbbell_flye', - 4: 'kettlebell_flye', - 5: 'kneeling_rear_flye', - 6: 'single_arm_standing_cable_reverse_flye', - 7: 'swiss_ball_dumbbell_flye', - }, - ), - 'garmin_product': FieldType( - name='garmin_product', - base_type=BASE_TYPES[0x84], # uint16 - values={ - 1: 'hrm1', - 2: 'axh01', # AXH01 HRM chipset - 3: 'axb01', - 4: 'axb02', - 5: 'hrm2ss', - 6: 'dsi_alf02', - 7: 'hrm3ss', - 8: 'hrm_run_single_byte_product_id', # hrm_run model for HRM ANT+ messaging - 9: 'bsm', # BSM model for ANT+ messaging - 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 - 14: 'fr225_single_byte_product_id', # fr225 model for HRM ANT+ messaging - 473: 'fr301_china', - 474: 'fr301_japan', - 475: 'fr301_korea', - 494: 'fr301_taiwan', - 717: 'fr405', # Forerunner 405 - 782: 'fr50', # Forerunner 50 - 987: 'fr405_japan', - 988: 'fr60', # Forerunner 60 - 1011: 'dsi_alf01', - 1018: 'fr310xt', # Forerunner 310 - 1036: 'edge500', - 1124: 'fr110', # Forerunner 110 - 1169: 'edge800', - 1199: 'edge500_taiwan', - 1213: 'edge500_japan', - 1253: 'chirp', - 1274: 'fr110_japan', - 1325: 'edge200', - 1328: 'fr910xt', - 1333: 'edge800_taiwan', - 1334: 'edge800_japan', - 1341: 'alf04', - 1345: 'fr610', - 1360: 'fr210_japan', - 1380: 'vector_ss', - 1381: 'vector_cp', - 1386: 'edge800_china', - 1387: 'edge500_china', - 1410: 'fr610_japan', - 1422: 'edge500_korea', - 1436: 'fr70', - 1446: 'fr310xt_4t', - 1461: 'amx', - 1482: 'fr10', - 1497: 'edge800_korea', - 1499: 'swim', - 1537: 'fr910xt_china', - 1551: 'fenix', - 1555: 'edge200_taiwan', - 1561: 'edge510', - 1567: 'edge810', - 1570: 'tempe', - 1600: 'fr910xt_japan', - 1623: 'fr620', - 1632: 'fr220', - 1664: 'fr910xt_korea', - 1688: 'fr10_japan', - 1721: 'edge810_japan', - 1735: 'virb_elite', - 1736: 'edge_touring', # Also Edge Touring Plus - 1742: 'edge510_japan', - 1743: 'hrm_tri', - 1752: 'hrm_run', - 1765: 'fr920xt', - 1821: 'edge510_asia', - 1822: 'edge810_china', - 1823: 'edge810_taiwan', - 1836: 'edge1000', - 1837: 'vivo_fit', - 1853: 'virb_remote', - 1885: 'vivo_ki', - 1903: 'fr15', - 1907: 'vivo_active', - 1918: 'edge510_korea', - 1928: 'fr620_japan', - 1929: 'fr620_china', - 1930: 'fr220_japan', - 1931: 'fr220_china', - 1936: 'approach_s6', - 1956: 'vivo_smart', - 1967: 'fenix2', - 1988: 'epix', - 2050: 'fenix3', - 2052: 'edge1000_taiwan', - 2053: 'edge1000_japan', - 2061: 'fr15_japan', - 2067: 'edge520', - 2070: 'edge1000_china', - 2072: 'fr620_russia', - 2073: 'fr220_russia', - 2079: 'vector_s', - 2100: 'edge1000_korea', - 2130: 'fr920xt_taiwan', - 2131: 'fr920xt_china', - 2132: 'fr920xt_japan', - 2134: 'virbx', - 2135: 'vivo_smart_apac', - 2140: 'etrex_touch', - 2147: 'edge25', - 2148: 'fr25', - 2150: 'vivo_fit2', - 2153: 'fr225', - 2156: 'fr630', - 2157: 'fr230', - 2160: 'vivo_active_apac', - 2161: 'vector_2', - 2162: 'vector_2s', - 2172: 'virbxe', - 2173: 'fr620_taiwan', - 2174: 'fr220_taiwan', - 2175: 'truswing', - 2188: 'fenix3_china', - 2189: 'fenix3_twn', - 2192: 'varia_headlight', - 2193: 'varia_taillight_old', - 2204: 'edge_explore_1000', - 2219: 'fr225_asia', - 2225: 'varia_radar_taillight', - 2226: 'varia_radar_display', - 2238: 'edge20', - 2262: 'd2_bravo', - 2266: 'approach_s20', - 2276: 'varia_remote', - 2327: 'hrm4_run', - 2337: 'vivo_active_hr', - 2347: 'vivo_smart_gps_hr', - 2348: 'vivo_smart_hr', - 2368: 'vivo_move', - 2398: 'varia_vision', - 2406: 'vivo_fit3', - 2413: 'fenix3_hr', - 2417: 'virb_ultra_30', - 2429: 'index_smart_scale', - 2431: 'fr235', - 2432: 'fenix3_chronos', - 2441: 'oregon7xx', - 2444: 'rino7xx', - 2496: 'nautix', - 2530: 'edge_820', - 2531: 'edge_explore_820', - 2544: 'fenix5s', - 2547: 'd2_bravo_titanium', - 2567: 'varia_ut800', # Varia UT 800 SW - 2593: 'running_dynamics_pod', - 2604: 'fenix5x', - 2606: 'vivo_fit_jr', - 2691: 'fr935', - 2697: 'fenix5', - 10007: 'sdm4', # SDM4 footpod - 10014: 'edge_remote', - 20119: 'training_center', - 65531: 'connectiq_simulator', - 65532: 'android_antplus_plugin', - 65534: 'connect', # Garmin Connect website - }, - ), - 'gender': FieldType( - name='gender', - base_type=BASE_TYPES[0x00], # enum - values={ - 0: 'female', - 1: 'male', - }, - ), - 'goal': FieldType( - name='goal', - base_type=BASE_TYPES[0x00], # enum - values={ - 0: 'time', - 1: 'distance', - 2: 'calories', - 3: 'frequency', - 4: 'steps', - 5: 'ascent', - 6: 'active_minutes', - }, - ), - 'goal_recurrence': FieldType( - name='goal_recurrence', - base_type=BASE_TYPES[0x00], # enum - values={ - 0: 'off', - 1: 'daily', - 2: 'weekly', - 3: 'monthly', - 4: 'yearly', - 5: 'custom', - }, - ), - 'goal_source': FieldType( - name='goal_source', - base_type=BASE_TYPES[0x00], # enum - values={ - 0: 'auto', # Device generated - 1: 'community', # Social network sourced goal - 2: 'user', # Manually generated - }, - ), - 'hip_raise_exercise_name': FieldType( - name='hip_raise_exercise_name', - base_type=BASE_TYPES[0x84], # uint16 - values={ - 0: 'barbell_hip_thrust_on_floor', - 1: 'barbell_hip_thrust_with_bench', - 2: 'bent_knee_swiss_ball_reverse_hip_raise', - 3: 'weighted_bent_knee_swiss_ball_reverse_hip_raise', - 4: 'bridge_with_leg_extension', - 5: 'weighted_bridge_with_leg_extension', - 6: 'clam_bridge', - 7: 'front_kick_tabletop', - 8: 'weighted_front_kick_tabletop', - 9: 'hip_extension_and_cross', - 10: 'weighted_hip_extension_and_cross', - 11: 'hip_raise', - 12: 'weighted_hip_raise', - 13: 'hip_raise_with_feet_on_swiss_ball', - 14: 'weighted_hip_raise_with_feet_on_swiss_ball', - 15: 'hip_raise_with_head_on_bosu_ball', - 16: 'weighted_hip_raise_with_head_on_bosu_ball', - 17: 'hip_raise_with_head_on_swiss_ball', - 18: 'weighted_hip_raise_with_head_on_swiss_ball', - 19: 'hip_raise_with_knee_squeeze', - 20: 'weighted_hip_raise_with_knee_squeeze', - 21: 'incline_rear_leg_extension', - 22: 'weighted_incline_rear_leg_extension', - 23: 'kettlebell_swing', - 24: 'marching_hip_raise', - 25: 'weighted_marching_hip_raise', - 26: 'marching_hip_raise_with_feet_on_a_swiss_ball', - 27: 'weighted_marching_hip_raise_with_feet_on_a_swiss_ball', - 28: 'reverse_hip_raise', - 29: 'weighted_reverse_hip_raise', - 30: 'single_leg_hip_raise', - 31: 'weighted_single_leg_hip_raise', - 32: 'single_leg_hip_raise_with_foot_on_bench', - 33: 'weighted_single_leg_hip_raise_with_foot_on_bench', - 34: 'single_leg_hip_raise_with_foot_on_bosu_ball', - 35: 'weighted_single_leg_hip_raise_with_foot_on_bosu_ball', - 36: 'single_leg_hip_raise_with_foot_on_foam_roller', - 37: 'weighted_single_leg_hip_raise_with_foot_on_foam_roller', - 38: 'single_leg_hip_raise_with_foot_on_medicine_ball', - 39: 'weighted_single_leg_hip_raise_with_foot_on_medicine_ball', - 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', - }, - ), - 'hip_stability_exercise_name': FieldType( - name='hip_stability_exercise_name', - base_type=BASE_TYPES[0x84], # uint16 - values={ - 0: 'band_side_lying_leg_raise', - 1: 'dead_bug', - 2: 'weighted_dead_bug', - 3: 'external_hip_raise', - 4: 'weighted_external_hip_raise', - 5: 'fire_hydrant_kicks', - 6: 'weighted_fire_hydrant_kicks', - 7: 'hip_circles', - 8: 'weighted_hip_circles', - 9: 'inner_thigh_lift', - 10: 'weighted_inner_thigh_lift', - 11: 'lateral_walks_with_band_at_ankles', - 12: 'pretzel_side_kick', - 13: 'weighted_pretzel_side_kick', - 14: 'prone_hip_internal_rotation', - 15: 'weighted_prone_hip_internal_rotation', - 16: 'quadruped', - 17: 'quadruped_hip_extension', - 18: 'weighted_quadruped_hip_extension', - 19: 'quadruped_with_leg_lift', - 20: 'weighted_quadruped_with_leg_lift', - 21: 'side_lying_leg_raise', - 22: 'weighted_side_lying_leg_raise', - 23: 'sliding_hip_adduction', - 24: 'weighted_sliding_hip_adduction', - 25: 'standing_adduction', - 26: 'weighted_standing_adduction', - 27: 'standing_cable_hip_abduction', - 28: 'standing_hip_abduction', - 29: 'weighted_standing_hip_abduction', - 30: 'standing_rear_leg_raise', - 31: 'weighted_standing_rear_leg_raise', - 32: 'supine_hip_internal_rotation', - 33: 'weighted_supine_hip_internal_rotation', - }, - ), - 'hip_swing_exercise_name': FieldType( - name='hip_swing_exercise_name', - base_type=BASE_TYPES[0x84], # uint16 - values={ - 0: 'single_arm_kettlebell_swing', - 1: 'single_arm_dumbbell_swing', - 2: 'step_out_swing', - }, - ), - 'hr_type': FieldType( - name='hr_type', - base_type=BASE_TYPES[0x00], # enum - values={ - 0: 'normal', - 1: 'irregular', - }, - ), - 'hr_zone_calc': FieldType( - name='hr_zone_calc', - base_type=BASE_TYPES[0x00], # enum - values={ - 0: 'custom', - 1: 'percent_max_hr', - 2: 'percent_hrr', - }, - ), - 'hyperextension_exercise_name': FieldType( - name='hyperextension_exercise_name', - base_type=BASE_TYPES[0x84], # uint16 - values={ - 0: 'back_extension_with_opposite_arm_and_leg_reach', - 1: 'weighted_back_extension_with_opposite_arm_and_leg_reach', - 2: 'base_rotations', - 3: 'weighted_base_rotations', - 4: 'bent_knee_reverse_hyperextension', - 5: 'weighted_bent_knee_reverse_hyperextension', - 6: 'hollow_hold_and_roll', - 7: 'weighted_hollow_hold_and_roll', - 8: 'kicks', - 9: 'weighted_kicks', - 10: 'knee_raises', - 11: 'weighted_knee_raises', - 12: 'kneeling_superman', - 13: 'weighted_kneeling_superman', - 14: 'lat_pull_down_with_row', - 15: 'medicine_ball_deadlift_to_reach', - 16: 'one_arm_one_leg_row', - 17: 'one_arm_row_with_band', - 18: 'overhead_lunge_with_medicine_ball', - 19: 'plank_knee_tucks', - 20: 'weighted_plank_knee_tucks', - 21: 'side_step', - 22: 'weighted_side_step', - 23: 'single_leg_back_extension', - 24: 'weighted_single_leg_back_extension', - 25: 'spine_extension', - 26: 'weighted_spine_extension', - 27: 'static_back_extension', - 28: 'weighted_static_back_extension', - 29: 'superman_from_floor', - 30: 'weighted_superman_from_floor', - 31: 'swiss_ball_back_extension', - 32: 'weighted_swiss_ball_back_extension', - 33: 'swiss_ball_hyperextension', - 34: 'weighted_swiss_ball_hyperextension', - 35: 'swiss_ball_opposite_arm_and_leg_lift', - 36: 'weighted_swiss_ball_opposite_arm_and_leg_lift', - }, - ), - 'intensity': FieldType( - name='intensity', - base_type=BASE_TYPES[0x00], # enum - values={ - 0: 'active', - 1: 'rest', - 2: 'warmup', - 3: 'cooldown', - }, - ), - 'language': FieldType( - name='language', - base_type=BASE_TYPES[0x00], # enum - values={ - 0: 'english', - 1: 'french', - 2: 'italian', - 3: 'german', - 4: 'spanish', - 5: 'croatian', - 6: 'czech', - 7: 'danish', - 8: 'dutch', - 9: 'finnish', - 10: 'greek', - 11: 'hungarian', - 12: 'norwegian', - 13: 'polish', - 14: 'portuguese', - 15: 'slovakian', - 16: 'slovenian', - 17: 'swedish', - 18: 'russian', - 19: 'turkish', - 20: 'latvian', - 21: 'ukrainian', - 22: 'arabic', - 23: 'farsi', - 24: 'bulgarian', - 25: 'romanian', - 26: 'chinese', - 27: 'japanese', - 28: 'korean', - 29: 'taiwanese', - 30: 'thai', - 31: 'hebrew', - 32: 'brazilian_portuguese', - 33: 'indonesian', - 34: 'malaysian', - 35: 'vietnamese', - 36: 'burmese', - 37: 'mongolian', - 254: 'custom', - }, - ), - 'language_bits_0': FieldType( # Bit field corresponding to language enum type (1 << language). - name='language_bits_0', - base_type=BASE_TYPES[0x0A], # uint8z - values={ - 0x01: 'english', - 0x02: 'french', - 0x04: 'italian', - 0x08: 'german', - 0x10: 'spanish', - 0x20: 'croatian', - 0x40: 'czech', - 0x80: 'danish', - }, - ), - 'language_bits_1': FieldType( - name='language_bits_1', - base_type=BASE_TYPES[0x0A], # uint8z - values={ - 0x01: 'dutch', - 0x02: 'finnish', - 0x04: 'greek', - 0x08: 'hungarian', - 0x10: 'norwegian', - 0x20: 'polish', - 0x40: 'portuguese', - 0x80: 'slovakian', - }, - ), - 'language_bits_2': FieldType( - name='language_bits_2', - base_type=BASE_TYPES[0x0A], # uint8z - values={ - 0x01: 'slovenian', - 0x02: 'swedish', - 0x04: 'russian', - 0x08: 'turkish', - 0x10: 'latvian', - 0x20: 'ukrainian', - 0x40: 'arabic', - 0x80: 'farsi', - }, - ), - 'language_bits_3': FieldType( - name='language_bits_3', - base_type=BASE_TYPES[0x0A], # uint8z - values={ - 0x01: 'bulgarian', - 0x02: 'romanian', - 0x04: 'chinese', - 0x08: 'japanese', - 0x10: 'korean', - 0x20: 'taiwanese', - 0x40: 'thai', - 0x80: 'hebrew', - }, - ), - 'language_bits_4': FieldType( - name='language_bits_4', - base_type=BASE_TYPES[0x0A], # uint8z - values={ - 0x01: 'brazilian_portuguese', - 0x02: 'indonesian', - 0x04: 'malaysian', - 0x08: 'vietnamese', - 0x10: 'burmese', - 0x20: 'mongolian', - }, - ), - 'lap_trigger': FieldType( - name='lap_trigger', - base_type=BASE_TYPES[0x00], # enum - values={ - 0: 'manual', - 1: 'time', - 2: 'distance', - 3: 'position_start', - 4: 'position_lap', - 5: 'position_waypoint', - 6: 'position_marked', - 7: 'session_end', - 8: 'fitness_equipment', - }, - ), - 'lateral_raise_exercise_name': FieldType( - name='lateral_raise_exercise_name', - base_type=BASE_TYPES[0x84], # uint16 - values={ - 0: '45_degree_cable_external_rotation', - 1: 'alternating_lateral_raise_with_static_hold', - 2: 'bar_muscle_up', - 3: 'bent_over_lateral_raise', - 4: 'cable_diagonal_raise', - 5: 'cable_front_raise', - 6: 'calorie_row', - 7: 'combo_shoulder_raise', - 8: 'dumbbell_diagonal_raise', - 9: 'dumbbell_v_raise', - 10: 'front_raise', - 11: 'leaning_dumbbell_lateral_raise', - 12: 'lying_dumbbell_raise', - 13: 'muscle_up', - 14: 'one_arm_cable_lateral_raise', - 15: 'overhand_grip_rear_lateral_raise', - 16: 'plate_raises', - 17: 'ring_dip', - 18: 'weighted_ring_dip', - 19: 'ring_muscle_up', - 20: 'weighted_ring_muscle_up', - 21: 'rope_climb', - 22: 'weighted_rope_climb', - 23: 'scaption', - 24: 'seated_lateral_raise', - 25: 'seated_rear_lateral_raise', - 26: 'side_lying_lateral_raise', - 27: 'standing_lift', - 28: 'suspended_row', - 29: 'underhand_grip_rear_lateral_raise', - 30: 'wall_slide', - 31: 'weighted_wall_slide', - }, - ), - 'left_right_balance': FieldType( - name='left_right_balance', - base_type=BASE_TYPES[0x02], # uint8 - values={ - 0x7F: 'mask', # % contribution - 0x80: 'right', # data corresponds to right if set, otherwise unknown - }, - ), - 'left_right_balance_100': FieldType( - name='left_right_balance_100', - base_type=BASE_TYPES[0x84], # uint16 - values={ - 0x3FFF: 'mask', # % contribution scaled by 100 - 0x8000: 'right', # data corresponds to right if set, otherwise unknown - }, - ), - 'leg_curl_exercise_name': FieldType( - name='leg_curl_exercise_name', - base_type=BASE_TYPES[0x84], # uint16 - values={ - 0: 'leg_curl', - 1: 'weighted_leg_curl', - 2: 'good_morning', - 3: 'seated_barbell_good_morning', - 4: 'single_leg_barbell_good_morning', - 5: 'single_leg_sliding_leg_curl', - 6: 'sliding_leg_curl', - 7: 'split_barbell_good_morning', - 8: 'split_stance_extension', - 9: 'staggered_stance_good_morning', - 10: 'swiss_ball_hip_raise_and_leg_curl', - 11: 'zercher_good_morning', - }, - ), - 'leg_raise_exercise_name': FieldType( - name='leg_raise_exercise_name', - base_type=BASE_TYPES[0x84], # uint16 - values={ - 0: 'hanging_knee_raise', - 1: 'hanging_leg_raise', - 2: 'weighted_hanging_leg_raise', - 3: 'hanging_single_leg_raise', - 4: 'weighted_hanging_single_leg_raise', - 5: 'kettlebell_leg_raises', - 6: 'leg_lowering_drill', - 7: 'weighted_leg_lowering_drill', - 8: 'lying_straight_leg_raise', - 9: 'weighted_lying_straight_leg_raise', - 10: 'medicine_ball_leg_drops', - 11: 'quadruped_leg_raise', - 12: 'weighted_quadruped_leg_raise', - 13: 'reverse_leg_raise', - 14: 'weighted_reverse_leg_raise', - 15: 'reverse_leg_raise_on_swiss_ball', - 16: 'weighted_reverse_leg_raise_on_swiss_ball', - 17: 'single_leg_lowering_drill', - 18: 'weighted_single_leg_lowering_drill', - 19: 'weighted_hanging_knee_raise', - 20: 'lateral_stepover', - 21: 'weighted_lateral_stepover', - }, - ), - 'length_type': FieldType( - name='length_type', - base_type=BASE_TYPES[0x00], # enum - values={ - 0: 'idle', # Rest period. Length with no strokes - 1: 'active', # Length with strokes. - }, - ), - 'local_date_time': FieldType( # seconds since 00:00 Dec 31 1989 in local time zone - name='local_date_time', - base_type=BASE_TYPES[0x86], # uint32 - values={ - 0x10000000: 'min', # if date_time is < 0x10000000 then it is system time (seconds from device power on) - }, - ), - 'local_device_type': FieldType( - name='local_device_type', - base_type=BASE_TYPES[0x02], # uint8 - ), - 'localtime_into_day': FieldType( # number of seconds into the day since local 00:00:00 - name='localtime_into_day', - base_type=BASE_TYPES[0x86], # uint32 - ), - 'lunge_exercise_name': FieldType( - name='lunge_exercise_name', - base_type=BASE_TYPES[0x84], # uint16 - values={ - 0: 'overhead_lunge', - 1: 'lunge_matrix', - 2: 'weighted_lunge_matrix', - 3: 'alternating_barbell_forward_lunge', - 4: 'alternating_dumbbell_lunge_with_reach', - 5: 'back_foot_elevated_dumbbell_split_squat', - 6: 'barbell_box_lunge', - 7: 'barbell_bulgarian_split_squat', - 8: 'barbell_crossover_lunge', - 9: 'barbell_front_split_squat', - 10: 'barbell_lunge', - 11: 'barbell_reverse_lunge', - 12: 'barbell_side_lunge', - 13: 'barbell_split_squat', - 14: 'core_control_rear_lunge', - 15: 'diagonal_lunge', - 16: 'drop_lunge', - 17: 'dumbbell_box_lunge', - 18: 'dumbbell_bulgarian_split_squat', - 19: 'dumbbell_crossover_lunge', - 20: 'dumbbell_diagonal_lunge', - 21: 'dumbbell_lunge', - 22: 'dumbbell_lunge_and_rotation', - 23: 'dumbbell_overhead_bulgarian_split_squat', - 24: 'dumbbell_reverse_lunge_to_high_knee_and_press', - 25: 'dumbbell_side_lunge', - 26: 'elevated_front_foot_barbell_split_squat', - 27: 'front_foot_elevated_dumbbell_split_squat', - 28: 'gunslinger_lunge', - 29: 'lawnmower_lunge', - 30: 'low_lunge_with_isometric_adduction', - 31: 'low_side_to_side_lunge', - 32: 'lunge', - 33: 'weighted_lunge', - 34: 'lunge_with_arm_reach', - 35: 'lunge_with_diagonal_reach', - 36: 'lunge_with_side_bend', - 37: 'offset_dumbbell_lunge', - 38: 'offset_dumbbell_reverse_lunge', - 39: 'overhead_bulgarian_split_squat', - 40: 'overhead_dumbbell_reverse_lunge', - 41: 'overhead_dumbbell_split_squat', - 42: 'overhead_lunge_with_rotation', - 43: 'reverse_barbell_box_lunge', - 44: 'reverse_box_lunge', - 45: 'reverse_dumbbell_box_lunge', - 46: 'reverse_dumbbell_crossover_lunge', - 47: 'reverse_dumbbell_diagonal_lunge', - 48: 'reverse_lunge_with_reach_back', - 49: 'weighted_reverse_lunge_with_reach_back', - 50: 'reverse_lunge_with_twist_and_overhead_reach', - 51: 'weighted_reverse_lunge_with_twist_and_overhead_reach', - 52: 'reverse_sliding_box_lunge', - 53: 'weighted_reverse_sliding_box_lunge', - 54: 'reverse_sliding_lunge', - 55: 'weighted_reverse_sliding_lunge', - 56: 'runners_lunge_to_balance', - 57: 'weighted_runners_lunge_to_balance', - 58: 'shifting_side_lunge', - 59: 'side_and_crossover_lunge', - 60: 'weighted_side_and_crossover_lunge', - 61: 'side_lunge', - 62: 'weighted_side_lunge', - 63: 'side_lunge_and_press', - 64: 'side_lunge_jump_off', - 65: 'side_lunge_sweep', - 66: 'weighted_side_lunge_sweep', - 67: 'side_lunge_to_crossover_tap', - 68: 'weighted_side_lunge_to_crossover_tap', - 69: 'side_to_side_lunge_chops', - 70: 'weighted_side_to_side_lunge_chops', - 71: 'siff_jump_lunge', - 72: 'weighted_siff_jump_lunge', - 73: 'single_arm_reverse_lunge_and_press', - 74: 'sliding_lateral_lunge', - 75: 'weighted_sliding_lateral_lunge', - 76: 'walking_barbell_lunge', - 77: 'walking_dumbbell_lunge', - 78: 'walking_lunge', - 79: 'weighted_walking_lunge', - 80: 'wide_grip_overhead_barbell_split_squat', - }, - ), - 'manufacturer': FieldType( - name='manufacturer', - base_type=BASE_TYPES[0x84], # uint16 - values={ - 1: 'garmin', - 2: 'garmin_fr405_antfs', # Do not use. Used by FR405 for ANTFS man id. - 3: 'zephyr', - 4: 'dayton', - 5: 'idt', - 6: 'srm', - 7: 'quarq', - 8: 'ibike', - 9: 'saris', - 10: 'spark_hk', - 11: 'tanita', - 12: 'echowell', - 13: 'dynastream_oem', - 14: 'nautilus', - 15: 'dynastream', - 16: 'timex', - 17: 'metrigear', - 18: 'xelic', - 19: 'beurer', - 20: 'cardiosport', - 21: 'a_and_d', - 22: 'hmm', - 23: 'suunto', - 24: 'thita_elektronik', - 25: 'gpulse', - 26: 'clean_mobile', - 27: 'pedal_brain', - 28: 'peaksware', - 29: 'saxonar', - 30: 'lemond_fitness', - 31: 'dexcom', - 32: 'wahoo_fitness', - 33: 'octane_fitness', - 34: 'archinoetics', - 35: 'the_hurt_box', - 36: 'citizen_systems', - 37: 'magellan', - 38: 'osynce', - 39: 'holux', - 40: 'concept2', - 42: 'one_giant_leap', - 43: 'ace_sensor', - 44: 'brim_brothers', - 45: 'xplova', - 46: 'perception_digital', - 47: 'bf1systems', - 48: 'pioneer', - 49: 'spantec', - 50: 'metalogics', - 51: '4iiiis', - 52: 'seiko_epson', - 53: 'seiko_epson_oem', - 54: 'ifor_powell', - 55: 'maxwell_guider', - 56: 'star_trac', - 57: 'breakaway', - 58: 'alatech_technology_ltd', - 59: 'mio_technology_europe', - 60: 'rotor', - 61: 'geonaute', - 62: 'id_bike', - 63: 'specialized', - 64: 'wtek', - 65: 'physical_enterprises', - 66: 'north_pole_engineering', - 67: 'bkool', - 68: 'cateye', - 69: 'stages_cycling', - 70: 'sigmasport', - 71: 'tomtom', - 72: 'peripedal', - 73: 'wattbike', - 76: 'moxy', - 77: 'ciclosport', - 78: 'powerbahn', - 79: 'acorn_projects_aps', - 80: 'lifebeam', - 81: 'bontrager', - 82: 'wellgo', - 83: 'scosche', - 84: 'magura', - 85: 'woodway', - 86: 'elite', - 87: 'nielsen_kellerman', - 88: 'dk_city', - 89: 'tacx', - 90: 'direction_technology', - 91: 'magtonic', - 92: '1partcarbon', - 93: 'inside_ride_technologies', - 94: 'sound_of_motion', - 95: 'stryd', - 96: 'icg', # Indoorcycling Group - 97: 'MiPulse', - 98: 'bsx_athletics', - 99: 'look', - 100: 'campagnolo_srl', - 101: 'body_bike_smart', - 102: 'praxisworks', - 103: 'limits_technology', # Limits Technology Ltd. - 104: 'topaction_technology', # TopAction Technology Inc. - 105: 'cosinuss', - 106: 'fitcare', - 107: 'magene', - 108: 'giant_manufacturing_co', - 109: 'tigrasport', # Tigrasport - 110: 'salutron', - 111: 'technogym', - 112: 'bryton_sensors', - 113: 'latitude_limited', - 114: 'soaring_technology', - 115: 'igpsport', - 116: 'thinkrider', - 117: 'gopher_sport', - 118: 'waterrower', - 119: 'orangetheory', - 120: 'inpeak', - 121: 'kinetic', - 122: 'johnson_health_tech', - 123: 'polar_electro', - 124: 'seesense', - 255: 'development', - 257: 'healthandlife', - 258: 'lezyne', - 259: 'scribe_labs', - 260: 'zwift', - 261: 'watteam', - 262: 'recon', - 263: 'favero_electronics', - 264: 'dynovelo', - 265: 'strava', - 266: 'precor', # Amer Sports - 267: 'bryton', - 268: 'sram', - 269: 'navman', # MiTAC Global Corporation (Mio Technology) - 270: 'cobi', # COBI GmbH - 271: 'spivi', - 272: 'mio_magellan', - 273: 'evesports', - 274: 'sensitivus_gauge', - 275: 'podoon', - 276: 'life_time_fitness', - 277: 'falco_e_motors', # Falco eMotors Inc. - 278: 'minoura', - 279: 'cycliq', - 280: 'luxottica', - 281: 'trainer_road', - 282: 'the_sufferfest', - 283: 'fullspeedahead', - 284: 'virtualtraining', - 285: 'feedbacksports', - 286: 'omata', - 287: 'vdo', - 288: 'magneticdays', - 289: 'hammerhead', - 290: 'kinetic_by_kurt', - 291: 'shapelog', - 292: 'dabuziduo', - 293: 'jetblack', - 5759: 'actigraphcorp', - }, - ), - 'mesg_count': FieldType( - name='mesg_count', - base_type=BASE_TYPES[0x00], # enum - values={ - 0: 'num_per_file', - 1: 'max_per_file', - 2: 'max_per_file_type', - }, - ), - 'mesg_num': FieldType( - name='mesg_num', - base_type=BASE_TYPES[0x84], # uint16 - values={ - 0: 'file_id', - 1: 'capabilities', - 2: 'device_settings', - 3: 'user_profile', - 4: 'hrm_profile', - 5: 'sdm_profile', - 6: 'bike_profile', - 7: 'zones_target', - 8: 'hr_zone', - 9: 'power_zone', - 10: 'met_zone', - 12: 'sport', - 15: 'goal', - 18: 'session', - 19: 'lap', - 20: 'record', - 21: 'event', - 23: 'device_info', - 26: 'workout', - 27: 'workout_step', - 28: 'schedule', - 30: 'weight_scale', - 31: 'course', - 32: 'course_point', - 33: 'totals', - 34: 'activity', - 35: 'software', - 37: 'file_capabilities', - 38: 'mesg_capabilities', - 39: 'field_capabilities', - 49: 'file_creator', - 51: 'blood_pressure', - 53: 'speed_zone', - 55: 'monitoring', - 72: 'training_file', - 78: 'hrv', - 80: 'ant_rx', - 81: 'ant_tx', - 82: 'ant_channel_id', - 101: 'length', - 103: 'monitoring_info', - 105: 'pad', - 106: 'slave_device', - 127: 'connectivity', - 128: 'weather_conditions', - 129: 'weather_alert', - 131: 'cadence_zone', - 132: 'hr', - 142: 'segment_lap', - 145: 'memo_glob', - 148: 'segment_id', - 149: 'segment_leaderboard_entry', - 150: 'segment_point', - 151: 'segment_file', - 158: 'workout_session', - 159: 'watchface_settings', - 160: 'gps_metadata', - 161: 'camera_event', - 162: 'timestamp_correlation', - 164: 'gyroscope_data', - 165: 'accelerometer_data', - 167: 'three_d_sensor_calibration', - 169: 'video_frame', - 174: 'obdii_data', - 177: 'nmea_sentence', - 178: 'aviation_attitude', - 184: 'video', - 185: 'video_title', - 186: 'video_description', - 187: 'video_clip', - 188: 'ohr_settings', - 200: 'exd_screen_configuration', - 201: 'exd_data_field_configuration', - 202: 'exd_data_concept_configuration', - 206: 'field_description', - 207: 'developer_data_id', - 208: 'magnetometer_data', - 209: 'barometer_data', - 210: 'one_d_sensor_calibration', - 225: 'set', - 227: 'stress_level', - 258: 'dive_settings', - 259: 'dive_gas', - 262: 'dive_alarm', - 264: 'exercise_title', - 268: 'dive_summary', - }, - ), - 'message_index': FieldType( - name='message_index', - base_type=BASE_TYPES[0x84], # uint16 - values={ - 0x0FFF: 'mask', # index - 0x7000: 'reserved', # reserved (default 0) - 0x8000: 'selected', # message is selected if set - }, - ), - 'olympic_lift_exercise_name': FieldType( - name='olympic_lift_exercise_name', - base_type=BASE_TYPES[0x84], # uint16 - values={ - 0: 'barbell_hang_power_clean', - 1: 'barbell_hang_squat_clean', - 2: 'barbell_power_clean', - 3: 'barbell_power_snatch', - 4: 'barbell_squat_clean', - 5: 'clean_and_jerk', - 6: 'barbell_hang_power_snatch', - 7: 'barbell_hang_pull', - 8: 'barbell_high_pull', - 9: 'barbell_snatch', - 10: 'barbell_split_jerk', - 11: 'clean', - 12: 'dumbbell_clean', - 13: 'dumbbell_hang_pull', - 14: 'one_hand_dumbbell_split_snatch', - 15: 'push_jerk', - 16: 'single_arm_dumbbell_snatch', - 17: 'single_arm_hang_snatch', - 18: 'single_arm_kettlebell_snatch', - 19: 'split_jerk', - 20: 'squat_clean_and_jerk', - }, - ), - 'plank_exercise_name': FieldType( - name='plank_exercise_name', - base_type=BASE_TYPES[0x84], # uint16 - values={ - 0: '45_degree_plank', - 1: 'weighted_45_degree_plank', - 2: '90_degree_static_hold', - 3: 'weighted_90_degree_static_hold', - 4: 'bear_crawl', - 5: 'weighted_bear_crawl', - 6: 'cross_body_mountain_climber', - 7: 'weighted_cross_body_mountain_climber', - 8: 'elbow_plank_pike_jacks', - 9: 'weighted_elbow_plank_pike_jacks', - 10: 'elevated_feet_plank', - 11: 'weighted_elevated_feet_plank', - 12: 'elevator_abs', - 13: 'weighted_elevator_abs', - 14: 'extended_plank', - 15: 'weighted_extended_plank', - 16: 'full_plank_passe_twist', - 17: 'weighted_full_plank_passe_twist', - 18: 'inching_elbow_plank', - 19: 'weighted_inching_elbow_plank', - 20: 'inchworm_to_side_plank', - 21: 'weighted_inchworm_to_side_plank', - 22: 'kneeling_plank', - 23: 'weighted_kneeling_plank', - 24: 'kneeling_side_plank_with_leg_lift', - 25: 'weighted_kneeling_side_plank_with_leg_lift', - 26: 'lateral_roll', - 27: 'weighted_lateral_roll', - 28: 'lying_reverse_plank', - 29: 'weighted_lying_reverse_plank', - 30: 'medicine_ball_mountain_climber', - 31: 'weighted_medicine_ball_mountain_climber', - 32: 'modified_mountain_climber_and_extension', - 33: 'weighted_modified_mountain_climber_and_extension', - 34: 'mountain_climber', - 35: 'weighted_mountain_climber', - 36: 'mountain_climber_on_sliding_discs', - 37: 'weighted_mountain_climber_on_sliding_discs', - 38: 'mountain_climber_with_feet_on_bosu_ball', - 39: 'weighted_mountain_climber_with_feet_on_bosu_ball', - 40: 'mountain_climber_with_hands_on_bench', - 41: 'mountain_climber_with_hands_on_swiss_ball', - 42: 'weighted_mountain_climber_with_hands_on_swiss_ball', - 43: 'plank', - 44: 'plank_jacks_with_feet_on_sliding_discs', - 45: 'weighted_plank_jacks_with_feet_on_sliding_discs', - 46: 'plank_knee_twist', - 47: 'weighted_plank_knee_twist', - 48: 'plank_pike_jumps', - 49: 'weighted_plank_pike_jumps', - 50: 'plank_pikes', - 51: 'weighted_plank_pikes', - 52: 'plank_to_stand_up', - 53: 'weighted_plank_to_stand_up', - 54: 'plank_with_arm_raise', - 55: 'weighted_plank_with_arm_raise', - 56: 'plank_with_knee_to_elbow', - 57: 'weighted_plank_with_knee_to_elbow', - 58: 'plank_with_oblique_crunch', - 59: 'weighted_plank_with_oblique_crunch', - 60: 'plyometric_side_plank', - 61: 'weighted_plyometric_side_plank', - 62: 'rolling_side_plank', - 63: 'weighted_rolling_side_plank', - 64: 'side_kick_plank', - 65: 'weighted_side_kick_plank', - 66: 'side_plank', - 67: 'weighted_side_plank', - 68: 'side_plank_and_row', - 69: 'weighted_side_plank_and_row', - 70: 'side_plank_lift', - 71: 'weighted_side_plank_lift', - 72: 'side_plank_with_elbow_on_bosu_ball', - 73: 'weighted_side_plank_with_elbow_on_bosu_ball', - 74: 'side_plank_with_feet_on_bench', - 75: 'weighted_side_plank_with_feet_on_bench', - 76: 'side_plank_with_knee_circle', - 77: 'weighted_side_plank_with_knee_circle', - 78: 'side_plank_with_knee_tuck', - 79: 'weighted_side_plank_with_knee_tuck', - 80: 'side_plank_with_leg_lift', - 81: 'weighted_side_plank_with_leg_lift', - 82: 'side_plank_with_reach_under', - 83: 'weighted_side_plank_with_reach_under', - 84: 'single_leg_elevated_feet_plank', - 85: 'weighted_single_leg_elevated_feet_plank', - 86: 'single_leg_flex_and_extend', - 87: 'weighted_single_leg_flex_and_extend', - 88: 'single_leg_side_plank', - 89: 'weighted_single_leg_side_plank', - 90: 'spiderman_plank', - 91: 'weighted_spiderman_plank', - 92: 'straight_arm_plank', - 93: 'weighted_straight_arm_plank', - 94: 'straight_arm_plank_with_shoulder_touch', - 95: 'weighted_straight_arm_plank_with_shoulder_touch', - 96: 'swiss_ball_plank', - 97: 'weighted_swiss_ball_plank', - 98: 'swiss_ball_plank_leg_lift', - 99: 'weighted_swiss_ball_plank_leg_lift', - 100: 'swiss_ball_plank_leg_lift_and_hold', - 101: 'swiss_ball_plank_with_feet_on_bench', - 102: 'weighted_swiss_ball_plank_with_feet_on_bench', - 103: 'swiss_ball_prone_jackknife', - 104: 'weighted_swiss_ball_prone_jackknife', - 105: 'swiss_ball_side_plank', - 106: 'weighted_swiss_ball_side_plank', - 107: 'three_way_plank', - 108: 'weighted_three_way_plank', - 109: 'towel_plank_and_knee_in', - 110: 'weighted_towel_plank_and_knee_in', - 111: 't_stabilization', - 112: 'weighted_t_stabilization', - 113: 'turkish_get_up_to_side_plank', - 114: 'weighted_turkish_get_up_to_side_plank', - 115: 'two_point_plank', - 116: 'weighted_two_point_plank', - 117: 'weighted_plank', - 118: 'wide_stance_plank_with_diagonal_arm_lift', - 119: 'weighted_wide_stance_plank_with_diagonal_arm_lift', - 120: 'wide_stance_plank_with_diagonal_leg_lift', - 121: 'weighted_wide_stance_plank_with_diagonal_leg_lift', - 122: 'wide_stance_plank_with_leg_lift', - 123: 'weighted_wide_stance_plank_with_leg_lift', - 124: 'wide_stance_plank_with_opposite_arm_and_leg_lift', - 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', - }, - ), - 'plyo_exercise_name': FieldType( - name='plyo_exercise_name', - base_type=BASE_TYPES[0x84], # uint16 - values={ - 0: 'alternating_jump_lunge', - 1: 'weighted_alternating_jump_lunge', - 2: 'barbell_jump_squat', - 3: 'body_weight_jump_squat', - 4: 'weighted_jump_squat', - 5: 'cross_knee_strike', - 6: 'weighted_cross_knee_strike', - 7: 'depth_jump', - 8: 'weighted_depth_jump', - 9: 'dumbbell_jump_squat', - 10: 'dumbbell_split_jump', - 11: 'front_knee_strike', - 12: 'weighted_front_knee_strike', - 13: 'high_box_jump', - 14: 'weighted_high_box_jump', - 15: 'isometric_explosive_body_weight_jump_squat', - 16: 'weighted_isometric_explosive_jump_squat', - 17: 'lateral_leap_and_hop', - 18: 'weighted_lateral_leap_and_hop', - 19: 'lateral_plyo_squats', - 20: 'weighted_lateral_plyo_squats', - 21: 'lateral_slide', - 22: 'weighted_lateral_slide', - 23: 'medicine_ball_overhead_throws', - 24: 'medicine_ball_side_throw', - 25: 'medicine_ball_slam', - 26: 'side_to_side_medicine_ball_throws', - 27: 'side_to_side_shuffle_jump', - 28: 'weighted_side_to_side_shuffle_jump', - 29: 'squat_jump_onto_box', - 30: 'weighted_squat_jump_onto_box', - 31: 'squat_jumps_in_and_out', - 32: 'weighted_squat_jumps_in_and_out', - }, - ), - 'power_phase_type': FieldType( - name='power_phase_type', - base_type=BASE_TYPES[0x00], # enum - values={ - 0: 'power_phase_start_angle', - 1: 'power_phase_end_angle', - 2: 'power_phase_arc_length', - 3: 'power_phase_center', - }, - ), - 'pull_up_exercise_name': FieldType( - name='pull_up_exercise_name', - base_type=BASE_TYPES[0x84], # uint16 - values={ - 0: 'banded_pull_ups', - 1: '30_degree_lat_pulldown', - 2: 'band_assisted_chin_up', - 3: 'close_grip_chin_up', - 4: 'weighted_close_grip_chin_up', - 5: 'close_grip_lat_pulldown', - 6: 'crossover_chin_up', - 7: 'weighted_crossover_chin_up', - 8: 'ez_bar_pullover', - 9: 'hanging_hurdle', - 10: 'weighted_hanging_hurdle', - 11: 'kneeling_lat_pulldown', - 12: 'kneeling_underhand_grip_lat_pulldown', - 13: 'lat_pulldown', - 14: 'mixed_grip_chin_up', - 15: 'weighted_mixed_grip_chin_up', - 16: 'mixed_grip_pull_up', - 17: 'weighted_mixed_grip_pull_up', - 18: 'reverse_grip_pulldown', - 19: 'standing_cable_pullover', - 20: 'straight_arm_pulldown', - 21: 'swiss_ball_ez_bar_pullover', - 22: 'towel_pull_up', - 23: 'weighted_towel_pull_up', - 24: 'weighted_pull_up', - 25: 'wide_grip_lat_pulldown', - 26: 'wide_grip_pull_up', - 27: 'weighted_wide_grip_pull_up', - 28: 'burpee_pull_up', - 29: 'weighted_burpee_pull_up', - 30: 'jumping_pull_ups', - 31: 'weighted_jumping_pull_ups', - 32: 'kipping_pull_up', - 33: 'weighted_kipping_pull_up', - 34: 'l_pull_up', - 35: 'weighted_l_pull_up', - 36: 'suspended_chin_up', - 37: 'weighted_suspended_chin_up', - 38: 'pull_up', - }, - ), - 'push_up_exercise_name': FieldType( - name='push_up_exercise_name', - base_type=BASE_TYPES[0x84], # uint16 - values={ - 0: 'chest_press_with_band', - 1: 'alternating_staggered_push_up', - 2: 'weighted_alternating_staggered_push_up', - 3: 'alternating_hands_medicine_ball_push_up', - 4: 'weighted_alternating_hands_medicine_ball_push_up', - 5: 'bosu_ball_push_up', - 6: 'weighted_bosu_ball_push_up', - 7: 'clapping_push_up', - 8: 'weighted_clapping_push_up', - 9: 'close_grip_medicine_ball_push_up', - 10: 'weighted_close_grip_medicine_ball_push_up', - 11: 'close_hands_push_up', - 12: 'weighted_close_hands_push_up', - 13: 'decline_push_up', - 14: 'weighted_decline_push_up', - 15: 'diamond_push_up', - 16: 'weighted_diamond_push_up', - 17: 'explosive_crossover_push_up', - 18: 'weighted_explosive_crossover_push_up', - 19: 'explosive_push_up', - 20: 'weighted_explosive_push_up', - 21: 'feet_elevated_side_to_side_push_up', - 22: 'weighted_feet_elevated_side_to_side_push_up', - 23: 'hand_release_push_up', - 24: 'weighted_hand_release_push_up', - 25: 'handstand_push_up', - 26: 'weighted_handstand_push_up', - 27: 'incline_push_up', - 28: 'weighted_incline_push_up', - 29: 'isometric_explosive_push_up', - 30: 'weighted_isometric_explosive_push_up', - 31: 'judo_push_up', - 32: 'weighted_judo_push_up', - 33: 'kneeling_push_up', - 34: 'weighted_kneeling_push_up', - 35: 'medicine_ball_chest_pass', - 36: 'medicine_ball_push_up', - 37: 'weighted_medicine_ball_push_up', - 38: 'one_arm_push_up', - 39: 'weighted_one_arm_push_up', - 40: 'weighted_push_up', - 41: 'push_up_and_row', - 42: 'weighted_push_up_and_row', - 43: 'push_up_plus', - 44: 'weighted_push_up_plus', - 45: 'push_up_with_feet_on_swiss_ball', - 46: 'weighted_push_up_with_feet_on_swiss_ball', - 47: 'push_up_with_one_hand_on_medicine_ball', - 48: 'weighted_push_up_with_one_hand_on_medicine_ball', - 49: 'shoulder_push_up', - 50: 'weighted_shoulder_push_up', - 51: 'single_arm_medicine_ball_push_up', - 52: 'weighted_single_arm_medicine_ball_push_up', - 53: 'spiderman_push_up', - 54: 'weighted_spiderman_push_up', - 55: 'stacked_feet_push_up', - 56: 'weighted_stacked_feet_push_up', - 57: 'staggered_hands_push_up', - 58: 'weighted_staggered_hands_push_up', - 59: 'suspended_push_up', - 60: 'weighted_suspended_push_up', - 61: 'swiss_ball_push_up', - 62: 'weighted_swiss_ball_push_up', - 63: 'swiss_ball_push_up_plus', - 64: 'weighted_swiss_ball_push_up_plus', - 65: 't_push_up', - 66: 'weighted_t_push_up', - 67: 'triple_stop_push_up', - 68: 'weighted_triple_stop_push_up', - 69: 'wide_hands_push_up', - 70: 'weighted_wide_hands_push_up', - 71: 'parallette_handstand_push_up', - 72: 'weighted_parallette_handstand_push_up', - 73: 'ring_handstand_push_up', - 74: 'weighted_ring_handstand_push_up', - 75: 'ring_push_up', - 76: 'weighted_ring_push_up', - 77: 'push_up', - }, - ), - 'pwr_zone_calc': FieldType( - name='pwr_zone_calc', - base_type=BASE_TYPES[0x00], # enum - values={ - 0: 'custom', - 1: 'percent_ftp', - }, - ), - 'rider_position_type': FieldType( - name='rider_position_type', - base_type=BASE_TYPES[0x00], # enum - values={ - 0: 'seated', - 1: 'standing', - 2: 'transition_to_seated', - 3: 'transition_to_standing', - }, - ), - 'row_exercise_name': FieldType( - name='row_exercise_name', - base_type=BASE_TYPES[0x84], # uint16 - values={ - 0: 'barbell_straight_leg_deadlift_to_row', - 1: 'cable_row_standing', - 2: 'dumbbell_row', - 3: 'elevated_feet_inverted_row', - 4: 'weighted_elevated_feet_inverted_row', - 5: 'face_pull', - 6: 'face_pull_with_external_rotation', - 7: 'inverted_row_with_feet_on_swiss_ball', - 8: 'weighted_inverted_row_with_feet_on_swiss_ball', - 9: 'kettlebell_row', - 10: 'modified_inverted_row', - 11: 'weighted_modified_inverted_row', - 12: 'neutral_grip_alternating_dumbbell_row', - 13: 'one_arm_bent_over_row', - 14: 'one_legged_dumbbell_row', - 15: 'renegade_row', - 16: 'reverse_grip_barbell_row', - 17: 'rope_handle_cable_row', - 18: 'seated_cable_row', - 19: 'seated_dumbbell_row', - 20: 'single_arm_cable_row', - 21: 'single_arm_cable_row_and_rotation', - 22: 'single_arm_inverted_row', - 23: 'weighted_single_arm_inverted_row', - 24: 'single_arm_neutral_grip_dumbbell_row', - 25: 'single_arm_neutral_grip_dumbbell_row_and_rotation', - 26: 'suspended_inverted_row', - 27: 'weighted_suspended_inverted_row', - 28: 't_bar_row', - 29: 'towel_grip_inverted_row', - 30: 'weighted_towel_grip_inverted_row', - 31: 'underhand_grip_cable_row', - 32: 'v_grip_cable_row', - 33: 'wide_grip_seated_cable_row', - }, - ), - 'run_exercise_name': FieldType( - name='run_exercise_name', - base_type=BASE_TYPES[0x84], # uint16 - values={ - 0: 'run', - 1: 'walk', - 2: 'jog', - 3: 'sprint', - }, - ), - 'schedule': FieldType( - name='schedule', - base_type=BASE_TYPES[0x00], # enum - values={ - 0: 'workout', - 1: 'course', - }, - ), - 'segment_delete_status': FieldType( - name='segment_delete_status', - base_type=BASE_TYPES[0x00], # enum - values={ - 0: 'do_not_delete', - 1: 'delete_one', - 2: 'delete_all', - }, - ), - 'segment_lap_status': FieldType( - name='segment_lap_status', - base_type=BASE_TYPES[0x00], # enum - values={ - 0: 'end', - 1: 'fail', - }, - ), - 'segment_leaderboard_type': FieldType( - name='segment_leaderboard_type', - base_type=BASE_TYPES[0x00], # enum - values={ - 0: 'overall', - 1: 'personal_best', - 2: 'connections', - 3: 'group', - 4: 'challenger', - 5: 'kom', - 6: 'qom', - 7: 'pr', - 8: 'goal', - 9: 'rival', - 10: 'club_leader', - }, - ), - 'segment_selection_type': FieldType( - name='segment_selection_type', - base_type=BASE_TYPES[0x00], # enum - values={ - 0: 'starred', - 1: 'suggested', - }, - ), - 'sensor_type': FieldType( - name='sensor_type', - base_type=BASE_TYPES[0x00], # enum - values={ - 0: 'accelerometer', - 1: 'gyroscope', - 2: 'compass', # Magnetometer - 3: 'barometer', - }, - ), - 'session_trigger': FieldType( - name='session_trigger', - base_type=BASE_TYPES[0x00], # enum - values={ - 0: 'activity_end', - 1: 'manual', # User changed sport. - 2: 'auto_multi_sport', # Auto multi-sport feature is enabled and user pressed lap button to advance session. - 3: 'fitness_equipment', # Auto sport change caused by user linking to fitness equipment. - }, - ), - 'set_type': FieldType( - name='set_type', - base_type=BASE_TYPES[0x02], # uint8 - values={ - 0: 'rest', - 1: 'active', - }, - ), - 'shoulder_press_exercise_name': FieldType( - name='shoulder_press_exercise_name', - base_type=BASE_TYPES[0x84], # uint16 - values={ - 0: 'alternating_dumbbell_shoulder_press', - 1: 'arnold_press', - 2: 'barbell_front_squat_to_push_press', - 3: 'barbell_push_press', - 4: 'barbell_shoulder_press', - 5: 'dead_curl_press', - 6: 'dumbbell_alternating_shoulder_press_and_twist', - 7: 'dumbbell_hammer_curl_to_lunge_to_press', - 8: 'dumbbell_push_press', - 9: 'floor_inverted_shoulder_press', - 10: 'weighted_floor_inverted_shoulder_press', - 11: 'inverted_shoulder_press', - 12: 'weighted_inverted_shoulder_press', - 13: 'one_arm_push_press', - 14: 'overhead_barbell_press', - 15: 'overhead_dumbbell_press', - 16: 'seated_barbell_shoulder_press', - 17: 'seated_dumbbell_shoulder_press', - 18: 'single_arm_dumbbell_shoulder_press', - 19: 'single_arm_step_up_and_press', - 20: 'smith_machine_overhead_press', - 21: 'split_stance_hammer_curl_to_press', - 22: 'swiss_ball_dumbbell_shoulder_press', - 23: 'weight_plate_front_raise', - }, - ), - 'shoulder_stability_exercise_name': FieldType( - name='shoulder_stability_exercise_name', - base_type=BASE_TYPES[0x84], # uint16 - values={ - 0: '90_degree_cable_external_rotation', - 1: 'band_external_rotation', - 2: 'band_internal_rotation', - 3: 'bent_arm_lateral_raise_and_external_rotation', - 4: 'cable_external_rotation', - 5: 'dumbbell_face_pull_with_external_rotation', - 6: 'floor_i_raise', - 7: 'weighted_floor_i_raise', - 8: 'floor_t_raise', - 9: 'weighted_floor_t_raise', - 10: 'floor_y_raise', - 11: 'weighted_floor_y_raise', - 12: 'incline_i_raise', - 13: 'weighted_incline_i_raise', - 14: 'incline_l_raise', - 15: 'weighted_incline_l_raise', - 16: 'incline_t_raise', - 17: 'weighted_incline_t_raise', - 18: 'incline_w_raise', - 19: 'weighted_incline_w_raise', - 20: 'incline_y_raise', - 21: 'weighted_incline_y_raise', - 22: 'lying_external_rotation', - 23: 'seated_dumbbell_external_rotation', - 24: 'standing_l_raise', - 25: 'swiss_ball_i_raise', - 26: 'weighted_swiss_ball_i_raise', - 27: 'swiss_ball_t_raise', - 28: 'weighted_swiss_ball_t_raise', - 29: 'swiss_ball_w_raise', - 30: 'weighted_swiss_ball_w_raise', - 31: 'swiss_ball_y_raise', - 32: 'weighted_swiss_ball_y_raise', - }, - ), - 'shrug_exercise_name': FieldType( - name='shrug_exercise_name', - base_type=BASE_TYPES[0x84], # uint16 - values={ - 0: 'barbell_jump_shrug', - 1: 'barbell_shrug', - 2: 'barbell_upright_row', - 3: 'behind_the_back_smith_machine_shrug', - 4: 'dumbbell_jump_shrug', - 5: 'dumbbell_shrug', - 6: 'dumbbell_upright_row', - 7: 'incline_dumbbell_shrug', - 8: 'overhead_barbell_shrug', - 9: 'overhead_dumbbell_shrug', - 10: 'scaption_and_shrug', - 11: 'scapular_retraction', - 12: 'serratus_chair_shrug', - 13: 'weighted_serratus_chair_shrug', - 14: 'serratus_shrug', - 15: 'weighted_serratus_shrug', - 16: 'wide_grip_jump_shrug', - }, - ), - 'side': FieldType( - name='side', - base_type=BASE_TYPES[0x00], # enum - values={ - 0: 'right', - 1: 'left', - }, - ), - 'sit_up_exercise_name': FieldType( - name='sit_up_exercise_name', - base_type=BASE_TYPES[0x84], # uint16 - values={ - 0: 'alternating_sit_up', - 1: 'weighted_alternating_sit_up', - 2: 'bent_knee_v_up', - 3: 'weighted_bent_knee_v_up', - 4: 'butterfly_sit_up', - 5: 'weighted_butterfly_situp', - 6: 'cross_punch_roll_up', - 7: 'weighted_cross_punch_roll_up', - 8: 'crossed_arms_sit_up', - 9: 'weighted_crossed_arms_sit_up', - 10: 'get_up_sit_up', - 11: 'weighted_get_up_sit_up', - 12: 'hovering_sit_up', - 13: 'weighted_hovering_sit_up', - 14: 'kettlebell_sit_up', - 15: 'medicine_ball_alternating_v_up', - 16: 'medicine_ball_sit_up', - 17: 'medicine_ball_v_up', - 18: 'modified_sit_up', - 19: 'negative_sit_up', - 20: 'one_arm_full_sit_up', - 21: 'reclining_circle', - 22: 'weighted_reclining_circle', - 23: 'reverse_curl_up', - 24: 'weighted_reverse_curl_up', - 25: 'single_leg_swiss_ball_jackknife', - 26: 'weighted_single_leg_swiss_ball_jackknife', - 27: 'the_teaser', - 28: 'the_teaser_weighted', - 29: 'three_part_roll_down', - 30: 'weighted_three_part_roll_down', - 31: 'v_up', - 32: 'weighted_v_up', - 33: 'weighted_russian_twist_on_swiss_ball', - 34: 'weighted_sit_up', - 35: 'x_abs', - 36: 'weighted_x_abs', - 37: 'sit_up', - }, - ), - 'source_type': FieldType( - name='source_type', - base_type=BASE_TYPES[0x00], # enum - values={ - 0: 'ant', # External device connected with ANT - 1: 'antplus', # External device connected with ANT+ - 2: 'bluetooth', # External device connected with BT - 3: 'bluetooth_low_energy', # External device connected with BLE - 4: 'wifi', # External device connected with Wifi - 5: 'local', # Onboard device - }, - ), - 'sport': FieldType( - name='sport', - base_type=BASE_TYPES[0x00], # enum - values={ - 0: 'generic', - 1: 'running', - 2: 'cycling', - 3: 'transition', # Mulitsport transition - 4: 'fitness_equipment', - 5: 'swimming', - 6: 'basketball', - 7: 'soccer', - 8: 'tennis', - 9: 'american_football', - 10: 'training', - 11: 'walking', - 12: 'cross_country_skiing', - 13: 'alpine_skiing', - 14: 'snowboarding', - 15: 'rowing', - 16: 'mountaineering', - 17: 'hiking', - 18: 'multisport', - 19: 'paddling', - 20: 'flying', - 21: 'e_biking', - 22: 'motorcycling', - 23: 'boating', - 24: 'driving', - 25: 'golf', - 26: 'hang_gliding', - 27: 'horseback_riding', - 28: 'hunting', - 29: 'fishing', - 30: 'inline_skating', - 31: 'rock_climbing', - 32: 'sailing', - 33: 'ice_skating', - 34: 'sky_diving', - 35: 'snowshoeing', - 36: 'snowmobiling', - 37: 'stand_up_paddleboarding', - 38: 'surfing', - 39: 'wakeboarding', - 40: 'water_skiing', - 41: 'kayaking', - 42: 'rafting', - 43: 'windsurfing', - 44: 'kitesurfing', - 45: 'tactical', - 46: 'jumpmaster', - 47: 'boxing', - 48: 'floor_climbing', - 254: 'all', # All is for goals only to include all sports. - }, - ), - 'sport_bits_0': FieldType( # Bit field corresponding to sport enum type (1 << sport). - name='sport_bits_0', - base_type=BASE_TYPES[0x0A], # uint8z - values={ - 0x01: 'generic', - 0x02: 'running', - 0x04: 'cycling', - 0x08: 'transition', # Mulitsport transition - 0x10: 'fitness_equipment', - 0x20: 'swimming', - 0x40: 'basketball', - 0x80: 'soccer', - }, - ), - 'sport_bits_1': FieldType( # Bit field corresponding to sport enum type (1 << (sport-8)). - name='sport_bits_1', - base_type=BASE_TYPES[0x0A], # uint8z - values={ - 0x01: 'tennis', - 0x02: 'american_football', - 0x04: 'training', - 0x08: 'walking', - 0x10: 'cross_country_skiing', - 0x20: 'alpine_skiing', - 0x40: 'snowboarding', - 0x80: 'rowing', - }, - ), - 'sport_bits_2': FieldType( # Bit field corresponding to sport enum type (1 << (sport-16)). - name='sport_bits_2', - base_type=BASE_TYPES[0x0A], # uint8z - values={ - 0x01: 'mountaineering', - 0x02: 'hiking', - 0x04: 'multisport', - 0x08: 'paddling', - 0x10: 'flying', - 0x20: 'e_biking', - 0x40: 'motorcycling', - 0x80: 'boating', - }, - ), - 'sport_bits_3': FieldType( # Bit field corresponding to sport enum type (1 << (sport-24)). - name='sport_bits_3', - base_type=BASE_TYPES[0x0A], # uint8z - values={ - 0x01: 'driving', - 0x02: 'golf', - 0x04: 'hang_gliding', - 0x08: 'horseback_riding', - 0x10: 'hunting', - 0x20: 'fishing', - 0x40: 'inline_skating', - 0x80: 'rock_climbing', - }, - ), - 'sport_bits_4': FieldType( # Bit field corresponding to sport enum type (1 << (sport-32)). - name='sport_bits_4', - base_type=BASE_TYPES[0x0A], # uint8z - values={ - 0x01: 'sailing', - 0x02: 'ice_skating', - 0x04: 'sky_diving', - 0x08: 'snowshoeing', - 0x10: 'snowmobiling', - 0x20: 'stand_up_paddleboarding', - 0x40: 'surfing', - 0x80: 'wakeboarding', - }, - ), - 'sport_bits_5': FieldType( # Bit field corresponding to sport enum type (1 << (sport-40)). - name='sport_bits_5', - base_type=BASE_TYPES[0x0A], # uint8z - values={ - 0x01: 'water_skiing', - 0x02: 'kayaking', - 0x04: 'rafting', - 0x08: 'windsurfing', - 0x10: 'kitesurfing', - 0x20: 'tactical', - 0x40: 'jumpmaster', - 0x80: 'boxing', - }, - ), - 'sport_bits_6': FieldType( # Bit field corresponding to sport enum type (1 << (sport-48)). - name='sport_bits_6', - base_type=BASE_TYPES[0x0A], # uint8z - values={ - 0x01: 'floor_climbing', - }, - ), - 'sport_event': FieldType( - name='sport_event', - base_type=BASE_TYPES[0x00], # enum - values={ - 0: 'uncategorized', - 1: 'geocaching', - 2: 'fitness', - 3: 'recreation', - 4: 'race', - 5: 'special_event', - 6: 'training', - 7: 'transportation', - 8: 'touring', - }, - ), - 'squat_exercise_name': FieldType( - name='squat_exercise_name', - base_type=BASE_TYPES[0x84], # uint16 - values={ - 0: 'leg_press', - 1: 'back_squat_with_body_bar', - 2: 'back_squats', - 3: 'weighted_back_squats', - 4: 'balancing_squat', - 5: 'weighted_balancing_squat', - 6: 'barbell_back_squat', - 7: 'barbell_box_squat', - 8: 'barbell_front_squat', - 9: 'barbell_hack_squat', - 10: 'barbell_hang_squat_snatch', - 11: 'barbell_lateral_step_up', - 12: 'barbell_quarter_squat', - 13: 'barbell_siff_squat', - 14: 'barbell_squat_snatch', - 15: 'barbell_squat_with_heels_raised', - 16: 'barbell_stepover', - 17: 'barbell_step_up', - 18: 'bench_squat_with_rotational_chop', - 19: 'weighted_bench_squat_with_rotational_chop', - 20: 'body_weight_wall_squat', - 21: 'weighted_wall_squat', - 22: 'box_step_squat', - 23: 'weighted_box_step_squat', - 24: 'braced_squat', - 25: 'crossed_arm_barbell_front_squat', - 26: 'crossover_dumbbell_step_up', - 27: 'dumbbell_front_squat', - 28: 'dumbbell_split_squat', - 29: 'dumbbell_squat', - 30: 'dumbbell_squat_clean', - 31: 'dumbbell_stepover', - 32: 'dumbbell_step_up', - 33: 'elevated_single_leg_squat', - 34: 'weighted_elevated_single_leg_squat', - 35: 'figure_four_squats', - 36: 'weighted_figure_four_squats', - 37: 'goblet_squat', - 38: 'kettlebell_squat', - 39: 'kettlebell_swing_overhead', - 40: 'kettlebell_swing_with_flip_to_squat', - 41: 'lateral_dumbbell_step_up', - 42: 'one_legged_squat', - 43: 'overhead_dumbbell_squat', - 44: 'overhead_squat', - 45: 'partial_single_leg_squat', - 46: 'weighted_partial_single_leg_squat', - 47: 'pistol_squat', - 48: 'weighted_pistol_squat', - 49: 'plie_slides', - 50: 'weighted_plie_slides', - 51: 'plie_squat', - 52: 'weighted_plie_squat', - 53: 'prisoner_squat', - 54: 'weighted_prisoner_squat', - 55: 'single_leg_bench_get_up', - 56: 'weighted_single_leg_bench_get_up', - 57: 'single_leg_bench_squat', - 58: 'weighted_single_leg_bench_squat', - 59: 'single_leg_squat_on_swiss_ball', - 60: 'weighted_single_leg_squat_on_swiss_ball', - 61: 'squat', - 62: 'weighted_squat', - 63: 'squats_with_band', - 64: 'staggered_squat', - 65: 'weighted_staggered_squat', - 66: 'step_up', - 67: 'weighted_step_up', - 68: 'suitcase_squats', - 69: 'sumo_squat', - 70: 'sumo_squat_slide_in', - 71: 'weighted_sumo_squat_slide_in', - 72: 'sumo_squat_to_high_pull', - 73: 'sumo_squat_to_stand', - 74: 'weighted_sumo_squat_to_stand', - 75: 'sumo_squat_with_rotation', - 76: 'weighted_sumo_squat_with_rotation', - 77: 'swiss_ball_body_weight_wall_squat', - 78: 'weighted_swiss_ball_wall_squat', - 79: 'thrusters', - 80: 'uneven_squat', - 81: 'weighted_uneven_squat', - 82: 'waist_slimming_squat', - 83: 'wall_ball', - 84: 'wide_stance_barbell_squat', - 85: 'wide_stance_goblet_squat', - 86: 'zercher_squat', - }, - ), - 'stroke_type': FieldType( - name='stroke_type', - base_type=BASE_TYPES[0x00], # enum - values={ - 0: 'no_event', - 1: 'other', # stroke was detected but cannot be identified - 2: 'serve', - 3: 'forehand', - 4: 'backhand', - 5: 'smash', - }, - ), - 'sub_sport': FieldType( - name='sub_sport', - base_type=BASE_TYPES[0x00], # enum - values={ - 0: 'generic', - 1: 'treadmill', # Run/Fitness Equipment - 2: 'street', # Run - 3: 'trail', # Run - 4: 'track', # Run - 5: 'spin', # Cycling - 6: 'indoor_cycling', # Cycling/Fitness Equipment - 7: 'road', # Cycling - 8: 'mountain', # Cycling - 9: 'downhill', # Cycling - 10: 'recumbent', # Cycling - 11: 'cyclocross', # Cycling - 12: 'hand_cycling', # Cycling - 13: 'track_cycling', # Cycling - 14: 'indoor_rowing', # Fitness Equipment - 15: 'elliptical', # Fitness Equipment - 16: 'stair_climbing', # Fitness Equipment - 17: 'lap_swimming', # Swimming - 18: 'open_water', # Swimming - 19: 'flexibility_training', # Training - 20: 'strength_training', # Training - 21: 'warm_up', # Tennis - 22: 'match', # Tennis - 23: 'exercise', # Tennis - 24: 'challenge', - 25: 'indoor_skiing', # Fitness Equipment - 26: 'cardio_training', # Training - 27: 'indoor_walking', # Walking/Fitness Equipment - 28: 'e_bike_fitness', # E-Biking - 29: 'bmx', # Cycling - 30: 'casual_walking', # Walking - 31: 'speed_walking', # Walking - 32: 'bike_to_run_transition', # Transition - 33: 'run_to_bike_transition', # Transition - 34: 'swim_to_bike_transition', # Transition - 35: 'atv', # Motorcycling - 36: 'motocross', # Motorcycling - 37: 'backcountry', # Alpine Skiing/Snowboarding - 38: 'resort', # Alpine Skiing/Snowboarding - 39: 'rc_drone', # Flying - 40: 'wingsuit', # Flying - 41: 'whitewater', # Kayaking/Rafting - 42: 'skate_skiing', # Cross Country Skiing - 43: 'yoga', # Training - 44: 'pilates', # Training - 45: 'indoor_running', # Run - 46: 'gravel_cycling', # Cycling - 47: 'e_bike_mountain', # Cycling - 48: 'commuting', # Cycling - 49: 'mixed_surface', # Cycling - 50: 'navigate', - 51: 'track_me', - 52: 'map', - 53: 'single_gas_diving', # Diving - 54: 'multi_gas_diving', # Diving - 55: 'gauge_diving', # Diving - 56: 'apnea_diving', # Diving - 57: 'apnea_hunting', # Diving - 58: 'virtual_activity', - 59: 'obstacle', # Used for events where participants run, crawl through mud, climb over walls, etc. - 254: 'all', - }, - ), - 'supported_exd_screen_layouts': FieldType( - name='supported_exd_screen_layouts', - base_type=BASE_TYPES[0x8C], # uint32z - values={ - 0x00000001: 'full_screen', - 0x00000002: 'half_vertical', - 0x00000004: 'half_horizontal', - 0x00000008: 'half_vertical_right_split', - 0x00000010: 'half_horizontal_bottom_split', - 0x00000020: 'full_quarter_split', - 0x00000040: 'half_vertical_left_split', - 0x00000080: 'half_horizontal_top_split', - }, - ), - 'swim_stroke': FieldType( - name='swim_stroke', - base_type=BASE_TYPES[0x00], # enum - values={ - 0: 'freestyle', - 1: 'backstroke', - 2: 'breaststroke', - 3: 'butterfly', - 4: 'drill', - 5: 'mixed', - 6: 'im', # IM is a mixed interval containing the same number of lengths for each of: Butterfly, Backstroke, Breaststroke, Freestyle, swam in that order. - }, - ), - 'switch': FieldType( - name='switch', - base_type=BASE_TYPES[0x00], # enum - values={ - 0: 'off', - 1: 'on', - 2: 'auto', - }, - ), - '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 - ), - 'time_mode': FieldType( - name='time_mode', - base_type=BASE_TYPES[0x00], # enum - values={ - 0: 'hour12', - 1: 'hour24', # Does not use a leading zero and has a colon - 2: 'military', # Uses a leading zero and does not have a colon - 3: 'hour_12_with_seconds', - 4: 'hour_24_with_seconds', - 5: 'utc', - }, - ), - 'time_zone': FieldType( - name='time_zone', - base_type=BASE_TYPES[0x00], # enum - values={ - 0: 'almaty', - 1: 'bangkok', - 2: 'bombay', - 3: 'brasilia', - 4: 'cairo', - 5: 'cape_verde_is', - 6: 'darwin', - 7: 'eniwetok', - 8: 'fiji', - 9: 'hong_kong', - 10: 'islamabad', - 11: 'kabul', - 12: 'magadan', - 13: 'mid_atlantic', - 14: 'moscow', - 15: 'muscat', - 16: 'newfoundland', - 17: 'samoa', - 18: 'sydney', - 19: 'tehran', - 20: 'tokyo', - 21: 'us_alaska', - 22: 'us_atlantic', - 23: 'us_central', - 24: 'us_eastern', - 25: 'us_hawaii', - 26: 'us_mountain', - 27: 'us_pacific', - 28: 'other', - 29: 'auckland', - 30: 'kathmandu', - 31: 'europe_western_wet', - 32: 'europe_central_cet', - 33: 'europe_eastern_eet', - 34: 'jakarta', - 35: 'perth', - 36: 'adelaide', - 37: 'brisbane', - 38: 'tasmania', - 39: 'iceland', - 40: 'amsterdam', - 41: 'athens', - 42: 'barcelona', - 43: 'berlin', - 44: 'brussels', - 45: 'budapest', - 46: 'copenhagen', - 47: 'dublin', - 48: 'helsinki', - 49: 'lisbon', - 50: 'london', - 51: 'madrid', - 52: 'munich', - 53: 'oslo', - 54: 'paris', - 55: 'prague', - 56: 'reykjavik', - 57: 'rome', - 58: 'stockholm', - 59: 'vienna', - 60: 'warsaw', - 61: 'zurich', - 62: 'quebec', - 63: 'ontario', - 64: 'manitoba', - 65: 'saskatchewan', - 66: 'alberta', - 67: 'british_columbia', - 68: 'boise', - 69: 'boston', - 70: 'chicago', - 71: 'dallas', - 72: 'denver', - 73: 'kansas_city', - 74: 'las_vegas', - 75: 'los_angeles', - 76: 'miami', - 77: 'minneapolis', - 78: 'new_york', - 79: 'new_orleans', - 80: 'phoenix', - 81: 'santa_fe', - 82: 'seattle', - 83: 'washington_dc', - 84: 'us_arizona', - 85: 'chita', - 86: 'ekaterinburg', - 87: 'irkutsk', - 88: 'kaliningrad', - 89: 'krasnoyarsk', - 90: 'novosibirsk', - 91: 'petropavlovsk_kamchatskiy', - 92: 'samara', - 93: 'vladivostok', - 94: 'mexico_central', - 95: 'mexico_mountain', - 96: 'mexico_pacific', - 97: 'cape_town', - 98: 'winkhoek', - 99: 'lagos', - 100: 'riyahd', - 101: 'venezuela', - 102: 'australia_lh', - 103: 'santiago', - 253: 'manual', - 254: 'automatic', - }, - ), - 'timer_trigger': FieldType( # timer event data - name='timer_trigger', - base_type=BASE_TYPES[0x00], # enum - values={ - 0: 'manual', - 1: 'auto', - 2: 'fitness_equipment', - }, - ), - 'tissue_model_type': FieldType( - name='tissue_model_type', - base_type=BASE_TYPES[0x00], # enum - values={ - 0: 'zhl_16c', # Buhlmann's decompression algorithm, version C - }, - ), - 'tone': FieldType( - name='tone', - base_type=BASE_TYPES[0x00], # enum - values={ - 0: 'off', - 1: 'tone', - 2: 'vibrate', - 3: 'tone_and_vibrate', - }, - ), - 'total_body_exercise_name': FieldType( - name='total_body_exercise_name', - base_type=BASE_TYPES[0x84], # uint16 - values={ - 0: 'burpee', - 1: 'weighted_burpee', - 2: 'burpee_box_jump', - 3: 'weighted_burpee_box_jump', - 4: 'high_pull_burpee', - 5: 'man_makers', - 6: 'one_arm_burpee', - 7: 'squat_thrusts', - 8: 'weighted_squat_thrusts', - 9: 'squat_plank_push_up', - 10: 'weighted_squat_plank_push_up', - 11: 'standing_t_rotation_balance', - 12: 'weighted_standing_t_rotation_balance', - }, - ), - 'triceps_extension_exercise_name': FieldType( - name='triceps_extension_exercise_name', - base_type=BASE_TYPES[0x84], # uint16 - values={ - 0: 'bench_dip', - 1: 'weighted_bench_dip', - 2: 'body_weight_dip', - 3: 'cable_kickback', - 4: 'cable_lying_triceps_extension', - 5: 'cable_overhead_triceps_extension', - 6: 'dumbbell_kickback', - 7: 'dumbbell_lying_triceps_extension', - 8: 'ez_bar_overhead_triceps_extension', - 9: 'incline_dip', - 10: 'weighted_incline_dip', - 11: 'incline_ez_bar_lying_triceps_extension', - 12: 'lying_dumbbell_pullover_to_extension', - 13: 'lying_ez_bar_triceps_extension', - 14: 'lying_triceps_extension_to_close_grip_bench_press', - 15: 'overhead_dumbbell_triceps_extension', - 16: 'reclining_triceps_press', - 17: 'reverse_grip_pressdown', - 18: 'reverse_grip_triceps_pressdown', - 19: 'rope_pressdown', - 20: 'seated_barbell_overhead_triceps_extension', - 21: 'seated_dumbbell_overhead_triceps_extension', - 22: 'seated_ez_bar_overhead_triceps_extension', - 23: 'seated_single_arm_overhead_dumbbell_extension', - 24: 'single_arm_dumbbell_overhead_triceps_extension', - 25: 'single_dumbbell_seated_overhead_triceps_extension', - 26: 'single_leg_bench_dip_and_kick', - 27: 'weighted_single_leg_bench_dip_and_kick', - 28: 'single_leg_dip', - 29: 'weighted_single_leg_dip', - 30: 'static_lying_triceps_extension', - 31: 'suspended_dip', - 32: 'weighted_suspended_dip', - 33: 'swiss_ball_dumbbell_lying_triceps_extension', - 34: 'swiss_ball_ez_bar_lying_triceps_extension', - 35: 'swiss_ball_ez_bar_overhead_triceps_extension', - 36: 'tabletop_dip', - 37: 'weighted_tabletop_dip', - 38: 'triceps_extension_on_floor', - 39: 'triceps_pressdown', - 40: 'weighted_dip', - }, - ), - 'turn_type': FieldType( - name='turn_type', - base_type=BASE_TYPES[0x00], # enum - values={ - 0: 'arriving_idx', - 1: 'arriving_left_idx', - 2: 'arriving_right_idx', - 3: 'arriving_via_idx', - 4: 'arriving_via_left_idx', - 5: 'arriving_via_right_idx', - 6: 'bear_keep_left_idx', - 7: 'bear_keep_right_idx', - 8: 'continue_idx', - 9: 'exit_left_idx', - 10: 'exit_right_idx', - 11: 'ferry_idx', - 12: 'roundabout_45_idx', - 13: 'roundabout_90_idx', - 14: 'roundabout_135_idx', - 15: 'roundabout_180_idx', - 16: 'roundabout_225_idx', - 17: 'roundabout_270_idx', - 18: 'roundabout_315_idx', - 19: 'roundabout_360_idx', - 20: 'roundabout_neg_45_idx', - 21: 'roundabout_neg_90_idx', - 22: 'roundabout_neg_135_idx', - 23: 'roundabout_neg_180_idx', - 24: 'roundabout_neg_225_idx', - 25: 'roundabout_neg_270_idx', - 26: 'roundabout_neg_315_idx', - 27: 'roundabout_neg_360_idx', - 28: 'roundabout_generic_idx', - 29: 'roundabout_neg_generic_idx', - 30: 'sharp_turn_left_idx', - 31: 'sharp_turn_right_idx', - 32: 'turn_left_idx', - 33: 'turn_right_idx', - 34: 'uturn_left_idx', - 35: 'uturn_right_idx', - 36: 'icon_inv_idx', - 37: 'icon_idx_cnt', - }, - ), - 'user_local_id': FieldType( - name='user_local_id', - base_type=BASE_TYPES[0x84], # uint16 - values={ - 0x0000: 'local_min', - 0x000F: 'local_max', - 0x0010: 'stationary_min', - 0x00FF: 'stationary_max', - 0x0100: 'portable_min', - 0xFFFE: 'portable_max', - }, - ), - 'warm_up_exercise_name': FieldType( - name='warm_up_exercise_name', - base_type=BASE_TYPES[0x84], # uint16 - values={ - 0: 'quadruped_rocking', - 1: 'neck_tilts', - 2: 'ankle_circles', - 3: 'ankle_dorsiflexion_with_band', - 4: 'ankle_internal_rotation', - 5: 'arm_circles', - 6: 'bent_over_reach_to_sky', - 7: 'cat_camel', - 8: 'elbow_to_foot_lunge', - 9: 'forward_and_backward_leg_swings', - 10: 'groiners', - 11: 'inverted_hamstring_stretch', - 12: 'lateral_duck_under', - 13: 'neck_rotations', - 14: 'opposite_arm_and_leg_balance', - 15: 'reach_roll_and_lift', - 16: 'scorpion', - 17: 'shoulder_circles', - 18: 'side_to_side_leg_swings', - 19: 'sleeper_stretch', - 20: 'slide_out', - 21: 'swiss_ball_hip_crossover', - 22: 'swiss_ball_reach_roll_and_lift', - 23: 'swiss_ball_windshield_wipers', - 24: 'thoracic_rotation', - 25: 'walking_high_kicks', - 26: 'walking_high_knees', - 27: 'walking_knee_hugs', - 28: 'walking_leg_cradles', - 29: 'walkout', - 30: 'walkout_from_push_up_position', - }, - ), - 'watchface_mode': FieldType( - name='watchface_mode', - base_type=BASE_TYPES[0x00], # enum - values={ - 0: 'digital', - 1: 'analog', - 2: 'connect_iq', - 3: 'disabled', - }, - ), - 'water_type': FieldType( - name='water_type', - base_type=BASE_TYPES[0x00], # enum - values={ - 0: 'fresh', - 1: 'salt', - 2: 'en13319', - 3: 'custom', - }, - ), - 'weather_report': FieldType( - name='weather_report', - base_type=BASE_TYPES[0x00], # enum - values={ - 0: 'current', - 1: 'forecast', # Deprecated use hourly_forecast instead - 1: 'hourly_forecast', - 2: 'daily_forecast', - }, - ), - 'weather_severe_type': FieldType( - name='weather_severe_type', - base_type=BASE_TYPES[0x00], # enum - values={ - 0: 'unspecified', - 1: 'tornado', - 2: 'tsunami', - 3: 'hurricane', - 4: 'extreme_wind', - 5: 'typhoon', - 6: 'inland_hurricane', - 7: 'hurricane_force_wind', - 8: 'waterspout', - 9: 'severe_thunderstorm', - 10: 'wreckhouse_winds', - 11: 'les_suetes_wind', - 12: 'avalanche', - 13: 'flash_flood', - 14: 'tropical_storm', - 15: 'inland_tropical_storm', - 16: 'blizzard', - 17: 'ice_storm', - 18: 'freezing_rain', - 19: 'debris_flow', - 20: 'flash_freeze', - 21: 'dust_storm', - 22: 'high_wind', - 23: 'winter_storm', - 24: 'heavy_freezing_spray', - 25: 'extreme_cold', - 26: 'wind_chill', - 27: 'cold_wave', - 28: 'heavy_snow_alert', - 29: 'lake_effect_blowing_snow', - 30: 'snow_squall', - 31: 'lake_effect_snow', - 32: 'winter_weather', - 33: 'sleet', - 34: 'snowfall', - 35: 'snow_and_blowing_snow', - 36: 'blowing_snow', - 37: 'snow_alert', - 38: 'arctic_outflow', - 39: 'freezing_drizzle', - 40: 'storm', - 41: 'storm_surge', - 42: 'rainfall', - 43: 'areal_flood', - 44: 'coastal_flood', - 45: 'lakeshore_flood', - 46: 'excessive_heat', - 47: 'heat', - 48: 'weather', - 49: 'high_heat_and_humidity', - 50: 'humidex_and_health', - 51: 'humidex', - 52: 'gale', - 53: 'freezing_spray', - 54: 'special_marine', - 55: 'squall', - 56: 'strong_wind', - 57: 'lake_wind', - 58: 'marine_weather', - 59: 'wind', - 60: 'small_craft_hazardous_seas', - 61: 'hazardous_seas', - 62: 'small_craft', - 63: 'small_craft_winds', - 64: 'small_craft_rough_bar', - 65: 'high_water_level', - 66: 'ashfall', - 67: 'freezing_fog', - 68: 'dense_fog', - 69: 'dense_smoke', - 70: 'blowing_dust', - 71: 'hard_freeze', - 72: 'freeze', - 73: 'frost', - 74: 'fire_weather', - 75: 'flood', - 76: 'rip_tide', - 77: 'high_surf', - 78: 'smog', - 79: 'air_quality', - 80: 'brisk_wind', - 81: 'air_stagnation', - 82: 'low_water', - 83: 'hydrological', - 84: 'special_weather', - }, - ), - 'weather_severity': FieldType( - name='weather_severity', - base_type=BASE_TYPES[0x00], # enum - values={ - 0: 'unknown', - 1: 'warning', - 2: 'watch', - 3: 'advisory', - 4: 'statement', - }, - ), - 'weather_status': FieldType( - name='weather_status', - base_type=BASE_TYPES[0x00], # enum - values={ - 0: 'clear', - 1: 'partly_cloudy', - 2: 'mostly_cloudy', - 3: 'rain', - 4: 'snow', - 5: 'windy', - 6: 'thunderstorms', - 7: 'wintry_mix', - 8: 'fog', - 11: 'hazy', - 12: 'hail', - 13: 'scattered_showers', - 14: 'scattered_thunderstorms', - 15: 'unknown_precipitation', - 16: 'light_rain', - 17: 'heavy_rain', - 18: 'light_snow', - 19: 'heavy_snow', - 20: 'light_rain_snow', - 21: 'heavy_rain_snow', - 22: 'cloudy', - }, - ), - 'weight': FieldType( - name='weight', - base_type=BASE_TYPES[0x84], # uint16 - values={ - 0xFFFE: 'calculating', - }, - ), - 'wkt_step_duration': FieldType( - name='wkt_step_duration', - base_type=BASE_TYPES[0x00], # enum - values={ - 0: 'time', - 1: 'distance', - 2: 'hr_less_than', - 3: 'hr_greater_than', - 4: 'calories', - 5: 'open', - 6: 'repeat_until_steps_cmplt', - 7: 'repeat_until_time', - 8: 'repeat_until_distance', - 9: 'repeat_until_calories', - 10: 'repeat_until_hr_less_than', - 11: 'repeat_until_hr_greater_than', - 12: 'repeat_until_power_less_than', - 13: 'repeat_until_power_greater_than', - 14: 'power_less_than', - 15: 'power_greater_than', - 16: 'training_peaks_tss', - 17: 'repeat_until_power_last_lap_less_than', - 18: 'repeat_until_max_power_last_lap_less_than', - 19: 'power_3s_less_than', - 20: 'power_10s_less_than', - 21: 'power_30s_less_than', - 22: 'power_3s_greater_than', - 23: 'power_10s_greater_than', - 24: 'power_30s_greater_than', - 25: 'power_lap_less_than', - 26: 'power_lap_greater_than', - 27: 'repeat_until_training_peaks_tss', - 28: 'repetition_time', - 29: 'reps', - }, - ), - 'wkt_step_target': FieldType( - name='wkt_step_target', - base_type=BASE_TYPES[0x00], # enum - values={ - 0: 'speed', - 1: 'heart_rate', - 2: 'open', - 3: 'cadence', - 4: 'power', - 5: 'grade', - 6: 'resistance', - 7: 'power_3s', - 8: 'power_10s', - 9: 'power_30s', - 10: 'power_lap', - 11: 'swim_stroke', - 12: 'speed_lap', - 13: 'heart_rate_lap', - }, - ), - 'workout_capabilities': FieldType( - name='workout_capabilities', - base_type=BASE_TYPES[0x8C], # uint32z - values={ - 0x00000001: 'interval', - 0x00000002: 'custom', - 0x00000004: 'fitness_equipment', - 0x00000008: 'firstbeat', - 0x00000010: 'new_leaf', - 0x00000020: 'tcx', # For backwards compatibility. Watch should add missing id fields then clear flag. - 0x00000080: 'speed', # Speed source required for workout step. - 0x00000100: 'heart_rate', # Heart rate source required for workout step. - 0x00000200: 'distance', # Distance source required for workout step. - 0x00000400: 'cadence', # Cadence source required for workout step. - 0x00000800: 'power', # Power source required for workout step. - 0x00001000: 'grade', # Grade source required for workout step. - 0x00002000: 'resistance', # Resistance source required for workout step. - 0x00004000: 'protected', - }, - ), - 'workout_equipment': FieldType( - name='workout_equipment', - base_type=BASE_TYPES[0x00], # enum - values={ - 0: 'none', - 1: 'swim_fins', - 2: 'swim_kickboard', - 3: 'swim_paddles', - 4: 'swim_pull_buoy', - 5: 'swim_snorkel', - }, - ), - 'workout_hr': FieldType( # 0 - 100 indicates% of max hr; >100 indicates bpm (255 max) plus 100 - name='workout_hr', - base_type=BASE_TYPES[0x86], # uint32 - values={ - 100: 'bpm_offset', - }, - ), - 'workout_power': FieldType( # 0 - 1000 indicates % of functional threshold power; >1000 indicates watts plus 1000. - name='workout_power', - base_type=BASE_TYPES[0x86], # uint32 - values={ - 1000: 'watts_offset', - }, - ), -} - - -FIELD_TYPE_TIMESTAMP = Field(name='timestamp', type=FIELD_TYPES['date_time'], def_num=253, units='s') - - -MESSAGE_TYPES = { - # **************************** Common Messages ***************************** - 0: MessageType( # Must be first message in file. - name='file_id', - mesg_num=0, - fields={ - 0: Field( - name='type', - type=FIELD_TYPES['file'], - def_num=0, - ), - 1: Field( - name='manufacturer', - type=FIELD_TYPES['manufacturer'], - def_num=1, - ), - 2: Field( - name='product', - type=BASE_TYPES[0x84], # uint16 - def_num=2, - subfields=( - SubField( - name='garmin_product', - def_num=2, - type=FIELD_TYPES['garmin_product'], - ref_fields=( - ReferenceField( - name='manufacturer', - def_num=1, - value='garmin', - raw_value=1, - ), - ReferenceField( - name='manufacturer', - def_num=1, - value='dynastream', - raw_value=15, - ), - ReferenceField( - name='manufacturer', - def_num=1, - value='dynastream_oem', - raw_value=13, - ), - ), - ), - ), - ), - 3: Field( - name='serial_number', - type=BASE_TYPES[0x8C], # uint32z - def_num=3, - ), - 4: Field( # Only set for files that are can be created/erased. - name='time_created', - type=FIELD_TYPES['date_time'], - def_num=4, - ), - 5: Field( # Only set for files that are not created/erased. - name='number', - type=BASE_TYPES[0x84], # uint16 - def_num=5, - ), - 8: Field( # Optional free form string to indicate the devices name or model - name='product_name', - type=BASE_TYPES[0x07], # string - def_num=8, - ), - }, - ), - - - # ************************************ ************************************ - 1: MessageType( - name='capabilities', - mesg_num=1, - fields={ - 0: Field( # Use language_bits_x types where x is index of array. - name='languages', - type=BASE_TYPES[0x0A], # uint8z - def_num=0, - ), - 1: Field( # Use sport_bits_x types where x is index of array. - name='sports', - type=FIELD_TYPES['sport_bits_0'], - def_num=1, - ), - 21: Field( - name='workouts_supported', - type=FIELD_TYPES['workout_capabilities'], - def_num=21, - ), - 23: Field( - name='connectivity_supported', - type=FIELD_TYPES['connectivity_capabilities'], - def_num=23, - ), - }, - ), - 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', - type=BASE_TYPES[0x84], # uint16 - def_num=11, - scale=10, - units='%', - ), - 12: Field( - name='auto_wheel_cal', - type=FIELD_TYPES['bool'], - def_num=12, - ), - 13: Field( - name='auto_power_zero', - type=FIELD_TYPES['bool'], - def_num=13, - ), - 14: Field( - name='id', - type=BASE_TYPES[0x02], # uint8 - def_num=14, - ), - 15: Field( - name='spd_enabled', - type=FIELD_TYPES['bool'], - def_num=15, - ), - 16: Field( - name='cad_enabled', - type=FIELD_TYPES['bool'], - def_num=16, - ), - 17: Field( - name='spdcad_enabled', - type=FIELD_TYPES['bool'], - def_num=17, - ), - 18: Field( - name='power_enabled', - type=FIELD_TYPES['bool'], - def_num=18, - ), - 19: Field( - name='crank_length', - type=BASE_TYPES[0x02], # uint8 - def_num=19, - scale=2, - offset=-110, - units='mm', - ), - 20: Field( - name='enabled', - type=FIELD_TYPES['bool'], - def_num=20, - ), - 21: Field( - name='bike_spd_ant_id_trans_type', - type=BASE_TYPES[0x0A], # uint8z - def_num=21, - ), - 22: Field( - name='bike_cad_ant_id_trans_type', - type=BASE_TYPES[0x0A], # uint8z - def_num=22, - ), - 23: Field( - name='bike_spdcad_ant_id_trans_type', - type=BASE_TYPES[0x0A], # uint8z - def_num=23, - ), - 24: Field( - name='bike_power_ant_id_trans_type', - type=BASE_TYPES[0x0A], # uint8z - def_num=24, - ), - 37: Field( # Rollover counter that can be used to extend the odometer - name='odometer_rollover', - type=BASE_TYPES[0x02], # uint8 - def_num=37, - ), - 38: Field( # Number of front gears - name='front_gear_num', - type=BASE_TYPES[0x0A], # uint8z - def_num=38, - ), - 39: Field( # Number of teeth on each gear 0 is innermost - name='front_gear', - type=BASE_TYPES[0x0A], # uint8z - def_num=39, - ), - 40: Field( # Number of rear gears - name='rear_gear_num', - type=BASE_TYPES[0x0A], # uint8z - def_num=40, - ), - 41: Field( # Number of teeth on each gear 0 is innermost - name='rear_gear', - type=BASE_TYPES[0x0A], # uint8z - def_num=41, - ), - 44: Field( - name='shimano_di2_enabled', - type=FIELD_TYPES['bool'], - def_num=44, - ), - 254: Field( - name='message_index', - type=FIELD_TYPES['message_index'], - def_num=254, - ), - }, - ), - 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( - name='message_index', - type=FIELD_TYPES['message_index'], - def_num=254, - ), - }, - ), - 9: MessageType( - name='power_zone', - mesg_num=9, - fields={ - 1: Field( - name='high_value', - type=BASE_TYPES[0x84], # uint16 - def_num=1, - units='watts', - ), - 2: Field( - name='name', - type=BASE_TYPES[0x07], # string - def_num=2, - ), - 254: Field( - name='message_index', - type=FIELD_TYPES['message_index'], - def_num=254, - ), - }, - ), - 10: MessageType( - name='met_zone', - mesg_num=10, - fields={ - 1: Field( - name='high_bpm', - type=BASE_TYPES[0x02], # uint8 - def_num=1, - ), - 2: Field( - name='calories', - type=BASE_TYPES[0x84], # uint16 - def_num=2, - scale=10, - units='kcal/min', - ), - 3: Field( - name='fat_calories', - type=BASE_TYPES[0x02], # uint8 - def_num=3, - scale=10, - units='kcal/min', - ), - 254: Field( - name='message_index', - type=FIELD_TYPES['message_index'], - def_num=254, - ), - }, - ), - 12: MessageType( - name='sport', - mesg_num=12, - 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, - ), - 3: Field( - name='name', - type=BASE_TYPES[0x07], # string - def_num=3, - ), - }, - ), - 18: MessageType( - name='session', - mesg_num=18, - fields={ - 0: Field( # session - name='event', - type=FIELD_TYPES['event'], - def_num=0, - ), - 1: Field( # stop - name='event_type', - type=FIELD_TYPES['event_type'], - def_num=1, - ), - 2: Field( - name='start_time', - type=FIELD_TYPES['date_time'], - def_num=2, - ), - 3: Field( - name='start_position_lat', - type=BASE_TYPES[0x85], # sint32 - def_num=3, - units='semicircles', - ), - 4: Field( - name='start_position_long', - type=BASE_TYPES[0x85], # sint32 - def_num=4, - units='semicircles', - ), - 5: Field( - name='sport', - type=FIELD_TYPES['sport'], - def_num=5, - ), - 6: Field( - name='sub_sport', - type=FIELD_TYPES['sub_sport'], - def_num=6, - ), - 7: Field( # Time (includes pauses) - name='total_elapsed_time', - type=BASE_TYPES[0x86], # uint32 - def_num=7, - scale=1000, - units='s', - ), - 8: Field( # Timer Time (excludes pauses) - name='total_timer_time', - type=BASE_TYPES[0x86], # uint32 - def_num=8, - scale=1000, - units='s', - ), - 9: Field( - name='total_distance', - type=BASE_TYPES[0x86], # uint32 - def_num=9, - scale=100, - units='m', - ), - 10: Field( - name='total_cycles', - type=BASE_TYPES[0x86], # uint32 - def_num=10, - units='cycles', - subfields=( - SubField( - name='total_strides', - def_num=10, - type=BASE_TYPES[0x86], # uint32 - units='strides', - ref_fields=( - ReferenceField( - name='sport', - def_num=5, - value='running', - raw_value=1, - ), - ReferenceField( - name='sport', - def_num=5, - value='walking', - raw_value=11, - ), - ), - ), - ), - ), - 11: Field( - name='total_calories', - type=BASE_TYPES[0x84], # uint16 - def_num=11, - units='kcal', - ), - 13: Field( - name='total_fat_calories', - type=BASE_TYPES[0x84], # uint16 - def_num=13, - units='kcal', - ), - 14: Field( # total_distance / total_timer_time - name='avg_speed', - type=BASE_TYPES[0x84], # uint16 - def_num=14, - components=( - ComponentField( - name='enhanced_avg_speed', - def_num=124, - scale=1000, - units='m/s', - accumulate=False, - bits=16, - bit_offset=0, - ), - ), - ), - 15: Field( - name='max_speed', - type=BASE_TYPES[0x84], # uint16 - def_num=15, - components=( - ComponentField( - name='enhanced_max_speed', - def_num=125, - scale=1000, - units='m/s', - accumulate=False, - bits=16, - bit_offset=0, - ), - ), - ), - 16: Field( # average heart rate (excludes pause time) - name='avg_heart_rate', - type=BASE_TYPES[0x02], # uint8 - def_num=16, - units='bpm', - ), - 17: Field( - name='max_heart_rate', - type=BASE_TYPES[0x02], # uint8 - def_num=17, - units='bpm', - ), - 18: Field( # total_cycles / total_timer_time if non_zero_avg_cadence otherwise total_cycles / total_elapsed_time - name='avg_cadence', - type=BASE_TYPES[0x02], # uint8 - def_num=18, - units='rpm', - subfields=( - SubField( - name='avg_running_cadence', - def_num=18, - type=BASE_TYPES[0x02], # uint8 - units='strides/min', - ref_fields=( - ReferenceField( - name='sport', - def_num=5, - value='running', - raw_value=1, - ), - ), - ), - ), - ), - 19: Field( - name='max_cadence', - type=BASE_TYPES[0x02], # uint8 - def_num=19, - units='rpm', - subfields=( - SubField( - name='max_running_cadence', - def_num=19, - type=BASE_TYPES[0x02], # uint8 - units='strides/min', - ref_fields=( - ReferenceField( - name='sport', - def_num=5, - value='running', - raw_value=1, - ), - ), - ), - ), - ), - 20: Field( # total_power / total_timer_time if non_zero_avg_power otherwise total_power / total_elapsed_time - name='avg_power', - type=BASE_TYPES[0x84], # uint16 - def_num=20, - units='watts', - ), - 21: Field( - name='max_power', - type=BASE_TYPES[0x84], # uint16 - def_num=21, - units='watts', - ), - 22: Field( - name='total_ascent', - type=BASE_TYPES[0x84], # uint16 - def_num=22, - units='m', - ), - 23: Field( - name='total_descent', - type=BASE_TYPES[0x84], # uint16 - def_num=23, - units='m', - ), - 24: Field( - name='total_training_effect', - type=BASE_TYPES[0x02], # uint8 - def_num=24, - scale=10, - ), - 25: Field( - name='first_lap_index', - type=BASE_TYPES[0x84], # uint16 - def_num=25, - ), - 26: Field( - name='num_laps', - type=BASE_TYPES[0x84], # uint16 - def_num=26, - ), - 27: Field( - name='event_group', - type=BASE_TYPES[0x02], # uint8 - def_num=27, - ), - 28: Field( - name='trigger', - type=FIELD_TYPES['session_trigger'], - def_num=28, - ), - 29: Field( - name='nec_lat', - type=BASE_TYPES[0x85], # sint32 - def_num=29, - units='semicircles', - ), - 30: Field( - name='nec_long', - type=BASE_TYPES[0x85], # sint32 - def_num=30, - units='semicircles', - ), - 31: Field( - name='swc_lat', - type=BASE_TYPES[0x85], # sint32 - def_num=31, - units='semicircles', - ), - 32: Field( - name='swc_long', - type=BASE_TYPES[0x85], # sint32 - def_num=32, - units='semicircles', - ), - 34: Field( - name='normalized_power', - type=BASE_TYPES[0x84], # uint16 - def_num=34, - units='watts', - ), - 35: Field( - name='training_stress_score', - type=BASE_TYPES[0x84], # uint16 - def_num=35, - scale=10, - units='tss', - ), - 36: Field( - name='intensity_factor', - type=BASE_TYPES[0x84], # uint16 - def_num=36, - scale=1000, - units='if', - ), - 37: Field( - name='left_right_balance', - type=FIELD_TYPES['left_right_balance_100'], - def_num=37, - ), - 41: Field( - name='avg_stroke_count', - type=BASE_TYPES[0x86], # uint32 - def_num=41, - scale=10, - units='strokes/lap', - ), - 42: Field( - name='avg_stroke_distance', - type=BASE_TYPES[0x84], # uint16 - def_num=42, - scale=100, - units='m', - ), - 43: Field( - name='swim_stroke', - type=FIELD_TYPES['swim_stroke'], - def_num=43, - units='swim_stroke', - ), - 44: Field( - name='pool_length', - type=BASE_TYPES[0x84], # uint16 - def_num=44, - scale=100, - units='m', - ), - 45: Field( - name='threshold_power', - type=BASE_TYPES[0x84], # uint16 - def_num=45, - units='watts', - ), - 46: Field( - name='pool_length_unit', - type=FIELD_TYPES['display_measure'], - def_num=46, - ), - 47: Field( # # of active lengths of swim pool - name='num_active_lengths', - type=BASE_TYPES[0x84], # uint16 - def_num=47, - units='lengths', - ), - 48: Field( - name='total_work', - type=BASE_TYPES[0x86], # uint32 - def_num=48, - units='J', - ), - 49: Field( - name='avg_altitude', - type=BASE_TYPES[0x84], # uint16 - def_num=49, - components=( - ComponentField( - name='enhanced_avg_altitude', - def_num=126, - scale=5, - offset=500, - units='m', - accumulate=False, - bits=16, - bit_offset=0, - ), - ), - ), - 50: Field( - name='max_altitude', - type=BASE_TYPES[0x84], # uint16 - def_num=50, - components=( - ComponentField( - name='enhanced_max_altitude', - def_num=128, - scale=5, - offset=500, - units='m', - accumulate=False, - bits=16, - bit_offset=0, - ), - ), - ), - 51: Field( - name='gps_accuracy', - type=BASE_TYPES[0x02], # uint8 - def_num=51, - units='m', - ), - 52: Field( - name='avg_grade', - type=BASE_TYPES[0x83], # sint16 - def_num=52, - scale=100, - units='%', - ), - 53: Field( - name='avg_pos_grade', - type=BASE_TYPES[0x83], # sint16 - def_num=53, - scale=100, - units='%', - ), - 54: Field( - name='avg_neg_grade', - type=BASE_TYPES[0x83], # sint16 - def_num=54, - scale=100, - units='%', - ), - 55: Field( - name='max_pos_grade', - type=BASE_TYPES[0x83], # sint16 - def_num=55, - scale=100, - units='%', - ), - 56: Field( - name='max_neg_grade', - type=BASE_TYPES[0x83], # sint16 - def_num=56, - scale=100, - units='%', - ), - 57: Field( - name='avg_temperature', - type=BASE_TYPES[0x01], # sint8 - def_num=57, - units='C', - ), - 58: Field( - name='max_temperature', - type=BASE_TYPES[0x01], # sint8 - def_num=58, - units='C', - ), - 59: Field( - name='total_moving_time', - type=BASE_TYPES[0x86], # uint32 - def_num=59, - scale=1000, - units='s', - ), - 60: Field( - name='avg_pos_vertical_speed', - type=BASE_TYPES[0x83], # sint16 - def_num=60, - scale=1000, - units='m/s', - ), - 61: Field( - name='avg_neg_vertical_speed', - type=BASE_TYPES[0x83], # sint16 - def_num=61, - scale=1000, - units='m/s', - ), - 62: Field( - name='max_pos_vertical_speed', - type=BASE_TYPES[0x83], # sint16 - def_num=62, - scale=1000, - units='m/s', - ), - 63: Field( - name='max_neg_vertical_speed', - type=BASE_TYPES[0x83], # sint16 - def_num=63, - scale=1000, - units='m/s', - ), - 64: Field( - name='min_heart_rate', - type=BASE_TYPES[0x02], # uint8 - def_num=64, - units='bpm', - ), - 65: Field( - name='time_in_hr_zone', - type=BASE_TYPES[0x86], # uint32 - def_num=65, - scale=1000, - units='s', - ), - 66: Field( - name='time_in_speed_zone', - type=BASE_TYPES[0x86], # uint32 - def_num=66, - scale=1000, - units='s', - ), - 67: Field( - name='time_in_cadence_zone', - type=BASE_TYPES[0x86], # uint32 - def_num=67, - scale=1000, - units='s', - ), - 68: Field( - name='time_in_power_zone', - type=BASE_TYPES[0x86], # uint32 - def_num=68, - scale=1000, - units='s', - ), - 69: Field( - name='avg_lap_time', - type=BASE_TYPES[0x86], # uint32 - def_num=69, - scale=1000, - units='s', - ), - 70: Field( - name='best_lap_index', - type=BASE_TYPES[0x84], # uint16 - def_num=70, - ), - 71: Field( - name='min_altitude', - type=BASE_TYPES[0x84], # uint16 - def_num=71, - components=( - ComponentField( - name='enhanced_min_altitude', - def_num=127, - scale=5, - offset=500, - units='m', - accumulate=False, - bits=16, - bit_offset=0, - ), - ), - ), - 82: Field( - name='player_score', - type=BASE_TYPES[0x84], # uint16 - def_num=82, - ), - 83: Field( - name='opponent_score', - type=BASE_TYPES[0x84], # uint16 - def_num=83, - ), - 84: Field( - name='opponent_name', - type=BASE_TYPES[0x07], # string - def_num=84, - ), - 85: Field( # stroke_type enum used as the index - name='stroke_count', - type=BASE_TYPES[0x84], # uint16 - def_num=85, - units='counts', - ), - 86: Field( # zone number used as the index - name='zone_count', - type=BASE_TYPES[0x84], # uint16 - def_num=86, - units='counts', - ), - 87: Field( - name='max_ball_speed', - type=BASE_TYPES[0x84], # uint16 - def_num=87, - scale=100, - units='m/s', - ), - 88: Field( - name='avg_ball_speed', - type=BASE_TYPES[0x84], # uint16 - def_num=88, - scale=100, - units='m/s', - ), - 89: Field( - name='avg_vertical_oscillation', - type=BASE_TYPES[0x84], # uint16 - def_num=89, - scale=10, - units='mm', - ), - 90: Field( - name='avg_stance_time_percent', - type=BASE_TYPES[0x84], # uint16 - def_num=90, - scale=100, - units='percent', - ), - 91: Field( - name='avg_stance_time', - type=BASE_TYPES[0x84], # uint16 - def_num=91, - scale=10, - units='ms', - ), - 92: Field( # fractional part of the avg_cadence - name='avg_fractional_cadence', - type=BASE_TYPES[0x02], # uint8 - def_num=92, - scale=128, - units='rpm', - ), - 93: Field( # fractional part of the max_cadence - name='max_fractional_cadence', - type=BASE_TYPES[0x02], # uint8 - def_num=93, - scale=128, - units='rpm', - ), - 94: Field( # fractional part of the total_cycles - name='total_fractional_cycles', - type=BASE_TYPES[0x02], # uint8 - def_num=94, - scale=128, - units='cycles', - ), - 95: Field( # Avg saturated and unsaturated hemoglobin - name='avg_total_hemoglobin_conc', - type=BASE_TYPES[0x84], # uint16 - def_num=95, - scale=100, - units='g/dL', - ), - 96: Field( # Min saturated and unsaturated hemoglobin - name='min_total_hemoglobin_conc', - type=BASE_TYPES[0x84], # uint16 - def_num=96, - scale=100, - units='g/dL', - ), - 97: Field( # Max saturated and unsaturated hemoglobin - name='max_total_hemoglobin_conc', - type=BASE_TYPES[0x84], # uint16 - def_num=97, - scale=100, - units='g/dL', - ), - 98: Field( # Avg percentage of hemoglobin saturated with oxygen - name='avg_saturated_hemoglobin_percent', - type=BASE_TYPES[0x84], # uint16 - def_num=98, - scale=10, - units='%', - ), - 99: Field( # Min percentage of hemoglobin saturated with oxygen - name='min_saturated_hemoglobin_percent', - type=BASE_TYPES[0x84], # uint16 - def_num=99, - scale=10, - units='%', - ), - 100: Field( # Max percentage of hemoglobin saturated with oxygen - name='max_saturated_hemoglobin_percent', - type=BASE_TYPES[0x84], # uint16 - def_num=100, - scale=10, - units='%', - ), - 101: Field( - name='avg_left_torque_effectiveness', - type=BASE_TYPES[0x02], # uint8 - def_num=101, - scale=2, - units='percent', - ), - 102: Field( - name='avg_right_torque_effectiveness', - type=BASE_TYPES[0x02], # uint8 - def_num=102, - scale=2, - units='percent', - ), - 103: Field( - name='avg_left_pedal_smoothness', - type=BASE_TYPES[0x02], # uint8 - def_num=103, - scale=2, - units='percent', - ), - 104: Field( - name='avg_right_pedal_smoothness', - type=BASE_TYPES[0x02], # uint8 - def_num=104, - scale=2, - units='percent', - ), - 105: Field( - name='avg_combined_pedal_smoothness', - type=BASE_TYPES[0x02], # uint8 - def_num=105, - scale=2, - units='percent', - ), - 111: Field( - name='sport_index', - type=BASE_TYPES[0x02], # uint8 - def_num=111, - ), - 112: Field( # Total time spend in the standing position - name='time_standing', - type=BASE_TYPES[0x86], # uint32 - def_num=112, - scale=1000, - units='s', - ), - 113: Field( # Number of transitions to the standing state - name='stand_count', - type=BASE_TYPES[0x84], # uint16 - def_num=113, - ), - 114: Field( # Average platform center offset Left - name='avg_left_pco', - type=BASE_TYPES[0x01], # sint8 - def_num=114, - units='mm', - ), - 115: Field( # Average platform center offset Right - name='avg_right_pco', - type=BASE_TYPES[0x01], # sint8 - def_num=115, - units='mm', - ), - 116: Field( # Average left power phase angles. Indexes defined by power_phase_type. - name='avg_left_power_phase', - type=BASE_TYPES[0x02], # uint8 - def_num=116, - scale=0.7111111, - units='degrees', - ), - 117: 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=117, - scale=0.7111111, - units='degrees', - ), - 118: 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=118, - scale=0.7111111, - units='degrees', - ), - 119: 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=119, - scale=0.7111111, - units='degrees', - ), - 120: Field( # Average power by position. Data value indexes defined by rider_position_type. - name='avg_power_position', - type=BASE_TYPES[0x84], # uint16 - def_num=120, - units='watts', - ), - 121: Field( # Maximum power by position. Data value indexes defined by rider_position_type. - name='max_power_position', - type=BASE_TYPES[0x84], # uint16 - def_num=121, - units='watts', - ), - 122: Field( # Average cadence by position. Data value indexes defined by rider_position_type. - name='avg_cadence_position', - type=BASE_TYPES[0x02], # uint8 - def_num=122, - units='rpm', - ), - 123: Field( # Maximum cadence by position. Data value indexes defined by rider_position_type. - name='max_cadence_position', - type=BASE_TYPES[0x02], # uint8 - def_num=123, - units='rpm', - ), - 124: Field( # total_distance / total_timer_time - name='enhanced_avg_speed', - type=BASE_TYPES[0x86], # uint32 - def_num=124, - scale=1000, - units='m/s', - ), - 125: Field( - name='enhanced_max_speed', - type=BASE_TYPES[0x86], # uint32 - def_num=125, - scale=1000, - units='m/s', - ), - 126: Field( - name='enhanced_avg_altitude', - type=BASE_TYPES[0x86], # uint32 - def_num=126, - scale=5, - offset=500, - units='m', - ), - 127: Field( - name='enhanced_min_altitude', - type=BASE_TYPES[0x86], # uint32 - def_num=127, - scale=5, - offset=500, - units='m', - ), - 128: Field( - name='enhanced_max_altitude', - type=BASE_TYPES[0x86], # uint32 - def_num=128, - scale=5, - offset=500, - units='m', - ), - 129: Field( # lev average motor power during session - name='avg_lev_motor_power', - type=BASE_TYPES[0x84], # uint16 - def_num=129, - units='watts', - ), - 130: Field( # lev maximum motor power during session - name='max_lev_motor_power', - type=BASE_TYPES[0x84], # uint16 - def_num=130, - units='watts', - ), - 131: Field( # lev battery consumption during session - name='lev_battery_consumption', - type=BASE_TYPES[0x02], # uint8 - def_num=131, - scale=2, - units='percent', - ), - 132: Field( - name='avg_vertical_ratio', - type=BASE_TYPES[0x84], # uint16 - def_num=132, - scale=100, - units='percent', - ), - 133: Field( - name='avg_stance_time_balance', - type=BASE_TYPES[0x84], # uint16 - def_num=133, - scale=100, - units='percent', - ), - 134: Field( - name='avg_step_length', - type=BASE_TYPES[0x84], # uint16 - def_num=134, - scale=10, - units='mm', - ), - 137: Field( - name='total_anaerobic_training_effect', - type=BASE_TYPES[0x02], # uint8 - def_num=137, - scale=10, - ), - 139: Field( - name='avg_vam', - type=BASE_TYPES[0x84], # uint16 - def_num=139, - scale=1000, - units='m/s', - ), - 253: FIELD_TYPE_TIMESTAMP, # Sesson end time. - 254: Field( # Selected bit is set for the current session. - name='message_index', - type=FIELD_TYPES['message_index'], - def_num=254, - ), - }, - ), - 19: MessageType( - name='lap', - mesg_num=19, - 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='start_time', - type=FIELD_TYPES['date_time'], - def_num=2, - ), - 3: Field( - name='start_position_lat', - type=BASE_TYPES[0x85], # sint32 - def_num=3, - units='semicircles', - ), - 4: Field( - name='start_position_long', - type=BASE_TYPES[0x85], # sint32 - def_num=4, - units='semicircles', - ), - 5: Field( - name='end_position_lat', - type=BASE_TYPES[0x85], # sint32 - def_num=5, - units='semicircles', - ), - 6: Field( - name='end_position_long', - type=BASE_TYPES[0x85], # sint32 - def_num=6, - units='semicircles', - ), - 7: Field( # Time (includes pauses) - name='total_elapsed_time', - type=BASE_TYPES[0x86], # uint32 - def_num=7, - scale=1000, - units='s', - ), - 8: Field( # Timer Time (excludes pauses) - name='total_timer_time', - type=BASE_TYPES[0x86], # uint32 - def_num=8, - scale=1000, - units='s', - ), - 9: Field( - name='total_distance', - type=BASE_TYPES[0x86], # uint32 - def_num=9, - scale=100, - units='m', - ), - 10: Field( - name='total_cycles', - type=BASE_TYPES[0x86], # uint32 - def_num=10, - units='cycles', - subfields=( - SubField( - name='total_strides', - def_num=10, - type=BASE_TYPES[0x86], # uint32 - units='strides', - ref_fields=( - ReferenceField( - name='sport', - def_num=25, - value='running', - raw_value=1, - ), - ReferenceField( - name='sport', - def_num=25, - value='walking', - raw_value=11, - ), - ), - ), - ), - ), - 11: Field( - name='total_calories', - type=BASE_TYPES[0x84], # uint16 - def_num=11, - units='kcal', - ), - 12: Field( # If New Leaf - name='total_fat_calories', - type=BASE_TYPES[0x84], # uint16 - def_num=12, - units='kcal', - ), - 13: Field( - name='avg_speed', - type=BASE_TYPES[0x84], # uint16 - def_num=13, - components=( - ComponentField( - name='enhanced_avg_speed', - def_num=110, - scale=1000, - units='m/s', - accumulate=False, - bits=16, - bit_offset=0, - ), - ), - ), - 14: Field( - name='max_speed', - type=BASE_TYPES[0x84], # uint16 - def_num=14, - components=( - ComponentField( - name='enhanced_max_speed', - def_num=111, - scale=1000, - units='m/s', - accumulate=False, - bits=16, - bit_offset=0, - ), - ), - ), - 15: Field( - name='avg_heart_rate', - type=BASE_TYPES[0x02], # uint8 - def_num=15, - units='bpm', - ), - 16: Field( - name='max_heart_rate', - type=BASE_TYPES[0x02], # uint8 - def_num=16, - units='bpm', - ), - 17: Field( # total_cycles / total_timer_time if non_zero_avg_cadence otherwise total_cycles / total_elapsed_time - name='avg_cadence', - type=BASE_TYPES[0x02], # uint8 - def_num=17, - units='rpm', - subfields=( - SubField( - name='avg_running_cadence', - def_num=17, - type=BASE_TYPES[0x02], # uint8 - units='strides/min', - ref_fields=( - ReferenceField( - name='sport', - def_num=25, - value='running', - raw_value=1, - ), - ), - ), - ), - ), - 18: Field( - name='max_cadence', - type=BASE_TYPES[0x02], # uint8 - def_num=18, - units='rpm', - subfields=( - SubField( - name='max_running_cadence', - def_num=18, - type=BASE_TYPES[0x02], # uint8 - units='strides/min', - ref_fields=( - ReferenceField( - name='sport', - def_num=25, - value='running', - raw_value=1, - ), - ), - ), - ), - ), - 19: Field( # total_power / total_timer_time if non_zero_avg_power otherwise total_power / total_elapsed_time - name='avg_power', - type=BASE_TYPES[0x84], # uint16 - def_num=19, - units='watts', - ), - 20: Field( - name='max_power', - type=BASE_TYPES[0x84], # uint16 - def_num=20, - units='watts', - ), - 21: Field( - name='total_ascent', - type=BASE_TYPES[0x84], # uint16 - def_num=21, - units='m', - ), - 22: Field( - name='total_descent', - type=BASE_TYPES[0x84], # uint16 - def_num=22, - units='m', - ), - 23: Field( - name='intensity', - type=FIELD_TYPES['intensity'], - def_num=23, - ), - 24: Field( - name='lap_trigger', - type=FIELD_TYPES['lap_trigger'], - def_num=24, - ), - 25: Field( - name='sport', - type=FIELD_TYPES['sport'], - def_num=25, - ), - 26: Field( - name='event_group', - type=BASE_TYPES[0x02], # uint8 - def_num=26, - ), - 32: Field( # # of lengths of swim pool - name='num_lengths', - type=BASE_TYPES[0x84], # uint16 - def_num=32, - units='lengths', - ), - 33: Field( - name='normalized_power', - type=BASE_TYPES[0x84], # uint16 - def_num=33, - units='watts', - ), - 34: Field( - name='left_right_balance', - type=FIELD_TYPES['left_right_balance_100'], - def_num=34, - ), - 35: Field( - name='first_length_index', - type=BASE_TYPES[0x84], # uint16 - def_num=35, - ), - 37: Field( - name='avg_stroke_distance', - type=BASE_TYPES[0x84], # uint16 - def_num=37, - scale=100, - units='m', - ), - 38: Field( - name='swim_stroke', - type=FIELD_TYPES['swim_stroke'], - def_num=38, - ), - 39: Field( - name='sub_sport', - type=FIELD_TYPES['sub_sport'], - def_num=39, - ), - 40: Field( # # of active lengths of swim pool - name='num_active_lengths', - type=BASE_TYPES[0x84], # uint16 - def_num=40, - units='lengths', - ), - 41: Field( - name='total_work', - type=BASE_TYPES[0x86], # uint32 - def_num=41, - units='J', - ), - 42: Field( - name='avg_altitude', - type=BASE_TYPES[0x84], # uint16 - def_num=42, - components=( - ComponentField( - name='enhanced_avg_altitude', - def_num=112, - scale=5, - offset=500, - units='m', - accumulate=False, - bits=16, - bit_offset=0, - ), - ), - ), - 43: Field( - name='max_altitude', - type=BASE_TYPES[0x84], # uint16 - def_num=43, - components=( - ComponentField( - name='enhanced_max_altitude', - def_num=114, - scale=5, - offset=500, - units='m', - accumulate=False, - bits=16, - bit_offset=0, - ), - ), - ), - 44: Field( - name='gps_accuracy', - type=BASE_TYPES[0x02], # uint8 - def_num=44, - units='m', - ), - 45: Field( - name='avg_grade', - type=BASE_TYPES[0x83], # sint16 - def_num=45, - scale=100, - units='%', - ), - 46: Field( - name='avg_pos_grade', - type=BASE_TYPES[0x83], # sint16 - def_num=46, - scale=100, - units='%', - ), - 47: Field( - name='avg_neg_grade', - type=BASE_TYPES[0x83], # sint16 - def_num=47, - scale=100, - units='%', - ), - 48: Field( - name='max_pos_grade', - type=BASE_TYPES[0x83], # sint16 - def_num=48, - scale=100, - units='%', - ), - 49: Field( - name='max_neg_grade', - type=BASE_TYPES[0x83], # sint16 - def_num=49, - scale=100, - units='%', - ), - 50: Field( - name='avg_temperature', - type=BASE_TYPES[0x01], # sint8 - def_num=50, - units='C', - ), - 51: Field( - name='max_temperature', - type=BASE_TYPES[0x01], # sint8 - def_num=51, - units='C', - ), - 52: Field( - name='total_moving_time', - type=BASE_TYPES[0x86], # uint32 - def_num=52, - scale=1000, - units='s', - ), - 53: Field( - name='avg_pos_vertical_speed', - type=BASE_TYPES[0x83], # sint16 - def_num=53, - scale=1000, - units='m/s', - ), - 54: Field( - name='avg_neg_vertical_speed', - type=BASE_TYPES[0x83], # sint16 - def_num=54, - scale=1000, - units='m/s', - ), - 55: Field( - name='max_pos_vertical_speed', - type=BASE_TYPES[0x83], # sint16 - def_num=55, - scale=1000, - units='m/s', - ), - 56: Field( - name='max_neg_vertical_speed', - type=BASE_TYPES[0x83], # sint16 - def_num=56, - scale=1000, - units='m/s', - ), - 57: Field( - name='time_in_hr_zone', - type=BASE_TYPES[0x86], # uint32 - def_num=57, - scale=1000, - units='s', - ), - 58: Field( - name='time_in_speed_zone', - type=BASE_TYPES[0x86], # uint32 - def_num=58, - scale=1000, - units='s', - ), - 59: Field( - name='time_in_cadence_zone', - type=BASE_TYPES[0x86], # uint32 - def_num=59, - scale=1000, - units='s', - ), - 60: Field( - name='time_in_power_zone', - type=BASE_TYPES[0x86], # uint32 - def_num=60, - scale=1000, - units='s', - ), - 61: Field( - name='repetition_num', - type=BASE_TYPES[0x84], # uint16 - def_num=61, - ), - 62: Field( - name='min_altitude', - type=BASE_TYPES[0x84], # uint16 - def_num=62, - components=( - ComponentField( - name='enhanced_min_altitude', - def_num=113, - scale=5, - offset=500, - units='m', - accumulate=False, - bits=16, - bit_offset=0, - ), - ), - ), - 63: Field( - name='min_heart_rate', - type=BASE_TYPES[0x02], # uint8 - def_num=63, - units='bpm', - ), - 71: Field( - name='wkt_step_index', - type=FIELD_TYPES['message_index'], - def_num=71, - ), - 74: Field( - name='opponent_score', - type=BASE_TYPES[0x84], # uint16 - def_num=74, - ), - 75: Field( # stroke_type enum used as the index - name='stroke_count', - type=BASE_TYPES[0x84], # uint16 - def_num=75, - units='counts', - ), - 76: Field( # zone number used as the index - name='zone_count', - type=BASE_TYPES[0x84], # uint16 - def_num=76, - units='counts', - ), - 77: Field( - name='avg_vertical_oscillation', - type=BASE_TYPES[0x84], # uint16 - def_num=77, - scale=10, - units='mm', - ), - 78: Field( - name='avg_stance_time_percent', - type=BASE_TYPES[0x84], # uint16 - def_num=78, - scale=100, - units='percent', - ), - 79: Field( - name='avg_stance_time', - type=BASE_TYPES[0x84], # uint16 - def_num=79, - scale=10, - units='ms', - ), - 80: Field( # fractional part of the avg_cadence - name='avg_fractional_cadence', - type=BASE_TYPES[0x02], # uint8 - def_num=80, - scale=128, - units='rpm', - ), - 81: Field( # fractional part of the max_cadence - name='max_fractional_cadence', - type=BASE_TYPES[0x02], # uint8 - def_num=81, - scale=128, - units='rpm', - ), - 82: Field( # fractional part of the total_cycles - name='total_fractional_cycles', - type=BASE_TYPES[0x02], # uint8 - def_num=82, - scale=128, - units='cycles', - ), - 83: Field( - name='player_score', - type=BASE_TYPES[0x84], # uint16 - def_num=83, - ), - 84: Field( # Avg saturated and unsaturated hemoglobin - name='avg_total_hemoglobin_conc', - type=BASE_TYPES[0x84], # uint16 - def_num=84, - scale=100, - units='g/dL', - ), - 85: Field( # Min saturated and unsaturated hemoglobin - name='min_total_hemoglobin_conc', - type=BASE_TYPES[0x84], # uint16 - def_num=85, - scale=100, - units='g/dL', - ), - 86: Field( # Max saturated and unsaturated hemoglobin - name='max_total_hemoglobin_conc', - type=BASE_TYPES[0x84], # uint16 - def_num=86, - scale=100, - units='g/dL', - ), - 87: Field( # Avg percentage of hemoglobin saturated with oxygen - name='avg_saturated_hemoglobin_percent', - type=BASE_TYPES[0x84], # uint16 - def_num=87, - scale=10, - units='%', - ), - 88: Field( # Min percentage of hemoglobin saturated with oxygen - name='min_saturated_hemoglobin_percent', - type=BASE_TYPES[0x84], # uint16 - def_num=88, - scale=10, - units='%', - ), - 89: Field( # Max percentage of hemoglobin saturated with oxygen - name='max_saturated_hemoglobin_percent', - type=BASE_TYPES[0x84], # uint16 - def_num=89, - scale=10, - units='%', - ), - 91: Field( - name='avg_left_torque_effectiveness', - type=BASE_TYPES[0x02], # uint8 - def_num=91, - scale=2, - units='percent', - ), - 92: Field( - name='avg_right_torque_effectiveness', - type=BASE_TYPES[0x02], # uint8 - def_num=92, - scale=2, - units='percent', - ), - 93: Field( - name='avg_left_pedal_smoothness', - type=BASE_TYPES[0x02], # uint8 - def_num=93, - scale=2, - units='percent', - ), - 94: Field( - name='avg_right_pedal_smoothness', - type=BASE_TYPES[0x02], # uint8 - def_num=94, - scale=2, - units='percent', - ), - 95: Field( - name='avg_combined_pedal_smoothness', - type=BASE_TYPES[0x02], # uint8 - def_num=95, - scale=2, - units='percent', - ), - 98: Field( # Total time spent in the standing position - name='time_standing', - type=BASE_TYPES[0x86], # uint32 - def_num=98, - scale=1000, - units='s', - ), - 99: Field( # Number of transitions to the standing state - name='stand_count', - type=BASE_TYPES[0x84], # uint16 - def_num=99, - ), - 100: Field( # Average left platform center offset - name='avg_left_pco', - type=BASE_TYPES[0x01], # sint8 - def_num=100, - units='mm', - ), - 101: Field( # Average right platform center offset - name='avg_right_pco', - type=BASE_TYPES[0x01], # sint8 - def_num=101, - units='mm', - ), - 102: 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=102, - scale=0.7111111, - units='degrees', - ), - 103: 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=103, - scale=0.7111111, - units='degrees', - ), - 104: 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=104, - scale=0.7111111, - units='degrees', - ), - 105: 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=105, - scale=0.7111111, - units='degrees', - ), - 106: Field( # Average power by position. Data value indexes defined by rider_position_type. - name='avg_power_position', - type=BASE_TYPES[0x84], # uint16 - def_num=106, - units='watts', - ), - 107: Field( # Maximum power by position. Data value indexes defined by rider_position_type. - name='max_power_position', - type=BASE_TYPES[0x84], # uint16 - def_num=107, - units='watts', - ), - 108: Field( # Average cadence by position. Data value indexes defined by rider_position_type. - name='avg_cadence_position', - type=BASE_TYPES[0x02], # uint8 - def_num=108, - units='rpm', - ), - 109: Field( # Maximum cadence by position. Data value indexes defined by rider_position_type. - name='max_cadence_position', - type=BASE_TYPES[0x02], # uint8 - def_num=109, - units='rpm', - ), - 110: Field( - name='enhanced_avg_speed', - type=BASE_TYPES[0x86], # uint32 - def_num=110, - scale=1000, - units='m/s', - ), - 111: Field( - name='enhanced_max_speed', - type=BASE_TYPES[0x86], # uint32 - def_num=111, - scale=1000, - units='m/s', - ), - 112: Field( - name='enhanced_avg_altitude', - type=BASE_TYPES[0x86], # uint32 - def_num=112, - scale=5, - offset=500, - units='m', - ), - 113: Field( - name='enhanced_min_altitude', - type=BASE_TYPES[0x86], # uint32 - def_num=113, - scale=5, - offset=500, - units='m', - ), - 114: Field( - name='enhanced_max_altitude', - type=BASE_TYPES[0x86], # uint32 - def_num=114, - scale=5, - offset=500, - units='m', - ), - 115: Field( # lev average motor power during lap - name='avg_lev_motor_power', - type=BASE_TYPES[0x84], # uint16 - def_num=115, - units='watts', - ), - 116: Field( # lev maximum motor power during lap - name='max_lev_motor_power', - type=BASE_TYPES[0x84], # uint16 - def_num=116, - units='watts', - ), - 117: Field( # lev battery consumption during lap - name='lev_battery_consumption', - type=BASE_TYPES[0x02], # uint8 - def_num=117, - scale=2, - units='percent', - ), - 118: Field( - name='avg_vertical_ratio', - type=BASE_TYPES[0x84], # uint16 - def_num=118, - scale=100, - units='percent', - ), - 119: Field( - name='avg_stance_time_balance', - type=BASE_TYPES[0x84], # uint16 - def_num=119, - scale=100, - units='percent', - ), - 120: Field( - name='avg_step_length', - type=BASE_TYPES[0x84], # uint16 - def_num=120, - scale=10, - units='mm', - ), - 121: Field( - name='avg_vam', - type=BASE_TYPES[0x84], # uint16 - def_num=121, - scale=1000, - units='m/s', - ), - 253: FIELD_TYPE_TIMESTAMP, # Lap end time. - 254: Field( - name='message_index', - type=FIELD_TYPES['message_index'], - def_num=254, - ), - }, - ), - 20: MessageType( - name='record', - mesg_num=20, - fields={ - 0: Field( - name='position_lat', - type=BASE_TYPES[0x85], # sint32 - def_num=0, - units='semicircles', - ), - 1: Field( - name='position_long', - type=BASE_TYPES[0x85], # sint32 - def_num=1, - units='semicircles', - ), - 2: Field( - name='altitude', - type=BASE_TYPES[0x84], # uint16 - def_num=2, - components=( - ComponentField( - name='enhanced_altitude', - def_num=78, - scale=5, - offset=500, - units='m', - accumulate=False, - bits=16, - bit_offset=0, - ), - ), - ), - 3: Field( - name='heart_rate', - type=BASE_TYPES[0x02], # uint8 - def_num=3, - units='bpm', - ), - 4: Field( - name='cadence', - type=BASE_TYPES[0x02], # uint8 - def_num=4, - units='rpm', - ), - 5: Field( - name='distance', - type=BASE_TYPES[0x86], # uint32 - def_num=5, - scale=100, - units='m', - ), - 6: Field( - name='speed', - type=BASE_TYPES[0x84], # uint16 - def_num=6, - components=( - ComponentField( - name='enhanced_speed', - def_num=73, - scale=1000, - units='m/s', - accumulate=False, - bits=16, - bit_offset=0, - ), - ), - ), - 7: Field( - name='power', - type=BASE_TYPES[0x84], # uint16 - def_num=7, - units='watts', - ), - 8: Field( - name='compressed_speed_distance', - type=BASE_TYPES[0x0D], # byte - def_num=8, - components=( - ComponentField( - name='speed', - def_num=6, - scale=100, - units='m/s', - accumulate=False, - bits=12, - bit_offset=0, - ), - ComponentField( - name='distance', - def_num=5, - scale=16, - units='m', - accumulate=True, - bits=12, - bit_offset=12, - ), - ), - ), - 9: Field( - name='grade', - type=BASE_TYPES[0x83], # sint16 - def_num=9, - scale=100, - units='%', - ), - 10: Field( # Relative. 0 is none 254 is Max. - name='resistance', - type=BASE_TYPES[0x02], # uint8 - def_num=10, - ), - 11: Field( - name='time_from_course', - type=BASE_TYPES[0x85], # sint32 - def_num=11, - scale=1000, - units='s', - ), - 12: Field( - name='cycle_length', - type=BASE_TYPES[0x02], # uint8 - def_num=12, - scale=100, - units='m', - ), - 13: Field( - name='temperature', - type=BASE_TYPES[0x01], # sint8 - def_num=13, - units='C', - ), - 17: Field( # Speed at 1s intervals. Timestamp field indicates time of last array element. - name='speed_1s', - type=BASE_TYPES[0x02], # uint8 - def_num=17, - scale=16, - units='m/s', - ), - 18: Field( - name='cycles', - type=BASE_TYPES[0x02], # uint8 - def_num=18, - components=( - ComponentField( - name='total_cycles', - def_num=19, - units='cycles', - accumulate=True, - bits=8, - bit_offset=0, - ), - ), - ), - 19: Field( - name='total_cycles', - type=BASE_TYPES[0x86], # uint32 - def_num=19, - units='cycles', - ), - 28: Field( - name='compressed_accumulated_power', - type=BASE_TYPES[0x84], # uint16 - def_num=28, - components=( - ComponentField( - name='accumulated_power', - def_num=29, - units='watts', - accumulate=True, - bits=16, - bit_offset=0, - ), - ), - ), - 29: Field( - name='accumulated_power', - type=BASE_TYPES[0x86], # uint32 - def_num=29, - units='watts', - ), - 30: Field( - name='left_right_balance', - type=FIELD_TYPES['left_right_balance'], - def_num=30, - ), - 31: Field( - name='gps_accuracy', - type=BASE_TYPES[0x02], # uint8 - def_num=31, - units='m', - ), - 32: Field( - name='vertical_speed', - type=BASE_TYPES[0x83], # sint16 - def_num=32, - scale=1000, - units='m/s', - ), - 33: Field( - name='calories', - type=BASE_TYPES[0x84], # uint16 - def_num=33, - units='kcal', - ), - 39: Field( - name='vertical_oscillation', - type=BASE_TYPES[0x84], # uint16 - def_num=39, - scale=10, - units='mm', - ), - 40: Field( - name='stance_time_percent', - type=BASE_TYPES[0x84], # uint16 - def_num=40, - scale=100, - units='percent', - ), - 41: Field( - name='stance_time', - type=BASE_TYPES[0x84], # uint16 - def_num=41, - scale=10, - units='ms', - ), - 42: Field( - name='activity_type', - type=FIELD_TYPES['activity_type'], - def_num=42, - ), - 43: Field( - name='left_torque_effectiveness', - type=BASE_TYPES[0x02], # uint8 - def_num=43, - scale=2, - units='percent', - ), - 44: Field( - name='right_torque_effectiveness', - type=BASE_TYPES[0x02], # uint8 - def_num=44, - scale=2, - units='percent', - ), - 45: Field( - name='left_pedal_smoothness', - type=BASE_TYPES[0x02], # uint8 - def_num=45, - scale=2, - units='percent', - ), - 46: Field( - name='right_pedal_smoothness', - type=BASE_TYPES[0x02], # uint8 - def_num=46, - scale=2, - units='percent', - ), - 47: Field( - name='combined_pedal_smoothness', - type=BASE_TYPES[0x02], # uint8 - def_num=47, - scale=2, - units='percent', - ), - 48: Field( - name='time128', - type=BASE_TYPES[0x02], # uint8 - def_num=48, - scale=128, - units='s', - ), - 49: Field( - name='stroke_type', - type=FIELD_TYPES['stroke_type'], - def_num=49, - ), - 50: Field( - name='zone', - type=BASE_TYPES[0x02], # uint8 - def_num=50, - ), - 51: Field( - name='ball_speed', - type=BASE_TYPES[0x84], # uint16 - def_num=51, - scale=100, - units='m/s', - ), - 52: Field( # Log cadence and fractional cadence for backwards compatability - name='cadence256', - type=BASE_TYPES[0x84], # uint16 - def_num=52, - scale=256, - units='rpm', - ), - 53: Field( - name='fractional_cadence', - type=BASE_TYPES[0x02], # uint8 - def_num=53, - scale=128, - units='rpm', - ), - 54: Field( # Total saturated and unsaturated hemoglobin - name='total_hemoglobin_conc', - type=BASE_TYPES[0x84], # uint16 - def_num=54, - scale=100, - units='g/dL', - ), - 55: Field( # Min saturated and unsaturated hemoglobin - name='total_hemoglobin_conc_min', - type=BASE_TYPES[0x84], # uint16 - def_num=55, - scale=100, - units='g/dL', - ), - 56: Field( # Max saturated and unsaturated hemoglobin - name='total_hemoglobin_conc_max', - type=BASE_TYPES[0x84], # uint16 - def_num=56, - scale=100, - units='g/dL', - ), - 57: Field( # Percentage of hemoglobin saturated with oxygen - name='saturated_hemoglobin_percent', - type=BASE_TYPES[0x84], # uint16 - def_num=57, - scale=10, - units='%', - ), - 58: Field( # Min percentage of hemoglobin saturated with oxygen - name='saturated_hemoglobin_percent_min', - type=BASE_TYPES[0x84], # uint16 - def_num=58, - scale=10, - units='%', - ), - 59: Field( # Max percentage of hemoglobin saturated with oxygen - name='saturated_hemoglobin_percent_max', - type=BASE_TYPES[0x84], # uint16 - def_num=59, - scale=10, - units='%', - ), - 62: Field( - name='device_index', - type=FIELD_TYPES['device_index'], - def_num=62, - ), - 67: Field( # Left platform center offset - name='left_pco', - type=BASE_TYPES[0x01], # sint8 - def_num=67, - units='mm', - ), - 68: Field( # Right platform center offset - name='right_pco', - type=BASE_TYPES[0x01], # sint8 - def_num=68, - units='mm', - ), - 69: Field( # Left power phase angles. Data value indexes defined by power_phase_type. - name='left_power_phase', - type=BASE_TYPES[0x02], # uint8 - def_num=69, - scale=0.7111111, - units='degrees', - ), - 70: Field( # Left power phase peak angles. Data value indexes defined by power_phase_type. - name='left_power_phase_peak', - type=BASE_TYPES[0x02], # uint8 - def_num=70, - scale=0.7111111, - units='degrees', - ), - 71: Field( # Right power phase angles. Data value indexes defined by power_phase_type. - name='right_power_phase', - type=BASE_TYPES[0x02], # uint8 - def_num=71, - scale=0.7111111, - units='degrees', - ), - 72: Field( # Right power phase peak angles. Data value indexes defined by power_phase_type. - name='right_power_phase_peak', - type=BASE_TYPES[0x02], # uint8 - def_num=72, - scale=0.7111111, - units='degrees', - ), - 73: Field( - name='enhanced_speed', - type=BASE_TYPES[0x86], # uint32 - def_num=73, - scale=1000, - units='m/s', - ), - 78: Field( - name='enhanced_altitude', - type=BASE_TYPES[0x86], # uint32 - def_num=78, - scale=5, - offset=500, - units='m', - ), - 81: Field( # lev battery state of charge - name='battery_soc', - type=BASE_TYPES[0x02], # uint8 - def_num=81, - scale=2, - units='percent', - ), - 82: Field( # lev motor power - name='motor_power', - type=BASE_TYPES[0x84], # uint16 - def_num=82, - units='watts', - ), - 83: Field( - name='vertical_ratio', - type=BASE_TYPES[0x84], # uint16 - def_num=83, - scale=100, - units='percent', - ), - 84: Field( - name='stance_time_balance', - type=BASE_TYPES[0x84], # uint16 - def_num=84, - scale=100, - units='percent', - ), - 85: Field( - name='step_length', - type=BASE_TYPES[0x84], # uint16 - def_num=85, - scale=10, - units='mm', - ), - 91: Field( # Includes atmospheric pressure - name='absolute_pressure', - type=BASE_TYPES[0x86], # uint32 - def_num=91, - units='Pa', - ), - 92: Field( # 0 if above water - name='depth', - type=BASE_TYPES[0x86], # uint32 - def_num=92, - scale=1000, - units='m', - ), - 93: Field( # 0 if above water - name='next_stop_depth', - type=BASE_TYPES[0x86], # uint32 - def_num=93, - scale=1000, - units='m', - ), - 94: Field( - name='next_stop_time', - type=BASE_TYPES[0x86], # uint32 - def_num=94, - units='s', - ), - 95: Field( - name='time_to_surface', - type=BASE_TYPES[0x86], # uint32 - def_num=95, - units='s', - ), - 96: Field( - name='ndl_time', - type=BASE_TYPES[0x86], # uint32 - def_num=96, - units='s', - ), - 97: Field( - name='cns_load', - type=BASE_TYPES[0x02], # uint8 - def_num=97, - units='percent', - ), - 98: Field( - name='n2_load', - type=BASE_TYPES[0x84], # uint16 - 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, - ), - 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, - bits=16, - bit_offset=0, - ), - ), - ), - 3: Field( - name='data', - type=BASE_TYPES[0x86], # uint32 - def_num=3, - subfields=( - SubField( - name='battery_level', - def_num=3, - type=BASE_TYPES[0x84], # uint16 - scale=1000, - units='V', - ref_fields=( - ReferenceField( - name='event', - def_num=0, - value='battery', - raw_value=11, - ), - ), - ), - SubField( - name='cad_high_alert', - def_num=3, - type=BASE_TYPES[0x84], # uint16 - units='rpm', - ref_fields=( - ReferenceField( - name='event', - def_num=0, - value='cad_high_alert', - raw_value=17, - ), - ), - ), - SubField( - name='cad_low_alert', - def_num=3, - type=BASE_TYPES[0x84], # uint16 - units='rpm', - ref_fields=( - ReferenceField( - name='event', - def_num=0, - value='cad_low_alert', - raw_value=18, - ), - ), - ), - SubField( - name='calorie_duration_alert', - def_num=3, - type=BASE_TYPES[0x86], # uint32 - units='calories', - ref_fields=( - ReferenceField( - name='event', - def_num=0, - value='calorie_duration_alert', - raw_value=25, - ), - ), - ), - SubField( - name='comm_timeout', - def_num=3, - type=FIELD_TYPES['comm_timeout_type'], - ref_fields=( - ReferenceField( - name='event', - def_num=0, - value='comm_timeout', - raw_value=47, - ), - ), - ), - SubField( - name='course_point_index', - def_num=3, - type=FIELD_TYPES['message_index'], - ref_fields=( - ReferenceField( - name='event', - def_num=0, - value='course_point', - raw_value=10, - ), - ), - ), - SubField( - name='distance_duration_alert', - def_num=3, - type=BASE_TYPES[0x86], # uint32 - scale=100, - units='m', - ref_fields=( - ReferenceField( - name='event', - def_num=0, - value='distance_duration_alert', - raw_value=24, - ), - ), - ), - SubField( - name='fitness_equipment_state', - def_num=3, - type=FIELD_TYPES['fitness_equipment_state'], - ref_fields=( - ReferenceField( - name='event', - def_num=0, - value='fitness_equipment', - raw_value=27, - ), - ), - ), - SubField( - name='gear_change_data', - def_num=3, - type=BASE_TYPES[0x86], # uint32 - ref_fields=( - ReferenceField( - name='event', - def_num=0, - value='front_gear_change', - raw_value=42, - ), - ReferenceField( - name='event', - def_num=0, - value='rear_gear_change', - raw_value=43, - ), - ), - components=( - ComponentField( - name='rear_gear_num', - def_num=11, - accumulate=False, - bits=8, - bit_offset=0, - ), - ComponentField( - name='rear_gear', - def_num=12, - accumulate=False, - bits=8, - bit_offset=8, - ), - ComponentField( - name='front_gear_num', - def_num=9, - accumulate=False, - bits=8, - bit_offset=16, - ), - ComponentField( - name='front_gear', - def_num=10, - accumulate=False, - bits=8, - bit_offset=24, - ), - ), - ), - SubField( - name='hr_high_alert', - def_num=3, - type=BASE_TYPES[0x02], # uint8 - units='bpm', - ref_fields=( - ReferenceField( - name='event', - def_num=0, - value='hr_high_alert', - raw_value=13, - ), - ), - ), - SubField( - name='hr_low_alert', - def_num=3, - type=BASE_TYPES[0x02], # uint8 - units='bpm', - ref_fields=( - ReferenceField( - name='event', - def_num=0, - value='hr_low_alert', - raw_value=14, - ), - ), - ), - SubField( - name='power_high_alert', - def_num=3, - type=BASE_TYPES[0x84], # uint16 - units='watts', - ref_fields=( - ReferenceField( - name='event', - def_num=0, - value='power_high_alert', - raw_value=19, - ), - ), - ), - SubField( - name='power_low_alert', - def_num=3, - type=BASE_TYPES[0x84], # uint16 - units='watts', - ref_fields=( - ReferenceField( - name='event', - def_num=0, - value='power_low_alert', - raw_value=20, - ), - ), - ), - SubField( # Indicates the rider position value. - name='rider_position', - def_num=3, - type=FIELD_TYPES['rider_position_type'], - ref_fields=( - ReferenceField( - name='event', - def_num=0, - value='rider_position_change', - raw_value=44, - ), - ), - ), - SubField( - name='speed_high_alert', - def_num=3, - type=BASE_TYPES[0x86], # uint32 - scale=1000, - units='m/s', - ref_fields=( - ReferenceField( - name='event', - def_num=0, - value='speed_high_alert', - raw_value=15, - ), - ), - ), - SubField( - name='speed_low_alert', - def_num=3, - type=BASE_TYPES[0x86], # uint32 - scale=1000, - units='m/s', - ref_fields=( - ReferenceField( - name='event', - def_num=0, - value='speed_low_alert', - raw_value=16, - ), - ), - ), - SubField( - name='sport_point', - def_num=3, - type=BASE_TYPES[0x86], # uint32 - ref_fields=( - ReferenceField( - name='event', - def_num=0, - value='sport_point', - raw_value=33, - ), - ), - components=( - ComponentField( - name='score', - def_num=7, - accumulate=False, - bits=16, - bit_offset=0, - ), - ComponentField( - name='opponent_score', - def_num=8, - accumulate=False, - bits=16, - bit_offset=16, - ), - ), - ), - SubField( - name='time_duration_alert', - def_num=3, - type=BASE_TYPES[0x86], # uint32 - scale=1000, - units='s', - ref_fields=( - ReferenceField( - name='event', - def_num=0, - value='time_duration_alert', - raw_value=23, - ), - ), - ), - SubField( - name='timer_trigger', - def_num=3, - type=FIELD_TYPES['timer_trigger'], - ref_fields=( - ReferenceField( - name='event', - def_num=0, - value='timer', - raw_value=0, - ), - ), - ), - SubField( - name='virtual_partner_speed', - def_num=3, - type=BASE_TYPES[0x84], # uint16 - scale=1000, - units='m/s', - ref_fields=( - ReferenceField( - name='event', - def_num=0, - value='virtual_partner_pace', - raw_value=12, - ), - ), - ), - ), - ), - 4: Field( - name='event_group', - type=BASE_TYPES[0x02], # uint8 - def_num=4, - ), - 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 - 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. - 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. - 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. - 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. - name='rear_gear', - type=BASE_TYPES[0x0A], # uint8z - def_num=12, - ), - 13: Field( - name='device_index', - type=FIELD_TYPES['device_index'], - def_num=13, - ), - 253: FIELD_TYPE_TIMESTAMP, - }, - ), - 23: MessageType( - name='device_info', - mesg_num=23, - fields={ - 0: Field( - name='device_index', - type=FIELD_TYPES['device_index'], - def_num=0, - ), - 1: Field( - name='device_type', - type=BASE_TYPES[0x02], # uint8 - def_num=1, - subfields=( - SubField( - name='ant_device_type', - def_num=1, - type=BASE_TYPES[0x02], # uint8 - ref_fields=( - ReferenceField( - name='source_type', - def_num=25, - value='ant', - raw_value=0, - ), - ), - ), - SubField( - name='antplus_device_type', - def_num=1, - type=FIELD_TYPES['antplus_device_type'], - ref_fields=( - ReferenceField( - name='source_type', - def_num=25, - value='antplus', - raw_value=1, - ), - ), - ), - ), - ), - 2: Field( - name='manufacturer', - type=FIELD_TYPES['manufacturer'], - def_num=2, - ), - 3: Field( - name='serial_number', - type=BASE_TYPES[0x8C], # uint32z - def_num=3, - ), - 4: Field( - name='product', - type=BASE_TYPES[0x84], # uint16 - def_num=4, - subfields=( - SubField( - name='garmin_product', - def_num=4, - type=FIELD_TYPES['garmin_product'], - ref_fields=( - ReferenceField( - name='manufacturer', - def_num=2, - value='garmin', - raw_value=1, - ), - ReferenceField( - name='manufacturer', - def_num=2, - value='dynastream', - raw_value=15, - ), - ReferenceField( - name='manufacturer', - def_num=2, - value='dynastream_oem', - raw_value=13, - ), - ), - ), - ), - ), - 5: Field( - name='software_version', - type=BASE_TYPES[0x84], # uint16 - def_num=5, - scale=100, - ), - 6: Field( - name='hardware_version', - type=BASE_TYPES[0x02], # uint8 - def_num=6, - ), - 7: Field( # Reset by new battery or charge. - name='cum_operating_time', - type=BASE_TYPES[0x86], # uint32 - def_num=7, - units='s', - ), - 10: Field( - name='battery_voltage', - type=BASE_TYPES[0x84], # uint16 - def_num=10, - scale=256, - units='V', - ), - 11: Field( - name='battery_status', - type=FIELD_TYPES['battery_status'], - def_num=11, - ), - 18: Field( # Indicates the location of the sensor - name='sensor_position', - type=FIELD_TYPES['body_location'], - def_num=18, - ), - 19: Field( # Used to describe the sensor or location - name='descriptor', - type=BASE_TYPES[0x07], # string - def_num=19, - ), - 20: Field( - name='ant_transmission_type', - type=BASE_TYPES[0x0A], # uint8z - def_num=20, - ), - 21: Field( - name='ant_device_number', - type=BASE_TYPES[0x8B], # uint16z - def_num=21, - ), - 22: Field( - name='ant_network', - type=FIELD_TYPES['ant_network'], - def_num=22, - ), - 25: Field( - name='source_type', - type=FIELD_TYPES['source_type'], - def_num=25, - ), - 27: Field( # Optional free form string to indicate the devices name or model - name='product_name', - type=BASE_TYPES[0x07], # string - def_num=27, - ), - 253: FIELD_TYPE_TIMESTAMP, - }, - ), - 27: MessageType( - name='workout_step', - mesg_num=27, - fields={ - 0: Field( - name='wkt_step_name', - type=BASE_TYPES[0x07], # string - def_num=0, - ), - 1: Field( - name='duration_type', - type=FIELD_TYPES['wkt_step_duration'], - def_num=1, - ), - 2: Field( - name='duration_value', - type=BASE_TYPES[0x86], # uint32 - def_num=2, - subfields=( - SubField( - name='duration_calories', - def_num=2, - type=BASE_TYPES[0x86], # uint32 - units='calories', - ref_fields=( - ReferenceField( - name='duration_type', - def_num=1, - value='calories', - raw_value=4, - ), - ), - ), - SubField( - name='duration_distance', - def_num=2, - type=BASE_TYPES[0x86], # uint32 - scale=100, - units='m', - ref_fields=( - ReferenceField( - name='duration_type', - def_num=1, - value='distance', - raw_value=1, - ), - ), - ), - SubField( - name='duration_hr', - def_num=2, - type=FIELD_TYPES['workout_hr'], - units='% or bpm', - ref_fields=( - ReferenceField( - name='duration_type', - def_num=1, - value='hr_less_than', - raw_value=2, - ), - ReferenceField( - name='duration_type', - def_num=1, - value='hr_greater_than', - raw_value=3, - ), - ), - ), - SubField( - name='duration_power', - def_num=2, - type=FIELD_TYPES['workout_power'], - units='% or watts', - ref_fields=( - ReferenceField( - name='duration_type', - def_num=1, - value='power_less_than', - raw_value=14, - ), - ReferenceField( - name='duration_type', - def_num=1, - value='power_greater_than', - raw_value=15, - ), - ), - ), - SubField( - name='duration_reps', - def_num=2, - type=BASE_TYPES[0x86], # uint32 - ref_fields=( - ReferenceField( - name='duration_type', - def_num=1, - value='reps', - raw_value=29, - ), - ), - ), - SubField( # message_index of step to loop back to. Steps are assumed to be in the order by message_index. custom_name and intensity members are undefined for this duration type. - name='duration_step', - def_num=2, - type=BASE_TYPES[0x86], # uint32 - ref_fields=( - ReferenceField( - name='duration_type', - def_num=1, - value='repeat_until_steps_cmplt', - raw_value=6, - ), - ReferenceField( - name='duration_type', - def_num=1, - value='repeat_until_time', - raw_value=7, - ), - ReferenceField( - name='duration_type', - def_num=1, - value='repeat_until_distance', - raw_value=8, - ), - ReferenceField( - name='duration_type', - def_num=1, - value='repeat_until_calories', - raw_value=9, - ), - ReferenceField( - name='duration_type', - def_num=1, - value='repeat_until_hr_less_than', - raw_value=10, - ), - ReferenceField( - name='duration_type', - def_num=1, - value='repeat_until_hr_greater_than', - raw_value=11, - ), - ReferenceField( - name='duration_type', - def_num=1, - value='repeat_until_power_less_than', - raw_value=12, - ), - ReferenceField( - name='duration_type', - def_num=1, - value='repeat_until_power_greater_than', - raw_value=13, - ), - ), - ), - SubField( - name='duration_time', - def_num=2, - type=BASE_TYPES[0x86], # uint32 - scale=1000, - units='s', - ref_fields=( - ReferenceField( - name='duration_type', - def_num=1, - value='time', - raw_value=0, - ), - ReferenceField( - name='duration_type', - def_num=1, - value='repetition_time', - raw_value=28, - ), - ), - ), - ), - ), - 3: Field( - name='target_type', - type=FIELD_TYPES['wkt_step_target'], - def_num=3, - ), - 4: Field( - name='target_value', - type=BASE_TYPES[0x86], # uint32 - def_num=4, - subfields=( - SubField( - name='repeat_calories', - def_num=4, - type=BASE_TYPES[0x86], # uint32 - units='calories', - ref_fields=( - ReferenceField( - name='duration_type', - def_num=1, - value='repeat_until_calories', - raw_value=9, - ), - ), - ), - SubField( - name='repeat_distance', - def_num=4, - type=BASE_TYPES[0x86], # uint32 - scale=100, - units='m', - ref_fields=( - ReferenceField( - name='duration_type', - def_num=1, - value='repeat_until_distance', - raw_value=8, - ), - ), - ), - SubField( - name='repeat_hr', - def_num=4, - type=FIELD_TYPES['workout_hr'], - units='% or bpm', - ref_fields=( - ReferenceField( - name='duration_type', - def_num=1, - value='repeat_until_hr_less_than', - raw_value=10, - ), - ReferenceField( - name='duration_type', - def_num=1, - value='repeat_until_hr_greater_than', - raw_value=11, - ), - ), - ), - SubField( - name='repeat_power', - def_num=4, - type=FIELD_TYPES['workout_power'], - units='% or watts', - ref_fields=( - ReferenceField( - name='duration_type', - def_num=1, - value='repeat_until_power_less_than', - raw_value=12, - ), - ReferenceField( - name='duration_type', - def_num=1, - value='repeat_until_power_greater_than', - raw_value=13, - ), - ), - ), - SubField( # # of repetitions - name='repeat_steps', - def_num=4, - type=BASE_TYPES[0x86], # uint32 - ref_fields=( - ReferenceField( - name='duration_type', - def_num=1, - value='repeat_until_steps_cmplt', - raw_value=6, - ), - ), - ), - SubField( - name='repeat_time', - def_num=4, - type=BASE_TYPES[0x86], # uint32 - scale=1000, - units='s', - ref_fields=( - ReferenceField( - name='duration_type', - def_num=1, - value='repeat_until_time', - raw_value=7, - ), - ), - ), - SubField( # Zone (1-?); Custom = 0; - name='target_cadence_zone', - def_num=4, - type=BASE_TYPES[0x86], # uint32 - ref_fields=( - ReferenceField( - name='target_type', - def_num=3, - value='cadence', - raw_value=3, - ), - ), - ), - SubField( # hr zone (1-5);Custom =0; - name='target_hr_zone', - def_num=4, - type=BASE_TYPES[0x86], # uint32 - ref_fields=( - ReferenceField( - name='target_type', - def_num=3, - value='heart_rate', - raw_value=1, - ), - ), - ), - SubField( # Power Zone ( 1-7); Custom = 0; - name='target_power_zone', - def_num=4, - type=BASE_TYPES[0x86], # uint32 - ref_fields=( - ReferenceField( - name='target_type', - def_num=3, - value='power', - raw_value=4, - ), - ), - ), - SubField( # speed zone (1-10);Custom =0; - name='target_speed_zone', - def_num=4, - type=BASE_TYPES[0x86], # uint32 - ref_fields=( - ReferenceField( - name='target_type', - def_num=3, - value='speed', - raw_value=0, - ), - ), - ), - SubField( - name='target_stroke_type', - def_num=4, - type=FIELD_TYPES['swim_stroke'], - ref_fields=( - ReferenceField( - name='target_type', - def_num=3, - value='swim_stroke', - raw_value=11, - ), - ), - ), - ), - ), - 5: Field( - name='custom_target_value_low', - type=BASE_TYPES[0x86], # uint32 - def_num=5, - subfields=( - SubField( - name='custom_target_cadence_low', - def_num=5, - type=BASE_TYPES[0x86], # uint32 - units='rpm', - ref_fields=( - ReferenceField( - name='target_type', - def_num=3, - value='cadence', - raw_value=3, - ), - ), - ), - SubField( - name='custom_target_heart_rate_low', - def_num=5, - type=FIELD_TYPES['workout_hr'], - units='% or bpm', - ref_fields=( - ReferenceField( - name='target_type', - def_num=3, - value='heart_rate', - raw_value=1, - ), - ), - ), - SubField( - name='custom_target_power_low', - def_num=5, - type=FIELD_TYPES['workout_power'], - units='% or watts', - ref_fields=( - ReferenceField( - name='target_type', - def_num=3, - value='power', - raw_value=4, - ), - ), - ), - SubField( - name='custom_target_speed_low', - def_num=5, - type=BASE_TYPES[0x86], # uint32 - scale=1000, - units='m/s', - ref_fields=( - ReferenceField( - name='target_type', - def_num=3, - value='speed', - raw_value=0, - ), - ), - ), - ), - ), - 6: Field( - name='custom_target_value_high', - type=BASE_TYPES[0x86], # uint32 - def_num=6, - subfields=( - SubField( - name='custom_target_cadence_high', - def_num=6, - type=BASE_TYPES[0x86], # uint32 - units='rpm', - ref_fields=( - ReferenceField( - name='target_type', - def_num=3, - value='cadence', - raw_value=3, - ), - ), - ), - SubField( - name='custom_target_heart_rate_high', - def_num=6, - type=FIELD_TYPES['workout_hr'], - units='% or bpm', - ref_fields=( - ReferenceField( - name='target_type', - def_num=3, - value='heart_rate', - raw_value=1, - ), - ), - ), - SubField( - name='custom_target_power_high', - def_num=6, - type=FIELD_TYPES['workout_power'], - units='% or watts', - ref_fields=( - ReferenceField( - name='target_type', - def_num=3, - value='power', - raw_value=4, - ), - ), - ), - SubField( - name='custom_target_speed_high', - def_num=6, - type=BASE_TYPES[0x86], # uint32 - scale=1000, - units='m/s', - ref_fields=( - ReferenceField( - name='target_type', - def_num=3, - value='speed', - raw_value=0, - ), - ), - ), - ), - ), - 7: Field( - name='intensity', - type=FIELD_TYPES['intensity'], - def_num=7, - ), - 8: Field( - name='notes', - type=BASE_TYPES[0x07], # string - def_num=8, - ), - 9: Field( - name='equipment', - type=FIELD_TYPES['workout_equipment'], - def_num=9, - ), - 10: Field( - name='exercise_category', - type=FIELD_TYPES['exercise_category'], - def_num=10, - ), - 11: Field( - name='exercise_name', - type=BASE_TYPES[0x84], # uint16 - def_num=11, - ), - 12: Field( - name='exercise_weight', - type=BASE_TYPES[0x84], # uint16 - def_num=12, - scale=100, - units='kg', - ), - 13: Field( - name='weight_display_unit', - type=FIELD_TYPES['fit_base_unit'], - def_num=13, - ), - 254: Field( - name='message_index', - type=FIELD_TYPES['message_index'], - def_num=254, - ), - }, - ), - 32: MessageType( - name='course_point', - mesg_num=32, - fields={ - 1: Field( - name='timestamp', - type=FIELD_TYPES['date_time'], - def_num=1, - ), - 2: Field( - name='position_lat', - type=BASE_TYPES[0x85], # sint32 - def_num=2, - units='semicircles', - ), - 3: Field( - name='position_long', - type=BASE_TYPES[0x85], # sint32 - def_num=3, - 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', - 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, - 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, - ), - ), - ), - ), - ), - 254: Field( - name='message_index', - type=FIELD_TYPES['message_index'], - def_num=254, - ), - }, - ), - 39: MessageType( - name='field_capabilities', - mesg_num=39, - 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='field_num', - type=BASE_TYPES[0x02], # uint8 - def_num=2, - ), - 3: Field( - name='count', - type=BASE_TYPES[0x84], # uint16 - def_num=3, - ), - 254: Field( - name='message_index', - type=FIELD_TYPES['message_index'], - def_num=254, - ), - }, - ), - 49: MessageType( - name='file_creator', - mesg_num=49, - fields={ - 0: Field( - name='software_version', - type=BASE_TYPES[0x84], # uint16 - def_num=0, - ), - 1: Field( - name='hardware_version', - type=BASE_TYPES[0x02], # uint8 - def_num=1, - ), - }, - ), - 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', - ), - 15: Field( # Max temperature during the logging interval ended at timestamp - name='temperature_max', - type=BASE_TYPES[0x83], # sint16 - def_num=15, - scale=100, - units='C', - ), - 16: Field( # Indexed using minute_activity_level enum - name='activity_time', - type=BASE_TYPES[0x84], # uint16 - def_num=16, - units='minutes', - ), - 19: Field( - name='active_calories', - type=BASE_TYPES[0x84], # uint16 - def_num=19, - units='kcal', - ), - 24: Field( # Indicates single type / intensity for duration since last monitoring message. - name='current_activity_type_intensity', - type=BASE_TYPES[0x0D], # byte - def_num=24, - components=( - ComponentField( - name='activity_type', - def_num=5, - accumulate=False, - bits=5, - bit_offset=0, - ), - ComponentField( - name='intensity', - def_num=28, - accumulate=False, - bits=3, - bit_offset=5, - ), - ), - ), - 25: Field( - name='timestamp_min_8', - type=BASE_TYPES[0x02], # uint8 - def_num=25, - units='min', - ), - 26: Field( - name='timestamp_16', - type=BASE_TYPES[0x84], # uint16 - def_num=26, - units='s', - ), - 27: Field( - name='heart_rate', - type=BASE_TYPES[0x02], # uint8 - def_num=27, - units='bpm', - ), - 28: Field( - name='intensity', - type=BASE_TYPES[0x02], # uint8 - def_num=28, - scale=10, - ), - 29: Field( - name='duration_min', - type=BASE_TYPES[0x84], # uint16 - def_num=29, - units='min', - ), - 30: Field( - name='duration', - type=BASE_TYPES[0x86], # uint32 - def_num=30, - units='s', - ), - 31: Field( - name='ascent', - type=BASE_TYPES[0x86], # uint32 - def_num=31, - scale=1000, - units='m', - ), - 32: Field( - name='descent', - type=BASE_TYPES[0x86], # uint32 - def_num=32, - scale=1000, - units='m', - ), - 33: Field( - name='moderate_activity_minutes', - type=BASE_TYPES[0x84], # uint16 - def_num=33, - units='minutes', - ), - 34: Field( - name='vigorous_activity_minutes', - type=BASE_TYPES[0x84], # uint16 - def_num=34, - units='minutes', - ), - 253: FIELD_TYPE_TIMESTAMP, # Must align to logging interval, for example, time must be 00:00:00 for daily log. - }, - ), - 72: MessageType( # Corresponds to file_id of workout or course. - name='training_file', - mesg_num=72, - fields={ - 0: Field( - name='type', - type=FIELD_TYPES['file'], - def_num=0, - ), - 1: Field( - name='manufacturer', - type=FIELD_TYPES['manufacturer'], - def_num=1, - ), - 2: Field( - name='product', - type=BASE_TYPES[0x84], # uint16 - def_num=2, - subfields=( - SubField( - name='garmin_product', - def_num=2, - type=FIELD_TYPES['garmin_product'], - ref_fields=( - ReferenceField( - name='manufacturer', - def_num=1, - value='garmin', - raw_value=1, - ), - ReferenceField( - name='manufacturer', - def_num=1, - value='dynastream', - raw_value=15, - ), - ReferenceField( - name='manufacturer', - def_num=1, - value='dynastream_oem', - raw_value=13, - ), - ), - ), - ), - ), - 3: Field( - name='serial_number', - type=BASE_TYPES[0x8C], # uint32z - def_num=3, - ), - 4: Field( - name='time_created', - type=FIELD_TYPES['date_time'], - def_num=4, - ), - 253: FIELD_TYPE_TIMESTAMP, - }, - ), - 78: MessageType( # Heart rate variability - name='hrv', - mesg_num=78, - fields={ - 0: Field( # Time between beats - name='time', - type=BASE_TYPES[0x84], # uint16 - def_num=0, - scale=1000, - units='s', - ), - }, - ), - 80: MessageType( - name='ant_rx', - mesg_num=80, - fields={ - 0: Field( - name='fractional_timestamp', - type=BASE_TYPES[0x84], # uint16 - def_num=0, - scale=32768, - units='s', - ), - 1: Field( - name='mesg_id', - type=BASE_TYPES[0x0D], # byte - def_num=1, - ), - 2: Field( - name='mesg_data', - type=BASE_TYPES[0x0D], # byte - def_num=2, - components=( - ComponentField( - name='channel_number', - def_num=3, - accumulate=False, - bits=8, - bit_offset=0, - ), - ComponentField( - name='data', - def_num=4, - accumulate=False, - bits=8, - bit_offset=8, - ), - ComponentField( - name='data', - def_num=4, - accumulate=False, - bits=8, - bit_offset=16, - ), - ComponentField( - name='data', - def_num=4, - accumulate=False, - bits=8, - bit_offset=24, - ), - ComponentField( - name='data', - def_num=4, - accumulate=False, - bits=8, - bit_offset=32, - ), - ComponentField( - name='data', - def_num=4, - accumulate=False, - bits=8, - bit_offset=40, - ), - ComponentField( - name='data', - def_num=4, - accumulate=False, - bits=8, - bit_offset=48, - ), - ComponentField( - name='data', - def_num=4, - accumulate=False, - bits=8, - bit_offset=56, - ), - ComponentField( - name='data', - def_num=4, - accumulate=False, - bits=8, - bit_offset=64, - ), - ), - ), - 3: Field( - name='channel_number', - type=BASE_TYPES[0x02], # uint8 - def_num=3, - ), - 4: Field( - name='data', - type=BASE_TYPES[0x0D], # byte - def_num=4, - ), - 253: FIELD_TYPE_TIMESTAMP, - }, - ), - 81: MessageType( - name='ant_tx', - mesg_num=81, - fields={ - 0: Field( - name='fractional_timestamp', - type=BASE_TYPES[0x84], # uint16 - def_num=0, - scale=32768, - units='s', - ), - 1: Field( - name='mesg_id', - type=BASE_TYPES[0x0D], # byte - def_num=1, - ), - 2: Field( - name='mesg_data', - type=BASE_TYPES[0x0D], # byte - def_num=2, - components=( - ComponentField( - name='channel_number', - def_num=3, - accumulate=False, - bits=8, - bit_offset=0, - ), - ComponentField( - name='data', - def_num=4, - accumulate=False, - bits=8, - bit_offset=8, - ), - ComponentField( - name='data', - def_num=4, - accumulate=False, - bits=8, - bit_offset=16, - ), - ComponentField( - name='data', - def_num=4, - accumulate=False, - bits=8, - bit_offset=24, - ), - ComponentField( - name='data', - def_num=4, - accumulate=False, - bits=8, - bit_offset=32, - ), - ComponentField( - name='data', - def_num=4, - accumulate=False, - bits=8, - bit_offset=40, - ), - ComponentField( - name='data', - def_num=4, - accumulate=False, - bits=8, - bit_offset=48, - ), - ComponentField( - name='data', - def_num=4, - accumulate=False, - bits=8, - bit_offset=56, - ), - ComponentField( - name='data', - def_num=4, - accumulate=False, - bits=8, - bit_offset=64, - ), - ), - ), - 3: Field( - name='channel_number', - type=BASE_TYPES[0x02], # uint8 - def_num=3, - ), - 4: Field( - name='data', - type=BASE_TYPES[0x0D], # byte - def_num=4, - ), - 253: FIELD_TYPE_TIMESTAMP, - }, - ), - 82: MessageType( - name='ant_channel_id', - mesg_num=82, - fields={ - 0: Field( - name='channel_number', - type=BASE_TYPES[0x02], # uint8 - def_num=0, - ), - 1: Field( - name='device_type', - type=BASE_TYPES[0x0A], # uint8z - def_num=1, - ), - 2: Field( - name='device_number', - type=BASE_TYPES[0x8B], # uint16z - def_num=2, - ), - 3: Field( - name='transmission_type', - type=BASE_TYPES[0x0A], # uint8z - def_num=3, - ), - 4: Field( - name='device_index', - type=FIELD_TYPES['device_index'], - def_num=4, - ), - }, - ), - 101: MessageType( - name='length', - mesg_num=101, - 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='start_time', - type=FIELD_TYPES['date_time'], - def_num=2, - ), - 3: Field( - name='total_elapsed_time', - type=BASE_TYPES[0x86], # uint32 - def_num=3, - scale=1000, - units='s', - ), - 4: Field( - name='total_timer_time', - type=BASE_TYPES[0x86], # uint32 - def_num=4, - scale=1000, - units='s', - ), - 5: Field( - name='total_strokes', - type=BASE_TYPES[0x84], # uint16 - def_num=5, - units='strokes', - ), - 6: Field( - name='avg_speed', - type=BASE_TYPES[0x84], # uint16 - def_num=6, - scale=1000, - units='m/s', - ), - 7: Field( - name='swim_stroke', - type=FIELD_TYPES['swim_stroke'], - def_num=7, - units='swim_stroke', - ), - 9: Field( - name='avg_swimming_cadence', - type=BASE_TYPES[0x02], # uint8 - def_num=9, - units='strokes/min', - ), - 10: Field( - name='event_group', - type=BASE_TYPES[0x02], # uint8 - def_num=10, - ), - 11: Field( - name='total_calories', - type=BASE_TYPES[0x84], # uint16 - def_num=11, - units='kcal', - ), - 12: Field( - name='length_type', - type=FIELD_TYPES['length_type'], - def_num=12, - ), - 18: Field( - name='player_score', - type=BASE_TYPES[0x84], # uint16 - def_num=18, - ), - 19: Field( - name='opponent_score', - type=BASE_TYPES[0x84], # uint16 - def_num=19, - ), - 20: Field( # stroke_type enum used as the index - name='stroke_count', - type=BASE_TYPES[0x84], # uint16 - def_num=20, - units='counts', - ), - 21: Field( # zone number used as the index - name='zone_count', - type=BASE_TYPES[0x84], # uint16 - def_num=21, - units='counts', - ), - 253: FIELD_TYPE_TIMESTAMP, - 254: Field( - name='message_index', - type=FIELD_TYPES['message_index'], - def_num=254, - ), - }, - ), - 106: MessageType( - name='slave_device', - mesg_num=106, - fields={ - 0: Field( - name='manufacturer', - type=FIELD_TYPES['manufacturer'], - def_num=0, - ), - 1: Field( - name='product', - type=BASE_TYPES[0x84], # uint16 - 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, - ), - ), - ), - ), - ), - }, - ), - 127: MessageType( - name='connectivity', - mesg_num=127, - fields={ - 0: Field( # Use Bluetooth for connectivity features - name='bluetooth_enabled', - type=FIELD_TYPES['bool'], - def_num=0, - ), - 1: Field( # Use Bluetooth Low Energy for connectivity features - name='bluetooth_le_enabled', - type=FIELD_TYPES['bool'], - def_num=1, - ), - 2: Field( # Use ANT for connectivity features - name='ant_enabled', - type=FIELD_TYPES['bool'], - def_num=2, - ), - 3: Field( - name='name', - type=BASE_TYPES[0x07], # string - def_num=3, - ), - 4: Field( - name='live_tracking_enabled', - type=FIELD_TYPES['bool'], - def_num=4, - ), - 5: Field( - name='weather_conditions_enabled', - type=FIELD_TYPES['bool'], - def_num=5, - ), - 6: Field( - name='weather_alerts_enabled', - type=FIELD_TYPES['bool'], - def_num=6, - ), - 7: Field( - name='auto_activity_upload_enabled', - type=FIELD_TYPES['bool'], - def_num=7, - ), - 8: Field( - name='course_download_enabled', - type=FIELD_TYPES['bool'], - def_num=8, - ), - 9: Field( - name='workout_download_enabled', - type=FIELD_TYPES['bool'], - def_num=9, - ), - 10: Field( - name='gps_ephemeris_download_enabled', - type=FIELD_TYPES['bool'], - def_num=10, - ), - 11: Field( - name='incident_detection_enabled', - type=FIELD_TYPES['bool'], - def_num=11, - ), - 12: Field( - name='grouptrack_enabled', - type=FIELD_TYPES['bool'], - def_num=12, - ), - }, - ), - 128: MessageType( - name='weather_conditions', - mesg_num=128, - fields={ - 0: Field( # Current or forecast - name='weather_report', - type=FIELD_TYPES['weather_report'], - def_num=0, - ), - 1: Field( - name='temperature', - type=BASE_TYPES[0x01], # sint8 - def_num=1, - units='C', - ), - 2: Field( # Corresponds to GSC Response weatherIcon field - name='condition', - type=FIELD_TYPES['weather_status'], - def_num=2, - ), - 3: Field( - name='wind_direction', - type=BASE_TYPES[0x84], # uint16 - def_num=3, - units='degrees', - ), - 4: Field( - name='wind_speed', - type=BASE_TYPES[0x84], # uint16 - def_num=4, - scale=1000, - units='m/s', - ), - 5: Field( # range 0-100 - name='precipitation_probability', - type=BASE_TYPES[0x02], # uint8 - def_num=5, - ), - 6: Field( # Heat Index if GCS heatIdx above or equal to 90F or wind chill if GCS windChill below or equal to 32F - name='temperature_feels_like', - type=BASE_TYPES[0x01], # sint8 - def_num=6, - units='C', - ), - 7: Field( - name='relative_humidity', - type=BASE_TYPES[0x02], # uint8 - def_num=7, - ), - 8: Field( # string corresponding to GCS response location string - name='location', - type=BASE_TYPES[0x07], # string - def_num=8, - ), - 9: Field( - name='observed_at_time', - type=FIELD_TYPES['date_time'], - def_num=9, - ), - 10: Field( - name='observed_location_lat', - type=BASE_TYPES[0x85], # sint32 - def_num=10, - units='semicircles', - ), - 11: Field( - name='observed_location_long', - type=BASE_TYPES[0x85], # sint32 - def_num=11, - units='semicircles', - ), - 12: Field( - name='day_of_week', - type=FIELD_TYPES['day_of_week'], - def_num=12, - ), - 13: Field( - name='high_temperature', - type=BASE_TYPES[0x01], # sint8 - def_num=13, - units='C', - ), - 14: Field( - name='low_temperature', - type=BASE_TYPES[0x01], # sint8 - def_num=14, - units='C', - ), - 253: FIELD_TYPE_TIMESTAMP, # time of update for current conditions, else forecast time - }, - ), - 129: MessageType( - name='weather_alert', - mesg_num=129, - fields={ - 0: Field( # Unique identifier from GCS report ID string, length is 12 - name='report_id', - type=BASE_TYPES[0x07], # string - def_num=0, - ), - 1: Field( # Time alert was issued - name='issue_time', - type=FIELD_TYPES['date_time'], - def_num=1, - ), - 2: Field( # Time alert expires - name='expire_time', - type=FIELD_TYPES['date_time'], - def_num=2, - ), - 3: Field( # Warning, Watch, Advisory, Statement - name='severity', - type=FIELD_TYPES['weather_severity'], - def_num=3, - ), - 4: Field( # Tornado, Severe Thunderstorm, etc. - name='type', - type=FIELD_TYPES['weather_severe_type'], - def_num=4, - ), - 253: FIELD_TYPE_TIMESTAMP, - }, - ), - 131: MessageType( - name='cadence_zone', - mesg_num=131, - fields={ - 0: Field( - name='high_value', - type=BASE_TYPES[0x02], # uint8 - def_num=0, - units='rpm', - ), - 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, - ), - }, - ), - 132: MessageType( - name='hr', - mesg_num=132, - fields={ - 0: Field( - name='fractional_timestamp', - type=BASE_TYPES[0x84], # uint16 - def_num=0, - scale=32768, - units='s', - ), - 1: Field( - name='time256', - type=BASE_TYPES[0x02], # uint8 - def_num=1, - components=( - ComponentField( - name='fractional_timestamp', - def_num=0, - scale=256, - units='s', - accumulate=False, - bits=8, - bit_offset=0, - ), - ), - ), - 6: Field( - name='filtered_bpm', - type=BASE_TYPES[0x02], # uint8 - def_num=6, - units='bpm', - ), - 9: Field( - name='event_timestamp', - type=BASE_TYPES[0x86], # uint32 - def_num=9, - scale=1024, - units='s', - ), - 10: Field( - name='event_timestamp_12', - type=BASE_TYPES[0x0D], # byte - def_num=10, - components=( - ComponentField( - name='event_timestamp', - def_num=9, - scale=1024, - units='s', - accumulate=True, - bits=12, - bit_offset=0, - ), - ComponentField( - name='event_timestamp', - def_num=9, - scale=1024, - units='s', - accumulate=True, - bits=12, - bit_offset=12, - ), - ComponentField( - name='event_timestamp', - def_num=9, - scale=1024, - units='s', - accumulate=True, - bits=12, - bit_offset=24, - ), - ComponentField( - name='event_timestamp', - def_num=9, - scale=1024, - units='s', - accumulate=True, - bits=12, - bit_offset=36, - ), - ComponentField( - name='event_timestamp', - def_num=9, - scale=1024, - units='s', - accumulate=True, - bits=12, - bit_offset=48, - ), - ComponentField( - name='event_timestamp', - def_num=9, - scale=1024, - units='s', - accumulate=True, - bits=12, - bit_offset=60, - ), - ComponentField( - name='event_timestamp', - def_num=9, - scale=1024, - units='s', - accumulate=True, - bits=12, - bit_offset=72, - ), - ComponentField( - name='event_timestamp', - def_num=9, - scale=1024, - units='s', - accumulate=True, - bits=12, - bit_offset=84, - ), - ComponentField( - name='event_timestamp', - def_num=9, - scale=1024, - units='s', - accumulate=True, - bits=12, - bit_offset=96, - ), - ComponentField( - name='event_timestamp', - def_num=9, - scale=1024, - units='s', - accumulate=True, - bits=12, - bit_offset=108, - ), - ), - ), - 253: FIELD_TYPE_TIMESTAMP, - }, - ), - 142: MessageType( - name='segment_lap', - mesg_num=142, - 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='start_time', - type=FIELD_TYPES['date_time'], - def_num=2, - ), - 3: Field( - name='start_position_lat', - type=BASE_TYPES[0x85], # sint32 - def_num=3, - units='semicircles', - ), - 4: Field( - name='start_position_long', - type=BASE_TYPES[0x85], # sint32 - def_num=4, - units='semicircles', - ), - 5: Field( - name='end_position_lat', - type=BASE_TYPES[0x85], # sint32 - def_num=5, - units='semicircles', - ), - 6: Field( - name='end_position_long', - type=BASE_TYPES[0x85], # sint32 - def_num=6, - units='semicircles', - ), - 7: Field( # Time (includes pauses) - name='total_elapsed_time', - type=BASE_TYPES[0x86], # uint32 - def_num=7, - scale=1000, - units='s', - ), - 8: Field( # Timer Time (excludes pauses) - name='total_timer_time', - type=BASE_TYPES[0x86], # uint32 - def_num=8, - scale=1000, - units='s', - ), - 9: Field( - name='total_distance', - type=BASE_TYPES[0x86], # uint32 - def_num=9, - scale=100, - units='m', - ), - 10: Field( - name='total_cycles', - type=BASE_TYPES[0x86], # uint32 - def_num=10, - units='cycles', - subfields=( - SubField( - name='total_strokes', - def_num=10, - type=BASE_TYPES[0x86], # uint32 - units='strokes', - ref_fields=( - ReferenceField( - name='sport', - def_num=23, - value='cycling', - raw_value=2, - ), - ), - ), - ), - ), - 11: Field( - name='total_calories', - type=BASE_TYPES[0x84], # uint16 - def_num=11, - units='kcal', - ), - 12: Field( # If New Leaf - name='total_fat_calories', - type=BASE_TYPES[0x84], # uint16 - def_num=12, - units='kcal', - ), - 13: Field( - name='avg_speed', - type=BASE_TYPES[0x84], # uint16 - def_num=13, - scale=1000, - units='m/s', - ), - 14: Field( - name='max_speed', - type=BASE_TYPES[0x84], # uint16 - def_num=14, - scale=1000, - units='m/s', - ), - 15: Field( - name='avg_heart_rate', - type=BASE_TYPES[0x02], # uint8 - def_num=15, - units='bpm', - ), - 16: Field( - name='max_heart_rate', - type=BASE_TYPES[0x02], # uint8 - def_num=16, - units='bpm', - ), - 17: Field( # total_cycles / total_timer_time if non_zero_avg_cadence otherwise total_cycles / total_elapsed_time - name='avg_cadence', - type=BASE_TYPES[0x02], # uint8 - def_num=17, - units='rpm', - ), - 18: Field( - name='max_cadence', - type=BASE_TYPES[0x02], # uint8 - def_num=18, - units='rpm', - ), - 19: Field( # total_power / total_timer_time if non_zero_avg_power otherwise total_power / total_elapsed_time - name='avg_power', - type=BASE_TYPES[0x84], # uint16 - def_num=19, - units='watts', - ), - 20: Field( - name='max_power', - type=BASE_TYPES[0x84], # uint16 - def_num=20, - units='watts', - ), - 21: Field( - name='total_ascent', - type=BASE_TYPES[0x84], # uint16 - def_num=21, - units='m', - ), - 22: Field( - name='total_descent', - type=BASE_TYPES[0x84], # uint16 - def_num=22, - units='m', - ), - 23: Field( - name='sport', - type=FIELD_TYPES['sport'], - def_num=23, - ), - 24: Field( - name='event_group', - type=BASE_TYPES[0x02], # uint8 - def_num=24, - ), - 25: Field( # North east corner latitude. - name='nec_lat', - type=BASE_TYPES[0x85], # sint32 - def_num=25, - units='semicircles', - ), - 26: Field( # North east corner longitude. - name='nec_long', - type=BASE_TYPES[0x85], # sint32 - def_num=26, - units='semicircles', - ), - 27: Field( # South west corner latitude. - name='swc_lat', - type=BASE_TYPES[0x85], # sint32 - def_num=27, - units='semicircles', - ), - 28: Field( # South west corner latitude. - name='swc_long', - type=BASE_TYPES[0x85], # sint32 - def_num=28, - units='semicircles', - ), - 29: Field( - name='name', - type=BASE_TYPES[0x07], # string - def_num=29, - ), - 30: Field( - name='normalized_power', - type=BASE_TYPES[0x84], # uint16 - def_num=30, - units='watts', - ), - 31: Field( - name='left_right_balance', - type=FIELD_TYPES['left_right_balance_100'], - def_num=31, - ), - 32: Field( - name='sub_sport', - type=FIELD_TYPES['sub_sport'], - def_num=32, - ), - 33: Field( - name='total_work', - type=BASE_TYPES[0x86], # uint32 - def_num=33, - units='J', - ), - 34: Field( - name='avg_altitude', - type=BASE_TYPES[0x84], # uint16 - def_num=34, - scale=5, - offset=500, - units='m', - ), - 35: Field( - name='max_altitude', - type=BASE_TYPES[0x84], # uint16 - def_num=35, - scale=5, - offset=500, - units='m', - ), - 36: Field( - name='gps_accuracy', - type=BASE_TYPES[0x02], # uint8 - def_num=36, - units='m', - ), - 37: Field( - name='avg_grade', - type=BASE_TYPES[0x83], # sint16 - def_num=37, - scale=100, - units='%', - ), - 38: Field( - name='avg_pos_grade', - type=BASE_TYPES[0x83], # sint16 - def_num=38, - scale=100, - units='%', - ), - 39: Field( - name='avg_neg_grade', - type=BASE_TYPES[0x83], # sint16 - def_num=39, - scale=100, - units='%', - ), - 40: Field( - name='max_pos_grade', - type=BASE_TYPES[0x83], # sint16 - def_num=40, - scale=100, - units='%', - ), - 41: Field( - name='max_neg_grade', - type=BASE_TYPES[0x83], # sint16 - def_num=41, - scale=100, - units='%', - ), - 42: Field( - name='avg_temperature', - type=BASE_TYPES[0x01], # sint8 - def_num=42, - units='C', - ), - 43: Field( - name='max_temperature', - type=BASE_TYPES[0x01], # sint8 - def_num=43, - units='C', - ), - 44: Field( - name='total_moving_time', - type=BASE_TYPES[0x86], # uint32 - def_num=44, - scale=1000, - units='s', - ), - 45: Field( - name='avg_pos_vertical_speed', - type=BASE_TYPES[0x83], # sint16 - def_num=45, - scale=1000, - units='m/s', - ), - 46: Field( - name='avg_neg_vertical_speed', - type=BASE_TYPES[0x83], # sint16 - def_num=46, - scale=1000, - units='m/s', - ), - 47: Field( - name='max_pos_vertical_speed', - type=BASE_TYPES[0x83], # sint16 - def_num=47, - scale=1000, - units='m/s', - ), - 48: Field( - name='max_neg_vertical_speed', - type=BASE_TYPES[0x83], # sint16 - def_num=48, - scale=1000, - units='m/s', - ), - 49: Field( - name='time_in_hr_zone', - type=BASE_TYPES[0x86], # uint32 - def_num=49, - scale=1000, - units='s', - ), - 50: Field( - name='time_in_speed_zone', - type=BASE_TYPES[0x86], # uint32 - def_num=50, - scale=1000, - units='s', - ), - 51: Field( - name='time_in_cadence_zone', - type=BASE_TYPES[0x86], # uint32 - def_num=51, - scale=1000, - units='s', - ), - 52: Field( - name='time_in_power_zone', - type=BASE_TYPES[0x86], # uint32 - def_num=52, - scale=1000, - units='s', - ), - 53: Field( - name='repetition_num', - type=BASE_TYPES[0x84], # uint16 - def_num=53, - ), - 54: Field( - name='min_altitude', - type=BASE_TYPES[0x84], # uint16 - def_num=54, - scale=5, - offset=500, - units='m', - ), - 55: Field( - name='min_heart_rate', - type=BASE_TYPES[0x02], # uint8 - def_num=55, - units='bpm', - ), - 56: Field( - name='active_time', - type=BASE_TYPES[0x86], # uint32 - def_num=56, - scale=1000, - units='s', - ), - 57: Field( - name='wkt_step_index', - type=FIELD_TYPES['message_index'], - def_num=57, - ), - 58: Field( - name='sport_event', - type=FIELD_TYPES['sport_event'], - def_num=58, - ), - 59: Field( - name='avg_left_torque_effectiveness', - type=BASE_TYPES[0x02], # uint8 - def_num=59, - scale=2, - units='percent', - ), - 60: Field( - name='avg_right_torque_effectiveness', - type=BASE_TYPES[0x02], # uint8 - def_num=60, - scale=2, - units='percent', - ), - 61: Field( - name='avg_left_pedal_smoothness', - type=BASE_TYPES[0x02], # uint8 - def_num=61, - scale=2, - units='percent', - ), - 62: Field( - name='avg_right_pedal_smoothness', - type=BASE_TYPES[0x02], # uint8 - def_num=62, - scale=2, - units='percent', - ), - 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, - ), - 2: Field( - name='fit_base_type_id', - type=FIELD_TYPES['fit_base_type'], - def_num=2, - ), - 3: Field( - name='field_name', - type=BASE_TYPES[0x07], # string - def_num=3, - ), - 4: Field( - name='array', - type=BASE_TYPES[0x02], # uint8 - def_num=4, - ), - 5: Field( - name='components', - type=BASE_TYPES[0x07], # string - def_num=5, - ), - 6: Field( - name='scale', - type=BASE_TYPES[0x02], # uint8 - def_num=6, - ), - 7: Field( - name='offset', - type=BASE_TYPES[0x01], # sint8 - def_num=7, - ), - 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, - ), - }, - ), - 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, - ), - 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( - name='application_version', - type=BASE_TYPES[0x86], # uint32 - def_num=4, - ), - }, - ), - 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', - ), - 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', - ), - 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', - ), - 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', - ), - 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', - ), - 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 - }, - ), - 210: MessageType( - name='one_d_sensor_calibration', - mesg_num=210, - 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( # 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 - 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 factor - name='offset_cal', - type=BASE_TYPES[0x85], # sint32 - def_num=4, - ), - 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', - ), - 3: Field( # # of repitions of the movement - name='repetitions', - type=BASE_TYPES[0x84], # uint16 - def_num=3, - ), - 4: Field( # Amount of weight applied for the set - name='weight', - type=BASE_TYPES[0x84], # uint16 - def_num=4, - scale=16, - units='kg', - ), - 5: Field( - name='set_type', - type=FIELD_TYPES['set_type'], - def_num=5, - ), - 6: Field( # Start time of the set - name='start_time', - type=FIELD_TYPES['date_time'], - def_num=6, - ), - 7: Field( - name='category', - type=FIELD_TYPES['exercise_category'], - def_num=7, - ), - 8: Field( # Based on the associated category, see [category]_exercise_names - name='category_subtype', - type=BASE_TYPES[0x84], # uint16 - 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, - fields={ - 0: Field( - name='stress_level_value', - type=BASE_TYPES[0x83], # sint16 - def_num=0, - ), - 1: Field( # Time stress score was calculated - name='stress_level_time', - type=FIELD_TYPES['date_time'], - def_num=1, - units='s', - ), - }, - ), - 258: MessageType( - name='dive_settings', - mesg_num=258, - fields={ - 0: Field( - name='name', - type=BASE_TYPES[0x07], # string - def_num=0, - ), - 1: Field( - name='model', - type=FIELD_TYPES['tissue_model_type'], - def_num=1, - ), - 2: Field( - name='gf_low', - type=BASE_TYPES[0x02], # uint8 - def_num=2, - units='percent', - ), - 3: Field( - name='gf_high', - type=BASE_TYPES[0x02], # uint8 - def_num=3, - units='percent', - ), - 4: Field( - name='water_type', - type=FIELD_TYPES['water_type'], - def_num=4, - ), - 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( # Typically 1.40 - name='po2_warn', - type=BASE_TYPES[0x02], # uint8 - def_num=6, - scale=100, - units='percent', - ), - 7: Field( # Typically 1.60 - name='po2_critical', - type=BASE_TYPES[0x02], # uint8 - def_num=7, - scale=100, - units='percent', - ), - 8: Field( - name='po2_deco', - type=BASE_TYPES[0x02], # uint8 - def_num=8, - scale=100, - units='percent', - ), - 9: Field( - name='safety_stop_enabled', - type=FIELD_TYPES['bool'], - def_num=9, - ), - 10: Field( - name='bottom_depth', - type=BASE_TYPES[0x88], # float32 - def_num=10, - ), - 11: Field( - name='bottom_time', - type=BASE_TYPES[0x86], # uint32 - 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, - ), - 14: Field( - 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='backlight_timeout', - type=FIELD_TYPES['backlight_timeout'], - def_num=16, - ), - 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( # Time at safety stop (if enabled) - name='safety_stop_time', - type=BASE_TYPES[0x84], # uint16 - def_num=18, - units='s', - ), - 19: Field( - name='heart_rate_source_type', - type=FIELD_TYPES['source_type'], - def_num=19, - ), - 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, - ), - ), - ), - ), - ), - 254: Field( - name='message_index', - type=FIELD_TYPES['message_index'], - def_num=254, - ), - }, - ), - 259: MessageType( - name='dive_gas', - mesg_num=259, - fields={ - 0: Field( - name='helium_content', - type=BASE_TYPES[0x02], # uint8 - def_num=0, - units='percent', - ), - 1: Field( - name='oxygen_content', - type=BASE_TYPES[0x02], # uint8 - def_num=1, - units='percent', - ), - 2: Field( - name='status', - type=FIELD_TYPES['dive_gas_status'], - def_num=2, - ), - 254: Field( - name='message_index', - type=FIELD_TYPES['message_index'], - def_num=254, - ), - }, - ), - 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='time', - type=BASE_TYPES[0x85], # sint32 - def_num=1, - units='s', - ), - 2: Field( - name='enabled', - type=FIELD_TYPES['bool'], - def_num=2, - ), - 3: Field( - 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='dive_types', - type=FIELD_TYPES['sub_sport'], - def_num=5, - ), - 254: Field( # Index of the alarm - name='message_index', - type=FIELD_TYPES['message_index'], - def_num=254, - ), - }, - ), - 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( - name='reference_mesg', - type=FIELD_TYPES['mesg_num'], - def_num=0, - ), - 1: Field( - name='reference_index', - type=FIELD_TYPES['message_index'], - def_num=1, - ), - 2: Field( # 0 if above water - name='avg_depth', - type=BASE_TYPES[0x86], # uint32 - def_num=2, - scale=1000, - units='m', - ), - 3: Field( # 0 if above water - name='max_depth', - type=BASE_TYPES[0x86], # uint32 - def_num=3, - scale=1000, - units='m', - ), - 4: Field( # Time since end of last dive - name='surface_interval', - type=BASE_TYPES[0x86], # uint32 - def_num=4, - units='s', - ), - 5: Field( - name='start_cns', - type=BASE_TYPES[0x02], # uint8 - def_num=5, - units='percent', - ), - 6: Field( - name='end_cns', - type=BASE_TYPES[0x02], # uint8 - def_num=6, - 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='o2_toxicity', - type=BASE_TYPES[0x84], # uint16 - def_num=9, - units='OTUs', - ), - 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', - ), - 253: FIELD_TYPE_TIMESTAMP, - }, - ), - - - # ************************* Activity File Messages ************************* - 34: MessageType( - name='activity', - mesg_num=34, - fields={ - 0: Field( # Exclude pauses - name='total_timer_time', - type=BASE_TYPES[0x86], # uint32 - def_num=0, - scale=1000, - units='s', - ), - 1: Field( - name='num_sessions', - type=BASE_TYPES[0x84], # uint16 - def_num=1, - ), - 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, - }, - ), - - - # ********************** Blood Pressure File Messages ********************** - 51: MessageType( - name='blood_pressure', - mesg_num=51, - fields={ - 0: Field( - name='systolic_pressure', - type=BASE_TYPES[0x84], # uint16 - def_num=0, - units='mmHg', - ), - 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, - }, - ), - - - # ************************** Course File Messages ************************** - 31: MessageType( - name='course', - mesg_num=31, - fields={ - 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, - ), - }, - ), - - - # ************************** Device File Messages ************************** - 35: MessageType( - name='software', - mesg_num=35, - fields={ - 3: Field( - name='version', - type=BASE_TYPES[0x84], # uint16 - def_num=3, - scale=100, - ), - 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, - ), - }, - ), - - - # ************************** Goals File Messages *************************** - 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, - ), - }, - ), - - - # ************************ Monitoring File Messages ************************ - 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, - }, - ), - - - # ***************************** Other Messages ***************************** - 145: MessageType( - name='memo_glob', - mesg_num=145, - fields={ - 0: Field( # Block of utf8 bytes - name='memo', - type=BASE_TYPES[0x0D], # byte - 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 - def_num=1, - ), - 2: Field( # Index of external mesg - name='message_index', - type=FIELD_TYPES['message_index'], - def_num=2, - ), - 250: Field( # Sequence number of memo blocks - name='part_index', - type=BASE_TYPES[0x86], # uint32 - def_num=250, - ), - }, - ), - - - # ************************* Schedule File Messages ************************* - 28: MessageType( - name='schedule', - mesg_num=28, - fields={ - 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='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, - ), - ), - ), - ), - ), - 2: Field( # Corresponds to file_id of scheduled workout / course. - name='serial_number', - type=BASE_TYPES[0x8C], # uint32z - def_num=2, - ), - 3: Field( # Corresponds to file_id of scheduled workout / course. - name='time_created', - type=FIELD_TYPES['date_time'], - def_num=3, - ), - 4: Field( # TRUE if this activity has been started - name='completed', - type=FIELD_TYPES['bool'], - def_num=4, - ), - 5: Field( - name='type', - type=FIELD_TYPES['schedule'], - def_num=5, - ), - 6: Field( - name='scheduled_time', - type=FIELD_TYPES['local_date_time'], - def_num=6, - ), - }, - ), - - - # ************************* Segment File Messages ************************** - 148: MessageType( # Unique Identification data for a segment file - name='segment_id', - mesg_num=148, - fields={ - 0: Field( # Friendly name assigned to segment - name='name', - type=BASE_TYPES[0x07], # string - def_num=0, - ), - 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( # Primary key of the user that created the segment - name='user_profile_primary_key', - type=BASE_TYPES[0x86], # uint32 - def_num=4, - ), - 5: Field( # ID of the device that created the segment - name='device_id', - type=BASE_TYPES[0x86], # uint32 - def_num=5, - ), - 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( # Indicates if any segments should be deleted - name='delete_status', - type=FIELD_TYPES['segment_delete_status'], - 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'], - def_num=8, - ), - }, - ), - - - # *********************** Segment List File Messages *********************** - 151: MessageType( # Summary of the unique segment and leaderboard information associated with a segment file. This message is used to compile a segment list file describing all segment files on a device. The segment list file is used when refreshing the contents of a segment file with the latest available leaderboard information. - name='segment_file', - mesg_num=151, - fields={ - 1: Field( # UUID of the segment file - name='file_uuid', - type=BASE_TYPES[0x07], # string - def_num=1, - ), - 3: Field( # Enabled state of the segment file - name='enabled', - type=FIELD_TYPES['bool'], - def_num=3, - ), - 4: Field( # Primary key of the user that created the segment file - name='user_profile_primary_key', - type=BASE_TYPES[0x86], # uint32 - def_num=4, - ), - 7: Field( # Leader type of each leader in the segment file - name='leader_type', - type=FIELD_TYPES['segment_leaderboard_type'], - def_num=7, - ), - 8: Field( # Group primary key of each leader in the segment file - name='leader_group_primary_key', - type=BASE_TYPES[0x86], # uint32 - def_num=8, - ), - 9: Field( # Activity ID of each leader in the segment file - name='leader_activity_id', - type=BASE_TYPES[0x86], # uint32 - def_num=9, - ), - 10: Field( # String version of the activity ID of each leader in the segment file. 21 characters long for each ID, express in decimal - name='leader_activity_id_string', - type=BASE_TYPES[0x07], # string - def_num=10, - ), - 11: Field( # Index for the Leader Board entry selected as the default race participant - name='default_race_leader', - type=BASE_TYPES[0x02], # uint8 - def_num=11, - ), - 254: Field( - name='message_index', - type=FIELD_TYPES['message_index'], - def_num=254, - ), - }, - ), - - - # ************************* Settings File Messages ************************* - 2: MessageType( - name='device_settings', - mesg_num=2, - fields={ - 0: Field( # Index into time zone arrays. - name='active_time_zone', - type=BASE_TYPES[0x02], # uint8 - def_num=0, - ), - 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( # Offset from system time. - name='time_offset', - 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', - ), - 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=36, - ), - 39: Field( # UTC timestamp used to set the devices clock and date - name='clock_time', - type=FIELD_TYPES['date_time'], - def_num=39, - ), - 40: Field( # Bitfield to configure enabled screens for each supported loop - name='pages_enabled', - 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, - ), - 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=80, - ), - 86: Field( # Automatically upload using BLE - name='ble_auto_upload_enabled', - type=FIELD_TYPES['bool'], - def_num=86, - ), - 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=94, - ), - 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, - ), - }, - ), - 3: MessageType( - name='user_profile', - mesg_num=3, - fields={ - 0: Field( - name='friendly_name', - type=BASE_TYPES[0x07], # string - def_num=0, - ), - 1: Field( - name='gender', - type=FIELD_TYPES['gender'], - def_num=1, - ), - 2: Field( - name='age', - type=BASE_TYPES[0x02], # uint8 - def_num=2, - units='years', - ), - 3: Field( - name='height', - type=BASE_TYPES[0x02], # uint8 - def_num=3, - scale=100, - units='m', - ), - 4: Field( - name='weight', - type=BASE_TYPES[0x84], # uint16 - def_num=4, - scale=10, - units='kg', - ), - 5: Field( - name='language', - type=FIELD_TYPES['language'], - def_num=5, - ), - 6: Field( - name='elev_setting', - type=FIELD_TYPES['display_measure'], - def_num=6, - ), - 7: Field( - name='weight_setting', - type=FIELD_TYPES['display_measure'], - def_num=7, - ), - 8: Field( - name='resting_heart_rate', - type=BASE_TYPES[0x02], # uint8 - def_num=8, - units='bpm', - ), - 9: Field( - name='default_max_running_heart_rate', - type=BASE_TYPES[0x02], # uint8 - def_num=9, - units='bpm', - ), - 10: Field( - name='default_max_biking_heart_rate', - type=BASE_TYPES[0x02], # uint8 - def_num=10, - 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, - ), - }, - ), - - - # ********************** Sport Settings File Messages ********************** - 7: MessageType( - name='zones_target', - mesg_num=7, - fields={ - 1: Field( - name='max_heart_rate', - type=BASE_TYPES[0x02], # uint8 - def_num=1, - ), - 2: Field( - 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, - ), - }, - ), - - - # ************************** Totals File Messages ************************** - 33: MessageType( - name='totals', - mesg_num=33, - fields={ - 0: Field( # Excludes pauses - name='timer_time', - type=BASE_TYPES[0x86], # uint32 - def_num=0, - units='s', - ), - 1: Field( - name='distance', - type=BASE_TYPES[0x86], # uint32 - def_num=1, - units='m', - ), - 2: Field( - name='calories', - type=BASE_TYPES[0x86], # uint32 - def_num=2, - units='kcal', - ), - 3: Field( - name='sport', - type=FIELD_TYPES['sport'], - def_num=3, - ), - 4: Field( # Includes pauses - name='elapsed_time', - type=BASE_TYPES[0x86], # uint32 - def_num=4, - units='s', - ), - 5: Field( - name='sessions', - type=BASE_TYPES[0x84], # uint16 - def_num=5, - ), - 6: Field( - name='active_time', - type=BASE_TYPES[0x86], # uint32 - def_num=6, - units='s', - ), - 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'], - def_num=254, - ), - }, - ), - - - # *********************** Weight Scale File Messages *********************** - 30: MessageType( - name='weight_scale', - mesg_num=30, - fields={ - 0: Field( - name='weight', - type=FIELD_TYPES['weight'], - def_num=0, - scale=100, - units='kg', - ), - 1: Field( - name='percent_fat', - type=BASE_TYPES[0x84], # uint16 - def_num=1, - scale=100, - units='%', - ), - 2: Field( - name='percent_hydration', - type=BASE_TYPES[0x84], # uint16 - def_num=2, - scale=100, - units='%', - ), - 3: Field( - name='visceral_fat_mass', - type=BASE_TYPES[0x84], # uint16 - def_num=3, - scale=100, - units='kg', - ), - 4: Field( - name='bone_mass', - type=BASE_TYPES[0x84], # uint16 - def_num=4, - 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=12, - ), - 253: FIELD_TYPE_TIMESTAMP, - }, - ), - - - # ************************* Workout File Messages ************************** - 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, - ), - }, - ), -} + +# ***************** 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) ********** + +from fitparse.records import ( + ComponentField, + Field, + FieldType, + MessageType, + ReferenceField, + SubField, + BASE_TYPES, +) + + +FIELD_NUM_TIMESTAMP = 253 + + +FIELD_TYPES = { + 'activity': FieldType( + name='activity', + base_type=BASE_TYPES[0x00], # enum + values={ + 0: 'manual', + 1: 'auto_multi_sport', + }, + ), + 'activity_class': FieldType( + name='activity_class', + base_type=BASE_TYPES[0x00], # enum + values={ + 100: 'level_max', + 0x7F: 'level', # 0 to 100 + 0x80: 'athlete', + }, + ), + 'activity_level': FieldType( + name='activity_level', + base_type=BASE_TYPES[0x00], # enum + values={ + 0: 'low', + 1: 'medium', + 2: 'high', + }, + ), + 'activity_subtype': FieldType( + name='activity_subtype', + base_type=BASE_TYPES[0x00], # enum + values={ + 0: 'generic', + 1: 'treadmill', # Run + 2: 'street', # Run + 3: 'trail', # Run + 4: 'track', # Run + 5: 'spin', # Cycling + 6: 'indoor_cycling', # Cycling + 7: 'road', # Cycling + 8: 'mountain', # Cycling + 9: 'downhill', # Cycling + 10: 'recumbent', # Cycling + 11: 'cyclocross', # Cycling + 12: 'hand_cycling', # Cycling + 13: 'track_cycling', # Cycling + 14: 'indoor_rowing', # Fitness Equipment + 15: 'elliptical', # Fitness Equipment + 16: 'stair_climbing', # Fitness Equipment + 17: 'lap_swimming', # Swimming + 18: 'open_water', # Swimming + 254: 'all', + }, + ), + 'activity_type': FieldType( + name='activity_type', + base_type=BASE_TYPES[0x00], # enum + values={ + 0: 'generic', + 1: 'running', + 2: 'cycling', + 3: 'transition', # Mulitsport transition + 4: 'fitness_equipment', + 5: 'swimming', + 6: 'walking', + 8: 'sedentary', + 254: 'all', # All is for goals only to include all sports. + }, + ), + 'analog_watchface_layout': FieldType( + name='analog_watchface_layout', + base_type=BASE_TYPES[0x00], # enum + values={ + 0: 'minimal', + 1: 'traditional', + 2: 'modern', + }, + ), + 'ant_network': FieldType( + name='ant_network', + base_type=BASE_TYPES[0x00], # enum + values={ + 0: 'public', + 1: 'antplus', + 2: 'antfs', + 3: 'private', + }, + ), + 'antplus_device_type': FieldType( + name='antplus_device_type', + base_type=BASE_TYPES[0x02], # uint8 + values={ + 1: 'antfs', + 11: 'bike_power', + 12: 'environment_sensor_legacy', + 15: 'multi_sport_speed_distance', + 16: 'control', + 17: 'fitness_equipment', + 18: 'blood_pressure', + 19: 'geocache_node', + 20: 'light_electric_vehicle', + 25: 'env_sensor', + 26: 'racquet', + 27: 'control_hub', + 31: 'muscle_oxygen', + 35: 'bike_light_main', + 36: 'bike_light_shared', + 38: 'exd', + 40: 'bike_radar', + 119: 'weight_scale', + 120: 'heart_rate', + 121: 'bike_speed_cadence', + 122: 'bike_cadence', + 123: 'bike_speed', + 124: 'stride_speed_distance', + }, + ), + 'attitude_stage': FieldType( + name='attitude_stage', + base_type=BASE_TYPES[0x00], # enum + values={ + 0: 'failed', + 1: 'aligning', + 2: 'degraded', + 3: 'valid', + }, + ), + 'attitude_validity': FieldType( + name='attitude_validity', + base_type=BASE_TYPES[0x84], # uint16 + values={ + 0x0001: 'track_angle_heading_valid', + 0x0002: 'pitch_valid', + 0x0004: 'roll_valid', + 0x0008: 'lateral_body_accel_valid', + 0x0010: 'normal_body_accel_valid', + 0x0020: 'turn_rate_valid', + 0x0040: 'hw_fail', + 0x0080: 'mag_invalid', + 0x0100: 'no_gps', + 0x0200: 'gps_invalid', + 0x0400: 'solution_coasting', + 0x0800: 'true_track_angle', + 0x1000: 'magnetic_heading', + }, + ), + 'auto_activity_detect': FieldType( + name='auto_activity_detect', + base_type=BASE_TYPES[0x86], # uint32 + values={ + 0x00000000: 'none', + 0x00000001: 'running', + 0x00000002: 'cycling', + 0x00000004: 'swimming', + 0x00000008: 'walking', + 0x00000020: 'elliptical', + 0x00000400: 'sedentary', + }, + ), + 'auto_sync_frequency': FieldType( + name='auto_sync_frequency', + base_type=BASE_TYPES[0x00], # enum + values={ + 0: 'never', + 1: 'occasionally', + 2: 'frequent', + 3: 'once_a_day', + 4: 'remote', + }, + ), + 'autolap_trigger': FieldType( + name='autolap_trigger', + base_type=BASE_TYPES[0x00], # enum + values={ + 0: 'time', + 1: 'distance', + 2: 'position_start', + 3: 'position_lap', + 4: 'position_waypoint', + 5: 'position_marked', + 6: 'off', + }, + ), + 'autoscroll': FieldType( + name='autoscroll', + base_type=BASE_TYPES[0x00], # enum + values={ + 0: 'none', + 1: 'slow', + 2: 'medium', + 3: 'fast', + }, + ), + 'backlight_mode': FieldType( + name='backlight_mode', + base_type=BASE_TYPES[0x00], # enum + values={ + 0: 'off', + 1: 'manual', + 2: 'key_and_messages', + 3: 'auto_brightness', + 4: 'smart_notifications', + 5: 'key_and_messages_night', + 6: 'key_and_messages_and_smart_notifications', + }, + ), + 'backlight_timeout': FieldType( # Timeout in seconds. + name='backlight_timeout', + base_type=BASE_TYPES[0x02], # uint8 + values={ + 0: 'infinite', # Backlight stays on forever. + }, + ), + 'battery_status': FieldType( + name='battery_status', + base_type=BASE_TYPES[0x02], # uint8 + values={ + 1: 'new', + 2: 'good', + 3: 'ok', + 4: 'low', + 5: 'critical', + 6: 'charging', + 7: 'unknown', + }, + ), + 'bench_press_exercise_name': FieldType( + name='bench_press_exercise_name', + base_type=BASE_TYPES[0x84], # uint16 + values={ + 0: 'alternating_dumbbell_chest_press_on_swiss_ball', + 1: 'barbell_bench_press', + 2: 'barbell_board_bench_press', + 3: 'barbell_floor_press', + 4: 'close_grip_barbell_bench_press', + 5: 'decline_dumbbell_bench_press', + 6: 'dumbbell_bench_press', + 7: 'dumbbell_floor_press', + 8: 'incline_barbell_bench_press', + 9: 'incline_dumbbell_bench_press', + 10: 'incline_smith_machine_bench_press', + 11: 'isometric_barbell_bench_press', + 12: 'kettlebell_chest_press', + 13: 'neutral_grip_dumbbell_bench_press', + 14: 'neutral_grip_dumbbell_incline_bench_press', + 15: 'one_arm_floor_press', + 16: 'weighted_one_arm_floor_press', + 17: 'partial_lockout', + 18: 'reverse_grip_barbell_bench_press', + 19: 'reverse_grip_incline_bench_press', + 20: 'single_arm_cable_chest_press', + 21: 'single_arm_dumbbell_bench_press', + 22: 'smith_machine_bench_press', + 23: 'swiss_ball_dumbbell_chest_press', + 24: 'triple_stop_barbell_bench_press', + 25: 'wide_grip_barbell_bench_press', + 26: 'alternating_dumbbell_chest_press', + }, + ), + 'bike_light_beam_angle_mode': FieldType( + name='bike_light_beam_angle_mode', + base_type=BASE_TYPES[0x02], # uint8 + values={ + 0: 'manual', + 1: 'auto', + }, + ), + 'bike_light_network_config_type': FieldType( + name='bike_light_network_config_type', + base_type=BASE_TYPES[0x00], # enum + values={ + 0: 'auto', + 4: 'individual', + 5: 'high_visibility', + 6: 'trail', + }, + ), + 'body_location': FieldType( + name='body_location', + base_type=BASE_TYPES[0x00], # enum + values={ + 0: 'left_leg', + 1: 'left_calf', + 2: 'left_shin', + 3: 'left_hamstring', + 4: 'left_quad', + 5: 'left_glute', + 6: 'right_leg', + 7: 'right_calf', + 8: 'right_shin', + 9: 'right_hamstring', + 10: 'right_quad', + 11: 'right_glute', + 12: 'torso_back', + 13: 'left_lower_back', + 14: 'left_upper_back', + 15: 'right_lower_back', + 16: 'right_upper_back', + 17: 'torso_front', + 18: 'left_abdomen', + 19: 'left_chest', + 20: 'right_abdomen', + 21: 'right_chest', + 22: 'left_arm', + 23: 'left_shoulder', + 24: 'left_bicep', + 25: 'left_tricep', + 26: 'left_brachioradialis', # Left anterior forearm + 27: 'left_forearm_extensors', # Left posterior forearm + 28: 'right_arm', + 29: 'right_shoulder', + 30: 'right_bicep', + 31: 'right_tricep', + 32: 'right_brachioradialis', # Right anterior forearm + 33: 'right_forearm_extensors', # Right posterior forearm + 34: 'neck', + 35: 'throat', + 36: 'waist_mid_back', + 37: 'waist_front', + 38: 'waist_left', + 39: 'waist_right', + }, + ), + 'bool': FieldType( + name='bool', + base_type=BASE_TYPES[0x00], # enum + ), + 'bp_status': FieldType( + name='bp_status', + base_type=BASE_TYPES[0x00], # enum + values={ + 0: 'no_error', + 1: 'error_incomplete_data', + 2: 'error_no_measurement', + 3: 'error_data_out_of_range', + 4: 'error_irregular_heart_rate', + }, + ), + 'calf_raise_exercise_name': FieldType( + name='calf_raise_exercise_name', + base_type=BASE_TYPES[0x84], # uint16 + values={ + 0: '3_way_calf_raise', + 1: '3_way_weighted_calf_raise', + 2: '3_way_single_leg_calf_raise', + 3: '3_way_weighted_single_leg_calf_raise', + 4: 'donkey_calf_raise', + 5: 'weighted_donkey_calf_raise', + 6: 'seated_calf_raise', + 7: 'weighted_seated_calf_raise', + 8: 'seated_dumbbell_toe_raise', + 9: 'single_leg_bent_knee_calf_raise', + 10: 'weighted_single_leg_bent_knee_calf_raise', + 11: 'single_leg_decline_push_up', + 12: 'single_leg_donkey_calf_raise', + 13: 'weighted_single_leg_donkey_calf_raise', + 14: 'single_leg_hip_raise_with_knee_hold', + 15: 'single_leg_standing_calf_raise', + 16: 'single_leg_standing_dumbbell_calf_raise', + 17: 'standing_barbell_calf_raise', + 18: 'standing_calf_raise', + 19: 'weighted_standing_calf_raise', + 20: 'standing_dumbbell_calf_raise', + }, + ), + 'camera_event_type': FieldType( + name='camera_event_type', + base_type=BASE_TYPES[0x00], # enum + values={ + 0: 'video_start', # Start of video recording + 1: 'video_split', # Mark of video file split (end of one file, beginning of the other) + 2: 'video_end', # End of video recording + 3: 'photo_taken', # Still photo taken + 4: 'video_second_stream_start', + 5: 'video_second_stream_split', + 6: 'video_second_stream_end', + 7: 'video_split_start', # Mark of video file split start + 8: 'video_second_stream_split_start', + 11: 'video_pause', # Mark when a video recording has been paused + 12: 'video_second_stream_pause', + 13: 'video_resume', # Mark when a video recording has been resumed + 14: 'video_second_stream_resume', + }, + ), + 'camera_orientation_type': FieldType( + name='camera_orientation_type', + base_type=BASE_TYPES[0x00], # enum + values={ + 0: 'camera_orientation_0', + 1: 'camera_orientation_90', + 2: 'camera_orientation_180', + 3: 'camera_orientation_270', + }, + ), + 'cardio_exercise_name': FieldType( + name='cardio_exercise_name', + base_type=BASE_TYPES[0x84], # uint16 + values={ + 0: 'bob_and_weave_circle', + 1: 'weighted_bob_and_weave_circle', + 2: 'cardio_core_crawl', + 3: 'weighted_cardio_core_crawl', + 4: 'double_under', + 5: 'weighted_double_under', + 6: 'jump_rope', + 7: 'weighted_jump_rope', + 8: 'jump_rope_crossover', + 9: 'weighted_jump_rope_crossover', + 10: 'jump_rope_jog', + 11: 'weighted_jump_rope_jog', + 12: 'jumping_jacks', + 13: 'weighted_jumping_jacks', + 14: 'ski_moguls', + 15: 'weighted_ski_moguls', + 16: 'split_jacks', + 17: 'weighted_split_jacks', + 18: 'squat_jacks', + 19: 'weighted_squat_jacks', + 20: 'triple_under', + 21: 'weighted_triple_under', + }, + ), + 'carry_exercise_name': FieldType( + name='carry_exercise_name', + base_type=BASE_TYPES[0x84], # uint16 + values={ + 0: 'bar_holds', + 1: 'farmers_walk', + 2: 'farmers_walk_on_toes', + 3: 'hex_dumbbell_hold', + 4: 'overhead_carry', + }, + ), + 'checksum': FieldType( + name='checksum', + base_type=BASE_TYPES[0x02], # uint8 + values={ + 0: 'clear', # Allows clear of checksum for flash memory where can only write 1 to 0 without erasing sector. + 1: 'ok', # Set to mark checksum as valid if computes to invalid values 0 or 0xFF. Checksum can also be set to ok to save encoding computation time. + }, + ), + 'chop_exercise_name': FieldType( + name='chop_exercise_name', + base_type=BASE_TYPES[0x84], # uint16 + values={ + 0: 'cable_pull_through', + 1: 'cable_rotational_lift', + 2: 'cable_woodchop', + 3: 'cross_chop_to_knee', + 4: 'weighted_cross_chop_to_knee', + 5: 'dumbbell_chop', + 6: 'half_kneeling_rotation', + 7: 'weighted_half_kneeling_rotation', + 8: 'half_kneeling_rotational_chop', + 9: 'half_kneeling_rotational_reverse_chop', + 10: 'half_kneeling_stability_chop', + 11: 'half_kneeling_stability_reverse_chop', + 12: 'kneeling_rotational_chop', + 13: 'kneeling_rotational_reverse_chop', + 14: 'kneeling_stability_chop', + 15: 'kneeling_woodchopper', + 16: 'medicine_ball_wood_chops', + 17: 'power_squat_chops', + 18: 'weighted_power_squat_chops', + 19: 'standing_rotational_chop', + 20: 'standing_split_rotational_chop', + 21: 'standing_split_rotational_reverse_chop', + 22: 'standing_stability_reverse_chop', + }, + ), + 'comm_timeout_type': FieldType( + name='comm_timeout_type', + base_type=BASE_TYPES[0x84], # uint16 + values={ + 0: 'wildcard_pairing_timeout', # Timeout pairing to any device + 1: 'pairing_timeout', # Timeout pairing to previously paired device + 2: 'connection_lost', # Temporary loss of communications + 3: 'connection_timeout', # Connection closed due to extended bad communications + }, + ), + 'connectivity_capabilities': FieldType( + name='connectivity_capabilities', + base_type=BASE_TYPES[0x8C], # uint32z + values={ + 0x00000001: 'bluetooth', + 0x00000002: 'bluetooth_le', + 0x00000004: 'ant', + 0x00000008: 'activity_upload', + 0x00000010: 'course_download', + 0x00000020: 'workout_download', + 0x00000040: 'live_track', + 0x00000080: 'weather_conditions', + 0x00000100: 'weather_alerts', + 0x00000200: 'gps_ephemeris_download', + 0x00000400: 'explicit_archive', + 0x00000800: 'setup_incomplete', + 0x00001000: 'continue_sync_after_software_update', + 0x00002000: 'connect_iq_app_download', + 0x00004000: 'golf_course_download', + 0x00008000: 'device_initiates_sync', # Indicates device is in control of initiating all syncs + 0x00010000: 'connect_iq_watch_app_download', + 0x00020000: 'connect_iq_widget_download', + 0x00040000: 'connect_iq_watch_face_download', + 0x00080000: 'connect_iq_data_field_download', + 0x00100000: 'connect_iq_app_managment', # Device supports delete and reorder of apps via GCM + 0x00200000: 'swing_sensor', + 0x00400000: 'swing_sensor_remote', + 0x00800000: 'incident_detection', # Device supports incident detection + 0x01000000: 'audio_prompts', + 0x02000000: 'wifi_verification', # Device supports reporting wifi verification via GCM + 0x04000000: 'true_up', # Device supports True Up + 0x08000000: 'find_my_watch', # Device supports Find My Watch + 0x10000000: 'remote_manual_sync', + 0x20000000: 'live_track_auto_start', # Device supports LiveTrack auto start + 0x40000000: 'live_track_messaging', # Device supports LiveTrack Messaging + 0x80000000: 'instant_input', # Device supports instant input feature + }, + ), + 'core_exercise_name': FieldType( + name='core_exercise_name', + base_type=BASE_TYPES[0x84], # uint16 + values={ + 0: 'abs_jabs', + 1: 'weighted_abs_jabs', + 2: 'alternating_plate_reach', + 3: 'barbell_rollout', + 4: 'weighted_barbell_rollout', + 5: 'body_bar_oblique_twist', + 6: 'cable_core_press', + 7: 'cable_side_bend', + 8: 'side_bend', + 9: 'weighted_side_bend', + 10: 'crescent_circle', + 11: 'weighted_crescent_circle', + 12: 'cycling_russian_twist', + 13: 'weighted_cycling_russian_twist', + 14: 'elevated_feet_russian_twist', + 15: 'weighted_elevated_feet_russian_twist', + 16: 'half_turkish_get_up', + 17: 'kettlebell_windmill', + 18: 'kneeling_ab_wheel', + 19: 'weighted_kneeling_ab_wheel', + 20: 'modified_front_lever', + 21: 'open_knee_tucks', + 22: 'weighted_open_knee_tucks', + 23: 'side_abs_leg_lift', + 24: 'weighted_side_abs_leg_lift', + 25: 'swiss_ball_jackknife', + 26: 'weighted_swiss_ball_jackknife', + 27: 'swiss_ball_pike', + 28: 'weighted_swiss_ball_pike', + 29: 'swiss_ball_rollout', + 30: 'weighted_swiss_ball_rollout', + 31: 'triangle_hip_press', + 32: 'weighted_triangle_hip_press', + 33: 'trx_suspended_jackknife', + 34: 'weighted_trx_suspended_jackknife', + 35: 'u_boat', + 36: 'weighted_u_boat', + 37: 'windmill_switches', + 38: 'weighted_windmill_switches', + 39: 'alternating_slide_out', + 40: 'weighted_alternating_slide_out', + 41: 'ghd_back_extensions', + 42: 'weighted_ghd_back_extensions', + 43: 'overhead_walk', + 44: 'inchworm', + 45: 'weighted_modified_front_lever', + }, + ), + 'course_capabilities': FieldType( + name='course_capabilities', + base_type=BASE_TYPES[0x8C], # uint32z + values={ + 0x00000001: 'processed', + 0x00000002: 'valid', + 0x00000004: 'time', + 0x00000008: 'distance', + 0x00000010: 'position', + 0x00000020: 'heart_rate', + 0x00000040: 'power', + 0x00000080: 'cadence', + 0x00000100: 'training', + 0x00000200: 'navigation', + 0x00000400: 'bikeway', + }, + ), + 'course_point': FieldType( + name='course_point', + base_type=BASE_TYPES[0x00], # enum + values={ + 0: 'generic', + 1: 'summit', + 2: 'valley', + 3: 'water', + 4: 'food', + 5: 'danger', + 6: 'left', + 7: 'right', + 8: 'straight', + 9: 'first_aid', + 10: 'fourth_category', + 11: 'third_category', + 12: 'second_category', + 13: 'first_category', + 14: 'hors_category', + 15: 'sprint', + 16: 'left_fork', + 17: 'right_fork', + 18: 'middle_fork', + 19: 'slight_left', + 20: 'sharp_left', + 21: 'slight_right', + 22: 'sharp_right', + 23: 'u_turn', + 24: 'segment_start', + 25: 'segment_end', + }, + ), + 'crunch_exercise_name': FieldType( + name='crunch_exercise_name', + base_type=BASE_TYPES[0x84], # uint16 + values={ + 0: 'bicycle_crunch', + 1: 'cable_crunch', + 2: 'circular_arm_crunch', + 3: 'crossed_arms_crunch', + 4: 'weighted_crossed_arms_crunch', + 5: 'cross_leg_reverse_crunch', + 6: 'weighted_cross_leg_reverse_crunch', + 7: 'crunch_chop', + 8: 'weighted_crunch_chop', + 9: 'double_crunch', + 10: 'weighted_double_crunch', + 11: 'elbow_to_knee_crunch', + 12: 'weighted_elbow_to_knee_crunch', + 13: 'flutter_kicks', + 14: 'weighted_flutter_kicks', + 15: 'foam_roller_reverse_crunch_on_bench', + 16: 'weighted_foam_roller_reverse_crunch_on_bench', + 17: 'foam_roller_reverse_crunch_with_dumbbell', + 18: 'foam_roller_reverse_crunch_with_medicine_ball', + 19: 'frog_press', + 20: 'hanging_knee_raise_oblique_crunch', + 21: 'weighted_hanging_knee_raise_oblique_crunch', + 22: 'hip_crossover', + 23: 'weighted_hip_crossover', + 24: 'hollow_rock', + 25: 'weighted_hollow_rock', + 26: 'incline_reverse_crunch', + 27: 'weighted_incline_reverse_crunch', + 28: 'kneeling_cable_crunch', + 29: 'kneeling_cross_crunch', + 30: 'weighted_kneeling_cross_crunch', + 31: 'kneeling_oblique_cable_crunch', + 32: 'knees_to_elbow', + 33: 'leg_extensions', + 34: 'weighted_leg_extensions', + 35: 'leg_levers', + 36: 'mcgill_curl_up', + 37: 'weighted_mcgill_curl_up', + 38: 'modified_pilates_roll_up_with_ball', + 39: 'weighted_modified_pilates_roll_up_with_ball', + 40: 'pilates_crunch', + 41: 'weighted_pilates_crunch', + 42: 'pilates_roll_up_with_ball', + 43: 'weighted_pilates_roll_up_with_ball', + 44: 'raised_legs_crunch', + 45: 'weighted_raised_legs_crunch', + 46: 'reverse_crunch', + 47: 'weighted_reverse_crunch', + 48: 'reverse_crunch_on_a_bench', + 49: 'weighted_reverse_crunch_on_a_bench', + 50: 'reverse_curl_and_lift', + 51: 'weighted_reverse_curl_and_lift', + 52: 'rotational_lift', + 53: 'weighted_rotational_lift', + 54: 'seated_alternating_reverse_crunch', + 55: 'weighted_seated_alternating_reverse_crunch', + 56: 'seated_leg_u', + 57: 'weighted_seated_leg_u', + 58: 'side_to_side_crunch_and_weave', + 59: 'weighted_side_to_side_crunch_and_weave', + 60: 'single_leg_reverse_crunch', + 61: 'weighted_single_leg_reverse_crunch', + 62: 'skater_crunch_cross', + 63: 'weighted_skater_crunch_cross', + 64: 'standing_cable_crunch', + 65: 'standing_side_crunch', + 66: 'step_climb', + 67: 'weighted_step_climb', + 68: 'swiss_ball_crunch', + 69: 'swiss_ball_reverse_crunch', + 70: 'weighted_swiss_ball_reverse_crunch', + 71: 'swiss_ball_russian_twist', + 72: 'weighted_swiss_ball_russian_twist', + 73: 'swiss_ball_side_crunch', + 74: 'weighted_swiss_ball_side_crunch', + 75: 'thoracic_crunches_on_foam_roller', + 76: 'weighted_thoracic_crunches_on_foam_roller', + 77: 'triceps_crunch', + 78: 'weighted_bicycle_crunch', + 79: 'weighted_crunch', + 80: 'weighted_swiss_ball_crunch', + 81: 'toes_to_bar', + 82: 'weighted_toes_to_bar', + 83: 'crunch', + }, + ), + 'curl_exercise_name': FieldType( + name='curl_exercise_name', + base_type=BASE_TYPES[0x84], # uint16 + values={ + 0: 'alternating_dumbbell_biceps_curl', + 1: 'alternating_dumbbell_biceps_curl_on_swiss_ball', + 2: 'alternating_incline_dumbbell_biceps_curl', + 3: 'barbell_biceps_curl', + 4: 'barbell_reverse_wrist_curl', + 5: 'barbell_wrist_curl', + 6: 'behind_the_back_barbell_reverse_wrist_curl', + 7: 'behind_the_back_one_arm_cable_curl', + 8: 'cable_biceps_curl', + 9: 'cable_hammer_curl', + 10: 'cheating_barbell_biceps_curl', + 11: 'close_grip_ez_bar_biceps_curl', + 12: 'cross_body_dumbbell_hammer_curl', + 13: 'dead_hang_biceps_curl', + 14: 'decline_hammer_curl', + 15: 'dumbbell_biceps_curl_with_static_hold', + 16: 'dumbbell_hammer_curl', + 17: 'dumbbell_reverse_wrist_curl', + 18: 'dumbbell_wrist_curl', + 19: 'ez_bar_preacher_curl', + 20: 'forward_bend_biceps_curl', + 21: 'hammer_curl_to_press', + 22: 'incline_dumbbell_biceps_curl', + 23: 'incline_offset_thumb_dumbbell_curl', + 24: 'kettlebell_biceps_curl', + 25: 'lying_concentration_cable_curl', + 26: 'one_arm_preacher_curl', + 27: 'plate_pinch_curl', + 28: 'preacher_curl_with_cable', + 29: 'reverse_ez_bar_curl', + 30: 'reverse_grip_wrist_curl', + 31: 'reverse_grip_barbell_biceps_curl', + 32: 'seated_alternating_dumbbell_biceps_curl', + 33: 'seated_dumbbell_biceps_curl', + 34: 'seated_reverse_dumbbell_curl', + 35: 'split_stance_offset_pinky_dumbbell_curl', + 36: 'standing_alternating_dumbbell_curls', + 37: 'standing_dumbbell_biceps_curl', + 38: 'standing_ez_bar_biceps_curl', + 39: 'static_curl', + 40: 'swiss_ball_dumbbell_overhead_triceps_extension', + 41: 'swiss_ball_ez_bar_preacher_curl', + 42: 'twisting_standing_dumbbell_biceps_curl', + 43: 'wide_grip_ez_bar_biceps_curl', + }, + ), + 'date_mode': FieldType( + name='date_mode', + base_type=BASE_TYPES[0x00], # enum + values={ + 0: 'day_month', + 1: 'month_day', + }, + ), + 'date_time': FieldType( # seconds since UTC 00:00 Dec 31 1989 + name='date_time', + base_type=BASE_TYPES[0x86], # uint32 + ), + 'day_of_week': FieldType( + name='day_of_week', + base_type=BASE_TYPES[0x00], # enum + values={ + 0: 'sunday', + 1: 'monday', + 2: 'tuesday', + 3: 'wednesday', + 4: 'thursday', + 5: 'friday', + 6: 'saturday', + }, + ), + 'deadlift_exercise_name': FieldType( + name='deadlift_exercise_name', + base_type=BASE_TYPES[0x84], # uint16 + values={ + 0: 'barbell_deadlift', + 1: 'barbell_straight_leg_deadlift', + 2: 'dumbbell_deadlift', + 3: 'dumbbell_single_leg_deadlift_to_row', + 4: 'dumbbell_straight_leg_deadlift', + 5: 'kettlebell_floor_to_shelf', + 6: 'one_arm_one_leg_deadlift', + 7: 'rack_pull', + 8: 'rotational_dumbbell_straight_leg_deadlift', + 9: 'single_arm_deadlift', + 10: 'single_leg_barbell_deadlift', + 11: 'single_leg_barbell_straight_leg_deadlift', + 12: 'single_leg_deadlift_with_barbell', + 13: 'single_leg_rdl_circuit', + 14: 'single_leg_romanian_deadlift_with_dumbbell', + 15: 'sumo_deadlift', + 16: 'sumo_deadlift_high_pull', + 17: 'trap_bar_deadlift', + 18: 'wide_grip_barbell_deadlift', + }, + ), + 'device_index': FieldType( + name='device_index', + base_type=BASE_TYPES[0x02], # uint8 + values={ + 0: 'creator', # Creator of the file is always device index 0. + }, + ), + 'digital_watchface_layout': FieldType( + name='digital_watchface_layout', + base_type=BASE_TYPES[0x00], # enum + values={ + 0: 'traditional', + 1: 'modern', + 2: 'bold', + }, + ), + 'display_heart': FieldType( + name='display_heart', + base_type=BASE_TYPES[0x00], # enum + values={ + 0: 'bpm', + 1: 'max', + 2: 'reserve', + }, + ), + 'display_measure': FieldType( + name='display_measure', + base_type=BASE_TYPES[0x00], # enum + values={ + 0: 'metric', + 1: 'statute', + 2: 'nautical', + }, + ), + 'display_orientation': FieldType( + name='display_orientation', + base_type=BASE_TYPES[0x00], # enum + values={ + 0: 'auto', # automatic if the device supports it + 1: 'portrait', + 2: 'landscape', + 3: 'portrait_flipped', # portrait mode but rotated 180 degrees + 4: 'landscape_flipped', # landscape mode but rotated 180 degrees + }, + ), + 'display_position': FieldType( + name='display_position', + base_type=BASE_TYPES[0x00], # enum + values={ + 0: 'degree', # dd.dddddd + 1: 'degree_minute', # dddmm.mmm + 2: 'degree_minute_second', # dddmmss + 3: 'austrian_grid', # Austrian Grid (BMN) + 4: 'british_grid', # British National Grid + 5: 'dutch_grid', # Dutch grid system + 6: 'hungarian_grid', # Hungarian grid system + 7: 'finnish_grid', # Finnish grid system Zone3 KKJ27 + 8: 'german_grid', # Gausss Krueger (German) + 9: 'icelandic_grid', # Icelandic Grid + 10: 'indonesian_equatorial', # Indonesian Equatorial LCO + 11: 'indonesian_irian', # Indonesian Irian LCO + 12: 'indonesian_southern', # Indonesian Southern LCO + 13: 'india_zone_0', # India zone 0 + 14: 'india_zone_IA', # India zone IA + 15: 'india_zone_IB', # India zone IB + 16: 'india_zone_IIA', # India zone IIA + 17: 'india_zone_IIB', # India zone IIB + 18: 'india_zone_IIIA', # India zone IIIA + 19: 'india_zone_IIIB', # India zone IIIB + 20: 'india_zone_IVA', # India zone IVA + 21: 'india_zone_IVB', # India zone IVB + 22: 'irish_transverse', # Irish Transverse Mercator + 23: 'irish_grid', # Irish Grid + 24: 'loran', # Loran TD + 25: 'maidenhead_grid', # Maidenhead grid system + 26: 'mgrs_grid', # MGRS grid system + 27: 'new_zealand_grid', # New Zealand grid system + 28: 'new_zealand_transverse', # New Zealand Transverse Mercator + 29: 'qatar_grid', # Qatar National Grid + 30: 'modified_swedish_grid', # Modified RT-90 (Sweden) + 31: 'swedish_grid', # RT-90 (Sweden) + 32: 'south_african_grid', # South African Grid + 33: 'swiss_grid', # Swiss CH-1903 grid + 34: 'taiwan_grid', # Taiwan Grid + 35: 'united_states_grid', # United States National Grid + 36: 'utm_ups_grid', # UTM/UPS grid system + 37: 'west_malayan', # West Malayan RSO + 38: 'borneo_rso', # Borneo RSO + 39: 'estonian_grid', # Estonian grid system + 40: 'latvian_grid', # Latvian Transverse Mercator + 41: 'swedish_ref_99_grid', # Reference Grid 99 TM (Swedish) + }, + ), + 'display_power': FieldType( + name='display_power', + base_type=BASE_TYPES[0x00], # enum + values={ + 0: 'watts', + 1: 'percent_ftp', + }, + ), + 'dive_alarm_type': FieldType( + name='dive_alarm_type', + base_type=BASE_TYPES[0x00], # enum + values={ + 0: 'depth', + 1: 'time', + }, + ), + 'dive_backlight_mode': FieldType( + name='dive_backlight_mode', + base_type=BASE_TYPES[0x00], # enum + values={ + 0: 'at_depth', + 1: 'always_on', + }, + ), + 'dive_gas_status': FieldType( + name='dive_gas_status', + base_type=BASE_TYPES[0x00], # enum + values={ + 0: 'disabled', + 1: 'enabled', + 2: 'backup_only', + }, + ), + 'event': FieldType( + name='event', + base_type=BASE_TYPES[0x00], # enum + values={ + 0: 'timer', # Group 0. Start / stop_all + 3: 'workout', # start / stop + 4: 'workout_step', # Start at beginning of workout. Stop at end of each step. + 5: 'power_down', # stop_all group 0 + 6: 'power_up', # stop_all group 0 + 7: 'off_course', # start / stop group 0 + 8: 'session', # Stop at end of each session. + 9: 'lap', # Stop at end of each lap. + 10: 'course_point', # marker + 11: 'battery', # marker + 12: 'virtual_partner_pace', # Group 1. Start at beginning of activity if VP enabled, when VP pace is changed during activity or VP enabled mid activity. stop_disable when VP disabled. + 13: 'hr_high_alert', # Group 0. Start / stop when in alert condition. + 14: 'hr_low_alert', # Group 0. Start / stop when in alert condition. + 15: 'speed_high_alert', # Group 0. Start / stop when in alert condition. + 16: 'speed_low_alert', # Group 0. Start / stop when in alert condition. + 17: 'cad_high_alert', # Group 0. Start / stop when in alert condition. + 18: 'cad_low_alert', # Group 0. Start / stop when in alert condition. + 19: 'power_high_alert', # Group 0. Start / stop when in alert condition. + 20: 'power_low_alert', # Group 0. Start / stop when in alert condition. + 21: 'recovery_hr', # marker + 22: 'battery_low', # marker + 23: 'time_duration_alert', # Group 1. Start if enabled mid activity (not required at start of activity). Stop when duration is reached. stop_disable if disabled. + 24: 'distance_duration_alert', # Group 1. Start if enabled mid activity (not required at start of activity). Stop when duration is reached. stop_disable if disabled. + 25: 'calorie_duration_alert', # Group 1. Start if enabled mid activity (not required at start of activity). Stop when duration is reached. stop_disable if disabled. + 26: 'activity', # Group 1.. Stop at end of activity. + 27: 'fitness_equipment', # marker + 28: 'length', # Stop at end of each length. + 32: 'user_marker', # marker + 33: 'sport_point', # marker + 36: 'calibration', # start/stop/marker + 42: 'front_gear_change', # marker + 43: 'rear_gear_change', # marker + 44: 'rider_position_change', # marker + 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 + }, + ), + 'event_type': FieldType( + name='event_type', + base_type=BASE_TYPES[0x00], # enum + values={ + 0: 'start', + 1: 'stop', + 2: 'consecutive_depreciated', + 3: 'marker', + 4: 'stop_all', + 5: 'begin_depreciated', + 6: 'end_depreciated', + 7: 'end_all_depreciated', + 8: 'stop_disable', + 9: 'stop_disable_all', + }, + ), + 'exd_data_units': FieldType( + name='exd_data_units', + base_type=BASE_TYPES[0x00], # enum + values={ + 0: 'no_units', + 1: 'laps', + 2: 'miles_per_hour', + 3: 'kilometers_per_hour', + 4: 'feet_per_hour', + 5: 'meters_per_hour', + 6: 'degrees_celsius', + 7: 'degrees_farenheit', + 8: 'zone', + 9: 'gear', + 10: 'rpm', + 11: 'bpm', + 12: 'degrees', + 13: 'millimeters', + 14: 'meters', + 15: 'kilometers', + 16: 'feet', + 17: 'yards', + 18: 'kilofeet', + 19: 'miles', + 20: 'time', + 21: 'enum_turn_type', + 22: 'percent', + 23: 'watts', + 24: 'watts_per_kilogram', + 25: 'enum_battery_status', + 26: 'enum_bike_light_beam_angle_mode', + 27: 'enum_bike_light_battery_status', + 28: 'enum_bike_light_network_config_type', + 29: 'lights', + 30: 'seconds', + 31: 'minutes', + 32: 'hours', + 33: 'calories', + 34: 'kilojoules', + 35: 'milliseconds', + 36: 'second_per_mile', + 37: 'second_per_kilometer', + 38: 'centimeter', + 39: 'enum_course_point', + 40: 'bradians', + 41: 'enum_sport', + 42: 'inches_hg', + 43: 'mm_hg', + 44: 'mbars', + 45: 'hecto_pascals', + 46: 'feet_per_min', + 47: 'meters_per_min', + 48: 'meters_per_sec', + 49: 'eight_cardinal', + }, + ), + 'exd_descriptors': FieldType( + name='exd_descriptors', + base_type=BASE_TYPES[0x00], # enum + values={ + 0: 'bike_light_battery_status', + 1: 'beam_angle_status', + 2: 'batery_level', + 3: 'light_network_mode', + 4: 'number_lights_connected', + 5: 'cadence', + 6: 'distance', + 7: 'estimated_time_of_arrival', + 8: 'heading', + 9: 'time', + 10: 'battery_level', + 11: 'trainer_resistance', + 12: 'trainer_target_power', + 13: 'time_seated', + 14: 'time_standing', + 15: 'elevation', + 16: 'grade', + 17: 'ascent', + 18: 'descent', + 19: 'vertical_speed', + 20: 'di2_battery_level', + 21: 'front_gear', + 22: 'rear_gear', + 23: 'gear_ratio', + 24: 'heart_rate', + 25: 'heart_rate_zone', + 26: 'time_in_heart_rate_zone', + 27: 'heart_rate_reserve', + 28: 'calories', + 29: 'gps_accuracy', + 30: 'gps_signal_strength', + 31: 'temperature', + 32: 'time_of_day', + 33: 'balance', + 34: 'pedal_smoothness', + 35: 'power', + 36: 'functional_threshold_power', + 37: 'intensity_factor', + 38: 'work', + 39: 'power_ratio', + 40: 'normalized_power', + 41: 'training_stress_Score', + 42: 'time_on_zone', + 43: 'speed', + 44: 'laps', + 45: 'reps', + 46: 'workout_step', + 47: 'course_distance', + 48: 'navigation_distance', + 49: 'course_estimated_time_of_arrival', + 50: 'navigation_estimated_time_of_arrival', + 51: 'course_time', + 52: 'navigation_time', + 53: 'course_heading', + 54: 'navigation_heading', + 55: 'power_zone', + 56: 'torque_effectiveness', + 57: 'timer_time', + 58: 'power_weight_ratio', + 59: 'left_platform_center_offset', + 60: 'right_platform_center_offset', + 61: 'left_power_phase_start_angle', + 62: 'right_power_phase_start_angle', + 63: 'left_power_phase_finish_angle', + 64: 'right_power_phase_finish_angle', + 65: 'gears', # Combined gear information + 66: 'pace', + 67: 'training_effect', + 68: 'vertical_oscillation', + 69: 'vertical_ratio', + 70: 'ground_contact_time', + 71: 'left_ground_contact_time_balance', + 72: 'right_ground_contact_time_balance', + 73: 'stride_length', + 74: 'running_cadence', + 75: 'performance_condition', + 76: 'course_type', + 77: 'time_in_power_zone', + 78: 'navigation_turn', + 79: 'course_location', + 80: 'navigation_location', + 81: 'compass', + 82: 'gear_combo', + 83: 'muscle_oxygen', + 84: 'icon', + 85: 'compass_heading', + 86: 'gps_heading', + 87: 'gps_elevation', + 88: 'anaerobic_training_effect', + 89: 'course', + 90: 'off_course', + 91: 'glide_ratio', + 92: 'vertical_distance', + 93: 'vmg', + 94: 'ambient_pressure', + 95: 'pressure', + 96: 'vam', + }, + ), + 'exd_display_type': FieldType( + name='exd_display_type', + base_type=BASE_TYPES[0x00], # enum + values={ + 0: 'numerical', + 1: 'simple', + 2: 'graph', + 3: 'bar', + 4: 'circle_graph', + 5: 'virtual_partner', + 6: 'balance', + 7: 'string_list', + 8: 'string', + 9: 'simple_dynamic_icon', + 10: 'gauge', + }, + ), + 'exd_layout': FieldType( + name='exd_layout', + base_type=BASE_TYPES[0x00], # enum + values={ + 0: 'full_screen', + 1: 'half_vertical', + 2: 'half_horizontal', + 3: 'half_vertical_right_split', + 4: 'half_horizontal_bottom_split', + 5: 'full_quarter_split', + 6: 'half_vertical_left_split', + 7: 'half_horizontal_top_split', + }, + ), + 'exd_qualifiers': FieldType( + name='exd_qualifiers', + base_type=BASE_TYPES[0x00], # enum + values={ + 0: 'no_qualifier', + 1: 'instantaneous', + 2: 'average', + 3: 'lap', + 4: 'maximum', + 5: 'maximum_average', + 6: 'maximum_lap', + 7: 'last_lap', + 8: 'average_lap', + 9: 'to_destination', + 10: 'to_go', + 11: 'to_next', + 12: 'next_course_point', + 13: 'total', + 14: 'three_second_average', + 15: 'ten_second_average', + 16: 'thirty_second_average', + 17: 'percent_maximum', + 18: 'percent_maximum_average', + 19: 'lap_percent_maximum', + 20: 'elapsed', + 21: 'sunrise', + 22: 'sunset', + 23: 'compared_to_virtual_partner', + 24: 'maximum_24h', + 25: 'minimum_24h', + 26: 'minimum', + 27: 'first', + 28: 'second', + 29: 'third', + 30: 'shifter', + 31: 'last_sport', + 32: 'moving', + 33: 'stopped', + 34: 'estimated_total', + 242: 'zone_9', + 243: 'zone_8', + 244: 'zone_7', + 245: 'zone_6', + 246: 'zone_5', + 247: 'zone_4', + 248: 'zone_3', + 249: 'zone_2', + 250: 'zone_1', + }, + ), + 'exercise_category': FieldType( + name='exercise_category', + base_type=BASE_TYPES[0x84], # uint16 + values={ + 0: 'bench_press', + 1: 'calf_raise', + 2: 'cardio', + 3: 'carry', + 4: 'chop', + 5: 'core', + 6: 'crunch', + 7: 'curl', + 8: 'deadlift', + 9: 'flye', + 10: 'hip_raise', + 11: 'hip_stability', + 12: 'hip_swing', + 13: 'hyperextension', + 14: 'lateral_raise', + 15: 'leg_curl', + 16: 'leg_raise', + 17: 'lunge', + 18: 'olympic_lift', + 19: 'plank', + 20: 'plyo', + 21: 'pull_up', + 22: 'push_up', + 23: 'row', + 24: 'shoulder_press', + 25: 'shoulder_stability', + 26: 'shrug', + 27: 'sit_up', + 28: 'squat', + 29: 'total_body', + 30: 'triceps_extension', + 31: 'warm_up', + 32: 'run', + 65534: 'unknown', + }, + ), + 'file': FieldType( + name='file', + base_type=BASE_TYPES[0x00], # enum + values={ + 1: 'device', # Read only, single file. Must be in root directory. + 2: 'settings', # Read/write, single file. Directory=Settings + 3: 'sport', # Read/write, multiple files, file number = sport type. Directory=Sports + 4: 'activity', # Read/erase, multiple files. Directory=Activities + 5: 'workout', # Read/write/erase, multiple files. Directory=Workouts + 6: 'course', # Read/write/erase, multiple files. Directory=Courses + 7: 'schedules', # Read/write, single file. Directory=Schedules + 9: 'weight', # Read only, single file. Circular buffer. All message definitions at start of file. Directory=Weight + 10: 'totals', # Read only, single file. Directory=Totals + 11: 'goals', # Read/write, single file. Directory=Goals + 14: 'blood_pressure', # Read only. Directory=Blood Pressure + 15: 'monitoring_a', # Read only. Directory=Monitoring. File number=sub type. + 20: 'activity_summary', # Read/erase, multiple files. Directory=Activities + 28: 'monitoring_daily', + 32: 'monitoring_b', # Read only. Directory=Monitoring. File number=identifier + 34: 'segment', # Read/write/erase. Multiple Files. Directory=Segments + 35: 'segment_list', # Read/write/erase. Single File. Directory=Segments + 40: 'exd_configuration', # Read/write/erase. Single File. Directory=Settings + 0xF7: 'mfg_range_min', # 0xF7 - 0xFE reserved for manufacturer specific file types + 0xFE: 'mfg_range_max', # 0xF7 - 0xFE reserved for manufacturer specific file types + }, + ), + 'file_flags': FieldType( + name='file_flags', + base_type=BASE_TYPES[0x0A], # uint8z + values={ + 0x02: 'read', + 0x04: 'write', + 0x08: 'erase', + }, + ), + 'fit_base_type': FieldType( + name='fit_base_type', + base_type=BASE_TYPES[0x02], # uint8 + values={ + 0: 'enum', + 1: 'sint8', + 2: 'uint8', + 7: 'string', + 10: 'uint8z', + 13: 'byte', + 131: 'sint16', + 132: 'uint16', + 133: 'sint32', + 134: 'uint32', + 136: 'float32', + 137: 'float64', + 139: 'uint16z', + 140: 'uint32z', + 142: 'sint64', + 143: 'uint64', + 144: 'uint64z', + }, + ), + 'fit_base_unit': FieldType( + name='fit_base_unit', + base_type=BASE_TYPES[0x84], # uint16 + values={ + 0: 'other', + 1: 'kilogram', + 2: 'pound', + }, + ), + 'fitness_equipment_state': FieldType( # fitness equipment event data + name='fitness_equipment_state', + base_type=BASE_TYPES[0x00], # enum + values={ + 0: 'ready', + 1: 'in_use', + 2: 'paused', + 3: 'unknown', # lost connection to fitness equipment + }, + ), + 'flye_exercise_name': FieldType( + name='flye_exercise_name', + base_type=BASE_TYPES[0x84], # uint16 + values={ + 0: 'cable_crossover', + 1: 'decline_dumbbell_flye', + 2: 'dumbbell_flye', + 3: 'incline_dumbbell_flye', + 4: 'kettlebell_flye', + 5: 'kneeling_rear_flye', + 6: 'single_arm_standing_cable_reverse_flye', + 7: 'swiss_ball_dumbbell_flye', + }, + ), + 'garmin_product': FieldType( + name='garmin_product', + base_type=BASE_TYPES[0x84], # uint16 + values={ + 1: 'hrm1', + 2: 'axh01', # AXH01 HRM chipset + 3: 'axb01', + 4: 'axb02', + 5: 'hrm2ss', + 6: 'dsi_alf02', + 7: 'hrm3ss', + 8: 'hrm_run_single_byte_product_id', # hrm_run model for HRM ANT+ messaging + 9: 'bsm', # BSM model for ANT+ messaging + 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 + 14: 'fr225_single_byte_product_id', # fr225 model for HRM ANT+ messaging + 473: 'fr301_china', + 474: 'fr301_japan', + 475: 'fr301_korea', + 494: 'fr301_taiwan', + 717: 'fr405', # Forerunner 405 + 782: 'fr50', # Forerunner 50 + 987: 'fr405_japan', + 988: 'fr60', # Forerunner 60 + 1011: 'dsi_alf01', + 1018: 'fr310xt', # Forerunner 310 + 1036: 'edge500', + 1124: 'fr110', # Forerunner 110 + 1169: 'edge800', + 1199: 'edge500_taiwan', + 1213: 'edge500_japan', + 1253: 'chirp', + 1274: 'fr110_japan', + 1325: 'edge200', + 1328: 'fr910xt', + 1333: 'edge800_taiwan', + 1334: 'edge800_japan', + 1341: 'alf04', + 1345: 'fr610', + 1360: 'fr210_japan', + 1380: 'vector_ss', + 1381: 'vector_cp', + 1386: 'edge800_china', + 1387: 'edge500_china', + 1410: 'fr610_japan', + 1422: 'edge500_korea', + 1436: 'fr70', + 1446: 'fr310xt_4t', + 1461: 'amx', + 1482: 'fr10', + 1497: 'edge800_korea', + 1499: 'swim', + 1537: 'fr910xt_china', + 1551: 'fenix', + 1555: 'edge200_taiwan', + 1561: 'edge510', + 1567: 'edge810', + 1570: 'tempe', + 1600: 'fr910xt_japan', + 1623: 'fr620', + 1632: 'fr220', + 1664: 'fr910xt_korea', + 1688: 'fr10_japan', + 1721: 'edge810_japan', + 1735: 'virb_elite', + 1736: 'edge_touring', # Also Edge Touring Plus + 1742: 'edge510_japan', + 1743: 'hrm_tri', + 1752: 'hrm_run', + 1765: 'fr920xt', + 1821: 'edge510_asia', + 1822: 'edge810_china', + 1823: 'edge810_taiwan', + 1836: 'edge1000', + 1837: 'vivo_fit', + 1853: 'virb_remote', + 1885: 'vivo_ki', + 1903: 'fr15', + 1907: 'vivo_active', + 1918: 'edge510_korea', + 1928: 'fr620_japan', + 1929: 'fr620_china', + 1930: 'fr220_japan', + 1931: 'fr220_china', + 1936: 'approach_s6', + 1956: 'vivo_smart', + 1967: 'fenix2', + 1988: 'epix', + 2050: 'fenix3', + 2052: 'edge1000_taiwan', + 2053: 'edge1000_japan', + 2061: 'fr15_japan', + 2067: 'edge520', + 2070: 'edge1000_china', + 2072: 'fr620_russia', + 2073: 'fr220_russia', + 2079: 'vector_s', + 2100: 'edge1000_korea', + 2130: 'fr920xt_taiwan', + 2131: 'fr920xt_china', + 2132: 'fr920xt_japan', + 2134: 'virbx', + 2135: 'vivo_smart_apac', + 2140: 'etrex_touch', + 2147: 'edge25', + 2148: 'fr25', + 2150: 'vivo_fit2', + 2153: 'fr225', + 2156: 'fr630', + 2157: 'fr230', + 2160: 'vivo_active_apac', + 2161: 'vector_2', + 2162: 'vector_2s', + 2172: 'virbxe', + 2173: 'fr620_taiwan', + 2174: 'fr220_taiwan', + 2175: 'truswing', + 2188: 'fenix3_china', + 2189: 'fenix3_twn', + 2192: 'varia_headlight', + 2193: 'varia_taillight_old', + 2204: 'edge_explore_1000', + 2219: 'fr225_asia', + 2225: 'varia_radar_taillight', + 2226: 'varia_radar_display', + 2238: 'edge20', + 2262: 'd2_bravo', + 2266: 'approach_s20', + 2276: 'varia_remote', + 2327: 'hrm4_run', + 2337: 'vivo_active_hr', + 2347: 'vivo_smart_gps_hr', + 2348: 'vivo_smart_hr', + 2368: 'vivo_move', + 2398: 'varia_vision', + 2406: 'vivo_fit3', + 2413: 'fenix3_hr', + 2417: 'virb_ultra_30', + 2429: 'index_smart_scale', + 2431: 'fr235', + 2432: 'fenix3_chronos', + 2441: 'oregon7xx', + 2444: 'rino7xx', + 2496: 'nautix', + 2530: 'edge_820', + 2531: 'edge_explore_820', + 2544: 'fenix5s', + 2547: 'd2_bravo_titanium', + 2567: 'varia_ut800', # Varia UT 800 SW + 2593: 'running_dynamics_pod', + 2604: 'fenix5x', + 2606: 'vivo_fit_jr', + 2691: 'fr935', + 2697: 'fenix5', + 10007: 'sdm4', # SDM4 footpod + 10014: 'edge_remote', + 20119: 'training_center', + 65531: 'connectiq_simulator', + 65532: 'android_antplus_plugin', + 65534: 'connect', # Garmin Connect website + }, + ), + 'gender': FieldType( + name='gender', + base_type=BASE_TYPES[0x00], # enum + values={ + 0: 'female', + 1: 'male', + }, + ), + 'goal': FieldType( + name='goal', + base_type=BASE_TYPES[0x00], # enum + values={ + 0: 'time', + 1: 'distance', + 2: 'calories', + 3: 'frequency', + 4: 'steps', + 5: 'ascent', + 6: 'active_minutes', + }, + ), + 'goal_recurrence': FieldType( + name='goal_recurrence', + base_type=BASE_TYPES[0x00], # enum + values={ + 0: 'off', + 1: 'daily', + 2: 'weekly', + 3: 'monthly', + 4: 'yearly', + 5: 'custom', + }, + ), + 'goal_source': FieldType( + name='goal_source', + base_type=BASE_TYPES[0x00], # enum + values={ + 0: 'auto', # Device generated + 1: 'community', # Social network sourced goal + 2: 'user', # Manually generated + }, + ), + 'hip_raise_exercise_name': FieldType( + name='hip_raise_exercise_name', + base_type=BASE_TYPES[0x84], # uint16 + values={ + 0: 'barbell_hip_thrust_on_floor', + 1: 'barbell_hip_thrust_with_bench', + 2: 'bent_knee_swiss_ball_reverse_hip_raise', + 3: 'weighted_bent_knee_swiss_ball_reverse_hip_raise', + 4: 'bridge_with_leg_extension', + 5: 'weighted_bridge_with_leg_extension', + 6: 'clam_bridge', + 7: 'front_kick_tabletop', + 8: 'weighted_front_kick_tabletop', + 9: 'hip_extension_and_cross', + 10: 'weighted_hip_extension_and_cross', + 11: 'hip_raise', + 12: 'weighted_hip_raise', + 13: 'hip_raise_with_feet_on_swiss_ball', + 14: 'weighted_hip_raise_with_feet_on_swiss_ball', + 15: 'hip_raise_with_head_on_bosu_ball', + 16: 'weighted_hip_raise_with_head_on_bosu_ball', + 17: 'hip_raise_with_head_on_swiss_ball', + 18: 'weighted_hip_raise_with_head_on_swiss_ball', + 19: 'hip_raise_with_knee_squeeze', + 20: 'weighted_hip_raise_with_knee_squeeze', + 21: 'incline_rear_leg_extension', + 22: 'weighted_incline_rear_leg_extension', + 23: 'kettlebell_swing', + 24: 'marching_hip_raise', + 25: 'weighted_marching_hip_raise', + 26: 'marching_hip_raise_with_feet_on_a_swiss_ball', + 27: 'weighted_marching_hip_raise_with_feet_on_a_swiss_ball', + 28: 'reverse_hip_raise', + 29: 'weighted_reverse_hip_raise', + 30: 'single_leg_hip_raise', + 31: 'weighted_single_leg_hip_raise', + 32: 'single_leg_hip_raise_with_foot_on_bench', + 33: 'weighted_single_leg_hip_raise_with_foot_on_bench', + 34: 'single_leg_hip_raise_with_foot_on_bosu_ball', + 35: 'weighted_single_leg_hip_raise_with_foot_on_bosu_ball', + 36: 'single_leg_hip_raise_with_foot_on_foam_roller', + 37: 'weighted_single_leg_hip_raise_with_foot_on_foam_roller', + 38: 'single_leg_hip_raise_with_foot_on_medicine_ball', + 39: 'weighted_single_leg_hip_raise_with_foot_on_medicine_ball', + 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', + }, + ), + 'hip_stability_exercise_name': FieldType( + name='hip_stability_exercise_name', + base_type=BASE_TYPES[0x84], # uint16 + values={ + 0: 'band_side_lying_leg_raise', + 1: 'dead_bug', + 2: 'weighted_dead_bug', + 3: 'external_hip_raise', + 4: 'weighted_external_hip_raise', + 5: 'fire_hydrant_kicks', + 6: 'weighted_fire_hydrant_kicks', + 7: 'hip_circles', + 8: 'weighted_hip_circles', + 9: 'inner_thigh_lift', + 10: 'weighted_inner_thigh_lift', + 11: 'lateral_walks_with_band_at_ankles', + 12: 'pretzel_side_kick', + 13: 'weighted_pretzel_side_kick', + 14: 'prone_hip_internal_rotation', + 15: 'weighted_prone_hip_internal_rotation', + 16: 'quadruped', + 17: 'quadruped_hip_extension', + 18: 'weighted_quadruped_hip_extension', + 19: 'quadruped_with_leg_lift', + 20: 'weighted_quadruped_with_leg_lift', + 21: 'side_lying_leg_raise', + 22: 'weighted_side_lying_leg_raise', + 23: 'sliding_hip_adduction', + 24: 'weighted_sliding_hip_adduction', + 25: 'standing_adduction', + 26: 'weighted_standing_adduction', + 27: 'standing_cable_hip_abduction', + 28: 'standing_hip_abduction', + 29: 'weighted_standing_hip_abduction', + 30: 'standing_rear_leg_raise', + 31: 'weighted_standing_rear_leg_raise', + 32: 'supine_hip_internal_rotation', + 33: 'weighted_supine_hip_internal_rotation', + }, + ), + 'hip_swing_exercise_name': FieldType( + name='hip_swing_exercise_name', + base_type=BASE_TYPES[0x84], # uint16 + values={ + 0: 'single_arm_kettlebell_swing', + 1: 'single_arm_dumbbell_swing', + 2: 'step_out_swing', + }, + ), + 'hr_type': FieldType( + name='hr_type', + base_type=BASE_TYPES[0x00], # enum + values={ + 0: 'normal', + 1: 'irregular', + }, + ), + 'hr_zone_calc': FieldType( + name='hr_zone_calc', + base_type=BASE_TYPES[0x00], # enum + values={ + 0: 'custom', + 1: 'percent_max_hr', + 2: 'percent_hrr', + }, + ), + 'hyperextension_exercise_name': FieldType( + name='hyperextension_exercise_name', + base_type=BASE_TYPES[0x84], # uint16 + values={ + 0: 'back_extension_with_opposite_arm_and_leg_reach', + 1: 'weighted_back_extension_with_opposite_arm_and_leg_reach', + 2: 'base_rotations', + 3: 'weighted_base_rotations', + 4: 'bent_knee_reverse_hyperextension', + 5: 'weighted_bent_knee_reverse_hyperextension', + 6: 'hollow_hold_and_roll', + 7: 'weighted_hollow_hold_and_roll', + 8: 'kicks', + 9: 'weighted_kicks', + 10: 'knee_raises', + 11: 'weighted_knee_raises', + 12: 'kneeling_superman', + 13: 'weighted_kneeling_superman', + 14: 'lat_pull_down_with_row', + 15: 'medicine_ball_deadlift_to_reach', + 16: 'one_arm_one_leg_row', + 17: 'one_arm_row_with_band', + 18: 'overhead_lunge_with_medicine_ball', + 19: 'plank_knee_tucks', + 20: 'weighted_plank_knee_tucks', + 21: 'side_step', + 22: 'weighted_side_step', + 23: 'single_leg_back_extension', + 24: 'weighted_single_leg_back_extension', + 25: 'spine_extension', + 26: 'weighted_spine_extension', + 27: 'static_back_extension', + 28: 'weighted_static_back_extension', + 29: 'superman_from_floor', + 30: 'weighted_superman_from_floor', + 31: 'swiss_ball_back_extension', + 32: 'weighted_swiss_ball_back_extension', + 33: 'swiss_ball_hyperextension', + 34: 'weighted_swiss_ball_hyperextension', + 35: 'swiss_ball_opposite_arm_and_leg_lift', + 36: 'weighted_swiss_ball_opposite_arm_and_leg_lift', + }, + ), + 'intensity': FieldType( + name='intensity', + base_type=BASE_TYPES[0x00], # enum + values={ + 0: 'active', + 1: 'rest', + 2: 'warmup', + 3: 'cooldown', + }, + ), + 'language': FieldType( + name='language', + base_type=BASE_TYPES[0x00], # enum + values={ + 0: 'english', + 1: 'french', + 2: 'italian', + 3: 'german', + 4: 'spanish', + 5: 'croatian', + 6: 'czech', + 7: 'danish', + 8: 'dutch', + 9: 'finnish', + 10: 'greek', + 11: 'hungarian', + 12: 'norwegian', + 13: 'polish', + 14: 'portuguese', + 15: 'slovakian', + 16: 'slovenian', + 17: 'swedish', + 18: 'russian', + 19: 'turkish', + 20: 'latvian', + 21: 'ukrainian', + 22: 'arabic', + 23: 'farsi', + 24: 'bulgarian', + 25: 'romanian', + 26: 'chinese', + 27: 'japanese', + 28: 'korean', + 29: 'taiwanese', + 30: 'thai', + 31: 'hebrew', + 32: 'brazilian_portuguese', + 33: 'indonesian', + 34: 'malaysian', + 35: 'vietnamese', + 36: 'burmese', + 37: 'mongolian', + 254: 'custom', + }, + ), + 'language_bits_0': FieldType( # Bit field corresponding to language enum type (1 << language). + name='language_bits_0', + base_type=BASE_TYPES[0x0A], # uint8z + values={ + 0x01: 'english', + 0x02: 'french', + 0x04: 'italian', + 0x08: 'german', + 0x10: 'spanish', + 0x20: 'croatian', + 0x40: 'czech', + 0x80: 'danish', + }, + ), + 'language_bits_1': FieldType( + name='language_bits_1', + base_type=BASE_TYPES[0x0A], # uint8z + values={ + 0x01: 'dutch', + 0x02: 'finnish', + 0x04: 'greek', + 0x08: 'hungarian', + 0x10: 'norwegian', + 0x20: 'polish', + 0x40: 'portuguese', + 0x80: 'slovakian', + }, + ), + 'language_bits_2': FieldType( + name='language_bits_2', + base_type=BASE_TYPES[0x0A], # uint8z + values={ + 0x01: 'slovenian', + 0x02: 'swedish', + 0x04: 'russian', + 0x08: 'turkish', + 0x10: 'latvian', + 0x20: 'ukrainian', + 0x40: 'arabic', + 0x80: 'farsi', + }, + ), + 'language_bits_3': FieldType( + name='language_bits_3', + base_type=BASE_TYPES[0x0A], # uint8z + values={ + 0x01: 'bulgarian', + 0x02: 'romanian', + 0x04: 'chinese', + 0x08: 'japanese', + 0x10: 'korean', + 0x20: 'taiwanese', + 0x40: 'thai', + 0x80: 'hebrew', + }, + ), + 'language_bits_4': FieldType( + name='language_bits_4', + base_type=BASE_TYPES[0x0A], # uint8z + values={ + 0x01: 'brazilian_portuguese', + 0x02: 'indonesian', + 0x04: 'malaysian', + 0x08: 'vietnamese', + 0x10: 'burmese', + 0x20: 'mongolian', + }, + ), + 'lap_trigger': FieldType( + name='lap_trigger', + base_type=BASE_TYPES[0x00], # enum + values={ + 0: 'manual', + 1: 'time', + 2: 'distance', + 3: 'position_start', + 4: 'position_lap', + 5: 'position_waypoint', + 6: 'position_marked', + 7: 'session_end', + 8: 'fitness_equipment', + }, + ), + 'lateral_raise_exercise_name': FieldType( + name='lateral_raise_exercise_name', + base_type=BASE_TYPES[0x84], # uint16 + values={ + 0: '45_degree_cable_external_rotation', + 1: 'alternating_lateral_raise_with_static_hold', + 2: 'bar_muscle_up', + 3: 'bent_over_lateral_raise', + 4: 'cable_diagonal_raise', + 5: 'cable_front_raise', + 6: 'calorie_row', + 7: 'combo_shoulder_raise', + 8: 'dumbbell_diagonal_raise', + 9: 'dumbbell_v_raise', + 10: 'front_raise', + 11: 'leaning_dumbbell_lateral_raise', + 12: 'lying_dumbbell_raise', + 13: 'muscle_up', + 14: 'one_arm_cable_lateral_raise', + 15: 'overhand_grip_rear_lateral_raise', + 16: 'plate_raises', + 17: 'ring_dip', + 18: 'weighted_ring_dip', + 19: 'ring_muscle_up', + 20: 'weighted_ring_muscle_up', + 21: 'rope_climb', + 22: 'weighted_rope_climb', + 23: 'scaption', + 24: 'seated_lateral_raise', + 25: 'seated_rear_lateral_raise', + 26: 'side_lying_lateral_raise', + 27: 'standing_lift', + 28: 'suspended_row', + 29: 'underhand_grip_rear_lateral_raise', + 30: 'wall_slide', + 31: 'weighted_wall_slide', + }, + ), + 'left_right_balance': FieldType( + name='left_right_balance', + base_type=BASE_TYPES[0x02], # uint8 + values={ + 0x7F: 'mask', # % contribution + 0x80: 'right', # data corresponds to right if set, otherwise unknown + }, + ), + 'left_right_balance_100': FieldType( + name='left_right_balance_100', + base_type=BASE_TYPES[0x84], # uint16 + values={ + 0x3FFF: 'mask', # % contribution scaled by 100 + 0x8000: 'right', # data corresponds to right if set, otherwise unknown + }, + ), + 'leg_curl_exercise_name': FieldType( + name='leg_curl_exercise_name', + base_type=BASE_TYPES[0x84], # uint16 + values={ + 0: 'leg_curl', + 1: 'weighted_leg_curl', + 2: 'good_morning', + 3: 'seated_barbell_good_morning', + 4: 'single_leg_barbell_good_morning', + 5: 'single_leg_sliding_leg_curl', + 6: 'sliding_leg_curl', + 7: 'split_barbell_good_morning', + 8: 'split_stance_extension', + 9: 'staggered_stance_good_morning', + 10: 'swiss_ball_hip_raise_and_leg_curl', + 11: 'zercher_good_morning', + }, + ), + 'leg_raise_exercise_name': FieldType( + name='leg_raise_exercise_name', + base_type=BASE_TYPES[0x84], # uint16 + values={ + 0: 'hanging_knee_raise', + 1: 'hanging_leg_raise', + 2: 'weighted_hanging_leg_raise', + 3: 'hanging_single_leg_raise', + 4: 'weighted_hanging_single_leg_raise', + 5: 'kettlebell_leg_raises', + 6: 'leg_lowering_drill', + 7: 'weighted_leg_lowering_drill', + 8: 'lying_straight_leg_raise', + 9: 'weighted_lying_straight_leg_raise', + 10: 'medicine_ball_leg_drops', + 11: 'quadruped_leg_raise', + 12: 'weighted_quadruped_leg_raise', + 13: 'reverse_leg_raise', + 14: 'weighted_reverse_leg_raise', + 15: 'reverse_leg_raise_on_swiss_ball', + 16: 'weighted_reverse_leg_raise_on_swiss_ball', + 17: 'single_leg_lowering_drill', + 18: 'weighted_single_leg_lowering_drill', + 19: 'weighted_hanging_knee_raise', + 20: 'lateral_stepover', + 21: 'weighted_lateral_stepover', + }, + ), + 'length_type': FieldType( + name='length_type', + base_type=BASE_TYPES[0x00], # enum + values={ + 0: 'idle', # Rest period. Length with no strokes + 1: 'active', # Length with strokes. + }, + ), + 'local_date_time': FieldType( # seconds since 00:00 Dec 31 1989 in local time zone + name='local_date_time', + base_type=BASE_TYPES[0x86], # uint32 + values={ + 0x10000000: 'min', # if date_time is < 0x10000000 then it is system time (seconds from device power on) + }, + ), + 'local_device_type': FieldType( + name='local_device_type', + base_type=BASE_TYPES[0x02], # uint8 + ), + 'localtime_into_day': FieldType( # number of seconds into the day since local 00:00:00 + name='localtime_into_day', + base_type=BASE_TYPES[0x86], # uint32 + ), + 'lunge_exercise_name': FieldType( + name='lunge_exercise_name', + base_type=BASE_TYPES[0x84], # uint16 + values={ + 0: 'overhead_lunge', + 1: 'lunge_matrix', + 2: 'weighted_lunge_matrix', + 3: 'alternating_barbell_forward_lunge', + 4: 'alternating_dumbbell_lunge_with_reach', + 5: 'back_foot_elevated_dumbbell_split_squat', + 6: 'barbell_box_lunge', + 7: 'barbell_bulgarian_split_squat', + 8: 'barbell_crossover_lunge', + 9: 'barbell_front_split_squat', + 10: 'barbell_lunge', + 11: 'barbell_reverse_lunge', + 12: 'barbell_side_lunge', + 13: 'barbell_split_squat', + 14: 'core_control_rear_lunge', + 15: 'diagonal_lunge', + 16: 'drop_lunge', + 17: 'dumbbell_box_lunge', + 18: 'dumbbell_bulgarian_split_squat', + 19: 'dumbbell_crossover_lunge', + 20: 'dumbbell_diagonal_lunge', + 21: 'dumbbell_lunge', + 22: 'dumbbell_lunge_and_rotation', + 23: 'dumbbell_overhead_bulgarian_split_squat', + 24: 'dumbbell_reverse_lunge_to_high_knee_and_press', + 25: 'dumbbell_side_lunge', + 26: 'elevated_front_foot_barbell_split_squat', + 27: 'front_foot_elevated_dumbbell_split_squat', + 28: 'gunslinger_lunge', + 29: 'lawnmower_lunge', + 30: 'low_lunge_with_isometric_adduction', + 31: 'low_side_to_side_lunge', + 32: 'lunge', + 33: 'weighted_lunge', + 34: 'lunge_with_arm_reach', + 35: 'lunge_with_diagonal_reach', + 36: 'lunge_with_side_bend', + 37: 'offset_dumbbell_lunge', + 38: 'offset_dumbbell_reverse_lunge', + 39: 'overhead_bulgarian_split_squat', + 40: 'overhead_dumbbell_reverse_lunge', + 41: 'overhead_dumbbell_split_squat', + 42: 'overhead_lunge_with_rotation', + 43: 'reverse_barbell_box_lunge', + 44: 'reverse_box_lunge', + 45: 'reverse_dumbbell_box_lunge', + 46: 'reverse_dumbbell_crossover_lunge', + 47: 'reverse_dumbbell_diagonal_lunge', + 48: 'reverse_lunge_with_reach_back', + 49: 'weighted_reverse_lunge_with_reach_back', + 50: 'reverse_lunge_with_twist_and_overhead_reach', + 51: 'weighted_reverse_lunge_with_twist_and_overhead_reach', + 52: 'reverse_sliding_box_lunge', + 53: 'weighted_reverse_sliding_box_lunge', + 54: 'reverse_sliding_lunge', + 55: 'weighted_reverse_sliding_lunge', + 56: 'runners_lunge_to_balance', + 57: 'weighted_runners_lunge_to_balance', + 58: 'shifting_side_lunge', + 59: 'side_and_crossover_lunge', + 60: 'weighted_side_and_crossover_lunge', + 61: 'side_lunge', + 62: 'weighted_side_lunge', + 63: 'side_lunge_and_press', + 64: 'side_lunge_jump_off', + 65: 'side_lunge_sweep', + 66: 'weighted_side_lunge_sweep', + 67: 'side_lunge_to_crossover_tap', + 68: 'weighted_side_lunge_to_crossover_tap', + 69: 'side_to_side_lunge_chops', + 70: 'weighted_side_to_side_lunge_chops', + 71: 'siff_jump_lunge', + 72: 'weighted_siff_jump_lunge', + 73: 'single_arm_reverse_lunge_and_press', + 74: 'sliding_lateral_lunge', + 75: 'weighted_sliding_lateral_lunge', + 76: 'walking_barbell_lunge', + 77: 'walking_dumbbell_lunge', + 78: 'walking_lunge', + 79: 'weighted_walking_lunge', + 80: 'wide_grip_overhead_barbell_split_squat', + }, + ), + 'manufacturer': FieldType( + name='manufacturer', + base_type=BASE_TYPES[0x84], # uint16 + values={ + 1: 'garmin', + 2: 'garmin_fr405_antfs', # Do not use. Used by FR405 for ANTFS man id. + 3: 'zephyr', + 4: 'dayton', + 5: 'idt', + 6: 'srm', + 7: 'quarq', + 8: 'ibike', + 9: 'saris', + 10: 'spark_hk', + 11: 'tanita', + 12: 'echowell', + 13: 'dynastream_oem', + 14: 'nautilus', + 15: 'dynastream', + 16: 'timex', + 17: 'metrigear', + 18: 'xelic', + 19: 'beurer', + 20: 'cardiosport', + 21: 'a_and_d', + 22: 'hmm', + 23: 'suunto', + 24: 'thita_elektronik', + 25: 'gpulse', + 26: 'clean_mobile', + 27: 'pedal_brain', + 28: 'peaksware', + 29: 'saxonar', + 30: 'lemond_fitness', + 31: 'dexcom', + 32: 'wahoo_fitness', + 33: 'octane_fitness', + 34: 'archinoetics', + 35: 'the_hurt_box', + 36: 'citizen_systems', + 37: 'magellan', + 38: 'osynce', + 39: 'holux', + 40: 'concept2', + 42: 'one_giant_leap', + 43: 'ace_sensor', + 44: 'brim_brothers', + 45: 'xplova', + 46: 'perception_digital', + 47: 'bf1systems', + 48: 'pioneer', + 49: 'spantec', + 50: 'metalogics', + 51: '4iiiis', + 52: 'seiko_epson', + 53: 'seiko_epson_oem', + 54: 'ifor_powell', + 55: 'maxwell_guider', + 56: 'star_trac', + 57: 'breakaway', + 58: 'alatech_technology_ltd', + 59: 'mio_technology_europe', + 60: 'rotor', + 61: 'geonaute', + 62: 'id_bike', + 63: 'specialized', + 64: 'wtek', + 65: 'physical_enterprises', + 66: 'north_pole_engineering', + 67: 'bkool', + 68: 'cateye', + 69: 'stages_cycling', + 70: 'sigmasport', + 71: 'tomtom', + 72: 'peripedal', + 73: 'wattbike', + 76: 'moxy', + 77: 'ciclosport', + 78: 'powerbahn', + 79: 'acorn_projects_aps', + 80: 'lifebeam', + 81: 'bontrager', + 82: 'wellgo', + 83: 'scosche', + 84: 'magura', + 85: 'woodway', + 86: 'elite', + 87: 'nielsen_kellerman', + 88: 'dk_city', + 89: 'tacx', + 90: 'direction_technology', + 91: 'magtonic', + 92: '1partcarbon', + 93: 'inside_ride_technologies', + 94: 'sound_of_motion', + 95: 'stryd', + 96: 'icg', # Indoorcycling Group + 97: 'MiPulse', + 98: 'bsx_athletics', + 99: 'look', + 100: 'campagnolo_srl', + 101: 'body_bike_smart', + 102: 'praxisworks', + 103: 'limits_technology', # Limits Technology Ltd. + 104: 'topaction_technology', # TopAction Technology Inc. + 105: 'cosinuss', + 106: 'fitcare', + 107: 'magene', + 108: 'giant_manufacturing_co', + 109: 'tigrasport', # Tigrasport + 110: 'salutron', + 111: 'technogym', + 112: 'bryton_sensors', + 113: 'latitude_limited', + 114: 'soaring_technology', + 115: 'igpsport', + 116: 'thinkrider', + 117: 'gopher_sport', + 118: 'waterrower', + 119: 'orangetheory', + 120: 'inpeak', + 121: 'kinetic', + 122: 'johnson_health_tech', + 123: 'polar_electro', + 124: 'seesense', + 255: 'development', + 257: 'healthandlife', + 258: 'lezyne', + 259: 'scribe_labs', + 260: 'zwift', + 261: 'watteam', + 262: 'recon', + 263: 'favero_electronics', + 264: 'dynovelo', + 265: 'strava', + 266: 'precor', # Amer Sports + 267: 'bryton', + 268: 'sram', + 269: 'navman', # MiTAC Global Corporation (Mio Technology) + 270: 'cobi', # COBI GmbH + 271: 'spivi', + 272: 'mio_magellan', + 273: 'evesports', + 274: 'sensitivus_gauge', + 275: 'podoon', + 276: 'life_time_fitness', + 277: 'falco_e_motors', # Falco eMotors Inc. + 278: 'minoura', + 279: 'cycliq', + 280: 'luxottica', + 281: 'trainer_road', + 282: 'the_sufferfest', + 283: 'fullspeedahead', + 284: 'virtualtraining', + 285: 'feedbacksports', + 286: 'omata', + 287: 'vdo', + 288: 'magneticdays', + 289: 'hammerhead', + 290: 'kinetic_by_kurt', + 291: 'shapelog', + 292: 'dabuziduo', + 293: 'jetblack', + 5759: 'actigraphcorp', + }, + ), + 'mesg_count': FieldType( + name='mesg_count', + base_type=BASE_TYPES[0x00], # enum + values={ + 0: 'num_per_file', + 1: 'max_per_file', + 2: 'max_per_file_type', + }, + ), + 'mesg_num': FieldType( + name='mesg_num', + base_type=BASE_TYPES[0x84], # uint16 + values={ + 0: 'file_id', + 1: 'capabilities', + 2: 'device_settings', + 3: 'user_profile', + 4: 'hrm_profile', + 5: 'sdm_profile', + 6: 'bike_profile', + 7: 'zones_target', + 8: 'hr_zone', + 9: 'power_zone', + 10: 'met_zone', + 12: 'sport', + 15: 'goal', + 18: 'session', + 19: 'lap', + 20: 'record', + 21: 'event', + 23: 'device_info', + 26: 'workout', + 27: 'workout_step', + 28: 'schedule', + 30: 'weight_scale', + 31: 'course', + 32: 'course_point', + 33: 'totals', + 34: 'activity', + 35: 'software', + 37: 'file_capabilities', + 38: 'mesg_capabilities', + 39: 'field_capabilities', + 49: 'file_creator', + 51: 'blood_pressure', + 53: 'speed_zone', + 55: 'monitoring', + 72: 'training_file', + 78: 'hrv', + 80: 'ant_rx', + 81: 'ant_tx', + 82: 'ant_channel_id', + 101: 'length', + 103: 'monitoring_info', + 105: 'pad', + 106: 'slave_device', + 127: 'connectivity', + 128: 'weather_conditions', + 129: 'weather_alert', + 131: 'cadence_zone', + 132: 'hr', + 142: 'segment_lap', + 145: 'memo_glob', + 148: 'segment_id', + 149: 'segment_leaderboard_entry', + 150: 'segment_point', + 151: 'segment_file', + 158: 'workout_session', + 159: 'watchface_settings', + 160: 'gps_metadata', + 161: 'camera_event', + 162: 'timestamp_correlation', + 164: 'gyroscope_data', + 165: 'accelerometer_data', + 167: 'three_d_sensor_calibration', + 169: 'video_frame', + 174: 'obdii_data', + 177: 'nmea_sentence', + 178: 'aviation_attitude', + 184: 'video', + 185: 'video_title', + 186: 'video_description', + 187: 'video_clip', + 188: 'ohr_settings', + 200: 'exd_screen_configuration', + 201: 'exd_data_field_configuration', + 202: 'exd_data_concept_configuration', + 206: 'field_description', + 207: 'developer_data_id', + 208: 'magnetometer_data', + 209: 'barometer_data', + 210: 'one_d_sensor_calibration', + 225: 'set', + 227: 'stress_level', + 258: 'dive_settings', + 259: 'dive_gas', + 262: 'dive_alarm', + 264: 'exercise_title', + 268: 'dive_summary', + }, + ), + 'message_index': FieldType( + name='message_index', + base_type=BASE_TYPES[0x84], # uint16 + values={ + 0x0FFF: 'mask', # index + 0x7000: 'reserved', # reserved (default 0) + 0x8000: 'selected', # message is selected if set + }, + ), + 'olympic_lift_exercise_name': FieldType( + name='olympic_lift_exercise_name', + base_type=BASE_TYPES[0x84], # uint16 + values={ + 0: 'barbell_hang_power_clean', + 1: 'barbell_hang_squat_clean', + 2: 'barbell_power_clean', + 3: 'barbell_power_snatch', + 4: 'barbell_squat_clean', + 5: 'clean_and_jerk', + 6: 'barbell_hang_power_snatch', + 7: 'barbell_hang_pull', + 8: 'barbell_high_pull', + 9: 'barbell_snatch', + 10: 'barbell_split_jerk', + 11: 'clean', + 12: 'dumbbell_clean', + 13: 'dumbbell_hang_pull', + 14: 'one_hand_dumbbell_split_snatch', + 15: 'push_jerk', + 16: 'single_arm_dumbbell_snatch', + 17: 'single_arm_hang_snatch', + 18: 'single_arm_kettlebell_snatch', + 19: 'split_jerk', + 20: 'squat_clean_and_jerk', + }, + ), + 'plank_exercise_name': FieldType( + name='plank_exercise_name', + base_type=BASE_TYPES[0x84], # uint16 + values={ + 0: '45_degree_plank', + 1: 'weighted_45_degree_plank', + 2: '90_degree_static_hold', + 3: 'weighted_90_degree_static_hold', + 4: 'bear_crawl', + 5: 'weighted_bear_crawl', + 6: 'cross_body_mountain_climber', + 7: 'weighted_cross_body_mountain_climber', + 8: 'elbow_plank_pike_jacks', + 9: 'weighted_elbow_plank_pike_jacks', + 10: 'elevated_feet_plank', + 11: 'weighted_elevated_feet_plank', + 12: 'elevator_abs', + 13: 'weighted_elevator_abs', + 14: 'extended_plank', + 15: 'weighted_extended_plank', + 16: 'full_plank_passe_twist', + 17: 'weighted_full_plank_passe_twist', + 18: 'inching_elbow_plank', + 19: 'weighted_inching_elbow_plank', + 20: 'inchworm_to_side_plank', + 21: 'weighted_inchworm_to_side_plank', + 22: 'kneeling_plank', + 23: 'weighted_kneeling_plank', + 24: 'kneeling_side_plank_with_leg_lift', + 25: 'weighted_kneeling_side_plank_with_leg_lift', + 26: 'lateral_roll', + 27: 'weighted_lateral_roll', + 28: 'lying_reverse_plank', + 29: 'weighted_lying_reverse_plank', + 30: 'medicine_ball_mountain_climber', + 31: 'weighted_medicine_ball_mountain_climber', + 32: 'modified_mountain_climber_and_extension', + 33: 'weighted_modified_mountain_climber_and_extension', + 34: 'mountain_climber', + 35: 'weighted_mountain_climber', + 36: 'mountain_climber_on_sliding_discs', + 37: 'weighted_mountain_climber_on_sliding_discs', + 38: 'mountain_climber_with_feet_on_bosu_ball', + 39: 'weighted_mountain_climber_with_feet_on_bosu_ball', + 40: 'mountain_climber_with_hands_on_bench', + 41: 'mountain_climber_with_hands_on_swiss_ball', + 42: 'weighted_mountain_climber_with_hands_on_swiss_ball', + 43: 'plank', + 44: 'plank_jacks_with_feet_on_sliding_discs', + 45: 'weighted_plank_jacks_with_feet_on_sliding_discs', + 46: 'plank_knee_twist', + 47: 'weighted_plank_knee_twist', + 48: 'plank_pike_jumps', + 49: 'weighted_plank_pike_jumps', + 50: 'plank_pikes', + 51: 'weighted_plank_pikes', + 52: 'plank_to_stand_up', + 53: 'weighted_plank_to_stand_up', + 54: 'plank_with_arm_raise', + 55: 'weighted_plank_with_arm_raise', + 56: 'plank_with_knee_to_elbow', + 57: 'weighted_plank_with_knee_to_elbow', + 58: 'plank_with_oblique_crunch', + 59: 'weighted_plank_with_oblique_crunch', + 60: 'plyometric_side_plank', + 61: 'weighted_plyometric_side_plank', + 62: 'rolling_side_plank', + 63: 'weighted_rolling_side_plank', + 64: 'side_kick_plank', + 65: 'weighted_side_kick_plank', + 66: 'side_plank', + 67: 'weighted_side_plank', + 68: 'side_plank_and_row', + 69: 'weighted_side_plank_and_row', + 70: 'side_plank_lift', + 71: 'weighted_side_plank_lift', + 72: 'side_plank_with_elbow_on_bosu_ball', + 73: 'weighted_side_plank_with_elbow_on_bosu_ball', + 74: 'side_plank_with_feet_on_bench', + 75: 'weighted_side_plank_with_feet_on_bench', + 76: 'side_plank_with_knee_circle', + 77: 'weighted_side_plank_with_knee_circle', + 78: 'side_plank_with_knee_tuck', + 79: 'weighted_side_plank_with_knee_tuck', + 80: 'side_plank_with_leg_lift', + 81: 'weighted_side_plank_with_leg_lift', + 82: 'side_plank_with_reach_under', + 83: 'weighted_side_plank_with_reach_under', + 84: 'single_leg_elevated_feet_plank', + 85: 'weighted_single_leg_elevated_feet_plank', + 86: 'single_leg_flex_and_extend', + 87: 'weighted_single_leg_flex_and_extend', + 88: 'single_leg_side_plank', + 89: 'weighted_single_leg_side_plank', + 90: 'spiderman_plank', + 91: 'weighted_spiderman_plank', + 92: 'straight_arm_plank', + 93: 'weighted_straight_arm_plank', + 94: 'straight_arm_plank_with_shoulder_touch', + 95: 'weighted_straight_arm_plank_with_shoulder_touch', + 96: 'swiss_ball_plank', + 97: 'weighted_swiss_ball_plank', + 98: 'swiss_ball_plank_leg_lift', + 99: 'weighted_swiss_ball_plank_leg_lift', + 100: 'swiss_ball_plank_leg_lift_and_hold', + 101: 'swiss_ball_plank_with_feet_on_bench', + 102: 'weighted_swiss_ball_plank_with_feet_on_bench', + 103: 'swiss_ball_prone_jackknife', + 104: 'weighted_swiss_ball_prone_jackknife', + 105: 'swiss_ball_side_plank', + 106: 'weighted_swiss_ball_side_plank', + 107: 'three_way_plank', + 108: 'weighted_three_way_plank', + 109: 'towel_plank_and_knee_in', + 110: 'weighted_towel_plank_and_knee_in', + 111: 't_stabilization', + 112: 'weighted_t_stabilization', + 113: 'turkish_get_up_to_side_plank', + 114: 'weighted_turkish_get_up_to_side_plank', + 115: 'two_point_plank', + 116: 'weighted_two_point_plank', + 117: 'weighted_plank', + 118: 'wide_stance_plank_with_diagonal_arm_lift', + 119: 'weighted_wide_stance_plank_with_diagonal_arm_lift', + 120: 'wide_stance_plank_with_diagonal_leg_lift', + 121: 'weighted_wide_stance_plank_with_diagonal_leg_lift', + 122: 'wide_stance_plank_with_leg_lift', + 123: 'weighted_wide_stance_plank_with_leg_lift', + 124: 'wide_stance_plank_with_opposite_arm_and_leg_lift', + 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', + }, + ), + 'plyo_exercise_name': FieldType( + name='plyo_exercise_name', + base_type=BASE_TYPES[0x84], # uint16 + values={ + 0: 'alternating_jump_lunge', + 1: 'weighted_alternating_jump_lunge', + 2: 'barbell_jump_squat', + 3: 'body_weight_jump_squat', + 4: 'weighted_jump_squat', + 5: 'cross_knee_strike', + 6: 'weighted_cross_knee_strike', + 7: 'depth_jump', + 8: 'weighted_depth_jump', + 9: 'dumbbell_jump_squat', + 10: 'dumbbell_split_jump', + 11: 'front_knee_strike', + 12: 'weighted_front_knee_strike', + 13: 'high_box_jump', + 14: 'weighted_high_box_jump', + 15: 'isometric_explosive_body_weight_jump_squat', + 16: 'weighted_isometric_explosive_jump_squat', + 17: 'lateral_leap_and_hop', + 18: 'weighted_lateral_leap_and_hop', + 19: 'lateral_plyo_squats', + 20: 'weighted_lateral_plyo_squats', + 21: 'lateral_slide', + 22: 'weighted_lateral_slide', + 23: 'medicine_ball_overhead_throws', + 24: 'medicine_ball_side_throw', + 25: 'medicine_ball_slam', + 26: 'side_to_side_medicine_ball_throws', + 27: 'side_to_side_shuffle_jump', + 28: 'weighted_side_to_side_shuffle_jump', + 29: 'squat_jump_onto_box', + 30: 'weighted_squat_jump_onto_box', + 31: 'squat_jumps_in_and_out', + 32: 'weighted_squat_jumps_in_and_out', + }, + ), + 'power_phase_type': FieldType( + name='power_phase_type', + base_type=BASE_TYPES[0x00], # enum + values={ + 0: 'power_phase_start_angle', + 1: 'power_phase_end_angle', + 2: 'power_phase_arc_length', + 3: 'power_phase_center', + }, + ), + 'pull_up_exercise_name': FieldType( + name='pull_up_exercise_name', + base_type=BASE_TYPES[0x84], # uint16 + values={ + 0: 'banded_pull_ups', + 1: '30_degree_lat_pulldown', + 2: 'band_assisted_chin_up', + 3: 'close_grip_chin_up', + 4: 'weighted_close_grip_chin_up', + 5: 'close_grip_lat_pulldown', + 6: 'crossover_chin_up', + 7: 'weighted_crossover_chin_up', + 8: 'ez_bar_pullover', + 9: 'hanging_hurdle', + 10: 'weighted_hanging_hurdle', + 11: 'kneeling_lat_pulldown', + 12: 'kneeling_underhand_grip_lat_pulldown', + 13: 'lat_pulldown', + 14: 'mixed_grip_chin_up', + 15: 'weighted_mixed_grip_chin_up', + 16: 'mixed_grip_pull_up', + 17: 'weighted_mixed_grip_pull_up', + 18: 'reverse_grip_pulldown', + 19: 'standing_cable_pullover', + 20: 'straight_arm_pulldown', + 21: 'swiss_ball_ez_bar_pullover', + 22: 'towel_pull_up', + 23: 'weighted_towel_pull_up', + 24: 'weighted_pull_up', + 25: 'wide_grip_lat_pulldown', + 26: 'wide_grip_pull_up', + 27: 'weighted_wide_grip_pull_up', + 28: 'burpee_pull_up', + 29: 'weighted_burpee_pull_up', + 30: 'jumping_pull_ups', + 31: 'weighted_jumping_pull_ups', + 32: 'kipping_pull_up', + 33: 'weighted_kipping_pull_up', + 34: 'l_pull_up', + 35: 'weighted_l_pull_up', + 36: 'suspended_chin_up', + 37: 'weighted_suspended_chin_up', + 38: 'pull_up', + }, + ), + 'push_up_exercise_name': FieldType( + name='push_up_exercise_name', + base_type=BASE_TYPES[0x84], # uint16 + values={ + 0: 'chest_press_with_band', + 1: 'alternating_staggered_push_up', + 2: 'weighted_alternating_staggered_push_up', + 3: 'alternating_hands_medicine_ball_push_up', + 4: 'weighted_alternating_hands_medicine_ball_push_up', + 5: 'bosu_ball_push_up', + 6: 'weighted_bosu_ball_push_up', + 7: 'clapping_push_up', + 8: 'weighted_clapping_push_up', + 9: 'close_grip_medicine_ball_push_up', + 10: 'weighted_close_grip_medicine_ball_push_up', + 11: 'close_hands_push_up', + 12: 'weighted_close_hands_push_up', + 13: 'decline_push_up', + 14: 'weighted_decline_push_up', + 15: 'diamond_push_up', + 16: 'weighted_diamond_push_up', + 17: 'explosive_crossover_push_up', + 18: 'weighted_explosive_crossover_push_up', + 19: 'explosive_push_up', + 20: 'weighted_explosive_push_up', + 21: 'feet_elevated_side_to_side_push_up', + 22: 'weighted_feet_elevated_side_to_side_push_up', + 23: 'hand_release_push_up', + 24: 'weighted_hand_release_push_up', + 25: 'handstand_push_up', + 26: 'weighted_handstand_push_up', + 27: 'incline_push_up', + 28: 'weighted_incline_push_up', + 29: 'isometric_explosive_push_up', + 30: 'weighted_isometric_explosive_push_up', + 31: 'judo_push_up', + 32: 'weighted_judo_push_up', + 33: 'kneeling_push_up', + 34: 'weighted_kneeling_push_up', + 35: 'medicine_ball_chest_pass', + 36: 'medicine_ball_push_up', + 37: 'weighted_medicine_ball_push_up', + 38: 'one_arm_push_up', + 39: 'weighted_one_arm_push_up', + 40: 'weighted_push_up', + 41: 'push_up_and_row', + 42: 'weighted_push_up_and_row', + 43: 'push_up_plus', + 44: 'weighted_push_up_plus', + 45: 'push_up_with_feet_on_swiss_ball', + 46: 'weighted_push_up_with_feet_on_swiss_ball', + 47: 'push_up_with_one_hand_on_medicine_ball', + 48: 'weighted_push_up_with_one_hand_on_medicine_ball', + 49: 'shoulder_push_up', + 50: 'weighted_shoulder_push_up', + 51: 'single_arm_medicine_ball_push_up', + 52: 'weighted_single_arm_medicine_ball_push_up', + 53: 'spiderman_push_up', + 54: 'weighted_spiderman_push_up', + 55: 'stacked_feet_push_up', + 56: 'weighted_stacked_feet_push_up', + 57: 'staggered_hands_push_up', + 58: 'weighted_staggered_hands_push_up', + 59: 'suspended_push_up', + 60: 'weighted_suspended_push_up', + 61: 'swiss_ball_push_up', + 62: 'weighted_swiss_ball_push_up', + 63: 'swiss_ball_push_up_plus', + 64: 'weighted_swiss_ball_push_up_plus', + 65: 't_push_up', + 66: 'weighted_t_push_up', + 67: 'triple_stop_push_up', + 68: 'weighted_triple_stop_push_up', + 69: 'wide_hands_push_up', + 70: 'weighted_wide_hands_push_up', + 71: 'parallette_handstand_push_up', + 72: 'weighted_parallette_handstand_push_up', + 73: 'ring_handstand_push_up', + 74: 'weighted_ring_handstand_push_up', + 75: 'ring_push_up', + 76: 'weighted_ring_push_up', + 77: 'push_up', + }, + ), + 'pwr_zone_calc': FieldType( + name='pwr_zone_calc', + base_type=BASE_TYPES[0x00], # enum + values={ + 0: 'custom', + 1: 'percent_ftp', + }, + ), + 'rider_position_type': FieldType( + name='rider_position_type', + base_type=BASE_TYPES[0x00], # enum + values={ + 0: 'seated', + 1: 'standing', + 2: 'transition_to_seated', + 3: 'transition_to_standing', + }, + ), + 'row_exercise_name': FieldType( + name='row_exercise_name', + base_type=BASE_TYPES[0x84], # uint16 + values={ + 0: 'barbell_straight_leg_deadlift_to_row', + 1: 'cable_row_standing', + 2: 'dumbbell_row', + 3: 'elevated_feet_inverted_row', + 4: 'weighted_elevated_feet_inverted_row', + 5: 'face_pull', + 6: 'face_pull_with_external_rotation', + 7: 'inverted_row_with_feet_on_swiss_ball', + 8: 'weighted_inverted_row_with_feet_on_swiss_ball', + 9: 'kettlebell_row', + 10: 'modified_inverted_row', + 11: 'weighted_modified_inverted_row', + 12: 'neutral_grip_alternating_dumbbell_row', + 13: 'one_arm_bent_over_row', + 14: 'one_legged_dumbbell_row', + 15: 'renegade_row', + 16: 'reverse_grip_barbell_row', + 17: 'rope_handle_cable_row', + 18: 'seated_cable_row', + 19: 'seated_dumbbell_row', + 20: 'single_arm_cable_row', + 21: 'single_arm_cable_row_and_rotation', + 22: 'single_arm_inverted_row', + 23: 'weighted_single_arm_inverted_row', + 24: 'single_arm_neutral_grip_dumbbell_row', + 25: 'single_arm_neutral_grip_dumbbell_row_and_rotation', + 26: 'suspended_inverted_row', + 27: 'weighted_suspended_inverted_row', + 28: 't_bar_row', + 29: 'towel_grip_inverted_row', + 30: 'weighted_towel_grip_inverted_row', + 31: 'underhand_grip_cable_row', + 32: 'v_grip_cable_row', + 33: 'wide_grip_seated_cable_row', + }, + ), + 'run_exercise_name': FieldType( + name='run_exercise_name', + base_type=BASE_TYPES[0x84], # uint16 + values={ + 0: 'run', + 1: 'walk', + 2: 'jog', + 3: 'sprint', + }, + ), + 'schedule': FieldType( + name='schedule', + base_type=BASE_TYPES[0x00], # enum + values={ + 0: 'workout', + 1: 'course', + }, + ), + 'segment_delete_status': FieldType( + name='segment_delete_status', + base_type=BASE_TYPES[0x00], # enum + values={ + 0: 'do_not_delete', + 1: 'delete_one', + 2: 'delete_all', + }, + ), + 'segment_lap_status': FieldType( + name='segment_lap_status', + base_type=BASE_TYPES[0x00], # enum + values={ + 0: 'end', + 1: 'fail', + }, + ), + 'segment_leaderboard_type': FieldType( + name='segment_leaderboard_type', + base_type=BASE_TYPES[0x00], # enum + values={ + 0: 'overall', + 1: 'personal_best', + 2: 'connections', + 3: 'group', + 4: 'challenger', + 5: 'kom', + 6: 'qom', + 7: 'pr', + 8: 'goal', + 9: 'rival', + 10: 'club_leader', + }, + ), + 'segment_selection_type': FieldType( + name='segment_selection_type', + base_type=BASE_TYPES[0x00], # enum + values={ + 0: 'starred', + 1: 'suggested', + }, + ), + 'sensor_type': FieldType( + name='sensor_type', + base_type=BASE_TYPES[0x00], # enum + values={ + 0: 'accelerometer', + 1: 'gyroscope', + 2: 'compass', # Magnetometer + 3: 'barometer', + }, + ), + 'session_trigger': FieldType( + name='session_trigger', + base_type=BASE_TYPES[0x00], # enum + values={ + 0: 'activity_end', + 1: 'manual', # User changed sport. + 2: 'auto_multi_sport', # Auto multi-sport feature is enabled and user pressed lap button to advance session. + 3: 'fitness_equipment', # Auto sport change caused by user linking to fitness equipment. + }, + ), + 'set_type': FieldType( + name='set_type', + base_type=BASE_TYPES[0x02], # uint8 + values={ + 0: 'rest', + 1: 'active', + }, + ), + 'shoulder_press_exercise_name': FieldType( + name='shoulder_press_exercise_name', + base_type=BASE_TYPES[0x84], # uint16 + values={ + 0: 'alternating_dumbbell_shoulder_press', + 1: 'arnold_press', + 2: 'barbell_front_squat_to_push_press', + 3: 'barbell_push_press', + 4: 'barbell_shoulder_press', + 5: 'dead_curl_press', + 6: 'dumbbell_alternating_shoulder_press_and_twist', + 7: 'dumbbell_hammer_curl_to_lunge_to_press', + 8: 'dumbbell_push_press', + 9: 'floor_inverted_shoulder_press', + 10: 'weighted_floor_inverted_shoulder_press', + 11: 'inverted_shoulder_press', + 12: 'weighted_inverted_shoulder_press', + 13: 'one_arm_push_press', + 14: 'overhead_barbell_press', + 15: 'overhead_dumbbell_press', + 16: 'seated_barbell_shoulder_press', + 17: 'seated_dumbbell_shoulder_press', + 18: 'single_arm_dumbbell_shoulder_press', + 19: 'single_arm_step_up_and_press', + 20: 'smith_machine_overhead_press', + 21: 'split_stance_hammer_curl_to_press', + 22: 'swiss_ball_dumbbell_shoulder_press', + 23: 'weight_plate_front_raise', + }, + ), + 'shoulder_stability_exercise_name': FieldType( + name='shoulder_stability_exercise_name', + base_type=BASE_TYPES[0x84], # uint16 + values={ + 0: '90_degree_cable_external_rotation', + 1: 'band_external_rotation', + 2: 'band_internal_rotation', + 3: 'bent_arm_lateral_raise_and_external_rotation', + 4: 'cable_external_rotation', + 5: 'dumbbell_face_pull_with_external_rotation', + 6: 'floor_i_raise', + 7: 'weighted_floor_i_raise', + 8: 'floor_t_raise', + 9: 'weighted_floor_t_raise', + 10: 'floor_y_raise', + 11: 'weighted_floor_y_raise', + 12: 'incline_i_raise', + 13: 'weighted_incline_i_raise', + 14: 'incline_l_raise', + 15: 'weighted_incline_l_raise', + 16: 'incline_t_raise', + 17: 'weighted_incline_t_raise', + 18: 'incline_w_raise', + 19: 'weighted_incline_w_raise', + 20: 'incline_y_raise', + 21: 'weighted_incline_y_raise', + 22: 'lying_external_rotation', + 23: 'seated_dumbbell_external_rotation', + 24: 'standing_l_raise', + 25: 'swiss_ball_i_raise', + 26: 'weighted_swiss_ball_i_raise', + 27: 'swiss_ball_t_raise', + 28: 'weighted_swiss_ball_t_raise', + 29: 'swiss_ball_w_raise', + 30: 'weighted_swiss_ball_w_raise', + 31: 'swiss_ball_y_raise', + 32: 'weighted_swiss_ball_y_raise', + }, + ), + 'shrug_exercise_name': FieldType( + name='shrug_exercise_name', + base_type=BASE_TYPES[0x84], # uint16 + values={ + 0: 'barbell_jump_shrug', + 1: 'barbell_shrug', + 2: 'barbell_upright_row', + 3: 'behind_the_back_smith_machine_shrug', + 4: 'dumbbell_jump_shrug', + 5: 'dumbbell_shrug', + 6: 'dumbbell_upright_row', + 7: 'incline_dumbbell_shrug', + 8: 'overhead_barbell_shrug', + 9: 'overhead_dumbbell_shrug', + 10: 'scaption_and_shrug', + 11: 'scapular_retraction', + 12: 'serratus_chair_shrug', + 13: 'weighted_serratus_chair_shrug', + 14: 'serratus_shrug', + 15: 'weighted_serratus_shrug', + 16: 'wide_grip_jump_shrug', + }, + ), + 'side': FieldType( + name='side', + base_type=BASE_TYPES[0x00], # enum + values={ + 0: 'right', + 1: 'left', + }, + ), + 'sit_up_exercise_name': FieldType( + name='sit_up_exercise_name', + base_type=BASE_TYPES[0x84], # uint16 + values={ + 0: 'alternating_sit_up', + 1: 'weighted_alternating_sit_up', + 2: 'bent_knee_v_up', + 3: 'weighted_bent_knee_v_up', + 4: 'butterfly_sit_up', + 5: 'weighted_butterfly_situp', + 6: 'cross_punch_roll_up', + 7: 'weighted_cross_punch_roll_up', + 8: 'crossed_arms_sit_up', + 9: 'weighted_crossed_arms_sit_up', + 10: 'get_up_sit_up', + 11: 'weighted_get_up_sit_up', + 12: 'hovering_sit_up', + 13: 'weighted_hovering_sit_up', + 14: 'kettlebell_sit_up', + 15: 'medicine_ball_alternating_v_up', + 16: 'medicine_ball_sit_up', + 17: 'medicine_ball_v_up', + 18: 'modified_sit_up', + 19: 'negative_sit_up', + 20: 'one_arm_full_sit_up', + 21: 'reclining_circle', + 22: 'weighted_reclining_circle', + 23: 'reverse_curl_up', + 24: 'weighted_reverse_curl_up', + 25: 'single_leg_swiss_ball_jackknife', + 26: 'weighted_single_leg_swiss_ball_jackknife', + 27: 'the_teaser', + 28: 'the_teaser_weighted', + 29: 'three_part_roll_down', + 30: 'weighted_three_part_roll_down', + 31: 'v_up', + 32: 'weighted_v_up', + 33: 'weighted_russian_twist_on_swiss_ball', + 34: 'weighted_sit_up', + 35: 'x_abs', + 36: 'weighted_x_abs', + 37: 'sit_up', + }, + ), + 'source_type': FieldType( + name='source_type', + base_type=BASE_TYPES[0x00], # enum + values={ + 0: 'ant', # External device connected with ANT + 1: 'antplus', # External device connected with ANT+ + 2: 'bluetooth', # External device connected with BT + 3: 'bluetooth_low_energy', # External device connected with BLE + 4: 'wifi', # External device connected with Wifi + 5: 'local', # Onboard device + }, + ), + 'sport': FieldType( + name='sport', + base_type=BASE_TYPES[0x00], # enum + values={ + 0: 'generic', + 1: 'running', + 2: 'cycling', + 3: 'transition', # Mulitsport transition + 4: 'fitness_equipment', + 5: 'swimming', + 6: 'basketball', + 7: 'soccer', + 8: 'tennis', + 9: 'american_football', + 10: 'training', + 11: 'walking', + 12: 'cross_country_skiing', + 13: 'alpine_skiing', + 14: 'snowboarding', + 15: 'rowing', + 16: 'mountaineering', + 17: 'hiking', + 18: 'multisport', + 19: 'paddling', + 20: 'flying', + 21: 'e_biking', + 22: 'motorcycling', + 23: 'boating', + 24: 'driving', + 25: 'golf', + 26: 'hang_gliding', + 27: 'horseback_riding', + 28: 'hunting', + 29: 'fishing', + 30: 'inline_skating', + 31: 'rock_climbing', + 32: 'sailing', + 33: 'ice_skating', + 34: 'sky_diving', + 35: 'snowshoeing', + 36: 'snowmobiling', + 37: 'stand_up_paddleboarding', + 38: 'surfing', + 39: 'wakeboarding', + 40: 'water_skiing', + 41: 'kayaking', + 42: 'rafting', + 43: 'windsurfing', + 44: 'kitesurfing', + 45: 'tactical', + 46: 'jumpmaster', + 47: 'boxing', + 48: 'floor_climbing', + 254: 'all', # All is for goals only to include all sports. + }, + ), + 'sport_bits_0': FieldType( # Bit field corresponding to sport enum type (1 << sport). + name='sport_bits_0', + base_type=BASE_TYPES[0x0A], # uint8z + values={ + 0x01: 'generic', + 0x02: 'running', + 0x04: 'cycling', + 0x08: 'transition', # Mulitsport transition + 0x10: 'fitness_equipment', + 0x20: 'swimming', + 0x40: 'basketball', + 0x80: 'soccer', + }, + ), + 'sport_bits_1': FieldType( # Bit field corresponding to sport enum type (1 << (sport-8)). + name='sport_bits_1', + base_type=BASE_TYPES[0x0A], # uint8z + values={ + 0x01: 'tennis', + 0x02: 'american_football', + 0x04: 'training', + 0x08: 'walking', + 0x10: 'cross_country_skiing', + 0x20: 'alpine_skiing', + 0x40: 'snowboarding', + 0x80: 'rowing', + }, + ), + 'sport_bits_2': FieldType( # Bit field corresponding to sport enum type (1 << (sport-16)). + name='sport_bits_2', + base_type=BASE_TYPES[0x0A], # uint8z + values={ + 0x01: 'mountaineering', + 0x02: 'hiking', + 0x04: 'multisport', + 0x08: 'paddling', + 0x10: 'flying', + 0x20: 'e_biking', + 0x40: 'motorcycling', + 0x80: 'boating', + }, + ), + 'sport_bits_3': FieldType( # Bit field corresponding to sport enum type (1 << (sport-24)). + name='sport_bits_3', + base_type=BASE_TYPES[0x0A], # uint8z + values={ + 0x01: 'driving', + 0x02: 'golf', + 0x04: 'hang_gliding', + 0x08: 'horseback_riding', + 0x10: 'hunting', + 0x20: 'fishing', + 0x40: 'inline_skating', + 0x80: 'rock_climbing', + }, + ), + 'sport_bits_4': FieldType( # Bit field corresponding to sport enum type (1 << (sport-32)). + name='sport_bits_4', + base_type=BASE_TYPES[0x0A], # uint8z + values={ + 0x01: 'sailing', + 0x02: 'ice_skating', + 0x04: 'sky_diving', + 0x08: 'snowshoeing', + 0x10: 'snowmobiling', + 0x20: 'stand_up_paddleboarding', + 0x40: 'surfing', + 0x80: 'wakeboarding', + }, + ), + 'sport_bits_5': FieldType( # Bit field corresponding to sport enum type (1 << (sport-40)). + name='sport_bits_5', + base_type=BASE_TYPES[0x0A], # uint8z + values={ + 0x01: 'water_skiing', + 0x02: 'kayaking', + 0x04: 'rafting', + 0x08: 'windsurfing', + 0x10: 'kitesurfing', + 0x20: 'tactical', + 0x40: 'jumpmaster', + 0x80: 'boxing', + }, + ), + 'sport_bits_6': FieldType( # Bit field corresponding to sport enum type (1 << (sport-48)). + name='sport_bits_6', + base_type=BASE_TYPES[0x0A], # uint8z + values={ + 0x01: 'floor_climbing', + }, + ), + 'sport_event': FieldType( + name='sport_event', + base_type=BASE_TYPES[0x00], # enum + values={ + 0: 'uncategorized', + 1: 'geocaching', + 2: 'fitness', + 3: 'recreation', + 4: 'race', + 5: 'special_event', + 6: 'training', + 7: 'transportation', + 8: 'touring', + }, + ), + 'squat_exercise_name': FieldType( + name='squat_exercise_name', + base_type=BASE_TYPES[0x84], # uint16 + values={ + 0: 'leg_press', + 1: 'back_squat_with_body_bar', + 2: 'back_squats', + 3: 'weighted_back_squats', + 4: 'balancing_squat', + 5: 'weighted_balancing_squat', + 6: 'barbell_back_squat', + 7: 'barbell_box_squat', + 8: 'barbell_front_squat', + 9: 'barbell_hack_squat', + 10: 'barbell_hang_squat_snatch', + 11: 'barbell_lateral_step_up', + 12: 'barbell_quarter_squat', + 13: 'barbell_siff_squat', + 14: 'barbell_squat_snatch', + 15: 'barbell_squat_with_heels_raised', + 16: 'barbell_stepover', + 17: 'barbell_step_up', + 18: 'bench_squat_with_rotational_chop', + 19: 'weighted_bench_squat_with_rotational_chop', + 20: 'body_weight_wall_squat', + 21: 'weighted_wall_squat', + 22: 'box_step_squat', + 23: 'weighted_box_step_squat', + 24: 'braced_squat', + 25: 'crossed_arm_barbell_front_squat', + 26: 'crossover_dumbbell_step_up', + 27: 'dumbbell_front_squat', + 28: 'dumbbell_split_squat', + 29: 'dumbbell_squat', + 30: 'dumbbell_squat_clean', + 31: 'dumbbell_stepover', + 32: 'dumbbell_step_up', + 33: 'elevated_single_leg_squat', + 34: 'weighted_elevated_single_leg_squat', + 35: 'figure_four_squats', + 36: 'weighted_figure_four_squats', + 37: 'goblet_squat', + 38: 'kettlebell_squat', + 39: 'kettlebell_swing_overhead', + 40: 'kettlebell_swing_with_flip_to_squat', + 41: 'lateral_dumbbell_step_up', + 42: 'one_legged_squat', + 43: 'overhead_dumbbell_squat', + 44: 'overhead_squat', + 45: 'partial_single_leg_squat', + 46: 'weighted_partial_single_leg_squat', + 47: 'pistol_squat', + 48: 'weighted_pistol_squat', + 49: 'plie_slides', + 50: 'weighted_plie_slides', + 51: 'plie_squat', + 52: 'weighted_plie_squat', + 53: 'prisoner_squat', + 54: 'weighted_prisoner_squat', + 55: 'single_leg_bench_get_up', + 56: 'weighted_single_leg_bench_get_up', + 57: 'single_leg_bench_squat', + 58: 'weighted_single_leg_bench_squat', + 59: 'single_leg_squat_on_swiss_ball', + 60: 'weighted_single_leg_squat_on_swiss_ball', + 61: 'squat', + 62: 'weighted_squat', + 63: 'squats_with_band', + 64: 'staggered_squat', + 65: 'weighted_staggered_squat', + 66: 'step_up', + 67: 'weighted_step_up', + 68: 'suitcase_squats', + 69: 'sumo_squat', + 70: 'sumo_squat_slide_in', + 71: 'weighted_sumo_squat_slide_in', + 72: 'sumo_squat_to_high_pull', + 73: 'sumo_squat_to_stand', + 74: 'weighted_sumo_squat_to_stand', + 75: 'sumo_squat_with_rotation', + 76: 'weighted_sumo_squat_with_rotation', + 77: 'swiss_ball_body_weight_wall_squat', + 78: 'weighted_swiss_ball_wall_squat', + 79: 'thrusters', + 80: 'uneven_squat', + 81: 'weighted_uneven_squat', + 82: 'waist_slimming_squat', + 83: 'wall_ball', + 84: 'wide_stance_barbell_squat', + 85: 'wide_stance_goblet_squat', + 86: 'zercher_squat', + }, + ), + 'stroke_type': FieldType( + name='stroke_type', + base_type=BASE_TYPES[0x00], # enum + values={ + 0: 'no_event', + 1: 'other', # stroke was detected but cannot be identified + 2: 'serve', + 3: 'forehand', + 4: 'backhand', + 5: 'smash', + }, + ), + 'sub_sport': FieldType( + name='sub_sport', + base_type=BASE_TYPES[0x00], # enum + values={ + 0: 'generic', + 1: 'treadmill', # Run/Fitness Equipment + 2: 'street', # Run + 3: 'trail', # Run + 4: 'track', # Run + 5: 'spin', # Cycling + 6: 'indoor_cycling', # Cycling/Fitness Equipment + 7: 'road', # Cycling + 8: 'mountain', # Cycling + 9: 'downhill', # Cycling + 10: 'recumbent', # Cycling + 11: 'cyclocross', # Cycling + 12: 'hand_cycling', # Cycling + 13: 'track_cycling', # Cycling + 14: 'indoor_rowing', # Fitness Equipment + 15: 'elliptical', # Fitness Equipment + 16: 'stair_climbing', # Fitness Equipment + 17: 'lap_swimming', # Swimming + 18: 'open_water', # Swimming + 19: 'flexibility_training', # Training + 20: 'strength_training', # Training + 21: 'warm_up', # Tennis + 22: 'match', # Tennis + 23: 'exercise', # Tennis + 24: 'challenge', + 25: 'indoor_skiing', # Fitness Equipment + 26: 'cardio_training', # Training + 27: 'indoor_walking', # Walking/Fitness Equipment + 28: 'e_bike_fitness', # E-Biking + 29: 'bmx', # Cycling + 30: 'casual_walking', # Walking + 31: 'speed_walking', # Walking + 32: 'bike_to_run_transition', # Transition + 33: 'run_to_bike_transition', # Transition + 34: 'swim_to_bike_transition', # Transition + 35: 'atv', # Motorcycling + 36: 'motocross', # Motorcycling + 37: 'backcountry', # Alpine Skiing/Snowboarding + 38: 'resort', # Alpine Skiing/Snowboarding + 39: 'rc_drone', # Flying + 40: 'wingsuit', # Flying + 41: 'whitewater', # Kayaking/Rafting + 42: 'skate_skiing', # Cross Country Skiing + 43: 'yoga', # Training + 44: 'pilates', # Training + 45: 'indoor_running', # Run + 46: 'gravel_cycling', # Cycling + 47: 'e_bike_mountain', # Cycling + 48: 'commuting', # Cycling + 49: 'mixed_surface', # Cycling + 50: 'navigate', + 51: 'track_me', + 52: 'map', + 53: 'single_gas_diving', # Diving + 54: 'multi_gas_diving', # Diving + 55: 'gauge_diving', # Diving + 56: 'apnea_diving', # Diving + 57: 'apnea_hunting', # Diving + 58: 'virtual_activity', + 59: 'obstacle', # Used for events where participants run, crawl through mud, climb over walls, etc. + 254: 'all', + }, + ), + 'supported_exd_screen_layouts': FieldType( + name='supported_exd_screen_layouts', + base_type=BASE_TYPES[0x8C], # uint32z + values={ + 0x00000001: 'full_screen', + 0x00000002: 'half_vertical', + 0x00000004: 'half_horizontal', + 0x00000008: 'half_vertical_right_split', + 0x00000010: 'half_horizontal_bottom_split', + 0x00000020: 'full_quarter_split', + 0x00000040: 'half_vertical_left_split', + 0x00000080: 'half_horizontal_top_split', + }, + ), + 'swim_stroke': FieldType( + name='swim_stroke', + base_type=BASE_TYPES[0x00], # enum + values={ + 0: 'freestyle', + 1: 'backstroke', + 2: 'breaststroke', + 3: 'butterfly', + 4: 'drill', + 5: 'mixed', + 6: 'im', # IM is a mixed interval containing the same number of lengths for each of: Butterfly, Backstroke, Breaststroke, Freestyle, swam in that order. + }, + ), + 'switch': FieldType( + name='switch', + base_type=BASE_TYPES[0x00], # enum + values={ + 0: 'off', + 1: 'on', + 2: 'auto', + }, + ), + '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 + ), + 'time_mode': FieldType( + name='time_mode', + base_type=BASE_TYPES[0x00], # enum + values={ + 0: 'hour12', + 1: 'hour24', # Does not use a leading zero and has a colon + 2: 'military', # Uses a leading zero and does not have a colon + 3: 'hour_12_with_seconds', + 4: 'hour_24_with_seconds', + 5: 'utc', + }, + ), + 'time_zone': FieldType( + name='time_zone', + base_type=BASE_TYPES[0x00], # enum + values={ + 0: 'almaty', + 1: 'bangkok', + 2: 'bombay', + 3: 'brasilia', + 4: 'cairo', + 5: 'cape_verde_is', + 6: 'darwin', + 7: 'eniwetok', + 8: 'fiji', + 9: 'hong_kong', + 10: 'islamabad', + 11: 'kabul', + 12: 'magadan', + 13: 'mid_atlantic', + 14: 'moscow', + 15: 'muscat', + 16: 'newfoundland', + 17: 'samoa', + 18: 'sydney', + 19: 'tehran', + 20: 'tokyo', + 21: 'us_alaska', + 22: 'us_atlantic', + 23: 'us_central', + 24: 'us_eastern', + 25: 'us_hawaii', + 26: 'us_mountain', + 27: 'us_pacific', + 28: 'other', + 29: 'auckland', + 30: 'kathmandu', + 31: 'europe_western_wet', + 32: 'europe_central_cet', + 33: 'europe_eastern_eet', + 34: 'jakarta', + 35: 'perth', + 36: 'adelaide', + 37: 'brisbane', + 38: 'tasmania', + 39: 'iceland', + 40: 'amsterdam', + 41: 'athens', + 42: 'barcelona', + 43: 'berlin', + 44: 'brussels', + 45: 'budapest', + 46: 'copenhagen', + 47: 'dublin', + 48: 'helsinki', + 49: 'lisbon', + 50: 'london', + 51: 'madrid', + 52: 'munich', + 53: 'oslo', + 54: 'paris', + 55: 'prague', + 56: 'reykjavik', + 57: 'rome', + 58: 'stockholm', + 59: 'vienna', + 60: 'warsaw', + 61: 'zurich', + 62: 'quebec', + 63: 'ontario', + 64: 'manitoba', + 65: 'saskatchewan', + 66: 'alberta', + 67: 'british_columbia', + 68: 'boise', + 69: 'boston', + 70: 'chicago', + 71: 'dallas', + 72: 'denver', + 73: 'kansas_city', + 74: 'las_vegas', + 75: 'los_angeles', + 76: 'miami', + 77: 'minneapolis', + 78: 'new_york', + 79: 'new_orleans', + 80: 'phoenix', + 81: 'santa_fe', + 82: 'seattle', + 83: 'washington_dc', + 84: 'us_arizona', + 85: 'chita', + 86: 'ekaterinburg', + 87: 'irkutsk', + 88: 'kaliningrad', + 89: 'krasnoyarsk', + 90: 'novosibirsk', + 91: 'petropavlovsk_kamchatskiy', + 92: 'samara', + 93: 'vladivostok', + 94: 'mexico_central', + 95: 'mexico_mountain', + 96: 'mexico_pacific', + 97: 'cape_town', + 98: 'winkhoek', + 99: 'lagos', + 100: 'riyahd', + 101: 'venezuela', + 102: 'australia_lh', + 103: 'santiago', + 253: 'manual', + 254: 'automatic', + }, + ), + 'timer_trigger': FieldType( # timer event data + name='timer_trigger', + base_type=BASE_TYPES[0x00], # enum + values={ + 0: 'manual', + 1: 'auto', + 2: 'fitness_equipment', + }, + ), + 'tissue_model_type': FieldType( + name='tissue_model_type', + base_type=BASE_TYPES[0x00], # enum + values={ + 0: 'zhl_16c', # Buhlmann's decompression algorithm, version C + }, + ), + 'tone': FieldType( + name='tone', + base_type=BASE_TYPES[0x00], # enum + values={ + 0: 'off', + 1: 'tone', + 2: 'vibrate', + 3: 'tone_and_vibrate', + }, + ), + 'total_body_exercise_name': FieldType( + name='total_body_exercise_name', + base_type=BASE_TYPES[0x84], # uint16 + values={ + 0: 'burpee', + 1: 'weighted_burpee', + 2: 'burpee_box_jump', + 3: 'weighted_burpee_box_jump', + 4: 'high_pull_burpee', + 5: 'man_makers', + 6: 'one_arm_burpee', + 7: 'squat_thrusts', + 8: 'weighted_squat_thrusts', + 9: 'squat_plank_push_up', + 10: 'weighted_squat_plank_push_up', + 11: 'standing_t_rotation_balance', + 12: 'weighted_standing_t_rotation_balance', + }, + ), + 'triceps_extension_exercise_name': FieldType( + name='triceps_extension_exercise_name', + base_type=BASE_TYPES[0x84], # uint16 + values={ + 0: 'bench_dip', + 1: 'weighted_bench_dip', + 2: 'body_weight_dip', + 3: 'cable_kickback', + 4: 'cable_lying_triceps_extension', + 5: 'cable_overhead_triceps_extension', + 6: 'dumbbell_kickback', + 7: 'dumbbell_lying_triceps_extension', + 8: 'ez_bar_overhead_triceps_extension', + 9: 'incline_dip', + 10: 'weighted_incline_dip', + 11: 'incline_ez_bar_lying_triceps_extension', + 12: 'lying_dumbbell_pullover_to_extension', + 13: 'lying_ez_bar_triceps_extension', + 14: 'lying_triceps_extension_to_close_grip_bench_press', + 15: 'overhead_dumbbell_triceps_extension', + 16: 'reclining_triceps_press', + 17: 'reverse_grip_pressdown', + 18: 'reverse_grip_triceps_pressdown', + 19: 'rope_pressdown', + 20: 'seated_barbell_overhead_triceps_extension', + 21: 'seated_dumbbell_overhead_triceps_extension', + 22: 'seated_ez_bar_overhead_triceps_extension', + 23: 'seated_single_arm_overhead_dumbbell_extension', + 24: 'single_arm_dumbbell_overhead_triceps_extension', + 25: 'single_dumbbell_seated_overhead_triceps_extension', + 26: 'single_leg_bench_dip_and_kick', + 27: 'weighted_single_leg_bench_dip_and_kick', + 28: 'single_leg_dip', + 29: 'weighted_single_leg_dip', + 30: 'static_lying_triceps_extension', + 31: 'suspended_dip', + 32: 'weighted_suspended_dip', + 33: 'swiss_ball_dumbbell_lying_triceps_extension', + 34: 'swiss_ball_ez_bar_lying_triceps_extension', + 35: 'swiss_ball_ez_bar_overhead_triceps_extension', + 36: 'tabletop_dip', + 37: 'weighted_tabletop_dip', + 38: 'triceps_extension_on_floor', + 39: 'triceps_pressdown', + 40: 'weighted_dip', + }, + ), + 'turn_type': FieldType( + name='turn_type', + base_type=BASE_TYPES[0x00], # enum + values={ + 0: 'arriving_idx', + 1: 'arriving_left_idx', + 2: 'arriving_right_idx', + 3: 'arriving_via_idx', + 4: 'arriving_via_left_idx', + 5: 'arriving_via_right_idx', + 6: 'bear_keep_left_idx', + 7: 'bear_keep_right_idx', + 8: 'continue_idx', + 9: 'exit_left_idx', + 10: 'exit_right_idx', + 11: 'ferry_idx', + 12: 'roundabout_45_idx', + 13: 'roundabout_90_idx', + 14: 'roundabout_135_idx', + 15: 'roundabout_180_idx', + 16: 'roundabout_225_idx', + 17: 'roundabout_270_idx', + 18: 'roundabout_315_idx', + 19: 'roundabout_360_idx', + 20: 'roundabout_neg_45_idx', + 21: 'roundabout_neg_90_idx', + 22: 'roundabout_neg_135_idx', + 23: 'roundabout_neg_180_idx', + 24: 'roundabout_neg_225_idx', + 25: 'roundabout_neg_270_idx', + 26: 'roundabout_neg_315_idx', + 27: 'roundabout_neg_360_idx', + 28: 'roundabout_generic_idx', + 29: 'roundabout_neg_generic_idx', + 30: 'sharp_turn_left_idx', + 31: 'sharp_turn_right_idx', + 32: 'turn_left_idx', + 33: 'turn_right_idx', + 34: 'uturn_left_idx', + 35: 'uturn_right_idx', + 36: 'icon_inv_idx', + 37: 'icon_idx_cnt', + }, + ), + 'user_local_id': FieldType( + name='user_local_id', + base_type=BASE_TYPES[0x84], # uint16 + values={ + 0x0000: 'local_min', + 0x000F: 'local_max', + 0x0010: 'stationary_min', + 0x00FF: 'stationary_max', + 0x0100: 'portable_min', + 0xFFFE: 'portable_max', + }, + ), + 'warm_up_exercise_name': FieldType( + name='warm_up_exercise_name', + base_type=BASE_TYPES[0x84], # uint16 + values={ + 0: 'quadruped_rocking', + 1: 'neck_tilts', + 2: 'ankle_circles', + 3: 'ankle_dorsiflexion_with_band', + 4: 'ankle_internal_rotation', + 5: 'arm_circles', + 6: 'bent_over_reach_to_sky', + 7: 'cat_camel', + 8: 'elbow_to_foot_lunge', + 9: 'forward_and_backward_leg_swings', + 10: 'groiners', + 11: 'inverted_hamstring_stretch', + 12: 'lateral_duck_under', + 13: 'neck_rotations', + 14: 'opposite_arm_and_leg_balance', + 15: 'reach_roll_and_lift', + 16: 'scorpion', + 17: 'shoulder_circles', + 18: 'side_to_side_leg_swings', + 19: 'sleeper_stretch', + 20: 'slide_out', + 21: 'swiss_ball_hip_crossover', + 22: 'swiss_ball_reach_roll_and_lift', + 23: 'swiss_ball_windshield_wipers', + 24: 'thoracic_rotation', + 25: 'walking_high_kicks', + 26: 'walking_high_knees', + 27: 'walking_knee_hugs', + 28: 'walking_leg_cradles', + 29: 'walkout', + 30: 'walkout_from_push_up_position', + }, + ), + 'watchface_mode': FieldType( + name='watchface_mode', + base_type=BASE_TYPES[0x00], # enum + values={ + 0: 'digital', + 1: 'analog', + 2: 'connect_iq', + 3: 'disabled', + }, + ), + 'water_type': FieldType( + name='water_type', + base_type=BASE_TYPES[0x00], # enum + values={ + 0: 'fresh', + 1: 'salt', + 2: 'en13319', + 3: 'custom', + }, + ), + 'weather_report': FieldType( + name='weather_report', + base_type=BASE_TYPES[0x00], # enum + values={ + 0: 'current', + 1: 'forecast', # Deprecated use hourly_forecast instead + 1: 'hourly_forecast', + 2: 'daily_forecast', + }, + ), + 'weather_severe_type': FieldType( + name='weather_severe_type', + base_type=BASE_TYPES[0x00], # enum + values={ + 0: 'unspecified', + 1: 'tornado', + 2: 'tsunami', + 3: 'hurricane', + 4: 'extreme_wind', + 5: 'typhoon', + 6: 'inland_hurricane', + 7: 'hurricane_force_wind', + 8: 'waterspout', + 9: 'severe_thunderstorm', + 10: 'wreckhouse_winds', + 11: 'les_suetes_wind', + 12: 'avalanche', + 13: 'flash_flood', + 14: 'tropical_storm', + 15: 'inland_tropical_storm', + 16: 'blizzard', + 17: 'ice_storm', + 18: 'freezing_rain', + 19: 'debris_flow', + 20: 'flash_freeze', + 21: 'dust_storm', + 22: 'high_wind', + 23: 'winter_storm', + 24: 'heavy_freezing_spray', + 25: 'extreme_cold', + 26: 'wind_chill', + 27: 'cold_wave', + 28: 'heavy_snow_alert', + 29: 'lake_effect_blowing_snow', + 30: 'snow_squall', + 31: 'lake_effect_snow', + 32: 'winter_weather', + 33: 'sleet', + 34: 'snowfall', + 35: 'snow_and_blowing_snow', + 36: 'blowing_snow', + 37: 'snow_alert', + 38: 'arctic_outflow', + 39: 'freezing_drizzle', + 40: 'storm', + 41: 'storm_surge', + 42: 'rainfall', + 43: 'areal_flood', + 44: 'coastal_flood', + 45: 'lakeshore_flood', + 46: 'excessive_heat', + 47: 'heat', + 48: 'weather', + 49: 'high_heat_and_humidity', + 50: 'humidex_and_health', + 51: 'humidex', + 52: 'gale', + 53: 'freezing_spray', + 54: 'special_marine', + 55: 'squall', + 56: 'strong_wind', + 57: 'lake_wind', + 58: 'marine_weather', + 59: 'wind', + 60: 'small_craft_hazardous_seas', + 61: 'hazardous_seas', + 62: 'small_craft', + 63: 'small_craft_winds', + 64: 'small_craft_rough_bar', + 65: 'high_water_level', + 66: 'ashfall', + 67: 'freezing_fog', + 68: 'dense_fog', + 69: 'dense_smoke', + 70: 'blowing_dust', + 71: 'hard_freeze', + 72: 'freeze', + 73: 'frost', + 74: 'fire_weather', + 75: 'flood', + 76: 'rip_tide', + 77: 'high_surf', + 78: 'smog', + 79: 'air_quality', + 80: 'brisk_wind', + 81: 'air_stagnation', + 82: 'low_water', + 83: 'hydrological', + 84: 'special_weather', + }, + ), + 'weather_severity': FieldType( + name='weather_severity', + base_type=BASE_TYPES[0x00], # enum + values={ + 0: 'unknown', + 1: 'warning', + 2: 'watch', + 3: 'advisory', + 4: 'statement', + }, + ), + 'weather_status': FieldType( + name='weather_status', + base_type=BASE_TYPES[0x00], # enum + values={ + 0: 'clear', + 1: 'partly_cloudy', + 2: 'mostly_cloudy', + 3: 'rain', + 4: 'snow', + 5: 'windy', + 6: 'thunderstorms', + 7: 'wintry_mix', + 8: 'fog', + 11: 'hazy', + 12: 'hail', + 13: 'scattered_showers', + 14: 'scattered_thunderstorms', + 15: 'unknown_precipitation', + 16: 'light_rain', + 17: 'heavy_rain', + 18: 'light_snow', + 19: 'heavy_snow', + 20: 'light_rain_snow', + 21: 'heavy_rain_snow', + 22: 'cloudy', + }, + ), + 'weight': FieldType( + name='weight', + base_type=BASE_TYPES[0x84], # uint16 + values={ + 0xFFFE: 'calculating', + }, + ), + 'wkt_step_duration': FieldType( + name='wkt_step_duration', + base_type=BASE_TYPES[0x00], # enum + values={ + 0: 'time', + 1: 'distance', + 2: 'hr_less_than', + 3: 'hr_greater_than', + 4: 'calories', + 5: 'open', + 6: 'repeat_until_steps_cmplt', + 7: 'repeat_until_time', + 8: 'repeat_until_distance', + 9: 'repeat_until_calories', + 10: 'repeat_until_hr_less_than', + 11: 'repeat_until_hr_greater_than', + 12: 'repeat_until_power_less_than', + 13: 'repeat_until_power_greater_than', + 14: 'power_less_than', + 15: 'power_greater_than', + 16: 'training_peaks_tss', + 17: 'repeat_until_power_last_lap_less_than', + 18: 'repeat_until_max_power_last_lap_less_than', + 19: 'power_3s_less_than', + 20: 'power_10s_less_than', + 21: 'power_30s_less_than', + 22: 'power_3s_greater_than', + 23: 'power_10s_greater_than', + 24: 'power_30s_greater_than', + 25: 'power_lap_less_than', + 26: 'power_lap_greater_than', + 27: 'repeat_until_training_peaks_tss', + 28: 'repetition_time', + 29: 'reps', + }, + ), + 'wkt_step_target': FieldType( + name='wkt_step_target', + base_type=BASE_TYPES[0x00], # enum + values={ + 0: 'speed', + 1: 'heart_rate', + 2: 'open', + 3: 'cadence', + 4: 'power', + 5: 'grade', + 6: 'resistance', + 7: 'power_3s', + 8: 'power_10s', + 9: 'power_30s', + 10: 'power_lap', + 11: 'swim_stroke', + 12: 'speed_lap', + 13: 'heart_rate_lap', + }, + ), + 'workout_capabilities': FieldType( + name='workout_capabilities', + base_type=BASE_TYPES[0x8C], # uint32z + values={ + 0x00000001: 'interval', + 0x00000002: 'custom', + 0x00000004: 'fitness_equipment', + 0x00000008: 'firstbeat', + 0x00000010: 'new_leaf', + 0x00000020: 'tcx', # For backwards compatibility. Watch should add missing id fields then clear flag. + 0x00000080: 'speed', # Speed source required for workout step. + 0x00000100: 'heart_rate', # Heart rate source required for workout step. + 0x00000200: 'distance', # Distance source required for workout step. + 0x00000400: 'cadence', # Cadence source required for workout step. + 0x00000800: 'power', # Power source required for workout step. + 0x00001000: 'grade', # Grade source required for workout step. + 0x00002000: 'resistance', # Resistance source required for workout step. + 0x00004000: 'protected', + }, + ), + 'workout_equipment': FieldType( + name='workout_equipment', + base_type=BASE_TYPES[0x00], # enum + values={ + 0: 'none', + 1: 'swim_fins', + 2: 'swim_kickboard', + 3: 'swim_paddles', + 4: 'swim_pull_buoy', + 5: 'swim_snorkel', + }, + ), + 'workout_hr': FieldType( # 0 - 100 indicates% of max hr; >100 indicates bpm (255 max) plus 100 + name='workout_hr', + base_type=BASE_TYPES[0x86], # uint32 + values={ + 100: 'bpm_offset', + }, + ), + 'workout_power': FieldType( # 0 - 1000 indicates % of functional threshold power; >1000 indicates watts plus 1000. + name='workout_power', + base_type=BASE_TYPES[0x86], # uint32 + values={ + 1000: 'watts_offset', + }, + ), +} + + +FIELD_TYPE_TIMESTAMP = Field(name='timestamp', type=FIELD_TYPES['date_time'], def_num=253, units='s') + + +MESSAGE_TYPES = { + # **************************** Common Messages ***************************** + 0: MessageType( # Must be first message in file. + name='file_id', + mesg_num=0, + fields={ + 0: Field( + name='type', + type=FIELD_TYPES['file'], + def_num=0, + ), + 1: Field( + name='manufacturer', + type=FIELD_TYPES['manufacturer'], + def_num=1, + ), + 2: Field( + name='product', + type=BASE_TYPES[0x84], # uint16 + def_num=2, + subfields=( + SubField( + name='garmin_product', + def_num=2, + type=FIELD_TYPES['garmin_product'], + ref_fields=( + ReferenceField( + name='manufacturer', + def_num=1, + value='garmin', + raw_value=1, + ), + ReferenceField( + name='manufacturer', + def_num=1, + value='dynastream', + raw_value=15, + ), + ReferenceField( + name='manufacturer', + def_num=1, + value='dynastream_oem', + raw_value=13, + ), + ), + ), + ), + ), + 3: Field( + name='serial_number', + type=BASE_TYPES[0x8C], # uint32z + def_num=3, + ), + 4: Field( # Only set for files that are can be created/erased. + name='time_created', + type=FIELD_TYPES['date_time'], + def_num=4, + ), + 5: Field( # Only set for files that are not created/erased. + name='number', + type=BASE_TYPES[0x84], # uint16 + def_num=5, + ), + 8: Field( # Optional free form string to indicate the devices name or model + name='product_name', + type=BASE_TYPES[0x07], # string + def_num=8, + ), + }, + ), + + + # ************************************ ************************************ + 1: MessageType( + name='capabilities', + mesg_num=1, + fields={ + 0: Field( # Use language_bits_x types where x is index of array. + name='languages', + type=BASE_TYPES[0x0A], # uint8z + def_num=0, + ), + 1: Field( # Use sport_bits_x types where x is index of array. + name='sports', + type=FIELD_TYPES['sport_bits_0'], + def_num=1, + ), + 21: Field( + name='workouts_supported', + type=FIELD_TYPES['workout_capabilities'], + def_num=21, + ), + 23: Field( + name='connectivity_supported', + type=FIELD_TYPES['connectivity_capabilities'], + def_num=23, + ), + }, + ), + 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', + type=BASE_TYPES[0x84], # uint16 + def_num=11, + scale=10, + units='%', + ), + 12: Field( + name='auto_wheel_cal', + type=FIELD_TYPES['bool'], + def_num=12, + ), + 13: Field( + name='auto_power_zero', + type=FIELD_TYPES['bool'], + def_num=13, + ), + 14: Field( + name='id', + type=BASE_TYPES[0x02], # uint8 + def_num=14, + ), + 15: Field( + name='spd_enabled', + type=FIELD_TYPES['bool'], + def_num=15, + ), + 16: Field( + name='cad_enabled', + type=FIELD_TYPES['bool'], + def_num=16, + ), + 17: Field( + name='spdcad_enabled', + type=FIELD_TYPES['bool'], + def_num=17, + ), + 18: Field( + name='power_enabled', + type=FIELD_TYPES['bool'], + def_num=18, + ), + 19: Field( + name='crank_length', + type=BASE_TYPES[0x02], # uint8 + def_num=19, + scale=2, + offset=-110, + units='mm', + ), + 20: Field( + name='enabled', + type=FIELD_TYPES['bool'], + def_num=20, + ), + 21: Field( + name='bike_spd_ant_id_trans_type', + type=BASE_TYPES[0x0A], # uint8z + def_num=21, + ), + 22: Field( + name='bike_cad_ant_id_trans_type', + type=BASE_TYPES[0x0A], # uint8z + def_num=22, + ), + 23: Field( + name='bike_spdcad_ant_id_trans_type', + type=BASE_TYPES[0x0A], # uint8z + def_num=23, + ), + 24: Field( + name='bike_power_ant_id_trans_type', + type=BASE_TYPES[0x0A], # uint8z + def_num=24, + ), + 37: Field( # Rollover counter that can be used to extend the odometer + name='odometer_rollover', + type=BASE_TYPES[0x02], # uint8 + def_num=37, + ), + 38: Field( # Number of front gears + name='front_gear_num', + type=BASE_TYPES[0x0A], # uint8z + def_num=38, + ), + 39: Field( # Number of teeth on each gear 0 is innermost + name='front_gear', + type=BASE_TYPES[0x0A], # uint8z + def_num=39, + ), + 40: Field( # Number of rear gears + name='rear_gear_num', + type=BASE_TYPES[0x0A], # uint8z + def_num=40, + ), + 41: Field( # Number of teeth on each gear 0 is innermost + name='rear_gear', + type=BASE_TYPES[0x0A], # uint8z + def_num=41, + ), + 44: Field( + name='shimano_di2_enabled', + type=FIELD_TYPES['bool'], + def_num=44, + ), + 254: Field( + name='message_index', + type=FIELD_TYPES['message_index'], + def_num=254, + ), + }, + ), + 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( + name='message_index', + type=FIELD_TYPES['message_index'], + def_num=254, + ), + }, + ), + 9: MessageType( + name='power_zone', + mesg_num=9, + fields={ + 1: Field( + name='high_value', + type=BASE_TYPES[0x84], # uint16 + def_num=1, + units='watts', + ), + 2: Field( + name='name', + type=BASE_TYPES[0x07], # string + def_num=2, + ), + 254: Field( + name='message_index', + type=FIELD_TYPES['message_index'], + def_num=254, + ), + }, + ), + 10: MessageType( + name='met_zone', + mesg_num=10, + fields={ + 1: Field( + name='high_bpm', + type=BASE_TYPES[0x02], # uint8 + def_num=1, + ), + 2: Field( + name='calories', + type=BASE_TYPES[0x84], # uint16 + def_num=2, + scale=10, + units='kcal/min', + ), + 3: Field( + name='fat_calories', + type=BASE_TYPES[0x02], # uint8 + def_num=3, + scale=10, + units='kcal/min', + ), + 254: Field( + name='message_index', + type=FIELD_TYPES['message_index'], + def_num=254, + ), + }, + ), + 12: MessageType( + name='sport', + mesg_num=12, + 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, + ), + 3: Field( + name='name', + type=BASE_TYPES[0x07], # string + def_num=3, + ), + }, + ), + 18: MessageType( + name='session', + mesg_num=18, + fields={ + 0: Field( # session + name='event', + type=FIELD_TYPES['event'], + def_num=0, + ), + 1: Field( # stop + name='event_type', + type=FIELD_TYPES['event_type'], + def_num=1, + ), + 2: Field( + name='start_time', + type=FIELD_TYPES['date_time'], + def_num=2, + ), + 3: Field( + name='start_position_lat', + type=BASE_TYPES[0x85], # sint32 + def_num=3, + units='semicircles', + ), + 4: Field( + name='start_position_long', + type=BASE_TYPES[0x85], # sint32 + def_num=4, + units='semicircles', + ), + 5: Field( + name='sport', + type=FIELD_TYPES['sport'], + def_num=5, + ), + 6: Field( + name='sub_sport', + type=FIELD_TYPES['sub_sport'], + def_num=6, + ), + 7: Field( # Time (includes pauses) + name='total_elapsed_time', + type=BASE_TYPES[0x86], # uint32 + def_num=7, + scale=1000, + units='s', + ), + 8: Field( # Timer Time (excludes pauses) + name='total_timer_time', + type=BASE_TYPES[0x86], # uint32 + def_num=8, + scale=1000, + units='s', + ), + 9: Field( + name='total_distance', + type=BASE_TYPES[0x86], # uint32 + def_num=9, + scale=100, + units='m', + ), + 10: Field( + name='total_cycles', + type=BASE_TYPES[0x86], # uint32 + def_num=10, + units='cycles', + subfields=( + SubField( + name='total_strides', + def_num=10, + type=BASE_TYPES[0x86], # uint32 + units='strides', + ref_fields=( + ReferenceField( + name='sport', + def_num=5, + value='running', + raw_value=1, + ), + ReferenceField( + name='sport', + def_num=5, + value='walking', + raw_value=11, + ), + ), + ), + ), + ), + 11: Field( + name='total_calories', + type=BASE_TYPES[0x84], # uint16 + def_num=11, + units='kcal', + ), + 13: Field( + name='total_fat_calories', + type=BASE_TYPES[0x84], # uint16 + def_num=13, + units='kcal', + ), + 14: Field( # total_distance / total_timer_time + name='avg_speed', + type=BASE_TYPES[0x84], # uint16 + def_num=14, + scale=1000, + units='m/s', + components=( + ComponentField( + name='enhanced_avg_speed', + def_num=124, + scale=1000, + units='m/s', + accumulate=False, + bits=16, + bit_offset=0, + ), + ), + ), + 15: Field( + name='max_speed', + type=BASE_TYPES[0x84], # uint16 + def_num=15, + scale=1000, + units='m/s', + components=( + ComponentField( + name='enhanced_max_speed', + def_num=125, + scale=1000, + units='m/s', + accumulate=False, + bits=16, + bit_offset=0, + ), + ), + ), + 16: Field( # average heart rate (excludes pause time) + name='avg_heart_rate', + type=BASE_TYPES[0x02], # uint8 + def_num=16, + units='bpm', + ), + 17: Field( + name='max_heart_rate', + type=BASE_TYPES[0x02], # uint8 + def_num=17, + units='bpm', + ), + 18: Field( # total_cycles / total_timer_time if non_zero_avg_cadence otherwise total_cycles / total_elapsed_time + name='avg_cadence', + type=BASE_TYPES[0x02], # uint8 + def_num=18, + units='rpm', + subfields=( + SubField( + name='avg_running_cadence', + def_num=18, + type=BASE_TYPES[0x02], # uint8 + units='strides/min', + ref_fields=( + ReferenceField( + name='sport', + def_num=5, + value='running', + raw_value=1, + ), + ), + ), + ), + ), + 19: Field( + name='max_cadence', + type=BASE_TYPES[0x02], # uint8 + def_num=19, + units='rpm', + subfields=( + SubField( + name='max_running_cadence', + def_num=19, + type=BASE_TYPES[0x02], # uint8 + units='strides/min', + ref_fields=( + ReferenceField( + name='sport', + def_num=5, + value='running', + raw_value=1, + ), + ), + ), + ), + ), + 20: Field( # total_power / total_timer_time if non_zero_avg_power otherwise total_power / total_elapsed_time + name='avg_power', + type=BASE_TYPES[0x84], # uint16 + def_num=20, + units='watts', + ), + 21: Field( + name='max_power', + type=BASE_TYPES[0x84], # uint16 + def_num=21, + units='watts', + ), + 22: Field( + name='total_ascent', + type=BASE_TYPES[0x84], # uint16 + def_num=22, + units='m', + ), + 23: Field( + name='total_descent', + type=BASE_TYPES[0x84], # uint16 + def_num=23, + units='m', + ), + 24: Field( + name='total_training_effect', + type=BASE_TYPES[0x02], # uint8 + def_num=24, + scale=10, + ), + 25: Field( + name='first_lap_index', + type=BASE_TYPES[0x84], # uint16 + def_num=25, + ), + 26: Field( + name='num_laps', + type=BASE_TYPES[0x84], # uint16 + def_num=26, + ), + 27: Field( + name='event_group', + type=BASE_TYPES[0x02], # uint8 + def_num=27, + ), + 28: Field( + name='trigger', + type=FIELD_TYPES['session_trigger'], + def_num=28, + ), + 29: Field( + name='nec_lat', + type=BASE_TYPES[0x85], # sint32 + def_num=29, + units='semicircles', + ), + 30: Field( + name='nec_long', + type=BASE_TYPES[0x85], # sint32 + def_num=30, + units='semicircles', + ), + 31: Field( + name='swc_lat', + type=BASE_TYPES[0x85], # sint32 + def_num=31, + units='semicircles', + ), + 32: Field( + name='swc_long', + type=BASE_TYPES[0x85], # sint32 + def_num=32, + units='semicircles', + ), + 34: Field( + name='normalized_power', + type=BASE_TYPES[0x84], # uint16 + def_num=34, + units='watts', + ), + 35: Field( + name='training_stress_score', + type=BASE_TYPES[0x84], # uint16 + def_num=35, + scale=10, + units='tss', + ), + 36: Field( + name='intensity_factor', + type=BASE_TYPES[0x84], # uint16 + def_num=36, + scale=1000, + units='if', + ), + 37: Field( + name='left_right_balance', + type=FIELD_TYPES['left_right_balance_100'], + def_num=37, + ), + 41: Field( + name='avg_stroke_count', + type=BASE_TYPES[0x86], # uint32 + def_num=41, + scale=10, + units='strokes/lap', + ), + 42: Field( + name='avg_stroke_distance', + type=BASE_TYPES[0x84], # uint16 + def_num=42, + scale=100, + units='m', + ), + 43: Field( + name='swim_stroke', + type=FIELD_TYPES['swim_stroke'], + def_num=43, + units='swim_stroke', + ), + 44: Field( + name='pool_length', + type=BASE_TYPES[0x84], # uint16 + def_num=44, + scale=100, + units='m', + ), + 45: Field( + name='threshold_power', + type=BASE_TYPES[0x84], # uint16 + def_num=45, + units='watts', + ), + 46: Field( + name='pool_length_unit', + type=FIELD_TYPES['display_measure'], + def_num=46, + ), + 47: Field( # # of active lengths of swim pool + name='num_active_lengths', + type=BASE_TYPES[0x84], # uint16 + def_num=47, + units='lengths', + ), + 48: Field( + name='total_work', + type=BASE_TYPES[0x86], # uint32 + def_num=48, + units='J', + ), + 49: Field( + name='avg_altitude', + type=BASE_TYPES[0x84], # uint16 + def_num=49, + scale=5, + offset=500, + units='m', + components=( + ComponentField( + name='enhanced_avg_altitude', + def_num=126, + scale=5, + offset=500, + units='m', + accumulate=False, + bits=16, + bit_offset=0, + ), + ), + ), + 50: Field( + name='max_altitude', + type=BASE_TYPES[0x84], # uint16 + def_num=50, + scale=5, + offset=500, + units='m', + components=( + ComponentField( + name='enhanced_max_altitude', + def_num=128, + scale=5, + offset=500, + units='m', + accumulate=False, + bits=16, + bit_offset=0, + ), + ), + ), + 51: Field( + name='gps_accuracy', + type=BASE_TYPES[0x02], # uint8 + def_num=51, + units='m', + ), + 52: Field( + name='avg_grade', + type=BASE_TYPES[0x83], # sint16 + def_num=52, + scale=100, + units='%', + ), + 53: Field( + name='avg_pos_grade', + type=BASE_TYPES[0x83], # sint16 + def_num=53, + scale=100, + units='%', + ), + 54: Field( + name='avg_neg_grade', + type=BASE_TYPES[0x83], # sint16 + def_num=54, + scale=100, + units='%', + ), + 55: Field( + name='max_pos_grade', + type=BASE_TYPES[0x83], # sint16 + def_num=55, + scale=100, + units='%', + ), + 56: Field( + name='max_neg_grade', + type=BASE_TYPES[0x83], # sint16 + def_num=56, + scale=100, + units='%', + ), + 57: Field( + name='avg_temperature', + type=BASE_TYPES[0x01], # sint8 + def_num=57, + units='C', + ), + 58: Field( + name='max_temperature', + type=BASE_TYPES[0x01], # sint8 + def_num=58, + units='C', + ), + 59: Field( + name='total_moving_time', + type=BASE_TYPES[0x86], # uint32 + def_num=59, + scale=1000, + units='s', + ), + 60: Field( + name='avg_pos_vertical_speed', + type=BASE_TYPES[0x83], # sint16 + def_num=60, + scale=1000, + units='m/s', + ), + 61: Field( + name='avg_neg_vertical_speed', + type=BASE_TYPES[0x83], # sint16 + def_num=61, + scale=1000, + units='m/s', + ), + 62: Field( + name='max_pos_vertical_speed', + type=BASE_TYPES[0x83], # sint16 + def_num=62, + scale=1000, + units='m/s', + ), + 63: Field( + name='max_neg_vertical_speed', + type=BASE_TYPES[0x83], # sint16 + def_num=63, + scale=1000, + units='m/s', + ), + 64: Field( + name='min_heart_rate', + type=BASE_TYPES[0x02], # uint8 + def_num=64, + units='bpm', + ), + 65: Field( + name='time_in_hr_zone', + type=BASE_TYPES[0x86], # uint32 + def_num=65, + scale=1000, + units='s', + ), + 66: Field( + name='time_in_speed_zone', + type=BASE_TYPES[0x86], # uint32 + def_num=66, + scale=1000, + units='s', + ), + 67: Field( + name='time_in_cadence_zone', + type=BASE_TYPES[0x86], # uint32 + def_num=67, + scale=1000, + units='s', + ), + 68: Field( + name='time_in_power_zone', + type=BASE_TYPES[0x86], # uint32 + def_num=68, + scale=1000, + units='s', + ), + 69: Field( + name='avg_lap_time', + type=BASE_TYPES[0x86], # uint32 + def_num=69, + scale=1000, + units='s', + ), + 70: Field( + name='best_lap_index', + type=BASE_TYPES[0x84], # uint16 + def_num=70, + ), + 71: Field( + name='min_altitude', + type=BASE_TYPES[0x84], # uint16 + def_num=71, + scale=5, + offset=500, + units='m', + components=( + ComponentField( + name='enhanced_min_altitude', + def_num=127, + scale=5, + offset=500, + units='m', + accumulate=False, + bits=16, + bit_offset=0, + ), + ), + ), + 82: Field( + name='player_score', + type=BASE_TYPES[0x84], # uint16 + def_num=82, + ), + 83: Field( + name='opponent_score', + type=BASE_TYPES[0x84], # uint16 + def_num=83, + ), + 84: Field( + name='opponent_name', + type=BASE_TYPES[0x07], # string + def_num=84, + ), + 85: Field( # stroke_type enum used as the index + name='stroke_count', + type=BASE_TYPES[0x84], # uint16 + def_num=85, + units='counts', + ), + 86: Field( # zone number used as the index + name='zone_count', + type=BASE_TYPES[0x84], # uint16 + def_num=86, + units='counts', + ), + 87: Field( + name='max_ball_speed', + type=BASE_TYPES[0x84], # uint16 + def_num=87, + scale=100, + units='m/s', + ), + 88: Field( + name='avg_ball_speed', + type=BASE_TYPES[0x84], # uint16 + def_num=88, + scale=100, + units='m/s', + ), + 89: Field( + name='avg_vertical_oscillation', + type=BASE_TYPES[0x84], # uint16 + def_num=89, + scale=10, + units='mm', + ), + 90: Field( + name='avg_stance_time_percent', + type=BASE_TYPES[0x84], # uint16 + def_num=90, + scale=100, + units='percent', + ), + 91: Field( + name='avg_stance_time', + type=BASE_TYPES[0x84], # uint16 + def_num=91, + scale=10, + units='ms', + ), + 92: Field( # fractional part of the avg_cadence + name='avg_fractional_cadence', + type=BASE_TYPES[0x02], # uint8 + def_num=92, + scale=128, + units='rpm', + ), + 93: Field( # fractional part of the max_cadence + name='max_fractional_cadence', + type=BASE_TYPES[0x02], # uint8 + def_num=93, + scale=128, + units='rpm', + ), + 94: Field( # fractional part of the total_cycles + name='total_fractional_cycles', + type=BASE_TYPES[0x02], # uint8 + def_num=94, + scale=128, + units='cycles', + ), + 95: Field( # Avg saturated and unsaturated hemoglobin + name='avg_total_hemoglobin_conc', + type=BASE_TYPES[0x84], # uint16 + def_num=95, + scale=100, + units='g/dL', + ), + 96: Field( # Min saturated and unsaturated hemoglobin + name='min_total_hemoglobin_conc', + type=BASE_TYPES[0x84], # uint16 + def_num=96, + scale=100, + units='g/dL', + ), + 97: Field( # Max saturated and unsaturated hemoglobin + name='max_total_hemoglobin_conc', + type=BASE_TYPES[0x84], # uint16 + def_num=97, + scale=100, + units='g/dL', + ), + 98: Field( # Avg percentage of hemoglobin saturated with oxygen + name='avg_saturated_hemoglobin_percent', + type=BASE_TYPES[0x84], # uint16 + def_num=98, + scale=10, + units='%', + ), + 99: Field( # Min percentage of hemoglobin saturated with oxygen + name='min_saturated_hemoglobin_percent', + type=BASE_TYPES[0x84], # uint16 + def_num=99, + scale=10, + units='%', + ), + 100: Field( # Max percentage of hemoglobin saturated with oxygen + name='max_saturated_hemoglobin_percent', + type=BASE_TYPES[0x84], # uint16 + def_num=100, + scale=10, + units='%', + ), + 101: Field( + name='avg_left_torque_effectiveness', + type=BASE_TYPES[0x02], # uint8 + def_num=101, + scale=2, + units='percent', + ), + 102: Field( + name='avg_right_torque_effectiveness', + type=BASE_TYPES[0x02], # uint8 + def_num=102, + scale=2, + units='percent', + ), + 103: Field( + name='avg_left_pedal_smoothness', + type=BASE_TYPES[0x02], # uint8 + def_num=103, + scale=2, + units='percent', + ), + 104: Field( + name='avg_right_pedal_smoothness', + type=BASE_TYPES[0x02], # uint8 + def_num=104, + scale=2, + units='percent', + ), + 105: Field( + name='avg_combined_pedal_smoothness', + type=BASE_TYPES[0x02], # uint8 + def_num=105, + scale=2, + units='percent', + ), + 111: Field( + name='sport_index', + type=BASE_TYPES[0x02], # uint8 + def_num=111, + ), + 112: Field( # Total time spend in the standing position + name='time_standing', + type=BASE_TYPES[0x86], # uint32 + def_num=112, + scale=1000, + units='s', + ), + 113: Field( # Number of transitions to the standing state + name='stand_count', + type=BASE_TYPES[0x84], # uint16 + def_num=113, + ), + 114: Field( # Average platform center offset Left + name='avg_left_pco', + type=BASE_TYPES[0x01], # sint8 + def_num=114, + units='mm', + ), + 115: Field( # Average platform center offset Right + name='avg_right_pco', + type=BASE_TYPES[0x01], # sint8 + def_num=115, + units='mm', + ), + 116: Field( # Average left power phase angles. Indexes defined by power_phase_type. + name='avg_left_power_phase', + type=BASE_TYPES[0x02], # uint8 + def_num=116, + scale=0.7111111, + units='degrees', + ), + 117: 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=117, + scale=0.7111111, + units='degrees', + ), + 118: 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=118, + scale=0.7111111, + units='degrees', + ), + 119: 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=119, + scale=0.7111111, + units='degrees', + ), + 120: Field( # Average power by position. Data value indexes defined by rider_position_type. + name='avg_power_position', + type=BASE_TYPES[0x84], # uint16 + def_num=120, + units='watts', + ), + 121: Field( # Maximum power by position. Data value indexes defined by rider_position_type. + name='max_power_position', + type=BASE_TYPES[0x84], # uint16 + def_num=121, + units='watts', + ), + 122: Field( # Average cadence by position. Data value indexes defined by rider_position_type. + name='avg_cadence_position', + type=BASE_TYPES[0x02], # uint8 + def_num=122, + units='rpm', + ), + 123: Field( # Maximum cadence by position. Data value indexes defined by rider_position_type. + name='max_cadence_position', + type=BASE_TYPES[0x02], # uint8 + def_num=123, + units='rpm', + ), + 124: Field( # total_distance / total_timer_time + name='enhanced_avg_speed', + type=BASE_TYPES[0x86], # uint32 + def_num=124, + scale=1000, + units='m/s', + ), + 125: Field( + name='enhanced_max_speed', + type=BASE_TYPES[0x86], # uint32 + def_num=125, + scale=1000, + units='m/s', + ), + 126: Field( + name='enhanced_avg_altitude', + type=BASE_TYPES[0x86], # uint32 + def_num=126, + scale=5, + offset=500, + units='m', + ), + 127: Field( + name='enhanced_min_altitude', + type=BASE_TYPES[0x86], # uint32 + def_num=127, + scale=5, + offset=500, + units='m', + ), + 128: Field( + name='enhanced_max_altitude', + type=BASE_TYPES[0x86], # uint32 + def_num=128, + scale=5, + offset=500, + units='m', + ), + 129: Field( # lev average motor power during session + name='avg_lev_motor_power', + type=BASE_TYPES[0x84], # uint16 + def_num=129, + units='watts', + ), + 130: Field( # lev maximum motor power during session + name='max_lev_motor_power', + type=BASE_TYPES[0x84], # uint16 + def_num=130, + units='watts', + ), + 131: Field( # lev battery consumption during session + name='lev_battery_consumption', + type=BASE_TYPES[0x02], # uint8 + def_num=131, + scale=2, + units='percent', + ), + 132: Field( + name='avg_vertical_ratio', + type=BASE_TYPES[0x84], # uint16 + def_num=132, + scale=100, + units='percent', + ), + 133: Field( + name='avg_stance_time_balance', + type=BASE_TYPES[0x84], # uint16 + def_num=133, + scale=100, + units='percent', + ), + 134: Field( + name='avg_step_length', + type=BASE_TYPES[0x84], # uint16 + def_num=134, + scale=10, + units='mm', + ), + 137: Field( + name='total_anaerobic_training_effect', + type=BASE_TYPES[0x02], # uint8 + def_num=137, + scale=10, + ), + 139: Field( + name='avg_vam', + type=BASE_TYPES[0x84], # uint16 + def_num=139, + scale=1000, + units='m/s', + ), + 253: FIELD_TYPE_TIMESTAMP, # Sesson end time. + 254: Field( # Selected bit is set for the current session. + name='message_index', + type=FIELD_TYPES['message_index'], + def_num=254, + ), + }, + ), + 19: MessageType( + name='lap', + mesg_num=19, + 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='start_time', + type=FIELD_TYPES['date_time'], + def_num=2, + ), + 3: Field( + name='start_position_lat', + type=BASE_TYPES[0x85], # sint32 + def_num=3, + units='semicircles', + ), + 4: Field( + name='start_position_long', + type=BASE_TYPES[0x85], # sint32 + def_num=4, + units='semicircles', + ), + 5: Field( + name='end_position_lat', + type=BASE_TYPES[0x85], # sint32 + def_num=5, + units='semicircles', + ), + 6: Field( + name='end_position_long', + type=BASE_TYPES[0x85], # sint32 + def_num=6, + units='semicircles', + ), + 7: Field( # Time (includes pauses) + name='total_elapsed_time', + type=BASE_TYPES[0x86], # uint32 + def_num=7, + scale=1000, + units='s', + ), + 8: Field( # Timer Time (excludes pauses) + name='total_timer_time', + type=BASE_TYPES[0x86], # uint32 + def_num=8, + scale=1000, + units='s', + ), + 9: Field( + name='total_distance', + type=BASE_TYPES[0x86], # uint32 + def_num=9, + scale=100, + units='m', + ), + 10: Field( + name='total_cycles', + type=BASE_TYPES[0x86], # uint32 + def_num=10, + units='cycles', + subfields=( + SubField( + name='total_strides', + def_num=10, + type=BASE_TYPES[0x86], # uint32 + units='strides', + ref_fields=( + ReferenceField( + name='sport', + def_num=25, + value='running', + raw_value=1, + ), + ReferenceField( + name='sport', + def_num=25, + value='walking', + raw_value=11, + ), + ), + ), + ), + ), + 11: Field( + name='total_calories', + type=BASE_TYPES[0x84], # uint16 + def_num=11, + units='kcal', + ), + 12: Field( # If New Leaf + name='total_fat_calories', + type=BASE_TYPES[0x84], # uint16 + def_num=12, + units='kcal', + ), + 13: Field( + name='avg_speed', + type=BASE_TYPES[0x84], # uint16 + def_num=13, + scale=1000, + units='m/s', + components=( + ComponentField( + name='enhanced_avg_speed', + def_num=110, + scale=1000, + units='m/s', + accumulate=False, + bits=16, + bit_offset=0, + ), + ), + ), + 14: Field( + name='max_speed', + type=BASE_TYPES[0x84], # uint16 + def_num=14, + scale=1000, + units='m/s', + components=( + ComponentField( + name='enhanced_max_speed', + def_num=111, + scale=1000, + units='m/s', + accumulate=False, + bits=16, + bit_offset=0, + ), + ), + ), + 15: Field( + name='avg_heart_rate', + type=BASE_TYPES[0x02], # uint8 + def_num=15, + units='bpm', + ), + 16: Field( + name='max_heart_rate', + type=BASE_TYPES[0x02], # uint8 + def_num=16, + units='bpm', + ), + 17: Field( # total_cycles / total_timer_time if non_zero_avg_cadence otherwise total_cycles / total_elapsed_time + name='avg_cadence', + type=BASE_TYPES[0x02], # uint8 + def_num=17, + units='rpm', + subfields=( + SubField( + name='avg_running_cadence', + def_num=17, + type=BASE_TYPES[0x02], # uint8 + units='strides/min', + ref_fields=( + ReferenceField( + name='sport', + def_num=25, + value='running', + raw_value=1, + ), + ), + ), + ), + ), + 18: Field( + name='max_cadence', + type=BASE_TYPES[0x02], # uint8 + def_num=18, + units='rpm', + subfields=( + SubField( + name='max_running_cadence', + def_num=18, + type=BASE_TYPES[0x02], # uint8 + units='strides/min', + ref_fields=( + ReferenceField( + name='sport', + def_num=25, + value='running', + raw_value=1, + ), + ), + ), + ), + ), + 19: Field( # total_power / total_timer_time if non_zero_avg_power otherwise total_power / total_elapsed_time + name='avg_power', + type=BASE_TYPES[0x84], # uint16 + def_num=19, + units='watts', + ), + 20: Field( + name='max_power', + type=BASE_TYPES[0x84], # uint16 + def_num=20, + units='watts', + ), + 21: Field( + name='total_ascent', + type=BASE_TYPES[0x84], # uint16 + def_num=21, + units='m', + ), + 22: Field( + name='total_descent', + type=BASE_TYPES[0x84], # uint16 + def_num=22, + units='m', + ), + 23: Field( + name='intensity', + type=FIELD_TYPES['intensity'], + def_num=23, + ), + 24: Field( + name='lap_trigger', + type=FIELD_TYPES['lap_trigger'], + def_num=24, + ), + 25: Field( + name='sport', + type=FIELD_TYPES['sport'], + def_num=25, + ), + 26: Field( + name='event_group', + type=BASE_TYPES[0x02], # uint8 + def_num=26, + ), + 32: Field( # # of lengths of swim pool + name='num_lengths', + type=BASE_TYPES[0x84], # uint16 + def_num=32, + units='lengths', + ), + 33: Field( + name='normalized_power', + type=BASE_TYPES[0x84], # uint16 + def_num=33, + units='watts', + ), + 34: Field( + name='left_right_balance', + type=FIELD_TYPES['left_right_balance_100'], + def_num=34, + ), + 35: Field( + name='first_length_index', + type=BASE_TYPES[0x84], # uint16 + def_num=35, + ), + 37: Field( + name='avg_stroke_distance', + type=BASE_TYPES[0x84], # uint16 + def_num=37, + scale=100, + units='m', + ), + 38: Field( + name='swim_stroke', + type=FIELD_TYPES['swim_stroke'], + def_num=38, + ), + 39: Field( + name='sub_sport', + type=FIELD_TYPES['sub_sport'], + def_num=39, + ), + 40: Field( # # of active lengths of swim pool + name='num_active_lengths', + type=BASE_TYPES[0x84], # uint16 + def_num=40, + units='lengths', + ), + 41: Field( + name='total_work', + type=BASE_TYPES[0x86], # uint32 + def_num=41, + units='J', + ), + 42: Field( + name='avg_altitude', + type=BASE_TYPES[0x84], # uint16 + def_num=42, + scale=5, + offset=500, + units='m', + components=( + ComponentField( + name='enhanced_avg_altitude', + def_num=112, + scale=5, + offset=500, + units='m', + accumulate=False, + bits=16, + bit_offset=0, + ), + ), + ), + 43: Field( + name='max_altitude', + type=BASE_TYPES[0x84], # uint16 + def_num=43, + scale=5, + offset=500, + units='m', + components=( + ComponentField( + name='enhanced_max_altitude', + def_num=114, + scale=5, + offset=500, + units='m', + accumulate=False, + bits=16, + bit_offset=0, + ), + ), + ), + 44: Field( + name='gps_accuracy', + type=BASE_TYPES[0x02], # uint8 + def_num=44, + units='m', + ), + 45: Field( + name='avg_grade', + type=BASE_TYPES[0x83], # sint16 + def_num=45, + scale=100, + units='%', + ), + 46: Field( + name='avg_pos_grade', + type=BASE_TYPES[0x83], # sint16 + def_num=46, + scale=100, + units='%', + ), + 47: Field( + name='avg_neg_grade', + type=BASE_TYPES[0x83], # sint16 + def_num=47, + scale=100, + units='%', + ), + 48: Field( + name='max_pos_grade', + type=BASE_TYPES[0x83], # sint16 + def_num=48, + scale=100, + units='%', + ), + 49: Field( + name='max_neg_grade', + type=BASE_TYPES[0x83], # sint16 + def_num=49, + scale=100, + units='%', + ), + 50: Field( + name='avg_temperature', + type=BASE_TYPES[0x01], # sint8 + def_num=50, + units='C', + ), + 51: Field( + name='max_temperature', + type=BASE_TYPES[0x01], # sint8 + def_num=51, + units='C', + ), + 52: Field( + name='total_moving_time', + type=BASE_TYPES[0x86], # uint32 + def_num=52, + scale=1000, + units='s', + ), + 53: Field( + name='avg_pos_vertical_speed', + type=BASE_TYPES[0x83], # sint16 + def_num=53, + scale=1000, + units='m/s', + ), + 54: Field( + name='avg_neg_vertical_speed', + type=BASE_TYPES[0x83], # sint16 + def_num=54, + scale=1000, + units='m/s', + ), + 55: Field( + name='max_pos_vertical_speed', + type=BASE_TYPES[0x83], # sint16 + def_num=55, + scale=1000, + units='m/s', + ), + 56: Field( + name='max_neg_vertical_speed', + type=BASE_TYPES[0x83], # sint16 + def_num=56, + scale=1000, + units='m/s', + ), + 57: Field( + name='time_in_hr_zone', + type=BASE_TYPES[0x86], # uint32 + def_num=57, + scale=1000, + units='s', + ), + 58: Field( + name='time_in_speed_zone', + type=BASE_TYPES[0x86], # uint32 + def_num=58, + scale=1000, + units='s', + ), + 59: Field( + name='time_in_cadence_zone', + type=BASE_TYPES[0x86], # uint32 + def_num=59, + scale=1000, + units='s', + ), + 60: Field( + name='time_in_power_zone', + type=BASE_TYPES[0x86], # uint32 + def_num=60, + scale=1000, + units='s', + ), + 61: Field( + name='repetition_num', + type=BASE_TYPES[0x84], # uint16 + def_num=61, + ), + 62: Field( + name='min_altitude', + type=BASE_TYPES[0x84], # uint16 + def_num=62, + scale=5, + offset=500, + units='m', + components=( + ComponentField( + name='enhanced_min_altitude', + def_num=113, + scale=5, + offset=500, + units='m', + accumulate=False, + bits=16, + bit_offset=0, + ), + ), + ), + 63: Field( + name='min_heart_rate', + type=BASE_TYPES[0x02], # uint8 + def_num=63, + units='bpm', + ), + 71: Field( + name='wkt_step_index', + type=FIELD_TYPES['message_index'], + def_num=71, + ), + 74: Field( + name='opponent_score', + type=BASE_TYPES[0x84], # uint16 + def_num=74, + ), + 75: Field( # stroke_type enum used as the index + name='stroke_count', + type=BASE_TYPES[0x84], # uint16 + def_num=75, + units='counts', + ), + 76: Field( # zone number used as the index + name='zone_count', + type=BASE_TYPES[0x84], # uint16 + def_num=76, + units='counts', + ), + 77: Field( + name='avg_vertical_oscillation', + type=BASE_TYPES[0x84], # uint16 + def_num=77, + scale=10, + units='mm', + ), + 78: Field( + name='avg_stance_time_percent', + type=BASE_TYPES[0x84], # uint16 + def_num=78, + scale=100, + units='percent', + ), + 79: Field( + name='avg_stance_time', + type=BASE_TYPES[0x84], # uint16 + def_num=79, + scale=10, + units='ms', + ), + 80: Field( # fractional part of the avg_cadence + name='avg_fractional_cadence', + type=BASE_TYPES[0x02], # uint8 + def_num=80, + scale=128, + units='rpm', + ), + 81: Field( # fractional part of the max_cadence + name='max_fractional_cadence', + type=BASE_TYPES[0x02], # uint8 + def_num=81, + scale=128, + units='rpm', + ), + 82: Field( # fractional part of the total_cycles + name='total_fractional_cycles', + type=BASE_TYPES[0x02], # uint8 + def_num=82, + scale=128, + units='cycles', + ), + 83: Field( + name='player_score', + type=BASE_TYPES[0x84], # uint16 + def_num=83, + ), + 84: Field( # Avg saturated and unsaturated hemoglobin + name='avg_total_hemoglobin_conc', + type=BASE_TYPES[0x84], # uint16 + def_num=84, + scale=100, + units='g/dL', + ), + 85: Field( # Min saturated and unsaturated hemoglobin + name='min_total_hemoglobin_conc', + type=BASE_TYPES[0x84], # uint16 + def_num=85, + scale=100, + units='g/dL', + ), + 86: Field( # Max saturated and unsaturated hemoglobin + name='max_total_hemoglobin_conc', + type=BASE_TYPES[0x84], # uint16 + def_num=86, + scale=100, + units='g/dL', + ), + 87: Field( # Avg percentage of hemoglobin saturated with oxygen + name='avg_saturated_hemoglobin_percent', + type=BASE_TYPES[0x84], # uint16 + def_num=87, + scale=10, + units='%', + ), + 88: Field( # Min percentage of hemoglobin saturated with oxygen + name='min_saturated_hemoglobin_percent', + type=BASE_TYPES[0x84], # uint16 + def_num=88, + scale=10, + units='%', + ), + 89: Field( # Max percentage of hemoglobin saturated with oxygen + name='max_saturated_hemoglobin_percent', + type=BASE_TYPES[0x84], # uint16 + def_num=89, + scale=10, + units='%', + ), + 91: Field( + name='avg_left_torque_effectiveness', + type=BASE_TYPES[0x02], # uint8 + def_num=91, + scale=2, + units='percent', + ), + 92: Field( + name='avg_right_torque_effectiveness', + type=BASE_TYPES[0x02], # uint8 + def_num=92, + scale=2, + units='percent', + ), + 93: Field( + name='avg_left_pedal_smoothness', + type=BASE_TYPES[0x02], # uint8 + def_num=93, + scale=2, + units='percent', + ), + 94: Field( + name='avg_right_pedal_smoothness', + type=BASE_TYPES[0x02], # uint8 + def_num=94, + scale=2, + units='percent', + ), + 95: Field( + name='avg_combined_pedal_smoothness', + type=BASE_TYPES[0x02], # uint8 + def_num=95, + scale=2, + units='percent', + ), + 98: Field( # Total time spent in the standing position + name='time_standing', + type=BASE_TYPES[0x86], # uint32 + def_num=98, + scale=1000, + units='s', + ), + 99: Field( # Number of transitions to the standing state + name='stand_count', + type=BASE_TYPES[0x84], # uint16 + def_num=99, + ), + 100: Field( # Average left platform center offset + name='avg_left_pco', + type=BASE_TYPES[0x01], # sint8 + def_num=100, + units='mm', + ), + 101: Field( # Average right platform center offset + name='avg_right_pco', + type=BASE_TYPES[0x01], # sint8 + def_num=101, + units='mm', + ), + 102: 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=102, + scale=0.7111111, + units='degrees', + ), + 103: 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=103, + scale=0.7111111, + units='degrees', + ), + 104: 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=104, + scale=0.7111111, + units='degrees', + ), + 105: 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=105, + scale=0.7111111, + units='degrees', + ), + 106: Field( # Average power by position. Data value indexes defined by rider_position_type. + name='avg_power_position', + type=BASE_TYPES[0x84], # uint16 + def_num=106, + units='watts', + ), + 107: Field( # Maximum power by position. Data value indexes defined by rider_position_type. + name='max_power_position', + type=BASE_TYPES[0x84], # uint16 + def_num=107, + units='watts', + ), + 108: Field( # Average cadence by position. Data value indexes defined by rider_position_type. + name='avg_cadence_position', + type=BASE_TYPES[0x02], # uint8 + def_num=108, + units='rpm', + ), + 109: Field( # Maximum cadence by position. Data value indexes defined by rider_position_type. + name='max_cadence_position', + type=BASE_TYPES[0x02], # uint8 + def_num=109, + units='rpm', + ), + 110: Field( + name='enhanced_avg_speed', + type=BASE_TYPES[0x86], # uint32 + def_num=110, + scale=1000, + units='m/s', + ), + 111: Field( + name='enhanced_max_speed', + type=BASE_TYPES[0x86], # uint32 + def_num=111, + scale=1000, + units='m/s', + ), + 112: Field( + name='enhanced_avg_altitude', + type=BASE_TYPES[0x86], # uint32 + def_num=112, + scale=5, + offset=500, + units='m', + ), + 113: Field( + name='enhanced_min_altitude', + type=BASE_TYPES[0x86], # uint32 + def_num=113, + scale=5, + offset=500, + units='m', + ), + 114: Field( + name='enhanced_max_altitude', + type=BASE_TYPES[0x86], # uint32 + def_num=114, + scale=5, + offset=500, + units='m', + ), + 115: Field( # lev average motor power during lap + name='avg_lev_motor_power', + type=BASE_TYPES[0x84], # uint16 + def_num=115, + units='watts', + ), + 116: Field( # lev maximum motor power during lap + name='max_lev_motor_power', + type=BASE_TYPES[0x84], # uint16 + def_num=116, + units='watts', + ), + 117: Field( # lev battery consumption during lap + name='lev_battery_consumption', + type=BASE_TYPES[0x02], # uint8 + def_num=117, + scale=2, + units='percent', + ), + 118: Field( + name='avg_vertical_ratio', + type=BASE_TYPES[0x84], # uint16 + def_num=118, + scale=100, + units='percent', + ), + 119: Field( + name='avg_stance_time_balance', + type=BASE_TYPES[0x84], # uint16 + def_num=119, + scale=100, + units='percent', + ), + 120: Field( + name='avg_step_length', + type=BASE_TYPES[0x84], # uint16 + def_num=120, + scale=10, + units='mm', + ), + 121: Field( + name='avg_vam', + type=BASE_TYPES[0x84], # uint16 + def_num=121, + scale=1000, + units='m/s', + ), + 253: FIELD_TYPE_TIMESTAMP, # Lap end time. + 254: Field( + name='message_index', + type=FIELD_TYPES['message_index'], + def_num=254, + ), + }, + ), + 20: MessageType( + name='record', + mesg_num=20, + fields={ + 0: Field( + name='position_lat', + type=BASE_TYPES[0x85], # sint32 + def_num=0, + units='semicircles', + ), + 1: Field( + name='position_long', + type=BASE_TYPES[0x85], # sint32 + def_num=1, + units='semicircles', + ), + 2: Field( + name='altitude', + type=BASE_TYPES[0x84], # uint16 + def_num=2, + scale=5, + offset=500, + units='m', + components=( + ComponentField( + name='enhanced_altitude', + def_num=78, + scale=5, + offset=500, + units='m', + accumulate=False, + bits=16, + bit_offset=0, + ), + ), + ), + 3: Field( + name='heart_rate', + type=BASE_TYPES[0x02], # uint8 + def_num=3, + units='bpm', + ), + 4: Field( + name='cadence', + type=BASE_TYPES[0x02], # uint8 + def_num=4, + units='rpm', + ), + 5: Field( + name='distance', + type=BASE_TYPES[0x86], # uint32 + def_num=5, + scale=100, + units='m', + ), + 6: Field( + name='speed', + type=BASE_TYPES[0x84], # uint16 + def_num=6, + scale=1000, + units='m/s', + components=( + ComponentField( + name='enhanced_speed', + def_num=73, + scale=1000, + units='m/s', + accumulate=False, + bits=16, + bit_offset=0, + ), + ), + ), + 7: Field( + name='power', + type=BASE_TYPES[0x84], # uint16 + def_num=7, + units='watts', + ), + 8: Field( + name='compressed_speed_distance', + type=BASE_TYPES[0x0D], # byte + def_num=8, + components=( + ComponentField( + name='speed', + def_num=6, + scale=100, + units='m/s', + accumulate=False, + bits=12, + bit_offset=0, + ), + ComponentField( + name='distance', + def_num=5, + scale=16, + units='m', + accumulate=True, + bits=12, + bit_offset=12, + ), + ), + ), + 9: Field( + name='grade', + type=BASE_TYPES[0x83], # sint16 + def_num=9, + scale=100, + units='%', + ), + 10: Field( # Relative. 0 is none 254 is Max. + name='resistance', + type=BASE_TYPES[0x02], # uint8 + def_num=10, + ), + 11: Field( + name='time_from_course', + type=BASE_TYPES[0x85], # sint32 + def_num=11, + scale=1000, + units='s', + ), + 12: Field( + name='cycle_length', + type=BASE_TYPES[0x02], # uint8 + def_num=12, + scale=100, + units='m', + ), + 13: Field( + name='temperature', + type=BASE_TYPES[0x01], # sint8 + def_num=13, + units='C', + ), + 17: Field( # Speed at 1s intervals. Timestamp field indicates time of last array element. + name='speed_1s', + type=BASE_TYPES[0x02], # uint8 + def_num=17, + scale=16, + units='m/s', + ), + 18: Field( + name='cycles', + type=BASE_TYPES[0x02], # uint8 + def_num=18, + components=( + ComponentField( + name='total_cycles', + def_num=19, + units='cycles', + accumulate=True, + bits=8, + bit_offset=0, + ), + ), + ), + 19: Field( + name='total_cycles', + type=BASE_TYPES[0x86], # uint32 + def_num=19, + units='cycles', + ), + 28: Field( + name='compressed_accumulated_power', + type=BASE_TYPES[0x84], # uint16 + def_num=28, + components=( + ComponentField( + name='accumulated_power', + def_num=29, + units='watts', + accumulate=True, + bits=16, + bit_offset=0, + ), + ), + ), + 29: Field( + name='accumulated_power', + type=BASE_TYPES[0x86], # uint32 + def_num=29, + units='watts', + ), + 30: Field( + name='left_right_balance', + type=FIELD_TYPES['left_right_balance'], + def_num=30, + ), + 31: Field( + name='gps_accuracy', + type=BASE_TYPES[0x02], # uint8 + def_num=31, + units='m', + ), + 32: Field( + name='vertical_speed', + type=BASE_TYPES[0x83], # sint16 + def_num=32, + scale=1000, + units='m/s', + ), + 33: Field( + name='calories', + type=BASE_TYPES[0x84], # uint16 + def_num=33, + units='kcal', + ), + 39: Field( + name='vertical_oscillation', + type=BASE_TYPES[0x84], # uint16 + def_num=39, + scale=10, + units='mm', + ), + 40: Field( + name='stance_time_percent', + type=BASE_TYPES[0x84], # uint16 + def_num=40, + scale=100, + units='percent', + ), + 41: Field( + name='stance_time', + type=BASE_TYPES[0x84], # uint16 + def_num=41, + scale=10, + units='ms', + ), + 42: Field( + name='activity_type', + type=FIELD_TYPES['activity_type'], + def_num=42, + ), + 43: Field( + name='left_torque_effectiveness', + type=BASE_TYPES[0x02], # uint8 + def_num=43, + scale=2, + units='percent', + ), + 44: Field( + name='right_torque_effectiveness', + type=BASE_TYPES[0x02], # uint8 + def_num=44, + scale=2, + units='percent', + ), + 45: Field( + name='left_pedal_smoothness', + type=BASE_TYPES[0x02], # uint8 + def_num=45, + scale=2, + units='percent', + ), + 46: Field( + name='right_pedal_smoothness', + type=BASE_TYPES[0x02], # uint8 + def_num=46, + scale=2, + units='percent', + ), + 47: Field( + name='combined_pedal_smoothness', + type=BASE_TYPES[0x02], # uint8 + def_num=47, + scale=2, + units='percent', + ), + 48: Field( + name='time128', + type=BASE_TYPES[0x02], # uint8 + def_num=48, + scale=128, + units='s', + ), + 49: Field( + name='stroke_type', + type=FIELD_TYPES['stroke_type'], + def_num=49, + ), + 50: Field( + name='zone', + type=BASE_TYPES[0x02], # uint8 + def_num=50, + ), + 51: Field( + name='ball_speed', + type=BASE_TYPES[0x84], # uint16 + def_num=51, + scale=100, + units='m/s', + ), + 52: Field( # Log cadence and fractional cadence for backwards compatability + name='cadence256', + type=BASE_TYPES[0x84], # uint16 + def_num=52, + scale=256, + units='rpm', + ), + 53: Field( + name='fractional_cadence', + type=BASE_TYPES[0x02], # uint8 + def_num=53, + scale=128, + units='rpm', + ), + 54: Field( # Total saturated and unsaturated hemoglobin + name='total_hemoglobin_conc', + type=BASE_TYPES[0x84], # uint16 + def_num=54, + scale=100, + units='g/dL', + ), + 55: Field( # Min saturated and unsaturated hemoglobin + name='total_hemoglobin_conc_min', + type=BASE_TYPES[0x84], # uint16 + def_num=55, + scale=100, + units='g/dL', + ), + 56: Field( # Max saturated and unsaturated hemoglobin + name='total_hemoglobin_conc_max', + type=BASE_TYPES[0x84], # uint16 + def_num=56, + scale=100, + units='g/dL', + ), + 57: Field( # Percentage of hemoglobin saturated with oxygen + name='saturated_hemoglobin_percent', + type=BASE_TYPES[0x84], # uint16 + def_num=57, + scale=10, + units='%', + ), + 58: Field( # Min percentage of hemoglobin saturated with oxygen + name='saturated_hemoglobin_percent_min', + type=BASE_TYPES[0x84], # uint16 + def_num=58, + scale=10, + units='%', + ), + 59: Field( # Max percentage of hemoglobin saturated with oxygen + name='saturated_hemoglobin_percent_max', + type=BASE_TYPES[0x84], # uint16 + def_num=59, + scale=10, + units='%', + ), + 62: Field( + name='device_index', + type=FIELD_TYPES['device_index'], + def_num=62, + ), + 67: Field( # Left platform center offset + name='left_pco', + type=BASE_TYPES[0x01], # sint8 + def_num=67, + units='mm', + ), + 68: Field( # Right platform center offset + name='right_pco', + type=BASE_TYPES[0x01], # sint8 + def_num=68, + units='mm', + ), + 69: Field( # Left power phase angles. Data value indexes defined by power_phase_type. + name='left_power_phase', + type=BASE_TYPES[0x02], # uint8 + def_num=69, + scale=0.7111111, + units='degrees', + ), + 70: Field( # Left power phase peak angles. Data value indexes defined by power_phase_type. + name='left_power_phase_peak', + type=BASE_TYPES[0x02], # uint8 + def_num=70, + scale=0.7111111, + units='degrees', + ), + 71: Field( # Right power phase angles. Data value indexes defined by power_phase_type. + name='right_power_phase', + type=BASE_TYPES[0x02], # uint8 + def_num=71, + scale=0.7111111, + units='degrees', + ), + 72: Field( # Right power phase peak angles. Data value indexes defined by power_phase_type. + name='right_power_phase_peak', + type=BASE_TYPES[0x02], # uint8 + def_num=72, + scale=0.7111111, + units='degrees', + ), + 73: Field( + name='enhanced_speed', + type=BASE_TYPES[0x86], # uint32 + def_num=73, + scale=1000, + units='m/s', + ), + 78: Field( + name='enhanced_altitude', + type=BASE_TYPES[0x86], # uint32 + def_num=78, + scale=5, + offset=500, + units='m', + ), + 81: Field( # lev battery state of charge + name='battery_soc', + type=BASE_TYPES[0x02], # uint8 + def_num=81, + scale=2, + units='percent', + ), + 82: Field( # lev motor power + name='motor_power', + type=BASE_TYPES[0x84], # uint16 + def_num=82, + units='watts', + ), + 83: Field( + name='vertical_ratio', + type=BASE_TYPES[0x84], # uint16 + def_num=83, + scale=100, + units='percent', + ), + 84: Field( + name='stance_time_balance', + type=BASE_TYPES[0x84], # uint16 + def_num=84, + scale=100, + units='percent', + ), + 85: Field( + name='step_length', + type=BASE_TYPES[0x84], # uint16 + def_num=85, + scale=10, + units='mm', + ), + 91: Field( # Includes atmospheric pressure + name='absolute_pressure', + type=BASE_TYPES[0x86], # uint32 + def_num=91, + units='Pa', + ), + 92: Field( # 0 if above water + name='depth', + type=BASE_TYPES[0x86], # uint32 + def_num=92, + scale=1000, + units='m', + ), + 93: Field( # 0 if above water + name='next_stop_depth', + type=BASE_TYPES[0x86], # uint32 + def_num=93, + scale=1000, + units='m', + ), + 94: Field( + name='next_stop_time', + type=BASE_TYPES[0x86], # uint32 + def_num=94, + units='s', + ), + 95: Field( + name='time_to_surface', + type=BASE_TYPES[0x86], # uint32 + def_num=95, + units='s', + ), + 96: Field( + name='ndl_time', + type=BASE_TYPES[0x86], # uint32 + def_num=96, + units='s', + ), + 97: Field( + name='cns_load', + type=BASE_TYPES[0x02], # uint8 + def_num=97, + units='percent', + ), + 98: Field( + name='n2_load', + type=BASE_TYPES[0x84], # uint16 + 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, + ), + 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, + bits=16, + bit_offset=0, + ), + ), + ), + 3: Field( + name='data', + type=BASE_TYPES[0x86], # uint32 + def_num=3, + subfields=( + SubField( + name='battery_level', + def_num=3, + type=BASE_TYPES[0x84], # uint16 + scale=1000, + units='V', + ref_fields=( + ReferenceField( + name='event', + def_num=0, + value='battery', + raw_value=11, + ), + ), + ), + SubField( + name='cad_high_alert', + def_num=3, + type=BASE_TYPES[0x84], # uint16 + units='rpm', + ref_fields=( + ReferenceField( + name='event', + def_num=0, + value='cad_high_alert', + raw_value=17, + ), + ), + ), + SubField( + name='cad_low_alert', + def_num=3, + type=BASE_TYPES[0x84], # uint16 + units='rpm', + ref_fields=( + ReferenceField( + name='event', + def_num=0, + value='cad_low_alert', + raw_value=18, + ), + ), + ), + SubField( + name='calorie_duration_alert', + def_num=3, + type=BASE_TYPES[0x86], # uint32 + units='calories', + ref_fields=( + ReferenceField( + name='event', + def_num=0, + value='calorie_duration_alert', + raw_value=25, + ), + ), + ), + SubField( + name='comm_timeout', + def_num=3, + type=FIELD_TYPES['comm_timeout_type'], + ref_fields=( + ReferenceField( + name='event', + def_num=0, + value='comm_timeout', + raw_value=47, + ), + ), + ), + SubField( + name='course_point_index', + def_num=3, + type=FIELD_TYPES['message_index'], + ref_fields=( + ReferenceField( + name='event', + def_num=0, + value='course_point', + raw_value=10, + ), + ), + ), + SubField( + name='distance_duration_alert', + def_num=3, + type=BASE_TYPES[0x86], # uint32 + scale=100, + units='m', + ref_fields=( + ReferenceField( + name='event', + def_num=0, + value='distance_duration_alert', + raw_value=24, + ), + ), + ), + SubField( + name='fitness_equipment_state', + def_num=3, + type=FIELD_TYPES['fitness_equipment_state'], + ref_fields=( + ReferenceField( + name='event', + def_num=0, + value='fitness_equipment', + raw_value=27, + ), + ), + ), + SubField( + name='gear_change_data', + def_num=3, + type=BASE_TYPES[0x86], # uint32 + ref_fields=( + ReferenceField( + name='event', + def_num=0, + value='front_gear_change', + raw_value=42, + ), + ReferenceField( + name='event', + def_num=0, + value='rear_gear_change', + raw_value=43, + ), + ), + components=( + ComponentField( + name='rear_gear_num', + def_num=11, + accumulate=False, + bits=8, + bit_offset=0, + ), + ComponentField( + name='rear_gear', + def_num=12, + accumulate=False, + bits=8, + bit_offset=8, + ), + ComponentField( + name='front_gear_num', + def_num=9, + accumulate=False, + bits=8, + bit_offset=16, + ), + ComponentField( + name='front_gear', + def_num=10, + accumulate=False, + bits=8, + bit_offset=24, + ), + ), + ), + SubField( + name='hr_high_alert', + def_num=3, + type=BASE_TYPES[0x02], # uint8 + units='bpm', + ref_fields=( + ReferenceField( + name='event', + def_num=0, + value='hr_high_alert', + raw_value=13, + ), + ), + ), + SubField( + name='hr_low_alert', + def_num=3, + type=BASE_TYPES[0x02], # uint8 + units='bpm', + ref_fields=( + ReferenceField( + name='event', + def_num=0, + value='hr_low_alert', + raw_value=14, + ), + ), + ), + SubField( + name='power_high_alert', + def_num=3, + type=BASE_TYPES[0x84], # uint16 + units='watts', + ref_fields=( + ReferenceField( + name='event', + def_num=0, + value='power_high_alert', + raw_value=19, + ), + ), + ), + SubField( + name='power_low_alert', + def_num=3, + type=BASE_TYPES[0x84], # uint16 + units='watts', + ref_fields=( + ReferenceField( + name='event', + def_num=0, + value='power_low_alert', + raw_value=20, + ), + ), + ), + SubField( # Indicates the rider position value. + name='rider_position', + def_num=3, + type=FIELD_TYPES['rider_position_type'], + ref_fields=( + ReferenceField( + name='event', + def_num=0, + value='rider_position_change', + raw_value=44, + ), + ), + ), + SubField( + name='speed_high_alert', + def_num=3, + type=BASE_TYPES[0x86], # uint32 + scale=1000, + units='m/s', + ref_fields=( + ReferenceField( + name='event', + def_num=0, + value='speed_high_alert', + raw_value=15, + ), + ), + ), + SubField( + name='speed_low_alert', + def_num=3, + type=BASE_TYPES[0x86], # uint32 + scale=1000, + units='m/s', + ref_fields=( + ReferenceField( + name='event', + def_num=0, + value='speed_low_alert', + raw_value=16, + ), + ), + ), + SubField( + name='sport_point', + def_num=3, + type=BASE_TYPES[0x86], # uint32 + ref_fields=( + ReferenceField( + name='event', + def_num=0, + value='sport_point', + raw_value=33, + ), + ), + components=( + ComponentField( + name='score', + def_num=7, + accumulate=False, + bits=16, + bit_offset=0, + ), + ComponentField( + name='opponent_score', + def_num=8, + accumulate=False, + bits=16, + bit_offset=16, + ), + ), + ), + SubField( + name='time_duration_alert', + def_num=3, + type=BASE_TYPES[0x86], # uint32 + scale=1000, + units='s', + ref_fields=( + ReferenceField( + name='event', + def_num=0, + value='time_duration_alert', + raw_value=23, + ), + ), + ), + SubField( + name='timer_trigger', + def_num=3, + type=FIELD_TYPES['timer_trigger'], + ref_fields=( + ReferenceField( + name='event', + def_num=0, + value='timer', + raw_value=0, + ), + ), + ), + SubField( + name='virtual_partner_speed', + def_num=3, + type=BASE_TYPES[0x84], # uint16 + scale=1000, + units='m/s', + ref_fields=( + ReferenceField( + name='event', + def_num=0, + value='virtual_partner_pace', + raw_value=12, + ), + ), + ), + ), + ), + 4: Field( + name='event_group', + type=BASE_TYPES[0x02], # uint8 + def_num=4, + ), + 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 + 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. + 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. + 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. + 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. + name='rear_gear', + type=BASE_TYPES[0x0A], # uint8z + def_num=12, + ), + 13: Field( + name='device_index', + type=FIELD_TYPES['device_index'], + def_num=13, + ), + 253: FIELD_TYPE_TIMESTAMP, + }, + ), + 23: MessageType( + name='device_info', + mesg_num=23, + fields={ + 0: Field( + name='device_index', + type=FIELD_TYPES['device_index'], + def_num=0, + ), + 1: Field( + name='device_type', + type=BASE_TYPES[0x02], # uint8 + def_num=1, + subfields=( + SubField( + name='ant_device_type', + def_num=1, + type=BASE_TYPES[0x02], # uint8 + ref_fields=( + ReferenceField( + name='source_type', + def_num=25, + value='ant', + raw_value=0, + ), + ), + ), + SubField( + name='antplus_device_type', + def_num=1, + type=FIELD_TYPES['antplus_device_type'], + ref_fields=( + ReferenceField( + name='source_type', + def_num=25, + value='antplus', + raw_value=1, + ), + ), + ), + ), + ), + 2: Field( + name='manufacturer', + type=FIELD_TYPES['manufacturer'], + def_num=2, + ), + 3: Field( + name='serial_number', + type=BASE_TYPES[0x8C], # uint32z + def_num=3, + ), + 4: Field( + name='product', + type=BASE_TYPES[0x84], # uint16 + def_num=4, + subfields=( + SubField( + name='garmin_product', + def_num=4, + type=FIELD_TYPES['garmin_product'], + ref_fields=( + ReferenceField( + name='manufacturer', + def_num=2, + value='garmin', + raw_value=1, + ), + ReferenceField( + name='manufacturer', + def_num=2, + value='dynastream', + raw_value=15, + ), + ReferenceField( + name='manufacturer', + def_num=2, + value='dynastream_oem', + raw_value=13, + ), + ), + ), + ), + ), + 5: Field( + name='software_version', + type=BASE_TYPES[0x84], # uint16 + def_num=5, + scale=100, + ), + 6: Field( + name='hardware_version', + type=BASE_TYPES[0x02], # uint8 + def_num=6, + ), + 7: Field( # Reset by new battery or charge. + name='cum_operating_time', + type=BASE_TYPES[0x86], # uint32 + def_num=7, + units='s', + ), + 10: Field( + name='battery_voltage', + type=BASE_TYPES[0x84], # uint16 + def_num=10, + scale=256, + units='V', + ), + 11: Field( + name='battery_status', + type=FIELD_TYPES['battery_status'], + def_num=11, + ), + 18: Field( # Indicates the location of the sensor + name='sensor_position', + type=FIELD_TYPES['body_location'], + def_num=18, + ), + 19: Field( # Used to describe the sensor or location + name='descriptor', + type=BASE_TYPES[0x07], # string + def_num=19, + ), + 20: Field( + name='ant_transmission_type', + type=BASE_TYPES[0x0A], # uint8z + def_num=20, + ), + 21: Field( + name='ant_device_number', + type=BASE_TYPES[0x8B], # uint16z + def_num=21, + ), + 22: Field( + name='ant_network', + type=FIELD_TYPES['ant_network'], + def_num=22, + ), + 25: Field( + name='source_type', + type=FIELD_TYPES['source_type'], + def_num=25, + ), + 27: Field( # Optional free form string to indicate the devices name or model + name='product_name', + type=BASE_TYPES[0x07], # string + def_num=27, + ), + 253: FIELD_TYPE_TIMESTAMP, + }, + ), + 27: MessageType( + name='workout_step', + mesg_num=27, + fields={ + 0: Field( + name='wkt_step_name', + type=BASE_TYPES[0x07], # string + def_num=0, + ), + 1: Field( + name='duration_type', + type=FIELD_TYPES['wkt_step_duration'], + def_num=1, + ), + 2: Field( + name='duration_value', + type=BASE_TYPES[0x86], # uint32 + def_num=2, + subfields=( + SubField( + name='duration_calories', + def_num=2, + type=BASE_TYPES[0x86], # uint32 + units='calories', + ref_fields=( + ReferenceField( + name='duration_type', + def_num=1, + value='calories', + raw_value=4, + ), + ), + ), + SubField( + name='duration_distance', + def_num=2, + type=BASE_TYPES[0x86], # uint32 + scale=100, + units='m', + ref_fields=( + ReferenceField( + name='duration_type', + def_num=1, + value='distance', + raw_value=1, + ), + ), + ), + SubField( + name='duration_hr', + def_num=2, + type=FIELD_TYPES['workout_hr'], + units='% or bpm', + ref_fields=( + ReferenceField( + name='duration_type', + def_num=1, + value='hr_less_than', + raw_value=2, + ), + ReferenceField( + name='duration_type', + def_num=1, + value='hr_greater_than', + raw_value=3, + ), + ), + ), + SubField( + name='duration_power', + def_num=2, + type=FIELD_TYPES['workout_power'], + units='% or watts', + ref_fields=( + ReferenceField( + name='duration_type', + def_num=1, + value='power_less_than', + raw_value=14, + ), + ReferenceField( + name='duration_type', + def_num=1, + value='power_greater_than', + raw_value=15, + ), + ), + ), + SubField( + name='duration_reps', + def_num=2, + type=BASE_TYPES[0x86], # uint32 + ref_fields=( + ReferenceField( + name='duration_type', + def_num=1, + value='reps', + raw_value=29, + ), + ), + ), + SubField( # message_index of step to loop back to. Steps are assumed to be in the order by message_index. custom_name and intensity members are undefined for this duration type. + name='duration_step', + def_num=2, + type=BASE_TYPES[0x86], # uint32 + ref_fields=( + ReferenceField( + name='duration_type', + def_num=1, + value='repeat_until_steps_cmplt', + raw_value=6, + ), + ReferenceField( + name='duration_type', + def_num=1, + value='repeat_until_time', + raw_value=7, + ), + ReferenceField( + name='duration_type', + def_num=1, + value='repeat_until_distance', + raw_value=8, + ), + ReferenceField( + name='duration_type', + def_num=1, + value='repeat_until_calories', + raw_value=9, + ), + ReferenceField( + name='duration_type', + def_num=1, + value='repeat_until_hr_less_than', + raw_value=10, + ), + ReferenceField( + name='duration_type', + def_num=1, + value='repeat_until_hr_greater_than', + raw_value=11, + ), + ReferenceField( + name='duration_type', + def_num=1, + value='repeat_until_power_less_than', + raw_value=12, + ), + ReferenceField( + name='duration_type', + def_num=1, + value='repeat_until_power_greater_than', + raw_value=13, + ), + ), + ), + SubField( + name='duration_time', + def_num=2, + type=BASE_TYPES[0x86], # uint32 + scale=1000, + units='s', + ref_fields=( + ReferenceField( + name='duration_type', + def_num=1, + value='time', + raw_value=0, + ), + ReferenceField( + name='duration_type', + def_num=1, + value='repetition_time', + raw_value=28, + ), + ), + ), + ), + ), + 3: Field( + name='target_type', + type=FIELD_TYPES['wkt_step_target'], + def_num=3, + ), + 4: Field( + name='target_value', + type=BASE_TYPES[0x86], # uint32 + def_num=4, + subfields=( + SubField( + name='repeat_calories', + def_num=4, + type=BASE_TYPES[0x86], # uint32 + units='calories', + ref_fields=( + ReferenceField( + name='duration_type', + def_num=1, + value='repeat_until_calories', + raw_value=9, + ), + ), + ), + SubField( + name='repeat_distance', + def_num=4, + type=BASE_TYPES[0x86], # uint32 + scale=100, + units='m', + ref_fields=( + ReferenceField( + name='duration_type', + def_num=1, + value='repeat_until_distance', + raw_value=8, + ), + ), + ), + SubField( + name='repeat_hr', + def_num=4, + type=FIELD_TYPES['workout_hr'], + units='% or bpm', + ref_fields=( + ReferenceField( + name='duration_type', + def_num=1, + value='repeat_until_hr_less_than', + raw_value=10, + ), + ReferenceField( + name='duration_type', + def_num=1, + value='repeat_until_hr_greater_than', + raw_value=11, + ), + ), + ), + SubField( + name='repeat_power', + def_num=4, + type=FIELD_TYPES['workout_power'], + units='% or watts', + ref_fields=( + ReferenceField( + name='duration_type', + def_num=1, + value='repeat_until_power_less_than', + raw_value=12, + ), + ReferenceField( + name='duration_type', + def_num=1, + value='repeat_until_power_greater_than', + raw_value=13, + ), + ), + ), + SubField( # # of repetitions + name='repeat_steps', + def_num=4, + type=BASE_TYPES[0x86], # uint32 + ref_fields=( + ReferenceField( + name='duration_type', + def_num=1, + value='repeat_until_steps_cmplt', + raw_value=6, + ), + ), + ), + SubField( + name='repeat_time', + def_num=4, + type=BASE_TYPES[0x86], # uint32 + scale=1000, + units='s', + ref_fields=( + ReferenceField( + name='duration_type', + def_num=1, + value='repeat_until_time', + raw_value=7, + ), + ), + ), + SubField( # Zone (1-?); Custom = 0; + name='target_cadence_zone', + def_num=4, + type=BASE_TYPES[0x86], # uint32 + ref_fields=( + ReferenceField( + name='target_type', + def_num=3, + value='cadence', + raw_value=3, + ), + ), + ), + SubField( # hr zone (1-5);Custom =0; + name='target_hr_zone', + def_num=4, + type=BASE_TYPES[0x86], # uint32 + ref_fields=( + ReferenceField( + name='target_type', + def_num=3, + value='heart_rate', + raw_value=1, + ), + ), + ), + SubField( # Power Zone ( 1-7); Custom = 0; + name='target_power_zone', + def_num=4, + type=BASE_TYPES[0x86], # uint32 + ref_fields=( + ReferenceField( + name='target_type', + def_num=3, + value='power', + raw_value=4, + ), + ), + ), + SubField( # speed zone (1-10);Custom =0; + name='target_speed_zone', + def_num=4, + type=BASE_TYPES[0x86], # uint32 + ref_fields=( + ReferenceField( + name='target_type', + def_num=3, + value='speed', + raw_value=0, + ), + ), + ), + SubField( + name='target_stroke_type', + def_num=4, + type=FIELD_TYPES['swim_stroke'], + ref_fields=( + ReferenceField( + name='target_type', + def_num=3, + value='swim_stroke', + raw_value=11, + ), + ), + ), + ), + ), + 5: Field( + name='custom_target_value_low', + type=BASE_TYPES[0x86], # uint32 + def_num=5, + subfields=( + SubField( + name='custom_target_cadence_low', + def_num=5, + type=BASE_TYPES[0x86], # uint32 + units='rpm', + ref_fields=( + ReferenceField( + name='target_type', + def_num=3, + value='cadence', + raw_value=3, + ), + ), + ), + SubField( + name='custom_target_heart_rate_low', + def_num=5, + type=FIELD_TYPES['workout_hr'], + units='% or bpm', + ref_fields=( + ReferenceField( + name='target_type', + def_num=3, + value='heart_rate', + raw_value=1, + ), + ), + ), + SubField( + name='custom_target_power_low', + def_num=5, + type=FIELD_TYPES['workout_power'], + units='% or watts', + ref_fields=( + ReferenceField( + name='target_type', + def_num=3, + value='power', + raw_value=4, + ), + ), + ), + SubField( + name='custom_target_speed_low', + def_num=5, + type=BASE_TYPES[0x86], # uint32 + scale=1000, + units='m/s', + ref_fields=( + ReferenceField( + name='target_type', + def_num=3, + value='speed', + raw_value=0, + ), + ), + ), + ), + ), + 6: Field( + name='custom_target_value_high', + type=BASE_TYPES[0x86], # uint32 + def_num=6, + subfields=( + SubField( + name='custom_target_cadence_high', + def_num=6, + type=BASE_TYPES[0x86], # uint32 + units='rpm', + ref_fields=( + ReferenceField( + name='target_type', + def_num=3, + value='cadence', + raw_value=3, + ), + ), + ), + SubField( + name='custom_target_heart_rate_high', + def_num=6, + type=FIELD_TYPES['workout_hr'], + units='% or bpm', + ref_fields=( + ReferenceField( + name='target_type', + def_num=3, + value='heart_rate', + raw_value=1, + ), + ), + ), + SubField( + name='custom_target_power_high', + def_num=6, + type=FIELD_TYPES['workout_power'], + units='% or watts', + ref_fields=( + ReferenceField( + name='target_type', + def_num=3, + value='power', + raw_value=4, + ), + ), + ), + SubField( + name='custom_target_speed_high', + def_num=6, + type=BASE_TYPES[0x86], # uint32 + scale=1000, + units='m/s', + ref_fields=( + ReferenceField( + name='target_type', + def_num=3, + value='speed', + raw_value=0, + ), + ), + ), + ), + ), + 7: Field( + name='intensity', + type=FIELD_TYPES['intensity'], + def_num=7, + ), + 8: Field( + name='notes', + type=BASE_TYPES[0x07], # string + def_num=8, + ), + 9: Field( + name='equipment', + type=FIELD_TYPES['workout_equipment'], + def_num=9, + ), + 10: Field( + name='exercise_category', + type=FIELD_TYPES['exercise_category'], + def_num=10, + ), + 11: Field( + name='exercise_name', + type=BASE_TYPES[0x84], # uint16 + def_num=11, + ), + 12: Field( + name='exercise_weight', + type=BASE_TYPES[0x84], # uint16 + def_num=12, + scale=100, + units='kg', + ), + 13: Field( + name='weight_display_unit', + type=FIELD_TYPES['fit_base_unit'], + def_num=13, + ), + 254: Field( + name='message_index', + type=FIELD_TYPES['message_index'], + def_num=254, + ), + }, + ), + 32: MessageType( + name='course_point', + mesg_num=32, + fields={ + 1: Field( + name='timestamp', + type=FIELD_TYPES['date_time'], + def_num=1, + ), + 2: Field( + name='position_lat', + type=BASE_TYPES[0x85], # sint32 + def_num=2, + units='semicircles', + ), + 3: Field( + name='position_long', + type=BASE_TYPES[0x85], # sint32 + def_num=3, + 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', + 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, + 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, + ), + ), + ), + ), + ), + 254: Field( + name='message_index', + type=FIELD_TYPES['message_index'], + def_num=254, + ), + }, + ), + 39: MessageType( + name='field_capabilities', + mesg_num=39, + 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='field_num', + type=BASE_TYPES[0x02], # uint8 + def_num=2, + ), + 3: Field( + name='count', + type=BASE_TYPES[0x84], # uint16 + def_num=3, + ), + 254: Field( + name='message_index', + type=FIELD_TYPES['message_index'], + def_num=254, + ), + }, + ), + 49: MessageType( + name='file_creator', + mesg_num=49, + fields={ + 0: Field( + name='software_version', + type=BASE_TYPES[0x84], # uint16 + def_num=0, + ), + 1: Field( + name='hardware_version', + type=BASE_TYPES[0x02], # uint8 + def_num=1, + ), + }, + ), + 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', + ), + 15: Field( # Max temperature during the logging interval ended at timestamp + name='temperature_max', + type=BASE_TYPES[0x83], # sint16 + def_num=15, + scale=100, + units='C', + ), + 16: Field( # Indexed using minute_activity_level enum + name='activity_time', + type=BASE_TYPES[0x84], # uint16 + def_num=16, + units='minutes', + ), + 19: Field( + name='active_calories', + type=BASE_TYPES[0x84], # uint16 + def_num=19, + units='kcal', + ), + 24: Field( # Indicates single type / intensity for duration since last monitoring message. + name='current_activity_type_intensity', + type=BASE_TYPES[0x0D], # byte + def_num=24, + components=( + ComponentField( + name='activity_type', + def_num=5, + accumulate=False, + bits=5, + bit_offset=0, + ), + ComponentField( + name='intensity', + def_num=28, + accumulate=False, + bits=3, + bit_offset=5, + ), + ), + ), + 25: Field( + name='timestamp_min_8', + type=BASE_TYPES[0x02], # uint8 + def_num=25, + units='min', + ), + 26: Field( + name='timestamp_16', + type=BASE_TYPES[0x84], # uint16 + def_num=26, + units='s', + ), + 27: Field( + name='heart_rate', + type=BASE_TYPES[0x02], # uint8 + def_num=27, + units='bpm', + ), + 28: Field( + name='intensity', + type=BASE_TYPES[0x02], # uint8 + def_num=28, + scale=10, + ), + 29: Field( + name='duration_min', + type=BASE_TYPES[0x84], # uint16 + def_num=29, + units='min', + ), + 30: Field( + name='duration', + type=BASE_TYPES[0x86], # uint32 + def_num=30, + units='s', + ), + 31: Field( + name='ascent', + type=BASE_TYPES[0x86], # uint32 + def_num=31, + scale=1000, + units='m', + ), + 32: Field( + name='descent', + type=BASE_TYPES[0x86], # uint32 + def_num=32, + scale=1000, + units='m', + ), + 33: Field( + name='moderate_activity_minutes', + type=BASE_TYPES[0x84], # uint16 + def_num=33, + units='minutes', + ), + 34: Field( + name='vigorous_activity_minutes', + type=BASE_TYPES[0x84], # uint16 + def_num=34, + units='minutes', + ), + 253: FIELD_TYPE_TIMESTAMP, # Must align to logging interval, for example, time must be 00:00:00 for daily log. + }, + ), + 72: MessageType( # Corresponds to file_id of workout or course. + name='training_file', + mesg_num=72, + fields={ + 0: Field( + name='type', + type=FIELD_TYPES['file'], + def_num=0, + ), + 1: Field( + name='manufacturer', + type=FIELD_TYPES['manufacturer'], + def_num=1, + ), + 2: Field( + name='product', + type=BASE_TYPES[0x84], # uint16 + def_num=2, + subfields=( + SubField( + name='garmin_product', + def_num=2, + type=FIELD_TYPES['garmin_product'], + ref_fields=( + ReferenceField( + name='manufacturer', + def_num=1, + value='garmin', + raw_value=1, + ), + ReferenceField( + name='manufacturer', + def_num=1, + value='dynastream', + raw_value=15, + ), + ReferenceField( + name='manufacturer', + def_num=1, + value='dynastream_oem', + raw_value=13, + ), + ), + ), + ), + ), + 3: Field( + name='serial_number', + type=BASE_TYPES[0x8C], # uint32z + def_num=3, + ), + 4: Field( + name='time_created', + type=FIELD_TYPES['date_time'], + def_num=4, + ), + 253: FIELD_TYPE_TIMESTAMP, + }, + ), + 78: MessageType( # Heart rate variability + name='hrv', + mesg_num=78, + fields={ + 0: Field( # Time between beats + name='time', + type=BASE_TYPES[0x84], # uint16 + def_num=0, + scale=1000, + units='s', + ), + }, + ), + 80: MessageType( + name='ant_rx', + mesg_num=80, + fields={ + 0: Field( + name='fractional_timestamp', + type=BASE_TYPES[0x84], # uint16 + def_num=0, + scale=32768, + units='s', + ), + 1: Field( + name='mesg_id', + type=BASE_TYPES[0x0D], # byte + def_num=1, + ), + 2: Field( + name='mesg_data', + type=BASE_TYPES[0x0D], # byte + def_num=2, + components=( + ComponentField( + name='channel_number', + def_num=3, + accumulate=False, + bits=8, + bit_offset=0, + ), + ComponentField( + name='data', + def_num=4, + accumulate=False, + bits=8, + bit_offset=8, + ), + ComponentField( + name='data', + def_num=4, + accumulate=False, + bits=8, + bit_offset=16, + ), + ComponentField( + name='data', + def_num=4, + accumulate=False, + bits=8, + bit_offset=24, + ), + ComponentField( + name='data', + def_num=4, + accumulate=False, + bits=8, + bit_offset=32, + ), + ComponentField( + name='data', + def_num=4, + accumulate=False, + bits=8, + bit_offset=40, + ), + ComponentField( + name='data', + def_num=4, + accumulate=False, + bits=8, + bit_offset=48, + ), + ComponentField( + name='data', + def_num=4, + accumulate=False, + bits=8, + bit_offset=56, + ), + ComponentField( + name='data', + def_num=4, + accumulate=False, + bits=8, + bit_offset=64, + ), + ), + ), + 3: Field( + name='channel_number', + type=BASE_TYPES[0x02], # uint8 + def_num=3, + ), + 4: Field( + name='data', + type=BASE_TYPES[0x0D], # byte + def_num=4, + ), + 253: FIELD_TYPE_TIMESTAMP, + }, + ), + 81: MessageType( + name='ant_tx', + mesg_num=81, + fields={ + 0: Field( + name='fractional_timestamp', + type=BASE_TYPES[0x84], # uint16 + def_num=0, + scale=32768, + units='s', + ), + 1: Field( + name='mesg_id', + type=BASE_TYPES[0x0D], # byte + def_num=1, + ), + 2: Field( + name='mesg_data', + type=BASE_TYPES[0x0D], # byte + def_num=2, + components=( + ComponentField( + name='channel_number', + def_num=3, + accumulate=False, + bits=8, + bit_offset=0, + ), + ComponentField( + name='data', + def_num=4, + accumulate=False, + bits=8, + bit_offset=8, + ), + ComponentField( + name='data', + def_num=4, + accumulate=False, + bits=8, + bit_offset=16, + ), + ComponentField( + name='data', + def_num=4, + accumulate=False, + bits=8, + bit_offset=24, + ), + ComponentField( + name='data', + def_num=4, + accumulate=False, + bits=8, + bit_offset=32, + ), + ComponentField( + name='data', + def_num=4, + accumulate=False, + bits=8, + bit_offset=40, + ), + ComponentField( + name='data', + def_num=4, + accumulate=False, + bits=8, + bit_offset=48, + ), + ComponentField( + name='data', + def_num=4, + accumulate=False, + bits=8, + bit_offset=56, + ), + ComponentField( + name='data', + def_num=4, + accumulate=False, + bits=8, + bit_offset=64, + ), + ), + ), + 3: Field( + name='channel_number', + type=BASE_TYPES[0x02], # uint8 + def_num=3, + ), + 4: Field( + name='data', + type=BASE_TYPES[0x0D], # byte + def_num=4, + ), + 253: FIELD_TYPE_TIMESTAMP, + }, + ), + 82: MessageType( + name='ant_channel_id', + mesg_num=82, + fields={ + 0: Field( + name='channel_number', + type=BASE_TYPES[0x02], # uint8 + def_num=0, + ), + 1: Field( + name='device_type', + type=BASE_TYPES[0x0A], # uint8z + def_num=1, + ), + 2: Field( + name='device_number', + type=BASE_TYPES[0x8B], # uint16z + def_num=2, + ), + 3: Field( + name='transmission_type', + type=BASE_TYPES[0x0A], # uint8z + def_num=3, + ), + 4: Field( + name='device_index', + type=FIELD_TYPES['device_index'], + def_num=4, + ), + }, + ), + 101: MessageType( + name='length', + mesg_num=101, + 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='start_time', + type=FIELD_TYPES['date_time'], + def_num=2, + ), + 3: Field( + name='total_elapsed_time', + type=BASE_TYPES[0x86], # uint32 + def_num=3, + scale=1000, + units='s', + ), + 4: Field( + name='total_timer_time', + type=BASE_TYPES[0x86], # uint32 + def_num=4, + scale=1000, + units='s', + ), + 5: Field( + name='total_strokes', + type=BASE_TYPES[0x84], # uint16 + def_num=5, + units='strokes', + ), + 6: Field( + name='avg_speed', + type=BASE_TYPES[0x84], # uint16 + def_num=6, + scale=1000, + units='m/s', + ), + 7: Field( + name='swim_stroke', + type=FIELD_TYPES['swim_stroke'], + def_num=7, + units='swim_stroke', + ), + 9: Field( + name='avg_swimming_cadence', + type=BASE_TYPES[0x02], # uint8 + def_num=9, + units='strokes/min', + ), + 10: Field( + name='event_group', + type=BASE_TYPES[0x02], # uint8 + def_num=10, + ), + 11: Field( + name='total_calories', + type=BASE_TYPES[0x84], # uint16 + def_num=11, + units='kcal', + ), + 12: Field( + name='length_type', + type=FIELD_TYPES['length_type'], + def_num=12, + ), + 18: Field( + name='player_score', + type=BASE_TYPES[0x84], # uint16 + def_num=18, + ), + 19: Field( + name='opponent_score', + type=BASE_TYPES[0x84], # uint16 + def_num=19, + ), + 20: Field( # stroke_type enum used as the index + name='stroke_count', + type=BASE_TYPES[0x84], # uint16 + def_num=20, + units='counts', + ), + 21: Field( # zone number used as the index + name='zone_count', + type=BASE_TYPES[0x84], # uint16 + def_num=21, + units='counts', + ), + 253: FIELD_TYPE_TIMESTAMP, + 254: Field( + name='message_index', + type=FIELD_TYPES['message_index'], + def_num=254, + ), + }, + ), + 106: MessageType( + name='slave_device', + mesg_num=106, + fields={ + 0: Field( + name='manufacturer', + type=FIELD_TYPES['manufacturer'], + def_num=0, + ), + 1: Field( + name='product', + type=BASE_TYPES[0x84], # uint16 + 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, + ), + ), + ), + ), + ), + }, + ), + 127: MessageType( + name='connectivity', + mesg_num=127, + fields={ + 0: Field( # Use Bluetooth for connectivity features + name='bluetooth_enabled', + type=FIELD_TYPES['bool'], + def_num=0, + ), + 1: Field( # Use Bluetooth Low Energy for connectivity features + name='bluetooth_le_enabled', + type=FIELD_TYPES['bool'], + def_num=1, + ), + 2: Field( # Use ANT for connectivity features + name='ant_enabled', + type=FIELD_TYPES['bool'], + def_num=2, + ), + 3: Field( + name='name', + type=BASE_TYPES[0x07], # string + def_num=3, + ), + 4: Field( + name='live_tracking_enabled', + type=FIELD_TYPES['bool'], + def_num=4, + ), + 5: Field( + name='weather_conditions_enabled', + type=FIELD_TYPES['bool'], + def_num=5, + ), + 6: Field( + name='weather_alerts_enabled', + type=FIELD_TYPES['bool'], + def_num=6, + ), + 7: Field( + name='auto_activity_upload_enabled', + type=FIELD_TYPES['bool'], + def_num=7, + ), + 8: Field( + name='course_download_enabled', + type=FIELD_TYPES['bool'], + def_num=8, + ), + 9: Field( + name='workout_download_enabled', + type=FIELD_TYPES['bool'], + def_num=9, + ), + 10: Field( + name='gps_ephemeris_download_enabled', + type=FIELD_TYPES['bool'], + def_num=10, + ), + 11: Field( + name='incident_detection_enabled', + type=FIELD_TYPES['bool'], + def_num=11, + ), + 12: Field( + name='grouptrack_enabled', + type=FIELD_TYPES['bool'], + def_num=12, + ), + }, + ), + 128: MessageType( + name='weather_conditions', + mesg_num=128, + fields={ + 0: Field( # Current or forecast + name='weather_report', + type=FIELD_TYPES['weather_report'], + def_num=0, + ), + 1: Field( + name='temperature', + type=BASE_TYPES[0x01], # sint8 + def_num=1, + units='C', + ), + 2: Field( # Corresponds to GSC Response weatherIcon field + name='condition', + type=FIELD_TYPES['weather_status'], + def_num=2, + ), + 3: Field( + name='wind_direction', + type=BASE_TYPES[0x84], # uint16 + def_num=3, + units='degrees', + ), + 4: Field( + name='wind_speed', + type=BASE_TYPES[0x84], # uint16 + def_num=4, + scale=1000, + units='m/s', + ), + 5: Field( # range 0-100 + name='precipitation_probability', + type=BASE_TYPES[0x02], # uint8 + def_num=5, + ), + 6: Field( # Heat Index if GCS heatIdx above or equal to 90F or wind chill if GCS windChill below or equal to 32F + name='temperature_feels_like', + type=BASE_TYPES[0x01], # sint8 + def_num=6, + units='C', + ), + 7: Field( + name='relative_humidity', + type=BASE_TYPES[0x02], # uint8 + def_num=7, + ), + 8: Field( # string corresponding to GCS response location string + name='location', + type=BASE_TYPES[0x07], # string + def_num=8, + ), + 9: Field( + name='observed_at_time', + type=FIELD_TYPES['date_time'], + def_num=9, + ), + 10: Field( + name='observed_location_lat', + type=BASE_TYPES[0x85], # sint32 + def_num=10, + units='semicircles', + ), + 11: Field( + name='observed_location_long', + type=BASE_TYPES[0x85], # sint32 + def_num=11, + units='semicircles', + ), + 12: Field( + name='day_of_week', + type=FIELD_TYPES['day_of_week'], + def_num=12, + ), + 13: Field( + name='high_temperature', + type=BASE_TYPES[0x01], # sint8 + def_num=13, + units='C', + ), + 14: Field( + name='low_temperature', + type=BASE_TYPES[0x01], # sint8 + def_num=14, + units='C', + ), + 253: FIELD_TYPE_TIMESTAMP, # time of update for current conditions, else forecast time + }, + ), + 129: MessageType( + name='weather_alert', + mesg_num=129, + fields={ + 0: Field( # Unique identifier from GCS report ID string, length is 12 + name='report_id', + type=BASE_TYPES[0x07], # string + def_num=0, + ), + 1: Field( # Time alert was issued + name='issue_time', + type=FIELD_TYPES['date_time'], + def_num=1, + ), + 2: Field( # Time alert expires + name='expire_time', + type=FIELD_TYPES['date_time'], + def_num=2, + ), + 3: Field( # Warning, Watch, Advisory, Statement + name='severity', + type=FIELD_TYPES['weather_severity'], + def_num=3, + ), + 4: Field( # Tornado, Severe Thunderstorm, etc. + name='type', + type=FIELD_TYPES['weather_severe_type'], + def_num=4, + ), + 253: FIELD_TYPE_TIMESTAMP, + }, + ), + 131: MessageType( + name='cadence_zone', + mesg_num=131, + fields={ + 0: Field( + name='high_value', + type=BASE_TYPES[0x02], # uint8 + def_num=0, + units='rpm', + ), + 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, + ), + }, + ), + 132: MessageType( + name='hr', + mesg_num=132, + fields={ + 0: Field( + name='fractional_timestamp', + type=BASE_TYPES[0x84], # uint16 + def_num=0, + scale=32768, + units='s', + ), + 1: Field( + name='time256', + type=BASE_TYPES[0x02], # uint8 + def_num=1, + scale=256, + units='s', + components=( + ComponentField( + name='fractional_timestamp', + def_num=0, + scale=256, + units='s', + accumulate=False, + bits=8, + bit_offset=0, + ), + ), + ), + 6: Field( + name='filtered_bpm', + type=BASE_TYPES[0x02], # uint8 + def_num=6, + units='bpm', + ), + 9: Field( + name='event_timestamp', + type=BASE_TYPES[0x86], # uint32 + def_num=9, + scale=1024, + units='s', + ), + 10: Field( + name='event_timestamp_12', + type=BASE_TYPES[0x0D], # byte + def_num=10, + components=( + ComponentField( + name='event_timestamp', + def_num=9, + scale=1024, + units='s', + accumulate=True, + bits=12, + bit_offset=0, + ), + ComponentField( + name='event_timestamp', + def_num=9, + scale=1024, + units='s', + accumulate=True, + bits=12, + bit_offset=12, + ), + ComponentField( + name='event_timestamp', + def_num=9, + scale=1024, + units='s', + accumulate=True, + bits=12, + bit_offset=24, + ), + ComponentField( + name='event_timestamp', + def_num=9, + scale=1024, + units='s', + accumulate=True, + bits=12, + bit_offset=36, + ), + ComponentField( + name='event_timestamp', + def_num=9, + scale=1024, + units='s', + accumulate=True, + bits=12, + bit_offset=48, + ), + ComponentField( + name='event_timestamp', + def_num=9, + scale=1024, + units='s', + accumulate=True, + bits=12, + bit_offset=60, + ), + ComponentField( + name='event_timestamp', + def_num=9, + scale=1024, + units='s', + accumulate=True, + bits=12, + bit_offset=72, + ), + ComponentField( + name='event_timestamp', + def_num=9, + scale=1024, + units='s', + accumulate=True, + bits=12, + bit_offset=84, + ), + ComponentField( + name='event_timestamp', + def_num=9, + scale=1024, + units='s', + accumulate=True, + bits=12, + bit_offset=96, + ), + ComponentField( + name='event_timestamp', + def_num=9, + scale=1024, + units='s', + accumulate=True, + bits=12, + bit_offset=108, + ), + ), + ), + 253: FIELD_TYPE_TIMESTAMP, + }, + ), + 142: MessageType( + name='segment_lap', + mesg_num=142, + 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='start_time', + type=FIELD_TYPES['date_time'], + def_num=2, + ), + 3: Field( + name='start_position_lat', + type=BASE_TYPES[0x85], # sint32 + def_num=3, + units='semicircles', + ), + 4: Field( + name='start_position_long', + type=BASE_TYPES[0x85], # sint32 + def_num=4, + units='semicircles', + ), + 5: Field( + name='end_position_lat', + type=BASE_TYPES[0x85], # sint32 + def_num=5, + units='semicircles', + ), + 6: Field( + name='end_position_long', + type=BASE_TYPES[0x85], # sint32 + def_num=6, + units='semicircles', + ), + 7: Field( # Time (includes pauses) + name='total_elapsed_time', + type=BASE_TYPES[0x86], # uint32 + def_num=7, + scale=1000, + units='s', + ), + 8: Field( # Timer Time (excludes pauses) + name='total_timer_time', + type=BASE_TYPES[0x86], # uint32 + def_num=8, + scale=1000, + units='s', + ), + 9: Field( + name='total_distance', + type=BASE_TYPES[0x86], # uint32 + def_num=9, + scale=100, + units='m', + ), + 10: Field( + name='total_cycles', + type=BASE_TYPES[0x86], # uint32 + def_num=10, + units='cycles', + subfields=( + SubField( + name='total_strokes', + def_num=10, + type=BASE_TYPES[0x86], # uint32 + units='strokes', + ref_fields=( + ReferenceField( + name='sport', + def_num=23, + value='cycling', + raw_value=2, + ), + ), + ), + ), + ), + 11: Field( + name='total_calories', + type=BASE_TYPES[0x84], # uint16 + def_num=11, + units='kcal', + ), + 12: Field( # If New Leaf + name='total_fat_calories', + type=BASE_TYPES[0x84], # uint16 + def_num=12, + units='kcal', + ), + 13: Field( + name='avg_speed', + type=BASE_TYPES[0x84], # uint16 + def_num=13, + scale=1000, + units='m/s', + ), + 14: Field( + name='max_speed', + type=BASE_TYPES[0x84], # uint16 + def_num=14, + scale=1000, + units='m/s', + ), + 15: Field( + name='avg_heart_rate', + type=BASE_TYPES[0x02], # uint8 + def_num=15, + units='bpm', + ), + 16: Field( + name='max_heart_rate', + type=BASE_TYPES[0x02], # uint8 + def_num=16, + units='bpm', + ), + 17: Field( # total_cycles / total_timer_time if non_zero_avg_cadence otherwise total_cycles / total_elapsed_time + name='avg_cadence', + type=BASE_TYPES[0x02], # uint8 + def_num=17, + units='rpm', + ), + 18: Field( + name='max_cadence', + type=BASE_TYPES[0x02], # uint8 + def_num=18, + units='rpm', + ), + 19: Field( # total_power / total_timer_time if non_zero_avg_power otherwise total_power / total_elapsed_time + name='avg_power', + type=BASE_TYPES[0x84], # uint16 + def_num=19, + units='watts', + ), + 20: Field( + name='max_power', + type=BASE_TYPES[0x84], # uint16 + def_num=20, + units='watts', + ), + 21: Field( + name='total_ascent', + type=BASE_TYPES[0x84], # uint16 + def_num=21, + units='m', + ), + 22: Field( + name='total_descent', + type=BASE_TYPES[0x84], # uint16 + def_num=22, + units='m', + ), + 23: Field( + name='sport', + type=FIELD_TYPES['sport'], + def_num=23, + ), + 24: Field( + name='event_group', + type=BASE_TYPES[0x02], # uint8 + def_num=24, + ), + 25: Field( # North east corner latitude. + name='nec_lat', + type=BASE_TYPES[0x85], # sint32 + def_num=25, + units='semicircles', + ), + 26: Field( # North east corner longitude. + name='nec_long', + type=BASE_TYPES[0x85], # sint32 + def_num=26, + units='semicircles', + ), + 27: Field( # South west corner latitude. + name='swc_lat', + type=BASE_TYPES[0x85], # sint32 + def_num=27, + units='semicircles', + ), + 28: Field( # South west corner latitude. + name='swc_long', + type=BASE_TYPES[0x85], # sint32 + def_num=28, + units='semicircles', + ), + 29: Field( + name='name', + type=BASE_TYPES[0x07], # string + def_num=29, + ), + 30: Field( + name='normalized_power', + type=BASE_TYPES[0x84], # uint16 + def_num=30, + units='watts', + ), + 31: Field( + name='left_right_balance', + type=FIELD_TYPES['left_right_balance_100'], + def_num=31, + ), + 32: Field( + name='sub_sport', + type=FIELD_TYPES['sub_sport'], + def_num=32, + ), + 33: Field( + name='total_work', + type=BASE_TYPES[0x86], # uint32 + def_num=33, + units='J', + ), + 34: Field( + name='avg_altitude', + type=BASE_TYPES[0x84], # uint16 + def_num=34, + scale=5, + offset=500, + units='m', + ), + 35: Field( + name='max_altitude', + type=BASE_TYPES[0x84], # uint16 + def_num=35, + scale=5, + offset=500, + units='m', + ), + 36: Field( + name='gps_accuracy', + type=BASE_TYPES[0x02], # uint8 + def_num=36, + units='m', + ), + 37: Field( + name='avg_grade', + type=BASE_TYPES[0x83], # sint16 + def_num=37, + scale=100, + units='%', + ), + 38: Field( + name='avg_pos_grade', + type=BASE_TYPES[0x83], # sint16 + def_num=38, + scale=100, + units='%', + ), + 39: Field( + name='avg_neg_grade', + type=BASE_TYPES[0x83], # sint16 + def_num=39, + scale=100, + units='%', + ), + 40: Field( + name='max_pos_grade', + type=BASE_TYPES[0x83], # sint16 + def_num=40, + scale=100, + units='%', + ), + 41: Field( + name='max_neg_grade', + type=BASE_TYPES[0x83], # sint16 + def_num=41, + scale=100, + units='%', + ), + 42: Field( + name='avg_temperature', + type=BASE_TYPES[0x01], # sint8 + def_num=42, + units='C', + ), + 43: Field( + name='max_temperature', + type=BASE_TYPES[0x01], # sint8 + def_num=43, + units='C', + ), + 44: Field( + name='total_moving_time', + type=BASE_TYPES[0x86], # uint32 + def_num=44, + scale=1000, + units='s', + ), + 45: Field( + name='avg_pos_vertical_speed', + type=BASE_TYPES[0x83], # sint16 + def_num=45, + scale=1000, + units='m/s', + ), + 46: Field( + name='avg_neg_vertical_speed', + type=BASE_TYPES[0x83], # sint16 + def_num=46, + scale=1000, + units='m/s', + ), + 47: Field( + name='max_pos_vertical_speed', + type=BASE_TYPES[0x83], # sint16 + def_num=47, + scale=1000, + units='m/s', + ), + 48: Field( + name='max_neg_vertical_speed', + type=BASE_TYPES[0x83], # sint16 + def_num=48, + scale=1000, + units='m/s', + ), + 49: Field( + name='time_in_hr_zone', + type=BASE_TYPES[0x86], # uint32 + def_num=49, + scale=1000, + units='s', + ), + 50: Field( + name='time_in_speed_zone', + type=BASE_TYPES[0x86], # uint32 + def_num=50, + scale=1000, + units='s', + ), + 51: Field( + name='time_in_cadence_zone', + type=BASE_TYPES[0x86], # uint32 + def_num=51, + scale=1000, + units='s', + ), + 52: Field( + name='time_in_power_zone', + type=BASE_TYPES[0x86], # uint32 + def_num=52, + scale=1000, + units='s', + ), + 53: Field( + name='repetition_num', + type=BASE_TYPES[0x84], # uint16 + def_num=53, + ), + 54: Field( + name='min_altitude', + type=BASE_TYPES[0x84], # uint16 + def_num=54, + scale=5, + offset=500, + units='m', + ), + 55: Field( + name='min_heart_rate', + type=BASE_TYPES[0x02], # uint8 + def_num=55, + units='bpm', + ), + 56: Field( + name='active_time', + type=BASE_TYPES[0x86], # uint32 + def_num=56, + scale=1000, + units='s', + ), + 57: Field( + name='wkt_step_index', + type=FIELD_TYPES['message_index'], + def_num=57, + ), + 58: Field( + name='sport_event', + type=FIELD_TYPES['sport_event'], + def_num=58, + ), + 59: Field( + name='avg_left_torque_effectiveness', + type=BASE_TYPES[0x02], # uint8 + def_num=59, + scale=2, + units='percent', + ), + 60: Field( + name='avg_right_torque_effectiveness', + type=BASE_TYPES[0x02], # uint8 + def_num=60, + scale=2, + units='percent', + ), + 61: Field( + name='avg_left_pedal_smoothness', + type=BASE_TYPES[0x02], # uint8 + def_num=61, + scale=2, + units='percent', + ), + 62: Field( + name='avg_right_pedal_smoothness', + type=BASE_TYPES[0x02], # uint8 + def_num=62, + scale=2, + units='percent', + ), + 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, + ), + 2: Field( + name='fit_base_type_id', + type=FIELD_TYPES['fit_base_type'], + def_num=2, + ), + 3: Field( + name='field_name', + type=BASE_TYPES[0x07], # string + def_num=3, + ), + 4: Field( + name='array', + type=BASE_TYPES[0x02], # uint8 + def_num=4, + ), + 5: Field( + name='components', + type=BASE_TYPES[0x07], # string + def_num=5, + ), + 6: Field( + name='scale', + type=BASE_TYPES[0x02], # uint8 + def_num=6, + ), + 7: Field( + name='offset', + type=BASE_TYPES[0x01], # sint8 + def_num=7, + ), + 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, + ), + }, + ), + 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, + ), + 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( + name='application_version', + type=BASE_TYPES[0x86], # uint32 + def_num=4, + ), + }, + ), + 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', + ), + 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', + ), + 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', + ), + 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', + ), + 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', + ), + 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 + }, + ), + 210: MessageType( + name='one_d_sensor_calibration', + mesg_num=210, + 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( # 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 + 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 factor + name='offset_cal', + type=BASE_TYPES[0x85], # sint32 + def_num=4, + ), + 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', + ), + 3: Field( # # of repitions of the movement + name='repetitions', + type=BASE_TYPES[0x84], # uint16 + def_num=3, + ), + 4: Field( # Amount of weight applied for the set + name='weight', + type=BASE_TYPES[0x84], # uint16 + def_num=4, + scale=16, + units='kg', + ), + 5: Field( + name='set_type', + type=FIELD_TYPES['set_type'], + def_num=5, + ), + 6: Field( # Start time of the set + name='start_time', + type=FIELD_TYPES['date_time'], + def_num=6, + ), + 7: Field( + name='category', + type=FIELD_TYPES['exercise_category'], + def_num=7, + ), + 8: Field( # Based on the associated category, see [category]_exercise_names + name='category_subtype', + type=BASE_TYPES[0x84], # uint16 + 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, + fields={ + 0: Field( + name='stress_level_value', + type=BASE_TYPES[0x83], # sint16 + def_num=0, + ), + 1: Field( # Time stress score was calculated + name='stress_level_time', + type=FIELD_TYPES['date_time'], + def_num=1, + units='s', + ), + }, + ), + 258: MessageType( + name='dive_settings', + mesg_num=258, + fields={ + 0: Field( + name='name', + type=BASE_TYPES[0x07], # string + def_num=0, + ), + 1: Field( + name='model', + type=FIELD_TYPES['tissue_model_type'], + def_num=1, + ), + 2: Field( + name='gf_low', + type=BASE_TYPES[0x02], # uint8 + def_num=2, + units='percent', + ), + 3: Field( + name='gf_high', + type=BASE_TYPES[0x02], # uint8 + def_num=3, + units='percent', + ), + 4: Field( + name='water_type', + type=FIELD_TYPES['water_type'], + def_num=4, + ), + 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( # Typically 1.40 + name='po2_warn', + type=BASE_TYPES[0x02], # uint8 + def_num=6, + scale=100, + units='percent', + ), + 7: Field( # Typically 1.60 + name='po2_critical', + type=BASE_TYPES[0x02], # uint8 + def_num=7, + scale=100, + units='percent', + ), + 8: Field( + name='po2_deco', + type=BASE_TYPES[0x02], # uint8 + def_num=8, + scale=100, + units='percent', + ), + 9: Field( + name='safety_stop_enabled', + type=FIELD_TYPES['bool'], + def_num=9, + ), + 10: Field( + name='bottom_depth', + type=BASE_TYPES[0x88], # float32 + def_num=10, + ), + 11: Field( + name='bottom_time', + type=BASE_TYPES[0x86], # uint32 + 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, + ), + 14: Field( + 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='backlight_timeout', + type=FIELD_TYPES['backlight_timeout'], + def_num=16, + ), + 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( # Time at safety stop (if enabled) + name='safety_stop_time', + type=BASE_TYPES[0x84], # uint16 + def_num=18, + units='s', + ), + 19: Field( + name='heart_rate_source_type', + type=FIELD_TYPES['source_type'], + def_num=19, + ), + 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, + ), + ), + ), + ), + ), + 254: Field( + name='message_index', + type=FIELD_TYPES['message_index'], + def_num=254, + ), + }, + ), + 259: MessageType( + name='dive_gas', + mesg_num=259, + fields={ + 0: Field( + name='helium_content', + type=BASE_TYPES[0x02], # uint8 + def_num=0, + units='percent', + ), + 1: Field( + name='oxygen_content', + type=BASE_TYPES[0x02], # uint8 + def_num=1, + units='percent', + ), + 2: Field( + name='status', + type=FIELD_TYPES['dive_gas_status'], + def_num=2, + ), + 254: Field( + name='message_index', + type=FIELD_TYPES['message_index'], + def_num=254, + ), + }, + ), + 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='time', + type=BASE_TYPES[0x85], # sint32 + def_num=1, + units='s', + ), + 2: Field( + name='enabled', + type=FIELD_TYPES['bool'], + def_num=2, + ), + 3: Field( + 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='dive_types', + type=FIELD_TYPES['sub_sport'], + def_num=5, + ), + 254: Field( # Index of the alarm + name='message_index', + type=FIELD_TYPES['message_index'], + def_num=254, + ), + }, + ), + 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( + name='reference_mesg', + type=FIELD_TYPES['mesg_num'], + def_num=0, + ), + 1: Field( + name='reference_index', + type=FIELD_TYPES['message_index'], + def_num=1, + ), + 2: Field( # 0 if above water + name='avg_depth', + type=BASE_TYPES[0x86], # uint32 + def_num=2, + scale=1000, + units='m', + ), + 3: Field( # 0 if above water + name='max_depth', + type=BASE_TYPES[0x86], # uint32 + def_num=3, + scale=1000, + units='m', + ), + 4: Field( # Time since end of last dive + name='surface_interval', + type=BASE_TYPES[0x86], # uint32 + def_num=4, + units='s', + ), + 5: Field( + name='start_cns', + type=BASE_TYPES[0x02], # uint8 + def_num=5, + units='percent', + ), + 6: Field( + name='end_cns', + type=BASE_TYPES[0x02], # uint8 + def_num=6, + 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='o2_toxicity', + type=BASE_TYPES[0x84], # uint16 + def_num=9, + units='OTUs', + ), + 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', + ), + 253: FIELD_TYPE_TIMESTAMP, + }, + ), + + + # ************************* Activity File Messages ************************* + 34: MessageType( + name='activity', + mesg_num=34, + fields={ + 0: Field( # Exclude pauses + name='total_timer_time', + type=BASE_TYPES[0x86], # uint32 + def_num=0, + scale=1000, + units='s', + ), + 1: Field( + name='num_sessions', + type=BASE_TYPES[0x84], # uint16 + def_num=1, + ), + 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, + }, + ), + + + # ********************** Blood Pressure File Messages ********************** + 51: MessageType( + name='blood_pressure', + mesg_num=51, + fields={ + 0: Field( + name='systolic_pressure', + type=BASE_TYPES[0x84], # uint16 + def_num=0, + units='mmHg', + ), + 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, + }, + ), + + + # ************************** Course File Messages ************************** + 31: MessageType( + name='course', + mesg_num=31, + fields={ + 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, + ), + }, + ), + + + # ************************** Device File Messages ************************** + 35: MessageType( + name='software', + mesg_num=35, + fields={ + 3: Field( + name='version', + type=BASE_TYPES[0x84], # uint16 + def_num=3, + scale=100, + ), + 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, + ), + }, + ), + + + # ************************** Goals File Messages *************************** + 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, + ), + }, + ), + + + # ************************ Monitoring File Messages ************************ + 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, + }, + ), + + + # ***************************** Other Messages ***************************** + 145: MessageType( + name='memo_glob', + mesg_num=145, + fields={ + 0: Field( # Block of utf8 bytes + name='memo', + type=BASE_TYPES[0x0D], # byte + 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 + def_num=1, + ), + 2: Field( # Index of external mesg + name='message_index', + type=FIELD_TYPES['message_index'], + def_num=2, + ), + 250: Field( # Sequence number of memo blocks + name='part_index', + type=BASE_TYPES[0x86], # uint32 + def_num=250, + ), + }, + ), + + + # ************************* Schedule File Messages ************************* + 28: MessageType( + name='schedule', + mesg_num=28, + fields={ + 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='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, + ), + ), + ), + ), + ), + 2: Field( # Corresponds to file_id of scheduled workout / course. + name='serial_number', + type=BASE_TYPES[0x8C], # uint32z + def_num=2, + ), + 3: Field( # Corresponds to file_id of scheduled workout / course. + name='time_created', + type=FIELD_TYPES['date_time'], + def_num=3, + ), + 4: Field( # TRUE if this activity has been started + name='completed', + type=FIELD_TYPES['bool'], + def_num=4, + ), + 5: Field( + name='type', + type=FIELD_TYPES['schedule'], + def_num=5, + ), + 6: Field( + name='scheduled_time', + type=FIELD_TYPES['local_date_time'], + def_num=6, + ), + }, + ), + + + # ************************* Segment File Messages ************************** + 148: MessageType( # Unique Identification data for a segment file + name='segment_id', + mesg_num=148, + fields={ + 0: Field( # Friendly name assigned to segment + name='name', + type=BASE_TYPES[0x07], # string + def_num=0, + ), + 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( # Primary key of the user that created the segment + name='user_profile_primary_key', + type=BASE_TYPES[0x86], # uint32 + def_num=4, + ), + 5: Field( # ID of the device that created the segment + name='device_id', + type=BASE_TYPES[0x86], # uint32 + def_num=5, + ), + 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( # Indicates if any segments should be deleted + name='delete_status', + type=FIELD_TYPES['segment_delete_status'], + 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'], + def_num=8, + ), + }, + ), + + + # *********************** Segment List File Messages *********************** + 151: MessageType( # Summary of the unique segment and leaderboard information associated with a segment file. This message is used to compile a segment list file describing all segment files on a device. The segment list file is used when refreshing the contents of a segment file with the latest available leaderboard information. + name='segment_file', + mesg_num=151, + fields={ + 1: Field( # UUID of the segment file + name='file_uuid', + type=BASE_TYPES[0x07], # string + def_num=1, + ), + 3: Field( # Enabled state of the segment file + name='enabled', + type=FIELD_TYPES['bool'], + def_num=3, + ), + 4: Field( # Primary key of the user that created the segment file + name='user_profile_primary_key', + type=BASE_TYPES[0x86], # uint32 + def_num=4, + ), + 7: Field( # Leader type of each leader in the segment file + name='leader_type', + type=FIELD_TYPES['segment_leaderboard_type'], + def_num=7, + ), + 8: Field( # Group primary key of each leader in the segment file + name='leader_group_primary_key', + type=BASE_TYPES[0x86], # uint32 + def_num=8, + ), + 9: Field( # Activity ID of each leader in the segment file + name='leader_activity_id', + type=BASE_TYPES[0x86], # uint32 + def_num=9, + ), + 10: Field( # String version of the activity ID of each leader in the segment file. 21 characters long for each ID, express in decimal + name='leader_activity_id_string', + type=BASE_TYPES[0x07], # string + def_num=10, + ), + 11: Field( # Index for the Leader Board entry selected as the default race participant + name='default_race_leader', + type=BASE_TYPES[0x02], # uint8 + def_num=11, + ), + 254: Field( + name='message_index', + type=FIELD_TYPES['message_index'], + def_num=254, + ), + }, + ), + + + # ************************* Settings File Messages ************************* + 2: MessageType( + name='device_settings', + mesg_num=2, + fields={ + 0: Field( # Index into time zone arrays. + name='active_time_zone', + type=BASE_TYPES[0x02], # uint8 + def_num=0, + ), + 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( # Offset from system time. + name='time_offset', + 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', + ), + 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=36, + ), + 39: Field( # UTC timestamp used to set the devices clock and date + name='clock_time', + type=FIELD_TYPES['date_time'], + def_num=39, + ), + 40: Field( # Bitfield to configure enabled screens for each supported loop + name='pages_enabled', + 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, + ), + 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=80, + ), + 86: Field( # Automatically upload using BLE + name='ble_auto_upload_enabled', + type=FIELD_TYPES['bool'], + def_num=86, + ), + 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=94, + ), + 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, + ), + }, + ), + 3: MessageType( + name='user_profile', + mesg_num=3, + fields={ + 0: Field( + name='friendly_name', + type=BASE_TYPES[0x07], # string + def_num=0, + ), + 1: Field( + name='gender', + type=FIELD_TYPES['gender'], + def_num=1, + ), + 2: Field( + name='age', + type=BASE_TYPES[0x02], # uint8 + def_num=2, + units='years', + ), + 3: Field( + name='height', + type=BASE_TYPES[0x02], # uint8 + def_num=3, + scale=100, + units='m', + ), + 4: Field( + name='weight', + type=BASE_TYPES[0x84], # uint16 + def_num=4, + scale=10, + units='kg', + ), + 5: Field( + name='language', + type=FIELD_TYPES['language'], + def_num=5, + ), + 6: Field( + name='elev_setting', + type=FIELD_TYPES['display_measure'], + def_num=6, + ), + 7: Field( + name='weight_setting', + type=FIELD_TYPES['display_measure'], + def_num=7, + ), + 8: Field( + name='resting_heart_rate', + type=BASE_TYPES[0x02], # uint8 + def_num=8, + units='bpm', + ), + 9: Field( + name='default_max_running_heart_rate', + type=BASE_TYPES[0x02], # uint8 + def_num=9, + units='bpm', + ), + 10: Field( + name='default_max_biking_heart_rate', + type=BASE_TYPES[0x02], # uint8 + def_num=10, + 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, + ), + }, + ), + + + # ********************** Sport Settings File Messages ********************** + 7: MessageType( + name='zones_target', + mesg_num=7, + fields={ + 1: Field( + name='max_heart_rate', + type=BASE_TYPES[0x02], # uint8 + def_num=1, + ), + 2: Field( + 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, + ), + }, + ), + + + # ************************** Totals File Messages ************************** + 33: MessageType( + name='totals', + mesg_num=33, + fields={ + 0: Field( # Excludes pauses + name='timer_time', + type=BASE_TYPES[0x86], # uint32 + def_num=0, + units='s', + ), + 1: Field( + name='distance', + type=BASE_TYPES[0x86], # uint32 + def_num=1, + units='m', + ), + 2: Field( + name='calories', + type=BASE_TYPES[0x86], # uint32 + def_num=2, + units='kcal', + ), + 3: Field( + name='sport', + type=FIELD_TYPES['sport'], + def_num=3, + ), + 4: Field( # Includes pauses + name='elapsed_time', + type=BASE_TYPES[0x86], # uint32 + def_num=4, + units='s', + ), + 5: Field( + name='sessions', + type=BASE_TYPES[0x84], # uint16 + def_num=5, + ), + 6: Field( + name='active_time', + type=BASE_TYPES[0x86], # uint32 + def_num=6, + units='s', + ), + 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'], + def_num=254, + ), + }, + ), + + + # *********************** Weight Scale File Messages *********************** + 30: MessageType( + name='weight_scale', + mesg_num=30, + fields={ + 0: Field( + name='weight', + type=FIELD_TYPES['weight'], + def_num=0, + scale=100, + units='kg', + ), + 1: Field( + name='percent_fat', + type=BASE_TYPES[0x84], # uint16 + def_num=1, + scale=100, + units='%', + ), + 2: Field( + name='percent_hydration', + type=BASE_TYPES[0x84], # uint16 + def_num=2, + scale=100, + units='%', + ), + 3: Field( + name='visceral_fat_mass', + type=BASE_TYPES[0x84], # uint16 + def_num=3, + scale=100, + units='kg', + ), + 4: Field( + name='bone_mass', + type=BASE_TYPES[0x84], # uint16 + def_num=4, + 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=12, + ), + 253: FIELD_TYPE_TIMESTAMP, + }, + ), + + + # ************************* Workout File Messages ************************** + 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, + ), + }, + ), +} diff --git a/scripts/generate_profile.py b/scripts/generate_profile.py index d4f72be..c88ab60 100755 --- a/scripts/generate_profile.py +++ b/scripts/generate_profile.py @@ -465,8 +465,10 @@ def parse_messages(messages_rows, type_list): # Add components if they exist if components: field.components.extend(components) - # Wipe out scale, units, offset from field since it's a component - field = field._replace(scale=None, offset=None, units=None) + + # Wipe out scale, units, offset from field since components scale is None or b'' or is not digit + if row[6] is None or row[6] == b'' or not str(row[6]).isdigit(): + field = field._replace(scale=None, offset=None, units=None) message.fields.append(field) elif row[2] != b'': diff --git a/tests/files/2019-02-17-062644-ELEMNT-297E-195-0.fit b/tests/files/2019-02-17-062644-ELEMNT-297E-195-0.fit new file mode 100644 index 0000000000000000000000000000000000000000..b9f0c00d9bf24cafab21e0e993a5055a80d97027 GIT binary patch literal 715726 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ʺV}vX!ZsJqj0t?rvc=liU4RV3i(niXJx_0} zXJOksG*68|cR?}?!S2F>9v+I(y^~`%rGUCv=q^NtfkUv)T-{_Sm=;!Y2u&^9=88XEG1KL>0 zUayrI8Ms1ILAK~yGQ?o~PR4pjlzcOAQdHn9_OBS-?y_WvM4l-7q@uSMXGI3KV)upR zxXY2D#dT1x?7d9TLF}1`Ox@+l(DX5POnQu!R{q~CEVnzd?X%cUF}mFq$k4bbGH%~_ z=tCCvpiOo(@(9gCg$65^;QEl8Fp;zv2RCC|1Atc|_RL ze~@i2#*&54ar=;=_DAFpKY8d6EbPT)c{r_9a72%=4p>PtWyO&g-ADTO%JQ zGhc2$GSn!E+$Az2xwu>u_O{~W*1`X%BVcZSGJF?`OPGIQJ)i$G3;V0n34z z+yP{$n!+6ezj`P}%D>;ER@Yg)q=96pf)@2hj3DTLi?ic`d$3NjpS5JLAolEydH#O> zMi%xt6SCFSVN;-@6?*qU2M2H#WIg@xtZ$zR99 zeX=IB3LJ}v>xHbI3>Ei)Ht^83EZo26_*Q{~*Qc@EcO2RhcUx8wDhllMO-yBcaB*;-_CPQ&(KOUZ6 z(1>N@oB5w&>!hrO3`G#d$7LyM@C9AVj!Ic8844jnjGd{dX~FpBpfXl*S0;nz9e2cd z`pWZNYq{}F@QhR!IZ~>SJ|Ckj>JLRLZyk?c*Qv)Q+*L{c6`7z&j8Gw4rDU4c_bKZy zGH&i_r2ho%w?K;|O;4-icU03}YX3XZe+<9{&KHVSYo1om_qnE>?8)k+|A0(T6Stz( zPmHhc^F~uoYM}<{|9OZ*6Kby|yjI=uO?*w7dQ!F~>Ho^cfr}AJwr-sXE&W@uqq47R zk^Ze)Uf>ixS^su=tH7bGm#kH7(*KU}Tl=1pZCrGsKBzvEy9@3*q<;lZSQB%%Xi>9H z6I%!GP}ktybxHp`3CB;GD%x^eMk4kO^q-d9N znMon_)xlDCQ_^3>{!rL@MeW@(TZcrdqi61Bq`!O-2bYjR7JcPvo0$+&T3s7CgR&BT-(P>^%W=Cz~bP+miHWkVgslqGbEs&G694vd*nY ze-e?oKQag6yMrvCbJX=3cO>b5MEvXvzai+*@)_~LZJATfbWx=DoGGD&iVpvp5f@yW z&62)7n)HX}ZaLG%kbXbb_vO~8-bksA@9NbPRPI>P@A(VI){v7B z`c10@>d%(QQ5Hvf{8iLZI#SW}5%_Kuwn>hoc+zk0gX3~u?Ps2YY$Dqvy;%b3w=(W1 zHb=>3&j9VM4iLE$Nxx|t4)HBkbm|Q;1zl85^wnrd z+me0-uA03spy<*b6XSzJ*(}+jcBEg1!_I%ZF_oru!XIXv@_}Fw#B8r*~&I{=1)urHnC3P z)QGza>1X5GR!%WR_a>p_P_LitO8QwNaWoh@5_WZ<#l*Ovzu0iuS2ohmK#M$=Z$zyQ zhlAc?-K5{JlYTm`=3Mjk)ej>l#sprozc?85Kek=As0ZoCzw?cNRx~SytOZs6AxP8x7&v)CfaQB#u#NbPK$X@hSKhh6I$-Bry zgIV~)oABN**6p`t4 z40* z8mz4Ec%rXAw@+#ve4NddRyTz7F4*MC(H^>)h5y4QB?i0MTv_L#q_<;)F3a%HO)UIF zo21v;*#Rx6&`w!g@0QzvVvnMskFY0wNk<{)nG6`;ObEf%}Z16ZOQp_53D$DZun zVUwbtYZyUWsB7ZxEYerK%3Vn18UVx-kgA-!=Nw|7+jxl)r&lcR!;uxhe5rjlNVOKk0XE7|6sCf5pz zVx^@`P9uFKjH7lK`=ZXR^0A*?n01%EF`e|G&~KaRibnr}9qWAc_^*2g>4R`NBMCVu zAscrkD<-HQn<{2Vs#9{Enu4u>)d zRrrYCy9n8Nq%Sv(+gnvov~z`tH7Y!0+a#S&`m&h2n5Y6VX?&y>7LmSG8E&t?LD3!@nK29d zL-y5T(wD$B#5xOA$-QnPyERNxNRFc=q{kY^UNcqEetP7uPP4mmgf1n0(d*p)9b!>Y z=K-6Lg-B)-rR*}&7r`aeDwPx+Y{_UD*qWuuSYvFr{hLRoeKC@mxT}D!NCFu*oZ|Fi49X%3{;XY?f+SMx37wE$6l}w6`eG46}R#yq# zt4YtGqwundj;o(h!)GX4A+@lEba;}<9)^6KXwmqY8O?mAv3IgXYf1M>3t9MQ&t>jP z>8mqZ`aEaPWu4cN?!!QQ*QRJ@bVj7_UUpIXob{yp=LEM$AbTlfv#w-D`n6!Qqz1ny z-CzEom^B2Q@-j2pU&Fdfx`A|WT__p3K0&7s$&B%D&n8Lly^(akLkr=UB?X=3KPlG# zIDTa%tZozOUSV{HUQ~3>%1NFlie}1^H z+ew$Vmm^Y=7yT=(o&Y)rKaCP~-a)$DuH0V!fTHV4fi7isxf0n)x_g)<%f=|WflrFn zCa|t@bnhbFoweLv`mCaxZcU2Pj$p@R$-7B+s~xwOgy+BM(cm_7X0&z*J0M5O9@5>w zNGaz1?v5SEK<;DLB;8B8Yx}spNRX1<{RQ+T+bQRxeWd#ZvqqtTitbCpiS1Bzj@-SU zbe9`(yCz%FgV&LD8KH8>?gON|*q+oy^LV6qa+6bU!}gwp)`F&6y1C_h4&e#CVEy$L?|4^?XJ1j!%lw zZc)!#xKESrhr`_V%LGLqmB*~{nGKdbd4_aHdve<)Xy5Z-Mx`g4Fyj|?I&nZ&{tywl~3ime2|l^wqvUl{d);y+u>Jqf?goqj{Dqp1nm_izjs6S zK5Hj+bdhx1p#4MVReL{G1%1TgWj|jc-R9cdcCeMAUk(dum$H{hx51Cw4k&w$&=kgZ zx2h+4-B(Dr_9|#qDH~Bp2in*h_5DJ+Rm-_;|Idnkb2~dGD25G}-@Qt@<=Nb}?^i{O zo3f&Vv@Baj=GREKWGc7q?WkzU>xdbOur1Q_Unkwdliap@sG?=QfEG|cgmC{#y7^Xa z+i6g=d~47S?4TUoH%K?<5VvhZWbU!ah>D+a_HG4RE|ScyeO!EjCm3RSxMUL~+~vii%d5pPd*|giV!o&L!QrL~ff~K+*4>ftuM=8JoFD zH?}di&GxppRxRYNbJ-5Dk3y*13vW-DHzwoga{H__y3P{eq$mO2Dh! zWGS+rAChkH-`qB>grbe@f_9f{=if*-;1jn^F)G?@FMQ5Q?+(!;()A1Bw(O#cwtNWM zUR~OAKPFvoC%0w(qG(hmXg!uCt?miwdYtCAi31dky$pX9&bG_B>?!HG)#SGE$Y2N^ zC0e21!fd+K(KFIH)^OW6^s{HCi%8lF8p4K4|NNYEHfSLQqg%+f%?HIJOfuehLAuVJ zxovcwq8-}6Ch?@W?2VVC>#&*IM&44i^G48K>d_kaE7G+?UyTS<)E0tUA{AMr)bDH3 zCI7>1!;~kCaE`{==yxniw&-`#CBEdgp~%RIT6MQ($7yddb4B4d-jFU1RyPEBGmqbh z=#`M2jQBaYw4i^GE*fKS2;v+;`+UwWgmX_!(zm2*-Jvm)nBOHY{fl&sY@iW}4nIGM(a(&P5GDUj zy88K`$jAxVQBfJJB2J8my>jCF1+0XxxuIf+RHpo$+ z_;pW<(l1VEP%(|ANF9A7U1iMd15vV|8FSL>R#?XDl71qc6;Z)}DT+>dlFrI)QBUT% zKa8j*`mQi$i<@BoGuGORn&ydGRSM3LG>wQ+ynJd!2105l$hIG|Y ztKQLy&Q6|KqpX8%5VguHfSxpRTdzK*2xUDB5bD@QK-)FFL z1=LB2yh5PRe)qYGE@+(*UgibcBz#U@Vbawo!EN0-E4uKX%xY!sX^di)%=-p9s>*FH zWKKlMi~q{3{_PM=M@fr7M;cJCT`k?0Rk!RojobyuD~g`n%5BaaN_P3z>;~nXnj|r6 zIl~j!db-L?z1BO8fd~LEk`<^(x|iBL%Xnu{jX-X^lPkXDN8O- zx{628-s&DdIf6wT>N}^EUupJU)~W*ODs1C68?v>x@Y~#oBh}_K_3goyOZ`?PUHNX@ z)&+U*TWl;}6Jb#`)>59U)x5MiAF5Af>ex5YHpwD^ri<-Ou(iP6)wzdmA^fZe&|8QOl-z>IS z%%ORKq$>db+~%Z*USJWI94OhPeg~4LB^`qoZ6orN+gZew+

2eTpKG)rC(MSMZT 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 literal 0 HcmV?d00001 diff --git a/tests/test.py b/tests/test.py index 5ed7137..b6fa732 100755 --- a/tests/test.py +++ b/tests/test.py @@ -406,6 +406,10 @@ def test_multiple_header(self): f = FitFile(testfile('sample_mulitple_header.fit')) assert len(f.messages) == 3023 + def test_speed(self): + f = FitFile(testfile('2019-02-17-062644-ELEMNT-297E-195-0.fit')) + avg_speed = list(f.get_messages('session'))[0].get_values().get('avg_speed') + self.assertEqual(avg_speed, 5.86) # TODO: # * Test Processors: From 40fa2918c3e91bd8f89908ad3bad81c1c1189dd2 Mon Sep 17 00:00:00 2001 From: twain young Date: Mon, 1 Apr 2019 23:41:30 +0800 Subject: [PATCH 32/69] Add travis ci and coverage script --- .gitignore | 2 ++ .travis.yml | 20 ++++++++++++++++++++ requirements-test.txt | 1 + 3 files changed, 23 insertions(+) create mode 100644 .travis.yml diff --git a/.gitignore b/.gitignore index 749a4c4..d478cbb 100644 --- a/.gitignore +++ b/.gitignore @@ -58,3 +58,5 @@ target/ # python-fitparse specific FitSDK* +Pipfile.lock +Pipfile* \ No newline at end of file diff --git a/.travis.yml b/.travis.yml new file mode 100644 index 0000000..4131539 --- /dev/null +++ b/.travis.yml @@ -0,0 +1,20 @@ +language: python +python: + - "2.7" + - "3.3" + - "3.4" + - "3.5" + - "3.6" + - "nightly" + - "pypy3" + - "pypy" + +install: + - pip install -r requirements-test.txt + +script: + - python -m unittest discover -s tests + - coverage run run_tests.py && coverage report -m + +notifications: + email: false \ No newline at end of file diff --git a/requirements-test.txt b/requirements-test.txt index 020c014..b6627b4 100644 --- a/requirements-test.txt +++ b/requirements-test.txt @@ -9,3 +9,4 @@ click==7.0 # via pip-tools coverage==4.5.2 pip-tools==3.2.0 six==1.12.0 # via pip-tools +coveralls==1.7.0 # via pip-tools From be89b43a6327da8db6246f7e9f58cfab272c5afb Mon Sep 17 00:00:00 2001 From: beyoung Date: Sun, 21 Jul 2019 07:36:23 +0800 Subject: [PATCH 33/69] Fix https://github.com/dtcooper/python-fitparse/issues/86 (#87) --- .gitignore | 4 ++-- tests/test.py | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/.gitignore b/.gitignore index d478cbb..b607499 100644 --- a/.gitignore +++ b/.gitignore @@ -21,6 +21,8 @@ var/ *.egg-info/ .installed.cfg *.egg +Pipfile.lock +Pipfile* # PyInstaller # Usually these files are written by a python script from a template @@ -58,5 +60,3 @@ target/ # python-fitparse specific FitSDK* -Pipfile.lock -Pipfile* \ No newline at end of file diff --git a/tests/test.py b/tests/test.py index b6fa732..9a55f71 100755 --- a/tests/test.py +++ b/tests/test.py @@ -395,7 +395,7 @@ def test_units_processor(self): def test_int_long(self): """Test that ints are properly shifted and scaled""" with FitFile(testfile('event_timestamp.fit')) as f: - assert f.messages[-1].fields[1].raw_value == 1739.486328125 + assert f.messages[-1].fields[1].raw_value == 863.486328125 def test_elemnt_bolt_developer_data_id_without_application_id(self): """Test that a file without application id set inside developer_data_id is parsed From 2861ad9b12d4194b0a8ef425bddd848251c44ada Mon Sep 17 00:00:00 2001 From: David Cooper Date: Sat, 4 Jan 2020 17:23:33 -0800 Subject: [PATCH 34/69] License bump 2020. Happy New Year! --- LICENSE | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/LICENSE b/LICENSE index 0e5daff..3f8862a 100644 --- a/LICENSE +++ b/LICENSE @@ -1,7 +1,7 @@ MIT License -Copyright (c) 2011-2019, David Cooper -Copyright (c) 2017-2019, Carey Metcalfe +Copyright (c) 2011-2020, David Cooper +Copyright (c) 2017-2020, Carey Metcalfe Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal From c789893237967ca4c5640e4c4e7d9f904b67e307 Mon Sep 17 00:00:00 2001 From: Fabian Gebhart Date: Sat, 11 Apr 2020 16:55:22 +0200 Subject: [PATCH 35/69] Fix collections deprecation warning (#99) Co-authored-by: Fabian Gebhart --- fitparse/utils.py | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/fitparse/utils.py b/fitparse/utils.py index d3e427a..d3e4e02 100644 --- a/fitparse/utils.py +++ b/fitparse/utils.py @@ -1,6 +1,9 @@ import io import re -from collections import Iterable +try: + from collections.abc import Iterable +except ImportError: + from collections import Iterable class FitParseError(ValueError): From 059eafe9445452f846eec3fb3dc89f9a71b638d3 Mon Sep 17 00:00:00 2001 From: Carey Metcalfe Date: Thu, 30 Jul 2020 13:28:37 -0400 Subject: [PATCH 36/69] Better handling of optional DataRecord fields Fixes #107 Closes #109 --- fitparse/records.py | 28 ++++++++++++++-------------- 1 file changed, 14 insertions(+), 14 deletions(-) diff --git a/fitparse/records.py b/fitparse/records.py index d007f0a..02c39e8 100644 --- a/fitparse/records.py +++ b/fitparse/records.py @@ -120,6 +120,12 @@ def get(self, field_name, as_dict=False): if field_data.is_named(field_name): return field_data.as_dict() if as_dict else field_data + def get_raw_value(self, field_name): + field_data = self.get(field_name) + if field_data: + return field_data.raw_value + return None + def get_value(self, field_name): # SIMPLIFY: get rid of this completely field_data = self.get(field_name) @@ -433,11 +439,8 @@ def parse_string(string): def add_dev_data_id(message): global DEV_TYPES - dev_data_index = message.get('developer_data_index').raw_value - if message.get('application_id'): - application_id = message.get('application_id').raw_value - else: - application_id = None + dev_data_index = message.get_raw_value('developer_data_index') + application_id = message.get_raw_value('application_id') # Note that nothing in the spec says overwriting an existing type is invalid DEV_TYPES[dev_data_index] = {'dev_data_index': dev_data_index, 'application_id': application_id, 'fields': {}} @@ -446,15 +449,12 @@ def add_dev_data_id(message): def add_dev_field_description(message): global DEV_TYPES - dev_data_index = message.get('developer_data_index').raw_value - field_def_num = message.get('field_definition_number').raw_value - base_type_id = message.get('fit_base_type_id').raw_value - field_name = message.get('field_name').raw_value - units = message.get('units').raw_value - - native_field_num = message.get('native_field_num') - if native_field_num is not None: - native_field_num = native_field_num.raw_value + dev_data_index = message.get_raw_value('developer_data_index') + field_def_num = message.get_raw_value('field_definition_number') + base_type_id = message.get_raw_value('fit_base_type_id') + field_name = message.get_raw_value('field_name') + units = message.get_raw_value("units") + native_field_num = message.get_raw_value('native_field_num') if dev_data_index not in DEV_TYPES: raise FitParseError("No such dev_data_index=%s found" % (dev_data_index)) From 5a02aef50dbb7450ed7d00f82594bab18d00581a Mon Sep 17 00:00:00 2001 From: Carey Metcalfe Date: Thu, 30 Jul 2020 14:44:19 -0400 Subject: [PATCH 37/69] Add more information to README --- README.md | 53 ++++++++++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 52 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index b221c59..752f28c 100644 --- a/README.md +++ b/README.md @@ -15,7 +15,58 @@ FIT files by [ANT](http://www.thisisant.com/). - The SDK, code examples, and detailed documentation can be found in the [ANT FIT SDK](http://www.thisisant.com/resources/fit). - + + +Usage +----- +A simple example of printing records from a fit file: + +```python +import fitparse + +# Load the FIT file +fitfile = fitparse.FitFile("my_activity.fit") + +# Iterate over all messages of type "record" +# (other types include "device_info", "file_creator", "event", etc) +for record in fitfile.get_messages("record"): + + # Records can contain multiple pieces of data (ex: timestamp, latitude, longitude, etc) + for data in record: + + # Print the name and value of the data (and the units if it has any) + if data.units: + print(" * {}: {} ({})".format(data.name, data.value, data.units)) + else: + print(" * {}: {}".format(data.name, data.value)) + + print("---") +``` + +The library also provides a `fitdump` script for command line usage: +``` +$ fitdump --help +usage: fitdump [-h] [-v] [-o OUTPUT] [-t {readable,json}] [-n NAME] [--ignore-crc] FITFILE + +Dump .FIT files to various formats + +positional arguments: + FITFILE Input .FIT file (Use - for stdin) + +optional arguments: + -h, --help show this help message and exit + -v, --verbose + -o OUTPUT, --output OUTPUT + File to output data into (defaults to stdout) + -t {readable,json}, --type {readable,json} + File type to output. (DEFAULT: readable) + -n NAME, --name NAME Message name (or number) to filter + --ignore-crc Some devices can write invalid crc's, ignore these. +``` + +See the documentation for more: http://dtcooper.github.com/python-fitparse + + Major Changes From Original Version ----------------------------------- From 3a9ce0f2009385aa178ef4ac08bb8e0e48569bae Mon Sep 17 00:00:00 2001 From: Carey Metcalfe Date: Sat, 1 Aug 2020 13:47:57 -0400 Subject: [PATCH 38/69] fitdump: Always try to close output file --- scripts/fitdump | 17 +++++++++++------ 1 file changed, 11 insertions(+), 6 deletions(-) diff --git a/scripts/fitdump b/scripts/fitdump index 5068456..f49c0f7 100755 --- a/scripts/fitdump +++ b/scripts/fitdump @@ -107,12 +107,17 @@ def main(args=None): as_dict=options.as_dict ) - if options.type == "json": - json.dump(records, fp=options.output, cls=RecordJSONEncoder) - elif options.type == "readable": - options.output.writelines(format_message(n, record, options) - for n, record in enumerate(records, 1)) - + try: + if options.type == "json": + json.dump(records, fp=options.output, cls=RecordJSONEncoder) + elif options.type == "readable": + options.output.writelines(format_message(n, record, options) + for n, record in enumerate(records, 1)) + finally: + try: + options.output.close() + except IOError: + pass if __name__ == '__main__': try: From 4a9c7191301f30b5497634bc2163bbbabdfa0418 Mon Sep 17 00:00:00 2001 From: Carey Metcalfe Date: Sun, 9 Aug 2020 15:55:10 -0400 Subject: [PATCH 39/69] Properly serialize times to json --- scripts/fitdump | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/scripts/fitdump b/scripts/fitdump index f49c0f7..8a5b0a1 100755 --- a/scripts/fitdump +++ b/scripts/fitdump @@ -80,7 +80,7 @@ class RecordJSONEncoder(json.JSONEncoder): def default(self, obj): if isinstance(obj, types.GeneratorType): return list(obj) - if isinstance(obj, datetime.datetime): + if isinstance(obj, (datetime.datetime, datetime.time)): return obj.isoformat() if isinstance(obj, fitparse.DataMessage): return { From 5b712e97103c2fd02f48f614a35b6ddcce32b37a Mon Sep 17 00:00:00 2001 From: Carey Metcalfe Date: Sun, 9 Aug 2020 16:33:04 -0400 Subject: [PATCH 40/69] Give unnamed dev fields a default name Fixes #62 --- fitparse/records.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/fitparse/records.py b/fitparse/records.py index 02c39e8..77794d4 100644 --- a/fitparse/records.py +++ b/fitparse/records.py @@ -452,7 +452,7 @@ def add_dev_field_description(message): dev_data_index = message.get_raw_value('developer_data_index') field_def_num = message.get_raw_value('field_definition_number') base_type_id = message.get_raw_value('fit_base_type_id') - field_name = message.get_raw_value('field_name') + field_name = message.get_raw_value('field_name') or "unnamed_dev_field_%s" % field_def_num units = message.get_raw_value("units") native_field_num = message.get_raw_value('native_field_num') From e7ba0bcee12a7a6cdae710b7455e80437c882e4e Mon Sep 17 00:00:00 2001 From: Carey Metcalfe Date: Sun, 9 Aug 2020 16:38:27 -0400 Subject: [PATCH 41/69] Fix processing enhanced_speed when it's a tuple Fixes the issue described in https://github.com/dtcooper/python-fitparse/issues/62#issuecomment-376587599 where the `StandardUnitsDataProcessor` was failing to parse speeds when they were tuples. The fix was mostly copied from https://github.com/polyvertex/fitdecode/commit/86f548c06e6025e84855bdb1d8c7d2c27c36e19b --- fitparse/processors.py | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/fitparse/processors.py b/fitparse/processors.py index 810233f..493f166 100644 --- a/fitparse/processors.py +++ b/fitparse/processors.py @@ -1,5 +1,5 @@ import datetime -from fitparse.utils import scrub_method_name +from fitparse.utils import scrub_method_name, is_iterable # Datetimes (uint32) represent seconds since this UTC_REFERENCE UTC_REFERENCE = 631065600 # timestamp for UTC 00:00 Dec 31 1989 @@ -107,7 +107,13 @@ def process_field_distance(self, field_data): def process_field_speed(self, field_data): if field_data.value is not None: - field_data.value *= 60.0 * 60.0 / 1000.0 + factor = 60.0 * 60.0 / 1000.0 + + # record.enhanced_speed field can be a tuple + if is_iterable(field_data.value): + field_data.value = tuple(x * factor for x in field_data.value) + else: + field_data.value *= factor field_data.units = 'km/h' def process_units_semicircles(self, field_data): From d46429e3cd69a27f8009a703e6bab1d1027919c7 Mon Sep 17 00:00:00 2001 From: Carey Metcalfe Date: Sun, 6 Sep 2020 23:26:15 -0400 Subject: [PATCH 42/69] Bump version to v1.2.0 --- fitparse/__init__.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/fitparse/__init__.py b/fitparse/__init__.py index 9053f66..bbf7cd4 100644 --- a/fitparse/__init__.py +++ b/fitparse/__init__.py @@ -3,7 +3,7 @@ from fitparse.processors import FitFileDataProcessor, StandardUnitsDataProcessor -__version__ = '1.1.0' +__version__ = '1.2.0' __all__ = [ 'FitFileDataProcessor', 'FitFile', 'FitParseError', 'StandardUnitsDataProcessor', 'DataMessage' From 4b029155c8817eee18c90f0086e28bb0c2c864b6 Mon Sep 17 00:00:00 2001 From: Daniel Lenski Date: Tue, 15 Dec 2020 20:17:08 -0800 Subject: [PATCH 43/69] Python 3 definitely supported now Minimum supported version appears to be 2.7, based on .travis.yml --- docs/index.rst | 8 +------- 1 file changed, 1 insertion(+), 7 deletions(-) diff --git a/docs/index.rst b/docs/index.rst index 78400e9..434a376 100644 --- a/docs/index.rst +++ b/docs/index.rst @@ -56,13 +56,7 @@ Requirements The following are required to install :mod:`fitparse`, -* `Python `_ 2.5 and above (Python 3 is currently not - supported) - -* The `argparse `_ is required for the - :command:`fitdump` command, but it is included in the Python standard library - as of version 2.7. Using ``pip`` to install the package will install this if - needed. +* `Python `_ 2.7 and above API Documentation From 64b7d26139c86de6e1907a66616603ba39f12a00 Mon Sep 17 00:00:00 2001 From: Dan Lenski Date: Tue, 15 Dec 2020 21:37:27 -0800 Subject: [PATCH 44/69] Warn and fall back to byte encoding in the case of a mismatched field size (#116) Real-world example in the file `Bicicleta20201025061019.fit` from https://github.com/GoldenCheetah/GoldenCheetah/issues/3645 (device is Coros Pace 2) It appears to parse fine with this small change. --- fitparse/base.py | 8 ++++---- .../coros-pace-2-cycling-misaligned-fields.fit | Bin 0 -> 258990 bytes tests/test.py | 9 +++++++++ 3 files changed, 13 insertions(+), 4 deletions(-) create mode 100644 tests/files/coros-pace-2-cycling-misaligned-fields.fit diff --git a/fitparse/base.py b/fitparse/base.py index d3370b4..43c5c35 100644 --- a/fitparse/base.py +++ b/fitparse/base.py @@ -1,6 +1,7 @@ import io import os import struct +import warnings # Python 2 compat try: @@ -191,10 +192,9 @@ def _parse_definition_message(self, header): base_type = BASE_TYPES.get(base_type_num, BASE_TYPE_BYTE) if (field_size % base_type.size) != 0: - # NOTE: we could fall back to byte encoding if there's any - # examples in the wild. For now, just throw an exception - raise FitParseError("Invalid field size %d for type '%s' (expected a multiple of %d)" % ( - field_size, base_type.name, base_type.size)) + warnings.warn("Message %d: Invalid field size %d for field '%s' of type '%s' (expected a multiple of %d); falling back to byte encoding." % ( + len(self._messages)+1, field_size, field.name, base_type.name, base_type.size)) + base_type = BASE_TYPE_BYTE # If the field has components that are accumulators # start recording their accumulation at 0 diff --git a/tests/files/coros-pace-2-cycling-misaligned-fields.fit b/tests/files/coros-pace-2-cycling-misaligned-fields.fit new file mode 100644 index 0000000000000000000000000000000000000000..ae824ab836761c166fa3ec2589a60ee70643357b GIT binary patch literal 258990 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%0DW_iZA5grX+fcrJkt>q#ACO9wL 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 VTRvoo-9Bfg1Zlo}p3l>H{||s<_{0DJ literal 0 HcmV?d00001 diff --git a/tests/test.py b/tests/test.py index 9a55f71..2e12cde 100755 --- a/tests/test.py +++ b/tests/test.py @@ -5,6 +5,7 @@ import os from struct import pack import sys +import warnings from fitparse import FitFile from fitparse.processors import UTC_REFERENCE, StandardUnitsDataProcessor @@ -411,6 +412,14 @@ def test_speed(self): avg_speed = list(f.get_messages('session'))[0].get_values().get('avg_speed') self.assertEqual(avg_speed, 5.86) + def test_mismatched_field_size(self): + f = FitFile(testfile('coros-pace-2-cycling-misaligned-fields.fit')) + with warnings.catch_warnings(record=True) as w: + f.parse() + assert len(w) == 5 + assert all("falling back to byte encoding" in str(x) for x in w) + self.assertEqual(len(f.messages), 11293) + # TODO: # * Test Processors: # - process_type_<>, process_field_<>, process_units_<>, process_message_<> From 5c0bff19c7f0de6b87532ee2899d844e2d2372ab Mon Sep 17 00:00:00 2001 From: Dan Lenski Date: Sun, 20 Dec 2020 06:45:22 -0800 Subject: [PATCH 45/69] Add Github actions workflow for test and coverage (#119) Also adds a Build Status badge to the README Replaces .travis.yml --- .github/workflows/test.yml | 42 ++++++++++++++++++++++++++++++++++++++ .travis.yml | 20 ------------------ README.md | 2 ++ requirements-test.txt | 14 ++----------- setup.py | 4 ++-- 5 files changed, 48 insertions(+), 34 deletions(-) create mode 100644 .github/workflows/test.yml delete mode 100644 .travis.yml diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml new file mode 100644 index 0000000..a535b93 --- /dev/null +++ b/.github/workflows/test.yml @@ -0,0 +1,42 @@ +# This workflow will install Python dependencies, run tests and lint with a variety of Python versions +# For more information see: https://help.github.com/actions/language-and-framework-guides/using-python-with-github-actions + +name: test + +on: [ push, pull_request] + +jobs: + build: + + runs-on: ubuntu-latest + strategy: + matrix: + python-version: ['2.7', '3.3', '3.4', '3.5', '3.6', '3.x', 'pypy2', 'pypy3'] + + steps: + - uses: actions/checkout@v2 + + - name: Set up Python ${{ matrix.python-version }} + uses: actions/setup-python@v2 + with: + python-version: ${{ matrix.python-version }} + + - name: Install dependencies + run: | + sudo apt install -y libgirepository1.0-dev + python -m pip install --upgrade pip + python -m pip install flake8 pytest + if [ -f requirements.txt ]; then pip install -r requirements.txt; fi + + - name: Lint with flake8 + run: | + # stop the build if there are Python syntax errors or undefined names + flake8 . --count --select=E9,F63,F7,F82 --show-source --statistics + # exit-zero treats all errors as warnings. The GitHub editor is 127 chars wide + flake8 . --count --exit-zero --max-complexity=10 --max-line-length=127 --statistics + + - name: Run tests + run: | + if [ -f requirements-test.txt ]; then pip install -r requirements-test.txt; fi + python -m unittest discover -s tests + coverage run run_tests.py && coverage report -m diff --git a/.travis.yml b/.travis.yml deleted file mode 100644 index 4131539..0000000 --- a/.travis.yml +++ /dev/null @@ -1,20 +0,0 @@ -language: python -python: - - "2.7" - - "3.3" - - "3.4" - - "3.5" - - "3.6" - - "nightly" - - "pypy3" - - "pypy" - -install: - - pip install -r requirements-test.txt - -script: - - python -m unittest discover -s tests - - coverage run run_tests.py && coverage report -m - -notifications: - email: false \ No newline at end of file diff --git a/README.md b/README.md index 752f28c..9841cb5 100644 --- a/README.md +++ b/README.md @@ -2,6 +2,8 @@ python-fitparse =============== Here's a Python library to parse ANT/Garmin `.FIT` files. +[![Build Status](https://github.com/dtcooper/python-fitparse/workflows/test/badge.svg)](https://github.com/dtcooper/python-fitparse/actions?query=workflow%3Atest) + Install from [![PyPI](https://img.shields.io/pypi/v/fitparse.svg)](https://pypi.python.org/pypi/fitparse/): ``` diff --git a/requirements-test.txt b/requirements-test.txt index b6627b4..5cc4f02 100644 --- a/requirements-test.txt +++ b/requirements-test.txt @@ -1,12 +1,2 @@ -# -# This file is autogenerated by pip-compile -# To update, run: -# -# pip-compile --output-file requirements-test.txt etc/requirements-test.in -# - -click==7.0 # via pip-tools -coverage==4.5.2 -pip-tools==3.2.0 -six==1.12.0 # via pip-tools -coveralls==1.7.0 # via pip-tools +coverage>=4.5.2 +coveralls>=1.7.0 # via pip-tools diff --git a/setup.py b/setup.py index 227293f..7c8dc13 100644 --- a/setup.py +++ b/setup.py @@ -5,8 +5,8 @@ requires = None -if sys.version_info < (2, 7): - requires = ['argparse'] +if sys.version_info < (2, 7) or (3, 0) <= sys.version_info < (3, 3): + sys.exit("Python 2.7 or Python 3.3+ are required.") setup( From 7c0b7641952e856e69d579d57d819fb77143a9da Mon Sep 17 00:00:00 2001 From: Scott Phillips <57362841+scott-phillips-ah@users.noreply.github.com> Date: Sun, 13 Sep 2020 10:32:04 -0400 Subject: [PATCH 46/69] Add support for badly terminated files (#114) --- fitparse/base.py | 15 +++++++++++---- scripts/fitdump | 2 +- tests/files/nick.fit | Bin 0 -> 403456 bytes tests/test.py | 4 ++++ 4 files changed, 16 insertions(+), 5 deletions(-) create mode 100644 tests/files/nick.fit diff --git a/fitparse/base.py b/fitparse/base.py index 43c5c35..63aec6e 100644 --- a/fitparse/base.py +++ b/fitparse/base.py @@ -80,6 +80,7 @@ def _read_struct(self, fmt, endian='<', data=None, always_tuple=False): def _read_and_assert_crc(self, allow_zero=False): # CRC Calculation is little endian from SDK + # TODO - How to handle the case of unterminated file? Error out and have user retry with check_crc=false? crc_computed, crc_read = self._crc.value, self._read_struct(Crc.FMT) if not self.check_crc: return @@ -132,7 +133,8 @@ def _parse_file_header(self): def _parse_message(self): # When done, calculate the CRC and return None if self._bytes_left <= 0: - if not self._complete: + # Don't assert CRC if requested not + if not self._complete and self.check_crc: self._read_and_assert_crc() if self._file.tell() >= self._filesize: @@ -245,9 +247,14 @@ def _parse_raw_values_from_data_message(self, def_mesg): struct_fmt = str(int(field_def.size / base_type.size)) + base_type.fmt # Extract the raw value, ask for a tuple if it's a byte type - raw_value = self._read_struct( - struct_fmt, endian=def_mesg.endian, always_tuple=is_byte, - ) + try: + raw_value = self._read_struct( + struct_fmt, endian=def_mesg.endian, always_tuple=is_byte, + ) + except FitEOFError: + # file was suddenly terminated, usually due to + print("File was terminated unexpectedly, some data will not be loaded.") + break # If the field returns with a tuple of values it's definitely an # oddball, but we'll parse it on a per-value basis it. diff --git a/scripts/fitdump b/scripts/fitdump index 8a5b0a1..b6043c2 100755 --- a/scripts/fitdump +++ b/scripts/fitdump @@ -99,7 +99,7 @@ def main(args=None): fitfile = fitparse.FitFile( options.infile, data_processor=fitparse.StandardUnitsDataProcessor(), - check_crc = not(options.ignore_crc), + check_crc=not(options.ignore_crc), ) records = fitfile.get_messages( name=options.name, diff --git a/tests/files/nick.fit b/tests/files/nick.fit new file mode 100644 index 0000000000000000000000000000000000000000..5c9d2e0e5a71370a8b831f15fc1f116766e4f695 GIT binary patch literal 403456 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℘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 &YXmhKJS+Yhuh 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¨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 literal 0 HcmV?d00001 diff --git a/tests/test.py b/tests/test.py index 2e12cde..c7fd624 100755 --- a/tests/test.py +++ b/tests/test.py @@ -420,6 +420,10 @@ def test_mismatched_field_size(self): assert all("falling back to byte encoding" in str(x) for x in w) self.assertEqual(len(f.messages), 11293) + def test_unterminated_file(self): + f = FitFile(testfile('nick.fit'), check_crc=False) + f.parse() + # TODO: # * Test Processors: # - process_type_<>, process_field_<>, process_units_<>, process_message_<> From 52a6f01447a00a67c05c6cca7ed7472abf24d564 Mon Sep 17 00:00:00 2001 From: Aart Goossens Date: Sun, 19 Apr 2020 21:08:49 +0200 Subject: [PATCH 47/69] Add pathlib support to fileish_open (#101) --- fitparse/utils.py | 16 +++++++++++++--- tests/test_utils.py | 8 ++++++++ 2 files changed, 21 insertions(+), 3 deletions(-) diff --git a/fitparse/utils.py b/fitparse/utils.py index d3e4e02..aa70a90 100644 --- a/fitparse/utils.py +++ b/fitparse/utils.py @@ -5,6 +5,12 @@ except ImportError: from collections import Iterable +try: + # Python 3.4+ + from pathlib import PurePath +except ImportError: + PurePath = None + class FitParseError(ValueError): pass @@ -56,9 +62,13 @@ def fileish_open(fileish, mode): return open(fileish, mode) except TypeError: return io.BytesIO(fileish) - else: - # Python 3 - file contents - return io.BytesIO(fileish) + + # Python 3 - pathlib obj + if PurePath and isinstance(fileish, PurePath): + return fileish.open(mode) + + # Python 3 - file contents + return io.BytesIO(fileish) def is_iterable(obj): diff --git a/tests/test_utils.py b/tests/test_utils.py index 966548c..01d3409 100644 --- a/tests/test_utils.py +++ b/tests/test_utils.py @@ -5,6 +5,12 @@ import sys import tempfile +try: + # Python 3.4+ + from pathlib import Path +except ImportError: + Path = None + from fitparse.utils import fileish_open, is_iterable if sys.version_info >= (2, 7): @@ -38,6 +44,8 @@ def test_fopen(fileish): test_fopen(f.read()) with open(testfile("nametest.FIT"), 'rb') as f: test_fopen(io.BytesIO(f.read())) + if Path: + test_fopen(Path(testfile('nametest.FIT'))) def test_fileish_open_write(self): From 55a30f274c0992bc1da73be2a80c3fb9eabb64c0 Mon Sep 17 00:00:00 2001 From: Carey Metcalfe Date: Mon, 21 Dec 2020 23:42:24 -0500 Subject: [PATCH 48/69] Emit a warning instead of printing a message --- fitparse/base.py | 4 ++-- tests/test.py | 6 ++++-- 2 files changed, 6 insertions(+), 4 deletions(-) diff --git a/fitparse/base.py b/fitparse/base.py index 63aec6e..e68278b 100644 --- a/fitparse/base.py +++ b/fitparse/base.py @@ -252,8 +252,8 @@ def _parse_raw_values_from_data_message(self, def_mesg): struct_fmt, endian=def_mesg.endian, always_tuple=is_byte, ) except FitEOFError: - # file was suddenly terminated, usually due to - print("File was terminated unexpectedly, some data will not be loaded.") + # file was suddenly terminated + warnings.warn("File was terminated unexpectedly, some data will not be loaded.") break # If the field returns with a tuple of values it's definitely an diff --git a/tests/test.py b/tests/test.py index c7fd624..a0d2b37 100755 --- a/tests/test.py +++ b/tests/test.py @@ -333,7 +333,8 @@ def test_invalid_crc(self): def test_unexpected_eof(self): try: - FitFile(testfile('activity-unexpected-eof.fit')).parse() + with warnings.catch_warnings(record=True): + FitFile(testfile('activity-unexpected-eof.fit')).parse() self.fail("Didn't detect an unexpected EOF") except FitEOFError: pass @@ -422,7 +423,8 @@ def test_mismatched_field_size(self): def test_unterminated_file(self): f = FitFile(testfile('nick.fit'), check_crc=False) - f.parse() + with warnings.catch_warnings(record=True) as w: + f.parse() # TODO: # * Test Processors: From 08d49beebba826f606de226acdf1537d47f41e6a Mon Sep 17 00:00:00 2001 From: Carey Metcalfe Date: Fri, 25 Dec 2020 13:14:11 -0500 Subject: [PATCH 49/69] Break optional functionality out of FitFile class (#120) `FitFile` was renamed to `FitFileDecoder` and the caching and data processing functionality was moved into mixin classes. This allows library users more flexibility in what features they want to use. A new `UncachedFitFile` class was added for parsing fit files with data processors without caching messages. The `fitdump` script now uses this class to reduce memory usage. The original `FitFile` behaviour has been preserved by adding a class that implements both caching and data processing mixins. --- fitparse/__init__.py | 10 +-- fitparse/base.py | 145 +++++++++++++++++++++++++++++++------------ scripts/fitdump | 2 +- tests/test.py | 2 +- 4 files changed, 112 insertions(+), 47 deletions(-) diff --git a/fitparse/__init__.py b/fitparse/__init__.py index bbf7cd4..3453ef9 100644 --- a/fitparse/__init__.py +++ b/fitparse/__init__.py @@ -1,10 +1,10 @@ -from fitparse.base import FitFile, FitParseError +#!/usr/bin/env python + +# Make classes available +from fitparse.base import FitFile, FitFileDecoder, UncachedFitFile, \ + FitParseError, CacheMixin, DataProcessorMixin from fitparse.records import DataMessage from fitparse.processors import FitFileDataProcessor, StandardUnitsDataProcessor __version__ = '1.2.0' -__all__ = [ - 'FitFileDataProcessor', 'FitFile', 'FitParseError', - 'StandardUnitsDataProcessor', 'DataMessage' -] diff --git a/fitparse/base.py b/fitparse/base.py index e68278b..c57d118 100644 --- a/fitparse/base.py +++ b/fitparse/base.py @@ -1,3 +1,5 @@ +#!/usr/bin/env python + import io import os import struct @@ -19,19 +21,19 @@ from fitparse.utils import fileish_open, is_iterable, FitParseError, FitEOFError, FitCRCError, FitHeaderError -class FitFile(object): +class FitFileDecoder(object): + """Basic decoder for fit files""" + def __init__(self, fileish, check_crc=True, data_processor=None): self._file = fileish_open(fileish, 'rb') self.check_crc = check_crc self._crc = None - self._processor = data_processor or FitFileDataProcessor() # Get total filesize self._file.seek(0, os.SEEK_END) self._filesize = self._file.tell() self._file.seek(0, os.SEEK_SET) - self._messages = [] # Start off by parsing the file header (sets initial attribute values) self._parse_file_header() @@ -158,7 +160,6 @@ def _parse_message(self): elif message.mesg_type.name == 'field_description': add_dev_field_description(message) - self._messages.append(message) return message def _parse_message_header(self): @@ -194,8 +195,10 @@ def _parse_definition_message(self, header): base_type = BASE_TYPES.get(base_type_num, BASE_TYPE_BYTE) if (field_size % base_type.size) != 0: - warnings.warn("Message %d: Invalid field size %d for field '%s' of type '%s' (expected a multiple of %d); falling back to byte encoding." % ( - len(self._messages)+1, field_size, field.name, base_type.name, base_type.size)) + warnings.warn( + "Invalid field size %d for field '%s' of type '%s' (expected a multiple of %d); falling back to byte encoding." % ( + field_size, field.name, base_type.name, base_type.size) + ) base_type = BASE_TYPE_BYTE # If the field has components that are accumulators @@ -306,7 +309,7 @@ def _apply_compressed_accumulation(raw_value, accumulation, num_bits): return base_value - def _parse_data_message(self, header): + def _parse_data_message_components(self, header): def_mesg = self._local_mesgs.get(header.local_mesg_num) if not def_mesg: raise FitParseError('Got data message with invalid local message type %d' % ( @@ -396,17 +399,33 @@ def _parse_data_message(self, header): ) ) - # Apply data processors - for field_data in field_datas: - # Apply type name processor - self._processor.run_type_processor(field_data) - self._processor.run_field_processor(field_data) - self._processor.run_unit_processor(field_data) + return header, def_mesg, field_datas - data_message = DataMessage(header=header, def_mesg=def_mesg, fields=field_datas) - self._processor.run_message_processor(data_message) + def _parse_data_message(self, header): + header, def_mesg, field_datas = self._parse_data_message_components(header) + return DataMessage(header=header, def_mesg=def_mesg, fields=field_datas) - return data_message + @staticmethod + def _should_yield(message, with_definitions, names): + if not message: + return False + if with_definitions or message.type == 'data': + # name arg is None we return all + if names is None: + return True + elif (message.name in names) or (message.mesg_num in names): + return True + return False + + @staticmethod + def _make_set(obj): + if obj is None: + return None + + if is_iterable(obj): + return set(obj) + else: + return set((obj,)) ########## # Public API @@ -415,44 +434,90 @@ def get_messages(self, name=None, with_definitions=False, as_dict=False): if with_definitions: # with_definitions implies as_dict=False as_dict = False - if name is not None: - if is_iterable(name): - names = set(name) - else: - names = set((name,)) - - def should_yield(message): - if with_definitions or message.type == 'data': - # name arg is None we return all - if name is None: - return True - else: - if (message.name in names) or (message.mesg_num in names): - return True - return False + names = self._make_set(name) + + while not self._complete: + message = self._parse_message() + if self._should_yield(message, with_definitions, names): + yield message.as_dict() if as_dict else message + + def __iter__(self): + return self.get_messages() + + +class CacheMixin(object): + """Add message caching to the FitFileDecoder""" + + def __init__(self, *args, **kwargs): + super(CacheMixin, self).__init__(*args, **kwargs) + self._messages = [] + + def _parse_message(self): + self._messages.append(super(CacheMixin, self)._parse_message()) + return self._messages[-1] + + def get_messages(self, name=None, with_definitions=False, as_dict=False): + if with_definitions: # with_definitions implies as_dict=False + as_dict = False + + names = self._make_set(name) # Yield all parsed messages first for message in self._messages: - if should_yield(message): + if self._should_yield(message, with_definitions, names): yield message.as_dict() if as_dict else message - # If there are unparsed messages, yield those too - while not self._complete: - message = self._parse_message() - if message and should_yield(message): - yield message.as_dict() if as_dict else message + for message in super(CacheMixin, self).get_messages(names, with_definitions, as_dict): + yield message @property def messages(self): - # TODO: could this be more efficient? return list(self.get_messages()) def parse(self): while self._parse_message(): pass - def __iter__(self): - return self.get_messages() + +class DataProcessorMixin(object): + """Add data processing to the FitFileDecoder""" + + def __init__(self, *args, **kwargs): + self._processor = kwargs.pop("data_processor", None) or FitFileDataProcessor() + super(DataProcessorMixin, self).__init__(*args, **kwargs) + + def _parse_data_message(self, header): + header, def_mesg, field_datas = self._parse_data_message_components(header) + + # Apply data processors + for field_data in field_datas: + # Apply type name processor + self._processor.run_type_processor(field_data) + self._processor.run_field_processor(field_data) + self._processor.run_unit_processor(field_data) + + data_message = DataMessage(header=header, def_mesg=def_mesg, fields=field_datas) + self._processor.run_message_processor(data_message) + + return data_message + + +class UncachedFitFile(DataProcessorMixin, FitFileDecoder): + """FitFileDecoder with data processing""" + + def __init__(self, fileish, check_crc=True, data_processor=None): + # Ensure all optional params are passed as kwargs + super(UncachedFitFile, self).__init__( + fileish, + check_crc=check_crc, + data_processor=data_processor + ) + + +class FitFile(CacheMixin, UncachedFitFile): + """FitFileDecoder with caching and data processing""" + pass + # TODO: Create subclasses like Activity and do per-value monkey patching diff --git a/scripts/fitdump b/scripts/fitdump index b6043c2..2af0f20 100755 --- a/scripts/fitdump +++ b/scripts/fitdump @@ -96,7 +96,7 @@ class RecordJSONEncoder(json.JSONEncoder): def main(args=None): options = parse_args(args) - fitfile = fitparse.FitFile( + fitfile = fitparse.UncachedFitFile( options.infile, data_processor=fitparse.StandardUnitsDataProcessor(), check_crc=not(options.ignore_crc), diff --git a/tests/test.py b/tests/test.py index a0d2b37..082e9f6 100755 --- a/tests/test.py +++ b/tests/test.py @@ -417,7 +417,7 @@ def test_mismatched_field_size(self): f = FitFile(testfile('coros-pace-2-cycling-misaligned-fields.fit')) with warnings.catch_warnings(record=True) as w: f.parse() - assert len(w) == 5 + assert w assert all("falling back to byte encoding" in str(x) for x in w) self.assertEqual(len(f.messages), 11293) From 0f4e23edbb2039c6c175e1528a3245d76302484d Mon Sep 17 00:00:00 2001 From: Jochen Peters Date: Fri, 26 Jun 2020 15:43:05 +0200 Subject: [PATCH 50/69] Add basic GPX output (#108) Currently only outputs time, position, elevation, and speed. --- scripts/fitdump | 94 +++++++++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 91 insertions(+), 3 deletions(-) diff --git a/scripts/fitdump b/scripts/fitdump index 2af0f20..5e4a4b4 100755 --- a/scripts/fitdump +++ b/scripts/fitdump @@ -4,7 +4,9 @@ from __future__ import print_function import argparse import codecs import datetime +import itertools import json +import os.path import sys import types @@ -47,7 +49,7 @@ def parse_args(args=None): ) parser.add_argument( # TODO: csv - '-t', '--type', choices=('readable', 'json'), default='readable', + '-t', '--type', choices=('readable', 'json', 'gpx'), default='readable', help='File type to output. (DEFAULT: %(default)s)', ) parser.add_argument( @@ -93,6 +95,86 @@ class RecordJSONEncoder(json.JSONEncoder): return super(RecordJSONEncoder, self).default(obj) +def generate_gpx(records, filename=None): + # TODO: Use xml.etree.ElementTree ? + + GPX_TIME_FMT = "%Y-%m-%dT%H:%M:%SZ" # ISO 8601 format + + records = iter(records) + + # header + open tags + yield '\n' + yield '\n' + yield ' \n' + + # file creation time (if a file_id record exists) + first_record = [] + for message in records: + if message.name == "file_id": + for field_data in message: + if field_data.name == "time_created" and type(field_data.value) == datetime.datetime: + yield ' \n'.format(field_data.value.strftime(GPX_TIME_FMT)) + break + else: + # No time found in the fields, check next record + continue + break + elif message.name == "record": + first_record.append(message) + break + + if filename: + yield ' {}\n'.format(filename) + + yield ' \n' + yield ' \n' + + if filename: + yield ' {}\n'.format(filename) + + yield ' \n' + + # track points + for message in itertools.chain(first_record, records): + if message.name != "record": + continue + + trkpt = {} + + # TODO: support more data types (heart rate, cadence, etc) + for field_data in message: + if field_data.name == "position_lat": + # Units are decimal degrees + trkpt["lat"] = field_data.value + elif field_data.name == "position_long": + # Units are decimal degrees + trkpt["lon"] = field_data.value + elif field_data.name == "enhanced_altitude": + # Units are m + trkpt["ele"] = field_data.value + elif field_data.name == "timestamp" and type(field_data.value) == datetime.datetime: + trkpt["time"] = field_data.value.strftime(GPX_TIME_FMT) + elif field_data.name == "enhanced_speed" and type(field_data.value) == float: + # convert from km/h to m/s + trkpt["speed"] = field_data.value / 3.6 + + # Add trackpoint + if "lat" in trkpt and "lon" in trkpt: + yield ' \n'.format(**trkpt) + if "ele" in trkpt: + yield ' {ele}\n'.format(**trkpt) + if "time" in trkpt: + yield ' \n'.format(**trkpt) + if "speed" in trkpt: + yield ' {speed}\n'.format(**trkpt) + yield ' \n' + + # close tags + yield ' \n' + yield ' \n' + yield '\n' + + def main(args=None): options = parse_args(args) @@ -111,8 +193,14 @@ def main(args=None): if options.type == "json": json.dump(records, fp=options.output, cls=RecordJSONEncoder) elif options.type == "readable": - options.output.writelines(format_message(n, record, options) - for n, record in enumerate(records, 1)) + options.output.writelines( + format_message(n, record, options) for n, record in enumerate(records, 1) + ) + elif options.type == "gpx": + filename = getattr(options.infile, "name") + if filename: + filename = os.path.basename(filename) + options.output.writelines(generate_gpx(records, filename)) finally: try: options.output.close() From 78241f3d0dda8cb7a2b29b599b2f519df1a30f9d Mon Sep 17 00:00:00 2001 From: David Cooper Date: Fri, 1 Jan 2021 17:47:06 -0800 Subject: [PATCH 51/69] License bump. Happy New Year! --- LICENSE | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/LICENSE b/LICENSE index 3f8862a..18e253b 100644 --- a/LICENSE +++ b/LICENSE @@ -1,7 +1,7 @@ MIT License -Copyright (c) 2011-2020, David Cooper -Copyright (c) 2017-2020, Carey Metcalfe +Copyright (c) 2011-2021, David Cooper +Copyright (c) 2017-2021, Carey Metcalfe Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal From f9ad9871c5df05af1aee9b0a2aeb2a871aaff559 Mon Sep 17 00:00:00 2001 From: Aart Goossens Date: Tue, 20 Apr 2021 10:13:27 +0200 Subject: [PATCH 52/69] Introduces DeveloperDataMixin to make python-fitparse thread-safe Fixes #125 --- fitparse/base.py | 65 +++++++++++++++++++++++++++++++++++++++------ fitparse/records.py | 46 -------------------------------- tests/test.py | 27 ++++++++++++++++++- 3 files changed, 83 insertions(+), 55 deletions(-) diff --git a/fitparse/base.py b/fitparse/base.py index c57d118..13087db 100644 --- a/fitparse/base.py +++ b/fitparse/base.py @@ -14,17 +14,64 @@ from fitparse.processors import FitFileDataProcessor from fitparse.profile import FIELD_TYPE_TIMESTAMP, MESSAGE_TYPES from fitparse.records import ( - Crc, DataMessage, FieldData, FieldDefinition, DevFieldDefinition, DefinitionMessage, MessageHeader, - BASE_TYPES, BASE_TYPE_BYTE, - add_dev_data_id, add_dev_field_description, get_dev_type + Crc, DevField, DataMessage, FieldData, FieldDefinition, DevFieldDefinition, DefinitionMessage, + MessageHeader, BASE_TYPES, BASE_TYPE_BYTE, ) from fitparse.utils import fileish_open, is_iterable, FitParseError, FitEOFError, FitCRCError, FitHeaderError -class FitFileDecoder(object): +class DeveloperDataMixin(object): + def __init__(self, *args, **kwargs): + self.dev_types = {} + + super(DeveloperDataMixin, self).__init__(*args, **kwargs) + + def add_dev_data_id(self, message): + dev_data_index = message.get_raw_value('developer_data_index') + application_id = message.get_raw_value('application_id') + + # Note that nothing in the spec says overwriting an existing type is invalid + self.dev_types[dev_data_index] = { + 'dev_data_index': dev_data_index, + 'application_id': application_id, + 'fields': {} + } + + def add_dev_field_description(self, message): + dev_data_index = message.get_raw_value('developer_data_index') + field_def_num = message.get_raw_value('field_definition_number') + base_type_id = message.get_raw_value('fit_base_type_id') + field_name = message.get_raw_value('field_name') or "unnamed_dev_field_%s" % field_def_num + units = message.get_raw_value("units") + native_field_num = message.get_raw_value('native_field_num') + + if dev_data_index not in self.dev_types: + raise FitParseError("No such dev_data_index=%s found" % (dev_data_index)) + fields = self.dev_types[int(dev_data_index)]['fields'] + + # Note that nothing in the spec says overwriting an existing field is invalid + fields[field_def_num] = DevField(dev_data_index=dev_data_index, + def_num=field_def_num, + type=BASE_TYPES[base_type_id], + name=field_name, + units=units, + native_field_num=native_field_num) + + + def get_dev_type(self, dev_data_index, field_def_num): + if dev_data_index not in self.dev_types: + raise FitParseError("No such dev_data_index=%s found when looking up field %s" % (dev_data_index, field_def_num)) + + if field_def_num not in self.dev_types[dev_data_index]['fields']: + raise FitParseError("No such field %s for dev_data_index %s" % (field_def_num, dev_data_index)) + + return self.dev_types[dev_data_index]['fields'][field_def_num] + + +class FitFileDecoder(DeveloperDataMixin): """Basic decoder for fit files""" - def __init__(self, fileish, check_crc=True, data_processor=None): + def __init__(self, fileish, *args, check_crc=True, data_processor=None, **kwargs): self._file = fileish_open(fileish, 'rb') self.check_crc = check_crc @@ -38,6 +85,8 @@ def __init__(self, fileish, check_crc=True, data_processor=None): # Start off by parsing the file header (sets initial attribute values) self._parse_file_header() + super(FitFileDecoder, self).__init__(*args, **kwargs) + def __del__(self): self.close() @@ -156,9 +205,9 @@ def _parse_message(self): message = self._parse_data_message(header) if message.mesg_type is not None: if message.mesg_type.name == 'developer_data_id': - add_dev_data_id(message) + self.add_dev_data_id(message) elif message.mesg_type.name == 'field_description': - add_dev_field_description(message) + self.add_dev_field_description(message) return message @@ -221,7 +270,7 @@ def _parse_definition_message(self, header): num_dev_fields = self._read_struct('B', endian=endian) for n in range(num_dev_fields): field_def_num, field_size, dev_data_index = self._read_struct('3B', endian=endian) - field = get_dev_type(dev_data_index, field_def_num) + field = self.get_dev_type(dev_data_index, field_def_num) dev_field_defs.append(DevFieldDefinition( field=field, dev_data_index=dev_data_index, diff --git a/fitparse/records.py b/fitparse/records.py index 77794d4..f9149e4 100644 --- a/fitparse/records.py +++ b/fitparse/records.py @@ -14,11 +14,6 @@ except ImportError: from itertools import izip_longest as zip_longest -from fitparse.utils import FitParseError - - -DEV_TYPES = {} - class RecordBase(object): # namedtuple-like base class. Subclasses should must __slots__ @@ -435,44 +430,3 @@ def parse_string(string): 0x8F: BaseType(name='uint64', identifier=0x8F, fmt='Q', parse=lambda x: None if x == 0xFFFFFFFFFFFFFFFF else x), 0x90: BaseType(name='uint64z', identifier=0x90, fmt='Q', parse=lambda x: None if x == 0 else x), } - - -def add_dev_data_id(message): - global DEV_TYPES - dev_data_index = message.get_raw_value('developer_data_index') - application_id = message.get_raw_value('application_id') - - # Note that nothing in the spec says overwriting an existing type is invalid - DEV_TYPES[dev_data_index] = {'dev_data_index': dev_data_index, 'application_id': application_id, 'fields': {}} - - -def add_dev_field_description(message): - global DEV_TYPES - - dev_data_index = message.get_raw_value('developer_data_index') - field_def_num = message.get_raw_value('field_definition_number') - base_type_id = message.get_raw_value('fit_base_type_id') - field_name = message.get_raw_value('field_name') or "unnamed_dev_field_%s" % field_def_num - units = message.get_raw_value("units") - native_field_num = message.get_raw_value('native_field_num') - - if dev_data_index not in DEV_TYPES: - raise FitParseError("No such dev_data_index=%s found" % (dev_data_index)) - fields = DEV_TYPES[int(dev_data_index)]['fields'] - - # Note that nothing in the spec says overwriting an existing field is invalid - fields[field_def_num] = DevField(dev_data_index=dev_data_index, - def_num=field_def_num, - type=BASE_TYPES[base_type_id], - name=field_name, - units=units, - native_field_num=native_field_num) - - -def get_dev_type(dev_data_index, field_def_num): - if dev_data_index not in DEV_TYPES: - raise FitParseError("No such dev_data_index=%s found when looking up field %s" % (dev_data_index, field_def_num)) - elif field_def_num not in DEV_TYPES[dev_data_index]['fields']: - raise FitParseError("No such field %s for dev_data_index %s" % (field_def_num, dev_data_index)) - - return DEV_TYPES[dev_data_index]['fields'][field_def_num] diff --git a/tests/test.py b/tests/test.py index 082e9f6..eea5dc2 100755 --- a/tests/test.py +++ b/tests/test.py @@ -10,7 +10,7 @@ from fitparse import FitFile from fitparse.processors import UTC_REFERENCE, StandardUnitsDataProcessor from fitparse.records import BASE_TYPES, Crc -from fitparse.utils import FitEOFError, FitCRCError, FitHeaderError +from fitparse.utils import FitEOFError, FitCRCError, FitHeaderError, FitParseError if sys.version_info >= (2, 7): import unittest @@ -426,6 +426,31 @@ def test_unterminated_file(self): with warnings.catch_warnings(record=True) as w: f.parse() + def test_developer_data_thread_safe(self): + """ + Test that a file with developer types in it can be parsed thread-safe. + This test opens 2 FIT files and tests whether the dev_types of one does not change the dev_types of the other. + """ + fit_file_1 = FitFile(testfile('developer-types-sample.fit')) + field_description_count = 0 + for message in fit_file_1.get_messages(): + if message.mesg_type.name == "field_description": + field_description_count += 1 + if field_description_count >= 4: + # Break after final field description message + break + + fit_file_2 = FitFile(testfile('developer-types-sample.fit')) + for message in fit_file_2.get_messages(): + if message.mesg_type.name == "developer_data_id": + break + + try: + fit_file_1.parse() + except FitParseError: + self.fail("parse() unexpectedly raised a FitParseError") + + # TODO: # * Test Processors: # - process_type_<>, process_field_<>, process_units_<>, process_message_<> From 13535bd326ec3cd6bb352a7123509e8d3e43d73f Mon Sep 17 00:00:00 2001 From: David Cooper Date: Mon, 3 May 2021 16:10:55 -0400 Subject: [PATCH 53/69] Update README.md Fixes #127 --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 9841cb5..331c704 100644 --- a/README.md +++ b/README.md @@ -80,7 +80,7 @@ The old version is archived as and internal parts. (Still unstable and partially complete.) * Proper documentation! - [Available here](http://dtcooper.github.com/python-fitparse/). + [Available here](https://dtcooper.github.io/python-fitparse/). * Unit tests and example programs. From 11e7dbbd030c3f5f8c3312e8a60c4a4f5d31338c Mon Sep 17 00:00:00 2001 From: David Cooper Date: Mon, 3 May 2021 16:11:58 -0400 Subject: [PATCH 54/69] Another #127 fix --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 331c704..50c3cad 100644 --- a/README.md +++ b/README.md @@ -66,7 +66,7 @@ optional arguments: --ignore-crc Some devices can write invalid crc's, ignore these. ``` -See the documentation for more: http://dtcooper.github.com/python-fitparse +See the documentation for more: http://dtcooper.github.io/python-fitparse Major Changes From Original Version From af4cf3a8a92bd54694526811c5d8c41bcb2d0cb2 Mon Sep 17 00:00:00 2001 From: Aart Goossens Date: Tue, 20 Apr 2021 11:06:34 +0200 Subject: [PATCH 55/69] Ignore developer data errors by passing check_developer_data=False Fixes #124 --- fitparse/base.py | 96 ++++++++++++++++++++++++++++++++++++++---------- 1 file changed, 77 insertions(+), 19 deletions(-) diff --git a/fitparse/base.py b/fitparse/base.py index 13087db..6af6392 100644 --- a/fitparse/base.py +++ b/fitparse/base.py @@ -21,22 +21,49 @@ class DeveloperDataMixin(object): - def __init__(self, *args, **kwargs): + def __init__(self, *args, check_developer_data=True, **kwargs): + self.check_developer_data = check_developer_data self.dev_types = {} super(DeveloperDataMixin, self).__init__(*args, **kwargs) - def add_dev_data_id(self, message): - dev_data_index = message.get_raw_value('developer_data_index') - application_id = message.get_raw_value('application_id') + def _append_dev_data_id(self, dev_data_index, application_id=None, fields=None): + if fields is None: + fields = {} # Note that nothing in the spec says overwriting an existing type is invalid self.dev_types[dev_data_index] = { 'dev_data_index': dev_data_index, 'application_id': application_id, - 'fields': {} + 'fields': fields } + def add_dev_data_id(self, message): + dev_data_index = message.get_raw_value('developer_data_index') + application_id = message.get_raw_value('application_id') + + self._append_dev_data_id(dev_data_index, application_id) + + def _append_dev_field_description(self, dev_data_index, field_def_num, type=BASE_TYPE_BYTE, name=None, + units=None, native_field_num=None): + if dev_data_index not in self.dev_types: + if self.check_developer_data: + raise FitParseError("No such dev_data_index=%s found" % (dev_data_index)) + + warnings.warn( + "Dev type for dev_data_index=%s missing. Adding dummy dev type." % (dev_data_index) + ) + self._append_dev_data_id(dev_data_index) + + self.dev_types[dev_data_index]["fields"][field_def_num] = DevField( + dev_data_index=dev_data_index, + def_num=field_def_num, + type=type, + name=name, + units=units, + native_field_num=native_field_num + ) + def add_dev_field_description(self, message): dev_data_index = message.get_raw_value('developer_data_index') field_def_num = message.get_raw_value('field_definition_number') @@ -46,26 +73,55 @@ def add_dev_field_description(self, message): native_field_num = message.get_raw_value('native_field_num') if dev_data_index not in self.dev_types: - raise FitParseError("No such dev_data_index=%s found" % (dev_data_index)) + if self.check_developer_data: + raise FitParseError("No such dev_data_index=%s found" % (dev_data_index)) + + warnings.warn( + "Dev type for dev_data_index=%s missing. Adding dummy dev type." % (dev_data_index) + ) + self._append_dev_data_id(dev_data_index) + fields = self.dev_types[int(dev_data_index)]['fields'] # Note that nothing in the spec says overwriting an existing field is invalid - fields[field_def_num] = DevField(dev_data_index=dev_data_index, - def_num=field_def_num, - type=BASE_TYPES[base_type_id], - name=field_name, - units=units, - native_field_num=native_field_num) - + fields[field_def_num] = DevField( + dev_data_index=dev_data_index, + def_num=field_def_num, + type=BASE_TYPES[base_type_id], + name=field_name, + units=units, + native_field_num=native_field_num + ) def get_dev_type(self, dev_data_index, field_def_num): if dev_data_index not in self.dev_types: - raise FitParseError("No such dev_data_index=%s found when looking up field %s" % (dev_data_index, field_def_num)) + if self.check_developer_data: + raise FitParseError( + "No such dev_data_index=%s found when looking up field %s" % (dev_data_index, field_def_num) + ) + + warnings.warn( + "Dev type for dev_data_index=%s missing. Adding dummy dev type." % (dev_data_index) + ) + self._append_dev_data_id(dev_data_index) - if field_def_num not in self.dev_types[dev_data_index]['fields']: - raise FitParseError("No such field %s for dev_data_index %s" % (field_def_num, dev_data_index)) + dev_type = self.dev_types[dev_data_index] - return self.dev_types[dev_data_index]['fields'][field_def_num] + if field_def_num not in dev_type['fields']: + if self.check_developer_data: + raise FitParseError( + "No such field %s for dev_data_index %s" % (field_def_num, dev_data_index) + ) + + warnings.warn( + "Field %s for dev_data_index %s missing. Adding dummy field." % (field_def_num, dev_data_index) + ) + self._append_dev_field_description( + dev_data_index=dev_data_index, + field_def_num=field_def_num + ) + + return dev_type['fields'][field_def_num] class FitFileDecoder(DeveloperDataMixin): @@ -554,12 +610,14 @@ def _parse_data_message(self, header): class UncachedFitFile(DataProcessorMixin, FitFileDecoder): """FitFileDecoder with data processing""" - def __init__(self, fileish, check_crc=True, data_processor=None): + def __init__(self, fileish, *args, check_crc=True, data_processor=None, **kwargs): # Ensure all optional params are passed as kwargs super(UncachedFitFile, self).__init__( fileish, + *args, check_crc=check_crc, - data_processor=data_processor + data_processor=data_processor, + **kwargs ) From fd3bd56da6d0a31dd2fdaa725c2f922a35b6be0b Mon Sep 17 00:00:00 2001 From: David Cooper Date: Fri, 7 Jan 2022 18:02:44 -0500 Subject: [PATCH 56/69] Update LICENSE Happy New Year! --- LICENSE | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/LICENSE b/LICENSE index 18e253b..387b0b0 100644 --- a/LICENSE +++ b/LICENSE @@ -1,7 +1,7 @@ MIT License -Copyright (c) 2011-2021, David Cooper -Copyright (c) 2017-2021, Carey Metcalfe +Copyright (c) 2011-2022, David Cooper +Copyright (c) 2017-2022, Carey Metcalfe Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal From 71fc57b735ded7d19bd40088298fd42980a6edd7 Mon Sep 17 00:00:00 2001 From: Mathias B Date: Sun, 3 Apr 2022 21:54:35 +0200 Subject: [PATCH 57/69] Handle error when parsing field with sleep_time of 86400 (#138) Fixes #132 --- fitparse/processors.py | 15 ++++++++++++--- 1 file changed, 12 insertions(+), 3 deletions(-) diff --git a/fitparse/processors.py b/fitparse/processors.py index 493f166..268859e 100644 --- a/fitparse/processors.py +++ b/fitparse/processors.py @@ -83,9 +83,18 @@ def process_type_local_date_time(self, field_data): def process_type_localtime_into_day(self, field_data): if field_data.value is not None: - m, s = divmod(field_data.value, 60) - h, m = divmod(m, 60) - field_data.value = datetime.time(h, m, s) + # NOTE: Values larger or equal to 86400 should not be possible. + # Additionally, if the value is exactly 86400, it will lead to an error when trying to + # create the time with datetime.time(24, 0 , 0). + # + # E.g. Garmin does add "sleep_time": 86400 to its fit files, + # which causes an error if not properly handled. + if field_data.value >= 86400: + field_data.value = datetime.time.max + else: + m, s = divmod(field_data.value, 60) + h, m = divmod(m, 60) + field_data.value = datetime.time(h, m, s) field_data.units = None From f28f220f8895a586fbc7f9afd62179f144fcfe61 Mon Sep 17 00:00:00 2001 From: Carey Metcalfe Date: Sun, 3 Apr 2022 16:10:51 -0400 Subject: [PATCH 58/69] Remove unsupported Python versions from CI script --- .github/workflows/test.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index a535b93..0d7ee4e 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -11,7 +11,7 @@ jobs: runs-on: ubuntu-latest strategy: matrix: - python-version: ['2.7', '3.3', '3.4', '3.5', '3.6', '3.x', 'pypy2', 'pypy3'] + python-version: ['2.7', '3.5', '3.6', '3.x', 'pypy2', 'pypy3'] steps: - uses: actions/checkout@v2 From 2a99f92bcdd43cd6179eaa9ddf5dab41b9861de2 Mon Sep 17 00:00:00 2001 From: David Cooper Date: Wed, 7 Sep 2022 13:53:18 -0700 Subject: [PATCH 59/69] Update README.md Call for maintiner --- README.md | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/README.md b/README.md index 50c3cad..09c8882 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,16 @@ python-fitparse =============== +> :warning: **NOTE:** *I have **limited to no time** to work on this package +> these days!* +> +> I am looking for a maintainer to help with issues and updating/releasing the package. +> Please reach out via email at if you have interest in helping. +> +> Cheers, +> +> David + Here's a Python library to parse ANT/Garmin `.FIT` files. [![Build Status](https://github.com/dtcooper/python-fitparse/workflows/test/badge.svg)](https://github.com/dtcooper/python-fitparse/actions?query=workflow%3Atest) From 301970f5da492ae23635bf5e3a55b3836785fa9f Mon Sep 17 00:00:00 2001 From: Tom Fryers Date: Mon, 22 Aug 2022 21:12:56 +0100 Subject: [PATCH 60/69] Use pyupgrade --- fitparse/base.py | 30 +++++++++++++++--------------- fitparse/processors.py | 4 ++-- fitparse/profile.py | 1 - fitparse/records.py | 18 +++++++++--------- fitparse/utils.py | 2 +- 5 files changed, 27 insertions(+), 28 deletions(-) diff --git a/fitparse/base.py b/fitparse/base.py index 6af6392..8880a00 100644 --- a/fitparse/base.py +++ b/fitparse/base.py @@ -20,12 +20,12 @@ from fitparse.utils import fileish_open, is_iterable, FitParseError, FitEOFError, FitCRCError, FitHeaderError -class DeveloperDataMixin(object): +class DeveloperDataMixin: def __init__(self, *args, check_developer_data=True, **kwargs): self.check_developer_data = check_developer_data self.dev_types = {} - super(DeveloperDataMixin, self).__init__(*args, **kwargs) + super().__init__(*args, **kwargs) def _append_dev_data_id(self, dev_data_index, application_id=None, fields=None): if fields is None: @@ -97,7 +97,7 @@ def get_dev_type(self, dev_data_index, field_def_num): if dev_data_index not in self.dev_types: if self.check_developer_data: raise FitParseError( - "No such dev_data_index=%s found when looking up field %s" % (dev_data_index, field_def_num) + f"No such dev_data_index={dev_data_index} found when looking up field {field_def_num}" ) warnings.warn( @@ -110,11 +110,11 @@ def get_dev_type(self, dev_data_index, field_def_num): if field_def_num not in dev_type['fields']: if self.check_developer_data: raise FitParseError( - "No such field %s for dev_data_index %s" % (field_def_num, dev_data_index) + f"No such field {field_def_num} for dev_data_index {dev_data_index}" ) warnings.warn( - "Field %s for dev_data_index %s missing. Adding dummy field." % (field_def_num, dev_data_index) + f"Field {field_def_num} for dev_data_index {dev_data_index} missing. Adding dummy field." ) self._append_dev_field_description( dev_data_index=dev_data_index, @@ -141,7 +141,7 @@ def __init__(self, fileish, *args, check_crc=True, data_processor=None, **kwargs # Start off by parsing the file header (sets initial attribute values) self._parse_file_header() - super(FitFileDecoder, self).__init__(*args, **kwargs) + super().__init__(*args, **kwargs) def __del__(self): self.close() @@ -193,7 +193,7 @@ def _read_and_assert_crc(self, allow_zero=False): return if crc_computed == crc_read or (allow_zero and crc_read == 0): return - raise FitCRCError('CRC Mismatch [computed: %s, read: %s]' % ( + raise FitCRCError('CRC Mismatch [computed: {}, read: {}]'.format( Crc.format(crc_computed), Crc.format(crc_read))) ########## @@ -530,7 +530,7 @@ def _make_set(obj): if is_iterable(obj): return set(obj) else: - return set((obj,)) + return {obj} ########## # Public API @@ -550,15 +550,15 @@ def __iter__(self): return self.get_messages() -class CacheMixin(object): +class CacheMixin: """Add message caching to the FitFileDecoder""" def __init__(self, *args, **kwargs): - super(CacheMixin, self).__init__(*args, **kwargs) + super().__init__(*args, **kwargs) self._messages = [] def _parse_message(self): - self._messages.append(super(CacheMixin, self)._parse_message()) + self._messages.append(super()._parse_message()) return self._messages[-1] def get_messages(self, name=None, with_definitions=False, as_dict=False): @@ -572,7 +572,7 @@ def get_messages(self, name=None, with_definitions=False, as_dict=False): if self._should_yield(message, with_definitions, names): yield message.as_dict() if as_dict else message - for message in super(CacheMixin, self).get_messages(names, with_definitions, as_dict): + for message in super().get_messages(names, with_definitions, as_dict): yield message @property @@ -584,12 +584,12 @@ def parse(self): pass -class DataProcessorMixin(object): +class DataProcessorMixin: """Add data processing to the FitFileDecoder""" def __init__(self, *args, **kwargs): self._processor = kwargs.pop("data_processor", None) or FitFileDataProcessor() - super(DataProcessorMixin, self).__init__(*args, **kwargs) + super().__init__(*args, **kwargs) def _parse_data_message(self, header): header, def_mesg, field_datas = self._parse_data_message_components(header) @@ -612,7 +612,7 @@ class UncachedFitFile(DataProcessorMixin, FitFileDecoder): def __init__(self, fileish, *args, check_crc=True, data_processor=None, **kwargs): # Ensure all optional params are passed as kwargs - super(UncachedFitFile, self).__init__( + super().__init__( fileish, *args, check_crc=check_crc, diff --git a/fitparse/processors.py b/fitparse/processors.py index 268859e..6848584 100644 --- a/fitparse/processors.py +++ b/fitparse/processors.py @@ -5,7 +5,7 @@ UTC_REFERENCE = 631065600 # timestamp for UTC 00:00 Dec 31 1989 -class FitFileDataProcessor(object): +class FitFileDataProcessor: # TODO: Document API # Functions that will be called to do the processing: #def run_type_processor(field_data) @@ -107,7 +107,7 @@ def run_field_processor(self, field_data): if field_data.name.endswith("_speed"): self.process_field_speed(field_data) else: - super(StandardUnitsDataProcessor, self).run_field_processor(field_data) + super().run_field_processor(field_data) def process_field_distance(self, field_data): if field_data.value is not None: diff --git a/fitparse/profile.py b/fitparse/profile.py index aa6ddbd..ce44c78 100644 --- a/fitparse/profile.py +++ b/fitparse/profile.py @@ -1,4 +1,3 @@ - # ***************** BEGIN AUTOMATICALLY GENERATED FIT PROFILE ****************** # *************************** DO NOT EDIT THIS FILE **************************** # ************ EXPORTED PROFILE FROM SDK VERSION 20.8 ON 2019-03-05 ************ diff --git a/fitparse/records.py b/fitparse/records.py index f9149e4..857a1dc 100644 --- a/fitparse/records.py +++ b/fitparse/records.py @@ -15,7 +15,7 @@ from itertools import izip_longest as zip_longest -class RecordBase(object): +class RecordBase: # namedtuple-like base class. Subclasses should must __slots__ __slots__ = () @@ -83,7 +83,7 @@ class DevFieldDefinition(RecordBase): __slots__ = ('field', 'dev_data_index', 'base_type', 'def_num', 'size') def __init__(self, **kwargs): - super(DevFieldDefinition, self).__init__(**kwargs) + super().__init__(**kwargs) # For dev fields, the base_type and type are always the same. self.base_type = self.type @@ -129,7 +129,7 @@ def get_value(self, field_name): def get_values(self): # SIMPLIFY: get rid of this completely - return dict((f.name if f.name else f.def_num, f.value) for f in self.fields) + return {f.name if f.name else f.def_num: f.value for f in self.fields} @property def name(self): @@ -159,7 +159,7 @@ def __iter__(self): def __repr__(self): return '' % ( self.name, self.mesg_num, self.header.local_mesg_num, - ', '.join(["%s: %s" % (fd.name, fd.value) for fd in self.fields]), + ', '.join([f"{fd.name}: {fd.value}" for fd in self.fields]), ) def __str__(self): @@ -171,7 +171,7 @@ class FieldData(RecordBase): __slots__ = ('field_def', 'field', 'parent_field', 'value', 'raw_value', 'units') def __init__(self, *args, **kwargs): - super(FieldData, self).__init__(self, *args, **kwargs) + super().__init__(self, *args, **kwargs) if not self.units and self.field: # Default to units on field, otherwise None. # NOTE:Not a property since you may want to override this in a data processor @@ -233,7 +233,7 @@ def __repr__(self): ) def __str__(self): - return '%s: %s%s' % ( + return '{}: {}{}'.format( self.name, self.value, ' [%s]' % self.units if self.units else '', ) @@ -260,7 +260,7 @@ class FieldType(RecordBase): __slots__ = ('name', 'base_type', 'values') def __repr__(self): - return '' % (self.name, self.base_type) + return f'' class MessageType(RecordBase): @@ -342,7 +342,7 @@ def render(self, raw_value): return raw_value -class Crc(object): +class Crc: """FIT file CRC computation.""" CRC_TABLE = ( @@ -358,7 +358,7 @@ def __init__(self, value=0, byte_arr=None): self.update(byte_arr) def __repr__(self): - return '<%s %s>' % (self.__class__.__name__, self.value or "-") + return '<{} {}>'.format(self.__class__.__name__, self.value or "-") def __str__(self): return self.format(self.value) diff --git a/fitparse/utils.py b/fitparse/utils.py index aa70a90..568df0f 100644 --- a/fitparse/utils.py +++ b/fitparse/utils.py @@ -3,7 +3,7 @@ try: from collections.abc import Iterable except ImportError: - from collections import Iterable + from collections.abc import Iterable try: # Python 3.4+ From 06b68d684a338cbffe15b903286bcacee2f27157 Mon Sep 17 00:00:00 2001 From: Tom Fryers Date: Mon, 22 Aug 2022 21:22:17 +0100 Subject: [PATCH 61/69] Remove Python 2 compatibility code --- docs/index.rst | 2 +- fitparse/base.py | 8 +------- fitparse/records.py | 22 ++++------------------ fitparse/utils.py | 25 +++++++------------------ scripts/fitdump | 17 ++--------------- setup.py | 4 ++-- tests/test.py | 6 +----- tests/test_records.py | 8 +------- tests/test_utils.py | 15 +++------------ 9 files changed, 22 insertions(+), 85 deletions(-) diff --git a/docs/index.rst b/docs/index.rst index 434a376..4a4fc30 100644 --- a/docs/index.rst +++ b/docs/index.rst @@ -56,7 +56,7 @@ Requirements The following are required to install :mod:`fitparse`, -* `Python `_ 2.7 and above +* `Python `_ 3.6 and above API Documentation diff --git a/fitparse/base.py b/fitparse/base.py index 8880a00..b0ebf87 100644 --- a/fitparse/base.py +++ b/fitparse/base.py @@ -5,12 +5,6 @@ import struct import warnings -# Python 2 compat -try: - num_types = (int, float, long) -except NameError: - num_types = (int, float) - from fitparse.processors import FitFileDataProcessor from fitparse.profile import FIELD_TYPE_TIMESTAMP, MESSAGE_TYPES from fitparse.records import ( @@ -396,7 +390,7 @@ def _apply_scale_offset(self, field, raw_value): if isinstance(raw_value, tuple): # Contains multiple values, apply transformations to all of them return tuple(self._apply_scale_offset(field, x) for x in raw_value) - elif isinstance(raw_value, num_types): + elif isinstance(raw_value, (int, float)): if field.scale: raw_value = float(raw_value) / field.scale if field.offset: diff --git a/fitparse/records.py b/fitparse/records.py index 857a1dc..7d557fa 100644 --- a/fitparse/records.py +++ b/fitparse/records.py @@ -1,18 +1,7 @@ import math import struct -# Python 2 compat -try: - int_types = (int, long,) - byte_iter = bytearray -except NameError: - int_types = (int,) - byte_iter = lambda x: x - -try: - from itertools import zip_longest -except ImportError: - from itertools import izip_longest as zip_longest +from itertools import zip_longest class RecordBase: @@ -336,7 +325,7 @@ def render(self, raw_value): raw_value = unpacked_num # Mask and shift like a normal number - if isinstance(raw_value, int_types): + if isinstance(raw_value, int): raw_value = (raw_value >> self.bit_offset) & ((1 << self.bits) - 1) return raw_value @@ -376,7 +365,7 @@ def format(value): @classmethod def calculate(cls, byte_arr, crc=0): """Compute CRC for input bytes.""" - for byte in byte_iter(byte_arr): + for byte in byte_arr: # Taken verbatim from FIT SDK docs tmp = cls.CRC_TABLE[crc & 0xF] crc = (crc >> 4) & 0x0FFF @@ -390,10 +379,7 @@ def calculate(cls, byte_arr, crc=0): def parse_string(string): try: - try: - s = string[:string.index(0x00)] - except TypeError: # Python 2 compat - s = string[:string.index('\x00')] + s = string[:string.index('\x00')] except ValueError: # FIT specification defines the 'string' type as follows: "Null # terminated string encoded in UTF-8 format". diff --git a/fitparse/utils.py b/fitparse/utils.py index 568df0f..65f424a 100644 --- a/fitparse/utils.py +++ b/fitparse/utils.py @@ -1,15 +1,8 @@ import io import re -try: - from collections.abc import Iterable -except ImportError: - from collections.abc import Iterable +from collections.abc import Iterable -try: - # Python 3.4+ - from pathlib import PurePath -except ImportError: - PurePath = None +from pathlib import PurePath class FitParseError(ValueError): @@ -56,18 +49,14 @@ def fileish_open(fileish, mode): # BytesIO-like object return fileish elif isinstance(fileish, str): - # Python2 - file path, file contents in the case of a TypeError - # Python3 - file path - try: - return open(fileish, mode) - except TypeError: - return io.BytesIO(fileish) + # file path + return open(fileish, mode) - # Python 3 - pathlib obj - if PurePath and isinstance(fileish, PurePath): + # pathlib obj + if isinstance(fileish, PurePath): return fileish.open(mode) - # Python 3 - file contents + # file contents return io.BytesIO(fileish) diff --git a/scripts/fitdump b/scripts/fitdump index 5e4a4b4..c907972 100755 --- a/scripts/fitdump +++ b/scripts/fitdump @@ -7,16 +7,8 @@ import datetime import itertools import json import os.path -import sys import types -# Python 2 compat -try: - BrokenPipeError -except NameError: - import socket - BrokenPipeError = socket.error - import fitparse @@ -44,7 +36,8 @@ def parse_args(args=None): ) parser.add_argument('-v', '--verbose', action='count', default=0) parser.add_argument( - '-o', '--output', type=argparse.FileType(mode='w'), default="-", + '-o', '--output', type=argparse.FileType(mode='w', encoding="utf-8"), + default="-", help='File to output data into (defaults to stdout)', ) parser.add_argument( @@ -65,12 +58,6 @@ def parse_args(args=None): options = parser.parse_args(args) - # Work around argparse.FileType not accepting an `encoding` kwarg in - # Python < 3.4 by closing and reopening the file (unless it's stdout) - if options.output is not sys.stdout: - options.output.close() - options.output = codecs.open(options.output.name, 'w', encoding='UTF-8') - options.verbose = options.verbose >= 1 options.with_defs = (options.type == "readable" and options.verbose) options.as_dict = (options.type != "readable" and options.verbose) diff --git a/setup.py b/setup.py index 7c8dc13..ad51427 100644 --- a/setup.py +++ b/setup.py @@ -5,8 +5,8 @@ requires = None -if sys.version_info < (2, 7) or (3, 0) <= sys.version_info < (3, 3): - sys.exit("Python 2.7 or Python 3.3+ are required.") +if sys.version_info < (3, 6): + sys.exit("Python 3.6+ is required.") setup( diff --git a/tests/test.py b/tests/test.py index eea5dc2..fd23282 100755 --- a/tests/test.py +++ b/tests/test.py @@ -4,7 +4,6 @@ import datetime import os from struct import pack -import sys import warnings from fitparse import FitFile @@ -12,10 +11,7 @@ from fitparse.records import BASE_TYPES, Crc from fitparse.utils import FitEOFError, FitCRCError, FitHeaderError, FitParseError -if sys.version_info >= (2, 7): - import unittest -else: - import unittest2 as unittest +import unittest def generate_messages(mesg_num, local_mesg_num, field_defs, endian='<', data=None): diff --git a/tests/test_records.py b/tests/test_records.py index 5e3b823..fd401f9 100644 --- a/tests/test_records.py +++ b/tests/test_records.py @@ -1,14 +1,8 @@ #!/usr/bin/env python -import sys - from fitparse.records import Crc -if sys.version_info >= (2, 7): - import unittest -else: - import unittest2 as unittest - +import unittest class RecordsTestCase(unittest.TestCase): def test_crc(self): diff --git a/tests/test_utils.py b/tests/test_utils.py index 01d3409..9d456aa 100644 --- a/tests/test_utils.py +++ b/tests/test_utils.py @@ -2,21 +2,13 @@ import io import os -import sys import tempfile -try: - # Python 3.4+ - from pathlib import Path -except ImportError: - Path = None +from pathlib import Path from fitparse.utils import fileish_open, is_iterable -if sys.version_info >= (2, 7): - import unittest -else: - import unittest2 as unittest +import unittest def testfile(filename): @@ -44,8 +36,7 @@ def test_fopen(fileish): test_fopen(f.read()) with open(testfile("nametest.FIT"), 'rb') as f: test_fopen(io.BytesIO(f.read())) - if Path: - test_fopen(Path(testfile('nametest.FIT'))) + test_fopen(Path(testfile('nametest.FIT'))) def test_fileish_open_write(self): From 90d0aacad1d595f03368cb66ca7435a179672a85 Mon Sep 17 00:00:00 2001 From: Tom Fryers Date: Mon, 22 Aug 2022 22:25:34 +0100 Subject: [PATCH 62/69] Pyupgrade tests scripts and tests --- scripts/fitdump | 19 +++++++++---------- scripts/generate_profile.py | 34 +++++++++++++++++----------------- scripts/unit_tool.py | 2 +- tests/test.py | 8 ++++---- 4 files changed, 31 insertions(+), 32 deletions(-) diff --git a/scripts/fitdump b/scripts/fitdump index c907972..629f61b 100755 --- a/scripts/fitdump +++ b/scripts/fitdump @@ -1,5 +1,4 @@ #!/usr/bin/env python -from __future__ import print_function import argparse import codecs @@ -13,16 +12,16 @@ import fitparse def format_message(num, message, options): - s = ["{}. {}".format(num, message.name)] + s = [f"{num}. {message.name}"] if options.with_defs: - s.append(' [{}]'.format(message.type)) + s.append(f' [{message.type}]') s.append('\n') if message.type == 'data': for field_data in message: - s.append(' * {}: {}'.format(field_data.name, field_data.value)) + s.append(f' * {field_data.name}: {field_data.value}') if field_data.units: - s.append(' [{}]'.format(field_data.units)) + s.append(f' [{field_data.units}]') s.append('\n') s.append('\n') @@ -79,7 +78,7 @@ class RecordJSONEncoder(json.JSONEncoder): } } # Fall back to original to raise a TypeError - return super(RecordJSONEncoder, self).default(obj) + return super().default(obj) def generate_gpx(records, filename=None): @@ -100,7 +99,7 @@ def generate_gpx(records, filename=None): if message.name == "file_id": for field_data in message: if field_data.name == "time_created" and type(field_data.value) == datetime.datetime: - yield ' \n'.format(field_data.value.strftime(GPX_TIME_FMT)) + yield f' \n' break else: # No time found in the fields, check next record @@ -111,13 +110,13 @@ def generate_gpx(records, filename=None): break if filename: - yield ' {}\n'.format(filename) + yield f' {filename}\n' yield ' \n' yield ' \n' if filename: - yield ' {}\n'.format(filename) + yield f' {filename}\n' yield ' \n' @@ -191,7 +190,7 @@ def main(args=None): finally: try: options.output.close() - except IOError: + except OSError: pass if __name__ == '__main__': diff --git a/scripts/generate_profile.py b/scripts/generate_profile.py index c88ab60..5d5a5fb 100755 --- a/scripts/generate_profile.py +++ b/scripts/generate_profile.py @@ -28,14 +28,14 @@ def header(header, indent=0): - return '%s# %s' % (' ' * indent, (' %s ' % header).center(78 - indent, '*')) + return '{}# {}'.format(' ' * indent, (' %s ' % header).center(78 - indent, '*')) def scrub_symbol_name(symbol_name): return SYMBOL_NAME_SCRUBBER.sub('_', symbol_name) -PROFILE_HEADER_FIRST_PART = "%s\n%s" % ( +PROFILE_HEADER_FIRST_PART = "{}\n{}".format( header('BEGIN AUTOMATICALLY GENERATED FIT PROFILE'), header('DO NOT EDIT THIS FILE'), ) @@ -92,7 +92,7 @@ def scrub_symbol_name(symbol_name): def render_type(name): if name in BASE_TYPES: - return "BASE_TYPES[%s], # %s" % (BASE_TYPES[name], name) + return "BASE_TYPES[{}], # {}".format(BASE_TYPES[name], name) else: return "FIELD_TYPES['%s']," % name @@ -121,7 +121,7 @@ def get_mesg_num(self, name): def __str__(self): s = 'FIELD_TYPES = {\n' for type in sorted(self.types, key=lambda x: x.name): - s += " '%s': %s,\n" % (type.name, indent(type)) + s += " '{}': {},\n".format(type.name, indent(type)) s += '}' return s @@ -131,18 +131,18 @@ def get(self, value_name): for value in self.values: if value.name == value_name: return value - raise AssertionError("Invalid value name %s in type %s" % (value_name, self.name)) + raise AssertionError("Invalid value name {} in type {}".format(value_name, self.name)) def __str__(self): s = 'FieldType(%s\n' % render_comment(self.comment) s += " name='%s',\n" % (self.name) - s += " base_type=BASE_TYPES[%s], # %s\n" % ( + s += " base_type=BASE_TYPES[{}], # {}\n".format( BASE_TYPES[self.base_type], self.base_type, ) if self.values: s += " values={\n" for value in sorted(self.values, key=lambda x: x.value if isinstance(x.value, int) else int(x.value, 16)): - s += " %s\n" % (value,) + s += " {}\n".format(value) s += " },\n" s += ")" return s @@ -150,7 +150,7 @@ def __str__(self): class TypeValueInfo(namedtuple('TypeValueInfo', ('name', 'value', 'comment'))): def __str__(self): - return "%s: '%s',%s" % (self.value, self.name, render_comment(self.comment)) + return "{}: '{}',{}".format(self.value, self.name, render_comment(self.comment)) class MessageList(namedtuple('MessageList', ('messages'))): @@ -170,7 +170,7 @@ def __str__(self): s += '\n\n' s += "%s\n" % header(message.group_name, 4) last_group_name = message.group_name - s += " %s: %s,\n" % (message.num, indent(message)) + s += " {}: {},\n".format(message.num, indent(message)) s += '}' return s @@ -188,7 +188,7 @@ def get_field_by_name(self, mesg_name, field_name): if field.name == field_name: return mesg, field - raise ValueError('field "%s" not found in message "%s"' % (field_name, mesg_name)) + raise ValueError('field "{}" not found in message "{}"'.format(field_name, mesg_name)) class MessageInfo(namedtuple('MessageInfo', ('name', 'num', 'group_name', 'fields', 'comment'))): @@ -196,7 +196,7 @@ def get(self, field_name): for field in self.fields: if field.name == field_name: return field - raise AssertionError("Invalid field name %s in message %s" % (field_name, self.name)) + raise AssertionError("Invalid field name {} in message {}".format(field_name, self.name)) def __str__(self): s = "MessageType(%s\n" % render_comment(self.comment) @@ -391,7 +391,7 @@ def parse_types(types_rows): if value.name and value.value is not None: # Don't add ignore keyed types - if "%s:%s" % (type.name, value.name) not in IGNORE_TYPE_VALUES: + if "{}:{}".format(type.name, value.name) not in IGNORE_TYPE_VALUES: type.values.append(value) # Add missing boolean type if it's not there @@ -546,7 +546,7 @@ def get_xls_and_version_from_zip(path): def main(input_xls_or_zip, output_py_path=None): if output_py_path and os.path.exists(output_py_path): - if not open(output_py_path, 'r').read().strip().startswith(PROFILE_HEADER_FIRST_PART): + if not open(output_py_path).read().strip().startswith(PROFILE_HEADER_FIRST_PART): print("Python file doesn't begin with appropriate header. Exiting.") sys.exit(1) @@ -563,7 +563,7 @@ def main(input_xls_or_zip, output_py_path=None): for mesg_name in MESSAGE_NUM_DECLARATIONS: mesg_info = message_list.get_by_name(mesg_name) - mesg_num_declarations.append('MESG_NUM_%s = %s' % ( + mesg_num_declarations.append('MESG_NUM_{} = {}'.format( scrub_symbol_name(mesg_name).upper(), str(mesg_info.num) if mesg_info else 'None')) @@ -573,7 +573,7 @@ def main(input_xls_or_zip, output_py_path=None): mesg_name, field_name = field_fqn.split('.', maxsplit=1) mesg_info, field_info = message_list.get_field_by_name(mesg_name, field_name) - field_decl = 'FIELD_NUM_%s_%s = %s' % ( + field_decl = 'FIELD_NUM_{}_{} = {}'.format( scrub_symbol_name(mesg_name).upper(), scrub_symbol_name(field_name).upper(), str(field_info.num)) @@ -582,7 +582,7 @@ def main(input_xls_or_zip, output_py_path=None): output = '\n'.join([ "\n%s" % PROFILE_HEADER_FIRST_PART, - header('EXPORTED PROFILE FROM %s ON %s' % ( + header('EXPORTED PROFILE FROM {} ON {}'.format( ('SDK VERSION %s' % profile_version) if profile_version else 'SPREADSHEET', datetime.datetime.now().strftime('%Y-%m-%d'), )), @@ -609,7 +609,7 @@ def main(input_xls_or_zip, output_py_path=None): if output_py_path: open(output_py_path, 'w').write(output) - print('Profile version %s written to %s' % ( + print('Profile version {} written to {}'.format( profile_version if profile_version else '', output_py_path)) else: diff --git a/scripts/unit_tool.py b/scripts/unit_tool.py index ee1c876..0f66258 100755 --- a/scripts/unit_tool.py +++ b/scripts/unit_tool.py @@ -54,7 +54,7 @@ def do_fitparse_profile(): if __name__ == '__main__': if len(sys.argv) < 2: - print("Usage: {0} Profile.xls".format(os.path.basename(__file__))) + print(f"Usage: {os.path.basename(__file__)} Profile.xls") sys.exit(0) do_profile_xls() diff --git a/tests/test.py b/tests/test.py index fd23282..886f21f 100755 --- a/tests/test.py +++ b/tests/test.py @@ -35,7 +35,7 @@ def generate_messages(mesg_num, local_mesg_num, field_defs, endian='<', data=Non for mesg_data in data: s = pack('B', local_mesg_num) for value, base_type in zip(mesg_data, base_type_list): - s += pack("%s%s" % (endian, base_type.fmt), value) + s += pack("{}{}".format(endian, base_type.fmt), value) mesgs.append(s) return b''.join(mesgs) @@ -106,7 +106,7 @@ def test_basic_file_big_endian(self): def test_component_field_accumulaters(self): # TODO: abstract CSV parsing - csv_fp = open(testfile('compressed-speed-distance-records.csv'), 'r') + csv_fp = open(testfile('compressed-speed-distance-records.csv')) csv_file = csv.reader(csv_fp) next(csv_file) # Consume header @@ -252,7 +252,7 @@ def test_parsing_edge_820_fit_file(self): 'garmin-edge-820-bike-records.csv') def _csv_test_helper(self, fit_file, csv_file): - csv_fp = open(testfile(csv_file), 'r') + csv_fp = open(testfile(csv_file)) csv_messages = csv.reader(csv_fp) field_names = next(csv_messages) # Consume header @@ -298,7 +298,7 @@ def _csv_test_helper(self, fit_file, csv_file): self.assertAlmostEqual(fit_value, float(csv_value)) else: self.assertEqual(fit_value, csv_value, - msg="For %s, FIT value '%s' did not match CSV value '%s'" % (field_name, fit_value, csv_value)) + msg="For {}, FIT value '{}' did not match CSV value '{}'".format(field_name, fit_value, csv_value)) try: next(messages) From 4372b36cbfbe8661a2cb843a33f5435504ae0bbc Mon Sep 17 00:00:00 2001 From: Tom Fryers Date: Wed, 7 Sep 2022 08:57:31 +0100 Subject: [PATCH 63/69] Fix indexing --- fitparse/records.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/fitparse/records.py b/fitparse/records.py index 7d557fa..e9fcd6a 100644 --- a/fitparse/records.py +++ b/fitparse/records.py @@ -379,7 +379,7 @@ def calculate(cls, byte_arr, crc=0): def parse_string(string): try: - s = string[:string.index('\x00')] + s = string[:string.index(0x00)] except ValueError: # FIT specification defines the 'string' type as follows: "Null # terminated string encoded in UTF-8 format". From c18025756de7d87fe0ea805046fff0637f5254d7 Mon Sep 17 00:00:00 2001 From: David Cooper Date: Wed, 22 Feb 2023 13:55:38 -0500 Subject: [PATCH 64/69] Update README.md Add link to fitdecode in absence of a maintainer --- README.md | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/README.md b/README.md index 09c8882..d526522 100644 --- a/README.md +++ b/README.md @@ -7,6 +7,10 @@ python-fitparse > I am looking for a maintainer to help with issues and updating/releasing the package. > Please reach out via email at if you have interest in helping. > +> If you're having trouble using this package for whatever reason, might we suggest using +> an alternative library: [fitdecode](https://github.com/polyvertex/fitdecode) by +> [polyvertex](https://github.com/polyvertex). +> > Cheers, > > David From 245945113f164a8556e0d087203c725a1e6e6cbe Mon Sep 17 00:00:00 2001 From: Daniel Lenski Date: Wed, 20 Oct 2021 07:43:12 -0700 Subject: [PATCH 65/69] Cleanup Python versions used for GitHub Actions GitHub Actions no longer supports Python versions prior to 3.7, including 2.7. Also, `docs/index.rst` has declared 3.6 to be the minimum supported version since 06b68d684, and python-fitparse has not compiled with Python 2.7 since f9ad9871c5df05af1aee9b0a2aeb2a871aaff559 (which uses Python 3.x-only syntax). --- .github/workflows/test.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index 0d7ee4e..d176d94 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -11,7 +11,7 @@ jobs: runs-on: ubuntu-latest strategy: matrix: - python-version: ['2.7', '3.5', '3.6', '3.x', 'pypy2', 'pypy3'] + python-version: ['3.7', '3.8', '3.9', '3.10', '3.11', '3.x'] steps: - uses: actions/checkout@v2 From 4fc9cd813ea0b6a191c95fa31b194ac65ac129f0 Mon Sep 17 00:00:00 2001 From: Daniel Lenski Date: Thu, 30 Sep 2021 13:50:38 -0700 Subject: [PATCH 66/69] Add strava_product subfield to identify FIT files generated by Strava apps --- fitparse/profile.py | 60 ++++++++++++++++++ .../strava-android-app-201.10-b1218918.fit | Bin 0 -> 78233 bytes 2 files changed, 60 insertions(+) create mode 100644 tests/files/strava-android-app-201.10-b1218918.fit diff --git a/fitparse/profile.py b/fitparse/profile.py index ce44c78..daaf579 100644 --- a/fitparse/profile.py +++ b/fitparse/profile.py @@ -1380,6 +1380,14 @@ 7: 'swiss_ball_dumbbell_flye', }, ), + 'strava_product': FieldType( + name='strava_product', + base_type=BASE_TYPES[0x84], # uint16 + values={ + 101: 'Strava iPhone App', # recent versions of Strava iPhone app + 102: 'Strava Android App', # recent versions of Strava Android app + } + ), 'garmin_product': FieldType( name='garmin_product', base_type=BASE_TYPES[0x84], # uint16 @@ -4009,6 +4017,19 @@ value='dynastream_oem', raw_value=13, ), + ) + ), + SubField( + name='strava_product', + def_num=2, + type=FIELD_TYPES['strava_product'], + ref_fields=( + ReferenceField( + name='manufacturer', + def_num=1, + value='strava', + raw_value=265, + ), ), ), ), @@ -7077,6 +7098,19 @@ ), ), ), + SubField( + name='strava_product', + def_num=4, + type=FIELD_TYPES['strava_product'], + ref_fields=( + ReferenceField( + name='manufacturer', + def_num=2, + value='strava', + raw_value=265, + ), + ), + ), ), ), 5: Field( @@ -8580,6 +8614,19 @@ ), ), ), + SubField( + name='strava_product', + def_num=1, + type=FIELD_TYPES['strava_product'], + ref_fields=( + ReferenceField( + name='manufacturer', + def_num=0, + value='strava', + raw_value=265, + ), + ), + ), ), ), }, @@ -11446,6 +11493,19 @@ ), ), ), + SubField( + name='strava_product', + def_num=1, + type=FIELD_TYPES['strava_product'], + ref_fields=( + ReferenceField( + name='manufacturer', + def_num=0, + value='strava', + raw_value=265, + ), + ), + ), ), ), 2: Field( # Corresponds to file_id of scheduled workout / course. diff --git a/tests/files/strava-android-app-201.10-b1218918.fit b/tests/files/strava-android-app-201.10-b1218918.fit new file mode 100644 index 0000000000000000000000000000000000000000..24977c71663f40c8ec8b2326eed9e1713ba1703a GIT binary patch literal 78233 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 literal 0 HcmV?d00001 From 9bd14c4575d7d549d6ec890748931959542ec904 Mon Sep 17 00:00:00 2001 From: Carey Metcalfe Date: Sun, 14 Jan 2024 09:50:09 -0500 Subject: [PATCH 67/69] Fix typo in api docs (#145) * Fix typo in api docs * Fix test that checked warning output --- docs/api.rst | 2 +- tests/test.py | 7 ++++++- 2 files changed, 7 insertions(+), 2 deletions(-) diff --git a/docs/api.rst b/docs/api.rst index 8d64e0f..e5db642 100644 --- a/docs/api.rst +++ b/docs/api.rst @@ -76,7 +76,7 @@ The ``FitFile`` Object try: fitfile = FitFile('/path.to/fitfile.fit') fitfile.parse() - except FitParseError, e: + except FitParseError as e: print "Error while parsing .FIT file: %s" % e sys.exit(1) diff --git a/tests/test.py b/tests/test.py index 886f21f..77082fb 100755 --- a/tests/test.py +++ b/tests/test.py @@ -74,6 +74,7 @@ def testfile(filename): class FitFileTestCase(unittest.TestCase): + def test_basic_file_with_one_record(self, endian='<'): f = FitFile(generate_fitfile(endian=endian)) f.parse() @@ -414,7 +415,11 @@ def test_mismatched_field_size(self): with warnings.catch_warnings(record=True) as w: f.parse() assert w - assert all("falling back to byte encoding" in str(x) for x in w) + assert all( + "falling back to byte encoding" in str(x) + for x in w + if x.category == UserWarning + ) self.assertEqual(len(f.messages), 11293) def test_unterminated_file(self): From 0ae62ab46856be418922b6e6cc72e16e7debcf96 Mon Sep 17 00:00:00 2001 From: David Cooper Date: Sun, 19 Jan 2025 17:38:37 -0500 Subject: [PATCH 68/69] License bump. Happy New Year! --- LICENSE | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/LICENSE b/LICENSE index 387b0b0..901fe39 100644 --- a/LICENSE +++ b/LICENSE @@ -1,7 +1,7 @@ MIT License -Copyright (c) 2011-2022, David Cooper -Copyright (c) 2017-2022, Carey Metcalfe +Copyright (c) 2011-2025, David Cooper +Copyright (c) 2017-2025, Carey Metcalfe Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal From 142578c9474d190d2c45e55172d99d41d41d8a27 Mon Sep 17 00:00:00 2001 From: roboes Date: Sat, 25 Jan 2025 16:44:46 +0100 Subject: [PATCH 69/69] Update datetime module as datetime.datetime.utcfromtimestamp() is deprecated --- fitparse/processors.py | 4 ++-- tests/test.py | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/fitparse/processors.py b/fitparse/processors.py index 6848584..34b36ba 100644 --- a/fitparse/processors.py +++ b/fitparse/processors.py @@ -70,7 +70,7 @@ def process_type_bool(self, field_data): def process_type_date_time(self, field_data): value = field_data.value if value is not None and value >= 0x10000000: - field_data.value = datetime.datetime.utcfromtimestamp(UTC_REFERENCE + value) + field_data.value = datetime.datetime.fromtimestamp(timestamp=(UTC_REFERENCE + value), tz=datetime.timezone.utc).replace(tzinfo=None) field_data.units = None # Units were 's', set to None def process_type_local_date_time(self, field_data): @@ -78,7 +78,7 @@ def process_type_local_date_time(self, field_data): # NOTE: This value was created on the device using it's local timezone. # Unless we know that timezone, this value won't be correct. However, if we # assume UTC, at least it'll be consistent. - field_data.value = datetime.datetime.utcfromtimestamp(UTC_REFERENCE + field_data.value) + field_data.value = datetime.datetime.fromtimestamp(timestamp=(UTC_REFERENCE + field_data.value), tz=datetime.timezone.utc).replace(tzinfo=None) field_data.units = None def process_type_localtime_into_day(self, field_data): diff --git a/tests/test.py b/tests/test.py index 77082fb..e4851d5 100755 --- a/tests/test.py +++ b/tests/test.py @@ -66,7 +66,7 @@ def generate_fitfile(data=None, endian='<'): def secs_to_dt(secs): - return datetime.datetime.utcfromtimestamp(secs + UTC_REFERENCE) + return datetime.datetime.fromtimestamp(timestamp=(secs + UTC_REFERENCE), tz=datetime.timezone.utc).replace(tzinfo=None) def testfile(filename):