diff --git a/qspectrumanalyzer/backends/__init__.py b/qspectrumanalyzer/backends/__init__.py index 82705ee..2546bfb 100644 --- a/qspectrumanalyzer/backends/__init__.py +++ b/qspectrumanalyzer/backends/__init__.py @@ -1,7 +1,9 @@ -import os, glob, subprocess, threading +import os, threading from Qt import QtCore +from qspectrumanalyzer import subprocess + class BaseInfo: """Default device metadata""" @@ -39,8 +41,8 @@ class BaseInfo: def help_params(cls, executable): try: text = subprocess.check_output([executable, '-h'], universal_newlines=True, - stderr=subprocess.STDOUT, - env=dict(os.environ, COLUMNS='125')) + stderr=subprocess.STDOUT, env=dict(os.environ, COLUMNS='125'), + console=False) except subprocess.CalledProcessError as e: text = e.output except OSError: diff --git a/qspectrumanalyzer/backends/hackrf_sweep.py b/qspectrumanalyzer/backends/hackrf_sweep.py index 433044f..29b0528 100644 --- a/qspectrumanalyzer/backends/hackrf_sweep.py +++ b/qspectrumanalyzer/backends/hackrf_sweep.py @@ -1,8 +1,9 @@ -import subprocess, pprint, struct, shlex, sys, time +import pprint, struct, shlex, sys, time import numpy as np from Qt import QtCore +from qspectrumanalyzer import subprocess from qspectrumanalyzer.backends import BaseInfo, BasePowerThread @@ -108,7 +109,7 @@ class PowerThread(BasePowerThread): cmdline.extend(shlex.split(additional_params)) self.process = subprocess.Popen(cmdline, stdout=subprocess.PIPE, - universal_newlines=False) + universal_newlines=False, console=False) def parse_output(self, buf): """Parse one buf of output from hackrf_sweep""" diff --git a/qspectrumanalyzer/backends/rtl_power.py b/qspectrumanalyzer/backends/rtl_power.py index 67752ef..ca0bdc3 100644 --- a/qspectrumanalyzer/backends/rtl_power.py +++ b/qspectrumanalyzer/backends/rtl_power.py @@ -1,8 +1,9 @@ -import subprocess, pprint, shlex +import pprint, shlex import numpy as np from Qt import QtCore +from qspectrumanalyzer import subprocess from qspectrumanalyzer.backends import BaseInfo, BasePowerThread @@ -66,7 +67,7 @@ class PowerThread(BasePowerThread): cmdline.extend(shlex.split(additional_params)) self.process = subprocess.Popen(cmdline, stdout=subprocess.PIPE, - universal_newlines=True) + universal_newlines=True, console=False) def parse_output(self, line): """Parse one line of output from rtl_power""" diff --git a/qspectrumanalyzer/backends/rtl_power_fftw.py b/qspectrumanalyzer/backends/rtl_power_fftw.py index 20fca8c..a511ee9 100644 --- a/qspectrumanalyzer/backends/rtl_power_fftw.py +++ b/qspectrumanalyzer/backends/rtl_power_fftw.py @@ -1,7 +1,8 @@ -import subprocess, math, pprint, shlex +import math, pprint, shlex from Qt import QtCore +from qspectrumanalyzer import subprocess from qspectrumanalyzer.backends import BaseInfo, BasePowerThread @@ -91,7 +92,7 @@ class PowerThread(BasePowerThread): cmdline.extend(shlex.split(additional_params)) self.process = subprocess.Popen(cmdline, stdout=subprocess.PIPE, - universal_newlines=True) + universal_newlines=True, console=False) def parse_output(self, line): """Parse one line of output from rtl_power_fftw""" diff --git a/qspectrumanalyzer/backends/rx_power.py b/qspectrumanalyzer/backends/rx_power.py index b2fceac..0b9d7f9 100644 --- a/qspectrumanalyzer/backends/rx_power.py +++ b/qspectrumanalyzer/backends/rx_power.py @@ -1,8 +1,9 @@ -import subprocess, pprint, shlex +import pprint, shlex import numpy as np from Qt import QtCore +from qspectrumanalyzer import subprocess from qspectrumanalyzer.backends import BaseInfo, BasePowerThread @@ -71,7 +72,7 @@ class PowerThread(BasePowerThread): cmdline.extend(shlex.split(additional_params)) self.process = subprocess.Popen(cmdline, stdout=subprocess.PIPE, - universal_newlines=True) + universal_newlines=True, console=False) def parse_output(self, line): """Parse one line of output from rx_power""" diff --git a/qspectrumanalyzer/backends/soapy_power.py b/qspectrumanalyzer/backends/soapy_power.py index 9eecfa0..099c586 100644 --- a/qspectrumanalyzer/backends/soapy_power.py +++ b/qspectrumanalyzer/backends/soapy_power.py @@ -1,8 +1,9 @@ -import os, subprocess, pprint, sys, shlex, signal +import os, sys, pprint, shlex, signal import numpy as np from Qt import QtCore +from qspectrumanalyzer import subprocess from qspectrumanalyzer.backends import BaseInfo, BasePowerThread try: @@ -12,20 +13,6 @@ except ImportError: print('soapy_power module not found!') formatter = None -if sys.platform == 'win32': - import msvcrt - import _winapi - - def _make_inheritable_handle(fd): - """Return a duplicate of handle, which is inheritable""" - h = _winapi.DuplicateHandle( - _winapi.GetCurrentProcess(), - msvcrt.get_osfhandle(fd), - _winapi.GetCurrentProcess(), 0, 1, - _winapi.DUPLICATE_SAME_ACCESS - ) - return subprocess.Handle(h) - class Info(BaseInfo): """soapy_power device metadata""" @@ -47,12 +34,12 @@ class Info(BaseInfo): def help_device(cls, executable, device): try: text = subprocess.check_output([executable, '--detect'], universal_newlines=True, - stderr=subprocess.DEVNULL, - env=dict(os.environ, COLUMNS='125')) + stderr=subprocess.DEVNULL, env=dict(os.environ, COLUMNS='125'), + console=False) text += '\n' text += subprocess.check_output([executable, '--device', device, '--info'], universal_newlines=True, - stderr=subprocess.DEVNULL, - env=dict(os.environ, COLUMNS='125')) + stderr=subprocess.DEVNULL, env=dict(os.environ, COLUMNS='125'), + console=False) except subprocess.CalledProcessError as e: text = e.output except OSError: @@ -101,7 +88,7 @@ class PowerThread(BasePowerThread): os.set_inheritable(self.pipe_write_fd, True) if sys.platform == 'win32': - self.pipe_write_handle = _make_inheritable_handle(self.pipe_write_fd) + self.pipe_write_handle = subprocess.make_inheritable_handle(self.pipe_write_fd) # Prepare soapy_power cmdline parameters settings = QtCore.QSettings() @@ -142,7 +129,7 @@ class PowerThread(BasePowerThread): creationflags = 0 self.process = subprocess.Popen(cmdline, close_fds=False, universal_newlines=False, - creationflags=creationflags) + creationflags=creationflags, console=False) os.close(self.pipe_write_fd) if sys.platform == 'win32': diff --git a/qspectrumanalyzer/data.py b/qspectrumanalyzer/data.py index 446e903..45c4676 100644 --- a/qspectrumanalyzer/data.py +++ b/qspectrumanalyzer/data.py @@ -106,8 +106,8 @@ class DataStorage(QtCore.QObject): def update(self, data): """Update data storage""" if self.y is not None and len(data["y"]) != len(self.y): - print("{:d} bins coming from backend, expected {:d}".format(len(data["y"]), len(self.y))) - return + print("{:d} bins coming from backend, expected {:d}".format(len(data["y"]), len(self.y))) + return self.average_counter += 1 diff --git a/qspectrumanalyzer/subprocess.py b/qspectrumanalyzer/subprocess.py new file mode 100644 index 0000000..063a923 --- /dev/null +++ b/qspectrumanalyzer/subprocess.py @@ -0,0 +1,81 @@ +import sys, subprocess + +# Basic attributes and exceptions +PIPE = subprocess.PIPE +STDOUT = subprocess.STDOUT +DEVNULL = subprocess.DEVNULL +SubprocessError = subprocess.SubprocessError +TimeoutExpired = subprocess.TimeoutExpired +CalledProcessError = subprocess.CalledProcessError + +# Windows-only attributes and functions +if sys.platform == 'win32': + import msvcrt + import _winapi + + # creationflags + CREATE_NEW_CONSOLE = subprocess.CREATE_NEW_CONSOLE + CREATE_NEW_PROCESS_GROUP = subprocess.CREATE_NEW_PROCESS_GROUP + + # startupinfo + STARTUPINFO = subprocess.STARTUPINFO + STARTF_USESTDHANDLES = subprocess.STARTF_USESTDHANDLES + STARTF_USESHOWWINDOW = subprocess.STARTF_USESHOWWINDOW + SW_HIDE = subprocess.SW_HIDE + + # file handles + Handle = subprocess.Handle + STD_INPUT_HANDLE = subprocess.STD_INPUT_HANDLE + STD_OUTPUT_HANDLE = subprocess.STD_OUTPUT_HANDLE + STD_ERROR_HANDLE = subprocess.STD_ERROR_HANDLE + + def make_inheritable_handle(fd): + """Create inheritable duplicate of handle from file descriptor""" + h = _winapi.DuplicateHandle( + _winapi.GetCurrentProcess(), + msvcrt.get_osfhandle(fd), + _winapi.GetCurrentProcess(), 0, 1, + _winapi.DUPLICATE_SAME_ACCESS + ) + return subprocess.Handle(h) + + +def hide_console_window(startupinfo=None): + """Returns altered startupinfo to hide console window on Windows""" + if sys.platform != 'win32': + return None + + if not startupinfo: + startupinfo = subprocess.STARTUPINFO() + + startupinfo.dwFlags |= subprocess.STARTF_USESHOWWINDOW + return startupinfo + + +class Popen(subprocess.Popen): + """subprocess.Popen with ability to hide console window on Windows""" + def __init__(self, *pargs, console=True, **kwargs): + if not console: + kwargs['startupinfo'] = hide_console_window(kwargs.get('startupinfo')) + super().__init__(*pargs, **kwargs) + + +def call(*pargs, console=True, **kwargs): + """subprocess.call with ability to hide console window on Windows""" + if not console: + kwargs['startupinfo'] = hide_console_window(kwargs.get('startupinfo')) + return subprocess.call(*pargs, **kwargs) + + +def check_call(*pargs, console=True, **kwargs): + """subprocess.check_call with ability to hide console window on Windows""" + if not console: + kwargs['startupinfo'] = hide_console_window(kwargs.get('startupinfo')) + return subprocess.check_call(*pargs, **kwargs) + + +def check_output(*pargs, console=True, **kwargs): + """subprocess.check_output with ability to hide console window on Windows""" + if not console: + kwargs['startupinfo'] = hide_console_window(kwargs.get('startupinfo')) + return subprocess.check_output(*pargs, **kwargs)