From cd2c3644bbe406f82863fa1a146178e6ad6b5427 Mon Sep 17 00:00:00 2001 From: semuadmin <28569967+semuadmin@users.noreply.github.com> Date: Sun, 5 May 2024 09:53:21 +0100 Subject: [PATCH 1/4] clarify field names --- .vscode/settings.json | 2 +- RELEASE_NOTES.md | 8 ++- pyproject.toml | 2 +- src/pyubx2/_version.py | 2 +- src/pyubx2/ubxhelpers.py | 28 +++++---- src/pyubx2/ubxmessage.py | 121 ++++++++++++++++++++------------------- 6 files changed, 84 insertions(+), 79 deletions(-) diff --git a/.vscode/settings.json b/.vscode/settings.json index 713203b..9452a52 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -4,5 +4,5 @@ "editor.formatOnSave": true, "modulename": "${workspaceFolderBasename}", "distname": "${workspaceFolderBasename}", - "moduleversion": "1.2.39", + "moduleversion": "1.2.40", } \ No newline at end of file diff --git a/RELEASE_NOTES.md b/RELEASE_NOTES.md index 9854961..3d1e324 100644 --- a/RELEASE_NOTES.md +++ b/RELEASE_NOTES.md @@ -1,6 +1,12 @@ # pyubx2 Release Notes -### RELEASE CANDIDATE 1.2.39 +### RELEASE 1.2.40 + +ENHANCEMENTS: + +1. Internal field naming clarified and docstrings updated - no functional changes. + +### RELEASE 1.2.39 FIXES: diff --git a/pyproject.toml b/pyproject.toml index c339906..19d4eac 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -7,7 +7,7 @@ name = "pyubx2" authors = [{ name = "semuadmin", email = "semuadmin@semuconsulting.com" }] maintainers = [{ name = "semuadmin", email = "semuadmin@semuconsulting.com" }] description = "UBX protocol parser and generator" -version = "1.2.39" +version = "1.2.40" license = { file = "LICENSE" } readme = "README.md" requires-python = ">=3.8" diff --git a/src/pyubx2/_version.py b/src/pyubx2/_version.py index 296aaeb..0e83f42 100644 --- a/src/pyubx2/_version.py +++ b/src/pyubx2/_version.py @@ -8,4 +8,4 @@ :license: BSD 3-Clause """ -__version__ = "1.2.39" +__version__ = "1.2.40" diff --git a/src/pyubx2/ubxhelpers.py b/src/pyubx2/ubxhelpers.py index 205c380..6235b30 100644 --- a/src/pyubx2/ubxhelpers.py +++ b/src/pyubx2/ubxhelpers.py @@ -9,8 +9,6 @@ :license: BSD 3-Clause """ -# pylint: disable=invalid-name - import struct from datetime import datetime, timedelta from math import cos, pi, sin, trunc @@ -349,7 +347,7 @@ def nomval(att: str) -> object: return val -def msgclass2bytes(msgClass: int, msgID: int) -> bytes: +def msgclass2bytes(msgclass: int, msgid: int) -> bytes: """ Convert message class/id integers to bytes. @@ -360,12 +358,12 @@ def msgclass2bytes(msgClass: int, msgID: int) -> bytes: """ - msgClass = val2bytes(msgClass, ubt.U1) - msgID = val2bytes(msgID, ubt.U1) - return (msgClass, msgID) + msgclass = val2bytes(msgclass, ubt.U1) + msgid = val2bytes(msgid, ubt.U1) + return (msgclass, msgid) -def msgstr2bytes(msgClass: str, msgID: str) -> bytes: +def msgstr2bytes(msgclass: str, msgid: str) -> bytes: """ Convert plain text UBX message class to bytes. @@ -378,12 +376,12 @@ def msgstr2bytes(msgClass: str, msgID: str) -> bytes: """ try: - clsid = key_from_val(ubt.UBX_CLASSES, msgClass) - msgid = key_from_val(ubt.UBX_MSGIDS, msgID)[1:2] + clsid = key_from_val(ubt.UBX_CLASSES, msgclass) + msgid = key_from_val(ubt.UBX_MSGIDS, msgid)[1:2] return (clsid, msgid) except KeyError as err: raise ube.UBXMessageError( - f"Undefined message, class {msgClass}, id {msgID}" + f"Undefined message, class {msgclass}, id {msgid}" ) from err @@ -406,7 +404,7 @@ def cfgname2key(name: str) -> tuple: ) from err -def cfgkey2name(keyID: int) -> tuple: +def cfgkey2name(keyid: int) -> tuple: """ Return key name and data type for given configuration database hexadecimal key. @@ -422,18 +420,18 @@ def cfgkey2name(keyID: int) -> tuple: val = None for key, val in ubcdb.UBX_CONFIG_DATABASE.items(): (kid, typ) = val - if keyID == kid: + if keyid == kid: return (key, typ) # undocumented configuration database key # type is derived from keyID - key = f"CFG_{hex(keyID)}" - typ = f"X{ubcdb.UBX_CONFIG_STORSIZE[int(hex(keyID)[2:3])]:03d}" + key = f"CFG_{hex(keyid)}" + typ = f"X{ubcdb.UBX_CONFIG_STORSIZE[int(hex(keyid)[2:3])]:03d}" return (key, typ) except KeyError as err: raise ube.UBXMessageError( - f"Invalid configuration database key {hex(keyID)}" + f"Invalid configuration database key {hex(keyid)}" ) from err diff --git a/src/pyubx2/ubxmessage.py b/src/pyubx2/ubxmessage.py index 2c988b6..8674ec4 100644 --- a/src/pyubx2/ubxmessage.py +++ b/src/pyubx2/ubxmessage.py @@ -111,9 +111,9 @@ def _do_attributes(self, **kwargs): else: self._payload = kwargs.get("payload", b"") pdict = self._get_dict(**kwargs) # get appropriate payload dict - for key in pdict: # process each attribute in dict + for anam in pdict: # process each attribute in dict (offset, index) = self._set_attribute( - offset, pdict, key, index, **kwargs + anam, pdict, offset, index, **kwargs ) self._do_len_checksum() @@ -125,7 +125,7 @@ def _do_attributes(self, **kwargs): ) as err: raise ube.UBXTypeError( ( - f"Incorrect type for attribute '{key}' " + f"Incorrect type for attribute '{anam}' " f"in {['GET', 'SET', 'POLL'][self._mode]} message " f"class {self.identity}" ) @@ -133,21 +133,21 @@ def _do_attributes(self, **kwargs): except (OverflowError,) as err: raise ube.UBXTypeError( ( - f"Overflow error for attribute '{key}' " + f"Overflow error for attribute '{anam}' " f"in {['GET', 'SET', 'POLL'][self._mode]} message " f"class {self.identity}" ) ) from err def _set_attribute( - self, offset: int, pdict: dict, key: str, index: list, **kwargs + self, anam: str, pdict: dict, offset: int, index: list, **kwargs ) -> tuple: """ Recursive routine to set individual or grouped payload attributes. - :param int offset: payload offset in bytes + :param str anam: attribute name :param dict pdict: dict representing payload definition - :param str key: attribute keyword + :param int offset: payload offset in bytes :param list index: repeating group index array :param kwargs: optional payload key/value pairs :return: (offset, index[]) @@ -155,36 +155,36 @@ def _set_attribute( """ - att = pdict[key] # get attribute type + adef = pdict[anam] # get attribute definition if isinstance( - att, tuple + adef, tuple ): # repeating group of attributes or subdefined bitfield - numr, _ = att + numr, _ = adef if numr in (ubt.X1, ubt.X2, ubt.X4, ubt.X6, ubt.X8, ubt.X24): # bitfield if self._parsebf: # if we're parsing bitfields (offset, index) = self._set_attribute_bitfield( - att, offset, index, **kwargs + adef, offset, index, **kwargs ) else: # treat bitfield as a single byte array offset = self._set_attribute_single( - numr, offset, key, index, **kwargs + anam, numr, offset, index, **kwargs ) else: # repeating group of attributes (offset, index) = self._set_attribute_group( - att, offset, index, **kwargs + adef, offset, index, **kwargs ) else: # single attribute - offset = self._set_attribute_single(att, offset, key, index, **kwargs) + offset = self._set_attribute_single(anam, adef, offset, index, **kwargs) return (offset, index) def _set_attribute_group( - self, att: tuple, offset: int, index: list, **kwargs + self, adef: tuple, offset: int, index: list, **kwargs ) -> tuple: """ Process (nested) group of attributes. - :param tuple att: attribute group - tuple of (num repeats, attribute dict) + :param tuple adef: attribute definition - tuple of (num repeats, attribute dict) :param int offset: payload offset in bytes :param list index: repeating group index array :param kwargs: optional payload key/value pairs @@ -194,7 +194,7 @@ def _set_attribute_group( """ index.append(0) # add a (nested) group index - numr, attd = att # number of repeats, attribute dictionary + anam, gdict = adef # attribute signifying group size, group dictionary # if CFG-VALGET or CFG-VALSET message, use dedicated method to # parse as configuration key value pairs if self._ubxClass == b"\x06" and ( @@ -204,12 +204,12 @@ def _set_attribute_group( self._set_attribute_cfgval(offset, **kwargs) else: # derive or retrieve number of items in group - if isinstance(numr, int): # fixed number of repeats - rng = numr - elif numr == "None": # number of repeats 'variable by size' - rng = self._calc_num_repeats(attd, self._payload, offset, 0) + if isinstance(anam, int): # fixed number of repeats + gsiz = anam + elif anam == "None": # number of repeats 'variable by size' + gsiz = self._calc_num_repeats(gdict, self._payload, offset, 0) else: # number of repeats is defined in named attribute - rng = getattr(self, numr) + gsiz = getattr(self, anam) # special handling for ESF-MEAS message types if ( self._ubxClass == b"\x10" @@ -217,14 +217,14 @@ def _set_attribute_group( and self._mode == ubt.SET ): if getattr(self, "calibTtagValid", 0): - rng += 1 + gsiz += 1 # recursively process each group attribute, # incrementing the payload offset and index as we go - for i in range(rng): + for i in range(gsiz): index[-1] = i + 1 - for key1 in attd: + for key1 in gdict: (offset, index) = self._set_attribute( - offset, attd, key1, index, **kwargs + key1, gdict, offset, index, **kwargs ) index.pop() # remove this (nested) group index @@ -232,17 +232,17 @@ def _set_attribute_group( return (offset, index) def _set_attribute_single( - self, att: object, offset: int, key: str, index: list, **kwargs + self, anam: str, adef: object, offset: int, index: list, **kwargs ) -> int: """ Set individual attribute value, applying scaling where appropriate. + :param str anam: attribute keyword EITHER - :param str att: attribute type string e.g. 'U002' + :param str adef: attribute definition string e.g. 'U002' OR - :param list att: if scaled, list of [attribute type string, scaling factor float] + :param list adef: if scaled, list of [attribute type string, scaling factor float] :param int offset: payload offset in bytes - :param str key: attribute keyword :param list index: repeating group index array :param kwargs: optional payload key/value pairs :return: offset @@ -252,60 +252,61 @@ def _set_attribute_single( # pylint: disable=no-member # if attribute is scaled - scale = 1 - if isinstance(att, list) and self._scaling: - scale = att[1] - att = att[0] + ares = 1 + if isinstance(adef, list) and self._scaling: + ares = adef[1] # attribute resolution (i.e. scaling factor) + adef = adef[0] # attribute definition # if attribute is part of a (nested) repeating group, suffix name with index - keyr = key + anami = anam for i in index: # one index for each nested level if i > 0: - keyr += f"_{i:02d}" + anami += f"_{i:02d}" # determine attribute size (bytes) - if att == ubt.CH: # variable length string - atts = len(self._payload) + if adef == ubt.CH: # variable length string + asiz = len(self._payload) else: - atts = attsiz(att) + asiz = attsiz(adef) # if payload keyword has been provided, # use the appropriate offset of the payload if "payload" in kwargs: - valb = self._payload[offset : offset + atts] - if scale == 1: - val = bytes2val(valb, att) + valb = self._payload[offset : offset + asiz] + if ares == 1: + val = bytes2val(valb, adef) else: - val = round(bytes2val(valb, att) * scale, ubt.SCALROUND) + val = round(bytes2val(valb, adef) * ares, ubt.SCALROUND) else: # if individual keyword has been provided, # set to provided value, else set to # nominal value - val = kwargs.get(keyr, nomval(att)) - if scale == 1: - valb = val2bytes(val, att) + val = kwargs.get(anami, nomval(adef)) + if ares == 1: + valb = val2bytes(val, adef) else: - valb = val2bytes(int(val / scale), att) + valb = val2bytes(int(val / ares), adef) self._payload += valb - if keyr[0:3] == "_HP": # high precision component of earlier attribute + if anami[0:3] == "_HP": # high precision component of earlier attribute # add standard and high precision values in a single attribute - setattr(self, keyr[3:], round(getattr(self, keyr[3:]) + val, ubt.SCALROUND)) + setattr( + self, anami[3:], round(getattr(self, anami[3:]) + val, ubt.SCALROUND) + ) else: - setattr(self, keyr, val) - offset += atts + setattr(self, anami, val) + offset += asiz return offset def _set_attribute_bitfield( - self, att: str, offset: int, index: list, **kwargs + self, atyp: str, offset: int, index: list, **kwargs ) -> tuple: """ Parse bitfield attribute (type 'X'). - :param str att: attribute type e.g. 'X002' + :param str atyp: attribute type e.g. 'X002' :param int offset: payload offset in bytes - :param str key: attribute key name :param list index: repeating group index array :param kwargs: optional payload key/value pairs :return: (offset, index[]) @@ -314,27 +315,27 @@ def _set_attribute_bitfield( """ # pylint: disable=no-member - bft, bfd = att # type of bitfield, bitfield dictionary - bfs = attsiz(bft) # size of bitfield in bytes + btyp, bdict = atyp # type of bitfield, bitfield dictionary + bsiz = attsiz(btyp) # size of bitfield in bytes bfoffset = 0 # if payload keyword has been provided, # use the appropriate offset of the payload if "payload" in kwargs: - bitfield = int.from_bytes(self._payload[offset : offset + bfs], "little") + bitfield = int.from_bytes(self._payload[offset : offset + bsiz], "little") else: bitfield = 0 # process each flag in bitfield - for key, keyt in bfd.items(): + for key, keyt in bdict.items(): (bitfield, bfoffset) = self._set_attribute_bits( bitfield, bfoffset, key, keyt, index, **kwargs ) # update payload - offset += bfs + offset += bsiz if "payload" not in kwargs: - self._payload += bitfield.to_bytes(bfs, "little") + self._payload += bitfield.to_bytes(bsiz, "little") return (offset, index) From b5c6b6b4fe534246d1351f64c1fa7aeb21a481b3 Mon Sep 17 00:00:00 2001 From: semuadmin <28569967+semuadmin@users.noreply.github.com> Date: Tue, 7 May 2024 09:50:43 +0100 Subject: [PATCH 2/4] update readme --- README.md | 32 ++++++++++++++++---------------- 1 file changed, 16 insertions(+), 16 deletions(-) diff --git a/README.md b/README.md index cd0f293..c4189b1 100644 --- a/README.md +++ b/README.md @@ -118,30 +118,30 @@ Example - Serial input. This example will output both UBX and NMEA messages: ```python from serial import Serial from pyubx2 import UBXReader -stream = Serial('/dev/tty.usbmodem14101', 9600, timeout=3) -ubr = UBXReader(stream) -(raw_data, parsed_data) = ubr.read() -print(parsed_data) +with Serial('/dev/tty.usbmodem14101', 9600, timeout=3) as stream: + ubr = UBXReader(stream) + raw_data, parsed_data = ubr.read() + print(parsed_data) ``` Example - File input (using iterator). This will only output UBX data: ```python from pyubx2 import UBXReader -stream = open('ubxdata.bin', 'rb') -ubr = UBXReader(stream, protfilter=2) -for (raw_data, parsed_data) in ubr: - print(parsed_data) +with open('ubxdata.bin', 'rb') as stream: + ubr = UBXReader(stream, protfilter=2) + for (raw_data, parsed_data) in ubr: + print(parsed_data) ``` Example - Socket input (using iterator). This will output UBX, NMEA and RTCM3 data: ```python import socket from pyubx2 import UBXReader -stream = socket.socket(socket.AF_INET, socket.SOCK_STREAM): -stream.connect(("localhost", 50007)) -ubr = UBXReader(stream, protfilter=7) -for (raw_data, parsed_data) in ubr: - print(parsed_data) +with socket.socket(socket.AF_INET, socket.SOCK_STREAM) as stream: + stream.connect(("localhost", 50007)) + ubr = UBXReader(stream, protfilter=7) + for (raw_data, parsed_data) in ubr: + print(parsed_data) ``` --- @@ -201,11 +201,11 @@ The `payload` attribute always contains the raw payload as bytes. Attributes wit **Tip:** To iterate through a repeating group of attributes (*e.g. svid*), the following construct can be used: ```python -svids = [] # list of svid values from repeating group +vals = [] # list of svid values from repeating group for i in range(msg.numSV): # numSV = size of repeating group svid = getattr(msg, f"svid_{i+1:02d}") - svids.append(svid) -print(svids) + vals.append(svid) +print(vals) ``` If the input message class / id is unrecognised (i.e. not publicly documented by u-blox), `pyubx2` will parse the message to a nominal payload definition and append the term 'NOMINAL' to the message identity. From 04343cf5674e0290ef65b2fcd91c532c534c8a58 Mon Sep 17 00:00:00 2001 From: semuadmin <28569967+semuadmin@users.noreply.github.com> Date: Tue, 7 May 2024 10:21:09 +0100 Subject: [PATCH 3/4] update readme --- README.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index c4189b1..a3cb78b 100644 --- a/README.md +++ b/README.md @@ -129,7 +129,7 @@ Example - File input (using iterator). This will only output UBX data: from pyubx2 import UBXReader with open('ubxdata.bin', 'rb') as stream: ubr = UBXReader(stream, protfilter=2) - for (raw_data, parsed_data) in ubr: + for raw_data, parsed_data in ubr: print(parsed_data) ``` @@ -140,7 +140,7 @@ from pyubx2 import UBXReader with socket.socket(socket.AF_INET, socket.SOCK_STREAM) as stream: stream.connect(("localhost", 50007)) ubr = UBXReader(stream, protfilter=7) - for (raw_data, parsed_data) in ubr: + for raw_data, parsed_data in ubr: print(parsed_data) ``` From 4cdad38f91dbac9cb60df1d657667e8a41c7542f Mon Sep 17 00:00:00 2001 From: semuadmin <28569967+semuadmin@users.noreply.github.com> Date: Wed, 8 May 2024 08:09:18 +0100 Subject: [PATCH 4/4] update min pyrtcm ver to 1.0.20 --- pyproject.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pyproject.toml b/pyproject.toml index 19d4eac..2995838 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -33,7 +33,7 @@ classifiers = [ "Topic :: Scientific/Engineering :: GIS", ] -dependencies = ["pynmeagps >= 1.0.35", "pyrtcm >= 1.0.19"] +dependencies = ["pynmeagps >= 1.0.35", "pyrtcm >= 1.0.20"] [project.urls] homepage = "https://www.semuconsulting.com/pyubx2/"