Skip to content

Commit

Permalink
Merge pull request #91 from semuconsulting/RC-1.1.2
Browse files Browse the repository at this point in the history
Rc 1.1.2
  • Loading branch information
semuadmin committed Sep 8, 2024
2 parents 33a7ebe + 7d1c122 commit 93bbdb8
Show file tree
Hide file tree
Showing 9 changed files with 103 additions and 28 deletions.
2 changes: 1 addition & 1 deletion .vscode/settings.json
Original file line number Diff line number Diff line change
Expand Up @@ -5,5 +5,5 @@
"python3.8InterpreterPath": "/Library/Frameworks/Python.framework/Versions/3.8/bin/python3.8",
"modulename": "${workspaceFolderBasename}",
"distname": "${workspaceFolderBasename}",
"moduleversion": "1.1.1"
"moduleversion": "1.1.2"
}
8 changes: 8 additions & 0 deletions RELEASE_NOTES.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,13 @@
# pygnssutils Release Notes

### RELEASE 1.1.2

FIXES:

1. Fix [#90](https://github.com/semuconsulting/pygnssutils/issues/90)
1. Minor fix to verbosity setting passthrough to lower modules e.g. `pyubx2`.
1. Minor fix to stream validation in gnssstreamer.

### RELEASE 1.1.1

ENHANCEMENTS:
Expand Down
2 changes: 1 addition & 1 deletion pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ name = "pygnssutils"
authors = [{ name = "semuadmin", email = "semuadmin@semuconsulting.com" }]
maintainers = [{ name = "semuadmin", email = "semuadmin@semuconsulting.com" }]
description = "GNSS Command Line Utilities"
version = "1.1.1"
version = "1.1.2"
license = { file = "LICENSE" }
readme = "README.md"
requires-python = ">=3.8"
Expand Down
2 changes: 1 addition & 1 deletion src/pygnssutils/_version.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,4 +8,4 @@
:license: BSD 3-Clause
"""

__version__ = "1.1.1"
__version__ = "1.1.2"
21 changes: 13 additions & 8 deletions src/pygnssutils/gnssserver.py
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@
from threading import Thread
from time import sleep

from pygnssutils.globals import FORMAT_BINARY, OUTPORT, OUTPORT_NTRIP
from pygnssutils.globals import CLIAPP, FORMAT_BINARY, OUTPORT, OUTPORT_NTRIP
from pygnssutils.gnssstreamer import GNSSStreamer
from pygnssutils.helpers import format_conn, ipprot2int
from pygnssutils.socket_server import ClientHandler, SocketServer
Expand All @@ -34,7 +34,7 @@ class GNSSSocketServer:

# pylint: disable=line-too-long

def __init__(self, app=None, **kwargs):
def __init__(self, app=None, stream: object = None, **kwargs):
"""
Context manager constructor.
Expand Down Expand Up @@ -70,6 +70,7 @@ def __init__(self, app=None, **kwargs):
self.logger = getLogger(__name__)
self.logger.debug(kwargs)
try:
self._stream = stream
self._kwargs = kwargs
# overrideable command line arguments..
# 0 = TCP Socket Server mode, 1 = NTRIP Server mode
Expand All @@ -93,7 +94,7 @@ def __init__(self, app=None, **kwargs):
)
# 5 is an arbitrary limit; could be significantly higher
self._kwargs["maxclients"] = int(kwargs.get("maxclients", 5))
self._kwargs["format"] = int(kwargs.get("format", FORMAT_BINARY))
self._kwargs["outformat"] = int(kwargs.get("format", FORMAT_BINARY))
# required fixed arguments...
# msgqueue = Queue()
# self._kwargs["outputhandler"] = msgqueue
Expand Down Expand Up @@ -134,7 +135,7 @@ def run(self) -> int:

if self._validargs:
self.logger.info("Starting server (type CTRL-C to stop)...")
self._in_thread = self._start_input_thread(**self._kwargs)
self._in_thread = self._start_input_thread(self._stream, **self._kwargs)
sleep(0.5)
if self._in_thread.is_alive():
self._out_thread = self._start_output_thread(**self._kwargs)
Expand All @@ -155,7 +156,7 @@ def stop(self):
self._socket_server.shutdown()
self.logger.info("Server shutdown.")

def _start_input_thread(self, **kwargs) -> Thread:
def _start_input_thread(self, stream, **kwargs) -> Thread:
"""
Start input (read) thread.
Expand All @@ -167,7 +168,7 @@ def _start_input_thread(self, **kwargs) -> Thread:
self.logger.info(f"Starting input thread, reading from {kwargs['port']}...")
thread = Thread(
target=self._input_thread,
args=(kwargs,),
args=(stream, kwargs),
daemon=True,
)
thread.start()
Expand Down Expand Up @@ -196,15 +197,19 @@ def _start_output_thread(self, **kwargs) -> Thread:
thread.start()
return thread

def _input_thread(self, kwargs):
def _input_thread(self, stream, kwargs):
"""
THREADED
Input (Serial reader) thread.
"""

self._streamer = GNSSStreamer(**kwargs)
self._streamer = GNSSStreamer(
CLIAPP, stream, outqueue=kwargs["output"], **kwargs
)
self._streamer.run()
while True:
sleep(1)

def _output_thread(self, app: object, kwargs):
"""
Expand Down
84 changes: 73 additions & 11 deletions src/pygnssutils/gnssserver_cli.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,12 +12,83 @@

import os
from argparse import ArgumentDefaultsHelpFormatter, ArgumentParser
from queue import Queue
from socket import create_connection, gethostbyname
from time import sleep

from serial import Serial

from pygnssutils._version import __version__ as VERSION
from pygnssutils.globals import CLIAPP, EPILOG
from pygnssutils.exceptions import ParameterError
from pygnssutils.globals import CLIAPP, ENCODE_NONE, EPILOG, UBXSIMULATOR
from pygnssutils.gnssserver import GNSSSocketServer
from pygnssutils.helpers import set_common_args
from pygnssutils.socketwrapper import SocketWrapper
from pygnssutils.ubxsimulator import UBXSimulator


def _run_streamer(stream, **kwargs):

try:
with GNSSSocketServer(CLIAPP, stream, **kwargs) as server:
goodtogo = server.run()

while goodtogo: # run until user presses CTRL-C
sleep(kwargs["waittime"])
sleep(kwargs["waittime"])

except KeyboardInterrupt:
pass


def _setup_datastream(**kwargs):
"""
Process CLI arguments to setup specified
input datastream (serial, socket, file, other),
and then run streamer using this stream.
:param dict kwargs: parsed CLI arguments
:raises: ParameterError if args are invalid
"""

datastream = kwargs.pop("datastream", None)
port = kwargs.pop("inport", None)
sock = kwargs.pop("socket", None)
baudrate = int(kwargs.pop("baudrate", 9600))
timeout = int(kwargs.pop("timeout", 3))
filename = kwargs.pop("filename", None)
encoding = kwargs.pop("encoding", ENCODE_NONE)

if datastream is None and port is None and sock is None and filename is None:
raise ParameterError(
"Either stream, port, socket or filename keyword argument "
"must be provided.\nType gnsssteamer -h for help.",
)

if datastream is not None: # generic stream
with datastream as stream:
_run_streamer(stream, **kwargs)
elif port is not None: # serial
if port.upper() == UBXSIMULATOR:
with UBXSimulator() as stream:
_run_streamer(stream, **kwargs)
else:
with Serial(port, baudrate, timeout=timeout) as stream:
_run_streamer(stream, **kwargs)
elif sock is not None: # socket
hostport = sock.split(":")
if len(hostport) != 2:
raise ParameterError("socket argument must be in the format host:port")
hostname = hostport[0]
port = int(hostport[1])
ip = gethostbyname(hostname)
with create_connection((ip, port), timeout) as sock:
# wrap socket to allow processing as normal stream
stream = SocketWrapper(sock, encoding)
_run_streamer(stream, **kwargs)
elif filename is not None: # binary file
with open(filename, "rb") as stream:
_run_streamer(stream, **kwargs)


def main():
Expand Down Expand Up @@ -190,16 +261,7 @@ def main():
if kwargs["hostip"] == "0.0.0.0" and kwargs["ipprot"] == "IPv6":
kwargs["hostip"] = "::"

try:
with GNSSSocketServer(CLIAPP, **kwargs) as server:
goodtogo = server.run()

while goodtogo: # run until user presses CTRL-C
sleep(kwargs["waittime"])
sleep(kwargs["waittime"])

except KeyboardInterrupt:
pass
_setup_datastream(**kwargs)


if __name__ == "__main__":
Expand Down
8 changes: 4 additions & 4 deletions src/pygnssutils/gnssstreamer.py
Original file line number Diff line number Diff line change
Expand Up @@ -103,7 +103,7 @@ def __init__(
:param bool validate: 1 = validate checksum, 0 = do not validate (1)
:param int msgmode: 0 = GET, 1 = SET, 2 = POLL (0)
:param bool parsebitfield: 1 = parse UBX 'X' attributes as bitfields, 0 = leave as bytes (1)
:param int format: output format 1 = parsed, 2 = raw, 4 = hex, 8 = tabulated hex, \
:param int outformat: output format 1 = parsed, 2 = raw, 4 = hex, 8 = tabulated hex, \
16 = parsed as string, 32 = JSON (can be OR'd) (1)
:param int quitonerror: 0 = ignore errors, 1 = log errors and continue, \
2 = (re)raise errors (1)
Expand Down Expand Up @@ -485,11 +485,11 @@ def do_output(raw_data: bytes, formatted_data: list, outqueue: Queue, **kwargs):
logger = kwargs.get("logger", None)
if logger is not None:
for i, data in enumerate(formatted_data):
logger.info(f"Formatted data output ({i+1} of {ld}):\n{data}")
logger.debug(f"Formatted data output ({i+1} of {ld}):\n{data}")
if outqueue is not None:
if ld == 1: # if only one format, de-list
formatted_data = formatted_data[0]
outqueue.put((raw_data, formatted_data))
outqueue.put(formatted_data)

@staticmethod
def do_input(datastream: object, inqueue: Queue, **kwargs):
Expand All @@ -513,7 +513,7 @@ def do_input(datastream: object, inqueue: Queue, **kwargs):
else: # just raw
raw = data
if logger is not None:
logger.info(f"Data input: {data}")
logger.debug(f"Data input: {data}")
datastream.write(raw)
inqueue.task_done()
except Empty:
Expand Down
2 changes: 1 addition & 1 deletion src/pygnssutils/gnssstreamer_cli.py
Original file line number Diff line number Diff line change
Expand Up @@ -305,7 +305,7 @@ def _setup_datastream(**kwargs):
filename = kwargs.pop("filename", None)
encoding = kwargs.pop("encoding", ENCODE_NONE)

if datastream is None and port is None and socket is None and filename is None:
if datastream is None and port is None and sock is None and filename is None:
raise ParameterError(
"Either stream, port, socket or filename keyword argument "
"must be provided.\nType gnsssteamer -h for help.",
Expand Down
2 changes: 1 addition & 1 deletion src/pygnssutils/helpers.py
Original file line number Diff line number Diff line change
Expand Up @@ -121,7 +121,7 @@ def set_common_args(

logger = logging.getLogger(logname)
set_logging(
logger, kwargs.pop("verbosity", logdefault), kwargs.pop("logtofile", "")
logger, kwargs.get("verbosity", logdefault), kwargs.get("logtofile", "")
)

return kwargs
Expand Down

0 comments on commit 93bbdb8

Please sign in to comment.