diff --git a/.gitignore b/.gitignore index d2d6f36..97e7d5a 100644 --- a/.gitignore +++ b/.gitignore @@ -33,3 +33,6 @@ nosetests.xml .mr.developer.cfg .project .pydevproject + +# Pycharm backup files +*~ diff --git a/README.md b/README.md index 16ca26c..71ee8ad 100644 --- a/README.md +++ b/README.md @@ -8,7 +8,7 @@ The `pynmea2` homepage is located at ## Compatibility -`pynmea2` is compatable with Python 2.7 and Python 3.4+ +`pynmea2` is compatible with Python 2.7 and Python 3.4+ ![Python version](https://img.shields.io/pypi/pyversions/pynmea2.svg?style=flat) [![Build status](https://github.com/Knio/pynmea2/actions/workflows/ci.yml/badge.svg?branch=master)](https://github.com/Knio/pynmea2/actions/workflows/ci.yml?query=branch%3Amaster+) diff --git a/examples/read_file.py b/examples/read_file.py index ebd46ea..265ff71 100644 --- a/examples/read_file.py +++ b/examples/read_file.py @@ -1,6 +1,6 @@ import pynmea2 -file = open('examples/data.log', encoding='utf-8') +file = open('data.log', encoding='utf-8') # Replaced example/data.log with data.log for line in file.readlines(): try: diff --git a/pynmea2/nmea.py b/pynmea2/nmea.py index a7c13d0..e72fbef 100644 --- a/pynmea2/nmea.py +++ b/pynmea2/nmea.py @@ -118,6 +118,14 @@ def parse(line, check=False): raise ChecksumError( 'strict checking requested but checksum missing', data) + + # For PQTM messages, extract the manufacturer (always "QTM") and subtype from concatenated type + if sentence_type.startswith("PQTM") and len(sentence_type) > 4: + manufacturer = "QTM" + sentence_type = sentence_type[4:] # Extract "SAVEPAR" part + data.insert(0, sentence_type) # Add sentence_type to data for class handling + manufacturer += sentence_type # Create full type for lookup + talker_match = NMEASentence.talker_re.match(sentence_type) if talker_match: talker = talker_match.group('talker') @@ -242,4 +250,4 @@ def __init__(self, manufacturer, data): self.data = list(data) def identifier(self): - return 'P%s' % (self.manufacturer) + return 'P%s' % self.manufacturer \ No newline at end of file diff --git a/pynmea2/types/__pycache__/talker.cpython-313.pyc.2311789097392 b/pynmea2/types/__pycache__/talker.cpython-313.pyc.2311789097392 new file mode 100644 index 0000000..82f738b Binary files /dev/null and b/pynmea2/types/__pycache__/talker.cpython-313.pyc.2311789097392 differ diff --git a/pynmea2/types/__pycache__/talker.cpython-313.pyc.2509003370928 b/pynmea2/types/__pycache__/talker.cpython-313.pyc.2509003370928 new file mode 100644 index 0000000..82f738b Binary files /dev/null and b/pynmea2/types/__pycache__/talker.cpython-313.pyc.2509003370928 differ diff --git a/pynmea2/types/__pycache__/talker.cpython-313.pyc.2953379525040 b/pynmea2/types/__pycache__/talker.cpython-313.pyc.2953379525040 new file mode 100644 index 0000000..82f738b Binary files /dev/null and b/pynmea2/types/__pycache__/talker.cpython-313.pyc.2953379525040 differ diff --git a/pynmea2/types/proprietary/__init__.py b/pynmea2/types/proprietary/__init__.py index 83aff16..0bf2c25 100644 --- a/pynmea2/types/proprietary/__init__.py +++ b/pynmea2/types/proprietary/__init__.py @@ -10,4 +10,5 @@ from . import ubx from . import vtx from . import nor +from . import qtm diff --git a/pynmea2/types/proprietary/__pycache__/__init__.cpython-313.pyc.2311788933552 b/pynmea2/types/proprietary/__pycache__/__init__.cpython-313.pyc.2311788933552 new file mode 100644 index 0000000..1e39332 Binary files /dev/null and b/pynmea2/types/proprietary/__pycache__/__init__.cpython-313.pyc.2311788933552 differ diff --git a/pynmea2/types/proprietary/__pycache__/__init__.cpython-313.pyc.2509003206944 b/pynmea2/types/proprietary/__pycache__/__init__.cpython-313.pyc.2509003206944 new file mode 100644 index 0000000..1e39332 Binary files /dev/null and b/pynmea2/types/proprietary/__pycache__/__init__.cpython-313.pyc.2509003206944 differ diff --git a/pynmea2/types/proprietary/__pycache__/__init__.cpython-313.pyc.2953377817360 b/pynmea2/types/proprietary/__pycache__/__init__.cpython-313.pyc.2953377817360 new file mode 100644 index 0000000..1e39332 Binary files /dev/null and b/pynmea2/types/proprietary/__pycache__/__init__.cpython-313.pyc.2953377817360 differ diff --git a/pynmea2/types/proprietary/__pycache__/ash.cpython-313.pyc.2953379361200 b/pynmea2/types/proprietary/__pycache__/ash.cpython-313.pyc.2953379361200 new file mode 100644 index 0000000..b3b6564 Binary files /dev/null and b/pynmea2/types/proprietary/__pycache__/ash.cpython-313.pyc.2953379361200 differ diff --git a/pynmea2/types/proprietary/__pycache__/fec.cpython-313.pyc.2311788929952 b/pynmea2/types/proprietary/__pycache__/fec.cpython-313.pyc.2311788929952 new file mode 100644 index 0000000..44a66db Binary files /dev/null and b/pynmea2/types/proprietary/__pycache__/fec.cpython-313.pyc.2311788929952 differ diff --git a/pynmea2/types/proprietary/__pycache__/fec.cpython-313.pyc.2509003206656 b/pynmea2/types/proprietary/__pycache__/fec.cpython-313.pyc.2509003206656 new file mode 100644 index 0000000..44a66db Binary files /dev/null and b/pynmea2/types/proprietary/__pycache__/fec.cpython-313.pyc.2509003206656 differ diff --git a/pynmea2/types/proprietary/__pycache__/fec.cpython-313.pyc.2953379357600 b/pynmea2/types/proprietary/__pycache__/fec.cpython-313.pyc.2953379357600 new file mode 100644 index 0000000..44a66db Binary files /dev/null and b/pynmea2/types/proprietary/__pycache__/fec.cpython-313.pyc.2953379357600 differ diff --git a/pynmea2/types/proprietary/__pycache__/grm.cpython-313.pyc.2953379357168 b/pynmea2/types/proprietary/__pycache__/grm.cpython-313.pyc.2953379357168 new file mode 100644 index 0000000..6892d0e Binary files /dev/null and b/pynmea2/types/proprietary/__pycache__/grm.cpython-313.pyc.2953379357168 differ diff --git a/pynmea2/types/proprietary/__pycache__/kwd.cpython-313.pyc.2311788928944 b/pynmea2/types/proprietary/__pycache__/kwd.cpython-313.pyc.2311788928944 new file mode 100644 index 0000000..1e87881 Binary files /dev/null and b/pynmea2/types/proprietary/__pycache__/kwd.cpython-313.pyc.2311788928944 differ diff --git a/pynmea2/types/proprietary/__pycache__/kwd.cpython-313.pyc.2509003206224 b/pynmea2/types/proprietary/__pycache__/kwd.cpython-313.pyc.2509003206224 new file mode 100644 index 0000000..1e87881 Binary files /dev/null and b/pynmea2/types/proprietary/__pycache__/kwd.cpython-313.pyc.2509003206224 differ diff --git a/pynmea2/types/proprietary/__pycache__/kwd.cpython-313.pyc.2953379356592 b/pynmea2/types/proprietary/__pycache__/kwd.cpython-313.pyc.2953379356592 new file mode 100644 index 0000000..1e87881 Binary files /dev/null and b/pynmea2/types/proprietary/__pycache__/kwd.cpython-313.pyc.2953379356592 differ diff --git a/pynmea2/types/proprietary/__pycache__/mgn.cpython-313.pyc.2953379359040 b/pynmea2/types/proprietary/__pycache__/mgn.cpython-313.pyc.2953379359040 new file mode 100644 index 0000000..fb5f014 Binary files /dev/null and b/pynmea2/types/proprietary/__pycache__/mgn.cpython-313.pyc.2953379359040 differ diff --git a/pynmea2/types/proprietary/__pycache__/nor.cpython-313.pyc.2311788933264 b/pynmea2/types/proprietary/__pycache__/nor.cpython-313.pyc.2311788933264 new file mode 100644 index 0000000..12d2848 Binary files /dev/null and b/pynmea2/types/proprietary/__pycache__/nor.cpython-313.pyc.2311788933264 differ diff --git a/pynmea2/types/proprietary/__pycache__/nor.cpython-313.pyc.2509003204640 b/pynmea2/types/proprietary/__pycache__/nor.cpython-313.pyc.2509003204640 new file mode 100644 index 0000000..12d2848 Binary files /dev/null and b/pynmea2/types/proprietary/__pycache__/nor.cpython-313.pyc.2509003204640 differ diff --git a/pynmea2/types/proprietary/__pycache__/nor.cpython-313.pyc.2953379357168 b/pynmea2/types/proprietary/__pycache__/nor.cpython-313.pyc.2953379357168 new file mode 100644 index 0000000..12d2848 Binary files /dev/null and b/pynmea2/types/proprietary/__pycache__/nor.cpython-313.pyc.2953379357168 differ diff --git a/pynmea2/types/proprietary/__pycache__/qtm.cpython-313.pyc.2311788926784 b/pynmea2/types/proprietary/__pycache__/qtm.cpython-313.pyc.2311788926784 new file mode 100644 index 0000000..c015c9f Binary files /dev/null and b/pynmea2/types/proprietary/__pycache__/qtm.cpython-313.pyc.2311788926784 differ diff --git a/pynmea2/types/proprietary/__pycache__/qtm.cpython-313.pyc.2509003200896 b/pynmea2/types/proprietary/__pycache__/qtm.cpython-313.pyc.2509003200896 new file mode 100644 index 0000000..c015c9f Binary files /dev/null and b/pynmea2/types/proprietary/__pycache__/qtm.cpython-313.pyc.2509003200896 differ diff --git a/pynmea2/types/proprietary/__pycache__/qtm.cpython-313.pyc.2953379351408 b/pynmea2/types/proprietary/__pycache__/qtm.cpython-313.pyc.2953379351408 new file mode 100644 index 0000000..c015c9f Binary files /dev/null and b/pynmea2/types/proprietary/__pycache__/qtm.cpython-313.pyc.2953379351408 differ diff --git a/pynmea2/types/proprietary/__pycache__/srf.cpython-313.pyc.2953379358896 b/pynmea2/types/proprietary/__pycache__/srf.cpython-313.pyc.2953379358896 new file mode 100644 index 0000000..a7e8f55 Binary files /dev/null and b/pynmea2/types/proprietary/__pycache__/srf.cpython-313.pyc.2953379358896 differ diff --git a/pynmea2/types/proprietary/__pycache__/sxn.cpython-313.pyc.2311788930528 b/pynmea2/types/proprietary/__pycache__/sxn.cpython-313.pyc.2311788930528 new file mode 100644 index 0000000..b6950b9 Binary files /dev/null and b/pynmea2/types/proprietary/__pycache__/sxn.cpython-313.pyc.2311788930528 differ diff --git a/pynmea2/types/proprietary/__pycache__/sxn.cpython-313.pyc.2509003204496 b/pynmea2/types/proprietary/__pycache__/sxn.cpython-313.pyc.2509003204496 new file mode 100644 index 0000000..b6950b9 Binary files /dev/null and b/pynmea2/types/proprietary/__pycache__/sxn.cpython-313.pyc.2509003204496 differ diff --git a/pynmea2/types/proprietary/__pycache__/sxn.cpython-313.pyc.2953379358032 b/pynmea2/types/proprietary/__pycache__/sxn.cpython-313.pyc.2953379358032 new file mode 100644 index 0000000..b6950b9 Binary files /dev/null and b/pynmea2/types/proprietary/__pycache__/sxn.cpython-313.pyc.2953379358032 differ diff --git a/pynmea2/types/proprietary/__pycache__/tnl.cpython-313.pyc.2953379357456 b/pynmea2/types/proprietary/__pycache__/tnl.cpython-313.pyc.2953379357456 new file mode 100644 index 0000000..4538fe3 Binary files /dev/null and b/pynmea2/types/proprietary/__pycache__/tnl.cpython-313.pyc.2953379357456 differ diff --git a/pynmea2/types/proprietary/qtm.py b/pynmea2/types/proprietary/qtm.py new file mode 100644 index 0000000..e943d13 --- /dev/null +++ b/pynmea2/types/proprietary/qtm.py @@ -0,0 +1,1618 @@ +from ... import nmea + +class QTM(nmea.ProprietarySentence): + sentence_types = {} + + def __new__(_cls, manufacturer, data): + # Dynamically derive the message class name + name = manufacturer + data[0] # Use first data element as part of the name + cls = _cls.sentence_types.get(name, _cls) + return super(QTM, cls).__new__(cls) + +class QTMVERNO(QTM): + """ + PQTMVERNO Message + + Supports: + - $PQTMVERNO,,,* + """ + fields = ( + ('sentence_type', 'sentence_type'), # VERNO + ('version', 'version'), # Example: LC29HAANR01A04S + ('build_date', 'build_date'), # Format: YYYY/MM/DD + ('build_time', 'build_time'), # Format: HH:MM:SS + ) + + def __init__(self, manufacturer, data): + super(QTMVERNO, self).__init__(manufacturer, data) + # print(data) # Debugging print to confirm input structure + + # Assign attributes using the shared utils for formatting + self.sentence_type = data[0] + self.version = data[1] + self.date = data[2] # Use the new date parser + self.build_time = data[3] # Use the shared timestamp function + + # def __repr__(self): + # # Improved __repr__ for better readability + # return ("").format( + # sentence_type=self.sentence_type, + # version=self.version, + # build_date=self.build_date, + # build_time=self.build_time + # ) + +class QTMSAVEPAR(QTM): + """ + PQTM SAVEPAR Message + + Supports: + - $PQTMSAVEPAR,OK*72 + """ + fields = ( + ('sentence_type', 'sentence_type'), + ('status', 'status') + ) + + def __init__(self, manufacturer, data): + super(QTMSAVEPAR, self).__init__(manufacturer, data) + self.status = data[1] # Handle status field + +class QTMRESTOREPAR(QTM): + """ + PQTM RESTOREPAR Message + + Supports: + - $PQTMRESTOREPAR,OK*3B + """ + fields = ( + ('sentence_type', 'sentence_type'), + ('status', 'status') + ) + + def __init__(self, manufacturer, data): + super(QTMRESTOREPAR, self).__init__(manufacturer, data) + self.status = data[1] # Handle status field + +class QTMEPE(QTM): + """ + PQTMEPE Message + + Outputs the estimated positioning error. + + Supports: + - $PQTMEPE,,,,,,* + """ + + fields = ( + ('sentence_type', 'sentence_type'), # EPE + ('msg_ver', 'msg_ver'), # Message version (always 2) + ('epe_north', 'epe_north'), # Estimated north error (in meters) + ('epe_east', 'epe_east'), # Estimated east error (in meters) + ('epe_down', 'epe_down'), # Estimated down error (in meters) + ('epe_2d', 'epe_2d'), # Estimated 2D position error (in meters) + ('epe_3d', 'epe_3d'), # Estimated 3D position error (in meters) + ) + + def __init__(self, manufacturer, data): + super(QTMEPE, self).__init__(manufacturer, data) + # print(data) # Debugging print to confirm input structure + + # Set attributes based on input data + self.sentence_type = data[0] + self.msg_ver = int(data[1]) + self.epe_north = float(data[2]) + self.epe_east = float(data[3]) + self.epe_down = float(data[4]) + self.epe_2d = float(data[5]) + self.epe_3d = float(data[6]) + +class QTMCFGGEOFENCE(QTM): + """ + PQTMCFGGEOFENCE Message + + Supports: + - $PQTMCFGGEOFENCE,OK,,,,,,,, + [,,,,]* + """ + + fields = ( + ('sentence_type', 'sentence_type'), # Always "CFGGEOGENCE" + ('Status', 'status'), # "OK" + ('Index', 'index'), # Geofence index (0-3) + ('Enabled', 'enabled'), # 0 = Disabled, 1 = Enabled + ('Reserved', 'reserved'), # Always 0 + ('Shape', 'shape'), # Geofence shape (0-3) + ('Lat0', 'lat0'), # Latitude of the first point + ('Lon0', 'lon0'), # Longitude of the first point + ('Lat1_or_Radius', 'lat1_or_radius'), # Latitude/Radius based on shape + ('Lon1', 'lon1'), # Longitude of the second point (optional) + ('Lat2', 'lat2'), # Latitude of the third point (optional) + ('Lon2', 'lon2'), # Longitude of the third point (optional) + ('Lat3', 'lat3'), # Latitude of the fourth point (optional) + ('Lon3', 'lon3') # Longitude of the fourth point (optional) + ) + + def __init__(self, manufacturer, data): + super(QTMCFGGEOFENCE, self).__init__(manufacturer, data) + # print(data) # Debugging print to confirm input structure + + # Extract and assign the mandatory fields + self.sentence_type = data[0] # Should always be "CFGGEOGENCE" + self.status = data[1] # Should be "OK" + self.index = data[2] + self.enabled = data[3] # 0 = Disabled, 1 = Enabled + self.reserved = data[4] + self.shape = data[5] + self.lat0 = data[6] + self.lon0 = data[7] + self.lat1_or_radius = data[8] + + # Optional fields (only for specific shapes) + if len(data) > 9: + self.lon1 = data[9] + if len(data) > 10: + self.lat2 = data[10] + if len(data) > 11: + self.lon2 = data[11] + if len(data) > 12: + self.lat3 = data[12] + if len(data) > 13: + self.lon3 = data[13] + +class QTMGEOFENCESTATUS(QTM): + """ + PQTMGEOFENCESTATUS Message + + Supports: + - $PQTMGEOFENCESTATUS,,