Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -178,7 +178,7 @@ For more comprehensive installation instructions, please refer to [INSTALLATION.
27. [RINEX Conversion](#rinex) facility which supports conversion of previously-saved binary datalogs to RINEX observation and navigation format. To display the RINEX Conversion dialog, go to Menu..Options..RINEX Conversion.
28. [Import Custom Map](#custommap) facility which allows the user to import geo-referenced images for use as background maps. To display the Import Custom Map dialog, go to Menu..Options..Import Custom Map.
29. [Configuration Command Recorder](#recorder) facility which allows the user to record, save, load, import (*as a preset*) and replay UBX, NMEA or TTY configuration commands sent to a receiver. To display the Command Record Facility dialog, go to Menu..Options..Configuration Command Recorder.
30. App Configuration facility which allows the user to amend certain internal configuration parameters, such as the GUI refresh interval, Toplevel window behaviour and maximum log file size. Updates must be saved and the application restarted for any changes to take effect. **NB:** Exercise caution when updating these values and any ensure settings are commensurate with your platform's performance and capacity constraints.
30. App Configuration facility which allows the user to amend certain internal configuration parameters, such as the GUI refresh interval, Toplevel window behaviour and maximum log file size. Updates must be saved and the application restarted for any changes to take effect. **NB:** Exercise caution when updating these values and ensure settings are commensurate with your platform's performance and capacity constraints.

#### <a name="refreshrate">GUI refresh rate setting</a>

Expand Down
10 changes: 10 additions & 0 deletions RELEASE_NOTES.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,15 @@
# PyGPSClient Release Notes

### RELEASE 1.7.5

FIXES:

1. Fix chart plotter updates, and make chart widget a full-width frame.

ENHANCEMENTS:

1. Add password hide/show button to panels with passwords.

### RELEASE 1.7.4

FIXES:
Expand Down
2 changes: 1 addition & 1 deletion src/pygpsclient/_version.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,4 +8,4 @@
:license: BSD 3-Clause
"""

__version__ = "1.7.4"
__version__ = "1.7.5"
11 changes: 6 additions & 5 deletions src/pygpsclient/app.py
Original file line number Diff line number Diff line change
Expand Up @@ -185,11 +185,12 @@ def __init__(self, **kwargs):

# initialise queues and protocol handlers
self._server_status = -1 # socket server status -1 = inactive
self.gnss_outqueue = Queue() # messages to GNSS receiver
self.ntrip_inqueue = Queue() # messages from NTRIP source
self.socket_inqueue = Queue() # message from socket
self.socket_outqueue = Queue() # message to socket
self.console_outqueue = Queue() # message to console
self.gnss_outqueue = Queue() # data to GNSS receiver
self.ntrip_inqueue = Queue() # data from NTRIP source
self.socket_inqueue = Queue() # data from socket
self.socket_outqueue = Queue() # data to socket
self.console_outqueue = Queue() # data to console
self.chart_outqueue = Queue() # data to chart plotter
self.gnssstatus_lock = Lock() # thread lock for GNSS status data
self.datalog_lock = Lock() # thread lock for datalog file
self.gpx_lock = Lock() # thread lock for gpx file
Expand Down
14 changes: 11 additions & 3 deletions src/pygpsclient/app_config_dialog.py
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,10 @@
READONLY,
TRACEMODE_WRITE,
)
from pygpsclient.helpers import trace_update # pylint: disable=unused-import
from pygpsclient.helpers import ( # pylint: disable=unused-import
PasswordButton,
trace_update,
)
from pygpsclient.strings import DLGGUIOPTIONS
from pygpsclient.toplevel_dialog import ToplevelDialog

Expand Down Expand Up @@ -125,12 +128,15 @@ def _body(self):
wrap=True,
textvariable=self._maprefresh,
)
self._lbl_mapkey = Label(self._frm_body, text="MapQuest API Key", anchor=W)
self._frm_mapkey = Frame(self._frm_body)
self._lbl_mapkey = Label(self._frm_mapkey, text="MapQuest API Key", anchor=W)
self._ent_mapkey = Entry(
self._frm_body,
width=35,
textvariable=self._mapkey,
show="*",
)
self._btn_mapkey = PasswordButton(self._frm_mapkey, self._ent_mapkey)
self._lbl_logsize = Label(
self._frm_body, text="Datalog Max File Size", anchor=W
)
Expand Down Expand Up @@ -181,7 +187,9 @@ def _do_layout(self):
self._lbl_logsize.grid(column=0, row=2, sticky=W)
self._spn_logsize.grid(column=1, row=2, sticky=W)
self._lbl_logsizeu.grid(column=2, row=2, padx=2, sticky=W)
self._lbl_mapkey.grid(column=0, row=3, sticky=W)
self._frm_mapkey.grid(column=0, row=3, sticky=EW)
self._lbl_mapkey.grid(column=0, row=0, sticky=W)
self._btn_mapkey.grid(column=1, row=0, sticky=E)
self._ent_mapkey.grid(column=1, row=3, columnspan=2, sticky=EW)
self._lbl_resizedialog.grid(column=0, row=4, sticky=W)
self._chk_resizedialog.grid(column=1, row=4, columnspan=2, sticky=W)
Expand Down
9 changes: 9 additions & 0 deletions src/pygpsclient/attitude_frame.py
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@
:license: BSD 3-Clause
"""

import logging
from tkinter import (
EW,
NSEW,
Expand Down Expand Up @@ -84,6 +85,7 @@ def __init__(self, app: Tk, parent: Frame, *args, **kwargs):
:param kwargs: Optional kwargs to pass to Frame parent class
"""
self.__app = app
self.logger = logging.getLogger(__name__)

super().__init__(parent, *args, **kwargs)

Expand Down Expand Up @@ -355,6 +357,13 @@ def update_frame(self):
except (KeyError, ValueError):
self._canvas.delete(DATA)

# MEMORY LEAK DEBUG
# tot = len(self._canvas.find_all())
# tags = {}
# for tag in (TAG_DATA, TAG_WAIT):
# tags[tag] = len(self._canvas.find_withtag(tag))
# self.logger.debug((tot, tags))

def _flag_range(self, over: bool = False):
"""
Flag range spinbox if data is overrange.
Expand Down
9 changes: 9 additions & 0 deletions src/pygpsclient/chart_frame.py
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@
:license: BSD 3-Clause
"""

from queue import Empty
from random import choice
from time import time
from tkinter import (
Expand Down Expand Up @@ -498,6 +499,14 @@ def update_frame(self):
Plot selected chart data.
"""

while True:
try:
parsed_data = self.__app.chart_outqueue.get(False)
self.update_data(parsed_data)
self.__app.chart_outqueue.task_done()
except Empty:
break

self._update_plot(self._chart_data)
self.update_idletasks()

Expand Down
2 changes: 2 additions & 0 deletions src/pygpsclient/globals.py
Original file line number Diff line number Diff line change
Expand Up @@ -157,6 +157,8 @@
ICON_END = path.join(DIRNAME, "resources/marker_end.png")
ICON_EXIT = path.join(DIRNAME, "resources/iconmonstr-door-6-24.png")
ICON_EXPAND = path.join(DIRNAME, "resources/iconmonstr-arrow-80-16.png")
ICON_EYEON = path.join(DIRNAME, "resources/iconmonstr-eye-lined-16.png")
ICON_EYEOFF = path.join(DIRNAME, "resources/iconmonstr-eye-off-lined-16.png")
ICON_GITHUB = path.join(DIRNAME, "resources/github-256.png")
ICON_IMPORT = path.join(DIRNAME, "resources/iconmonstr-import-24.png")
ICON_LEFT = path.join(DIRNAME, "resources/iconmonstr-caret-left-filled-32.png")
Expand Down
55 changes: 54 additions & 1 deletion src/pygpsclient/helpers.py
Original file line number Diff line number Diff line change
Expand Up @@ -30,8 +30,10 @@
from time import strftime
from tkinter import (
BooleanVar,
Button,
DoubleVar,
Entry,
Frame,
IntVar,
Spinbox,
StringVar,
Expand All @@ -41,6 +43,7 @@
from types import FunctionType, MethodType, NoneType
from typing import Any, Literal

from PIL import Image, ImageTk
from pygnssutils import version as PGVERSION
from pynmeagps import WGS84_SMAJ_AXIS, NMEAMessage, haversine
from pynmeagps import version as NMEAVERSION
Expand All @@ -66,9 +69,12 @@
from pygpsclient._version import __version__ as VERSION
from pygpsclient.globals import (
BSR,
CLICK_CURSOR,
ERRCOL,
FIXLOOKUP,
GPSEPOCH0,
ICON_EYEOFF,
ICON_EYEON,
M2FT,
M2KM,
M2MIL,
Expand Down Expand Up @@ -120,6 +126,10 @@
"pyunigps": UNIVERSION,
}

# ****************************************************************
# Start of Custom Tkinter Class Extensions
# ****************************************************************


def validate(
self: Entry,
Expand Down Expand Up @@ -226,8 +236,51 @@ def trace_update(
for var in (BooleanVar, DoubleVar, IntVar, StringVar):
var.trace_update = trace_update


class PasswordButton(Button):
"""
Custom password show/hide button.
"""

def __init__(self, parent: Frame, password: Entry, **kwargs):
"""
Constructor.

:param Frame parent: parent Frame
:param Entry password: associated password Entry field
"""

self._ent_password = password
self._show_password = False
self._img_eyeon = ImageTk.PhotoImage(Image.open(ICON_EYEON))
self._img_eyeoff = ImageTk.PhotoImage(Image.open(ICON_EYEOFF))

super().__init__(
parent,
width=20,
height=20,
command=self.toggle_password,
cursor=CLICK_CURSOR,
image=self._img_eyeon,
**kwargs,
)

def toggle_password(self):
"""
Toggle password visibility.
"""

self._show_password = not self._show_password
if self._show_password:
self._ent_password["show"] = ""
self["image"] = self._img_eyeoff
else:
self._ent_password["show"] = "*"
self["image"] = self._img_eyeon


# ****************************************************************
# End of Custom Class Extensions
# End of Custom Tkinter Class Extensions
# ****************************************************************


Expand Down
2 changes: 1 addition & 1 deletion src/pygpsclient/nmea_handler.py
Original file line number Diff line number Diff line change
Expand Up @@ -185,7 +185,7 @@ def _process_GLL(self, data: NMEAMessage):
self.__app.gnss_status.utc = data.time # datetime.time
self.__app.gnss_status.lat = data.lat
self.__app.gnss_status.lon = data.lon
self.__app.gnss_status.fix = fix2desc("GLL", data.posMode)
# self.__app.gnss_status.fix = fix2desc("GLL", data.posMode)
# only works for NMEA 4.10 and later...
# self.__app.gnss_status.diff_corr = 1 if data.posMode == "D" else 0

Expand Down
26 changes: 21 additions & 5 deletions src/pygpsclient/ntrip_client_dialog.py
Original file line number Diff line number Diff line change
Expand Up @@ -70,7 +70,7 @@
UIK,
VALFLOAT,
)
from pygpsclient.helpers import MAXALT, get_mp_info
from pygpsclient.helpers import MAXALT, PasswordButton, get_mp_info
from pygpsclient.socketconfig_ntrip_frame import SocketConfigNtripFrame
from pygpsclient.strings import (
DLGTNTRIP,
Expand Down Expand Up @@ -138,6 +138,7 @@ def __init__(self, app: Tk, *args, **kwargs): # pylint: disable=unused-argument
self._ntrip_gga_lon = StringVar()
self._ntrip_gga_alt = StringVar()
self._ntrip_gga_sep = StringVar()
self._show_password = False
self._settings = {}
self._connected = False
self._sourcetable = None
Expand Down Expand Up @@ -213,17 +214,18 @@ def _body(self):
textvariable=self._ntrip_user,
state=NORMAL,
relief="sunken",
width=40,
width=30,
)
self._lbl_password = Label(self._frm_body, text=LBLNTRIPPWD)
self._ent_password = Entry(
self._frm_body,
textvariable=self._ntrip_password,
state=NORMAL,
relief="sunken",
width=40,
width=30,
show="*",
)
self._btn_password = PasswordButton(self._frm_body, self._ent_password)
self._lbl_ntripggaint = Label(self._frm_body, text=LBLNTRIPGGAINT)
self._spn_ntripggaint = Spinbox(
self._frm_body,
Expand Down Expand Up @@ -322,11 +324,12 @@ def _do_layout(self):
self._lbl_datatype.grid(column=2, row=10, padx=3, pady=3, sticky=W)
self._spn_datatype.grid(column=3, row=10, padx=3, pady=3, sticky=W)
self._lbl_user.grid(column=0, row=11, padx=3, pady=3, sticky=W)
self._ent_user.grid(column=1, row=11, columnspan=3, padx=3, pady=3, sticky=W)
self._ent_user.grid(column=1, row=11, columnspan=2, padx=3, pady=3, sticky=W)
self._lbl_password.grid(column=0, row=12, padx=3, pady=3, sticky=W)
self._ent_password.grid(
column=1, row=12, columnspan=3, padx=3, pady=3, sticky=W
column=1, row=12, columnspan=2, padx=3, pady=3, sticky=W
)
self._btn_password.grid(column=3, row=12, padx=3, pady=3, sticky=W)
ttk.Separator(self._frm_body).grid(
column=0, row=13, columnspan=5, padx=3, pady=3, sticky=EW
)
Expand Down Expand Up @@ -379,6 +382,19 @@ def _reset(self):
self._get_settings()
self.set_controls(self._connected)

# def _on_hide_password(self):
# """
# Toggle NTRIP password visibility.
# """

# self._show_password = not self._show_password
# if self._show_password:
# self._ent_password["show"] = ""
# self._btn_password["image"] = self._img_eyeoff
# else:
# self._ent_password["show"] = "*"
# self._btn_password["image"] = self._img_eyeon

def _on_update_config(self, var, index, mode): # pylint: disable=unused-argument
"""
Update in-memory configuration if setting is changed.
Expand Down
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
9 changes: 0 additions & 9 deletions src/pygpsclient/rover_frame.py
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,6 @@

# pylint: disable=invalid-name, no-member

# import logging
from random import randrange
from tkinter import EW, NSEW, NW, SW, Frame, Label, Spinbox, StringVar, Tk, W

Expand Down Expand Up @@ -63,7 +62,6 @@ def __init__(self, app: Tk, parent: Frame, *args, **kwargs):
"""

self.__app = app
# self.logger = logging.getLogger(__name__)

super().__init__(parent, *args, **kwargs)

Expand Down Expand Up @@ -274,13 +272,6 @@ def update_frame(self):
self._canvas.create_circle(x, y, 3, fill=PNTCOL, outline=PNTCOL, tags=TAG_DATA)
self.update_idletasks()

# MEMORY LEAK DEBUG
# tot = len(self._canvas.find_all())
# tags = {}
# for tag in (TAG_DATA, TAG_GRID, TAG_WAIT, TAG_XLABEL):
# tags[tag] = len(self._canvas.find_withtag(tag))
# self.logger.debug((tot, tags))

def _set_range(self, distance: float):
"""
Set range and scale.
Expand Down
9 changes: 0 additions & 9 deletions src/pygpsclient/scatter_frame.py
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,6 @@

# pylint: disable=no-member

# import logging
from tkinter import (
EW,
HORIZONTAL,
Expand Down Expand Up @@ -105,7 +104,6 @@ def __init__(self, app: Tk, parent: Frame, *args, **kwargs):
"""

self.__app = app
# self.logger = logging.getLogger(__name__)

super().__init__(parent, *args, **kwargs)

Expand Down Expand Up @@ -557,13 +555,6 @@ def update_frame(self):
self.init_frame()
self._update_plot()

# MEMORY LEAK DEBUG
# tot = len(self._canvas.find_all())
# tags = {}
# for tag in (TAG_DATA, TAG_GRID, TAG_WAIT, TAG_XLABEL):
# tags[tag] = len(self._canvas.find_withtag(tag))
# self.logger.debug((tot, tags))

def _limit_points(self):
"""
Limit number of points in in-memory array.
Expand Down
Loading