diff --git a/RELEASE_NOTES.md b/RELEASE_NOTES.md index 49256f49..1917b699 100644 --- a/RELEASE_NOTES.md +++ b/RELEASE_NOTES.md @@ -1,5 +1,13 @@ # PyGPSClient Release Notes +### RELEASE 1.6.10 + +1. Minor enhancements to UBX Config Dialog confirmation signalling. +1. Amend CFG-VALSET/GET/DEL Configuration Interface panel; X-type attributes (`X004`, `X008`, etc.) are now entered in +conventional hexadecimal integer notation rather than little-endian hex strings, consistent with values illustrated in the Interface +Specifications e.g. value for CFG_SBAS_PRNSCANMASK (`X008`) would now be entered `0x000000000003ab88` rather than `88ab030000000000`. +1. Make 'Check for update on startup' 'opt-in' rather than 'opt-out'. Setting available via About dialog. + ### RELEASE 1.6.9 1. Add manually-editable `resizeable_dialog_b` configuration setting as a workaround for screen scaling issues on some platforms (e.g. Ubuntu Wayland). Fixes #250. diff --git a/pyproject.toml b/pyproject.toml index 95b01984..488f567e 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -55,6 +55,7 @@ dependencies = [ "pygnssutils>=1.2.1", "pyunigps>=1.0.0", "pynmeagps>=1.1.4", + "pyubx2>=1.3.1", ] [project.scripts] diff --git a/src/pygpsclient/_version.py b/src/pygpsclient/_version.py index 160a57ea..a97d72e2 100644 --- a/src/pygpsclient/_version.py +++ b/src/pygpsclient/_version.py @@ -8,4 +8,4 @@ :license: BSD 3-Clause """ -__version__ = "1.6.9" +__version__ = "1.6.10" diff --git a/src/pygpsclient/configuration.py b/src/pygpsclient/configuration.py index 63a6834f..2bfad4b3 100644 --- a/src/pygpsclient/configuration.py +++ b/src/pygpsclient/configuration.py @@ -107,7 +107,7 @@ def __init__(self, app): "showsettings_b": 1, "docksettings_b": 1, **self.widget_config, - "checkforupdate_b": 1, + "checkforupdate_b": 0, "transient_dialog_b": 1, # whether pop-up dialogs are on top of main app window "resizeable_dialog_b": 0, # whether pop-up dialogs are all resizeable "guiupdateinterval_f": GUI_UPDATE_INTERVAL, # GUI widget update interval in seconds diff --git a/src/pygpsclient/helpers.py b/src/pygpsclient/helpers.py index 20b696c3..1c35ff92 100644 --- a/src/pygpsclient/helpers.py +++ b/src/pygpsclient/helpers.py @@ -1483,6 +1483,23 @@ def valid_geom(geom: str) -> bool: return regexgeom.match(geom) is not None +def valid_hex(val: str, *args) -> bool: + """ + Validate hex string in Entry field. + + :param str val: hexadecimal value + :return: Valid/Invalid + :rtype: bool + """ + + try: + atts = args[0] + int.to_bytes(int(val, 16), atts, "little") + return True + except (TypeError, ValueError, OverflowError): + return False + + def xy2ll(width: int, height: int, bounds: Area, xy: tuple) -> Point | NoneType: """ Convert canvas x/y to lat/lon. diff --git a/src/pygpsclient/ubx_cfgval_frame.py b/src/pygpsclient/ubx_cfgval_frame.py index 0cd2b181..91ec1a28 100644 --- a/src/pygpsclient/ubx_cfgval_frame.py +++ b/src/pygpsclient/ubx_cfgval_frame.py @@ -41,6 +41,7 @@ from pygpsclient.globals import ( ERRCOL, + ICON_BLANK, ICON_CONFIRMED, ICON_PENDING, ICON_SEND, @@ -50,10 +51,12 @@ TRACEMODE_WRITE, UBX_CFGVAL, VALBOOL, + VALCUSTOM, VALFLOAT, VALINT, VALNONBLANK, ) +from pygpsclient.helpers import valid_hex VALSET = 0 VALDEL = 1 @@ -94,6 +97,7 @@ def __init__(self, app: Frame, parent: Frame, *args, **kwargs): self._img_pending = ImageTk.PhotoImage(Image.open(ICON_PENDING)) self._img_confirmed = ImageTk.PhotoImage(Image.open(ICON_CONFIRMED)) self._img_warn = ImageTk.PhotoImage(Image.open(ICON_WARNING)) + self._img_blank = ImageTk.PhotoImage(Image.open(ICON_BLANK)) self._cfgval_cat = None self._cfgval_keyname = None self._cfgval_keyid = None @@ -257,6 +261,7 @@ def reset(self): for i, cat in enumerate(cdb_cats): self._lbx_cat.insert(i, cat) self._cfgmode.set(2) + self._lbl_send_command.config(image=self._img_blank) def _on_select_mode(self, *args, **kwargs): # pylint: disable=unused-argument """ @@ -267,6 +272,7 @@ def _on_select_mode(self, *args, **kwargs): # pylint: disable=unused-argument self._ent_val.config(state=NORMAL) else: self._ent_val.config(state=READONLY) + self._lbl_send_command.config(image=self._img_blank) def _on_select_cat(self, *args, **kwargs): # pylint: disable=unused-argument """ @@ -285,6 +291,7 @@ def _on_select_cat(self, *args, **kwargs): # pylint: disable=unused-argument self._lbx_parm.insert(idx, keyname) idx += 1 self._cfgval.set("") + self._lbl_send_command.config(image=self._img_blank) def _on_select_parm(self, *args, **kwargs): # pylint: disable=unused-argument """ @@ -299,6 +306,7 @@ def _on_select_parm(self, *args, **kwargs): # pylint: disable=unused-argument self._cfgkeyid.set(hex(keyid)) self._cfgatt.set(att) self._cfgval.set("") + self._lbl_send_command.config(image=self._img_blank) except TclError: pass @@ -307,6 +315,7 @@ def _on_send_config(self, *args, **kwargs): # pylint: disable=unused-argument Config interface send button has been clicked. """ + self._lbl_send_command.config(image=self._img_blank) if self._cfgval_keyname is not None: if self._cfgmode.get() == VALSET: self._do_valset() @@ -341,12 +350,15 @@ def _do_valset(self): layers = 1 try: if att in ("C", "X"): # byte or char - self._ent_val.validate(VALNONBLANK) - if len(val) == atts * 2: # 2 hex chars per byte - val = bytearray.fromhex(val) - else: - valid = False - + valid = self._ent_val.validate( + VALCUSTOM, + func=valid_hex, + args=[ + atts, + ], + ) + if valid: + val = int.to_bytes(int(val, 16), atts, "little") elif att in ("E", "U"): # unsigned integer self._ent_val.validate(VALINT) val = int(val) @@ -451,7 +463,9 @@ def update_status(self, msg: UBXMessage): # pylint: disable=unused-argument val = getattr(msg, self._cfgval_keyname, None) if val is not None: if isinstance(val, bytes): - val = val.hex() + atts = attsiz(self._cfgatt.get()) + vali = int.from_bytes(val, "little") + val = f"0x{vali:0{atts*2}x}" self._cfgval.set(val) self.__container.status_label = ("CFG-VALGET GET message received", OKCOL) diff --git a/tests/test_static.py b/tests/test_static.py index 4567bc4c..90ed7898 100644 --- a/tests/test_static.py +++ b/tests/test_static.py @@ -77,6 +77,7 @@ unused_sats, val2sphp, valid_geom, + valid_hex, xy2ll, ) from pygpsclient.mapquest_handler import ( @@ -963,6 +964,15 @@ def testhdg2yaw(self): self.assertEqual(hdg2yaw(375.0),15.0) self.assertEqual(hdg2yaw(715.0),-5.0) + def testvalidhex(self): + + self.assertTrue(valid_hex("0x11223344", 4)) + self.assertFalse(valid_hex("0x112233zz", 4)) + self.assertFalse(valid_hex("0x1122334455667788", 4)) + self.assertTrue(valid_hex("0x1122334455667788", 8)) + self.assertFalse(valid_hex("asdfttwergazz", 4)) + self.assertFalse(valid_hex("", 4)) + if __name__ == "__main__": # import sys;sys.argv = ['', 'Test.testName'] unittest.main()