Skip to content
Closed
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
28 changes: 21 additions & 7 deletions README.md

Large diffs are not rendered by default.

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

### RELEASE 1.6.0

1. Add user-selectable Signals widget, displaying individual GNSS PRN / Signal ID levels and (where applicable) correction sources (receiver must support UBX NAV-SIG messages). Provides greater granularity than the standard Levels widget. Signal IDs are shown in RINEX format e.g. "L1_C/A", "E5_aQ", etc.
1. Add user-defined preset import facility to Configuration Load/Save/Record panel. This allows user to record a sequence of UBX, NMEA or TTY commands as they are sent to the receiver and to import this sequence as a user-defined preset in the PyGPSClient json configuration file. This obviates the need to edit the configuration file manually. Remember to re-save the configuration file to persist the changes.
1. NTRIP Caster / Socket Server Configuration is now a separate Toplevel dialog panel, accessed through Server Config button or Menu Option Server Configuration. Number of connected clients is now displayed in topmost banner panel.
1. Show "C/No = 0 dbHz" option ("unused satellites") is now accessible through double-right-click on LevelsView and SignalsView widgets; option removed from main Settings panel.
1. Minor cosmetic updates to SpectrumView widget and Settings panel.

### RELEASE 1.5.23

FIXES:
Expand Down
14 changes: 11 additions & 3 deletions docs/pygpsclient.rst
Original file line number Diff line number Diff line change
Expand Up @@ -300,10 +300,10 @@ pygpsclient.serialconfig\_lband\_frame module
:undoc-members:
:show-inheritance:

pygpsclient.serverconfig\_frame module
--------------------------------------
pygpsclient.serverconfig\_dialog module
---------------------------------------

.. automodule:: pygpsclient.serverconfig_frame
.. automodule:: pygpsclient.serverconfig_dialog
:members:
:undoc-members:
:show-inheritance:
Expand All @@ -316,6 +316,14 @@ pygpsclient.settings\_frame module
:undoc-members:
:show-inheritance:

pygpsclient.signalsview\_frame module
-------------------------------------

.. automodule:: pygpsclient.signalsview_frame
:members:
:undoc-members:
:show-inheritance:

pygpsclient.skyview\_frame module
---------------------------------

Expand Down
Binary file modified images/app.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file modified images/recorder_dialog.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added images/signalsview_widget.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
7 changes: 4 additions & 3 deletions pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -129,12 +129,13 @@ disable = """
too-many-public-methods,
too-many-locals,
invalid-name,
logging-fstring-interpolation
logging-fstring-interpolation,
fixme,
"""

[tool.pytest.ini_options]
minversion = "7.0"
addopts = "--cov --cov-report html --cov-fail-under 18"
addopts = "--cov --cov-report html --cov-fail-under 17"
pythonpath = ["src"]
testpaths = ["tests"]

Expand All @@ -145,7 +146,7 @@ source = ["src"]
source = ["src"]

[tool.coverage.report]
fail_under = 18
fail_under = 17

[tool.coverage.html]
directory = "htmlcov"
2 changes: 1 addition & 1 deletion src/pygpsclient/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@
# pylint: disable=invalid-name

from pygpsclient._version import __version__
from pygpsclient.helpers import nmea2preset, ubx2preset
from pygpsclient.helpers import nmea2preset, tty2preset, ubx2preset
from pygpsclient.sqlite_handler import retrieve_data

version = __version__
10 changes: 10 additions & 0 deletions src/pygpsclient/__main__.py
Original file line number Diff line number Diff line change
Expand Up @@ -102,6 +102,16 @@ def main():
type=int,
default=SUPPRESS,
)
ap.add_argument(
"--tlspempath",
help="Fully qualified path to TLS PEM (private key/certificate) file",
default=SUPPRESS,
)
ap.add_argument(
"--tlscrtpath",
help="Fully qualified path to TLS CRT (certificate) file",
default=SUPPRESS,
)
ap.add_argument(
"--verbosity",
help=(
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.5.23"
__version__ = "1.6.0"
57 changes: 44 additions & 13 deletions src/pygpsclient/app.py
Original file line number Diff line number Diff line change
Expand Up @@ -176,6 +176,7 @@ def __init__(self, master, **kwargs): # pylint: disable=too-many-statements
self.__master.iconphoto(True, PhotoImage(file=ICON_APP128))

self._deferredmsg = None
self._server_status = -1 # socket server status -1 = inactive
self.gnss_inqueue = Queue() # messages from GNSS receiver
self.gnss_outqueue = Queue() # messages to GNSS receiver
self.ntrip_inqueue = Queue() # messages from NTRIP source
Expand Down Expand Up @@ -465,7 +466,6 @@ def load_config(self):
self.frm_settings,
self.frm_settings.frm_serial,
self.frm_settings.frm_socketclient,
self.frm_settings.frm_socketserver,
):
frm.reset()
self._do_layout()
Expand Down Expand Up @@ -560,13 +560,17 @@ def sockserver_start(self):
https = cfg.get("sockhttps_b")
ntripuser = cfg.get("ntripcasteruser_s")
ntrippassword = cfg.get("ntripcasterpassword_s")
tlspempath = cfg.get("tlspempath_s")
ntriprtcmstr = "1002(1),1006(5),1077(1),1087(1),1097(1),1127(1),1230(1)" # TODO
self._socket_thread = Thread(
target=self._sockserver_thread,
args=(
ntripmode,
host,
port,
https,
tlspempath,
ntriprtcmstr,
ntripuser,
ntrippassword,
SOCKSERVER_MAX_CLIENTS,
Expand All @@ -575,23 +579,25 @@ def sockserver_start(self):
daemon=True,
)
self._socket_thread.start()
self.frm_banner.update_transmit_status(0)
self.server_status = 0 # 0 = active, no clients

def sockserver_stop(self):
"""
Stop socket server thread.
"""

self.frm_banner.update_transmit_status(-1)
if self._socket_server is not None:
self._socket_server.shutdown()
self.server_status = -1 # -1 = inactive

def _sockserver_thread(
self,
ntripmode: int,
host: str,
port: int,
https: int,
tlspempath: str,
ntriprtcmstr: str,
ntripuser: str,
ntrippassword: str,
maxclients: int,
Expand All @@ -605,6 +611,8 @@ def _sockserver_thread(
:param str host: socket host name (0.0.0.0)
:param int port: socket port (50010)
:param int https: https enabled (0)
:param str tlspempath: path to TLS PEM file ("$HOME/pygnssutils.pem")
:param str ntriprtcmstr: NTRIP caster RTCM type(rate) sourcetable entry
:param int maxclients: max num of clients (5)
:param Queue socketqueue: socket server read queue
"""
Expand All @@ -620,6 +628,8 @@ def _sockserver_thread(
requesthandler,
ntripuser=ntripuser,
ntrippassword=ntrippassword,
tlspempath=tlspempath,
ntriprtcmstr=ntriprtcmstr,
) as self._socket_server:
self._socket_server.serve_forever()
except OSError as err:
Expand All @@ -633,7 +643,8 @@ def update_clients(self, clients: int):
:param int clients: no of connected clients
"""

self.frm_settings.frm_socketserver.clients = clients
self.server_status = clients
# self.frm_settings.frm_socketserver.clients = clients TODO

def _shutdown(self):
"""
Expand Down Expand Up @@ -684,9 +695,9 @@ def on_gnss_read(self, event): # pylint: disable=unused-argument
raw_data, parsed_data = self.gnss_inqueue.get(False)
if raw_data is not None and parsed_data is not None:
self.process_data(raw_data, parsed_data)
# if socket server is running, output raw data to socket
if self.frm_settings.frm_socketserver.socketserving:
self.socket_outqueue.put(raw_data)
# if socket server is running, output raw data to socket
if self.server_status: # TODO
self.socket_outqueue.put(raw_data)
self.gnss_inqueue.task_done()
except Empty:
pass
Expand All @@ -699,9 +710,7 @@ def on_gnss_eof(self, event): # pylint: disable=unused-argument
:param event event: <<gnss_eof>> event
"""

self.frm_settings.frm_socketserver.socketserving = (
False # turn off socket server
)
self.server_status = -1
self._refresh_widgets()
self.conn_status = DISCONNECTED
self.status_label = (ENDOFFILE, ERRCOL)
Expand All @@ -714,9 +723,7 @@ def on_gnss_timeout(self, event): # pylint: disable=unused-argument
:param event event: <<gnss_timeout>> event
"""

self.frm_settings.frm_socketserver.socketserving = (
False # turn off socket server
)
self.server_status = -1
self._refresh_widgets()
self.conn_status = DISCONNECTED
self.status_label = (INACTIVE_TIMEOUT, ERRCOL)
Expand Down Expand Up @@ -1078,6 +1085,30 @@ def conn_status(self, status: int):
if status == DISCONNECTED:
self.conn_label = (NOTCONN, INFOCOL)

@property
def server_status(self) -> int:
"""
Getter for socket server status.

:return: server status
:rtype: int
"""

return self._server_status

@server_status.setter
def server_status(self, status: int):
"""
Setter for socket server status.

:param int status: server status
-1 - inactive, 0 = active no clients, >0 = active clients
"""

self._server_status = status
self.frm_banner.update_transmit_status(status)
self.configuration.set("sockserver_b", status >= 0)

@property
def rtk_conn_status(self) -> int:
"""
Expand Down
11 changes: 9 additions & 2 deletions src/pygpsclient/banner_frame.py
Original file line number Diff line number Diff line change
Expand Up @@ -170,7 +170,7 @@ def _body(self):
)
self._lbl_ldgps = Label(
self._frm_advanced2,
text="dgps:",
text="corr:",
bg=self._bgcol,
fg=self._fgcol,
anchor=N,
Expand All @@ -186,6 +186,9 @@ def _body(self):
self._lbl_transmit_preset = Label(
self._frm_connect, bg=self._bgcol, image=self._img_blank
)
self._lbl_clients = Label(
self._frm_connect, bg=self._bgcol, fg="green", width=2, anchor=W
)

self._lbl_time = Label(
self._frm_basic, bg=self._bgcol, fg="cyan", width=15, anchor=W
Expand Down Expand Up @@ -252,7 +255,8 @@ def _do_layout(self):

self._lbl_status_preset.grid(column=0, row=0, padx=2, pady=3, sticky=W)
self._lbl_rtk_preset.grid(column=1, row=0, padx=2, pady=3, sticky=W)
self._lbl_transmit_preset.grid(column=2, row=0, padx=2, pady=3, sticky=W)
self._lbl_transmit_preset.grid(column=2, row=0, padx=1, pady=3, sticky=W)
self._lbl_clients.grid(column=3, row=0, padx=1, pady=3, sticky=W)
self._lbl_ltime.grid(column=1, row=0, pady=0, padx=0, sticky=W)
self._lbl_time.grid(column=2, row=0, pady=0, padx=0, sticky=W)
self._lbl_llat.grid(column=3, row=0, pady=0, padx=0, sticky=W)
Expand Down Expand Up @@ -358,10 +362,13 @@ def update_transmit_status(self, transmit: int = 1):

if transmit > 0:
self._lbl_transmit_preset.configure(image=self._img_transmit)
self._lbl_clients.config(text=transmit, fg="#6b8839")
elif transmit == 0:
self._lbl_transmit_preset.configure(image=self._img_noclient)
self._lbl_clients.config(text=transmit, fg="#e7b03e")
else:
self._lbl_transmit_preset.configure(image=self._img_blank)
self._lbl_clients.config(text=" ", fg=BGCOL)

def update_frame(self):
"""
Expand Down
45 changes: 24 additions & 21 deletions src/pygpsclient/canvas_plot.py
Original file line number Diff line number Diff line change
Expand Up @@ -69,6 +69,7 @@ def create_graph(
xcol: str = "#000000",
ycol: tuple = ("#000000",),
xlabels: bool = False,
xlabelsfrm: str = "000",
ylabels: bool = False,
fontscale: int = 30,
**kwargs,
Expand All @@ -77,26 +78,27 @@ def create_graph(
Extends tkinter.Canvas Class to simplify drawing graphs on canvas.
Accommodates multiple Y axis channels.

:param float xdatamax: x maximum data value,
:param float xdatamin: x minimum data value,
:param tuple ydatamax: y channel(s) maximum data value,
:param tuple ydatamin: y channel(s) minimum data value,
:param int xtickmaj: x major ticks,
:param float xdatamax: x maximum data value
:param float xdatamin: x minimum data value
:param tuple ydatamax: y channel(s) maximum data value
:param tuple ydatamin: y channel(s) minimum data value
:param int xtickmaj: x major ticks
:param int ytickmaj: y major ticks
:param int xtickmin: x minor ticks,
:param int ytickmin: y minor ticks,
:param str fillmaj: major axis color,
:param str fillmin: minor axis color,
:param int xdp: x label decimal places,
:param tuple ydp: y channel(s) label decimal places,
:param str xlegend: x legend,
:param int xtickmin: x minor ticks
:param int ytickmin: y minor ticks
:param str fillmaj: major axis color
:param str fillmin: minor axis color
:param int xdp: x label decimal places
:param tuple ydp: y channel(s) label decimal places
:param str xlegend: x legend
:param str xtimeformat: x label time format e.g. "%H:%M:%S"
:param tuple ylegend: y channels legend,
:param str xcol: x label color,
:param tuple ycol: y channel(s) color,
:param bool xlabels: x labels on/off,
:param bool ylabels: y labels on/off,
:param int fontscale: font scaling factor (higher is smaller),
:param tuple ylegend: y channels legend
:param str xcol: x label color
:param tuple ycol: y channel(s) color
:param bool xlabels: x labels on/off
:param str xlabelsfrm: xlabel format string e.g. "000"
:param bool ylabels: y labels on/off
:param int fontscale: font scaling factor (higher is smaller)
:return: return code
:rtype: int
:raises: ValueError if Y channel args have dissimilar lengths
Expand Down Expand Up @@ -140,10 +142,11 @@ def linspace(num: int, start: float, stop: float):
self.fnth = self.font.metrics("linespace")
self.xoffl = self.fnth * ceil(len(ydatamax) / 2) * 1.5
self.xoffr = self.xoffl
self.yoffb = self.fnth * 1.5
xangle = kwargs.pop("xangle", 0)
if xangle != 0: # add extra Y offset for slanted X labels
self.yoffb += self.font.measure("000") * sin(radians(xangle))
if xangle == 0:
self.yoffb = self.fnth * 1.5
else: # add extra Y offset for slanted X labels
self.yoffb = self.font.measure(xlabelsfrm) * cos(radians(xangle)) * 1.2
self.yofft = self.fnth
self.xdatamax = xdatamax
self.xdatamin = xdatamin
Expand Down
Loading