diff --git a/.github/workflows/black.yml b/.github/workflows/black.yml new file mode 100644 index 0000000000..053967a9ff --- /dev/null +++ b/.github/workflows/black.yml @@ -0,0 +1,27 @@ +name: Black + +env: + PYTHONUNBUFFERED: 1 + +on: + push: + branches: [ master ] + pull_request: + branches: [ master ] + +jobs: + black: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + + - name: Set up Python + uses: actions/setup-python@v4 + with: + python-version: '3.11' + + - name: Install black + run: pip install black==23.7.0 + + - name: Check code with black + run: black --check --diff --color . diff --git a/README.md b/README.md index a7a5389a7c..6297b9a96c 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,7 @@ ![URH image](https://raw.githubusercontent.com/jopohl/urh/master/data/icons/banner.png) [![CI](https://github.com/jopohl/urh/actions/workflows/ci.yml/badge.svg)](https://github.com/jopohl/urh/actions/workflows/ci.yml) +[![Code style: black](https://img.shields.io/badge/code%20style-black-black)](https://github.com/psf/black) [![PyPI version](https://badge.fury.io/py/urh.svg)](https://badge.fury.io/py/urh) [![Packaging status](https://repology.org/badge/tiny-repos/urh.svg)](https://repology.org/project/urh/versions) [![Blackhat Arsenal 2017](https://rawgit.com/toolswatch/badges/master/arsenal/usa/2017.svg)](http://www.toolswatch.org/2017/06/the-black-hat-arsenal-usa-2017-phenomenal-line-up-announced/) diff --git a/data/build_icons.py b/data/build_icons.py index 65e9314ae2..dc8a4c9323 100644 --- a/data/build_icons.py +++ b/data/build_icons.py @@ -25,7 +25,7 @@ def get_used_icon_names(): with open(sourcefile, "r") as f: for line in f: if "QIcon.fromTheme" in line: - icon = line[line.find("QIcon.fromTheme"):] + icon = line[line.find("QIcon.fromTheme") :] icon = icon.replace('"', "'") start = icon.find("'") + 1 end = icon.find("'", start) @@ -35,7 +35,11 @@ def get_used_icon_names(): def copy_icons(icon_names: set): target_dir = "/tmp/oxy" - sizes = [s for s in os.listdir(OXYGEN_PATH) if os.path.isdir(os.path.join(OXYGEN_PATH, s))] # 8x8, 22x22 ... + sizes = [ + s + for s in os.listdir(OXYGEN_PATH) + if os.path.isdir(os.path.join(OXYGEN_PATH, s)) + ] # 8x8, 22x22 ... for size in sizes: target_size_dir = os.path.join(target_dir, size) os.makedirs(target_size_dir, exist_ok=True) @@ -59,7 +63,7 @@ def copy_icons(icon_names: set): for size in sizes: f.write("\n") f.write("[" + size + "]\n") - f.write("Size=" + size[:size.index("x")] + "\n") + f.write("Size=" + size[: size.index("x")] + "\n") f.write("\n") root = ET.Element("RCC") diff --git a/data/check_native_backends.py b/data/check_native_backends.py index 5c1503b774..9fea18cafc 100755 --- a/data/check_native_backends.py +++ b/data/check_native_backends.py @@ -3,21 +3,33 @@ import importlib import os import sys + rc = 0 if sys.platform == "win32": - shared_lib_dir = os.path.realpath(os.path.join(os.path.dirname(__file__), "..", "src/urh/dev/native/lib/shared")) + shared_lib_dir = os.path.realpath( + os.path.join(os.path.dirname(__file__), "..", "src/urh/dev/native/lib/shared") + ) print("Attempting to read", shared_lib_dir) if os.path.isdir(shared_lib_dir): os.environ["PATH"] = os.environ.get("PATH", "") + os.pathsep + shared_lib_dir print("PATH updated") -for sdr in ("AirSpy", "BladeRF", "HackRF", "RTLSDR", "LimeSDR", "PlutoSDR", "SDRPlay", "USRP"): +for sdr in ( + "AirSpy", + "BladeRF", + "HackRF", + "RTLSDR", + "LimeSDR", + "PlutoSDR", + "SDRPlay", + "USRP", +): try: - importlib.import_module('.{}'.format(sdr.lower()), 'urh.dev.native.lib') - print("{:<10} \033[92mSUCCESS\033[0m".format(sdr+":")) + importlib.import_module(".{}".format(sdr.lower()), "urh.dev.native.lib") + print("{:<10} \033[92mSUCCESS\033[0m".format(sdr + ":")) except ImportError as e: - print("{:<10} \033[91mFAILURE\033[0m ({})".format(sdr+":", e)) + print("{:<10} \033[91mFAILURE\033[0m ({})".format(sdr + ":", e)) rc = 1 sys.exit(rc) diff --git a/data/generate_ui.py b/data/generate_ui.py index e4fa353c34..5a400681a8 100644 --- a/data/generate_ui.py +++ b/data/generate_ui.py @@ -44,13 +44,14 @@ def gen(force=False): # Remove Line: # Form implementation generated from reading ui file '/home/joe/GIT/urh/ui/fuzzing.ui' # to avoid useless git updates when working on another computer for line in fileinput.input(out_file_path, inplace=True): - if line.startswith("# Form implementation generated from reading ui file") or line.startswith( - "# Created by: "): + if line.startswith( + "# Form implementation generated from reading ui file" + ) or line.startswith("# Created by: "): continue if line.strip().startswith("QtCore.QMetaObject.connectSlotsByName("): # disable auto slot connection, as we do not use it, and it causes crash on python 3.7 continue - print(line, end='') + print(line, end="") for f in rc_files: file_path = os.path.join(rc_path, f) diff --git a/data/pyinstaller_helper.py b/data/pyinstaller_helper.py index 7869148c62..1f65d91838 100644 --- a/data/pyinstaller_helper.py +++ b/data/pyinstaller_helper.py @@ -2,14 +2,24 @@ import shutil import sys -HIDDEN_IMPORTS = ["packaging.specifiers", "packaging.requirements", "pkg_resources.py2_warn", - "numpy.core._methods", "numpy.core._dtype_ctypes", - "numpy.random.common", "numpy.random.entropy", "numpy.random.bounded_integers"] -DATA = [("src/urh/dev/native/lib/shared", "."), ("src/urh/plugins", "urh/plugins"), ] +HIDDEN_IMPORTS = [ + "packaging.specifiers", + "packaging.requirements", + "pkg_resources.py2_warn", + "numpy.core._methods", + "numpy.core._dtype_ctypes", + "numpy.random.common", + "numpy.random.entropy", + "numpy.random.bounded_integers", +] +DATA = [ + ("src/urh/dev/native/lib/shared", "."), + ("src/urh/plugins", "urh/plugins"), +] EXCLUDE = ["matplotlib"] -def run_pyinstaller(cmd_list: list, env: list=None): +def run_pyinstaller(cmd_list: list, env: list = None): cmd = " ".join(cmd_list) print(cmd, flush=True) @@ -20,7 +30,7 @@ def run_pyinstaller(cmd_list: list, env: list=None): os.system(cmd) -if __name__ == '__main__': +if __name__ == "__main__": cmd = ["pyinstaller", "--clean"] if sys.platform == "darwin": cmd.append("--onefile") @@ -38,31 +48,52 @@ def run_pyinstaller(cmd_list: list, env: list=None): urh_path = os.path.realpath(os.path.join(os.path.dirname(__file__), "..")) if sys.platform == "darwin": - cmd.append('--icon="{}"'.format(os.path.join(urh_path, "data/icons/appicon.icns"))) + cmd.append( + '--icon="{}"'.format(os.path.join(urh_path, "data/icons/appicon.icns")) + ) else: - cmd.append('--icon="{}"'.format(os.path.join(urh_path, "data/icons/appicon.ico"))) + cmd.append( + '--icon="{}"'.format(os.path.join(urh_path, "data/icons/appicon.ico")) + ) cmd.extend(["--distpath", "./pyinstaller"]) - urh_cmd = cmd + ["--name=urh", "--windowed", "--workpath", "./urh_build", - os.path.join(urh_path, "src/urh/main.py")] - - urh_debug_cmd = cmd + ["--name=urh_debug", "--workpath", "./urh_debug_build", - os.path.join(urh_path, "src/urh/main.py")] - - cli_cmd = cmd + ["--workpath", "./urh_cli_build", - os.path.join(urh_path, "src/urh/cli/urh_cli.py")] + urh_cmd = cmd + [ + "--name=urh", + "--windowed", + "--workpath", + "./urh_build", + os.path.join(urh_path, "src/urh/main.py"), + ] + + urh_debug_cmd = cmd + [ + "--name=urh_debug", + "--workpath", + "./urh_debug_build", + os.path.join(urh_path, "src/urh/main.py"), + ] + + cli_cmd = cmd + [ + "--workpath", + "./urh_cli_build", + os.path.join(urh_path, "src/urh/cli/urh_cli.py"), + ] os.makedirs("./pyinstaller") if sys.platform == "darwin": - run_pyinstaller(urh_cmd, env=["DYLD_LIBRARY_PATH=src/urh/dev/native/lib/shared"]) + run_pyinstaller( + urh_cmd, env=["DYLD_LIBRARY_PATH=src/urh/dev/native/lib/shared"] + ) import plistlib + with open("pyinstaller/urh.app/Contents/Info.plist", "rb") as f: p = plistlib.load(f) p["NSHighResolutionCapable"] = True p["NSRequiresAquaSystemAppearance"] = True - p["NSMicrophoneUsageDescription"] = "URH needs access to your microphone to capture signals via Soundcard." + p[ + "NSMicrophoneUsageDescription" + ] = "URH needs access to your microphone to capture signals via Soundcard." with open("pyinstaller/urh.app/Contents/Info.plist", "wb") as f: plistlib.dump(p, f) @@ -70,5 +101,9 @@ def run_pyinstaller(cmd_list: list, env: list=None): for cmd in [urh_cmd, cli_cmd, urh_debug_cmd]: run_pyinstaller(cmd) - shutil.copy("./pyinstaller/urh_cli/urh_cli.exe", "./pyinstaller/urh/urh_cli.exe") - shutil.copy("./pyinstaller/urh_debug/urh_debug.exe", "./pyinstaller/urh/urh_debug.exe") + shutil.copy( + "./pyinstaller/urh_cli/urh_cli.exe", "./pyinstaller/urh/urh_cli.exe" + ) + shutil.copy( + "./pyinstaller/urh_debug/urh_debug.exe", "./pyinstaller/urh/urh_debug.exe" + ) diff --git a/data/release.py b/data/release.py index 4c42f4914b..aee41c6fe6 100644 --- a/data/release.py +++ b/data/release.py @@ -11,7 +11,11 @@ def cleanup(): Remove all cache directories :return: """ - script_dir = os.path.dirname(__file__) if not os.path.islink(__file__) else os.path.dirname(os.readlink(__file__)) + script_dir = ( + os.path.dirname(__file__) + if not os.path.islink(__file__) + else os.path.dirname(os.readlink(__file__)) + ) script_dir = os.path.realpath(os.path.join(script_dir, "..")) shutil.rmtree(os.path.join(script_dir, "dist"), ignore_errors=True) shutil.rmtree(os.path.join(script_dir, "tmp"), ignore_errors=True) @@ -21,11 +25,19 @@ def cleanup(): def release(): - script_dir = os.path.dirname(__file__) if not os.path.islink(__file__) else os.path.dirname(os.readlink(__file__)) + script_dir = ( + os.path.dirname(__file__) + if not os.path.islink(__file__) + else os.path.dirname(os.readlink(__file__)) + ) script_dir = os.path.realpath(os.path.join(script_dir, "..")) os.chdir(script_dir) - current_branch = check_output(["git", "rev-parse", "--abbrev-ref", "HEAD"]).decode("UTF-8").strip() + current_branch = ( + check_output(["git", "rev-parse", "--abbrev-ref", "HEAD"]) + .decode("UTF-8") + .strip() + ) if current_branch != "master": print("You can only release from master!") @@ -34,7 +46,10 @@ def release(): open(os.path.join(tempfile.gettempdir(), "urh_releasing"), "w").close() from src.urh import version - version_file = os.path.realpath(os.path.join(script_dir, "src", "urh", "version.py")) + + version_file = os.path.realpath( + os.path.join(script_dir, "src", "urh", "version.py") + ) cur_version = version.VERSION numbers = cur_version.split(".") @@ -44,7 +59,7 @@ def release(): for line in fileinput.input(version_file, inplace=True): if line.startswith("VERSION"): line = 'VERSION = "{0}" \n'.format(cur_version) - print(line, end='') + print(line, end="") # Publish new version number call(["git", "add", version_file]) @@ -61,16 +76,27 @@ def release(): # Push new tag call(["git", "tag", "v" + cur_version, "-m", "version " + cur_version]) - call(["git", "push", "origin", "--tags"]) # Creates tar package on https://github.com/jopohl/urh/tarball/va.b.c.d + call( + ["git", "push", "origin", "--tags"] + ) # Creates tar package on https://github.com/jopohl/urh/tarball/va.b.c.d os.remove(os.path.join(tempfile.gettempdir(), "urh_releasing")) # region Build docker image and push to DockerHub os.chdir(os.path.dirname(__file__)) call(["docker", "login"]) - call(["docker", "build", "--no-cache", - "--tag", "jopohl/urh:latest", - "--tag", "jopohl/urh:{}".format(cur_version), "."]) + call( + [ + "docker", + "build", + "--no-cache", + "--tag", + "jopohl/urh:latest", + "--tag", + "jopohl/urh:{}".format(cur_version), + ".", + ] + ) call(["docker", "push", "jopohl/urh:latest"]) call(["docker", "push", "jopohl/urh:{}".format(cur_version)]) # endregion diff --git a/setup.py b/setup.py index 8b51ec6f57..ac76efcbad 100644 --- a/setup.py +++ b/setup.py @@ -31,7 +31,11 @@ NO_NUMPY_WARNINGS_FLAG = "-Wno-cpp" UI_SUBDIRS = ("actions", "delegates", "views") -PLUGINS = [path for path in os.listdir("src/urh/plugins") if os.path.isdir(os.path.join("src/urh/plugins", path))] +PLUGINS = [ + path + for path in os.listdir("src/urh/plugins") + if os.path.isdir(os.path.join("src/urh/plugins", path)) +] URH_DIR = "urh" IS_RELEASE = os.path.isfile(os.path.join(tempfile.gettempdir(), "urh_releasing")) @@ -39,9 +43,11 @@ try: from Cython.Build import cythonize except ImportError: - print("You need Cython to build URH's extensions!\n" - "You can get it e.g. with python3 -m pip install cython.", - file=sys.stderr) + print( + "You need Cython to build URH's extensions!\n" + "You can get it e.g. with python3 -m pip install cython.", + file=sys.stderr, + ) sys.exit(1) @@ -52,6 +58,7 @@ def finalize_options(self): # Prevent numpy from thinking it is still in its setup process: __builtins__.__NUMPY_SETUP__ = False import numpy + self.include_dirs.append(numpy.get_include()) @@ -59,7 +66,9 @@ def get_packages(): packages = [URH_DIR] separator = os.path.normpath("/") for dirpath, dirnames, filenames in os.walk(os.path.join("./src/", URH_DIR)): - package_path = os.path.relpath(dirpath, os.path.join("./src/", URH_DIR)).replace(separator, ".") + package_path = os.path.relpath( + dirpath, os.path.join("./src/", URH_DIR) + ).replace(separator, ".") if len(package_path) > 1: packages.append(URH_DIR + "." + package_path) @@ -69,7 +78,7 @@ def get_packages(): def get_package_data(): package_data = {"urh.cythonext": ["*.pyx", "*.pxd"]} for plugin in PLUGINS: - package_data["urh.plugins." + plugin] = ['*.ui', "*.txt"] + package_data["urh.plugins." + plugin] = ["*.ui", "*.txt"] package_data["urh.dev.native.lib"] = ["*.pyx", "*.pxd"] @@ -80,21 +89,38 @@ def get_package_data(): def get_extensions(): - filenames = [os.path.splitext(f)[0] for f in os.listdir("src/urh/cythonext") if f.endswith(".pyx")] - extensions = [Extension("urh.cythonext." + f, ["src/urh/cythonext/" + f + ".pyx"], - extra_compile_args=[OPEN_MP_FLAG], - extra_link_args=[OPEN_MP_FLAG], - language="c++") for f in filenames] + filenames = [ + os.path.splitext(f)[0] + for f in os.listdir("src/urh/cythonext") + if f.endswith(".pyx") + ] + extensions = [ + Extension( + "urh.cythonext." + f, + ["src/urh/cythonext/" + f + ".pyx"], + extra_compile_args=[OPEN_MP_FLAG], + extra_link_args=[OPEN_MP_FLAG], + language="c++", + ) + for f in filenames + ] ExtensionHelper.USE_RELATIVE_PATHS = True - device_extensions, device_extras = ExtensionHelper.get_device_extensions_and_extras() + ( + device_extensions, + device_extras, + ) = ExtensionHelper.get_device_extensions_and_extras() extensions += device_extensions if NO_NUMPY_WARNINGS_FLAG: for extension in extensions: extension.extra_compile_args.append(NO_NUMPY_WARNINGS_FLAG) - extensions = cythonize(extensions, compiler_directives=COMPILER_DIRECTIVES, compile_time_env=device_extras) + extensions = cythonize( + extensions, + compiler_directives=COMPILER_DIRECTIVES, + compile_time_env=device_extras, + ) return extensions @@ -117,7 +143,7 @@ def read_long_description(): install_requires.append("pyqt5") if sys.version_info < (3, 4): - install_requires.append('enum34') + install_requires.append("enum34") setup( name="urh", @@ -133,14 +159,15 @@ def read_long_description(): license="GNU General Public License (GPL)", download_url="https://github.com/jopohl/urh/tarball/v" + str(version.VERSION), install_requires=install_requires, - setup_requires=['numpy'], + setup_requires=["numpy"], packages=get_packages(), ext_modules=get_extensions(), - cmdclass={'build_ext': build_ext}, + cmdclass={"build_ext": build_ext}, zip_safe=False, entry_points={ - 'console_scripts': [ - 'urh = urh.main:main', - 'urh_cli = urh.cli.urh_cli:main', - ]} + "console_scripts": [ + "urh = urh.main:main", + "urh_cli = urh.cli.urh_cli:main", + ] + }, ) diff --git a/src/urh/ainterpretation/AutoInterpretation.py b/src/urh/ainterpretation/AutoInterpretation.py index aaede6cd48..8f3fc13acf 100644 --- a/src/urh/ainterpretation/AutoInterpretation.py +++ b/src/urh/ainterpretation/AutoInterpretation.py @@ -26,6 +26,7 @@ def min_without_outliers(data: np.ndarray, z=2): return np.min(data[abs(data - np.mean(data)) <= z * np.std(data)]) + def get_most_frequent_value(values: list): """ Return the most frequent value in list. @@ -66,9 +67,15 @@ def detect_noise_level(magnitudes): chunksize_percent = 1 chunksize = max(1, int(len(magnitudes) * chunksize_percent / 100)) - chunks = [magnitudes[i - chunksize:i] for i in range(len(magnitudes), 0, -chunksize) if i - chunksize >= 0] + chunks = [ + magnitudes[i - chunksize : i] + for i in range(len(magnitudes), 0, -chunksize) + if i - chunksize >= 0 + ] - mean_values = np.fromiter((np.mean(chunk) for chunk in chunks), dtype=np.float32, count=len(chunks)) + mean_values = np.fromiter( + (np.mean(chunk) for chunk in chunks), dtype=np.float32, count=len(chunks) + ) minimum, maximum = util.minmax(mean_values) if maximum == 0 or minimum / maximum > 0.9: # Mean values are very close to each other, so there is probably no noise in the signal @@ -94,7 +101,9 @@ def segment_messages_from_magnitudes(magnitudes: np.ndarray, noise_threshold: fl :param noise_threshold: Threshold for noise :return: """ - return c_auto_interpretation.segment_messages_from_magnitudes(magnitudes, noise_threshold) + return c_auto_interpretation.segment_messages_from_magnitudes( + magnitudes, noise_threshold + ) def merge_message_segments_for_ook(segments: list): @@ -106,13 +115,13 @@ def merge_message_segments_for_ook(segments: list): pauses = np.fromiter( (segments[i + 1][0] - segments[i][1] for i in range(len(segments) - 1)), count=len(segments) - 1, - dtype=np.uint64 + dtype=np.uint64, ) pulses = np.fromiter( (segments[i][1] - segments[i][0] for i in range(len(segments))), count=len(segments), - dtype=np.uint64 + dtype=np.uint64, ) # Find relatively large pauses, these mark new messages @@ -122,7 +131,9 @@ def merge_message_segments_for_ook(segments: list): # Merge Pulse Lengths between long pauses for i in range(0, len(large_pause_indices) + 1): if i == 0: - start, end = 0, large_pause_indices[i] + 1 if len(large_pause_indices) >= 1 else len(segments) + start, end = 0, large_pause_indices[i] + 1 if len( + large_pause_indices + ) >= 1 else len(segments) elif i == len(large_pause_indices): start, end = large_pause_indices[i - 1] + 1, len(segments) else: @@ -130,7 +141,9 @@ def merge_message_segments_for_ook(segments: list): msg_begin = segments[start][0] msg_length = sum(segments[j][1] - segments[j][0] for j in range(start, end)) - msg_length += sum(segments[j][0] - segments[j - 1][1] for j in range(start + 1, end)) + msg_length += sum( + segments[j][0] - segments[j - 1][1] for j in range(start + 1, end) + ) result.append((msg_begin, msg_begin + msg_length)) @@ -156,10 +169,17 @@ def detect_modulation(data: np.ndarray, wavelet_scale=4, median_filter_order=11) var_mag = np.var(mag_wavlt) var_norm_mag = np.var(norm_mag_wavlt) - var_filtered_mag = np.var(c_auto_interpretation.median_filter(mag_wavlt, k=median_filter_order)) - var_filtered_norm_mag = np.var(c_auto_interpretation.median_filter(norm_mag_wavlt, k=median_filter_order)) + var_filtered_mag = np.var( + c_auto_interpretation.median_filter(mag_wavlt, k=median_filter_order) + ) + var_filtered_norm_mag = np.var( + c_auto_interpretation.median_filter(norm_mag_wavlt, k=median_filter_order) + ) - if all(v < 0.15 for v in (var_mag, var_norm_mag, var_filtered_mag, var_filtered_norm_mag)): + if all( + v < 0.15 + for v in (var_mag, var_norm_mag, var_filtered_mag, var_filtered_norm_mag) + ): return "OOK" if var_mag > 1.5 * var_norm_mag: @@ -173,14 +193,17 @@ def detect_modulation(data: np.ndarray, wavelet_scale=4, median_filter_order=11) else: # Now we either have a FSK signal or we a have OOK single pulse # If we have an FSK, there should be at least two peaks in FFT - fft = np.fft.fft(data[0:2 ** int(np.log2(len(data)))]) + fft = np.fft.fft(data[0 : 2 ** int(np.log2(len(data)))]) fft = np.abs(np.fft.fftshift(fft)) ten_greatest_indices = np.argsort(fft)[::-1][0:10] greatest_index = ten_greatest_indices[0] min_distance = 10 min_freq = 100 # 100 seems to be magnitude of noise frequency - if any(abs(i - greatest_index) >= min_distance and fft[i] >= min_freq for i in ten_greatest_indices): + if any( + abs(i - greatest_index) >= min_distance and fft[i] >= min_freq + for i in ten_greatest_indices + ): return "FSK" else: return "OOK" @@ -207,7 +230,7 @@ def detect_center(rectangular_signal: np.ndarray, max_size=None): # Ignore the first and last 5% of samples, # because there tends to be an overshoot at start/end of rectangular signal - rect = rect[int(0.05*len(rect)):int(0.95*len(rect))] + rect = rect[int(0.05 * len(rect)) : int(0.95 * len(rect))] if max_size is not None and len(rect) > max_size: rect = rect[0:max_size] @@ -219,7 +242,9 @@ def detect_center(rectangular_signal: np.ndarray, max_size=None): hist_step = float(np.var(rect)) try: - y, x = np.histogram(rect, bins=np.arange(hist_min, hist_max + hist_step, hist_step)) + y, x = np.histogram( + rect, bins=np.arange(hist_min, hist_max + hist_step, hist_step) + ) except (ZeroDivisionError, ValueError): # For a segment with zero variance (constant line) it is not possible to find a center return None @@ -227,7 +252,7 @@ def detect_center(rectangular_signal: np.ndarray, max_size=None): num_values = 2 most_common_levels = [] - window_size = max(2, int(0.05*len(y)) + 1) + window_size = max(2, int(0.05 * len(y)) + 1) def get_elem(arr, index: int, default): if 0 <= index < len(arr): @@ -237,9 +262,11 @@ def get_elem(arr, index: int, default): for index in np.argsort(y)[::-1]: # check if we have a local maximum in histogram, if yes, append the value - if all(y[index] > get_elem(y, index+i, 0) and - y[index] > get_elem(y, index-i, 0) - for i in range(1, window_size)): + if all( + y[index] > get_elem(y, index + i, 0) + and y[index] > get_elem(y, index - i, 0) + for i in range(1, window_size) + ): most_common_levels.append(x[index]) if len(most_common_levels) == num_values: @@ -280,7 +307,9 @@ def merge_plateau_lengths(plateau_lengths, tolerance=None) -> list: if tolerance == 0 or tolerance is None: return plateau_lengths - return c_auto_interpretation.merge_plateaus(plateau_lengths, tolerance, max_count=10000) + return c_auto_interpretation.merge_plateaus( + plateau_lengths, tolerance, max_count=10000 + ) def round_plateau_lengths(plateau_lengths: list): @@ -322,7 +351,9 @@ def get_bit_length_from_plateau_lengths(merged_plateau_lengths) -> int: return int(merged_plateau_lengths[0]) round_plateau_lengths(merged_plateau_lengths) - histogram = c_auto_interpretation.get_threshold_divisor_histogram(merged_plateau_lengths) + histogram = c_auto_interpretation.get_threshold_divisor_histogram( + merged_plateau_lengths + ) if len(histogram) == 0: return 0 @@ -350,10 +381,16 @@ def estimate(iq_array: IQArray, noise: float = None, modulation: str = None) -> noise = detect_noise_level(magnitudes) if noise is None else noise # segment messages - message_indices = segment_messages_from_magnitudes(magnitudes, noise_threshold=noise) + message_indices = segment_messages_from_magnitudes( + magnitudes, noise_threshold=noise + ) # detect modulation - modulation = detect_modulation_for_messages(iq_array, message_indices) if modulation is None else modulation + modulation = ( + detect_modulation_for_messages(iq_array, message_indices) + if modulation is None + else modulation + ) if modulation is None: return None @@ -379,7 +416,9 @@ def estimate(iq_array: IQArray, noise: float = None, modulation: str = None) -> if center is None: continue - plateau_lengths = c_auto_interpretation.get_plateau_lengths(msg_rect_data, center, percentage=25) + plateau_lengths = c_auto_interpretation.get_plateau_lengths( + msg_rect_data, center, percentage=25 + ) tolerance = estimate_tolerance_from_plateau_lengths(plateau_lengths) if tolerance is None: tolerance = 0 @@ -428,7 +467,7 @@ def estimate(iq_array: IQArray, noise: float = None, modulation: str = None) -> "bit_length": bit_length, "center": center, "tolerance": int(tolerance), - "noise": noise + "noise": noise, } return result diff --git a/src/urh/ainterpretation/Wavelet.py b/src/urh/ainterpretation/Wavelet.py index 37ca23c8e8..74af0af9f5 100644 --- a/src/urh/ainterpretation/Wavelet.py +++ b/src/urh/ainterpretation/Wavelet.py @@ -1,6 +1,6 @@ import numpy as np -from urh.cythonext import auto_interpretation as cy_auto_interpretation +from urh.cythonext import auto_interpretation as cy_auto_interpretation from urh.signalprocessing.Modulator import Modulator @@ -27,16 +27,20 @@ def cwt_haar(x: np.ndarray, scale=10): x_hat = np.fft.fft(x) # Get omega (eq. (5) in paper) - f = (2.0 * np.pi / num_data) - omega = f * np.concatenate((np.arange(0, num_data // 2), np.arange(num_data // 2, num_data) * -1)) + f = 2.0 * np.pi / num_data + omega = f * np.concatenate( + (np.arange(0, num_data // 2), np.arange(num_data // 2, num_data) * -1) + ) # get psi hat (eq. (6) in paper) - psi_hat = np.sqrt(2.0 * np.pi * scale) * normalized_haar_wavelet(scale * omega, scale) + psi_hat = np.sqrt(2.0 * np.pi * scale) * normalized_haar_wavelet( + scale * omega, scale + ) # get W (eq. (4) in paper) W = np.fft.ifft(x_hat * psi_hat) - return W[2 * scale:-2 * scale] + return W[2 * scale : -2 * scale] if __name__ == "__main__": @@ -45,8 +49,10 @@ def cwt_haar(x: np.ndarray, scale=10): # data = np.fromfile("/home/joe/GIT/urh/tests/data/fsk.complex", dtype=np.complex64)[5:15000] # data = np.fromfile("/home/joe/GIT/urh/tests/data/ask.complex", dtype=np.complex64)[462:754] # data = np.fromfile("/home/joe/GIT/urh/tests/data/enocean.complex", dtype=np.complex64)[9724:10228] - data = np.fromfile("/home/joe/GIT/publications/ainterpretation/experiments/signals/esaver_test4on.complex", - dtype=np.complex64)[86452:115541] + data = np.fromfile( + "/home/joe/GIT/publications/ainterpretation/experiments/signals/esaver_test4on.complex", + dtype=np.complex64, + )[86452:115541] # data = np.fromfile("/home/joe/GIT/urh/tests/data/action_ook.complex", dtype=np.complex64)[3780:4300] diff --git a/src/urh/awre/AutoAssigner.py b/src/urh/awre/AutoAssigner.py index 6b37d9a1a3..8333b3cfae 100644 --- a/src/urh/awre/AutoAssigner.py +++ b/src/urh/awre/AutoAssigner.py @@ -24,7 +24,9 @@ def auto_assign_participants(messages, participants): src_address = msg.get_src_address_from_data() if src_address: try: - msg.participant = next(p for p in participants if p.address_hex == src_address) + msg.participant = next( + p for p in participants if p.address_hex == src_address + ) except StopIteration: pass diff --git a/src/urh/awre/CommonRange.py b/src/urh/awre/CommonRange.py index a7f1c50aba..f43729bb2b 100644 --- a/src/urh/awre/CommonRange.py +++ b/src/urh/awre/CommonRange.py @@ -8,8 +8,17 @@ class CommonRange(object): - def __init__(self, start, length, value: np.ndarray = None, score=0, field_type="Generic", message_indices=None, - range_type="bit", byte_order="big"): + def __init__( + self, + start, + length, + value: np.ndarray = None, + score=0, + field_type="Generic", + message_indices=None, + range_type="bit", + byte_order="big", + ): """ :param start: @@ -31,7 +40,9 @@ def __init__(self, start, length, value: np.ndarray = None, score=0, field_type= self.range_type = range_type.lower() # one of bit/hex/byte - self.message_indices = set() if message_indices is None else set(message_indices) + self.message_indices = ( + set() if message_indices is None else set(message_indices) + ) """ Set of message indices, this range applies to """ @@ -46,7 +57,12 @@ def bit_start(self): @property def bit_end(self): - return self.__convert_number(self.start) + self.__convert_number(self.length) - 1 + self.sync_end + return ( + self.__convert_number(self.start) + + self.__convert_number(self.length) + - 1 + + self.sync_end + ) @property def length_in_bits(self): @@ -85,9 +101,11 @@ def byte_order_is_unknown(self) -> bool: return self.__byte_order is None def matches(self, start: int, value: np.ndarray): - return self.start == start and \ - self.length == len(value) and \ - self.value.tobytes() == value.tobytes() + return ( + self.start == start + and self.length == len(value) + and self.value.tobytes() == value.tobytes() + ) def __convert_number(self, n): if self.range_type == "bit": @@ -100,22 +118,31 @@ def __convert_number(self, n): raise ValueError("Unknown range type {}".format(self.range_type)) def __repr__(self): - result = "{} {}-{} ({} {})".format(self.field_type, self.bit_start, - self.bit_end, self.length, self.range_type) + result = "{} {}-{} ({} {})".format( + self.field_type, self.bit_start, self.bit_end, self.length, self.range_type + ) - result += " Values: " + " ".join(map(util.convert_numbers_to_hex_string, self.values)) + result += " Values: " + " ".join( + map(util.convert_numbers_to_hex_string, self.values) + ) if self.score is not None: result += " Score: " + str(self.score) - result += " Message indices: {" + ",".join(map(str, sorted(self.message_indices))) + "}" + result += ( + " Message indices: {" + + ",".join(map(str, sorted(self.message_indices))) + + "}" + ) return result def __eq__(self, other): if not isinstance(other, CommonRange): return False - return self.bit_start == other.bit_start and \ - self.bit_end == other.bit_end and \ - self.field_type == other.field_type + return ( + self.bit_start == other.bit_start + and self.bit_end == other.bit_end + and self.field_type == other.field_type + ) def __hash__(self): return hash((self.start, self.length, self.field_type)) @@ -126,8 +153,10 @@ def __lt__(self, other): def overlaps_with(self, other) -> bool: if not isinstance(other, CommonRange): raise ValueError("Need another bit range to compare") - return any(i in range(self.bit_start, self.bit_end) - for i in range(other.bit_start, other.bit_end)) + return any( + i in range(self.bit_start, self.bit_end) + for i in range(other.bit_start, other.bit_end) + ) def ensure_not_overlaps(self, start: int, end: int): """ @@ -145,14 +174,16 @@ def ensure_not_overlaps(self, start: int, end: int): result = copy.deepcopy(self) result.length -= end - result.start result.start = end - result.value = result.value[result.start-self.start:(result.start-self.start)+result.length] + result.value = result.value[ + result.start - self.start : (result.start - self.start) + result.length + ] return [result] if self.start < start <= self.end <= end: # overlaps on the right result = copy.deepcopy(self) result.length -= self.end + 1 - start - result.value = result.value[:result.length] + result.value = result.value[: result.length] return [result] if self.start < start and self.end > end: @@ -160,21 +191,36 @@ def ensure_not_overlaps(self, start: int, end: int): left = copy.deepcopy(self) right = copy.deepcopy(self) - left.length -= (left.end + 1 - start) - left.value = self.value[:left.length] + left.length -= left.end + 1 - start + left.value = self.value[: left.length] right.start = end + 1 right.length = self.end - end - right.value = self.value[right.start-self.start:(right.start-self.start)+right.length] + right.value = self.value[ + right.start - self.start : (right.start - self.start) + right.length + ] return [left, right] return [] class ChecksumRange(CommonRange): - def __init__(self, start, length, crc: GenericCRC, data_range_start, data_range_end, value: np.ndarray = None, - score=0, field_type="Generic", message_indices=None, range_type="bit"): - super().__init__(start, length, value, score, field_type, message_indices, range_type) + def __init__( + self, + start, + length, + crc: GenericCRC, + data_range_start, + data_range_end, + value: np.ndarray = None, + score=0, + field_type="Generic", + message_indices=None, + range_type="bit", + ): + super().__init__( + start, length, value, score, field_type, message_indices, range_type + ) self.data_range_start = data_range_start self.data_range_end = data_range_end self.crc = crc @@ -188,18 +234,31 @@ def data_range_bit_end(self): return self.data_range_end + self.sync_end def __eq__(self, other): - return super().__eq__(other) \ - and self.data_range_start == other.data_range_start \ - and self.data_range_end == other.data_range_end \ - and self.crc == other.crc + return ( + super().__eq__(other) + and self.data_range_start == other.data_range_start + and self.data_range_end == other.data_range_end + and self.crc == other.crc + ) def __hash__(self): - return hash((self.start, self.length, self.data_range_start, self.data_range_end, self.crc)) + return hash( + ( + self.start, + self.length, + self.data_range_start, + self.data_range_end, + self.crc, + ) + ) def __repr__(self): - return super().__repr__() + " \t" + \ - "{}".format(self.crc.caption) + \ - " Datarange: {}-{} ".format(self.data_range_start, self.data_range_end) + return ( + super().__repr__() + + " \t" + + "{}".format(self.crc.caption) + + " Datarange: {}-{} ".format(self.data_range_start, self.data_range_end) + ) class EmptyCommonRange(CommonRange): @@ -212,8 +271,9 @@ def __init__(self, field_type="Generic"): self.field_type = field_type def __eq__(self, other): - return isinstance(other, EmptyCommonRange) \ - and other.field_type == self.field_type + return ( + isinstance(other, EmptyCommonRange) and other.field_type == self.field_type + ) def __repr__(self): return "No " + self.field_type @@ -229,7 +289,6 @@ class CommonRangeContainer(object): """ def __init__(self, ranges: list, message_indices: set = None): - assert isinstance(ranges, list) self.__ranges = ranges # type: list[CommonRange] @@ -287,10 +346,14 @@ def __getitem__(self, item): def __repr__(self): from pprint import pformat + return pformat(self.__ranges) def __eq__(self, other): if not isinstance(other, CommonRangeContainer): return False - return self.__ranges == other.__ranges and self.message_indices == other.message_indices + return ( + self.__ranges == other.__ranges + and self.message_indices == other.message_indices + ) diff --git a/src/urh/awre/FormatFinder.py b/src/urh/awre/FormatFinder.py index ae2be2d8f2..79c39fef26 100644 --- a/src/urh/awre/FormatFinder.py +++ b/src/urh/awre/FormatFinder.py @@ -5,7 +5,12 @@ import numpy as np from urh.awre import AutoAssigner -from urh.awre.CommonRange import CommonRange, EmptyCommonRange, CommonRangeContainer, ChecksumRange +from urh.awre.CommonRange import ( + CommonRange, + EmptyCommonRange, + CommonRangeContainer, + ChecksumRange, +) from urh.awre.Preprocessor import Preprocessor from urh.awre.engines.AddressEngine import AddressEngine from urh.awre.engines.ChecksumEngine import ChecksumEngine @@ -32,25 +37,43 @@ def __init__(self, messages, participants=None, shortest_field_length=None): if participants is not None: AutoAssigner.auto_assign_participants(messages, participants) - existing_message_types_by_msg = {i: msg.message_type for i, msg in enumerate(messages)} + existing_message_types_by_msg = { + i: msg.message_type for i, msg in enumerate(messages) + } self.existing_message_types = defaultdict(list) for i, message_type in existing_message_types_by_msg.items(): self.existing_message_types[message_type].append(i) - preprocessor = Preprocessor(self.get_bitvectors_from_messages(messages), existing_message_types_by_msg) - self.preamble_starts, self.preamble_lengths, sync_len = preprocessor.preprocess() + preprocessor = Preprocessor( + self.get_bitvectors_from_messages(messages), existing_message_types_by_msg + ) + ( + self.preamble_starts, + self.preamble_lengths, + sync_len, + ) = preprocessor.preprocess() self.sync_ends = self.preamble_starts + self.preamble_lengths + sync_len n = shortest_field_length if n is None: # 0 = no sync found - n = 8 if sync_len >= 8 else 4 if sync_len >= 4 else 1 if sync_len >= 1 else 0 + n = ( + 8 + if sync_len >= 8 + else 4 + if sync_len >= 4 + else 1 + if sync_len >= 1 + else 0 + ) for i, value in enumerate(self.sync_ends): # In doubt it is better to under estimate the sync end if n > 0: - self.sync_ends[i] = n * max(int(math.floor((value - self.preamble_starts[i]) / n)), 1) + \ - self.preamble_starts[i] + self.sync_ends[i] = ( + n * max(int(math.floor((value - self.preamble_starts[i]) / n)), 1) + + self.preamble_starts[i] + ) else: self.sync_ends[i] = self.preamble_starts[i] @@ -61,12 +84,21 @@ def __init__(self, messages, participants=None, shortest_field_length=None): self.hexvectors = self.get_hexvectors(self.bitvectors) self.current_iteration = 0 - participants = list(sorted(set(msg.participant for msg in messages if msg.participant is not None))) - self.participant_indices = [participants.index(msg.participant) if msg.participant is not None else -1 - for msg in messages] + participants = list( + sorted( + set(msg.participant for msg in messages if msg.participant is not None) + ) + ) + self.participant_indices = [ + participants.index(msg.participant) if msg.participant is not None else -1 + for msg in messages + ] self.known_participant_addresses = { - participants.index(p): np.array([int(h, 16) for h in p.address_hex], dtype=np.uint8) - for p in participants if p and p.address_hex + participants.index(p): np.array( + [int(h, 16) for h in p.address_hex], dtype=np.uint8 + ) + for p in participants + if p and p.address_hex } @property @@ -92,34 +124,65 @@ def perform_iteration_for_message_type(self, message_type: MessageType): # because if the existing labels would have different sync positions, # they would not belong to the same message type in the first place sync_end = self.sync_ends[indices[0]] if indices else 0 - already_labeled = [(lbl.start - sync_end, lbl.end - sync_end) for lbl in message_type if lbl.start >= sync_end] + already_labeled = [ + (lbl.start - sync_end, lbl.end - sync_end) + for lbl in message_type + if lbl.start >= sync_end + ] if not message_type.get_first_label_with_type(FieldType.Function.LENGTH): - engines.append(LengthEngine([self.bitvectors[i] for i in indices], already_labeled=already_labeled)) + engines.append( + LengthEngine( + [self.bitvectors[i] for i in indices], + already_labeled=already_labeled, + ) + ) if not message_type.get_first_label_with_type(FieldType.Function.SRC_ADDRESS): - engines.append(AddressEngine([self.hexvectors[i] for i in indices], - [self.participant_indices[i] for i in indices], - self.known_participant_addresses, - already_labeled=already_labeled)) + engines.append( + AddressEngine( + [self.hexvectors[i] for i in indices], + [self.participant_indices[i] for i in indices], + self.known_participant_addresses, + already_labeled=already_labeled, + ) + ) elif not message_type.get_first_label_with_type(FieldType.Function.DST_ADDRESS): - engines.append(AddressEngine([self.hexvectors[i] for i in indices], - [self.participant_indices[i] for i in indices], - self.known_participant_addresses, - already_labeled=already_labeled, - src_field_present=True)) - - if not message_type.get_first_label_with_type(FieldType.Function.SEQUENCE_NUMBER): - engines.append(SequenceNumberEngine([self.bitvectors[i] for i in indices], already_labeled=already_labeled)) + engines.append( + AddressEngine( + [self.hexvectors[i] for i in indices], + [self.participant_indices[i] for i in indices], + self.known_participant_addresses, + already_labeled=already_labeled, + src_field_present=True, + ) + ) + + if not message_type.get_first_label_with_type( + FieldType.Function.SEQUENCE_NUMBER + ): + engines.append( + SequenceNumberEngine( + [self.bitvectors[i] for i in indices], + already_labeled=already_labeled, + ) + ) if not message_type.get_first_label_with_type(FieldType.Function.CHECKSUM): # If checksum was not found in first iteration, it will also not be found in next one if self.current_iteration == 0: - engines.append(ChecksumEngine([self.bitvectors[i] for i in indices], already_labeled=already_labeled)) + engines.append( + ChecksumEngine( + [self.bitvectors[i] for i in indices], + already_labeled=already_labeled, + ) + ) result = set() for engine in engines: high_scored_ranges = engine.find() # type: list[CommonRange] - high_scored_ranges = self.retransform_message_indices(high_scored_ranges, indices, self.sync_ends) + high_scored_ranges = self.retransform_message_indices( + high_scored_ranges, indices, self.sync_ends + ) merged_ranges = self.merge_common_ranges(high_scored_ranges) result.update(merged_ranges) return result @@ -128,22 +191,39 @@ def perform_iteration(self) -> bool: new_field_found = False for message_type in self.existing_message_types.copy(): - new_fields_for_message_type = self.perform_iteration_for_message_type(message_type) + new_fields_for_message_type = self.perform_iteration_for_message_type( + message_type + ) new_fields_for_message_type.update( - self.get_preamble_and_sync(self.preamble_starts, self.preamble_lengths, self.sync_ends, - message_type_indices=self.existing_message_types[message_type]) + self.get_preamble_and_sync( + self.preamble_starts, + self.preamble_lengths, + self.sync_ends, + message_type_indices=self.existing_message_types[message_type], + ) ) self.remove_overlapping_fields(new_fields_for_message_type, message_type) - containers = self.create_common_range_containers(new_fields_for_message_type) + containers = self.create_common_range_containers( + new_fields_for_message_type + ) # Store addresses of participants if we found a SRC address field - participants_with_unknown_address = set(self.participant_indices) - set(self.known_participant_addresses) + participants_with_unknown_address = set(self.participant_indices) - set( + self.known_participant_addresses + ) participants_with_unknown_address.discard(-1) if participants_with_unknown_address: for container in containers: - src_range = next((rng for rng in container if rng.field_type == "source address"), None) + src_range = next( + ( + rng + for rng in container + if rng.field_type == "source address" + ), + None, + ) if src_range is None: continue for msg_index in src_range.message_indices: @@ -152,7 +232,9 @@ def perform_iteration(self) -> bool: p = self.participant_indices[msg_index] if p not in self.known_participant_addresses: hex_vector = self.hexvectors[msg_index] - self.known_participant_addresses[p] = hex_vector[src_range.start:src_range.end + 1] + self.known_participant_addresses[p] = hex_vector[ + src_range.start : src_range.end + 1 + ] participants_with_unknown_address.discard(p) new_field_found |= len(containers) > 0 @@ -167,13 +249,17 @@ def perform_iteration(self) -> bool: new_message_type = copy.deepcopy(message_type) # type: MessageType if i > 0: - new_message_type.name = "Message Type {}.{}".format(self.current_iteration+1, i) + new_message_type.name = "Message Type {}.{}".format( + self.current_iteration + 1, i + ) new_message_type.give_new_id() for rng in container: self.add_range_to_message_type(rng, new_message_type) - self.existing_message_types[new_message_type].extend(sorted(container.message_indices)) + self.existing_message_types[new_message_type].extend( + sorted(container.message_indices) + ) return new_field_found @@ -184,11 +270,13 @@ def run(self, max_iterations=10): if len(self.message_types) > 0: messages_without_message_type = set(range(len(self.bitvectors))) - set( - i for l in self.existing_message_types.values() for i in l) + i for l in self.existing_message_types.values() for i in l + ) # add to default message type - self.existing_message_types[self.message_types[0]].extend(list(messages_without_message_type)) - + self.existing_message_types[self.message_types[0]].extend( + list(messages_without_message_type) + ) @staticmethod def remove_overlapping_fields(common_ranges, message_type: MessageType): @@ -204,7 +292,10 @@ def remove_overlapping_fields(common_ranges, message_type: MessageType): for rng in common_ranges.copy(): for lbl in message_type: # type: ProtocolLabel - if any(i in range(rng.bit_start, rng.bit_end) for i in range(lbl.start, lbl.end)): + if any( + i in range(rng.bit_start, rng.bit_end) + for i in range(lbl.start, lbl.end) + ): common_ranges.discard(rng) break @@ -220,10 +311,13 @@ def merge_common_ranges(common_ranges): for common_range in common_ranges: assert isinstance(common_range, CommonRange) try: - same_range = next(rng for rng in merged_ranges - if rng.bit_start == common_range.bit_start - and rng.bit_end == common_range.bit_end - and rng.field_type == common_range.field_type) + same_range = next( + rng + for rng in merged_ranges + if rng.bit_start == common_range.bit_start + and rng.bit_end == common_range.bit_end + and rng.field_type == common_range.field_type + ) same_range.values.extend(common_range.values) same_range.message_indices.update(common_range.message_indices) except StopIteration: @@ -234,17 +328,21 @@ def merge_common_ranges(common_ranges): @staticmethod def add_range_to_message_type(common_range: CommonRange, message_type: MessageType): field_type = FieldType.from_caption(common_range.field_type) - label = message_type.add_protocol_label(name=common_range.field_type, - start=common_range.bit_start, end=common_range.bit_end, - auto_created=True, - type=field_type - ) + label = message_type.add_protocol_label( + name=common_range.field_type, + start=common_range.bit_start, + end=common_range.bit_end, + auto_created=True, + type=field_type, + ) label.display_endianness = common_range.byte_order if field_type.function == FieldType.Function.CHECKSUM: assert isinstance(label, ChecksumLabel) assert isinstance(common_range, ChecksumRange) - label.data_ranges = [[common_range.data_range_bit_start, common_range.data_range_bit_end]] + label.data_ranges = [ + [common_range.data_range_bit_start, common_range.data_range_bit_end] + ] if isinstance(common_range.crc, WSPChecksum): label.category = ChecksumLabel.Category.wsp @@ -261,7 +359,10 @@ def get_bitvectors_from_messages(messages: list, sync_ends: np.ndarray = None): if sync_ends is None: sync_ends = defaultdict(lambda: None) - return [np.array(msg.decoded_bits[sync_ends[i]:], dtype=np.uint8, order="C") for i, msg in enumerate(messages)] + return [ + np.array(msg.decoded_bits[sync_ends[i] :], dtype=np.uint8, order="C") + for i, msg in enumerate(messages) + ] @staticmethod def create_common_range_containers(label_set: set, num_messages: int = None): @@ -275,16 +376,31 @@ def create_common_range_containers(label_set: set, num_messages: int = None): :rtype: list of CommonRangeContainer """ if num_messages is None: - message_indices = sorted(set(i for rng in label_set for i in rng.message_indices)) + message_indices = sorted( + set(i for rng in label_set for i in rng.message_indices) + ) else: message_indices = range(num_messages) result = [] for i in message_indices: - labels = sorted(set(rng for rng in label_set if i in rng.message_indices - and not isinstance(rng, EmptyCommonRange))) + labels = sorted( + set( + rng + for rng in label_set + if i in rng.message_indices + and not isinstance(rng, EmptyCommonRange) + ) + ) - container = next((container for container in result if container.has_same_ranges(labels)), None) + container = next( + ( + container + for container in result + if container.has_same_ranges(labels) + ), + None, + ) if container is None: result.append(CommonRangeContainer(labels, message_indices={i})) else: @@ -305,13 +421,21 @@ def handle_overlapping_conflict(containers): result = [] for container in containers: if container.ranges_overlap: - conflicted_handled = FormatFinder.__handle_container_overlapping_conflict(container) + conflicted_handled = ( + FormatFinder.__handle_container_overlapping_conflict(container) + ) else: conflicted_handled = container try: - same_rng_container = next(c for c in result if c.has_same_ranges_as_container(conflicted_handled)) - same_rng_container.message_indices.update(conflicted_handled.message_indices) + same_rng_container = next( + c + for c in result + if c.has_same_ranges_as_container(conflicted_handled) + ) + same_rng_container.message_indices.update( + conflicted_handled.message_indices + ) except StopIteration: result.append(conflicted_handled) @@ -356,23 +480,31 @@ def __handle_container_overlapping_conflict(container: CommonRangeContainer): possible_solutions = [] for i, rng in enumerate(partition): # Append every range to this solution that does not overlap with current rng - solution = [rng] + [r for r in partition[i + 1:] if not rng.overlaps_with(r)] + solution = [rng] + [ + r for r in partition[i + 1 :] if not rng.overlaps_with(r) + ] possible_solutions.append(solution) # Take solution that maximizes score. In case of tie, choose solution with shorter total length. # if there is still a tie prefer solution that contains a length field as is is very likely to be correct # if nothing else helps break tie by names of field types to prevent randomness - best_solution = max(possible_solutions, - key=lambda sol: (sum(r.score for r in sol), - -sum(r.length_in_bits for r in sol), - "length" in {r.field_type for r in sol}, - "".join(r.field_type[0] for r in sol))) + best_solution = max( + possible_solutions, + key=lambda sol: ( + sum(r.score for r in sol), + -sum(r.length_in_bits for r in sol), + "length" in {r.field_type for r in sol}, + "".join(r.field_type[0] for r in sol), + ), + ) result.extend(best_solution) return CommonRangeContainer(result, message_indices=container.message_indices) @staticmethod - def retransform_message_indices(common_ranges, message_type_indices: list, sync_ends) -> list: + def retransform_message_indices( + common_ranges, message_type_indices: list, sync_ends + ) -> list: """ Retransform the found message indices of an engine to the original index space based on the message indices of the message type. @@ -388,21 +520,28 @@ def retransform_message_indices(common_ranges, message_type_indices: list, sync_ result = [] for common_range in common_ranges: # Retransform message indices into original space - message_indices = np.fromiter((message_type_indices[i] for i in common_range.message_indices), - dtype=int, count=len(common_range.message_indices)) + message_indices = np.fromiter( + (message_type_indices[i] for i in common_range.message_indices), + dtype=int, + count=len(common_range.message_indices), + ) # If we have different sync_ends we need to create a new common range for each different sync_length matching_sync_ends = sync_ends[message_indices] for sync_end in np.unique(matching_sync_ends): rng = copy.deepcopy(common_range) rng.sync_end = sync_end - rng.message_indices = set(message_indices[np.nonzero(matching_sync_ends == sync_end)]) + rng.message_indices = set( + message_indices[np.nonzero(matching_sync_ends == sync_end)] + ) result.append(rng) return result @staticmethod - def get_preamble_and_sync(preamble_starts, preamble_lengths, sync_ends, message_type_indices): + def get_preamble_and_sync( + preamble_starts, preamble_lengths, sync_ends, message_type_indices + ): """ Get preamble and sync common ranges based on the data @@ -416,7 +555,12 @@ def get_preamble_and_sync(preamble_starts, preamble_lengths, sync_ends, message_ result = set() # type: set[CommonRange] for i in message_type_indices: - preamble = CommonRange(preamble_starts[i], preamble_lengths[i], field_type="preamble", message_indices={i}) + preamble = CommonRange( + preamble_starts[i], + preamble_lengths[i], + field_type="preamble", + message_indices={i}, + ) existing_preamble = next((rng for rng in result if preamble == rng), None) if existing_preamble is not None: existing_preamble.message_indices.add(i) @@ -425,7 +569,12 @@ def get_preamble_and_sync(preamble_starts, preamble_lengths, sync_ends, message_ preamble_end = preamble_starts[i] + preamble_lengths[i] sync_end = sync_ends[i] - sync = CommonRange(preamble_end, sync_end - preamble_end, field_type="synchronization", message_indices={i}) + sync = CommonRange( + preamble_end, + sync_end - preamble_end, + field_type="synchronization", + message_indices={i}, + ) existing_sync = next((rng for rng in result if sync == rng), None) if existing_sync is not None: existing_sync.message_indices.add(i) diff --git a/src/urh/awre/Histogram.py b/src/urh/awre/Histogram.py index b863de6cea..8bf6661778 100644 --- a/src/urh/awre/Histogram.py +++ b/src/urh/awre/Histogram.py @@ -22,13 +22,17 @@ def __init__(self, vectors, indices=None, normalize=True, debug=False): :param normalize: """ self.__vectors = vectors # type: list[np.ndarray] - self.__active_indices = list(range(len(vectors))) if indices is None else indices + self.__active_indices = ( + list(range(len(vectors))) if indices is None else indices + ) self.normalize = normalize self.data = self.__create_histogram() def __create_histogram(self): - return awre_util.create_difference_histogram(self.__vectors, self.__active_indices) + return awre_util.create_difference_histogram( + self.__vectors, self.__active_indices + ) def __repr__(self): return str(self.data.tolist()) @@ -58,15 +62,29 @@ def find_common_ranges(self, alpha=0.95, range_type="bit"): else: if length >= 2: value = self.__get_value_for_common_range(start, length) - result.append(CommonRange(start, length, value, message_indices=set(self.__active_indices), - range_type=range_type)) + result.append( + CommonRange( + start, + length, + value, + message_indices=set(self.__active_indices), + range_type=range_type, + ) + ) start, length = None, 0 if i == len(data_indices) - 1 and length >= 2: value = self.__get_value_for_common_range(start, length) - result.append(CommonRange(start, length, value, message_indices=set(self.__active_indices), - range_type=range_type)) + result.append( + CommonRange( + start, + length, + value, + message_indices=set(self.__active_indices), + range_type=range_type, + ) + ) return result @@ -81,10 +99,10 @@ def __get_value_for_common_range(self, start: int, length: int): values = defaultdict(list) for i in self.__active_indices: vector = self.__vectors[i] - values[vector[start:start + length].tostring()].append(i) + values[vector[start : start + length].tostring()].append(i) value = max(values, key=lambda x: len(x)) indices = values[value] - return self.__vectors[indices[0]][start:start + length] + return self.__vectors[indices[0]][start : start + length] def __vector_to_string(self, data_vector) -> str: lut = {i: "{0:x}".format(i) for i in range(16)} @@ -92,6 +110,7 @@ def __vector_to_string(self, data_vector) -> str: def plot(self): import matplotlib.pyplot as plt + self.subplot_on(plt) plt.show() diff --git a/src/urh/awre/MessageTypeBuilder.py b/src/urh/awre/MessageTypeBuilder.py index a35a02a577..5190887e0e 100644 --- a/src/urh/awre/MessageTypeBuilder.py +++ b/src/urh/awre/MessageTypeBuilder.py @@ -10,7 +10,7 @@ def __init__(self, name: str): self.name = name self.message_type = MessageType(name) - def add_label(self, label_type: FieldType.Function, length: int, name: str=None): + def add_label(self, label_type: FieldType.Function, length: int, name: str = None): try: start = self.message_type[-1].end color_index = self.message_type[-1].color_index + 1 @@ -20,10 +20,18 @@ def add_label(self, label_type: FieldType.Function, length: int, name: str=None) if name is None: name = label_type.value - lbl = ProtocolLabel(name, start, start+length-1, color_index, field_type=FieldType(label_type.name, label_type)) + lbl = ProtocolLabel( + name, + start, + start + length - 1, + color_index, + field_type=FieldType(label_type.name, label_type), + ) self.message_type.append(lbl) - def add_checksum_label(self, length, checksum, data_start=None, data_end=None, name: str=None): + def add_checksum_label( + self, length, checksum, data_start=None, data_end=None, name: str = None + ): label_type = FieldType.Function.CHECKSUM try: start = self.message_type[-1].end @@ -36,11 +44,15 @@ def add_checksum_label(self, length, checksum, data_start=None, data_end=None, n if data_start is None: # End of sync or preamble - sync_label = self.message_type.get_first_label_with_type(FieldType.Function.SYNC) + sync_label = self.message_type.get_first_label_with_type( + FieldType.Function.SYNC + ) if sync_label: data_start = sync_label.end else: - preamble_label = self.message_type.get_first_label_with_type(FieldType.Function.PREAMBLE) + preamble_label = self.message_type.get_first_label_with_type( + FieldType.Function.PREAMBLE + ) if preamble_label: data_start = preamble_label.end else: @@ -49,7 +61,13 @@ def add_checksum_label(self, length, checksum, data_start=None, data_end=None, n if data_end is None: data_end = start - lbl = ChecksumLabel(name, start, start+length-1, color_index, field_type=FieldType(label_type.name, label_type)) + lbl = ChecksumLabel( + name, + start, + start + length - 1, + color_index, + field_type=FieldType(label_type.name, label_type), + ) lbl.data_ranges = [(data_start, data_end)] lbl.checksum = checksum self.message_type.append(lbl) diff --git a/src/urh/awre/Preprocessor.py b/src/urh/awre/Preprocessor.py index 0747899827..9c65ef0aa6 100644 --- a/src/urh/awre/Preprocessor.py +++ b/src/urh/awre/Preprocessor.py @@ -22,7 +22,9 @@ class Preprocessor(object): def __init__(self, bitvectors: list, existing_message_types: dict = None): self.bitvectors = bitvectors # type: list[np.ndarray] - self.existing_message_types = existing_message_types if existing_message_types is not None else dict() + self.existing_message_types = ( + existing_message_types if existing_message_types is not None else dict() + ) def preprocess(self) -> (np.ndarray, int): raw_preamble_positions = self.get_raw_preamble_positions() @@ -34,11 +36,15 @@ def preprocess(self) -> (np.ndarray, int): sync_words = existing_sync_words preamble_starts = raw_preamble_positions[:, 0] - preamble_lengths = self.get_preamble_lengths_from_sync_words(sync_words, preamble_starts=preamble_starts) + preamble_lengths = self.get_preamble_lengths_from_sync_words( + sync_words, preamble_starts=preamble_starts + ) sync_len = len(sync_words[0]) if len(sync_words) > 0 else 0 return preamble_starts, preamble_lengths, sync_len - def get_preamble_lengths_from_sync_words(self, sync_words: list, preamble_starts: np.ndarray): + def get_preamble_lengths_from_sync_words( + self, sync_words: list, preamble_starts: np.ndarray + ): """ Get the preamble lengths based on the found sync words for all messages. If there should be more than one sync word in a message, use the first one. @@ -65,7 +71,9 @@ def get_preamble_lengths_from_sync_words(self, sync_words: list, preamble_starts preamble_lengths.append(sync_start - preamble_starts[i]) # Consider case where sync word starts with preamble pattern - sync_start = bits.find(sync_word, sync_start + 1, sync_start + 2 * len(sync_word)) + sync_start = bits.find( + sync_word, sync_start + 1, sync_start + 2 * len(sync_word) + ) if sync_start != -1: if sync_start - preamble_starts[i] >= 2: @@ -79,12 +87,18 @@ def get_preamble_lengths_from_sync_words(self, sync_words: list, preamble_starts result[i] = preamble_lengths[0] else: # consider all indices not more than one byte before first one - preamble_lengths = list(filter(lambda x: x < preamble_lengths[0] + 7, preamble_lengths)) + preamble_lengths = list( + filter(lambda x: x < preamble_lengths[0] + 7, preamble_lengths) + ) # take the smallest preamble_length, but prefer a greater one if it is divisible by 8 (or 4) - preamble_length = next((pl for pl in preamble_lengths if pl % 8 == 0), None) + preamble_length = next( + (pl for pl in preamble_lengths if pl % 8 == 0), None + ) if preamble_length is None: - preamble_length = next((pl for pl in preamble_lengths if pl % 4 == 0), None) + preamble_length = next( + (pl for pl in preamble_lengths if pl % 4 == 0), None + ) if preamble_length is None: preamble_length = preamble_lengths[0] result[i] = preamble_length @@ -95,7 +109,9 @@ def find_possible_syncs(self, raw_preamble_positions=None): difference_matrix = self.get_difference_matrix() if raw_preamble_positions is None: raw_preamble_positions = self.get_raw_preamble_positions() - return self.determine_sync_candidates(raw_preamble_positions, difference_matrix, n_gram_length=4) + return self.determine_sync_candidates( + raw_preamble_positions, difference_matrix, n_gram_length=4 + ) @staticmethod def merge_possible_sync_words(possible_sync_words: dict, n_gram_length: int): @@ -112,25 +128,31 @@ def merge_possible_sync_words(possible_sync_words: dict, n_gram_length: int): for sync1, sync2 in itertools.combinations(possible_sync_words, 2): common_prefix = os.path.commonprefix([sync1, sync2]) if len(common_prefix) > n_gram_length: - result[common_prefix] += possible_sync_words[sync1] + possible_sync_words[sync2] + result[common_prefix] += ( + possible_sync_words[sync1] + possible_sync_words[sync2] + ) else: result[sync1] += possible_sync_words[sync1] result[sync2] += possible_sync_words[sync2] return result - def determine_sync_candidates(self, - raw_preamble_positions: np.ndarray, - difference_matrix: np.ndarray, - n_gram_length=4) -> list: - - possible_sync_words = awre_util.find_possible_sync_words(difference_matrix, raw_preamble_positions, - self.bitvectors, n_gram_length) + def determine_sync_candidates( + self, + raw_preamble_positions: np.ndarray, + difference_matrix: np.ndarray, + n_gram_length=4, + ) -> list: + possible_sync_words = awre_util.find_possible_sync_words( + difference_matrix, raw_preamble_positions, self.bitvectors, n_gram_length + ) self.__debug("Possible sync words", possible_sync_words) if len(possible_sync_words) == 0: return [] - possible_sync_words = self.merge_possible_sync_words(possible_sync_words, n_gram_length) + possible_sync_words = self.merge_possible_sync_words( + possible_sync_words, n_gram_length + ) self.__debug("Merged sync words", possible_sync_words) scores = self.__score_sync_lengths(possible_sync_words) @@ -138,17 +160,24 @@ def determine_sync_candidates(self, sorted_scores = sorted(scores, reverse=True, key=scores.get) estimated_sync_length = sorted_scores[0] if estimated_sync_length % 8 != 0: - for other in filter(lambda x: 0 < estimated_sync_length-x < 7, sorted_scores): + for other in filter( + lambda x: 0 < estimated_sync_length - x < 7, sorted_scores + ): if other % 8 == 0: estimated_sync_length = other break # Now we look at all possible sync words with this length - sync_words = {word: frequency for word, frequency in possible_sync_words.items() - if len(word) == estimated_sync_length} + sync_words = { + word: frequency + for word, frequency in possible_sync_words.items() + if len(word) == estimated_sync_length + } self.__debug("Sync words", sync_words) - additional_syncs = self.__find_additional_sync_words(estimated_sync_length, sync_words, possible_sync_words) + additional_syncs = self.__find_additional_sync_words( + estimated_sync_length, sync_words, possible_sync_words + ) if additional_syncs: self.__debug("Found additional sync words", additional_syncs) @@ -161,7 +190,9 @@ def determine_sync_candidates(self, return result - def __find_additional_sync_words(self, sync_length: int, present_sync_words, possible_sync_words) -> dict: + def __find_additional_sync_words( + self, sync_length: int, present_sync_words, possible_sync_words + ) -> dict: """ Look for additional sync words, in case we had varying preamble lengths and multiple sync words (see test_with_three_syncs_different_preamble_lengths for an example) @@ -171,29 +202,48 @@ def __find_additional_sync_words(self, sync_length: int, present_sync_words, pos :type possible_sync_words: dict :return: """ - np_syn = [np.fromiter(map(int, sync_word), dtype=np.uint8, count=len(sync_word)) - for sync_word in present_sync_words] - - messages_without_sync = [i for i, bv in enumerate(self.bitvectors) - if not any(awre_util.find_occurrences(bv, s, return_after_first=True) for s in np_syn)] + np_syn = [ + np.fromiter(map(int, sync_word), dtype=np.uint8, count=len(sync_word)) + for sync_word in present_sync_words + ] + + messages_without_sync = [ + i + for i, bv in enumerate(self.bitvectors) + if not any( + awre_util.find_occurrences(bv, s, return_after_first=True) + for s in np_syn + ) + ] result = dict() if len(messages_without_sync) == 0: return result # Is there another sync word that applies to all messages without sync? - additional_candidates = {word: score for word, score in possible_sync_words.items() - if len(word) > sync_length and not any(s in word for s in present_sync_words)} - - for sync in sorted(additional_candidates, key=additional_candidates.get, reverse=True): + additional_candidates = { + word: score + for word, score in possible_sync_words.items() + if len(word) > sync_length + and not any(s in word for s in present_sync_words) + } + + for sync in sorted( + additional_candidates, key=additional_candidates.get, reverse=True + ): if len(messages_without_sync) == 0: break score = additional_candidates[sync] s = sync[:sync_length] np_s = np.fromiter(s, dtype=np.uint8, count=len(s)) - matching = [i for i in messages_without_sync - if awre_util.find_occurrences(self.bitvectors[i], np_s, return_after_first=True)] + matching = [ + i + for i in messages_without_sync + if awre_util.find_occurrences( + self.bitvectors[i], np_s, return_after_first=True + ) + ] if matching: result[s] = score for m in matching: @@ -210,7 +260,9 @@ def get_raw_preamble_positions(self) -> np.ndarray: for i, bitvector in enumerate(self.bitvectors): if i in self.existing_message_types: - preamble_label = self.existing_message_types[i].get_first_label_with_type(FieldType.Function.PREAMBLE) + preamble_label = self.existing_message_types[ + i + ].get_first_label_with_type(FieldType.Function.PREAMBLE) else: preamble_label = None @@ -218,7 +270,11 @@ def get_raw_preamble_positions(self) -> np.ndarray: start, lower, upper = awre_util.get_raw_preamble_position(bitvector) else: # If this message is already labeled with a preamble we just use it's values - start, lower, upper = preamble_label.start, preamble_label.end, preamble_label.end + start, lower, upper = ( + preamble_label.start, + preamble_label.end, + preamble_label.end, + ) result[i, 0] = start result[i, 1] = lower - start @@ -246,12 +302,16 @@ def __get_existing_sync_words(self) -> list: result = [] for i, bitvector in enumerate(self.bitvectors): if i in self.existing_message_types: - sync_label = self.existing_message_types[i].get_first_label_with_type(FieldType.Function.SYNC) + sync_label = self.existing_message_types[i].get_first_label_with_type( + FieldType.Function.SYNC + ) else: sync_label = None if sync_label is not None: - result.append("".join(map(str, bitvector[sync_label.start:sync_label.end]))) + result.append( + "".join(map(str, bitvector[sync_label.start : sync_label.end])) + ) return result def __debug(self, *args): diff --git a/src/urh/awre/ProtocolGenerator.py b/src/urh/awre/ProtocolGenerator.py index b17003daa2..6643775828 100644 --- a/src/urh/awre/ProtocolGenerator.py +++ b/src/urh/awre/ProtocolGenerator.py @@ -20,9 +20,18 @@ class ProtocolGenerator(object): DEFAULT_SYNC = "1001" BROADCAST_ADDRESS = "0xffff" - def __init__(self, message_types: list, participants: list = None, preambles_by_mt=None, - syncs_by_mt=None, little_endian=False, length_in_bytes=True, sequence_numbers=None, - sequence_number_increment=1, message_type_codes=None): + def __init__( + self, + message_types: list, + participants: list = None, + preambles_by_mt=None, + syncs_by_mt=None, + little_endian=False, + length_in_bytes=True, + sequence_numbers=None, + sequence_number_increment=1, + message_type_codes=None, + ): """ :param message_types: @@ -65,7 +74,6 @@ def __init__(self, message_types: list, participants: list = None, preambles_by_ message_type_codes[mt] = i self.message_type_codes = message_type_codes - @property def messages(self): return self.protocol.messages @@ -78,8 +86,11 @@ def __get_address_for_participant(self, participant: Participant): if participant is None: return self.to_bits(self.BROADCAST_ADDRESS) - address = "0x" + participant.address_hex if not participant.address_hex.startswith( - "0x") else participant.address_hex + address = ( + "0x" + participant.address_hex + if not participant.address_hex.startswith("0x") + else participant.address_hex + ) return self.to_bits(address) @staticmethod @@ -93,7 +104,9 @@ def to_bits(bit_or_hex_str: str): def decimal_to_bits(self, number: int, num_bits: int) -> str: len_formats = {8: "B", 16: "H", 32: "I", 64: "Q"} if num_bits not in len_formats: - raise ValueError("Invalid length for length field: {} bits".format(num_bits)) + raise ValueError( + "Invalid length for length field: {} bits".format(num_bits) + ) struct_format = "<" if self.little_endian else ">" struct_format += len_formats[num_bits] @@ -101,10 +114,18 @@ def decimal_to_bits(self, number: int, num_bits: int) -> str: byte_length = struct.pack(struct_format, number) return "".join("{0:08b}".format(byte) for byte in byte_length) - def generate_message(self, message_type=None, data="0x00", source: Participant = None, - destination: Participant = None): + def generate_message( + self, + message_type=None, + data="0x00", + source: Participant = None, + destination: Participant = None, + ): for participant in (source, destination): - if isinstance(participant, Participant) and participant not in self.participants: + if ( + isinstance(participant, Participant) + and participant not in self.participants + ): self.participants.append(participant) if isinstance(message_type, MessageType): @@ -123,7 +144,9 @@ def generate_message(self, message_type=None, data="0x00", source: Participant = start = 0 - data_label_present = mt.get_first_label_with_type(FieldType.Function.DATA) is not None + data_label_present = ( + mt.get_first_label_with_type(FieldType.Function.DATA) is not None + ) if data_label_present: message_length = mt[-1].end - 1 @@ -158,15 +181,26 @@ def generate_message(self, message_type=None, data="0x00", source: Participant = bits.append(self.decimal_to_bits(value, len_field)) elif lbl.field_type.function == FieldType.Function.TYPE: - bits.append(self.decimal_to_bits(self.message_type_codes[mt] % (2 ** len_field), len_field)) + bits.append( + self.decimal_to_bits( + self.message_type_codes[mt] % (2**len_field), len_field + ) + ) elif lbl.field_type.function == FieldType.Function.SEQUENCE_NUMBER: - bits.append(self.decimal_to_bits(self.sequence_numbers[mt] % (2 ** len_field), len_field)) + bits.append( + self.decimal_to_bits( + self.sequence_numbers[mt] % (2**len_field), len_field + ) + ) elif lbl.field_type.function == FieldType.Function.DST_ADDRESS: dst_bits = self.__get_address_for_participant(destination) if len(dst_bits) != len_field: raise ValueError( - "Length of dst ({0} bits) != length dst field ({1} bits)".format(len(dst_bits), len_field)) + "Length of dst ({0} bits) != length dst field ({1} bits)".format( + len(dst_bits), len_field + ) + ) bits.append(dst_bits) elif lbl.field_type.function == FieldType.Function.SRC_ADDRESS: @@ -174,13 +208,19 @@ def generate_message(self, message_type=None, data="0x00", source: Participant = if len(src_bits) != len_field: raise ValueError( - "Length of src ({0} bits) != length src field ({1} bits)".format(len(src_bits), len_field)) + "Length of src ({0} bits) != length src field ({1} bits)".format( + len(src_bits), len_field + ) + ) bits.append(src_bits) elif lbl.field_type.function == FieldType.Function.DATA: if len(data) != len_field: raise ValueError( - "Length of data ({} bits) != length data field ({} bits)".format(len(data), len_field)) + "Length of data ({} bits) != length data field ({} bits)".format( + len(data), len_field + ) + ) bits.append(data) start = lbl.end @@ -194,7 +234,9 @@ def generate_message(self, message_type=None, data="0x00", source: Participant = self.sequence_numbers[mt] += self.sequence_number_increment for checksum_label in checksum_labels: - msg[checksum_label.start:checksum_label.end] = checksum_label.calculate_checksum_for_message(msg, False) + msg[ + checksum_label.start : checksum_label.end + ] = checksum_label.calculate_checksum_for_message(msg, False) self.protocol.messages.append(msg) @@ -206,15 +248,39 @@ def export_message_type_to_latex(message_type, f): f.write(" \\begin{itemize}\n") for lbl in message_type: # type: ProtocolLabel if lbl.field_type.function == FieldType.Function.SYNC: - sync = array("B", map(int, self.syncs_by_message_type[message_type])) - f.write(" \\item {}: \\texttt{{0x{}}}\n".format(lbl.name, util.bit2hex(sync))) + sync = array( + "B", map(int, self.syncs_by_message_type[message_type]) + ) + f.write( + " \\item {}: \\texttt{{0x{}}}\n".format( + lbl.name, util.bit2hex(sync) + ) + ) elif lbl.field_type.function == FieldType.Function.PREAMBLE: - preamble = array("B", map(int, self.preambles_by_message_type[message_type])) - f.write(" \\item {}: \\texttt{{0x{}}}\n".format(lbl.name, util.bit2hex(preamble))) + preamble = array( + "B", map(int, self.preambles_by_message_type[message_type]) + ) + f.write( + " \\item {}: \\texttt{{0x{}}}\n".format( + lbl.name, util.bit2hex(preamble) + ) + ) elif lbl.field_type.function == FieldType.Function.CHECKSUM: - f.write(" \\item {}: {}\n".format(lbl.name, lbl.checksum.caption)) - elif lbl.field_type.function in (FieldType.Function.LENGTH, FieldType.Function.SEQUENCE_NUMBER) and lbl.length > 8: - f.write(" \\item {}: {} bit (\\textbf{{{} endian}})\n".format(lbl.name, lbl.length, "little" if self.little_endian else "big")) + f.write( + " \\item {}: {}\n".format(lbl.name, lbl.checksum.caption) + ) + elif ( + lbl.field_type.function + in (FieldType.Function.LENGTH, FieldType.Function.SEQUENCE_NUMBER) + and lbl.length > 8 + ): + f.write( + " \\item {}: {} bit (\\textbf{{{} endian}})\n".format( + lbl.name, + lbl.length, + "little" if self.little_endian else "big", + ) + ) elif lbl.field_type.function == FieldType.Function.DATA: f.write(" \\item payload: {} byte\n".format(lbl.length // 8)) else: @@ -225,16 +291,35 @@ def export_message_type_to_latex(message_type, f): f.write("\\subsection{{Protocol {}}}\n".format(number)) if len(self.participants) > 1: - f.write("There were {} participants involved in communication: ".format(len(self.participants))) - f.write(", ".join("{} (\\texttt{{0x{}}})".format(p.name, p.address_hex) for p in self.participants[:-1])) - f.write(" and {} (\\texttt{{0x{}}})".format(self.participants[-1].name, self.participants[-1].address_hex)) + f.write( + "There were {} participants involved in communication: ".format( + len(self.participants) + ) + ) + f.write( + ", ".join( + "{} (\\texttt{{0x{}}})".format(p.name, p.address_hex) + for p in self.participants[:-1] + ) + ) + f.write( + " and {} (\\texttt{{0x{}}})".format( + self.participants[-1].name, self.participants[-1].address_hex + ) + ) f.write(".\n") if len(self.message_types) == 1: - f.write("The protocol has one message type with the following fields:\n") + f.write( + "The protocol has one message type with the following fields:\n" + ) export_message_type_to_latex(self.message_types[0], f) else: - f.write("The protocol has {} message types with the following fields:\n".format(len(self.message_types))) + f.write( + "The protocol has {} message types with the following fields:\n".format( + len(self.message_types) + ) + ) f.write("\\begin{itemize}\n") for mt in self.message_types: f.write(" \\item \\textbf{{{}}}\n".format(mt.name)) @@ -244,7 +329,7 @@ def export_message_type_to_latex(message_type, f): f.write("\n") -if __name__ == '__main__': +if __name__ == "__main__": mb = MessageTypeBuilder("test") mb.add_label(FieldType.Function.PREAMBLE, 8) mb.add_label(FieldType.Function.SYNC, 4) @@ -255,6 +340,9 @@ def export_message_type_to_latex(message_type, f): pg = ProtocolGenerator([mb.message_type], [], little_endian=False) pg.generate_message(data="1" * 8) pg.generate_message(data="1" * 16) - pg.generate_message(data="0xab", source=Participant("Alice", "A", "1234"), - destination=Participant("Bob", "B", "4567")) + pg.generate_message( + data="0xab", + source=Participant("Alice", "A", "1234"), + destination=Participant("Bob", "B", "4567"), + ) pg.to_file("/tmp/test.proto") diff --git a/src/urh/awre/engines/AddressEngine.py b/src/urh/awre/engines/AddressEngine.py index 7aa50f1248..e382bed8bb 100644 --- a/src/urh/awre/engines/AddressEngine.py +++ b/src/urh/awre/engines/AddressEngine.py @@ -12,8 +12,14 @@ class AddressEngine(Engine): - def __init__(self, msg_vectors, participant_indices, known_participant_addresses: dict = None, - already_labeled: list = None, src_field_present=False): + def __init__( + self, + msg_vectors, + participant_indices, + known_participant_addresses: dict = None, + already_labeled: list = None, + src_field_present=False, + ): """ :param msg_vectors: Message data behind synchronization @@ -35,7 +41,9 @@ def __init__(self, msg_vectors, participant_indices, known_participant_addresses if already_labeled is not None: for start, end in already_labeled: # convert it to hex - self.already_labeled.append((int(math.ceil(start / 4)), int(math.ceil(end / 4)))) + self.already_labeled.append( + (int(math.ceil(start / 4)), int(math.ceil(end / 4))) + ) self.message_indices_by_participant = defaultdict(list) for i, participant_index in enumerate(self.participant_indices): @@ -44,44 +52,69 @@ def __init__(self, msg_vectors, participant_indices, known_participant_addresses if known_participant_addresses is None: self.known_addresses_by_participant = dict() # type: dict[int, np.ndarray] else: - self.known_addresses_by_participant = known_participant_addresses # type: dict[int, np.ndarray] + self.known_addresses_by_participant = ( + known_participant_addresses + ) # type: dict[int, np.ndarray] @staticmethod def cross_swap_check(rng1: CommonRange, rng2: CommonRange): - return (rng1.start == rng2.start + rng1.length or rng1.start == rng2.start - rng1.length) \ - and rng1.value.tobytes() == rng2.value.tobytes() + return ( + rng1.start == rng2.start + rng1.length + or rng1.start == rng2.start - rng1.length + ) and rng1.value.tobytes() == rng2.value.tobytes() @staticmethod def ack_check(rng1: CommonRange, rng2: CommonRange): - return rng1.start == rng2.start and rng1.length == rng2.length and rng1.value.tobytes() != rng2.value.tobytes() + return ( + rng1.start == rng2.start + and rng1.length == rng2.length + and rng1.value.tobytes() != rng2.value.tobytes() + ) def find(self): - addresses_by_participant = {p: [addr.tostring()] for p, addr in self.known_addresses_by_participant.items()} + addresses_by_participant = { + p: [addr.tostring()] + for p, addr in self.known_addresses_by_participant.items() + } addresses_by_participant.update(self.find_addresses()) self._debug("Addresses by participant", addresses_by_participant) # Find the address candidates by participant in messages ranges_by_participant = defaultdict(list) # type: dict[int, list[CommonRange]] - addresses = [np.array(np.frombuffer(a, dtype=np.uint8)) - for address_list in addresses_by_participant.values() - for a in address_list] + addresses = [ + np.array(np.frombuffer(a, dtype=np.uint8)) + for address_list in addresses_by_participant.values() + for a in address_list + ] - already_labeled_cols = array("L", [e for rng in self.already_labeled for e in range(*rng)]) + already_labeled_cols = array( + "L", [e for rng in self.already_labeled for e in range(*rng)] + ) # Find occurrences of address candidates in messages and create common ranges over matching positions for i, msg_vector in enumerate(self.msg_vectors): participant = self.participant_indices[i] for address in addresses: - for index in awre_util.find_occurrences(msg_vector, address, already_labeled_cols): + for index in awre_util.find_occurrences( + msg_vector, address, already_labeled_cols + ): common_ranges = ranges_by_participant[participant] - rng = next((cr for cr in common_ranges if cr.matches(index, address)), None) # type: CommonRange + rng = next( + (cr for cr in common_ranges if cr.matches(index, address)), None + ) # type: CommonRange if rng is not None: rng.message_indices.add(i) else: - common_ranges.append(CommonRange(index, len(address), address, - message_indices={i}, - range_type="hex")) + common_ranges.append( + CommonRange( + index, + len(address), + address, + message_indices={i}, + range_type="hex", + ) + ) num_messages_by_participant = defaultdict(int) for participant in self.participant_indices: @@ -89,23 +122,37 @@ def find(self): # Look for cross swapped values between participant clusters for p1, p2 in itertools.combinations(ranges_by_participant, 2): - ranges1_set, ranges2_set = set(ranges_by_participant[p1]), set(ranges_by_participant[p2]) + ranges1_set, ranges2_set = set(ranges_by_participant[p1]), set( + ranges_by_participant[p2] + ) - for rng1, rng2 in itertools.product(ranges_by_participant[p1], ranges_by_participant[p2]): + for rng1, rng2 in itertools.product( + ranges_by_participant[p1], ranges_by_participant[p2] + ): if rng1 in ranges2_set and rng2 in ranges1_set: if self.cross_swap_check(rng1, rng2): - rng1.score += len(rng2.message_indices) / num_messages_by_participant[p2] - rng2.score += len(rng1.message_indices) / num_messages_by_participant[p1] + rng1.score += ( + len(rng2.message_indices) / num_messages_by_participant[p2] + ) + rng2.score += ( + len(rng1.message_indices) / num_messages_by_participant[p1] + ) elif self.ack_check(rng1, rng2): # Add previous score in divisor to add bonus to ranges that apply to all messages - rng1.score += len(rng2.message_indices) / (num_messages_by_participant[p2] + rng1.score) - rng2.score += len(rng1.message_indices) / (num_messages_by_participant[p1] + rng2.score) + rng1.score += len(rng2.message_indices) / ( + num_messages_by_participant[p2] + rng1.score + ) + rng2.score += len(rng1.message_indices) / ( + num_messages_by_participant[p1] + rng2.score + ) if len(ranges_by_participant) == 1 and not self.src_field_present: for p, ranges in ranges_by_participant.items(): for rng in sorted(ranges): try: - if np.array_equal(rng.value, self.known_addresses_by_participant[p]): + if np.array_equal( + rng.value, self.known_addresses_by_participant[p] + ): # Only one participant in this iteration and address already known -> Highscore rng.score = 1 break # Take only the first (leftmost) range @@ -120,21 +167,28 @@ def find(self): for participant, common_ranges in ranges_by_participant.items(): # Sort by negative score so ranges with highest score appear first # Secondary sort by tuple to ensure order when ranges have same score - sorted_ranges = sorted(filter(lambda cr: cr.score > self.minimum_score, common_ranges), - key=lambda cr: (-cr.score, cr)) + sorted_ranges = sorted( + filter(lambda cr: cr.score > self.minimum_score, common_ranges), + key=lambda cr: (-cr.score, cr), + ) if len(sorted_ranges) == 0: addresses_by_participant[participant] = dict() continue - addresses_by_participant[participant] = {a for a in addresses_by_participant.get(participant, []) - if len(a) == address_length} + addresses_by_participant[participant] = { + a + for a in addresses_by_participant.get(participant, []) + if len(a) == address_length + } for rng in filter(lambda r: r.length == address_length, sorted_ranges): rng.score = min(rng.score, 1.0) high_scored_ranges_by_participant[participant].append(rng) # Now we find the most probable address for all participants - self.__assign_participant_addresses(addresses_by_participant, high_scored_ranges_by_participant) + self.__assign_participant_addresses( + addresses_by_participant, high_scored_ranges_by_participant + ) # Eliminate participants for which we could not assign an address for participant, address in addresses_by_participant.copy().items(): @@ -152,17 +206,30 @@ def find(self): result = [] for rng in sorted(ranges, key=lambda r: r.score, reverse=True): - rng.field_type = "source address" if rng.value.tostring() == address else "destination address" + rng.field_type = ( + "source address" + if rng.value.tostring() == address + else "destination address" + ) if len(result) == 0: result.append(rng) else: - subset = next((r for r in result if rng.message_indices.issubset(r.message_indices)), None) + subset = next( + ( + r + for r in result + if rng.message_indices.issubset(r.message_indices) + ), + None, + ) if subset is not None: if rng.field_type == subset.field_type: # Avoid adding same address type twice continue - if rng.length != subset.length or (rng.start != subset.end + 1 and rng.end + 1 != subset.start): + if rng.length != subset.length or ( + rng.start != subset.end + 1 and rng.end + 1 != subset.start + ): # Ensure addresses are next to each other continue @@ -170,9 +237,15 @@ def find(self): high_scored_ranges_by_participant[participant] = result - self.__find_broadcast_fields(high_scored_ranges_by_participant, addresses_by_participant) + self.__find_broadcast_fields( + high_scored_ranges_by_participant, addresses_by_participant + ) - result = [rng for ranges in high_scored_ranges_by_participant.values() for rng in ranges] + result = [ + rng + for ranges in high_scored_ranges_by_participant.values() + for rng in ranges + ] # If we did not find a SRC address, lower the score a bit, # so DST fields do not win later e.g. again length fields in case of tie if not any(rng.field_type == "source address" for rng in result): @@ -190,18 +263,26 @@ def __estimate_address_length(self, ranges_by_participant: dict): """ address_lengths = [] for participant, common_ranges in ranges_by_participant.items(): - sorted_ranges = sorted(filter(lambda cr: cr.score > self.minimum_score, common_ranges), - key=lambda cr: (-cr.score, cr)) + sorted_ranges = sorted( + filter(lambda cr: cr.score > self.minimum_score, common_ranges), + key=lambda cr: (-cr.score, cr), + ) max_scored = [r for r in sorted_ranges if r.score == sorted_ranges[0].score] # Prevent overestimation of address length by looking for substrings for rng in max_scored[:]: - same_message_rng = [r for r in sorted_ranges - if r not in max_scored and r.score > 0 and r.message_indices == rng.message_indices] + same_message_rng = [ + r + for r in sorted_ranges + if r not in max_scored + and r.score > 0 + and r.message_indices == rng.message_indices + ] if len(same_message_rng) > 1 and all( - r.value.tobytes() in rng.value.tobytes() for r in same_message_rng): + r.value.tobytes() in rng.value.tobytes() for r in same_message_rng + ): # remove the longer range and add the smaller ones max_scored.remove(rng) max_scored.extend(same_message_rng) @@ -225,7 +306,9 @@ def __estimate_address_length(self, ranges_by_participant: dict): except ValueError: # max() arg is an empty sequence return 0 - def __assign_participant_addresses(self, addresses_by_participant, high_scored_ranges_by_participant): + def __assign_participant_addresses( + self, addresses_by_participant, high_scored_ranges_by_participant + ): scored_participants_addresses = dict() for participant in addresses_by_participant: scored_participants_addresses[participant] = defaultdict(int) @@ -237,8 +320,11 @@ def __assign_participant_addresses(self, addresses_by_participant, high_scored_r continue for i in self.message_indices_by_participant[participant]: - matching = [rng for rng in high_scored_ranges_by_participant[participant] - if i in rng.message_indices and rng.value.tostring() in addresses] + matching = [ + rng + for rng in high_scored_ranges_by_participant[participant] + if i in rng.message_indices and rng.value.tostring() in addresses + ] if len(matching) == 1: address = matching[0].value.tostring() @@ -248,25 +334,44 @@ def __assign_participant_addresses(self, addresses_by_participant, high_scored_r # Since this is probably an ACK, the address is probably SRC of participant of previous message if i > 0 and self.participant_indices[i - 1] != participant: prev_participant = self.participant_indices[i - 1] - prev_matching = [rng for rng in high_scored_ranges_by_participant[prev_participant] - if i - 1 in rng.message_indices and rng.value.tostring() in addresses] + prev_matching = [ + rng + for rng in high_scored_ranges_by_participant[ + prev_participant + ] + if i - 1 in rng.message_indices + and rng.value.tostring() in addresses + ] if len(prev_matching) > 1: - for prev_rng in filter(lambda r: r.value.tostring() == address, prev_matching): - scored_participants_addresses[prev_participant][address] += prev_rng.score + for prev_rng in filter( + lambda r: r.value.tostring() == address, prev_matching + ): + scored_participants_addresses[prev_participant][ + address + ] += prev_rng.score elif len(matching) > 1: # more than one address, so there must be a source address included for rng in matching: - scored_participants_addresses[participant][rng.value.tostring()] += rng.score + scored_participants_addresses[participant][ + rng.value.tostring() + ] += rng.score minimum_score = 0.5 taken_addresses = set() self._debug("Scored addresses", scored_participants_addresses) # If all participants have exactly one possible address and they all differ, we can assign them right away - if all(len(addresses) == 1 for addresses in scored_participants_addresses.values()): - all_addresses = [list(addresses)[0] for addresses in scored_participants_addresses.values()] - if len(all_addresses) == len(set(all_addresses)): # ensure all addresses are different + if all( + len(addresses) == 1 for addresses in scored_participants_addresses.values() + ): + all_addresses = [ + list(addresses)[0] + for addresses in scored_participants_addresses.values() + ] + if len(all_addresses) == len( + set(all_addresses) + ): # ensure all addresses are different for p, addresses in scored_participants_addresses.items(): addresses_by_participant[p] = list(addresses)[0] return @@ -274,10 +379,17 @@ def __assign_participant_addresses(self, addresses_by_participant, high_scored_r for participant, addresses in sorted(scored_participants_addresses.items()): try: # sort filtered results to prevent randomness for equal scores - found_address = max(sorted( - filter(lambda a: a not in taken_addresses and addresses[a] >= minimum_score, addresses), - reverse=True - ), key=addresses.get) + found_address = max( + sorted( + filter( + lambda a: a not in taken_addresses + and addresses[a] >= minimum_score, + addresses, + ), + reverse=True, + ), + key=addresses.get, + ) except ValueError: # Could not assign address for this participant addresses_by_participant[participant] = None @@ -286,7 +398,9 @@ def __assign_participant_addresses(self, addresses_by_participant, high_scored_r addresses_by_participant[participant] = found_address taken_addresses.add(found_address) - def __find_broadcast_fields(self, high_scored_ranges_by_participant, addresses_by_participant: dict): + def __find_broadcast_fields( + self, high_scored_ranges_by_participant, addresses_by_participant: dict + ): """ Last we check for messages that were sent to broadcast 1. we search for messages that have a SRC address but no DST address @@ -302,18 +416,35 @@ def __find_broadcast_fields(self, high_scored_ranges_by_participant, addresses_b broadcast_bag = defaultdict(list) # type: dict[CommonRange, list[int]] for common_ranges in high_scored_ranges_by_participant.values(): - src_address_fields = sorted(filter(lambda r: r.field_type == "source address", common_ranges)) - dst_address_fields = sorted(filter(lambda r: r.field_type == "destination address", common_ranges)) - msg_with_dst = {i for dst_address_field in dst_address_fields for i in dst_address_field.message_indices} + src_address_fields = sorted( + filter(lambda r: r.field_type == "source address", common_ranges) + ) + dst_address_fields = sorted( + filter(lambda r: r.field_type == "destination address", common_ranges) + ) + msg_with_dst = { + i + for dst_address_field in dst_address_fields + for i in dst_address_field.message_indices + } for src_address_field in src_address_fields: # type: CommonRange - msg_without_dst = {i for i in src_address_field.message_indices if i not in msg_with_dst} + msg_without_dst = { + i + for i in src_address_field.message_indices + if i not in msg_with_dst + } if len(msg_without_dst) == 0: continue try: - matching_dst = next(dst for dst in dst_address_fields - if all(i in dst.message_indices - for i in src_address_field.message_indices - msg_without_dst)) + matching_dst = next( + dst + for dst in dst_address_fields + if all( + i in dst.message_indices + for i in src_address_field.message_indices - msg_without_dst + ) + ) except StopIteration: continue for msg in msg_without_dst: @@ -325,7 +456,7 @@ def __find_broadcast_fields(self, high_scored_ranges_by_participant, addresses_b broadcast_address = None for dst, messages in broadcast_bag.items(): for msg_index in messages: - value = self.msg_vectors[msg_index][dst.start:dst.end + 1] + value = self.msg_vectors[msg_index][dst.start : dst.end + 1] if broadcast_address is None: broadcast_address = value elif value.tobytes() != broadcast_address.tobytes(): @@ -350,11 +481,14 @@ def find_addresses(self) -> dict: for i in message_indices: length_clusters[len(self.msg_vectors[i])].append(i) - common_ranges_by_length = self.find_common_ranges_by_cluster(self.msg_vectors, length_clusters, range_type="hex") + common_ranges_by_length = self.find_common_ranges_by_cluster( + self.msg_vectors, length_clusters, range_type="hex" + ) common_ranges_by_participant[participant] = [] for ranges in common_ranges_by_length.values(): - common_ranges_by_participant[participant].extend(self.ignore_already_labeled(ranges, - self.already_labeled)) + common_ranges_by_participant[participant].extend( + self.ignore_already_labeled(ranges, self.already_labeled) + ) self._debug("Common ranges by participant:", common_ranges_by_participant) @@ -367,8 +501,15 @@ def find_addresses(self) -> dict: # If we already know the address length we do not need to bother with other candidates if len(already_assigned) > 0: addr_len = len(self.known_addresses_by_participant[already_assigned[0]]) - if any(len(self.known_addresses_by_participant[i]) != addr_len for i in already_assigned): - logger.warning("Addresses do not have a common length. Assuming length of {}".format(addr_len)) + if any( + len(self.known_addresses_by_participant[i]) != addr_len + for i in already_assigned + ): + logger.warning( + "Addresses do not have a common length. Assuming length of {}".format( + addr_len + ) + ) else: addr_len = None @@ -392,8 +533,16 @@ def find_addresses(self) -> dict: if not p1_already_assigned and not p2_already_assigned: result[p1].add(val.tostring()) result[p2].add(val.tostring()) - elif p1_already_assigned and val.tostring() != self.known_addresses_by_participant[p1].tostring(): + elif ( + p1_already_assigned + and val.tostring() + != self.known_addresses_by_participant[p1].tostring() + ): result[p2].add(val.tostring()) - elif p2_already_assigned and val.tostring() != self.known_addresses_by_participant[p2].tostring(): + elif ( + p2_already_assigned + and val.tostring() + != self.known_addresses_by_participant[p2].tostring() + ): result[p1].add(val.tostring()) return result diff --git a/src/urh/awre/engines/ChecksumEngine.py b/src/urh/awre/engines/ChecksumEngine.py index 9ad5d7a3a7..ccc80944a0 100644 --- a/src/urh/awre/engines/ChecksumEngine.py +++ b/src/urh/awre/engines/ChecksumEngine.py @@ -12,7 +12,13 @@ class ChecksumEngine(Engine): - def __init__(self, bitvectors, n_gram_length=8, minimum_score=0.9, already_labeled: list = None): + def __init__( + self, + bitvectors, + n_gram_length=8, + minimum_score=0.9, + already_labeled: list = None, + ): """ :type bitvectors: list of np.ndarray :param bitvectors: bitvectors behind the synchronization @@ -23,7 +29,9 @@ def __init__(self, bitvectors, n_gram_length=8, minimum_score=0.9, already_label if already_labeled is None: self.already_labeled_cols = set() else: - self.already_labeled_cols = {e for rng in already_labeled for e in range(*rng)} + self.already_labeled_cols = { + e for rng in already_labeled for e in range(*rng) + } def find(self): result = list() @@ -37,31 +45,58 @@ def find(self): checksums_for_length = [] for index in message_indices: bits = self.bitvectors[index] - data_start, data_stop, crc_start, crc_stop = WSPChecksum.search_for_wsp_checksum(bits) + ( + data_start, + data_stop, + crc_start, + crc_stop, + ) = WSPChecksum.search_for_wsp_checksum(bits) if (data_start, data_stop, crc_start, crc_stop) != (0, 0, 0, 0): - checksum_range = ChecksumRange(start=crc_start, length=crc_stop-crc_start, - data_range_start=data_start, data_range_end=data_stop, - crc=WSPChecksum(), score=1/len(message_indices), - field_type="checksum", message_indices={index}) + checksum_range = ChecksumRange( + start=crc_start, + length=crc_stop - crc_start, + data_range_start=data_start, + data_range_end=data_stop, + crc=WSPChecksum(), + score=1 / len(message_indices), + field_type="checksum", + message_indices={index}, + ) try: - present = next(c for c in checksums_for_length if c == checksum_range) + present = next( + c for c in checksums_for_length if c == checksum_range + ) present.message_indices.add(index) except StopIteration: checksums_for_length.append(checksum_range) continue - crc_object, data_start, data_stop, crc_start, crc_stop = crc.guess_all(bits, - ignore_positions=self.already_labeled_cols) - - if (crc_object, data_start, data_stop, crc_start, crc_stop) != (0, 0, 0, 0, 0): - checksum_range = ChecksumRange(start=crc_start, length=crc_stop - crc_start, - data_range_start=data_start, data_range_end=data_stop, - crc=copy.copy(crc_object), score=1 / len(message_indices), - field_type="checksum", message_indices={index} - ) + crc_object, data_start, data_stop, crc_start, crc_stop = crc.guess_all( + bits, ignore_positions=self.already_labeled_cols + ) + + if (crc_object, data_start, data_stop, crc_start, crc_stop) != ( + 0, + 0, + 0, + 0, + 0, + ): + checksum_range = ChecksumRange( + start=crc_start, + length=crc_stop - crc_start, + data_range_start=data_start, + data_range_end=data_stop, + crc=copy.copy(crc_object), + score=1 / len(message_indices), + field_type="checksum", + message_indices={index}, + ) try: - present = next(rng for rng in checksums_for_length if rng == checksum_range) + present = next( + rng for rng in checksums_for_length if rng == checksum_range + ) present.message_indices.add(index) continue except StopIteration: @@ -69,10 +104,15 @@ def find(self): checksums_for_length.append(checksum_range) - matching = awre_util.check_crc_for_messages(message_indices, self.bitvectors, - data_start, data_stop, - crc_start, crc_stop, - *crc_object.get_parameters()) + matching = awre_util.check_crc_for_messages( + message_indices, + self.bitvectors, + data_start, + data_stop, + crc_start, + crc_stop, + *crc_object.get_parameters() + ) checksum_range.message_indices.update(matching) @@ -87,8 +127,14 @@ def find(self): self._debug("Found Checksums", result) try: - max_scored = max(filter(lambda x: len(x.message_indices) >= 2 and x.score >= self.minimum_score, result), - key=lambda x: x.score) + max_scored = max( + filter( + lambda x: len(x.message_indices) >= 2 + and x.score >= self.minimum_score, + result, + ), + key=lambda x: x.score, + ) except ValueError: return [] diff --git a/src/urh/awre/engines/Engine.py b/src/urh/awre/engines/Engine.py index 3198797d5c..d50f655010 100644 --- a/src/urh/awre/engines/Engine.py +++ b/src/urh/awre/engines/Engine.py @@ -13,7 +13,9 @@ def _debug(self, *args): print("[{}]".format(self.__class__.__name__), *args) @staticmethod - def find_common_ranges_by_cluster(msg_vectors, clustered_bitvectors, alpha=0.95, range_type="bit"): + def find_common_ranges_by_cluster( + msg_vectors, clustered_bitvectors, alpha=0.95, range_type="bit" + ): """ :param alpha: How many percent of values must be equal per range? @@ -36,13 +38,22 @@ def find_common_ranges_by_cluster(msg_vectors, clustered_bitvectors, alpha=0.95, return common_ranges_by_cluster @staticmethod - def find_common_ranges_exhaustive(msg_vectors, msg_indices, range_type="bit") -> list: + def find_common_ranges_exhaustive( + msg_vectors, msg_indices, range_type="bit" + ) -> list: result = [] for i, j in itertools.combinations(msg_indices, 2): - for rng in Histogram(msg_vectors, indices=[i, j]).find_common_ranges(alpha=1, range_type=range_type): + for rng in Histogram(msg_vectors, indices=[i, j]).find_common_ranges( + alpha=1, range_type=range_type + ): try: - common_range = next(cr for cr in result if cr.start == rng.start and cr.value.tobytes() == rng.value.tobytes()) + common_range = next( + cr + for cr in result + if cr.start == rng.start + and cr.value.tobytes() == rng.value.tobytes() + ) common_range.message_indices.update({i, j}) except StopIteration: result.append(rng) diff --git a/src/urh/awre/engines/LengthEngine.py b/src/urh/awre/engines/LengthEngine.py index 9dc2a697fb..f9fcdefd3c 100644 --- a/src/urh/awre/engines/LengthEngine.py +++ b/src/urh/awre/engines/LengthEngine.py @@ -25,12 +25,14 @@ def find(self, n_gram_length=8, minimum_score=0.1): bin_num = int(math.ceil(len(bitvector) / n_gram_length)) bitvectors_by_n_gram_length[bin_num].append(i) - common_ranges_by_length = self.find_common_ranges_by_cluster(self.bitvectors, - bitvectors_by_n_gram_length, - alpha=0.7) + common_ranges_by_length = self.find_common_ranges_by_cluster( + self.bitvectors, bitvectors_by_n_gram_length, alpha=0.7 + ) for length, ranges in common_ranges_by_length.items(): - common_ranges_by_length[length] = self.ignore_already_labeled(ranges, self.already_labeled) + common_ranges_by_length[length] = self.ignore_already_labeled( + ranges, self.already_labeled + ) self.filter_common_ranges(common_ranges_by_length) self._debug("Common Ranges:", common_ranges_by_length) @@ -39,8 +41,9 @@ def find(self, n_gram_length=8, minimum_score=0.1): self._debug("Scored Ranges", scored_ranges) # Take the ranges with highest score per cluster if it's score surpasses the minimum score - high_scores_by_length = self.choose_high_scored_ranges(scored_ranges, bitvectors_by_n_gram_length, - minimum_score) + high_scores_by_length = self.choose_high_scored_ranges( + scored_ranges, bitvectors_by_n_gram_length, minimum_score + ) self._debug("Highscored Ranges", high_scores_by_length) return high_scores_by_length.values() @@ -57,10 +60,15 @@ def filter_common_ranges(common_ranges_by_length: dict): ranges = [r for rng in common_ranges_by_length.values() for r in rng] for rng in ranges: - count = len([r for r in ranges if rng.start == r.start - and rng.length == r.length - and rng.value.tobytes() == r.value.tobytes()] - ) + count = len( + [ + r + for r in ranges + if rng.start == r.start + and rng.length == r.length + and rng.value.tobytes() == r.value.tobytes() + ] + ) if count < 2: continue @@ -97,47 +105,65 @@ def score_ranges(common_ranges_by_length: dict, n_gram_length: int): byteorders = ["big", "little"] if n_gram_length == 8 else ["big"] for window_length in window_lengths: for length, common_ranges in common_ranges_by_length.items(): - for common_range in filter(lambda cr: cr.length >= window_length, common_ranges): + for common_range in filter( + lambda cr: cr.length >= window_length, common_ranges + ): bits = common_range.value rng_byte_order = "big" max_score = max_start = -1 for start in range(0, len(bits) + 1 - window_length, n_gram_length): for byteorder in byteorders: - score = LengthEngine.score_bits(bits[start:start + window_length], - length, position=start, byteorder=byteorder) + score = LengthEngine.score_bits( + bits[start : start + window_length], + length, + position=start, + byteorder=byteorder, + ) if score > max_score: max_score = score max_start = start rng_byte_order = byteorder - rng = CommonRange(common_range.start + max_start, window_length, - common_range.value[max_start:max_start + window_length], - score=max_score, field_type="length", - message_indices=common_range.message_indices, - range_type=common_range.range_type, - byte_order=rng_byte_order) + rng = CommonRange( + common_range.start + max_start, + window_length, + common_range.value[max_start : max_start + window_length], + score=max_score, + field_type="length", + message_indices=common_range.message_indices, + range_type=common_range.range_type, + byte_order=rng_byte_order, + ) scored_ranges[length][window_length].append(rng) return scored_ranges - def choose_high_scored_ranges(self, scored_ranges: dict, bitvectors_by_n_gram_length: dict, minimum_score: float): - + def choose_high_scored_ranges( + self, + scored_ranges: dict, + bitvectors_by_n_gram_length: dict, + minimum_score: float, + ): # Set for every window length the highest scored range as candidate possible_window_lengths = defaultdict(int) for length, ranges_by_window_length in scored_ranges.items(): for window_length, ranges in ranges_by_window_length.items(): try: - ranges_by_window_length[window_length] = max(filter(lambda x: x.score >= minimum_score, ranges), - key=lambda x: x.score) + ranges_by_window_length[window_length] = max( + filter(lambda x: x.score >= minimum_score, ranges), + key=lambda x: x.score, + ) possible_window_lengths[window_length] += 1 except ValueError: ranges_by_window_length[window_length] = None try: # Choose window length -> window length that has a result most often and choose greater on tie - chosen_window_length = max(possible_window_lengths, key=lambda x: (possible_window_lengths[x], x)) + chosen_window_length = max( + possible_window_lengths, key=lambda x: (possible_window_lengths[x], x) + ) except ValueError: return dict() @@ -147,7 +173,9 @@ def choose_high_scored_ranges(self, scored_ranges: dict, bitvectors_by_n_gram_le for length, ranges_by_window_length in scored_ranges.items(): try: if ranges_by_window_length[chosen_window_length]: - high_scores_by_length[length] = ranges_by_window_length[chosen_window_length] + high_scores_by_length[length] = ranges_by_window_length[ + chosen_window_length + ] except KeyError: continue @@ -161,30 +189,39 @@ def choose_high_scored_ranges(self, scored_ranges: dict, bitvectors_by_n_gram_le max_score, best_match = 0, None for rng in high_scores_by_length.values(): - bits = bitvector[rng.start:rng.end + 1] + bits = bitvector[rng.start : rng.end + 1] if len(bits) > 0: score = self.score_bits(bits, length, rng.start) if score > max_score: best_match, max_score = rng, score if best_match is not None: - high_scores_by_length[length] = CommonRange(best_match.start, best_match.length, - value=bitvector[best_match.start:best_match.end + 1], - score=max_score, field_type="length", - message_indices={msg_index}, range_type="bit") + high_scores_by_length[length] = CommonRange( + best_match.start, + best_match.length, + value=bitvector[best_match.start : best_match.end + 1], + score=max_score, + field_type="length", + message_indices={msg_index}, + range_type="bit", + ) return high_scores_by_length @staticmethod - def score_bits(bits: np.ndarray, target_length: int, position: int, byteorder="big"): + def score_bits( + bits: np.ndarray, target_length: int, position: int, byteorder="big" + ): value = util.bit_array_to_number(bits, len(bits)) if byteorder == "little": if len(bits) > 8 and len(bits) % 8 == 0: n = len(bits) // 8 - value = int.from_bytes(value.to_bytes(n, byteorder="big"), byteorder="little", signed=False) + value = int.from_bytes( + value.to_bytes(n, byteorder="big"), byteorder="little", signed=False + ) # Length field should be at front, so we give lower scores for large starts - f = (1 / (1 + 0.25 * position)) + f = 1 / (1 + 0.25 * position) return f * LengthEngine.gauss(value, target_length) diff --git a/src/urh/awre/engines/SequenceNumberEngine.py b/src/urh/awre/engines/SequenceNumberEngine.py index aa64406963..ced8206aa4 100644 --- a/src/urh/awre/engines/SequenceNumberEngine.py +++ b/src/urh/awre/engines/SequenceNumberEngine.py @@ -6,7 +6,13 @@ class SequenceNumberEngine(Engine): - def __init__(self, bitvectors, n_gram_length=8, minimum_score=0.75, already_labeled: list = None): + def __init__( + self, + bitvectors, + n_gram_length=8, + minimum_score=0.75, + already_labeled: list = None, + ): """ :type bitvectors: list of np.ndarray @@ -18,7 +24,9 @@ def __init__(self, bitvectors, n_gram_length=8, minimum_score=0.75, already_labe if already_labeled is None: self.already_labeled_cols = set() else: - self.already_labeled_cols = {e // n_gram_length for rng in already_labeled for e in range(*rng)} + self.already_labeled_cols = { + e // n_gram_length for rng in already_labeled for e in range(*rng) + } def find(self): n = self.n_gram_length @@ -44,28 +52,43 @@ def find(self): self._debug("Scores by column", scores_by_column) result = [] - for candidate_column in sorted(scores_by_column, key=scores_by_column.get, reverse=True): + for candidate_column in sorted( + scores_by_column, key=scores_by_column.get, reverse=True + ): score = scores_by_column[candidate_column] if score < self.minimum_score: continue - most_common_diff = self.get_most_frequent(diff_frequencies_by_column[candidate_column]) + most_common_diff = self.get_most_frequent( + diff_frequencies_by_column[candidate_column] + ) message_indices = np.flatnonzero( # get all rows that have the most common difference or zero - (diff_matrix[:, candidate_column] == most_common_diff) | (diff_matrix[:, candidate_column] == 0) + (diff_matrix[:, candidate_column] == most_common_diff) + | (diff_matrix[:, candidate_column] == 0) ) # For example, index 1 in diff matrix corresponds to index 1 and 2 of messages message_indices = set(message_indices) | set(message_indices + 1) values = set() for i in message_indices: - values.add(self.bitvectors[i][candidate_column * n:(candidate_column + 1) * n].tobytes()) + values.add( + self.bitvectors[i][ + candidate_column * n : (candidate_column + 1) * n + ].tobytes() + ) - matching_ranges = [r for r in result if r.message_indices == message_indices] + matching_ranges = [ + r for r in result if r.message_indices == message_indices + ] try: - matching_range = next(r for r in matching_ranges if r.start == (candidate_column - 1) * n - and (r.byte_order_is_unknown or r.byte_order == "big")) + matching_range = next( + r + for r in matching_ranges + if r.start == (candidate_column - 1) * n + and (r.byte_order_is_unknown or r.byte_order == "big") + ) matching_range.length += n matching_range.byte_order = "big" matching_range.values.extend(list(values)) @@ -74,8 +97,12 @@ def find(self): pass try: - matching_range = next(r for r in matching_ranges if r.start == (candidate_column + 1) * n - and (r.byte_order_is_unknown or r.byte_order == "little")) + matching_range = next( + r + for r in matching_ranges + if r.start == (candidate_column + 1) * n + and (r.byte_order_is_unknown or r.byte_order == "little") + ) matching_range.start -= n matching_range.length += n matching_range.byte_order = "little" @@ -84,9 +111,14 @@ def find(self): except StopIteration: pass - new_range = CommonRange(start=candidate_column * n, length=n, score=score, - field_type="sequence number", message_indices=message_indices, - byte_order=None) + new_range = CommonRange( + start=candidate_column * n, + length=n, + score=score, + field_type="sequence number", + message_indices=message_indices, + byte_order=None, + ) new_range.values.extend(list(values)) result.append(new_range) @@ -95,7 +127,10 @@ def find(self): @staticmethod def get_most_frequent(diff_frequencies: dict): - return max(filter(lambda x: x not in (0, -1), diff_frequencies), key=diff_frequencies.get) + return max( + filter(lambda x: x not in (0, -1), diff_frequencies), + key=diff_frequencies.get, + ) @staticmethod def calc_score(diff_frequencies: dict) -> float: diff --git a/src/urh/cli/urh_cli.py b/src/urh/cli/urh_cli.py index 5765437ed0..025b945810 100755 --- a/src/urh/cli/urh_cli.py +++ b/src/urh/cli/urh_cli.py @@ -18,7 +18,7 @@ DEFAULT_CENTER_SPACING = 0.1 DEFAULT_TOLERANCE = 5 -cli_exe = sys.executable if hasattr(sys, 'frozen') else sys.argv[0] +cli_exe = sys.executable if hasattr(sys, "frozen") else sys.argv[0] cur_dir = os.path.realpath(os.path.dirname(os.path.realpath(cli_exe))) SRC_DIR = os.path.realpath(os.path.join(cur_dir, "..", "..")) @@ -64,9 +64,11 @@ def cli_progress_bar(value, end_value, bar_length=20, title="Percent"): percent = value / end_value - hashes = '#' * int(round(percent * bar_length)) - spaces = ' ' * (bar_length - len(hashes)) - sys.stdout.write("\r{0}:\t[{1}] {2}%".format(title, hashes + spaces, int(round(percent * 100)))) + hashes = "#" * int(round(percent * bar_length)) + spaces = " " * (bar_length - len(hashes)) + sys.stdout.write( + "\r{0}:\t[{1}] {2}%".format(title, hashes + spaces, int(round(percent * 100))) + ) sys.stdout.flush() @@ -83,7 +85,11 @@ def build_modulator_from_args(arguments: argparse.Namespace): n = 2 ** int(arguments.bits_per_symbol) if arguments.parameters is None or len(arguments.parameters) != n: - raise ValueError("You need to give {} parameters for {} bits per symbol".format(n, int(arguments.bits_per_symbol))) + raise ValueError( + "You need to give {} parameters for {} bits per symbol".format( + n, int(arguments.bits_per_symbol) + ) + ) result = Modulator("CLI Modulator") result.carrier_freq_hz = float(arguments.carrier_frequency) @@ -107,6 +113,7 @@ def build_modulator_from_args(arguments: argparse.Namespace): def build_backend_handler_from_args(arguments: argparse.Namespace): from urh.dev.BackendHandler import Backends + bh = BackendHandler() if arguments.device_backend == "native": bh.device_backends[arguments.device.lower()].selected_backend = Backends.native @@ -119,13 +126,23 @@ def build_backend_handler_from_args(arguments: argparse.Namespace): def build_device_from_args(arguments: argparse.Namespace): from urh.dev.VirtualDevice import Mode + bh = build_backend_handler_from_args(arguments) - bandwidth = arguments.sample_rate if arguments.bandwidth is None else arguments.bandwidth - result = VirtualDevice(bh, name=arguments.device, mode=Mode.receive if arguments.receive else Mode.send, - freq=arguments.frequency, sample_rate=arguments.sample_rate, - bandwidth=bandwidth, - gain=arguments.gain, if_gain=arguments.if_gain, baseband_gain=arguments.baseband_gain) + bandwidth = ( + arguments.sample_rate if arguments.bandwidth is None else arguments.bandwidth + ) + result = VirtualDevice( + bh, + name=arguments.device, + mode=Mode.receive if arguments.receive else Mode.send, + freq=arguments.frequency, + sample_rate=arguments.sample_rate, + bandwidth=bandwidth, + gain=arguments.gain, + if_gain=arguments.if_gain, + baseband_gain=arguments.baseband_gain, + ) result.freq_correction = arguments.frequency_correction if arguments.device_identifier is not None: @@ -142,13 +159,22 @@ def build_device_from_args(arguments: argparse.Namespace): def build_protocol_sniffer_from_args(arguments: argparse.Namespace): bh = build_backend_handler_from_args(arguments) - result = ProtocolSniffer(arguments.samples_per_symbol, arguments.center, arguments.center_spacing, - arguments.noise, arguments.tolerance, - arguments.modulation_type, arguments.bits_per_symbol, - arguments.device.lower(), bh) + result = ProtocolSniffer( + arguments.samples_per_symbol, + arguments.center, + arguments.center_spacing, + arguments.noise, + arguments.tolerance, + arguments.modulation_type, + arguments.bits_per_symbol, + arguments.device.lower(), + bh, + ) result.rcv_device.frequency = arguments.frequency result.rcv_device.sample_rate = arguments.sample_rate - result.rcv_device.bandwidth = arguments.sample_rate if arguments.bandwidth is None else arguments.bandwidth + result.rcv_device.bandwidth = ( + arguments.sample_rate if arguments.bandwidth is None else arguments.bandwidth + ) result.rcv_device.freq_correction = arguments.frequency_correction if arguments.gain is not None: result.rcv_device.gain = arguments.gain @@ -187,23 +213,28 @@ def read_messages_to_send(arguments: argparse.Namespace): print("Either give messages (-m) or a file to read from (-file) not both.") sys.exit(1) elif arguments.messages is not None: - #support for calls from external tools e.g. metasploit + # support for calls from external tools e.g. metasploit if len(arguments.messages) == 1: - message_strings = arguments.messages[0].split(' ') + message_strings = arguments.messages[0].split(" ") else: message_strings = arguments.messages elif arguments.filename is not None: with open(arguments.filename) as f: message_strings = list(map(str.strip, f.readlines())) else: - print("You need to give messages to send either with (-m) or a file (-file) to read them from.") + print( + "You need to give messages to send either with (-m) or a file (-file) to read them from." + ) sys.exit(1) encoding = build_encoding_from_args(arguments) - result = ProtocolAnalyzer.get_protocol_from_string(message_strings, is_hex=arguments.hex, - default_pause=arguments.pause, - sample_rate=arguments.sample_rate).messages + result = ProtocolAnalyzer.get_protocol_from_string( + message_strings, + is_hex=arguments.hex, + default_pause=arguments.pause, + sample_rate=arguments.sample_rate, + ).messages if encoding: for msg in result: msg.decoder = encoding @@ -216,13 +247,16 @@ def modulate_messages(messages, modulator): return None cli_progress_bar(0, len(messages), title="Modulating") - nsamples = sum(int(len(msg.encoded_bits) * modulator.samples_per_symbol + msg.pause) for msg in messages) + nsamples = sum( + int(len(msg.encoded_bits) * modulator.samples_per_symbol + msg.pause) + for msg in messages + ) buffer = IQArray(None, dtype=np.float32, n=nsamples) pos = 0 for i, msg in enumerate(messages): # We do not need to modulate the pause extra, as result is already initialized with zeros modulated = modulator.modulate(start=0, data=msg.encoded_bits, pause=0) - buffer[pos:pos + len(modulated)] = modulated + buffer[pos : pos + len(modulated)] = modulated pos += len(modulated) + msg.pause cli_progress_bar(i + 1, len(messages), title="Modulating") print("\nSuccessfully modulated {} messages".format(len(messages))) @@ -260,90 +294,220 @@ def parse_project_file(file_path: str): def create_parser(): - parser = argparse.ArgumentParser(description='This is the Command Line Interface for the Universal Radio Hacker.', - add_help=False) - parser.add_argument('project_file', nargs='?', default=None) - - group1 = parser.add_argument_group('Software Defined Radio Settings', "Configure Software Defined Radio options") - group1.add_argument("-d", "--device", choices=DEVICES, metavar="DEVICE", - help="Choose a Software Defined Radio. Allowed values are " + ", ".join(DEVICES)) + parser = argparse.ArgumentParser( + description="This is the Command Line Interface for the Universal Radio Hacker.", + add_help=False, + ) + parser.add_argument("project_file", nargs="?", default=None) + + group1 = parser.add_argument_group( + "Software Defined Radio Settings", "Configure Software Defined Radio options" + ) + group1.add_argument( + "-d", + "--device", + choices=DEVICES, + metavar="DEVICE", + help="Choose a Software Defined Radio. Allowed values are " + + ", ".join(DEVICES), + ) group1.add_argument("-di", "--device-identifier") - group1.add_argument("-db", "--device-backend", choices=["native", "gnuradio"], default="native") - group1.add_argument("-f", "--frequency", type=float, - help="Center frequency the SDR shall be tuned to") + group1.add_argument( + "-db", "--device-backend", choices=["native", "gnuradio"], default="native" + ) + group1.add_argument( + "-f", + "--frequency", + type=float, + help="Center frequency the SDR shall be tuned to", + ) group1.add_argument("-s", "--sample-rate", type=float, help="Sample rate to use") - group1.add_argument("-b", "--bandwidth", type=float, help="Bandwidth to use (defaults to sample rate)") + group1.add_argument( + "-b", + "--bandwidth", + type=float, + help="Bandwidth to use (defaults to sample rate)", + ) group1.add_argument("-g", "--gain", type=int, help="RF gain the SDR shall use") - group1.add_argument("-if", "--if-gain", type=int, help="IF gain to use (only supported for some SDRs)") - group1.add_argument("-bb", "--baseband-gain", type=int, help="Baseband gain to use (only supported for some SDRs)") - group1.add_argument("-a", "--adaptive-noise", action="store_true", help="Use adaptive noise when receiving.") - group1.add_argument("-fcorr", "--frequency-correction", default=1, type=int, - help="Set the frequency correction for SDR (if supported)") - - group2 = parser.add_argument_group('Modulation/Demodulation settings', - "Configure the Modulator/Demodulator. Not required in raw mode." - "In case of RX there are additional demodulation options.") - group2.add_argument("-cf", "--carrier-frequency", type=float, - help="Carrier frequency in Hertz (default: {})".format(DEFAULT_CARRIER_FREQUENCY)) - group2.add_argument("-ca", "--carrier-amplitude", type=float, - help="Carrier amplitude (default: {})".format(DEFAULT_CARRIER_AMPLITUDE)) - group2.add_argument("-cp", "--carrier-phase", type=float, - help="Carrier phase in degree (default: {})".format(DEFAULT_CARRIER_PHASE)) - group2.add_argument("-mo", "--modulation-type", choices=MODULATIONS, metavar="MOD_TYPE", default="FSK", - help="Modulation type must be one of " + ", ".join(MODULATIONS) + " (default: %(default)s)") - group2.add_argument("-bps", "--bits-per-symbol", type=int, - help="Bits per symbol e.g. 1 means binary modulation (default: 1).") - group2.add_argument("-pm", "--parameters", nargs='+', help="Parameters for modulation. Separate with spaces") + group1.add_argument( + "-if", + "--if-gain", + type=int, + help="IF gain to use (only supported for some SDRs)", + ) + group1.add_argument( + "-bb", + "--baseband-gain", + type=int, + help="Baseband gain to use (only supported for some SDRs)", + ) + group1.add_argument( + "-a", + "--adaptive-noise", + action="store_true", + help="Use adaptive noise when receiving.", + ) + group1.add_argument( + "-fcorr", + "--frequency-correction", + default=1, + type=int, + help="Set the frequency correction for SDR (if supported)", + ) + + group2 = parser.add_argument_group( + "Modulation/Demodulation settings", + "Configure the Modulator/Demodulator. Not required in raw mode." + "In case of RX there are additional demodulation options.", + ) + group2.add_argument( + "-cf", + "--carrier-frequency", + type=float, + help="Carrier frequency in Hertz (default: {})".format( + DEFAULT_CARRIER_FREQUENCY + ), + ) + group2.add_argument( + "-ca", + "--carrier-amplitude", + type=float, + help="Carrier amplitude (default: {})".format(DEFAULT_CARRIER_AMPLITUDE), + ) + group2.add_argument( + "-cp", + "--carrier-phase", + type=float, + help="Carrier phase in degree (default: {})".format(DEFAULT_CARRIER_PHASE), + ) + group2.add_argument( + "-mo", + "--modulation-type", + choices=MODULATIONS, + metavar="MOD_TYPE", + default="FSK", + help="Modulation type must be one of " + + ", ".join(MODULATIONS) + + " (default: %(default)s)", + ) + group2.add_argument( + "-bps", + "--bits-per-symbol", + type=int, + help="Bits per symbol e.g. 1 means binary modulation (default: 1).", + ) + group2.add_argument( + "-pm", + "--parameters", + nargs="+", + help="Parameters for modulation. Separate with spaces", + ) # Legacy group2.add_argument("-p0", "--parameter-zero", help=argparse.SUPPRESS) group2.add_argument("-p1", "--parameter-one", help=argparse.SUPPRESS) - group2.add_argument("-sps", "--samples-per-symbol", type=int, - help="Length of a symbol in samples (default: {}).".format(DEFAULT_SAMPLES_PER_SYMBOL)) - group2.add_argument("-bl", "--bit-length", type=int, - help="Same as samples per symbol, just there for legacy support (default: {}).".format(DEFAULT_SAMPLES_PER_SYMBOL)) - - group2.add_argument("-n", "--noise", type=float, - help="Noise threshold (default: {}). Used for RX only.".format(DEFAULT_NOISE)) - group2.add_argument("-c", "--center", type=float, - help="Center between symbols for demodulation (default: {}). " - "Used for RX only.".format(DEFAULT_CENTER)) - group2.add_argument("-cs", "--center-spacing", type=float, - help="Center spacing between symbols for demodulation (default: {}). " - "Value has only effect for modulations with more than 1 bit per symbol. " - "Used only for RX.".format(DEFAULT_CENTER_SPACING)) - group2.add_argument("-t", "--tolerance", type=float, - help="Tolerance for demodulation in samples (default: {}). " - "Used for RX only.".format(DEFAULT_TOLERANCE)) - - group3 = parser.add_argument_group('Data configuration', "Configure which data to send or where to receive it.") - group3.add_argument("--hex", action='store_true', help="Give messages as hex instead of bits") + group2.add_argument( + "-sps", + "--samples-per-symbol", + type=int, + help="Length of a symbol in samples (default: {}).".format( + DEFAULT_SAMPLES_PER_SYMBOL + ), + ) + group2.add_argument( + "-bl", + "--bit-length", + type=int, + help="Same as samples per symbol, just there for legacy support (default: {}).".format( + DEFAULT_SAMPLES_PER_SYMBOL + ), + ) + + group2.add_argument( + "-n", + "--noise", + type=float, + help="Noise threshold (default: {}). Used for RX only.".format(DEFAULT_NOISE), + ) + group2.add_argument( + "-c", + "--center", + type=float, + help="Center between symbols for demodulation (default: {}). " + "Used for RX only.".format(DEFAULT_CENTER), + ) + group2.add_argument( + "-cs", + "--center-spacing", + type=float, + help="Center spacing between symbols for demodulation (default: {}). " + "Value has only effect for modulations with more than 1 bit per symbol. " + "Used only for RX.".format(DEFAULT_CENTER_SPACING), + ) + group2.add_argument( + "-t", + "--tolerance", + type=float, + help="Tolerance for demodulation in samples (default: {}). " + "Used for RX only.".format(DEFAULT_TOLERANCE), + ) + + group3 = parser.add_argument_group( + "Data configuration", "Configure which data to send or where to receive it." + ) + group3.add_argument( + "--hex", action="store_true", help="Give messages as hex instead of bits" + ) group3.add_argument("-e", "--encoding", help="Specify encoding") - group3.add_argument("-m", "--messages", nargs='+', help="Messages to send. Give pauses after with a {0}. " - "Separate with spaces e.g. " - "1001{0}42ms 1100{0}3ns 0001 1111{0}200. " - "If you give no time suffix after a pause " - "it is assumed to be in samples. ".format(PAUSE_SEP)) - - group3.add_argument("-file", "--filename", help="Filename to read messages from in send mode. " - "In receive mode messages will be written to this file " - "instead to STDOUT.") - group3.add_argument("-p", "--pause", default="250ms", - help="The default pause which is inserted after a every message " - "which does not have a pause configured. (default: %(default)s) " - "Supported time units: s (second), ms (millisecond), µs (microsecond), ns (nanosecond) " - "If you do not give a time suffix the pause is assumed to be in samples.") + group3.add_argument( + "-m", + "--messages", + nargs="+", + help="Messages to send. Give pauses after with a {0}. " + "Separate with spaces e.g. " + "1001{0}42ms 1100{0}3ns 0001 1111{0}200. " + "If you give no time suffix after a pause " + "it is assumed to be in samples. ".format(PAUSE_SEP), + ) + + group3.add_argument( + "-file", + "--filename", + help="Filename to read messages from in send mode. " + "In receive mode messages will be written to this file " + "instead to STDOUT.", + ) + group3.add_argument( + "-p", + "--pause", + default="250ms", + help="The default pause which is inserted after a every message " + "which does not have a pause configured. (default: %(default)s) " + "Supported time units: s (second), ms (millisecond), µs (microsecond), ns (nanosecond) " + "If you do not give a time suffix the pause is assumed to be in samples.", + ) group3.add_argument("-rx", "--receive", action="store_true", help="Enter RX mode") group3.add_argument("-tx", "--transmit", action="store_true", help="Enter TX mode") - group3.add_argument("-rt", "--receive-time", default="3.0", type=float, - help="How long to receive messages. (default: %(default)s) " - "Any negative value means infinite.") - group3.add_argument("-r", "--raw", action="store_true", - help="Use raw mode i.e. send/receive IQ data instead of bits.") + group3.add_argument( + "-rt", + "--receive-time", + default="3.0", + type=float, + help="How long to receive messages. (default: %(default)s) " + "Any negative value means infinite.", + ) + group3.add_argument( + "-r", + "--raw", + action="store_true", + help="Use raw mode i.e. send/receive IQ data instead of bits.", + ) group4 = parser.add_argument_group("Miscellaneous options") - group4.add_argument("-h", "--help", action="help", help="show this help message and exit") + group4.add_argument( + "-h", "--help", action="help", help="show this help message and exit" + ) group4.add_argument("-v", "--verbose", action="count") return parser @@ -359,14 +523,17 @@ def get_val(value, project_params: dict, project_param_key: str, default): return default import multiprocessing as mp + mp.set_start_method("spawn") # allow usage of prange (OpenMP) in Processes mp.freeze_support() parser = create_parser() args = parser.parse_args() if args.parameter_zero is not None or args.parameter_one is not None: - print("Options -p0 (--parameter-zero) and -p1 (--parameter-one) are not supported anymore.\n" - "Use --parameters instead e.g. --parameters 20K 40K for a binary FSK.") + print( + "Options -p0 (--parameter-zero) and -p1 (--parameter-one) are not supported anymore.\n" + "Use --parameters instead e.g. --parameters 20K 40K for a binary FSK." + ) sys.exit(1) project_params = parse_project_file(args.project_file) @@ -384,19 +551,25 @@ def get_val(value, project_params: dict, project_param_key: str, default): print("You cannot use receive and transmit mode at the same time.") sys.exit(1) if not args.receive and not args.transmit: - print("You must choose a mode either RX (-rx, --receive) or TX (-tx, --transmit)") + print( + "You must choose a mode either RX (-rx, --receive) or TX (-tx, --transmit)" + ) sys.exit(1) args.bandwidth = get_val(args.bandwidth, project_params, "bandwidth", None) rx_tx_prefix = "rx_" if args.receive else "tx_" args.gain = get_val(args.gain, project_params, rx_tx_prefix + "gain", None) args.if_gain = get_val(args.if_gain, project_params, rx_tx_prefix + "if_gain", None) - args.baseband_gain = get_val(args.baseband_gain, project_params, rx_tx_prefix + "baseband_gain", None) + args.baseband_gain = get_val( + args.baseband_gain, project_params, rx_tx_prefix + "baseband_gain", None + ) if args.modulation_type is None: try: if project_params["modulation_type"] is None: - args.modulation_type = MODULATIONS[int(project_params["modulation_index"])] + args.modulation_type = MODULATIONS[ + int(project_params["modulation_index"]) + ] else: args.modulation_type = project_params["modulation_type"] except: @@ -405,20 +578,40 @@ def get_val(value, project_params: dict, project_param_key: str, default): if args.bit_length is not None and args.samples_per_symbol is None: args.samples_per_symbol = args.bit_length # legacy else: - args.samples_per_symbol = get_val(args.samples_per_symbol, project_params, - "samples_per_symbol", DEFAULT_SAMPLES_PER_SYMBOL) + args.samples_per_symbol = get_val( + args.samples_per_symbol, + project_params, + "samples_per_symbol", + DEFAULT_SAMPLES_PER_SYMBOL, + ) args.center = get_val(args.center, project_params, "center", DEFAULT_CENTER) - args.center_spacing = get_val(args.center_spacing, project_params, "center_spacing", DEFAULT_CENTER_SPACING) + args.center_spacing = get_val( + args.center_spacing, project_params, "center_spacing", DEFAULT_CENTER_SPACING + ) args.noise = get_val(args.noise, project_params, "noise", DEFAULT_NOISE) - args.tolerance = get_val(args.tolerance, project_params, "tolerance", DEFAULT_TOLERANCE) - args.bits_per_symbol = get_val(args.bits_per_symbol, project_params, "bits_per_symbol", 1) - - args.carrier_frequency = get_val(args.carrier_frequency, project_params, "carrier_frequency", - DEFAULT_CARRIER_FREQUENCY) - args.carrier_amplitude = get_val(args.carrier_amplitude, project_params, "carrier_amplitude", - DEFAULT_CARRIER_AMPLITUDE) - args.carrier_phase = get_val(args.carrier_phase, project_params, "carrier_phase", DEFAULT_CARRIER_PHASE) + args.tolerance = get_val( + args.tolerance, project_params, "tolerance", DEFAULT_TOLERANCE + ) + args.bits_per_symbol = get_val( + args.bits_per_symbol, project_params, "bits_per_symbol", 1 + ) + + args.carrier_frequency = get_val( + args.carrier_frequency, + project_params, + "carrier_frequency", + DEFAULT_CARRIER_FREQUENCY, + ) + args.carrier_amplitude = get_val( + args.carrier_amplitude, + project_params, + "carrier_amplitude", + DEFAULT_CARRIER_AMPLITUDE, + ) + args.carrier_phase = get_val( + args.carrier_phase, project_params, "carrier_phase", DEFAULT_CARRIER_PHASE + ) args.parameters = get_val(args.parameters, project_params, "parameters", None) if args.parameters is None: print("You must give modulation parameters (--parameters)") @@ -432,14 +625,18 @@ def get_val(value, project_params: dict, project_param_key: str, default): logger.setLevel(logging.DEBUG) Logger.save_log_level() - argument_string = "\n".join("{} {}".format(arg, getattr(args, arg)) for arg in vars(args)) + argument_string = "\n".join( + "{} {}".format(arg, getattr(args, arg)) for arg in vars(args) + ) logger.debug("Using these parameters\n" + argument_string) if args.transmit: device = build_device_from_args(args) if args.raw: if args.filename is None: - print("You need to give a file (-file, --filename) where to read samples from.") + print( + "You need to give a file (-file, --filename) where to read samples from." + ) sys.exit(1) samples_to_send = np.fromfile(args.filename, dtype=np.complex64) else: @@ -454,7 +651,11 @@ def get_val(value, project_params: dict, project_param_key: str, default): time.sleep(0.1) device.read_messages() if device.current_index > 0: - cli_progress_bar(device.current_index, len(device.samples_to_send), title="Sending") + cli_progress_bar( + device.current_index, + len(device.samples_to_send), + title="Sending", + ) except KeyboardInterrupt: break @@ -463,7 +664,9 @@ def get_val(value, project_params: dict, project_param_key: str, default): elif args.receive: if args.raw: if args.filename is None: - print("You need to give a file (-file, --filename) to receive into when using raw RX mode.") + print( + "You need to give a file (-file, --filename) to receive into when using raw RX mode." + ) sys.exit(1) receiver = build_device_from_args(args) @@ -495,7 +698,10 @@ def get_val(value, project_params: dict, project_param_key: str, default): if not args.raw: num_messages = len(receiver.messages) for msg in receiver.messages[:num_messages]: - print(msg.decoded_hex_str if args.hex else msg.decoded_bits_str, **kwargs) + print( + msg.decoded_hex_str if args.hex else msg.decoded_bits_str, + **kwargs + ) del receiver.messages[:num_messages] except KeyboardInterrupt: break @@ -503,7 +709,7 @@ def get_val(value, project_params: dict, project_param_key: str, default): print("\nStopping receiving...") if args.raw: receiver.stop("Receiving finished") - receiver.data[:receiver.current_index].tofile(f) + receiver.data[: receiver.current_index].tofile(f) else: receiver.stop() @@ -512,5 +718,5 @@ def get_val(value, project_params: dict, project_param_key: str, default): print("Received data written to {}".format(args.filename)) -if __name__ == '__main__': +if __name__ == "__main__": main() diff --git a/src/urh/colormaps.py b/src/urh/colormaps.py index 21cb6c4caf..aa12a3752f 100644 --- a/src/urh/colormaps.py +++ b/src/urh/colormaps.py @@ -2,1033 +2,1041 @@ from urh import settings -magma = [[0.001462, 0.000466, 0.013866], - [0.002258, 0.001295, 0.018331], - [0.003279, 0.002305, 0.023708], - [0.004512, 0.003490, 0.029965], - [0.005950, 0.004843, 0.037130], - [0.007588, 0.006356, 0.044973], - [0.009426, 0.008022, 0.052844], - [0.011465, 0.009828, 0.060750], - [0.013708, 0.011771, 0.068667], - [0.016156, 0.013840, 0.076603], - [0.018815, 0.016026, 0.084584], - [0.021692, 0.018320, 0.092610], - [0.024792, 0.020715, 0.100676], - [0.028123, 0.023201, 0.108787], - [0.031696, 0.025765, 0.116965], - [0.035520, 0.028397, 0.125209], - [0.039608, 0.031090, 0.133515], - [0.043830, 0.033830, 0.141886], - [0.048062, 0.036607, 0.150327], - [0.052320, 0.039407, 0.158841], - [0.056615, 0.042160, 0.167446], - [0.060949, 0.044794, 0.176129], - [0.065330, 0.047318, 0.184892], - [0.069764, 0.049726, 0.193735], - [0.074257, 0.052017, 0.202660], - [0.078815, 0.054184, 0.211667], - [0.083446, 0.056225, 0.220755], - [0.088155, 0.058133, 0.229922], - [0.092949, 0.059904, 0.239164], - [0.097833, 0.061531, 0.248477], - [0.102815, 0.063010, 0.257854], - [0.107899, 0.064335, 0.267289], - [0.113094, 0.065492, 0.276784], - [0.118405, 0.066479, 0.286321], - [0.123833, 0.067295, 0.295879], - [0.129380, 0.067935, 0.305443], - [0.135053, 0.068391, 0.315000], - [0.140858, 0.068654, 0.324538], - [0.146785, 0.068738, 0.334011], - [0.152839, 0.068637, 0.343404], - [0.159018, 0.068354, 0.352688], - [0.165308, 0.067911, 0.361816], - [0.171713, 0.067305, 0.370771], - [0.178212, 0.066576, 0.379497], - [0.184801, 0.065732, 0.387973], - [0.191460, 0.064818, 0.396152], - [0.198177, 0.063862, 0.404009], - [0.204935, 0.062907, 0.411514], - [0.211718, 0.061992, 0.418647], - [0.218512, 0.061158, 0.425392], - [0.225302, 0.060445, 0.431742], - [0.232077, 0.059889, 0.437695], - [0.238826, 0.059517, 0.443256], - [0.245543, 0.059352, 0.448436], - [0.252220, 0.059415, 0.453248], - [0.258857, 0.059706, 0.457710], - [0.265447, 0.060237, 0.461840], - [0.271994, 0.060994, 0.465660], - [0.278493, 0.061978, 0.469190], - [0.284951, 0.063168, 0.472451], - [0.291366, 0.064553, 0.475462], - [0.297740, 0.066117, 0.478243], - [0.304081, 0.067835, 0.480812], - [0.310382, 0.069702, 0.483186], - [0.316654, 0.071690, 0.485380], - [0.322899, 0.073782, 0.487408], - [0.329114, 0.075972, 0.489287], - [0.335308, 0.078236, 0.491024], - [0.341482, 0.080564, 0.492631], - [0.347636, 0.082946, 0.494121], - [0.353773, 0.085373, 0.495501], - [0.359898, 0.087831, 0.496778], - [0.366012, 0.090314, 0.497960], - [0.372116, 0.092816, 0.499053], - [0.378211, 0.095332, 0.500067], - [0.384299, 0.097855, 0.501002], - [0.390384, 0.100379, 0.501864], - [0.396467, 0.102902, 0.502658], - [0.402548, 0.105420, 0.503386], - [0.408629, 0.107930, 0.504052], - [0.414709, 0.110431, 0.504662], - [0.420791, 0.112920, 0.505215], - [0.426877, 0.115395, 0.505714], - [0.432967, 0.117855, 0.506160], - [0.439062, 0.120298, 0.506555], - [0.445163, 0.122724, 0.506901], - [0.451271, 0.125132, 0.507198], - [0.457386, 0.127522, 0.507448], - [0.463508, 0.129893, 0.507652], - [0.469640, 0.132245, 0.507809], - [0.475780, 0.134577, 0.507921], - [0.481929, 0.136891, 0.507989], - [0.488088, 0.139186, 0.508011], - [0.494258, 0.141462, 0.507988], - [0.500438, 0.143719, 0.507920], - [0.506629, 0.145958, 0.507806], - [0.512831, 0.148179, 0.507648], - [0.519045, 0.150383, 0.507443], - [0.525270, 0.152569, 0.507192], - [0.531507, 0.154739, 0.506895], - [0.537755, 0.156894, 0.506551], - [0.544015, 0.159033, 0.506159], - [0.550287, 0.161158, 0.505719], - [0.556571, 0.163269, 0.505230], - [0.562866, 0.165368, 0.504692], - [0.569172, 0.167454, 0.504105], - [0.575490, 0.169530, 0.503466], - [0.581819, 0.171596, 0.502777], - [0.588158, 0.173652, 0.502035], - [0.594508, 0.175701, 0.501241], - [0.600868, 0.177743, 0.500394], - [0.607238, 0.179779, 0.499492], - [0.613617, 0.181811, 0.498536], - [0.620005, 0.183840, 0.497524], - [0.626401, 0.185867, 0.496456], - [0.632805, 0.187893, 0.495332], - [0.639216, 0.189921, 0.494150], - [0.645633, 0.191952, 0.492910], - [0.652056, 0.193986, 0.491611], - [0.658483, 0.196027, 0.490253], - [0.664915, 0.198075, 0.488836], - [0.671349, 0.200133, 0.487358], - [0.677786, 0.202203, 0.485819], - [0.684224, 0.204286, 0.484219], - [0.690661, 0.206384, 0.482558], - [0.697098, 0.208501, 0.480835], - [0.703532, 0.210638, 0.479049], - [0.709962, 0.212797, 0.477201], - [0.716387, 0.214982, 0.475290], - [0.722805, 0.217194, 0.473316], - [0.729216, 0.219437, 0.471279], - [0.735616, 0.221713, 0.469180], - [0.742004, 0.224025, 0.467018], - [0.748378, 0.226377, 0.464794], - [0.754737, 0.228772, 0.462509], - [0.761077, 0.231214, 0.460162], - [0.767398, 0.233705, 0.457755], - [0.773695, 0.236249, 0.455289], - [0.779968, 0.238851, 0.452765], - [0.786212, 0.241514, 0.450184], - [0.792427, 0.244242, 0.447543], - [0.798608, 0.247040, 0.444848], - [0.804752, 0.249911, 0.442102], - [0.810855, 0.252861, 0.439305], - [0.816914, 0.255895, 0.436461], - [0.822926, 0.259016, 0.433573], - [0.828886, 0.262229, 0.430644], - [0.834791, 0.265540, 0.427671], - [0.840636, 0.268953, 0.424666], - [0.846416, 0.272473, 0.421631], - [0.852126, 0.276106, 0.418573], - [0.857763, 0.279857, 0.415496], - [0.863320, 0.283729, 0.412403], - [0.868793, 0.287728, 0.409303], - [0.874176, 0.291859, 0.406205], - [0.879464, 0.296125, 0.403118], - [0.884651, 0.300530, 0.400047], - [0.889731, 0.305079, 0.397002], - [0.894700, 0.309773, 0.393995], - [0.899552, 0.314616, 0.391037], - [0.904281, 0.319610, 0.388137], - [0.908884, 0.324755, 0.385308], - [0.913354, 0.330052, 0.382563], - [0.917689, 0.335500, 0.379915], - [0.921884, 0.341098, 0.377376], - [0.925937, 0.346844, 0.374959], - [0.929845, 0.352734, 0.372677], - [0.933606, 0.358764, 0.370541], - [0.937221, 0.364929, 0.368567], - [0.940687, 0.371224, 0.366762], - [0.944006, 0.377643, 0.365136], - [0.947180, 0.384178, 0.363701], - [0.950210, 0.390820, 0.362468], - [0.953099, 0.397563, 0.361438], - [0.955849, 0.404400, 0.360619], - [0.958464, 0.411324, 0.360014], - [0.960949, 0.418323, 0.359630], - [0.963310, 0.425390, 0.359469], - [0.965549, 0.432519, 0.359529], - [0.967671, 0.439703, 0.359810], - [0.969680, 0.446936, 0.360311], - [0.971582, 0.454210, 0.361030], - [0.973381, 0.461520, 0.361965], - [0.975082, 0.468861, 0.363111], - [0.976690, 0.476226, 0.364466], - [0.978210, 0.483612, 0.366025], - [0.979645, 0.491014, 0.367783], - [0.981000, 0.498428, 0.369734], - [0.982279, 0.505851, 0.371874], - [0.983485, 0.513280, 0.374198], - [0.984622, 0.520713, 0.376698], - [0.985693, 0.528148, 0.379371], - [0.986700, 0.535582, 0.382210], - [0.987646, 0.543015, 0.385210], - [0.988533, 0.550446, 0.388365], - [0.989363, 0.557873, 0.391671], - [0.990138, 0.565296, 0.395122], - [0.990871, 0.572706, 0.398714], - [0.991558, 0.580107, 0.402441], - [0.992196, 0.587502, 0.406299], - [0.992785, 0.594891, 0.410283], - [0.993326, 0.602275, 0.414390], - [0.993834, 0.609644, 0.418613], - [0.994309, 0.616999, 0.422950], - [0.994738, 0.624350, 0.427397], - [0.995122, 0.631696, 0.431951], - [0.995480, 0.639027, 0.436607], - [0.995810, 0.646344, 0.441361], - [0.996096, 0.653659, 0.446213], - [0.996341, 0.660969, 0.451160], - [0.996580, 0.668256, 0.456192], - [0.996775, 0.675541, 0.461314], - [0.996925, 0.682828, 0.466526], - [0.997077, 0.690088, 0.471811], - [0.997186, 0.697349, 0.477182], - [0.997254, 0.704611, 0.482635], - [0.997325, 0.711848, 0.488154], - [0.997351, 0.719089, 0.493755], - [0.997351, 0.726324, 0.499428], - [0.997341, 0.733545, 0.505167], - [0.997285, 0.740772, 0.510983], - [0.997228, 0.747981, 0.516859], - [0.997138, 0.755190, 0.522806], - [0.997019, 0.762398, 0.528821], - [0.996898, 0.769591, 0.534892], - [0.996727, 0.776795, 0.541039], - [0.996571, 0.783977, 0.547233], - [0.996369, 0.791167, 0.553499], - [0.996162, 0.798348, 0.559820], - [0.995932, 0.805527, 0.566202], - [0.995680, 0.812706, 0.572645], - [0.995424, 0.819875, 0.579140], - [0.995131, 0.827052, 0.585701], - [0.994851, 0.834213, 0.592307], - [0.994524, 0.841387, 0.598983], - [0.994222, 0.848540, 0.605696], - [0.993866, 0.855711, 0.612482], - [0.993545, 0.862859, 0.619299], - [0.993170, 0.870024, 0.626189], - [0.992831, 0.877168, 0.633109], - [0.992440, 0.884330, 0.640099], - [0.992089, 0.891470, 0.647116], - [0.991688, 0.898627, 0.654202], - [0.991332, 0.905763, 0.661309], - [0.990930, 0.912915, 0.668481], - [0.990570, 0.920049, 0.675675], - [0.990175, 0.927196, 0.682926], - [0.989815, 0.934329, 0.690198], - [0.989434, 0.941470, 0.697519], - [0.989077, 0.948604, 0.704863], - [0.988717, 0.955742, 0.712242], - [0.988367, 0.962878, 0.719649], - [0.988033, 0.970012, 0.727077], - [0.987691, 0.977154, 0.734536], - [0.987387, 0.984288, 0.742002], - [0.987053, 0.991438, 0.749504]] +magma = [ + [0.001462, 0.000466, 0.013866], + [0.002258, 0.001295, 0.018331], + [0.003279, 0.002305, 0.023708], + [0.004512, 0.003490, 0.029965], + [0.005950, 0.004843, 0.037130], + [0.007588, 0.006356, 0.044973], + [0.009426, 0.008022, 0.052844], + [0.011465, 0.009828, 0.060750], + [0.013708, 0.011771, 0.068667], + [0.016156, 0.013840, 0.076603], + [0.018815, 0.016026, 0.084584], + [0.021692, 0.018320, 0.092610], + [0.024792, 0.020715, 0.100676], + [0.028123, 0.023201, 0.108787], + [0.031696, 0.025765, 0.116965], + [0.035520, 0.028397, 0.125209], + [0.039608, 0.031090, 0.133515], + [0.043830, 0.033830, 0.141886], + [0.048062, 0.036607, 0.150327], + [0.052320, 0.039407, 0.158841], + [0.056615, 0.042160, 0.167446], + [0.060949, 0.044794, 0.176129], + [0.065330, 0.047318, 0.184892], + [0.069764, 0.049726, 0.193735], + [0.074257, 0.052017, 0.202660], + [0.078815, 0.054184, 0.211667], + [0.083446, 0.056225, 0.220755], + [0.088155, 0.058133, 0.229922], + [0.092949, 0.059904, 0.239164], + [0.097833, 0.061531, 0.248477], + [0.102815, 0.063010, 0.257854], + [0.107899, 0.064335, 0.267289], + [0.113094, 0.065492, 0.276784], + [0.118405, 0.066479, 0.286321], + [0.123833, 0.067295, 0.295879], + [0.129380, 0.067935, 0.305443], + [0.135053, 0.068391, 0.315000], + [0.140858, 0.068654, 0.324538], + [0.146785, 0.068738, 0.334011], + [0.152839, 0.068637, 0.343404], + [0.159018, 0.068354, 0.352688], + [0.165308, 0.067911, 0.361816], + [0.171713, 0.067305, 0.370771], + [0.178212, 0.066576, 0.379497], + [0.184801, 0.065732, 0.387973], + [0.191460, 0.064818, 0.396152], + [0.198177, 0.063862, 0.404009], + [0.204935, 0.062907, 0.411514], + [0.211718, 0.061992, 0.418647], + [0.218512, 0.061158, 0.425392], + [0.225302, 0.060445, 0.431742], + [0.232077, 0.059889, 0.437695], + [0.238826, 0.059517, 0.443256], + [0.245543, 0.059352, 0.448436], + [0.252220, 0.059415, 0.453248], + [0.258857, 0.059706, 0.457710], + [0.265447, 0.060237, 0.461840], + [0.271994, 0.060994, 0.465660], + [0.278493, 0.061978, 0.469190], + [0.284951, 0.063168, 0.472451], + [0.291366, 0.064553, 0.475462], + [0.297740, 0.066117, 0.478243], + [0.304081, 0.067835, 0.480812], + [0.310382, 0.069702, 0.483186], + [0.316654, 0.071690, 0.485380], + [0.322899, 0.073782, 0.487408], + [0.329114, 0.075972, 0.489287], + [0.335308, 0.078236, 0.491024], + [0.341482, 0.080564, 0.492631], + [0.347636, 0.082946, 0.494121], + [0.353773, 0.085373, 0.495501], + [0.359898, 0.087831, 0.496778], + [0.366012, 0.090314, 0.497960], + [0.372116, 0.092816, 0.499053], + [0.378211, 0.095332, 0.500067], + [0.384299, 0.097855, 0.501002], + [0.390384, 0.100379, 0.501864], + [0.396467, 0.102902, 0.502658], + [0.402548, 0.105420, 0.503386], + [0.408629, 0.107930, 0.504052], + [0.414709, 0.110431, 0.504662], + [0.420791, 0.112920, 0.505215], + [0.426877, 0.115395, 0.505714], + [0.432967, 0.117855, 0.506160], + [0.439062, 0.120298, 0.506555], + [0.445163, 0.122724, 0.506901], + [0.451271, 0.125132, 0.507198], + [0.457386, 0.127522, 0.507448], + [0.463508, 0.129893, 0.507652], + [0.469640, 0.132245, 0.507809], + [0.475780, 0.134577, 0.507921], + [0.481929, 0.136891, 0.507989], + [0.488088, 0.139186, 0.508011], + [0.494258, 0.141462, 0.507988], + [0.500438, 0.143719, 0.507920], + [0.506629, 0.145958, 0.507806], + [0.512831, 0.148179, 0.507648], + [0.519045, 0.150383, 0.507443], + [0.525270, 0.152569, 0.507192], + [0.531507, 0.154739, 0.506895], + [0.537755, 0.156894, 0.506551], + [0.544015, 0.159033, 0.506159], + [0.550287, 0.161158, 0.505719], + [0.556571, 0.163269, 0.505230], + [0.562866, 0.165368, 0.504692], + [0.569172, 0.167454, 0.504105], + [0.575490, 0.169530, 0.503466], + [0.581819, 0.171596, 0.502777], + [0.588158, 0.173652, 0.502035], + [0.594508, 0.175701, 0.501241], + [0.600868, 0.177743, 0.500394], + [0.607238, 0.179779, 0.499492], + [0.613617, 0.181811, 0.498536], + [0.620005, 0.183840, 0.497524], + [0.626401, 0.185867, 0.496456], + [0.632805, 0.187893, 0.495332], + [0.639216, 0.189921, 0.494150], + [0.645633, 0.191952, 0.492910], + [0.652056, 0.193986, 0.491611], + [0.658483, 0.196027, 0.490253], + [0.664915, 0.198075, 0.488836], + [0.671349, 0.200133, 0.487358], + [0.677786, 0.202203, 0.485819], + [0.684224, 0.204286, 0.484219], + [0.690661, 0.206384, 0.482558], + [0.697098, 0.208501, 0.480835], + [0.703532, 0.210638, 0.479049], + [0.709962, 0.212797, 0.477201], + [0.716387, 0.214982, 0.475290], + [0.722805, 0.217194, 0.473316], + [0.729216, 0.219437, 0.471279], + [0.735616, 0.221713, 0.469180], + [0.742004, 0.224025, 0.467018], + [0.748378, 0.226377, 0.464794], + [0.754737, 0.228772, 0.462509], + [0.761077, 0.231214, 0.460162], + [0.767398, 0.233705, 0.457755], + [0.773695, 0.236249, 0.455289], + [0.779968, 0.238851, 0.452765], + [0.786212, 0.241514, 0.450184], + [0.792427, 0.244242, 0.447543], + [0.798608, 0.247040, 0.444848], + [0.804752, 0.249911, 0.442102], + [0.810855, 0.252861, 0.439305], + [0.816914, 0.255895, 0.436461], + [0.822926, 0.259016, 0.433573], + [0.828886, 0.262229, 0.430644], + [0.834791, 0.265540, 0.427671], + [0.840636, 0.268953, 0.424666], + [0.846416, 0.272473, 0.421631], + [0.852126, 0.276106, 0.418573], + [0.857763, 0.279857, 0.415496], + [0.863320, 0.283729, 0.412403], + [0.868793, 0.287728, 0.409303], + [0.874176, 0.291859, 0.406205], + [0.879464, 0.296125, 0.403118], + [0.884651, 0.300530, 0.400047], + [0.889731, 0.305079, 0.397002], + [0.894700, 0.309773, 0.393995], + [0.899552, 0.314616, 0.391037], + [0.904281, 0.319610, 0.388137], + [0.908884, 0.324755, 0.385308], + [0.913354, 0.330052, 0.382563], + [0.917689, 0.335500, 0.379915], + [0.921884, 0.341098, 0.377376], + [0.925937, 0.346844, 0.374959], + [0.929845, 0.352734, 0.372677], + [0.933606, 0.358764, 0.370541], + [0.937221, 0.364929, 0.368567], + [0.940687, 0.371224, 0.366762], + [0.944006, 0.377643, 0.365136], + [0.947180, 0.384178, 0.363701], + [0.950210, 0.390820, 0.362468], + [0.953099, 0.397563, 0.361438], + [0.955849, 0.404400, 0.360619], + [0.958464, 0.411324, 0.360014], + [0.960949, 0.418323, 0.359630], + [0.963310, 0.425390, 0.359469], + [0.965549, 0.432519, 0.359529], + [0.967671, 0.439703, 0.359810], + [0.969680, 0.446936, 0.360311], + [0.971582, 0.454210, 0.361030], + [0.973381, 0.461520, 0.361965], + [0.975082, 0.468861, 0.363111], + [0.976690, 0.476226, 0.364466], + [0.978210, 0.483612, 0.366025], + [0.979645, 0.491014, 0.367783], + [0.981000, 0.498428, 0.369734], + [0.982279, 0.505851, 0.371874], + [0.983485, 0.513280, 0.374198], + [0.984622, 0.520713, 0.376698], + [0.985693, 0.528148, 0.379371], + [0.986700, 0.535582, 0.382210], + [0.987646, 0.543015, 0.385210], + [0.988533, 0.550446, 0.388365], + [0.989363, 0.557873, 0.391671], + [0.990138, 0.565296, 0.395122], + [0.990871, 0.572706, 0.398714], + [0.991558, 0.580107, 0.402441], + [0.992196, 0.587502, 0.406299], + [0.992785, 0.594891, 0.410283], + [0.993326, 0.602275, 0.414390], + [0.993834, 0.609644, 0.418613], + [0.994309, 0.616999, 0.422950], + [0.994738, 0.624350, 0.427397], + [0.995122, 0.631696, 0.431951], + [0.995480, 0.639027, 0.436607], + [0.995810, 0.646344, 0.441361], + [0.996096, 0.653659, 0.446213], + [0.996341, 0.660969, 0.451160], + [0.996580, 0.668256, 0.456192], + [0.996775, 0.675541, 0.461314], + [0.996925, 0.682828, 0.466526], + [0.997077, 0.690088, 0.471811], + [0.997186, 0.697349, 0.477182], + [0.997254, 0.704611, 0.482635], + [0.997325, 0.711848, 0.488154], + [0.997351, 0.719089, 0.493755], + [0.997351, 0.726324, 0.499428], + [0.997341, 0.733545, 0.505167], + [0.997285, 0.740772, 0.510983], + [0.997228, 0.747981, 0.516859], + [0.997138, 0.755190, 0.522806], + [0.997019, 0.762398, 0.528821], + [0.996898, 0.769591, 0.534892], + [0.996727, 0.776795, 0.541039], + [0.996571, 0.783977, 0.547233], + [0.996369, 0.791167, 0.553499], + [0.996162, 0.798348, 0.559820], + [0.995932, 0.805527, 0.566202], + [0.995680, 0.812706, 0.572645], + [0.995424, 0.819875, 0.579140], + [0.995131, 0.827052, 0.585701], + [0.994851, 0.834213, 0.592307], + [0.994524, 0.841387, 0.598983], + [0.994222, 0.848540, 0.605696], + [0.993866, 0.855711, 0.612482], + [0.993545, 0.862859, 0.619299], + [0.993170, 0.870024, 0.626189], + [0.992831, 0.877168, 0.633109], + [0.992440, 0.884330, 0.640099], + [0.992089, 0.891470, 0.647116], + [0.991688, 0.898627, 0.654202], + [0.991332, 0.905763, 0.661309], + [0.990930, 0.912915, 0.668481], + [0.990570, 0.920049, 0.675675], + [0.990175, 0.927196, 0.682926], + [0.989815, 0.934329, 0.690198], + [0.989434, 0.941470, 0.697519], + [0.989077, 0.948604, 0.704863], + [0.988717, 0.955742, 0.712242], + [0.988367, 0.962878, 0.719649], + [0.988033, 0.970012, 0.727077], + [0.987691, 0.977154, 0.734536], + [0.987387, 0.984288, 0.742002], + [0.987053, 0.991438, 0.749504], +] -inferno = [[0.001462, 0.000466, 0.013866], - [0.002267, 0.001270, 0.018570], - [0.003299, 0.002249, 0.024239], - [0.004547, 0.003392, 0.030909], - [0.006006, 0.004692, 0.038558], - [0.007676, 0.006136, 0.046836], - [0.009561, 0.007713, 0.055143], - [0.011663, 0.009417, 0.063460], - [0.013995, 0.011225, 0.071862], - [0.016561, 0.013136, 0.080282], - [0.019373, 0.015133, 0.088767], - [0.022447, 0.017199, 0.097327], - [0.025793, 0.019331, 0.105930], - [0.029432, 0.021503, 0.114621], - [0.033385, 0.023702, 0.123397], - [0.037668, 0.025921, 0.132232], - [0.042253, 0.028139, 0.141141], - [0.046915, 0.030324, 0.150164], - [0.051644, 0.032474, 0.159254], - [0.056449, 0.034569, 0.168414], - [0.061340, 0.036590, 0.177642], - [0.066331, 0.038504, 0.186962], - [0.071429, 0.040294, 0.196354], - [0.076637, 0.041905, 0.205799], - [0.081962, 0.043328, 0.215289], - [0.087411, 0.044556, 0.224813], - [0.092990, 0.045583, 0.234358], - [0.098702, 0.046402, 0.243904], - [0.104551, 0.047008, 0.253430], - [0.110536, 0.047399, 0.262912], - [0.116656, 0.047574, 0.272321], - [0.122908, 0.047536, 0.281624], - [0.129285, 0.047293, 0.290788], - [0.135778, 0.046856, 0.299776], - [0.142378, 0.046242, 0.308553], - [0.149073, 0.045468, 0.317085], - [0.155850, 0.044559, 0.325338], - [0.162689, 0.043554, 0.333277], - [0.169575, 0.042489, 0.340874], - [0.176493, 0.041402, 0.348111], - [0.183429, 0.040329, 0.354971], - [0.190367, 0.039309, 0.361447], - [0.197297, 0.038400, 0.367535], - [0.204209, 0.037632, 0.373238], - [0.211095, 0.037030, 0.378563], - [0.217949, 0.036615, 0.383522], - [0.224763, 0.036405, 0.388129], - [0.231538, 0.036405, 0.392400], - [0.238273, 0.036621, 0.396353], - [0.244967, 0.037055, 0.400007], - [0.251620, 0.037705, 0.403378], - [0.258234, 0.038571, 0.406485], - [0.264810, 0.039647, 0.409345], - [0.271347, 0.040922, 0.411976], - [0.277850, 0.042353, 0.414392], - [0.284321, 0.043933, 0.416608], - [0.290763, 0.045644, 0.418637], - [0.297178, 0.047470, 0.420491], - [0.303568, 0.049396, 0.422182], - [0.309935, 0.051407, 0.423721], - [0.316282, 0.053490, 0.425116], - [0.322610, 0.055634, 0.426377], - [0.328921, 0.057827, 0.427511], - [0.335217, 0.060060, 0.428524], - [0.341500, 0.062325, 0.429425], - [0.347771, 0.064616, 0.430217], - [0.354032, 0.066925, 0.430906], - [0.360284, 0.069247, 0.431497], - [0.366529, 0.071579, 0.431994], - [0.372768, 0.073915, 0.432400], - [0.379001, 0.076253, 0.432719], - [0.385228, 0.078591, 0.432955], - [0.391453, 0.080927, 0.433109], - [0.397674, 0.083257, 0.433183], - [0.403894, 0.085580, 0.433179], - [0.410113, 0.087896, 0.433098], - [0.416331, 0.090203, 0.432943], - [0.422549, 0.092501, 0.432714], - [0.428768, 0.094790, 0.432412], - [0.434987, 0.097069, 0.432039], - [0.441207, 0.099338, 0.431594], - [0.447428, 0.101597, 0.431080], - [0.453651, 0.103848, 0.430498], - [0.459875, 0.106089, 0.429846], - [0.466100, 0.108322, 0.429125], - [0.472328, 0.110547, 0.428334], - [0.478558, 0.112764, 0.427475], - [0.484789, 0.114974, 0.426548], - [0.491022, 0.117179, 0.425552], - [0.497257, 0.119379, 0.424488], - [0.503493, 0.121575, 0.423356], - [0.509730, 0.123769, 0.422156], - [0.515967, 0.125960, 0.420887], - [0.522206, 0.128150, 0.419549], - [0.528444, 0.130341, 0.418142], - [0.534683, 0.132534, 0.416667], - [0.540920, 0.134729, 0.415123], - [0.547157, 0.136929, 0.413511], - [0.553392, 0.139134, 0.411829], - [0.559624, 0.141346, 0.410078], - [0.565854, 0.143567, 0.408258], - [0.572081, 0.145797, 0.406369], - [0.578304, 0.148039, 0.404411], - [0.584521, 0.150294, 0.402385], - [0.590734, 0.152563, 0.400290], - [0.596940, 0.154848, 0.398125], - [0.603139, 0.157151, 0.395891], - [0.609330, 0.159474, 0.393589], - [0.615513, 0.161817, 0.391219], - [0.621685, 0.164184, 0.388781], - [0.627847, 0.166575, 0.386276], - [0.633998, 0.168992, 0.383704], - [0.640135, 0.171438, 0.381065], - [0.646260, 0.173914, 0.378359], - [0.652369, 0.176421, 0.375586], - [0.658463, 0.178962, 0.372748], - [0.664540, 0.181539, 0.369846], - [0.670599, 0.184153, 0.366879], - [0.676638, 0.186807, 0.363849], - [0.682656, 0.189501, 0.360757], - [0.688653, 0.192239, 0.357603], - [0.694627, 0.195021, 0.354388], - [0.700576, 0.197851, 0.351113], - [0.706500, 0.200728, 0.347777], - [0.712396, 0.203656, 0.344383], - [0.718264, 0.206636, 0.340931], - [0.724103, 0.209670, 0.337424], - [0.729909, 0.212759, 0.333861], - [0.735683, 0.215906, 0.330245], - [0.741423, 0.219112, 0.326576], - [0.747127, 0.222378, 0.322856], - [0.752794, 0.225706, 0.319085], - [0.758422, 0.229097, 0.315266], - [0.764010, 0.232554, 0.311399], - [0.769556, 0.236077, 0.307485], - [0.775059, 0.239667, 0.303526], - [0.780517, 0.243327, 0.299523], - [0.785929, 0.247056, 0.295477], - [0.791293, 0.250856, 0.291390], - [0.796607, 0.254728, 0.287264], - [0.801871, 0.258674, 0.283099], - [0.807082, 0.262692, 0.278898], - [0.812239, 0.266786, 0.274661], - [0.817341, 0.270954, 0.270390], - [0.822386, 0.275197, 0.266085], - [0.827372, 0.279517, 0.261750], - [0.832299, 0.283913, 0.257383], - [0.837165, 0.288385, 0.252988], - [0.841969, 0.292933, 0.248564], - [0.846709, 0.297559, 0.244113], - [0.851384, 0.302260, 0.239636], - [0.855992, 0.307038, 0.235133], - [0.860533, 0.311892, 0.230606], - [0.865006, 0.316822, 0.226055], - [0.869409, 0.321827, 0.221482], - [0.873741, 0.326906, 0.216886], - [0.878001, 0.332060, 0.212268], - [0.882188, 0.337287, 0.207628], - [0.886302, 0.342586, 0.202968], - [0.890341, 0.347957, 0.198286], - [0.894305, 0.353399, 0.193584], - [0.898192, 0.358911, 0.188860], - [0.902003, 0.364492, 0.184116], - [0.905735, 0.370140, 0.179350], - [0.909390, 0.375856, 0.174563], - [0.912966, 0.381636, 0.169755], - [0.916462, 0.387481, 0.164924], - [0.919879, 0.393389, 0.160070], - [0.923215, 0.399359, 0.155193], - [0.926470, 0.405389, 0.150292], - [0.929644, 0.411479, 0.145367], - [0.932737, 0.417627, 0.140417], - [0.935747, 0.423831, 0.135440], - [0.938675, 0.430091, 0.130438], - [0.941521, 0.436405, 0.125409], - [0.944285, 0.442772, 0.120354], - [0.946965, 0.449191, 0.115272], - [0.949562, 0.455660, 0.110164], - [0.952075, 0.462178, 0.105031], - [0.954506, 0.468744, 0.099874], - [0.956852, 0.475356, 0.094695], - [0.959114, 0.482014, 0.089499], - [0.961293, 0.488716, 0.084289], - [0.963387, 0.495462, 0.079073], - [0.965397, 0.502249, 0.073859], - [0.967322, 0.509078, 0.068659], - [0.969163, 0.515946, 0.063488], - [0.970919, 0.522853, 0.058367], - [0.972590, 0.529798, 0.053324], - [0.974176, 0.536780, 0.048392], - [0.975677, 0.543798, 0.043618], - [0.977092, 0.550850, 0.039050], - [0.978422, 0.557937, 0.034931], - [0.979666, 0.565057, 0.031409], - [0.980824, 0.572209, 0.028508], - [0.981895, 0.579392, 0.026250], - [0.982881, 0.586606, 0.024661], - [0.983779, 0.593849, 0.023770], - [0.984591, 0.601122, 0.023606], - [0.985315, 0.608422, 0.024202], - [0.985952, 0.615750, 0.025592], - [0.986502, 0.623105, 0.027814], - [0.986964, 0.630485, 0.030908], - [0.987337, 0.637890, 0.034916], - [0.987622, 0.645320, 0.039886], - [0.987819, 0.652773, 0.045581], - [0.987926, 0.660250, 0.051750], - [0.987945, 0.667748, 0.058329], - [0.987874, 0.675267, 0.065257], - [0.987714, 0.682807, 0.072489], - [0.987464, 0.690366, 0.079990], - [0.987124, 0.697944, 0.087731], - [0.986694, 0.705540, 0.095694], - [0.986175, 0.713153, 0.103863], - [0.985566, 0.720782, 0.112229], - [0.984865, 0.728427, 0.120785], - [0.984075, 0.736087, 0.129527], - [0.983196, 0.743758, 0.138453], - [0.982228, 0.751442, 0.147565], - [0.981173, 0.759135, 0.156863], - [0.980032, 0.766837, 0.166353], - [0.978806, 0.774545, 0.176037], - [0.977497, 0.782258, 0.185923], - [0.976108, 0.789974, 0.196018], - [0.974638, 0.797692, 0.206332], - [0.973088, 0.805409, 0.216877], - [0.971468, 0.813122, 0.227658], - [0.969783, 0.820825, 0.238686], - [0.968041, 0.828515, 0.249972], - [0.966243, 0.836191, 0.261534], - [0.964394, 0.843848, 0.273391], - [0.962517, 0.851476, 0.285546], - [0.960626, 0.859069, 0.298010], - [0.958720, 0.866624, 0.310820], - [0.956834, 0.874129, 0.323974], - [0.954997, 0.881569, 0.337475], - [0.953215, 0.888942, 0.351369], - [0.951546, 0.896226, 0.365627], - [0.950018, 0.903409, 0.380271], - [0.948683, 0.910473, 0.395289], - [0.947594, 0.917399, 0.410665], - [0.946809, 0.924168, 0.426373], - [0.946392, 0.930761, 0.442367], - [0.946403, 0.937159, 0.458592], - [0.946903, 0.943348, 0.474970], - [0.947937, 0.949318, 0.491426], - [0.949545, 0.955063, 0.507860], - [0.951740, 0.960587, 0.524203], - [0.954529, 0.965896, 0.540361], - [0.957896, 0.971003, 0.556275], - [0.961812, 0.975924, 0.571925], - [0.966249, 0.980678, 0.587206], - [0.971162, 0.985282, 0.602154], - [0.976511, 0.989753, 0.616760], - [0.982257, 0.994109, 0.631017], - [0.988362, 0.998364, 0.644924]] +inferno = [ + [0.001462, 0.000466, 0.013866], + [0.002267, 0.001270, 0.018570], + [0.003299, 0.002249, 0.024239], + [0.004547, 0.003392, 0.030909], + [0.006006, 0.004692, 0.038558], + [0.007676, 0.006136, 0.046836], + [0.009561, 0.007713, 0.055143], + [0.011663, 0.009417, 0.063460], + [0.013995, 0.011225, 0.071862], + [0.016561, 0.013136, 0.080282], + [0.019373, 0.015133, 0.088767], + [0.022447, 0.017199, 0.097327], + [0.025793, 0.019331, 0.105930], + [0.029432, 0.021503, 0.114621], + [0.033385, 0.023702, 0.123397], + [0.037668, 0.025921, 0.132232], + [0.042253, 0.028139, 0.141141], + [0.046915, 0.030324, 0.150164], + [0.051644, 0.032474, 0.159254], + [0.056449, 0.034569, 0.168414], + [0.061340, 0.036590, 0.177642], + [0.066331, 0.038504, 0.186962], + [0.071429, 0.040294, 0.196354], + [0.076637, 0.041905, 0.205799], + [0.081962, 0.043328, 0.215289], + [0.087411, 0.044556, 0.224813], + [0.092990, 0.045583, 0.234358], + [0.098702, 0.046402, 0.243904], + [0.104551, 0.047008, 0.253430], + [0.110536, 0.047399, 0.262912], + [0.116656, 0.047574, 0.272321], + [0.122908, 0.047536, 0.281624], + [0.129285, 0.047293, 0.290788], + [0.135778, 0.046856, 0.299776], + [0.142378, 0.046242, 0.308553], + [0.149073, 0.045468, 0.317085], + [0.155850, 0.044559, 0.325338], + [0.162689, 0.043554, 0.333277], + [0.169575, 0.042489, 0.340874], + [0.176493, 0.041402, 0.348111], + [0.183429, 0.040329, 0.354971], + [0.190367, 0.039309, 0.361447], + [0.197297, 0.038400, 0.367535], + [0.204209, 0.037632, 0.373238], + [0.211095, 0.037030, 0.378563], + [0.217949, 0.036615, 0.383522], + [0.224763, 0.036405, 0.388129], + [0.231538, 0.036405, 0.392400], + [0.238273, 0.036621, 0.396353], + [0.244967, 0.037055, 0.400007], + [0.251620, 0.037705, 0.403378], + [0.258234, 0.038571, 0.406485], + [0.264810, 0.039647, 0.409345], + [0.271347, 0.040922, 0.411976], + [0.277850, 0.042353, 0.414392], + [0.284321, 0.043933, 0.416608], + [0.290763, 0.045644, 0.418637], + [0.297178, 0.047470, 0.420491], + [0.303568, 0.049396, 0.422182], + [0.309935, 0.051407, 0.423721], + [0.316282, 0.053490, 0.425116], + [0.322610, 0.055634, 0.426377], + [0.328921, 0.057827, 0.427511], + [0.335217, 0.060060, 0.428524], + [0.341500, 0.062325, 0.429425], + [0.347771, 0.064616, 0.430217], + [0.354032, 0.066925, 0.430906], + [0.360284, 0.069247, 0.431497], + [0.366529, 0.071579, 0.431994], + [0.372768, 0.073915, 0.432400], + [0.379001, 0.076253, 0.432719], + [0.385228, 0.078591, 0.432955], + [0.391453, 0.080927, 0.433109], + [0.397674, 0.083257, 0.433183], + [0.403894, 0.085580, 0.433179], + [0.410113, 0.087896, 0.433098], + [0.416331, 0.090203, 0.432943], + [0.422549, 0.092501, 0.432714], + [0.428768, 0.094790, 0.432412], + [0.434987, 0.097069, 0.432039], + [0.441207, 0.099338, 0.431594], + [0.447428, 0.101597, 0.431080], + [0.453651, 0.103848, 0.430498], + [0.459875, 0.106089, 0.429846], + [0.466100, 0.108322, 0.429125], + [0.472328, 0.110547, 0.428334], + [0.478558, 0.112764, 0.427475], + [0.484789, 0.114974, 0.426548], + [0.491022, 0.117179, 0.425552], + [0.497257, 0.119379, 0.424488], + [0.503493, 0.121575, 0.423356], + [0.509730, 0.123769, 0.422156], + [0.515967, 0.125960, 0.420887], + [0.522206, 0.128150, 0.419549], + [0.528444, 0.130341, 0.418142], + [0.534683, 0.132534, 0.416667], + [0.540920, 0.134729, 0.415123], + [0.547157, 0.136929, 0.413511], + [0.553392, 0.139134, 0.411829], + [0.559624, 0.141346, 0.410078], + [0.565854, 0.143567, 0.408258], + [0.572081, 0.145797, 0.406369], + [0.578304, 0.148039, 0.404411], + [0.584521, 0.150294, 0.402385], + [0.590734, 0.152563, 0.400290], + [0.596940, 0.154848, 0.398125], + [0.603139, 0.157151, 0.395891], + [0.609330, 0.159474, 0.393589], + [0.615513, 0.161817, 0.391219], + [0.621685, 0.164184, 0.388781], + [0.627847, 0.166575, 0.386276], + [0.633998, 0.168992, 0.383704], + [0.640135, 0.171438, 0.381065], + [0.646260, 0.173914, 0.378359], + [0.652369, 0.176421, 0.375586], + [0.658463, 0.178962, 0.372748], + [0.664540, 0.181539, 0.369846], + [0.670599, 0.184153, 0.366879], + [0.676638, 0.186807, 0.363849], + [0.682656, 0.189501, 0.360757], + [0.688653, 0.192239, 0.357603], + [0.694627, 0.195021, 0.354388], + [0.700576, 0.197851, 0.351113], + [0.706500, 0.200728, 0.347777], + [0.712396, 0.203656, 0.344383], + [0.718264, 0.206636, 0.340931], + [0.724103, 0.209670, 0.337424], + [0.729909, 0.212759, 0.333861], + [0.735683, 0.215906, 0.330245], + [0.741423, 0.219112, 0.326576], + [0.747127, 0.222378, 0.322856], + [0.752794, 0.225706, 0.319085], + [0.758422, 0.229097, 0.315266], + [0.764010, 0.232554, 0.311399], + [0.769556, 0.236077, 0.307485], + [0.775059, 0.239667, 0.303526], + [0.780517, 0.243327, 0.299523], + [0.785929, 0.247056, 0.295477], + [0.791293, 0.250856, 0.291390], + [0.796607, 0.254728, 0.287264], + [0.801871, 0.258674, 0.283099], + [0.807082, 0.262692, 0.278898], + [0.812239, 0.266786, 0.274661], + [0.817341, 0.270954, 0.270390], + [0.822386, 0.275197, 0.266085], + [0.827372, 0.279517, 0.261750], + [0.832299, 0.283913, 0.257383], + [0.837165, 0.288385, 0.252988], + [0.841969, 0.292933, 0.248564], + [0.846709, 0.297559, 0.244113], + [0.851384, 0.302260, 0.239636], + [0.855992, 0.307038, 0.235133], + [0.860533, 0.311892, 0.230606], + [0.865006, 0.316822, 0.226055], + [0.869409, 0.321827, 0.221482], + [0.873741, 0.326906, 0.216886], + [0.878001, 0.332060, 0.212268], + [0.882188, 0.337287, 0.207628], + [0.886302, 0.342586, 0.202968], + [0.890341, 0.347957, 0.198286], + [0.894305, 0.353399, 0.193584], + [0.898192, 0.358911, 0.188860], + [0.902003, 0.364492, 0.184116], + [0.905735, 0.370140, 0.179350], + [0.909390, 0.375856, 0.174563], + [0.912966, 0.381636, 0.169755], + [0.916462, 0.387481, 0.164924], + [0.919879, 0.393389, 0.160070], + [0.923215, 0.399359, 0.155193], + [0.926470, 0.405389, 0.150292], + [0.929644, 0.411479, 0.145367], + [0.932737, 0.417627, 0.140417], + [0.935747, 0.423831, 0.135440], + [0.938675, 0.430091, 0.130438], + [0.941521, 0.436405, 0.125409], + [0.944285, 0.442772, 0.120354], + [0.946965, 0.449191, 0.115272], + [0.949562, 0.455660, 0.110164], + [0.952075, 0.462178, 0.105031], + [0.954506, 0.468744, 0.099874], + [0.956852, 0.475356, 0.094695], + [0.959114, 0.482014, 0.089499], + [0.961293, 0.488716, 0.084289], + [0.963387, 0.495462, 0.079073], + [0.965397, 0.502249, 0.073859], + [0.967322, 0.509078, 0.068659], + [0.969163, 0.515946, 0.063488], + [0.970919, 0.522853, 0.058367], + [0.972590, 0.529798, 0.053324], + [0.974176, 0.536780, 0.048392], + [0.975677, 0.543798, 0.043618], + [0.977092, 0.550850, 0.039050], + [0.978422, 0.557937, 0.034931], + [0.979666, 0.565057, 0.031409], + [0.980824, 0.572209, 0.028508], + [0.981895, 0.579392, 0.026250], + [0.982881, 0.586606, 0.024661], + [0.983779, 0.593849, 0.023770], + [0.984591, 0.601122, 0.023606], + [0.985315, 0.608422, 0.024202], + [0.985952, 0.615750, 0.025592], + [0.986502, 0.623105, 0.027814], + [0.986964, 0.630485, 0.030908], + [0.987337, 0.637890, 0.034916], + [0.987622, 0.645320, 0.039886], + [0.987819, 0.652773, 0.045581], + [0.987926, 0.660250, 0.051750], + [0.987945, 0.667748, 0.058329], + [0.987874, 0.675267, 0.065257], + [0.987714, 0.682807, 0.072489], + [0.987464, 0.690366, 0.079990], + [0.987124, 0.697944, 0.087731], + [0.986694, 0.705540, 0.095694], + [0.986175, 0.713153, 0.103863], + [0.985566, 0.720782, 0.112229], + [0.984865, 0.728427, 0.120785], + [0.984075, 0.736087, 0.129527], + [0.983196, 0.743758, 0.138453], + [0.982228, 0.751442, 0.147565], + [0.981173, 0.759135, 0.156863], + [0.980032, 0.766837, 0.166353], + [0.978806, 0.774545, 0.176037], + [0.977497, 0.782258, 0.185923], + [0.976108, 0.789974, 0.196018], + [0.974638, 0.797692, 0.206332], + [0.973088, 0.805409, 0.216877], + [0.971468, 0.813122, 0.227658], + [0.969783, 0.820825, 0.238686], + [0.968041, 0.828515, 0.249972], + [0.966243, 0.836191, 0.261534], + [0.964394, 0.843848, 0.273391], + [0.962517, 0.851476, 0.285546], + [0.960626, 0.859069, 0.298010], + [0.958720, 0.866624, 0.310820], + [0.956834, 0.874129, 0.323974], + [0.954997, 0.881569, 0.337475], + [0.953215, 0.888942, 0.351369], + [0.951546, 0.896226, 0.365627], + [0.950018, 0.903409, 0.380271], + [0.948683, 0.910473, 0.395289], + [0.947594, 0.917399, 0.410665], + [0.946809, 0.924168, 0.426373], + [0.946392, 0.930761, 0.442367], + [0.946403, 0.937159, 0.458592], + [0.946903, 0.943348, 0.474970], + [0.947937, 0.949318, 0.491426], + [0.949545, 0.955063, 0.507860], + [0.951740, 0.960587, 0.524203], + [0.954529, 0.965896, 0.540361], + [0.957896, 0.971003, 0.556275], + [0.961812, 0.975924, 0.571925], + [0.966249, 0.980678, 0.587206], + [0.971162, 0.985282, 0.602154], + [0.976511, 0.989753, 0.616760], + [0.982257, 0.994109, 0.631017], + [0.988362, 0.998364, 0.644924], +] -plasma = [[0.050383, 0.029803, 0.527975], - [0.063536, 0.028426, 0.533124], - [0.075353, 0.027206, 0.538007], - [0.086222, 0.026125, 0.542658], - [0.096379, 0.025165, 0.547103], - [0.105980, 0.024309, 0.551368], - [0.115124, 0.023556, 0.555468], - [0.123903, 0.022878, 0.559423], - [0.132381, 0.022258, 0.563250], - [0.140603, 0.021687, 0.566959], - [0.148607, 0.021154, 0.570562], - [0.156421, 0.020651, 0.574065], - [0.164070, 0.020171, 0.577478], - [0.171574, 0.019706, 0.580806], - [0.178950, 0.019252, 0.584054], - [0.186213, 0.018803, 0.587228], - [0.193374, 0.018354, 0.590330], - [0.200445, 0.017902, 0.593364], - [0.207435, 0.017442, 0.596333], - [0.214350, 0.016973, 0.599239], - [0.221197, 0.016497, 0.602083], - [0.227983, 0.016007, 0.604867], - [0.234715, 0.015502, 0.607592], - [0.241396, 0.014979, 0.610259], - [0.248032, 0.014439, 0.612868], - [0.254627, 0.013882, 0.615419], - [0.261183, 0.013308, 0.617911], - [0.267703, 0.012716, 0.620346], - [0.274191, 0.012109, 0.622722], - [0.280648, 0.011488, 0.625038], - [0.287076, 0.010855, 0.627295], - [0.293478, 0.010213, 0.629490], - [0.299855, 0.009561, 0.631624], - [0.306210, 0.008902, 0.633694], - [0.312543, 0.008239, 0.635700], - [0.318856, 0.007576, 0.637640], - [0.325150, 0.006915, 0.639512], - [0.331426, 0.006261, 0.641316], - [0.337683, 0.005618, 0.643049], - [0.343925, 0.004991, 0.644710], - [0.350150, 0.004382, 0.646298], - [0.356359, 0.003798, 0.647810], - [0.362553, 0.003243, 0.649245], - [0.368733, 0.002724, 0.650601], - [0.374897, 0.002245, 0.651876], - [0.381047, 0.001814, 0.653068], - [0.387183, 0.001434, 0.654177], - [0.393304, 0.001114, 0.655199], - [0.399411, 0.000859, 0.656133], - [0.405503, 0.000678, 0.656977], - [0.411580, 0.000577, 0.657730], - [0.417642, 0.000564, 0.658390], - [0.423689, 0.000646, 0.658956], - [0.429719, 0.000831, 0.659425], - [0.435734, 0.001127, 0.659797], - [0.441732, 0.001540, 0.660069], - [0.447714, 0.002080, 0.660240], - [0.453677, 0.002755, 0.660310], - [0.459623, 0.003574, 0.660277], - [0.465550, 0.004545, 0.660139], - [0.471457, 0.005678, 0.659897], - [0.477344, 0.006980, 0.659549], - [0.483210, 0.008460, 0.659095], - [0.489055, 0.010127, 0.658534], - [0.494877, 0.011990, 0.657865], - [0.500678, 0.014055, 0.657088], - [0.506454, 0.016333, 0.656202], - [0.512206, 0.018833, 0.655209], - [0.517933, 0.021563, 0.654109], - [0.523633, 0.024532, 0.652901], - [0.529306, 0.027747, 0.651586], - [0.534952, 0.031217, 0.650165], - [0.540570, 0.034950, 0.648640], - [0.546157, 0.038954, 0.647010], - [0.551715, 0.043136, 0.645277], - [0.557243, 0.047331, 0.643443], - [0.562738, 0.051545, 0.641509], - [0.568201, 0.055778, 0.639477], - [0.573632, 0.060028, 0.637349], - [0.579029, 0.064296, 0.635126], - [0.584391, 0.068579, 0.632812], - [0.589719, 0.072878, 0.630408], - [0.595011, 0.077190, 0.627917], - [0.600266, 0.081516, 0.625342], - [0.605485, 0.085854, 0.622686], - [0.610667, 0.090204, 0.619951], - [0.615812, 0.094564, 0.617140], - [0.620919, 0.098934, 0.614257], - [0.625987, 0.103312, 0.611305], - [0.631017, 0.107699, 0.608287], - [0.636008, 0.112092, 0.605205], - [0.640959, 0.116492, 0.602065], - [0.645872, 0.120898, 0.598867], - [0.650746, 0.125309, 0.595617], - [0.655580, 0.129725, 0.592317], - [0.660374, 0.134144, 0.588971], - [0.665129, 0.138566, 0.585582], - [0.669845, 0.142992, 0.582154], - [0.674522, 0.147419, 0.578688], - [0.679160, 0.151848, 0.575189], - [0.683758, 0.156278, 0.571660], - [0.688318, 0.160709, 0.568103], - [0.692840, 0.165141, 0.564522], - [0.697324, 0.169573, 0.560919], - [0.701769, 0.174005, 0.557296], - [0.706178, 0.178437, 0.553657], - [0.710549, 0.182868, 0.550004], - [0.714883, 0.187299, 0.546338], - [0.719181, 0.191729, 0.542663], - [0.723444, 0.196158, 0.538981], - [0.727670, 0.200586, 0.535293], - [0.731862, 0.205013, 0.531601], - [0.736019, 0.209439, 0.527908], - [0.740143, 0.213864, 0.524216], - [0.744232, 0.218288, 0.520524], - [0.748289, 0.222711, 0.516834], - [0.752312, 0.227133, 0.513149], - [0.756304, 0.231555, 0.509468], - [0.760264, 0.235976, 0.505794], - [0.764193, 0.240396, 0.502126], - [0.768090, 0.244817, 0.498465], - [0.771958, 0.249237, 0.494813], - [0.775796, 0.253658, 0.491171], - [0.779604, 0.258078, 0.487539], - [0.783383, 0.262500, 0.483918], - [0.787133, 0.266922, 0.480307], - [0.790855, 0.271345, 0.476706], - [0.794549, 0.275770, 0.473117], - [0.798216, 0.280197, 0.469538], - [0.801855, 0.284626, 0.465971], - [0.805467, 0.289057, 0.462415], - [0.809052, 0.293491, 0.458870], - [0.812612, 0.297928, 0.455338], - [0.816144, 0.302368, 0.451816], - [0.819651, 0.306812, 0.448306], - [0.823132, 0.311261, 0.444806], - [0.826588, 0.315714, 0.441316], - [0.830018, 0.320172, 0.437836], - [0.833422, 0.324635, 0.434366], - [0.836801, 0.329105, 0.430905], - [0.840155, 0.333580, 0.427455], - [0.843484, 0.338062, 0.424013], - [0.846788, 0.342551, 0.420579], - [0.850066, 0.347048, 0.417153], - [0.853319, 0.351553, 0.413734], - [0.856547, 0.356066, 0.410322], - [0.859750, 0.360588, 0.406917], - [0.862927, 0.365119, 0.403519], - [0.866078, 0.369660, 0.400126], - [0.869203, 0.374212, 0.396738], - [0.872303, 0.378774, 0.393355], - [0.875376, 0.383347, 0.389976], - [0.878423, 0.387932, 0.386600], - [0.881443, 0.392529, 0.383229], - [0.884436, 0.397139, 0.379860], - [0.887402, 0.401762, 0.376494], - [0.890340, 0.406398, 0.373130], - [0.893250, 0.411048, 0.369768], - [0.896131, 0.415712, 0.366407], - [0.898984, 0.420392, 0.363047], - [0.901807, 0.425087, 0.359688], - [0.904601, 0.429797, 0.356329], - [0.907365, 0.434524, 0.352970], - [0.910098, 0.439268, 0.349610], - [0.912800, 0.444029, 0.346251], - [0.915471, 0.448807, 0.342890], - [0.918109, 0.453603, 0.339529], - [0.920714, 0.458417, 0.336166], - [0.923287, 0.463251, 0.332801], - [0.925825, 0.468103, 0.329435], - [0.928329, 0.472975, 0.326067], - [0.930798, 0.477867, 0.322697], - [0.933232, 0.482780, 0.319325], - [0.935630, 0.487712, 0.315952], - [0.937990, 0.492667, 0.312575], - [0.940313, 0.497642, 0.309197], - [0.942598, 0.502639, 0.305816], - [0.944844, 0.507658, 0.302433], - [0.947051, 0.512699, 0.299049], - [0.949217, 0.517763, 0.295662], - [0.951344, 0.522850, 0.292275], - [0.953428, 0.527960, 0.288883], - [0.955470, 0.533093, 0.285490], - [0.957469, 0.538250, 0.282096], - [0.959424, 0.543431, 0.278701], - [0.961336, 0.548636, 0.275305], - [0.963203, 0.553865, 0.271909], - [0.965024, 0.559118, 0.268513], - [0.966798, 0.564396, 0.265118], - [0.968526, 0.569700, 0.261721], - [0.970205, 0.575028, 0.258325], - [0.971835, 0.580382, 0.254931], - [0.973416, 0.585761, 0.251540], - [0.974947, 0.591165, 0.248151], - [0.976428, 0.596595, 0.244767], - [0.977856, 0.602051, 0.241387], - [0.979233, 0.607532, 0.238013], - [0.980556, 0.613039, 0.234646], - [0.981826, 0.618572, 0.231287], - [0.983041, 0.624131, 0.227937], - [0.984199, 0.629718, 0.224595], - [0.985301, 0.635330, 0.221265], - [0.986345, 0.640969, 0.217948], - [0.987332, 0.646633, 0.214648], - [0.988260, 0.652325, 0.211364], - [0.989128, 0.658043, 0.208100], - [0.989935, 0.663787, 0.204859], - [0.990681, 0.669558, 0.201642], - [0.991365, 0.675355, 0.198453], - [0.991985, 0.681179, 0.195295], - [0.992541, 0.687030, 0.192170], - [0.993032, 0.692907, 0.189084], - [0.993456, 0.698810, 0.186041], - [0.993814, 0.704741, 0.183043], - [0.994103, 0.710698, 0.180097], - [0.994324, 0.716681, 0.177208], - [0.994474, 0.722691, 0.174381], - [0.994553, 0.728728, 0.171622], - [0.994561, 0.734791, 0.168938], - [0.994495, 0.740880, 0.166335], - [0.994355, 0.746995, 0.163821], - [0.994141, 0.753137, 0.161404], - [0.993851, 0.759304, 0.159092], - [0.993482, 0.765499, 0.156891], - [0.993033, 0.771720, 0.154808], - [0.992505, 0.777967, 0.152855], - [0.991897, 0.784239, 0.151042], - [0.991209, 0.790537, 0.149377], - [0.990439, 0.796859, 0.147870], - [0.989587, 0.803205, 0.146529], - [0.988648, 0.809579, 0.145357], - [0.987621, 0.815978, 0.144363], - [0.986509, 0.822401, 0.143557], - [0.985314, 0.828846, 0.142945], - [0.984031, 0.835315, 0.142528], - [0.982653, 0.841812, 0.142303], - [0.981190, 0.848329, 0.142279], - [0.979644, 0.854866, 0.142453], - [0.977995, 0.861432, 0.142808], - [0.976265, 0.868016, 0.143351], - [0.974443, 0.874622, 0.144061], - [0.972530, 0.881250, 0.144923], - [0.970533, 0.887896, 0.145919], - [0.968443, 0.894564, 0.147014], - [0.966271, 0.901249, 0.148180], - [0.964021, 0.907950, 0.149370], - [0.961681, 0.914672, 0.150520], - [0.959276, 0.921407, 0.151566], - [0.956808, 0.928152, 0.152409], - [0.954287, 0.934908, 0.152921], - [0.951726, 0.941671, 0.152925], - [0.949151, 0.948435, 0.152178], - [0.946602, 0.955190, 0.150328], - [0.944152, 0.961916, 0.146861], - [0.941896, 0.968590, 0.140956], - [0.940015, 0.975158, 0.131326]] +plasma = [ + [0.050383, 0.029803, 0.527975], + [0.063536, 0.028426, 0.533124], + [0.075353, 0.027206, 0.538007], + [0.086222, 0.026125, 0.542658], + [0.096379, 0.025165, 0.547103], + [0.105980, 0.024309, 0.551368], + [0.115124, 0.023556, 0.555468], + [0.123903, 0.022878, 0.559423], + [0.132381, 0.022258, 0.563250], + [0.140603, 0.021687, 0.566959], + [0.148607, 0.021154, 0.570562], + [0.156421, 0.020651, 0.574065], + [0.164070, 0.020171, 0.577478], + [0.171574, 0.019706, 0.580806], + [0.178950, 0.019252, 0.584054], + [0.186213, 0.018803, 0.587228], + [0.193374, 0.018354, 0.590330], + [0.200445, 0.017902, 0.593364], + [0.207435, 0.017442, 0.596333], + [0.214350, 0.016973, 0.599239], + [0.221197, 0.016497, 0.602083], + [0.227983, 0.016007, 0.604867], + [0.234715, 0.015502, 0.607592], + [0.241396, 0.014979, 0.610259], + [0.248032, 0.014439, 0.612868], + [0.254627, 0.013882, 0.615419], + [0.261183, 0.013308, 0.617911], + [0.267703, 0.012716, 0.620346], + [0.274191, 0.012109, 0.622722], + [0.280648, 0.011488, 0.625038], + [0.287076, 0.010855, 0.627295], + [0.293478, 0.010213, 0.629490], + [0.299855, 0.009561, 0.631624], + [0.306210, 0.008902, 0.633694], + [0.312543, 0.008239, 0.635700], + [0.318856, 0.007576, 0.637640], + [0.325150, 0.006915, 0.639512], + [0.331426, 0.006261, 0.641316], + [0.337683, 0.005618, 0.643049], + [0.343925, 0.004991, 0.644710], + [0.350150, 0.004382, 0.646298], + [0.356359, 0.003798, 0.647810], + [0.362553, 0.003243, 0.649245], + [0.368733, 0.002724, 0.650601], + [0.374897, 0.002245, 0.651876], + [0.381047, 0.001814, 0.653068], + [0.387183, 0.001434, 0.654177], + [0.393304, 0.001114, 0.655199], + [0.399411, 0.000859, 0.656133], + [0.405503, 0.000678, 0.656977], + [0.411580, 0.000577, 0.657730], + [0.417642, 0.000564, 0.658390], + [0.423689, 0.000646, 0.658956], + [0.429719, 0.000831, 0.659425], + [0.435734, 0.001127, 0.659797], + [0.441732, 0.001540, 0.660069], + [0.447714, 0.002080, 0.660240], + [0.453677, 0.002755, 0.660310], + [0.459623, 0.003574, 0.660277], + [0.465550, 0.004545, 0.660139], + [0.471457, 0.005678, 0.659897], + [0.477344, 0.006980, 0.659549], + [0.483210, 0.008460, 0.659095], + [0.489055, 0.010127, 0.658534], + [0.494877, 0.011990, 0.657865], + [0.500678, 0.014055, 0.657088], + [0.506454, 0.016333, 0.656202], + [0.512206, 0.018833, 0.655209], + [0.517933, 0.021563, 0.654109], + [0.523633, 0.024532, 0.652901], + [0.529306, 0.027747, 0.651586], + [0.534952, 0.031217, 0.650165], + [0.540570, 0.034950, 0.648640], + [0.546157, 0.038954, 0.647010], + [0.551715, 0.043136, 0.645277], + [0.557243, 0.047331, 0.643443], + [0.562738, 0.051545, 0.641509], + [0.568201, 0.055778, 0.639477], + [0.573632, 0.060028, 0.637349], + [0.579029, 0.064296, 0.635126], + [0.584391, 0.068579, 0.632812], + [0.589719, 0.072878, 0.630408], + [0.595011, 0.077190, 0.627917], + [0.600266, 0.081516, 0.625342], + [0.605485, 0.085854, 0.622686], + [0.610667, 0.090204, 0.619951], + [0.615812, 0.094564, 0.617140], + [0.620919, 0.098934, 0.614257], + [0.625987, 0.103312, 0.611305], + [0.631017, 0.107699, 0.608287], + [0.636008, 0.112092, 0.605205], + [0.640959, 0.116492, 0.602065], + [0.645872, 0.120898, 0.598867], + [0.650746, 0.125309, 0.595617], + [0.655580, 0.129725, 0.592317], + [0.660374, 0.134144, 0.588971], + [0.665129, 0.138566, 0.585582], + [0.669845, 0.142992, 0.582154], + [0.674522, 0.147419, 0.578688], + [0.679160, 0.151848, 0.575189], + [0.683758, 0.156278, 0.571660], + [0.688318, 0.160709, 0.568103], + [0.692840, 0.165141, 0.564522], + [0.697324, 0.169573, 0.560919], + [0.701769, 0.174005, 0.557296], + [0.706178, 0.178437, 0.553657], + [0.710549, 0.182868, 0.550004], + [0.714883, 0.187299, 0.546338], + [0.719181, 0.191729, 0.542663], + [0.723444, 0.196158, 0.538981], + [0.727670, 0.200586, 0.535293], + [0.731862, 0.205013, 0.531601], + [0.736019, 0.209439, 0.527908], + [0.740143, 0.213864, 0.524216], + [0.744232, 0.218288, 0.520524], + [0.748289, 0.222711, 0.516834], + [0.752312, 0.227133, 0.513149], + [0.756304, 0.231555, 0.509468], + [0.760264, 0.235976, 0.505794], + [0.764193, 0.240396, 0.502126], + [0.768090, 0.244817, 0.498465], + [0.771958, 0.249237, 0.494813], + [0.775796, 0.253658, 0.491171], + [0.779604, 0.258078, 0.487539], + [0.783383, 0.262500, 0.483918], + [0.787133, 0.266922, 0.480307], + [0.790855, 0.271345, 0.476706], + [0.794549, 0.275770, 0.473117], + [0.798216, 0.280197, 0.469538], + [0.801855, 0.284626, 0.465971], + [0.805467, 0.289057, 0.462415], + [0.809052, 0.293491, 0.458870], + [0.812612, 0.297928, 0.455338], + [0.816144, 0.302368, 0.451816], + [0.819651, 0.306812, 0.448306], + [0.823132, 0.311261, 0.444806], + [0.826588, 0.315714, 0.441316], + [0.830018, 0.320172, 0.437836], + [0.833422, 0.324635, 0.434366], + [0.836801, 0.329105, 0.430905], + [0.840155, 0.333580, 0.427455], + [0.843484, 0.338062, 0.424013], + [0.846788, 0.342551, 0.420579], + [0.850066, 0.347048, 0.417153], + [0.853319, 0.351553, 0.413734], + [0.856547, 0.356066, 0.410322], + [0.859750, 0.360588, 0.406917], + [0.862927, 0.365119, 0.403519], + [0.866078, 0.369660, 0.400126], + [0.869203, 0.374212, 0.396738], + [0.872303, 0.378774, 0.393355], + [0.875376, 0.383347, 0.389976], + [0.878423, 0.387932, 0.386600], + [0.881443, 0.392529, 0.383229], + [0.884436, 0.397139, 0.379860], + [0.887402, 0.401762, 0.376494], + [0.890340, 0.406398, 0.373130], + [0.893250, 0.411048, 0.369768], + [0.896131, 0.415712, 0.366407], + [0.898984, 0.420392, 0.363047], + [0.901807, 0.425087, 0.359688], + [0.904601, 0.429797, 0.356329], + [0.907365, 0.434524, 0.352970], + [0.910098, 0.439268, 0.349610], + [0.912800, 0.444029, 0.346251], + [0.915471, 0.448807, 0.342890], + [0.918109, 0.453603, 0.339529], + [0.920714, 0.458417, 0.336166], + [0.923287, 0.463251, 0.332801], + [0.925825, 0.468103, 0.329435], + [0.928329, 0.472975, 0.326067], + [0.930798, 0.477867, 0.322697], + [0.933232, 0.482780, 0.319325], + [0.935630, 0.487712, 0.315952], + [0.937990, 0.492667, 0.312575], + [0.940313, 0.497642, 0.309197], + [0.942598, 0.502639, 0.305816], + [0.944844, 0.507658, 0.302433], + [0.947051, 0.512699, 0.299049], + [0.949217, 0.517763, 0.295662], + [0.951344, 0.522850, 0.292275], + [0.953428, 0.527960, 0.288883], + [0.955470, 0.533093, 0.285490], + [0.957469, 0.538250, 0.282096], + [0.959424, 0.543431, 0.278701], + [0.961336, 0.548636, 0.275305], + [0.963203, 0.553865, 0.271909], + [0.965024, 0.559118, 0.268513], + [0.966798, 0.564396, 0.265118], + [0.968526, 0.569700, 0.261721], + [0.970205, 0.575028, 0.258325], + [0.971835, 0.580382, 0.254931], + [0.973416, 0.585761, 0.251540], + [0.974947, 0.591165, 0.248151], + [0.976428, 0.596595, 0.244767], + [0.977856, 0.602051, 0.241387], + [0.979233, 0.607532, 0.238013], + [0.980556, 0.613039, 0.234646], + [0.981826, 0.618572, 0.231287], + [0.983041, 0.624131, 0.227937], + [0.984199, 0.629718, 0.224595], + [0.985301, 0.635330, 0.221265], + [0.986345, 0.640969, 0.217948], + [0.987332, 0.646633, 0.214648], + [0.988260, 0.652325, 0.211364], + [0.989128, 0.658043, 0.208100], + [0.989935, 0.663787, 0.204859], + [0.990681, 0.669558, 0.201642], + [0.991365, 0.675355, 0.198453], + [0.991985, 0.681179, 0.195295], + [0.992541, 0.687030, 0.192170], + [0.993032, 0.692907, 0.189084], + [0.993456, 0.698810, 0.186041], + [0.993814, 0.704741, 0.183043], + [0.994103, 0.710698, 0.180097], + [0.994324, 0.716681, 0.177208], + [0.994474, 0.722691, 0.174381], + [0.994553, 0.728728, 0.171622], + [0.994561, 0.734791, 0.168938], + [0.994495, 0.740880, 0.166335], + [0.994355, 0.746995, 0.163821], + [0.994141, 0.753137, 0.161404], + [0.993851, 0.759304, 0.159092], + [0.993482, 0.765499, 0.156891], + [0.993033, 0.771720, 0.154808], + [0.992505, 0.777967, 0.152855], + [0.991897, 0.784239, 0.151042], + [0.991209, 0.790537, 0.149377], + [0.990439, 0.796859, 0.147870], + [0.989587, 0.803205, 0.146529], + [0.988648, 0.809579, 0.145357], + [0.987621, 0.815978, 0.144363], + [0.986509, 0.822401, 0.143557], + [0.985314, 0.828846, 0.142945], + [0.984031, 0.835315, 0.142528], + [0.982653, 0.841812, 0.142303], + [0.981190, 0.848329, 0.142279], + [0.979644, 0.854866, 0.142453], + [0.977995, 0.861432, 0.142808], + [0.976265, 0.868016, 0.143351], + [0.974443, 0.874622, 0.144061], + [0.972530, 0.881250, 0.144923], + [0.970533, 0.887896, 0.145919], + [0.968443, 0.894564, 0.147014], + [0.966271, 0.901249, 0.148180], + [0.964021, 0.907950, 0.149370], + [0.961681, 0.914672, 0.150520], + [0.959276, 0.921407, 0.151566], + [0.956808, 0.928152, 0.152409], + [0.954287, 0.934908, 0.152921], + [0.951726, 0.941671, 0.152925], + [0.949151, 0.948435, 0.152178], + [0.946602, 0.955190, 0.150328], + [0.944152, 0.961916, 0.146861], + [0.941896, 0.968590, 0.140956], + [0.940015, 0.975158, 0.131326], +] -viridis = [[0.267004, 0.004874, 0.329415], - [0.268510, 0.009605, 0.335427], - [0.269944, 0.014625, 0.341379], - [0.271305, 0.019942, 0.347269], - [0.272594, 0.025563, 0.353093], - [0.273809, 0.031497, 0.358853], - [0.274952, 0.037752, 0.364543], - [0.276022, 0.044167, 0.370164], - [0.277018, 0.050344, 0.375715], - [0.277941, 0.056324, 0.381191], - [0.278791, 0.062145, 0.386592], - [0.279566, 0.067836, 0.391917], - [0.280267, 0.073417, 0.397163], - [0.280894, 0.078907, 0.402329], - [0.281446, 0.084320, 0.407414], - [0.281924, 0.089666, 0.412415], - [0.282327, 0.094955, 0.417331], - [0.282656, 0.100196, 0.422160], - [0.282910, 0.105393, 0.426902], - [0.283091, 0.110553, 0.431554], - [0.283197, 0.115680, 0.436115], - [0.283229, 0.120777, 0.440584], - [0.283187, 0.125848, 0.444960], - [0.283072, 0.130895, 0.449241], - [0.282884, 0.135920, 0.453427], - [0.282623, 0.140926, 0.457517], - [0.282290, 0.145912, 0.461510], - [0.281887, 0.150881, 0.465405], - [0.281412, 0.155834, 0.469201], - [0.280868, 0.160771, 0.472899], - [0.280255, 0.165693, 0.476498], - [0.279574, 0.170599, 0.479997], - [0.278826, 0.175490, 0.483397], - [0.278012, 0.180367, 0.486697], - [0.277134, 0.185228, 0.489898], - [0.276194, 0.190074, 0.493001], - [0.275191, 0.194905, 0.496005], - [0.274128, 0.199721, 0.498911], - [0.273006, 0.204520, 0.501721], - [0.271828, 0.209303, 0.504434], - [0.270595, 0.214069, 0.507052], - [0.269308, 0.218818, 0.509577], - [0.267968, 0.223549, 0.512008], - [0.266580, 0.228262, 0.514349], - [0.265145, 0.232956, 0.516599], - [0.263663, 0.237631, 0.518762], - [0.262138, 0.242286, 0.520837], - [0.260571, 0.246922, 0.522828], - [0.258965, 0.251537, 0.524736], - [0.257322, 0.256130, 0.526563], - [0.255645, 0.260703, 0.528312], - [0.253935, 0.265254, 0.529983], - [0.252194, 0.269783, 0.531579], - [0.250425, 0.274290, 0.533103], - [0.248629, 0.278775, 0.534556], - [0.246811, 0.283237, 0.535941], - [0.244972, 0.287675, 0.537260], - [0.243113, 0.292092, 0.538516], - [0.241237, 0.296485, 0.539709], - [0.239346, 0.300855, 0.540844], - [0.237441, 0.305202, 0.541921], - [0.235526, 0.309527, 0.542944], - [0.233603, 0.313828, 0.543914], - [0.231674, 0.318106, 0.544834], - [0.229739, 0.322361, 0.545706], - [0.227802, 0.326594, 0.546532], - [0.225863, 0.330805, 0.547314], - [0.223925, 0.334994, 0.548053], - [0.221989, 0.339161, 0.548752], - [0.220057, 0.343307, 0.549413], - [0.218130, 0.347432, 0.550038], - [0.216210, 0.351535, 0.550627], - [0.214298, 0.355619, 0.551184], - [0.212395, 0.359683, 0.551710], - [0.210503, 0.363727, 0.552206], - [0.208623, 0.367752, 0.552675], - [0.206756, 0.371758, 0.553117], - [0.204903, 0.375746, 0.553533], - [0.203063, 0.379716, 0.553925], - [0.201239, 0.383670, 0.554294], - [0.199430, 0.387607, 0.554642], - [0.197636, 0.391528, 0.554969], - [0.195860, 0.395433, 0.555276], - [0.194100, 0.399323, 0.555565], - [0.192357, 0.403199, 0.555836], - [0.190631, 0.407061, 0.556089], - [0.188923, 0.410910, 0.556326], - [0.187231, 0.414746, 0.556547], - [0.185556, 0.418570, 0.556753], - [0.183898, 0.422383, 0.556944], - [0.182256, 0.426184, 0.557120], - [0.180629, 0.429975, 0.557282], - [0.179019, 0.433756, 0.557430], - [0.177423, 0.437527, 0.557565], - [0.175841, 0.441290, 0.557685], - [0.174274, 0.445044, 0.557792], - [0.172719, 0.448791, 0.557885], - [0.171176, 0.452530, 0.557965], - [0.169646, 0.456262, 0.558030], - [0.168126, 0.459988, 0.558082], - [0.166617, 0.463708, 0.558119], - [0.165117, 0.467423, 0.558141], - [0.163625, 0.471133, 0.558148], - [0.162142, 0.474838, 0.558140], - [0.160665, 0.478540, 0.558115], - [0.159194, 0.482237, 0.558073], - [0.157729, 0.485932, 0.558013], - [0.156270, 0.489624, 0.557936], - [0.154815, 0.493313, 0.557840], - [0.153364, 0.497000, 0.557724], - [0.151918, 0.500685, 0.557587], - [0.150476, 0.504369, 0.557430], - [0.149039, 0.508051, 0.557250], - [0.147607, 0.511733, 0.557049], - [0.146180, 0.515413, 0.556823], - [0.144759, 0.519093, 0.556572], - [0.143343, 0.522773, 0.556295], - [0.141935, 0.526453, 0.555991], - [0.140536, 0.530132, 0.555659], - [0.139147, 0.533812, 0.555298], - [0.137770, 0.537492, 0.554906], - [0.136408, 0.541173, 0.554483], - [0.135066, 0.544853, 0.554029], - [0.133743, 0.548535, 0.553541], - [0.132444, 0.552216, 0.553018], - [0.131172, 0.555899, 0.552459], - [0.129933, 0.559582, 0.551864], - [0.128729, 0.563265, 0.551229], - [0.127568, 0.566949, 0.550556], - [0.126453, 0.570633, 0.549841], - [0.125394, 0.574318, 0.549086], - [0.124395, 0.578002, 0.548287], - [0.123463, 0.581687, 0.547445], - [0.122606, 0.585371, 0.546557], - [0.121831, 0.589055, 0.545623], - [0.121148, 0.592739, 0.544641], - [0.120565, 0.596422, 0.543611], - [0.120092, 0.600104, 0.542530], - [0.119738, 0.603785, 0.541400], - [0.119512, 0.607464, 0.540218], - [0.119423, 0.611141, 0.538982], - [0.119483, 0.614817, 0.537692], - [0.119699, 0.618490, 0.536347], - [0.120081, 0.622161, 0.534946], - [0.120638, 0.625828, 0.533488], - [0.121380, 0.629492, 0.531973], - [0.122312, 0.633153, 0.530398], - [0.123444, 0.636809, 0.528763], - [0.124780, 0.640461, 0.527068], - [0.126326, 0.644107, 0.525311], - [0.128087, 0.647749, 0.523491], - [0.130067, 0.651384, 0.521608], - [0.132268, 0.655014, 0.519661], - [0.134692, 0.658636, 0.517649], - [0.137339, 0.662252, 0.515571], - [0.140210, 0.665859, 0.513427], - [0.143303, 0.669459, 0.511215], - [0.146616, 0.673050, 0.508936], - [0.150148, 0.676631, 0.506589], - [0.153894, 0.680203, 0.504172], - [0.157851, 0.683765, 0.501686], - [0.162016, 0.687316, 0.499129], - [0.166383, 0.690856, 0.496502], - [0.170948, 0.694384, 0.493803], - [0.175707, 0.697900, 0.491033], - [0.180653, 0.701402, 0.488189], - [0.185783, 0.704891, 0.485273], - [0.191090, 0.708366, 0.482284], - [0.196571, 0.711827, 0.479221], - [0.202219, 0.715272, 0.476084], - [0.208030, 0.718701, 0.472873], - [0.214000, 0.722114, 0.469588], - [0.220124, 0.725509, 0.466226], - [0.226397, 0.728888, 0.462789], - [0.232815, 0.732247, 0.459277], - [0.239374, 0.735588, 0.455688], - [0.246070, 0.738910, 0.452024], - [0.252899, 0.742211, 0.448284], - [0.259857, 0.745492, 0.444467], - [0.266941, 0.748751, 0.440573], - [0.274149, 0.751988, 0.436601], - [0.281477, 0.755203, 0.432552], - [0.288921, 0.758394, 0.428426], - [0.296479, 0.761561, 0.424223], - [0.304148, 0.764704, 0.419943], - [0.311925, 0.767822, 0.415586], - [0.319809, 0.770914, 0.411152], - [0.327796, 0.773980, 0.406640], - [0.335885, 0.777018, 0.402049], - [0.344074, 0.780029, 0.397381], - [0.352360, 0.783011, 0.392636], - [0.360741, 0.785964, 0.387814], - [0.369214, 0.788888, 0.382914], - [0.377779, 0.791781, 0.377939], - [0.386433, 0.794644, 0.372886], - [0.395174, 0.797475, 0.367757], - [0.404001, 0.800275, 0.362552], - [0.412913, 0.803041, 0.357269], - [0.421908, 0.805774, 0.351910], - [0.430983, 0.808473, 0.346476], - [0.440137, 0.811138, 0.340967], - [0.449368, 0.813768, 0.335384], - [0.458674, 0.816363, 0.329727], - [0.468053, 0.818921, 0.323998], - [0.477504, 0.821444, 0.318195], - [0.487026, 0.823929, 0.312321], - [0.496615, 0.826376, 0.306377], - [0.506271, 0.828786, 0.300362], - [0.515992, 0.831158, 0.294279], - [0.525776, 0.833491, 0.288127], - [0.535621, 0.835785, 0.281908], - [0.545524, 0.838039, 0.275626], - [0.555484, 0.840254, 0.269281], - [0.565498, 0.842430, 0.262877], - [0.575563, 0.844566, 0.256415], - [0.585678, 0.846661, 0.249897], - [0.595839, 0.848717, 0.243329], - [0.606045, 0.850733, 0.236712], - [0.616293, 0.852709, 0.230052], - [0.626579, 0.854645, 0.223353], - [0.636902, 0.856542, 0.216620], - [0.647257, 0.858400, 0.209861], - [0.657642, 0.860219, 0.203082], - [0.668054, 0.861999, 0.196293], - [0.678489, 0.863742, 0.189503], - [0.688944, 0.865448, 0.182725], - [0.699415, 0.867117, 0.175971], - [0.709898, 0.868751, 0.169257], - [0.720391, 0.870350, 0.162603], - [0.730889, 0.871916, 0.156029], - [0.741388, 0.873449, 0.149561], - [0.751884, 0.874951, 0.143228], - [0.762373, 0.876424, 0.137064], - [0.772852, 0.877868, 0.131109], - [0.783315, 0.879285, 0.125405], - [0.793760, 0.880678, 0.120005], - [0.804182, 0.882046, 0.114965], - [0.814576, 0.883393, 0.110347], - [0.824940, 0.884720, 0.106217], - [0.835270, 0.886029, 0.102646], - [0.845561, 0.887322, 0.099702], - [0.855810, 0.888601, 0.097452], - [0.866013, 0.889868, 0.095953], - [0.876168, 0.891125, 0.095250], - [0.886271, 0.892374, 0.095374], - [0.896320, 0.893616, 0.096335], - [0.906311, 0.894855, 0.098125], - [0.916242, 0.896091, 0.100717], - [0.926106, 0.897330, 0.104071], - [0.935904, 0.898570, 0.108131], - [0.945636, 0.899815, 0.112838], - [0.955300, 0.901065, 0.118128], - [0.964894, 0.902323, 0.123941], - [0.974417, 0.903590, 0.130215], - [0.983868, 0.904867, 0.136897], - [0.993248, 0.906157, 0.143936]] +viridis = [ + [0.267004, 0.004874, 0.329415], + [0.268510, 0.009605, 0.335427], + [0.269944, 0.014625, 0.341379], + [0.271305, 0.019942, 0.347269], + [0.272594, 0.025563, 0.353093], + [0.273809, 0.031497, 0.358853], + [0.274952, 0.037752, 0.364543], + [0.276022, 0.044167, 0.370164], + [0.277018, 0.050344, 0.375715], + [0.277941, 0.056324, 0.381191], + [0.278791, 0.062145, 0.386592], + [0.279566, 0.067836, 0.391917], + [0.280267, 0.073417, 0.397163], + [0.280894, 0.078907, 0.402329], + [0.281446, 0.084320, 0.407414], + [0.281924, 0.089666, 0.412415], + [0.282327, 0.094955, 0.417331], + [0.282656, 0.100196, 0.422160], + [0.282910, 0.105393, 0.426902], + [0.283091, 0.110553, 0.431554], + [0.283197, 0.115680, 0.436115], + [0.283229, 0.120777, 0.440584], + [0.283187, 0.125848, 0.444960], + [0.283072, 0.130895, 0.449241], + [0.282884, 0.135920, 0.453427], + [0.282623, 0.140926, 0.457517], + [0.282290, 0.145912, 0.461510], + [0.281887, 0.150881, 0.465405], + [0.281412, 0.155834, 0.469201], + [0.280868, 0.160771, 0.472899], + [0.280255, 0.165693, 0.476498], + [0.279574, 0.170599, 0.479997], + [0.278826, 0.175490, 0.483397], + [0.278012, 0.180367, 0.486697], + [0.277134, 0.185228, 0.489898], + [0.276194, 0.190074, 0.493001], + [0.275191, 0.194905, 0.496005], + [0.274128, 0.199721, 0.498911], + [0.273006, 0.204520, 0.501721], + [0.271828, 0.209303, 0.504434], + [0.270595, 0.214069, 0.507052], + [0.269308, 0.218818, 0.509577], + [0.267968, 0.223549, 0.512008], + [0.266580, 0.228262, 0.514349], + [0.265145, 0.232956, 0.516599], + [0.263663, 0.237631, 0.518762], + [0.262138, 0.242286, 0.520837], + [0.260571, 0.246922, 0.522828], + [0.258965, 0.251537, 0.524736], + [0.257322, 0.256130, 0.526563], + [0.255645, 0.260703, 0.528312], + [0.253935, 0.265254, 0.529983], + [0.252194, 0.269783, 0.531579], + [0.250425, 0.274290, 0.533103], + [0.248629, 0.278775, 0.534556], + [0.246811, 0.283237, 0.535941], + [0.244972, 0.287675, 0.537260], + [0.243113, 0.292092, 0.538516], + [0.241237, 0.296485, 0.539709], + [0.239346, 0.300855, 0.540844], + [0.237441, 0.305202, 0.541921], + [0.235526, 0.309527, 0.542944], + [0.233603, 0.313828, 0.543914], + [0.231674, 0.318106, 0.544834], + [0.229739, 0.322361, 0.545706], + [0.227802, 0.326594, 0.546532], + [0.225863, 0.330805, 0.547314], + [0.223925, 0.334994, 0.548053], + [0.221989, 0.339161, 0.548752], + [0.220057, 0.343307, 0.549413], + [0.218130, 0.347432, 0.550038], + [0.216210, 0.351535, 0.550627], + [0.214298, 0.355619, 0.551184], + [0.212395, 0.359683, 0.551710], + [0.210503, 0.363727, 0.552206], + [0.208623, 0.367752, 0.552675], + [0.206756, 0.371758, 0.553117], + [0.204903, 0.375746, 0.553533], + [0.203063, 0.379716, 0.553925], + [0.201239, 0.383670, 0.554294], + [0.199430, 0.387607, 0.554642], + [0.197636, 0.391528, 0.554969], + [0.195860, 0.395433, 0.555276], + [0.194100, 0.399323, 0.555565], + [0.192357, 0.403199, 0.555836], + [0.190631, 0.407061, 0.556089], + [0.188923, 0.410910, 0.556326], + [0.187231, 0.414746, 0.556547], + [0.185556, 0.418570, 0.556753], + [0.183898, 0.422383, 0.556944], + [0.182256, 0.426184, 0.557120], + [0.180629, 0.429975, 0.557282], + [0.179019, 0.433756, 0.557430], + [0.177423, 0.437527, 0.557565], + [0.175841, 0.441290, 0.557685], + [0.174274, 0.445044, 0.557792], + [0.172719, 0.448791, 0.557885], + [0.171176, 0.452530, 0.557965], + [0.169646, 0.456262, 0.558030], + [0.168126, 0.459988, 0.558082], + [0.166617, 0.463708, 0.558119], + [0.165117, 0.467423, 0.558141], + [0.163625, 0.471133, 0.558148], + [0.162142, 0.474838, 0.558140], + [0.160665, 0.478540, 0.558115], + [0.159194, 0.482237, 0.558073], + [0.157729, 0.485932, 0.558013], + [0.156270, 0.489624, 0.557936], + [0.154815, 0.493313, 0.557840], + [0.153364, 0.497000, 0.557724], + [0.151918, 0.500685, 0.557587], + [0.150476, 0.504369, 0.557430], + [0.149039, 0.508051, 0.557250], + [0.147607, 0.511733, 0.557049], + [0.146180, 0.515413, 0.556823], + [0.144759, 0.519093, 0.556572], + [0.143343, 0.522773, 0.556295], + [0.141935, 0.526453, 0.555991], + [0.140536, 0.530132, 0.555659], + [0.139147, 0.533812, 0.555298], + [0.137770, 0.537492, 0.554906], + [0.136408, 0.541173, 0.554483], + [0.135066, 0.544853, 0.554029], + [0.133743, 0.548535, 0.553541], + [0.132444, 0.552216, 0.553018], + [0.131172, 0.555899, 0.552459], + [0.129933, 0.559582, 0.551864], + [0.128729, 0.563265, 0.551229], + [0.127568, 0.566949, 0.550556], + [0.126453, 0.570633, 0.549841], + [0.125394, 0.574318, 0.549086], + [0.124395, 0.578002, 0.548287], + [0.123463, 0.581687, 0.547445], + [0.122606, 0.585371, 0.546557], + [0.121831, 0.589055, 0.545623], + [0.121148, 0.592739, 0.544641], + [0.120565, 0.596422, 0.543611], + [0.120092, 0.600104, 0.542530], + [0.119738, 0.603785, 0.541400], + [0.119512, 0.607464, 0.540218], + [0.119423, 0.611141, 0.538982], + [0.119483, 0.614817, 0.537692], + [0.119699, 0.618490, 0.536347], + [0.120081, 0.622161, 0.534946], + [0.120638, 0.625828, 0.533488], + [0.121380, 0.629492, 0.531973], + [0.122312, 0.633153, 0.530398], + [0.123444, 0.636809, 0.528763], + [0.124780, 0.640461, 0.527068], + [0.126326, 0.644107, 0.525311], + [0.128087, 0.647749, 0.523491], + [0.130067, 0.651384, 0.521608], + [0.132268, 0.655014, 0.519661], + [0.134692, 0.658636, 0.517649], + [0.137339, 0.662252, 0.515571], + [0.140210, 0.665859, 0.513427], + [0.143303, 0.669459, 0.511215], + [0.146616, 0.673050, 0.508936], + [0.150148, 0.676631, 0.506589], + [0.153894, 0.680203, 0.504172], + [0.157851, 0.683765, 0.501686], + [0.162016, 0.687316, 0.499129], + [0.166383, 0.690856, 0.496502], + [0.170948, 0.694384, 0.493803], + [0.175707, 0.697900, 0.491033], + [0.180653, 0.701402, 0.488189], + [0.185783, 0.704891, 0.485273], + [0.191090, 0.708366, 0.482284], + [0.196571, 0.711827, 0.479221], + [0.202219, 0.715272, 0.476084], + [0.208030, 0.718701, 0.472873], + [0.214000, 0.722114, 0.469588], + [0.220124, 0.725509, 0.466226], + [0.226397, 0.728888, 0.462789], + [0.232815, 0.732247, 0.459277], + [0.239374, 0.735588, 0.455688], + [0.246070, 0.738910, 0.452024], + [0.252899, 0.742211, 0.448284], + [0.259857, 0.745492, 0.444467], + [0.266941, 0.748751, 0.440573], + [0.274149, 0.751988, 0.436601], + [0.281477, 0.755203, 0.432552], + [0.288921, 0.758394, 0.428426], + [0.296479, 0.761561, 0.424223], + [0.304148, 0.764704, 0.419943], + [0.311925, 0.767822, 0.415586], + [0.319809, 0.770914, 0.411152], + [0.327796, 0.773980, 0.406640], + [0.335885, 0.777018, 0.402049], + [0.344074, 0.780029, 0.397381], + [0.352360, 0.783011, 0.392636], + [0.360741, 0.785964, 0.387814], + [0.369214, 0.788888, 0.382914], + [0.377779, 0.791781, 0.377939], + [0.386433, 0.794644, 0.372886], + [0.395174, 0.797475, 0.367757], + [0.404001, 0.800275, 0.362552], + [0.412913, 0.803041, 0.357269], + [0.421908, 0.805774, 0.351910], + [0.430983, 0.808473, 0.346476], + [0.440137, 0.811138, 0.340967], + [0.449368, 0.813768, 0.335384], + [0.458674, 0.816363, 0.329727], + [0.468053, 0.818921, 0.323998], + [0.477504, 0.821444, 0.318195], + [0.487026, 0.823929, 0.312321], + [0.496615, 0.826376, 0.306377], + [0.506271, 0.828786, 0.300362], + [0.515992, 0.831158, 0.294279], + [0.525776, 0.833491, 0.288127], + [0.535621, 0.835785, 0.281908], + [0.545524, 0.838039, 0.275626], + [0.555484, 0.840254, 0.269281], + [0.565498, 0.842430, 0.262877], + [0.575563, 0.844566, 0.256415], + [0.585678, 0.846661, 0.249897], + [0.595839, 0.848717, 0.243329], + [0.606045, 0.850733, 0.236712], + [0.616293, 0.852709, 0.230052], + [0.626579, 0.854645, 0.223353], + [0.636902, 0.856542, 0.216620], + [0.647257, 0.858400, 0.209861], + [0.657642, 0.860219, 0.203082], + [0.668054, 0.861999, 0.196293], + [0.678489, 0.863742, 0.189503], + [0.688944, 0.865448, 0.182725], + [0.699415, 0.867117, 0.175971], + [0.709898, 0.868751, 0.169257], + [0.720391, 0.870350, 0.162603], + [0.730889, 0.871916, 0.156029], + [0.741388, 0.873449, 0.149561], + [0.751884, 0.874951, 0.143228], + [0.762373, 0.876424, 0.137064], + [0.772852, 0.877868, 0.131109], + [0.783315, 0.879285, 0.125405], + [0.793760, 0.880678, 0.120005], + [0.804182, 0.882046, 0.114965], + [0.814576, 0.883393, 0.110347], + [0.824940, 0.884720, 0.106217], + [0.835270, 0.886029, 0.102646], + [0.845561, 0.887322, 0.099702], + [0.855810, 0.888601, 0.097452], + [0.866013, 0.889868, 0.095953], + [0.876168, 0.891125, 0.095250], + [0.886271, 0.892374, 0.095374], + [0.896320, 0.893616, 0.096335], + [0.906311, 0.894855, 0.098125], + [0.916242, 0.896091, 0.100717], + [0.926106, 0.897330, 0.104071], + [0.935904, 0.898570, 0.108131], + [0.945636, 0.899815, 0.112838], + [0.955300, 0.901065, 0.118128], + [0.964894, 0.902323, 0.123941], + [0.974417, 0.903590, 0.130215], + [0.983868, 0.904867, 0.136897], + [0.993248, 0.906157, 0.143936], +] default_colormap = "plasma" @@ -1039,7 +1047,9 @@ def read_selected_colormap_name_from_settings() -> str: - selected = settings.read("spectrogram_colormap", default_value=default_colormap, type=str) + selected = settings.read( + "spectrogram_colormap", default_value=default_colormap, type=str + ) if selected not in maps.keys(): selected = default_colormap return selected diff --git a/src/urh/controller/CompareFrameController.py b/src/urh/controller/CompareFrameController.py index 54c85acb5c..a5f4563749 100644 --- a/src/urh/controller/CompareFrameController.py +++ b/src/urh/controller/CompareFrameController.py @@ -5,10 +5,26 @@ from datetime import datetime import numpy -from PyQt5.QtCore import pyqtSlot, QTimer, Qt, pyqtSignal, QItemSelection, QItemSelectionModel, QLocale, \ - QModelIndex +from PyQt5.QtCore import ( + pyqtSlot, + QTimer, + Qt, + pyqtSignal, + QItemSelection, + QItemSelectionModel, + QLocale, + QModelIndex, +) from PyQt5.QtGui import QContextMenuEvent, QIcon -from PyQt5.QtWidgets import QMessageBox, QAbstractItemView, QUndoStack, QMenu, QWidget, QHeaderView, QInputDialog +from PyQt5.QtWidgets import ( + QMessageBox, + QAbstractItemView, + QUndoStack, + QMenu, + QWidget, + QHeaderView, + QInputDialog, +) from urh import settings from urh.awre import AutoAssigner @@ -44,8 +60,9 @@ class CompareFrameController(QWidget): show_config_field_types_triggered = pyqtSignal() load_protocol_clicked = pyqtSignal() - def __init__(self, plugin_manager: PluginManager, project_manager: ProjectManager, parent): - + def __init__( + self, plugin_manager: PluginManager, project_manager: ProjectManager, parent + ): super().__init__(parent) self.proto_analyzer = ProtocolAnalyzer(None) @@ -71,23 +88,39 @@ def __init__(self, plugin_manager: PluginManager, project_manager: ProjectManage self.selected_protocols = set() self.search_select_filter_align_menu = QMenu() - self.search_action = self.search_select_filter_align_menu.addAction(self.tr("Search")) - self.select_action = self.search_select_filter_align_menu.addAction(self.tr("Select all")) - self.filter_action = self.search_select_filter_align_menu.addAction(self.tr("Filter")) - self.align_action = self.search_select_filter_align_menu.addAction(self.tr("Align")) + self.search_action = self.search_select_filter_align_menu.addAction( + self.tr("Search") + ) + self.select_action = self.search_select_filter_align_menu.addAction( + self.tr("Select all") + ) + self.filter_action = self.search_select_filter_align_menu.addAction( + self.tr("Filter") + ) + self.align_action = self.search_select_filter_align_menu.addAction( + self.tr("Align") + ) self.ui.btnSearchSelectFilter.setMenu(self.search_select_filter_align_menu) self.analyze_menu = QMenu() - self.assign_participants_action = self.analyze_menu.addAction(self.tr("Assign participants")) + self.assign_participants_action = self.analyze_menu.addAction( + self.tr("Assign participants") + ) self.assign_participants_action.setCheckable(True) self.assign_participants_action.setChecked(True) - self.assign_message_type_action = self.analyze_menu.addAction(self.tr("Assign message type")) + self.assign_message_type_action = self.analyze_menu.addAction( + self.tr("Assign message type") + ) self.assign_message_type_action.setCheckable(True) self.assign_message_type_action.setChecked(True) - self.assign_labels_action = self.analyze_menu.addAction(self.tr("Assign labels")) + self.assign_labels_action = self.analyze_menu.addAction( + self.tr("Assign labels") + ) self.assign_labels_action.setCheckable(True) self.assign_labels_action.setChecked(True) - self.assign_participant_address_action = self.analyze_menu.addAction(self.tr("Assign participant addresses")) + self.assign_participant_address_action = self.analyze_menu.addAction( + self.tr("Assign participant addresses") + ) self.assign_participant_address_action.setCheckable(True) self.assign_participant_address_action.setChecked(True) self.ui.btnAnalyze.setMenu(self.analyze_menu) @@ -95,32 +128,49 @@ def __init__(self, plugin_manager: PluginManager, project_manager: ProjectManage self.ui.lblShownRows.hide() self.ui.lblClearAlignment.hide() - self.protocol_model = ProtocolTableModel(self.proto_analyzer, project_manager.participants, - self) # type: ProtocolTableModel - self.message_type_table_model = MessageTypeTableModel(self.proto_analyzer.message_types) + self.protocol_model = ProtocolTableModel( + self.proto_analyzer, project_manager.participants, self + ) # type: ProtocolTableModel + self.message_type_table_model = MessageTypeTableModel( + self.proto_analyzer.message_types + ) - self.label_value_model = LabelValueTableModel(self.proto_analyzer, - controller=self) # type: LabelValueTableModel + self.label_value_model = LabelValueTableModel( + self.proto_analyzer, controller=self + ) # type: LabelValueTableModel self.ui.tblViewProtocol.setModel(self.protocol_model) self.ui.tblViewProtocol.controller = self self.ui.tblLabelValues.setModel(self.label_value_model) self.ui.tblViewMessageTypes.setModel(self.message_type_table_model) - self.ui.tblViewMessageTypes.setItemDelegateForColumn(1, MessageTypeButtonDelegate( - parent=self.ui.tblViewMessageTypes)) - self.ui.tblViewMessageTypes.horizontalHeader().setSectionResizeMode(0, QHeaderView.Stretch) - self.ui.tblViewMessageTypes.horizontalHeader().setSectionResizeMode(1, QHeaderView.ResizeToContents) - - self.ui.tblLabelValues.horizontalHeader().setSectionResizeMode(1, QHeaderView.ResizeToContents) - self.ui.tblLabelValues.horizontalHeader().setSectionResizeMode(2, QHeaderView.ResizeToContents) - self.ui.tblLabelValues.horizontalHeader().setSectionResizeMode(3, QHeaderView.ResizeToContents) + self.ui.tblViewMessageTypes.setItemDelegateForColumn( + 1, MessageTypeButtonDelegate(parent=self.ui.tblViewMessageTypes) + ) + self.ui.tblViewMessageTypes.horizontalHeader().setSectionResizeMode( + 0, QHeaderView.Stretch + ) + self.ui.tblViewMessageTypes.horizontalHeader().setSectionResizeMode( + 1, QHeaderView.ResizeToContents + ) + + self.ui.tblLabelValues.horizontalHeader().setSectionResizeMode( + 1, QHeaderView.ResizeToContents + ) + self.ui.tblLabelValues.horizontalHeader().setSectionResizeMode( + 2, QHeaderView.ResizeToContents + ) + self.ui.tblLabelValues.horizontalHeader().setSectionResizeMode( + 3, QHeaderView.ResizeToContents + ) self.selection_timer = QTimer(self) self.selection_timer.setSingleShot(True) self.setAcceptDrops(False) - self.proto_tree_model = ProtocolTreeModel(controller=self) # type: ProtocolTreeModel + self.proto_tree_model = ProtocolTreeModel( + controller=self + ) # type: ProtocolTreeModel self.ui.treeViewProtocols.setModel(self.proto_tree_model) self.create_connects() @@ -238,68 +288,119 @@ def __set_decoding_error_label(self, message: Message): if message: errors = message.decoding_errors percent = 100 * (errors / len(message)) - state = message.decoding_state if message.decoding_state != message.decoder.ErrorState.SUCCESS else "" + state = ( + message.decoding_state + if message.decoding_state != message.decoder.ErrorState.SUCCESS + else "" + ) color = "green" if errors == 0 and state == "" else "red" self.ui.lDecodingErrorsValue.setStyleSheet("color: " + color) - self.ui.lDecodingErrorsValue.setText(locale.format_string("%d (%.02f%%) %s", (errors, percent, state))) + self.ui.lDecodingErrorsValue.setText( + locale.format_string("%d (%.02f%%) %s", (errors, percent, state)) + ) else: self.ui.lDecodingErrorsValue.setText("No message selected") def create_connects(self): self.protocol_undo_stack.indexChanged.connect(self.on_undo_stack_index_changed) self.ui.cbProtoView.currentIndexChanged.connect(self.on_protocol_view_changed) - self.ui.cbDecoding.currentIndexChanged.connect(self.on_combobox_decoding_current_index_changed) + self.ui.cbDecoding.currentIndexChanged.connect( + self.on_combobox_decoding_current_index_changed + ) self.ui.cbShowDiffs.clicked.connect(self.on_chkbox_show_differences_clicked) - self.ui.chkBoxOnlyShowLabelsInProtocol.stateChanged.connect(self.on_check_box_show_only_labels_state_changed) - self.ui.chkBoxShowOnlyDiffs.stateChanged.connect(self.on_check_box_show_only_diffs_state_changed) + self.ui.chkBoxOnlyShowLabelsInProtocol.stateChanged.connect( + self.on_check_box_show_only_labels_state_changed + ) + self.ui.chkBoxShowOnlyDiffs.stateChanged.connect( + self.on_check_box_show_only_diffs_state_changed + ) self.protocol_model.vertical_header_color_status_changed.connect( - self.ui.tblViewProtocol.on_vertical_header_color_status_changed) - - self.ui.tblViewProtocol.show_interpretation_clicked.connect(self.show_interpretation_clicked.emit) - self.ui.tblViewProtocol.protocol_view_change_clicked.connect(self.ui.cbProtoView.setCurrentIndex) - self.ui.tblViewProtocol.selection_changed.connect(self.on_table_selection_changed) + self.ui.tblViewProtocol.on_vertical_header_color_status_changed + ) + + self.ui.tblViewProtocol.show_interpretation_clicked.connect( + self.show_interpretation_clicked.emit + ) + self.ui.tblViewProtocol.protocol_view_change_clicked.connect( + self.ui.cbProtoView.setCurrentIndex + ) + self.ui.tblViewProtocol.selection_changed.connect( + self.on_table_selection_changed + ) self.ui.tblViewProtocol.writeable_changed.connect(self.on_writeable_changed) - self.ui.tblViewProtocol.row_visibility_changed.connect(self.on_tbl_view_protocol_row_visibility_changed) - self.ui.tblViewProtocol.edit_label_triggered.connect(self.on_edit_label_clicked_in_table) - self.ui.tblViewProtocol.create_label_triggered.connect(self.on_create_label_triggered) + self.ui.tblViewProtocol.row_visibility_changed.connect( + self.on_tbl_view_protocol_row_visibility_changed + ) + self.ui.tblViewProtocol.edit_label_triggered.connect( + self.on_edit_label_clicked_in_table + ) + self.ui.tblViewProtocol.create_label_triggered.connect( + self.on_create_label_triggered + ) self.ui.tblViewProtocol.participant_changed.connect(self.on_participant_edited) - self.ui.tblViewProtocol.messagetype_selected.connect(self.on_message_type_selected) - self.ui.tblViewProtocol.new_messagetype_clicked.connect(self.on_table_new_message_type_clicked) + self.ui.tblViewProtocol.messagetype_selected.connect( + self.on_message_type_selected + ) + self.ui.tblViewProtocol.new_messagetype_clicked.connect( + self.on_table_new_message_type_clicked + ) self.ui.tblViewProtocol.files_dropped.connect(self.on_files_dropped) - self.ui.tblLabelValues.edit_label_action_triggered.connect(self.on_edit_label_action_triggered) + self.ui.tblLabelValues.edit_label_action_triggered.connect( + self.on_edit_label_action_triggered + ) self.ui.tblLabelValues.configure_field_types_action_triggered.connect( - self.show_config_field_types_triggered.emit) - - self.label_value_model.protolabel_visibility_changed.connect(self.on_protolabel_visibility_changed) - self.label_value_model.protocol_label_name_edited.connect(self.label_value_model.update) + self.show_config_field_types_triggered.emit + ) + + self.label_value_model.protolabel_visibility_changed.connect( + self.on_protolabel_visibility_changed + ) + self.label_value_model.protocol_label_name_edited.connect( + self.label_value_model.update + ) self.label_value_model.label_removed.connect(self.on_label_removed) self.label_value_model.label_color_changed.connect(self.on_label_color_changed) self.ui.tblViewMessageTypes.selectionModel().currentRowChanged.connect( - self.on_tbl_view_message_current_row_changed) + self.on_tbl_view_message_current_row_changed + ) self.ui.tblViewMessageTypes.configure_message_type_rules_triggered.connect( - self.on_configure_message_type_rules_triggered) + self.on_configure_message_type_rules_triggered + ) self.ui.tblViewMessageTypes.auto_message_type_update_triggered.connect( - self.update_automatic_assigned_message_types) - - self.message_type_table_model.modelReset.connect(self.on_message_type_table_model_updated) - self.message_type_table_model.message_type_removed.connect(self.on_message_type_removed) - self.message_type_table_model.message_type_visibility_changed.connect(self.on_message_type_visibility_changed) - self.message_type_table_model.message_type_name_edited.connect(self.on_message_type_name_edited) + self.update_automatic_assigned_message_types + ) + + self.message_type_table_model.modelReset.connect( + self.on_message_type_table_model_updated + ) + self.message_type_table_model.message_type_removed.connect( + self.on_message_type_removed + ) + self.message_type_table_model.message_type_visibility_changed.connect( + self.on_message_type_visibility_changed + ) + self.message_type_table_model.message_type_name_edited.connect( + self.on_message_type_name_edited + ) self.ui.btnSearchSelectFilter.clicked.connect(self.on_btn_search_clicked) self.ui.btnNextSearch.clicked.connect(self.on_btn_next_search_clicked) self.ui.btnPrevSearch.clicked.connect(self.on_btn_prev_search_clicked) - self.ui.lineEditSearch.returnPressed.connect(self.ui.btnSearchSelectFilter.click) + self.ui.lineEditSearch.returnPressed.connect( + self.ui.btnSearchSelectFilter.click + ) self.search_action.triggered.connect(self.on_search_action_triggered) self.select_action.triggered.connect(self.on_select_action_triggered) self.filter_action.triggered.connect(self.on_filter_action_triggered) self.align_action.triggered.connect(self.on_align_action_triggered) self.ui.lblShownRows.linkActivated.connect(self.on_label_shown_link_activated) - self.ui.lblClearAlignment.linkActivated.connect(self.on_label_clear_alignment_link_activated) + self.ui.lblClearAlignment.linkActivated.connect( + self.on_label_clear_alignment_link_activated + ) self.ui.btnSaveProto.clicked.connect(self.on_btn_save_protocol_clicked) self.ui.btnLoadProto.clicked.connect(self.on_btn_load_proto_clicked) @@ -309,12 +410,16 @@ def create_connects(self): self.protocol_model.ref_index_changed.connect(self.on_ref_index_changed) self.project_manager.project_updated.connect(self.on_project_updated) - self.participant_list_model.show_state_changed.connect(self.on_participant_show_state_changed) + self.participant_list_model.show_state_changed.connect( + self.on_participant_show_state_changed + ) self.ui.btnAddMessagetype.clicked.connect(self.on_btn_new_message_type_clicked) self.selection_timer.timeout.connect(self.on_table_selection_timer_timeout) - self.ui.treeViewProtocols.selection_changed.connect(self.on_tree_view_selection_changed) + self.ui.treeViewProtocols.selection_changed.connect( + self.on_tree_view_selection_changed + ) self.proto_tree_model.item_dropped.connect(self.on_item_in_proto_tree_dropped) self.proto_tree_model.group_deleted.connect(self.on_group_deleted) @@ -323,7 +428,14 @@ def create_connects(self): self.ui.tabWidget.tabBarDoubleClicked.connect(self.on_tab_bar_double_clicked) def get_message_type_for_label(self, lbl: ProtocolLabel) -> MessageType: - return next((msg_type for msg_type in self.proto_analyzer.message_types if lbl in msg_type), None) + return next( + ( + msg_type + for msg_type in self.proto_analyzer.message_types + if lbl in msg_type + ), + None, + ) def update_field_type_combobox(self): field_types = [ft.caption for ft in self.field_types] @@ -343,9 +455,14 @@ def set_decoding(self, decoding: Encoding, messages=None): if messages is None: messages = self.proto_analyzer.messages if len(messages) > 10: - reply = QMessageBox.question(self, "Set decoding", - "Do you want to apply the selected decoding to {} messages?".format( - len(messages)), QMessageBox.Yes | QMessageBox.No) + reply = QMessageBox.question( + self, + "Set decoding", + "Do you want to apply the selected decoding to {} messages?".format( + len(messages) + ), + QMessageBox.Yes | QMessageBox.No, + ) if reply != QMessageBox.Yes: self.ui.cbDecoding.blockSignals(True) self.ui.cbDecoding.setCurrentText("...") @@ -363,7 +480,11 @@ def set_decoding(self, decoding: Encoding, messages=None): selected = self.ui.tblViewProtocol.selectionModel().selection() - if not selected.isEmpty() and self.isVisible() and self.proto_analyzer.num_messages > 0: + if ( + not selected.isEmpty() + and self.isVisible() + and self.proto_analyzer.num_messages > 0 + ): min_row = min(rng.top() for rng in selected) min_row = min_row if min_row < len(self.proto_analyzer.messages) else -1 try: @@ -396,7 +517,9 @@ def refresh_existing_encodings(self): update = False for msg in self.proto_analyzer.messages: - decoder = next((d for d in self.decodings if d.name == msg.decoder.name), None) + decoder = next( + (d for d in self.decodings if d.name == msg.decoder.name), None + ) if decoder is None: continue @@ -411,7 +534,9 @@ def refresh_existing_encodings(self): self.label_value_model.update() def fill_decoding_combobox(self): - cur_item = self.ui.cbDecoding.currentText() if self.ui.cbDecoding.count() > 0 else None + cur_item = ( + self.ui.cbDecoding.currentText() if self.ui.cbDecoding.count() > 0 else None + ) self.ui.cbDecoding.blockSignals(True) self.ui.cbDecoding.clear() prev_index = 0 @@ -425,12 +550,16 @@ def fill_decoding_combobox(self): self.ui.cbDecoding.setToolTip(self.ui.cbDecoding.currentText()) self.ui.cbDecoding.blockSignals(False) - def add_protocol(self, protocol: ProtocolAnalyzer, group_id: int = 0) -> ProtocolAnalyzer: + def add_protocol( + self, protocol: ProtocolAnalyzer, group_id: int = 0 + ) -> ProtocolAnalyzer: self.__protocols = None self.proto_tree_model.add_protocol(protocol, group_id) protocol.qt_signals.protocol_updated.connect(self.on_protocol_updated) if protocol.signal: - protocol.signal.sample_rate_changed.connect(self.set_shown_protocols) # Refresh times + protocol.signal.sample_rate_changed.connect( + self.set_shown_protocols + ) # Refresh times protocol.qt_signals.show_state_changed.connect(self.set_shown_protocols) protocol.qt_signals.show_state_changed.connect(self.filter_search_results) for i in range(self.proto_tree_model.ngroups): @@ -447,13 +576,22 @@ def add_protocol_from_file(self, filename: str) -> ProtocolAnalyzer: pa.from_xml_file(filename=filename, read_bits=True) for messsage_type in pa.message_types: if messsage_type not in self.proto_analyzer.message_types: - if messsage_type.name in (mt.name for mt in self.proto_analyzer.message_types): - messsage_type.name += " (" + os.path.split(filename)[1].rstrip(".xml").rstrip(".proto") + ")" + if messsage_type.name in ( + mt.name for mt in self.proto_analyzer.message_types + ): + messsage_type.name += ( + " (" + + os.path.split(filename)[1].rstrip(".xml").rstrip(".proto") + + ")" + ) self.proto_analyzer.message_types.append(messsage_type) update_project = False for msg in pa.messages: - if msg.participant is not None and msg.participant not in self.project_manager.participants: + if ( + msg.participant is not None + and msg.participant not in self.project_manager.participants + ): self.project_manager.participants.append(msg.participant) update_project = True @@ -469,23 +607,40 @@ def add_protocol_from_file(self, filename: str) -> ProtocolAnalyzer: def add_sniffed_protocol_messages(self, messages: list): if len(messages) > 0: proto_analyzer = ProtocolAnalyzer(None) - proto_analyzer.name = datetime.fromtimestamp(messages[0].timestamp).strftime("%Y-%m-%d %H:%M:%S") + proto_analyzer.name = datetime.fromtimestamp( + messages[0].timestamp + ).strftime("%Y-%m-%d %H:%M:%S") proto_analyzer.messages = messages - self.add_protocol(proto_analyzer, group_id=self.proto_tree_model.ngroups - 1) + self.add_protocol( + proto_analyzer, group_id=self.proto_tree_model.ngroups - 1 + ) self.refresh() - def add_protocol_label(self, start: int, end: int, messagenr: int, proto_view: int, edit_label_name=True): + def add_protocol_label( + self, + start: int, + end: int, + messagenr: int, + proto_view: int, + edit_label_name=True, + ): # Ensure at least one Group is active - start, end = self.proto_analyzer.convert_range(start, end, proto_view, 0, decoded=True, message_indx=messagenr) + start, end = self.proto_analyzer.convert_range( + start, end, proto_view, 0, decoded=True, message_indx=messagenr + ) message_type = self.proto_analyzer.messages[messagenr].message_type try: used_field_types = [lbl.field_type for lbl in message_type] - first_unused_type = next(ft for ft in self.field_types if ft not in used_field_types) + first_unused_type = next( + ft for ft in self.field_types if ft not in used_field_types + ) name = first_unused_type.caption except (StopIteration, AttributeError): first_unused_type, name = None, None - proto_label = message_type.add_protocol_label(start=start, end=end, name=name, type=first_unused_type) + proto_label = message_type.add_protocol_label( + start=start, end=end, name=name, type=first_unused_type + ) self.message_type_table_model.update() self.protocol_model.update() @@ -493,7 +648,9 @@ def add_protocol_label(self, start: int, end: int, messagenr: int, proto_view: i if edit_label_name: try: - index = self.ui.tblLabelValues.model().index(message_type.index(proto_label), 0) + index = self.ui.tblLabelValues.model().index( + message_type.index(proto_label), 0 + ) self.ui.tblLabelValues.setCurrentIndex(index) self.ui.tblLabelValues.edit(index) except ValueError: @@ -502,8 +659,12 @@ def add_protocol_label(self, start: int, end: int, messagenr: int, proto_view: i return True def add_message_type(self, selected_messages: list = None): - selected_messages = selected_messages if isinstance(selected_messages, list) else [] - self.proto_analyzer.add_new_message_type(labels=self.proto_analyzer.default_message_type) + selected_messages = ( + selected_messages if isinstance(selected_messages, list) else [] + ) + self.proto_analyzer.add_new_message_type( + labels=self.proto_analyzer.default_message_type + ) self.message_type_table_model.update() self.active_message_type = self.proto_analyzer.message_types[-1] for msg in selected_messages: @@ -521,13 +682,18 @@ def remove_protocol(self, protocol: ProtocolAnalyzer): self.set_shown_protocols() def set_shown_protocols(self): - hidden_rows = {i for i in range(self.protocol_model.row_count) if self.ui.tblViewProtocol.isRowHidden(i)} + hidden_rows = { + i + for i in range(self.protocol_model.row_count) + if self.ui.tblViewProtocol.isRowHidden(i) + } relative_hidden_row_positions = {} for proto in self.rows_for_protocols.keys(): if any(i in hidden_rows for i in self.rows_for_protocols[proto]): m = min(self.rows_for_protocols[proto]) - relative_hidden_row_positions[proto] = [i - m for i in hidden_rows if - i in self.rows_for_protocols[proto]] + relative_hidden_row_positions[proto] = [ + i - m for i in hidden_rows if i in self.rows_for_protocols[proto] + ] # self.protocol_undo_stack.clear() self.proto_analyzer.messages[:] = [] @@ -549,13 +715,19 @@ def set_shown_protocols(self): try: if hasattr(proto.signal, "sample_rate"): if i > 0: - rel_time = proto.messages[i - 1].get_duration(proto.signal.sample_rate) + rel_time = proto.messages[i - 1].get_duration( + proto.signal.sample_rate + ) abs_time += rel_time else: # No signal, loaded from protocol file - abs_time = datetime.fromtimestamp(message.timestamp).strftime("%Y-%m-%d %H:%M:%S.%f") + abs_time = datetime.fromtimestamp( + message.timestamp + ).strftime("%Y-%m-%d %H:%M:%S.%f") if i > 0: - rel_time = message.timestamp - proto.messages[i - 1].timestamp + rel_time = ( + message.timestamp - proto.messages[i - 1].timestamp + ) except IndexError: pass @@ -622,16 +794,22 @@ def restore_selection(self, old_view: int, sel_cols, sel_rows): start_index = self.protocol_model.index(start_row, start_col) end_index = self.protocol_model.index(end_row, end_col) - mid_index = self.protocol_model.index(int((start_row + end_row) / 2), int((start_col + end_col) / 2)) + mid_index = self.protocol_model.index( + int((start_row + end_row) / 2), int((start_col + end_col) / 2) + ) sel = QItemSelection() sel.select(start_index, end_index) - self.ui.tblViewProtocol.selectionModel().select(sel, QItemSelectionModel.ClearAndSelect) + self.ui.tblViewProtocol.selectionModel().select( + sel, QItemSelectionModel.ClearAndSelect + ) self.ui.tblViewProtocol.scrollTo(mid_index) def expand_group_node(self, group_id): - index = self.proto_tree_model.createIndex(group_id, 0, self.proto_tree_model.rootItem.child(group_id)) + index = self.proto_tree_model.createIndex( + group_id, 0, self.proto_tree_model.rootItem.child(group_id) + ) self.ui.treeViewProtocols.expand(index) def updateUI(self, ignore_table_model=False, resize_table=True): @@ -658,13 +836,25 @@ def create_protocol_label_dialog(self, selected_index=None): view_type = self.ui.cbProtoView.currentIndex() try: longest_message = max( - (msg for msg in self.proto_analyzer.messages if msg.message_type == self.active_message_type), key=len) + ( + msg + for msg in self.proto_analyzer.messages + if msg.message_type == self.active_message_type + ), + key=len, + ) except ValueError: logger.warning("Configuring message type with empty message set.") longest_message = Message([True] * 1000, 1000, self.active_message_type) - protocol_label_dialog = ProtocolLabelDialog(message=longest_message, viewtype=view_type, - selected_index=selected_index, parent=self) - protocol_label_dialog.apply_decoding_changed.connect(self.on_apply_decoding_changed) + protocol_label_dialog = ProtocolLabelDialog( + message=longest_message, + viewtype=view_type, + selected_index=selected_index, + parent=self, + ) + protocol_label_dialog.apply_decoding_changed.connect( + self.on_apply_decoding_changed + ) protocol_label_dialog.finished.connect(self.on_protocol_label_dialog_finished) return protocol_label_dialog @@ -692,14 +882,20 @@ def select_all_search_results(self): for search_result in self.protocol_model.search_results: startindex = self.protocol_model.index(search_result[0], search_result[1]) - endindex = self.protocol_model.index(search_result[0], - search_result[1] + len(self.protocol_model.search_value) - 1) + endindex = self.protocol_model.index( + search_result[0], + search_result[1] + len(self.protocol_model.search_value) - 1, + ) sel = QItemSelection() sel.select(startindex, endindex) - self.ui.tblViewProtocol.selectionModel().select(sel, QItemSelectionModel.Select) - self.ui.tblViewProtocol.scrollTo(startindex, QAbstractItemView.PositionAtCenter) + self.ui.tblViewProtocol.selectionModel().select( + sel, QItemSelectionModel.Select + ) + self.ui.tblViewProtocol.scrollTo( + startindex, QAbstractItemView.PositionAtCenter + ) self.ui.tblViewProtocol.setFocus() @@ -714,7 +910,9 @@ def filter_search_results(self): self.search() self.ui.tblLabelValues.clearSelection() - matching_rows = set(search_result[0] for search_result in self.protocol_model.search_results) + matching_rows = set( + search_result[0] for search_result in self.protocol_model.search_results + ) rows_to_hide = set(range(0, self.protocol_model.row_count)) - matching_rows self.ui.tblViewProtocol.hide_rows(rows_to_hide) else: @@ -727,15 +925,21 @@ def __set_shown_rows_status_label(self): if len(self.protocol_model.hidden_rows) > 0: rc = self.protocol_model.row_count text = self.tr("shown: {}/{} (reset)") - self.ui.lblShownRows.setText(text.format(rc - len(self.protocol_model.hidden_rows), rc)) + self.ui.lblShownRows.setText( + text.format(rc - len(self.protocol_model.hidden_rows), rc) + ) self.ui.lblShownRows.show() else: self.ui.lblShownRows.hide() def align_messages(self, pattern=None): pattern = self.ui.lineEditSearch.text() if pattern is None else pattern - self.proto_analyzer.align_messages(pattern, view_type=self.ui.cbProtoView.currentIndex()) - self.ui.lblClearAlignment.setVisible(any(msg.alignment_offset != 0 for msg in self.proto_analyzer.messages)) + self.proto_analyzer.align_messages( + pattern, view_type=self.ui.cbProtoView.currentIndex() + ) + self.ui.lblClearAlignment.setVisible( + any(msg.alignment_offset != 0 for msg in self.proto_analyzer.messages) + ) self.protocol_model.update() row = column = 0 @@ -743,10 +947,17 @@ def align_messages(self, pattern=None): if self.ui.tblViewProtocol.isRowHidden(i): continue - data = message.view_to_string(self.ui.cbProtoView.currentIndex(), decoded=True) + data = message.view_to_string( + self.ui.cbProtoView.currentIndex(), decoded=True + ) try: row = i - column = data.index(pattern) + len(pattern) + self.protocol_model.get_alignment_offset_at(i) - 1 + column = ( + data.index(pattern) + + len(pattern) + + self.protocol_model.get_alignment_offset_at(i) + - 1 + ) break except ValueError: pass @@ -763,14 +974,20 @@ def next_search_result(self): try: search_result = self.protocol_model.search_results[index] startindex = self.protocol_model.index(search_result[0], search_result[1]) - endindex = self.protocol_model.index(search_result[0], - search_result[1] + len(self.protocol_model.search_value) - 1) + endindex = self.protocol_model.index( + search_result[0], + search_result[1] + len(self.protocol_model.search_value) - 1, + ) sel = QItemSelection() sel.select(startindex, endindex) - self.ui.tblViewProtocol.selectionModel().select(sel, QItemSelectionModel.ClearAndSelect) - self.ui.tblViewProtocol.scrollTo(startindex, QAbstractItemView.PositionAtCenter) + self.ui.tblViewProtocol.selectionModel().select( + sel, QItemSelectionModel.ClearAndSelect + ) + self.ui.tblViewProtocol.scrollTo( + startindex, QAbstractItemView.PositionAtCenter + ) self.ui.lSearchCurrent.setText(str(index + 1)) except IndexError: @@ -788,14 +1005,20 @@ def prev_search_result(self): try: search_result = self.protocol_model.search_results[index] startindex = self.protocol_model.index(search_result[0], search_result[1]) - endindex = self.protocol_model.index(search_result[0], - search_result[1] + len(self.protocol_model.search_value) - 1) + endindex = self.protocol_model.index( + search_result[0], + search_result[1] + len(self.protocol_model.search_value) - 1, + ) sel = QItemSelection() sel.select(startindex, endindex) - self.ui.tblViewProtocol.selectionModel().select(sel, QItemSelectionModel.ClearAndSelect) - self.ui.tblViewProtocol.scrollTo(startindex, QAbstractItemView.PositionAtCenter) + self.ui.tblViewProtocol.selectionModel().select( + sel, QItemSelectionModel.ClearAndSelect + ) + self.ui.tblViewProtocol.scrollTo( + startindex, QAbstractItemView.PositionAtCenter + ) self.ui.lSearchCurrent.setText(str(index + 1)) except IndexError: @@ -815,10 +1038,20 @@ def clear_search(self): self.protocol_model.search_results[:] = [] self.protocol_model.search_value = "" - def set_protocol_label_visibility(self, lbl: ProtocolLabel, message: Message = None): + def set_protocol_label_visibility( + self, lbl: ProtocolLabel, message: Message = None + ): try: - message = message if message else next(m for m in self.proto_analyzer.messages if lbl in m.message_type) - start, end = message.get_label_range(lbl, self.ui.cbProtoView.currentIndex(), True, consider_alignment=True) + message = ( + message + if message + else next( + m for m in self.proto_analyzer.messages if lbl in m.message_type + ) + ) + start, end = message.get_label_range( + lbl, self.ui.cbProtoView.currentIndex(), True, consider_alignment=True + ) for i in range(start, end): self.ui.tblViewProtocol.setColumnHidden(i, not lbl.show) @@ -827,7 +1060,11 @@ def set_protocol_label_visibility(self, lbl: ProtocolLabel, message: Message = N def set_message_type_visibility(self, message_type: MessageType): try: - rows = {i for i, msg in enumerate(self.proto_analyzer.messages) if msg.message_type == message_type} + rows = { + i + for i, msg in enumerate(self.proto_analyzer.messages) + if msg.message_type == message_type + } if message_type.show: self.ui.tblViewProtocol.show_rows(rows) else: @@ -847,17 +1084,23 @@ def show_all_cols(self): def save_protocol(self): for msg in self.proto_analyzer.messages: if not msg.decoder.is_nrz: - reply = QMessageBox.question(self, "Saving of protocol", - "You want to save this protocol with an encoding different from NRZ.\n" - "This may cause loss of information if you load it again.\n\n" - "Save anyway?", QMessageBox.Yes | QMessageBox.No) + reply = QMessageBox.question( + self, + "Saving of protocol", + "You want to save this protocol with an encoding different from NRZ.\n" + "This may cause loss of information if you load it again.\n\n" + "Save anyway?", + QMessageBox.Yes | QMessageBox.No, + ) if reply != QMessageBox.Yes: return else: break text = "protocol" - filename = FileOperator.ask_save_file_name("{0}.proto.xml".format(text), caption="Save protocol") + filename = FileOperator.ask_save_file_name( + "{0}.proto.xml".format(text), caption="Save protocol" + ) if not filename: return @@ -865,13 +1108,25 @@ def save_protocol(self): if filename.endswith(".bin"): self.proto_analyzer.to_binary(filename, use_decoded=True) elif filename.endswith(".pcapng"): - data_link_type, ok = QInputDialog.getInt(self, "Link type", - "Interface Link Type to use (probably one between DLT_USER0-DLT_USER15 (147-162)):", 147, 0, 65535) + data_link_type, ok = QInputDialog.getInt( + self, + "Link type", + "Interface Link Type to use (probably one between DLT_USER0-DLT_USER15 (147-162)):", + 147, + 0, + 65535, + ) if ok: - self.proto_analyzer.to_pcapng(filename=filename, link_type=data_link_type) + self.proto_analyzer.to_pcapng( + filename=filename, link_type=data_link_type + ) else: - self.proto_analyzer.to_xml_file(filename=filename, decoders=self.decodings, - participants=self.project_manager.participants, write_bits=True) + self.proto_analyzer.to_xml_file( + filename=filename, + decoders=self.decodings, + participants=self.project_manager.participants, + write_bits=True, + ) def show_differences(self, show_differences: bool): if show_differences: @@ -890,15 +1145,27 @@ def set_show_only_status(self): - Show only labels - Show only Diffs """ - if self.ui.chkBoxShowOnlyDiffs.isChecked() and not self.ui.cbShowDiffs.isChecked(): + if ( + self.ui.chkBoxShowOnlyDiffs.isChecked() + and not self.ui.cbShowDiffs.isChecked() + ): self.ui.cbShowDiffs.setChecked(True) self.show_differences(True) - if self.ui.chkBoxOnlyShowLabelsInProtocol.isChecked() and self.ui.chkBoxShowOnlyDiffs.isChecked(): + if ( + self.ui.chkBoxOnlyShowLabelsInProtocol.isChecked() + and self.ui.chkBoxShowOnlyDiffs.isChecked() + ): self.show_only_diffs_and_labels() - elif self.ui.chkBoxOnlyShowLabelsInProtocol.isChecked() and not self.ui.chkBoxShowOnlyDiffs.isChecked(): + elif ( + self.ui.chkBoxOnlyShowLabelsInProtocol.isChecked() + and not self.ui.chkBoxShowOnlyDiffs.isChecked() + ): self.show_only_labels() - elif not self.ui.chkBoxOnlyShowLabelsInProtocol.isChecked() and self.ui.chkBoxShowOnlyDiffs.isChecked(): + elif ( + not self.ui.chkBoxOnlyShowLabelsInProtocol.isChecked() + and self.ui.chkBoxShowOnlyDiffs.isChecked() + ): self.show_only_diffs() else: self.restore_visibility() @@ -909,17 +1176,27 @@ def show_only_labels(self): visible_columns = set() for msg in self.proto_analyzer.messages: for lbl in filter(lambda lbl: lbl.show, msg.message_type): - start, end = msg.get_label_range(lbl=lbl, view=self.ui.cbProtoView.currentIndex(), decode=True) + start, end = msg.get_label_range( + lbl=lbl, view=self.ui.cbProtoView.currentIndex(), decode=True + ) visible_columns |= set(range(start, end)) for i in range(self.protocol_model.col_count): self.ui.tblViewProtocol.setColumnHidden(i, i not in visible_columns) def show_only_diffs(self): - visible_rows = [i for i in range(self.protocol_model.row_count) if not self.ui.tblViewProtocol.isRowHidden(i) - and i != self.protocol_model.refindex] - - visible_diff_columns = [diff_col for i in visible_rows for diff_col in self.protocol_model.diff_columns[i]] + visible_rows = [ + i + for i in range(self.protocol_model.row_count) + if not self.ui.tblViewProtocol.isRowHidden(i) + and i != self.protocol_model.refindex + ] + + visible_diff_columns = [ + diff_col + for i in visible_rows + for diff_col in self.protocol_model.diff_columns[i] + ] for j in range(self.protocol_model.col_count): if j in visible_diff_columns: @@ -931,14 +1208,25 @@ def show_only_diffs_and_labels(self): visible_label_columns = set() for lbl in self.proto_analyzer.protocol_labels: if lbl.show: - start, end = self.proto_analyzer.messages[0].get_label_range(lbl, self.ui.cbProtoView.currentIndex(), - True) - visible_label_columns |= (set(range(start, end))) - - visible_rows = [i for i in range(self.protocol_model.row_count) if not self.ui.tblViewProtocol.isRowHidden(i) - and i != self.protocol_model.refindex] - - visible_diff_columns = set([diff_col for i in visible_rows for diff_col in self.protocol_model.diff_columns[i]]) + start, end = self.proto_analyzer.messages[0].get_label_range( + lbl, self.ui.cbProtoView.currentIndex(), True + ) + visible_label_columns |= set(range(start, end)) + + visible_rows = [ + i + for i in range(self.protocol_model.row_count) + if not self.ui.tblViewProtocol.isRowHidden(i) + and i != self.protocol_model.refindex + ] + + visible_diff_columns = set( + [ + diff_col + for i in visible_rows + for diff_col in self.protocol_model.diff_columns[i] + ] + ) visible_cols = visible_label_columns & visible_diff_columns for j in range(self.protocol_model.col_count): @@ -948,12 +1236,16 @@ def show_only_diffs_and_labels(self): self.ui.tblViewProtocol.hideColumn(j) def restore_visibility(self): - selected = self.ui.tblViewProtocol.selectionModel().selection() # type: QItemSelection + selected = ( + self.ui.tblViewProtocol.selectionModel().selection() + ) # type: QItemSelection for i in range(self.protocol_model.col_count): self.ui.tblViewProtocol.showColumn(i) - for lbl in filter(lambda lbl: not lbl.show, self.proto_analyzer.protocol_labels): + for lbl in filter( + lambda lbl: not lbl.show, self.proto_analyzer.protocol_labels + ): self.set_protocol_label_visibility(lbl) if not selected.isEmpty(): @@ -961,7 +1253,9 @@ def restore_visibility(self): start = numpy.min([rng.left() for rng in selected]) self.ui.tblViewProtocol.scrollTo(self.protocol_model.index(min_row, start)) - def get_labels_from_selection(self, row_start: int, row_end: int, col_start: int, col_end: int): + def get_labels_from_selection( + self, row_start: int, row_end: int, col_start: int, col_end: int + ): """ :rtype: list of ProtocolLabel @@ -971,15 +1265,26 @@ def get_labels_from_selection(self, row_start: int, row_end: int, col_start: int view = self.ui.cbProtoView.currentIndex() result = [] - f = 1 if self.ui.cbProtoView.currentIndex() == 0 else 4 if self.ui.cbProtoView.currentIndex() == 1 else 8 + f = ( + 1 + if self.ui.cbProtoView.currentIndex() == 0 + else 4 + if self.ui.cbProtoView.currentIndex() == 1 + else 8 + ) for i in range(row_start, row_end): message = self.proto_analyzer.messages[i] for label in message.message_type: if label in result: continue - lbl_start, lbl_end = message.get_label_range(lbl=label, view=view, decode=True) + lbl_start, lbl_end = message.get_label_range( + lbl=label, view=view, decode=True + ) a = message.alignment_offset - if any(j in range(lbl_start, lbl_end) for j in range(col_start - a//f, col_end - a//f)): + if any( + j in range(lbl_start, lbl_end) + for j in range(col_start - a // f, col_end - a // f) + ): result.append(label) return result @@ -1003,8 +1308,12 @@ def refresh_assigned_participants_ui(self): def refresh_field_types_for_labels(self): for mt in self.proto_analyzer.message_types: - for lbl in (lbl for lbl in mt if lbl.field_type is not None): # type: ProtocolLabel - mt.change_field_type_of_label(lbl, self.field_types_by_caption.get(lbl.field_type.caption, None)) + for lbl in ( + lbl for lbl in mt if lbl.field_type is not None + ): # type: ProtocolLabel + mt.change_field_type_of_label( + lbl, self.field_types_by_caption.get(lbl.field_type.caption, None) + ) self.update_field_type_combobox() @@ -1036,7 +1345,9 @@ def on_btn_analyze_clicked(self): if self.assign_participants_action.isChecked(): for protocol in self.protocol_list: - AutoAssigner.auto_assign_participants(protocol.messages, self.protocol_model.participants) + AutoAssigner.auto_assign_participants( + protocol.messages, self.protocol_model.participants + ) self.refresh_assigned_participants_ui() self.ui.progressBarLogicAnalyzer.setFormat("%p% (Assign message type by rules)") @@ -1045,7 +1356,9 @@ def on_btn_analyze_clicked(self): if self.assign_message_type_action.isChecked(): self.update_automatic_assigned_message_types() - self.ui.progressBarLogicAnalyzer.setFormat("%p% (Find new labels/message types)") + self.ui.progressBarLogicAnalyzer.setFormat( + "%p% (Find new labels/message types)" + ) self.ui.progressBarLogicAnalyzer.setValue(75) if self.assign_labels_action.isChecked(): @@ -1061,8 +1374,9 @@ def on_btn_analyze_clicked(self): self.ui.progressBarLogicAnalyzer.setValue(90) if self.assign_participant_address_action.isChecked(): - AutoAssigner.auto_assign_participant_addresses(self.proto_analyzer.messages, - self.protocol_model.participants) + AutoAssigner.auto_assign_participant_addresses( + self.proto_analyzer.messages, self.protocol_model.participants + ) self.ui.progressBarLogicAnalyzer.setValue(100) self.unsetCursor() @@ -1092,7 +1406,9 @@ def on_btn_search_clicked(self): @pyqtSlot(int) def on_configure_message_type_rules_triggered(self, message_type_index: int): - dialog = MessageTypeDialog(self.proto_analyzer.message_types[message_type_index], parent=self) + dialog = MessageTypeDialog( + self.proto_analyzer.message_types[message_type_index], parent=self + ) dialog.show() dialog.accepted.connect(self.on_message_type_dialog_accepted) @@ -1118,13 +1434,19 @@ def on_combobox_decoding_current_index_changed(self): if new_index == self.ui.cbDecoding.count() - 1: self.set_decoding(None) else: - self.set_decoding(self.decodings[new_index], - messages=self.selected_messages if self.selected_messages else None) + self.set_decoding( + self.decodings[new_index], + messages=self.selected_messages if self.selected_messages else None, + ) @pyqtSlot() def on_participant_show_state_changed(self): for i, msg in enumerate(self.proto_analyzer.messages): - hide = not msg.participant.show if msg.participant is not None else not self.participant_list_model.show_unassigned + hide = ( + not msg.participant.show + if msg.participant is not None + else not self.participant_list_model.show_unassigned + ) self.ui.tblViewProtocol.setRowHidden(i, hide) self.set_shown_protocols() @@ -1212,11 +1534,17 @@ def on_btn_search_select_filter_clicked(): self.ui.btnSearchSelectFilter.setIcon(QIcon.fromTheme("align-horizontal-left")) self.set_search_ui_visibility(False) self.ui.btnSearchSelectFilter.clicked.disconnect() - self.ui.btnSearchSelectFilter.clicked.connect(on_btn_search_select_filter_clicked) + self.ui.btnSearchSelectFilter.clicked.connect( + on_btn_search_select_filter_clicked + ) @pyqtSlot(bool) def on_writeable_changed(self, writeable_status: bool): - hidden_rows = {i for i in range(self.protocol_model.row_count) if self.ui.tblViewProtocol.isRowHidden(i)} + hidden_rows = { + i + for i in range(self.protocol_model.row_count) + if self.ui.tblViewProtocol.isRowHidden(i) + } self.protocol_model.is_writeable = writeable_status self.proto_tree_model.set_copy_mode(writeable_status) self.ui.cbDecoding.setDisabled(writeable_status) @@ -1264,8 +1592,12 @@ def on_edit_label_clicked_in_table(self, proto_label_index: int): @pyqtSlot(int, int, int) def on_create_label_triggered(self, msg_index, start, end): a = self.protocol_model.get_alignment_offset_at(msg_index) - self.add_protocol_label(start=start - a, end=end - a - 1, - messagenr=msg_index, proto_view=self.ui.cbProtoView.currentIndex()) + self.add_protocol_label( + start=start - a, + end=end - a - 1, + messagenr=msg_index, + proto_view=self.ui.cbProtoView.currentIndex(), + ) @pyqtSlot() def on_edit_label_action_triggered(self): @@ -1309,7 +1641,9 @@ def on_tree_view_selection_changed(self): if item.is_group: active_group_ids.add(self.proto_tree_model.rootItem.index_of(item)) elif item.show: - active_group_ids.add(self.proto_tree_model.rootItem.index_of(item.parent())) + active_group_ids.add( + self.proto_tree_model.rootItem.index_of(item.parent()) + ) if len(active_group_ids) == 0: active_group_ids.add(0) @@ -1321,7 +1655,9 @@ def on_tree_view_selection_changed(self): self.active_group_ids = list(active_group_ids) self.active_group_ids.sort() - self.ui.tblViewProtocol.selectionModel().select(sel, QItemSelectionModel.ClearAndSelect) + self.ui.tblViewProtocol.selectionModel().select( + sel, QItemSelectionModel.ClearAndSelect + ) self.ui.tblViewProtocol.blockSignals(False) self.updateUI(ignore_table_model=ignore_table_model_on_update) @@ -1342,14 +1678,17 @@ def on_table_selection_timer_timeout(self): self.ui.lDecimalSelection.setText("") self.ui.lHexSelection.setText("") self.ui.lNumSelectedColumns.setText("0") - self.ui.lblLabelValues.setText(self.tr("Labels of {}".format(self.active_message_type.name))) + self.ui.lblLabelValues.setText( + self.tr("Labels of {}".format(self.active_message_type.name)) + ) self.__set_decoding_error_label(message=None) self.updateUI(ignore_table_model=True, resize_table=False) return -1, -1 selected_messages = self.selected_messages self.message_type_table_model.selected_message_type_indices = { - self.proto_analyzer.message_types.index(msg.message_type) for msg in selected_messages + self.proto_analyzer.message_types.index(msg.message_type) + for msg in selected_messages } cur_view = self.ui.cbProtoView.currentIndex() @@ -1358,7 +1697,9 @@ def on_table_selection_timer_timeout(self): message = self.proto_analyzer.messages[min_row] self.active_message_type = message.message_type - selected_labels = self.get_labels_from_selection(min_row, min_row, start, end - 1) + selected_labels = self.get_labels_from_selection( + min_row, min_row, start, end - 1 + ) self.label_value_model.selected_label_indices = { self.active_message_type.index(lbl) for lbl in selected_labels } @@ -1366,8 +1707,12 @@ def on_table_selection_timer_timeout(self): f = 4 if cur_view == 1 else 8 if cur_view == 2 else 1 start, end = start * f, end * f - bits = message.decoded_bits_str[start-message.alignment_offset:end-message.alignment_offset] - hexs = "".join(("{0:x}".format(int(bits[i:i + 4], 2)) for i in range(0, len(bits), 4))) + bits = message.decoded_bits_str[ + start - message.alignment_offset : end - message.alignment_offset + ] + hexs = "".join( + ("{0:x}".format(int(bits[i : i + 4], 2)) for i in range(0, len(bits), 4)) + ) decimals = str(int(bits, 2)) if len(bits) > 0 else "" self.ui.lBitsSelection.setText(bits) @@ -1375,7 +1720,9 @@ def on_table_selection_timer_timeout(self): self.ui.lDecimalSelection.setText(decimals) self.__set_decoding_error_label(message) - self.ui.lblLabelValues.setText(self.tr("Labels for message #") + str(min_row + 1)) + self.ui.lblLabelValues.setText( + self.tr("Labels for message #") + str(min_row + 1) + ) if min_row != self.label_value_model.message_index: self.label_value_model.message_index = min_row @@ -1385,7 +1732,10 @@ def on_table_selection_timer_timeout(self): for i, tree_item in enumerate(tree_items): proto = tree_item.protocol if proto.show and proto in self.rows_for_protocols: - if any(i in self.rows_for_protocols[proto] for i in range(min_row, max_row + 1)): + if any( + i in self.rows_for_protocols[proto] + for i in range(min_row, max_row + 1) + ): active_group_ids.add(group) self.selected_protocols.add(proto) @@ -1394,7 +1744,9 @@ def on_table_selection_timer_timeout(self): self.active_group_ids.sort() if message.rssi > 0: - self.ui.lblRSSI.setText(locale.format_string("%.2f dBm", 10*math.log10(message.rssi))) + self.ui.lblRSSI.setText( + locale.format_string("%.2f dBm", 10 * math.log10(message.rssi)) + ) else: self.ui.lblRSSI.setText("-\u221e dBm") if isinstance(message.absolute_time, str): @@ -1408,8 +1760,12 @@ def on_table_selection_timer_timeout(self): # Set Decoding Combobox self.ui.cbDecoding.blockSignals(True) - different_encodings = any(msg.decoder != message.decoder for msg in selected_messages) - self.ui.cbDecoding.setCurrentText("..." if different_encodings else message.decoder.name) + different_encodings = any( + msg.decoder != message.decoder for msg in selected_messages + ) + self.ui.cbDecoding.setCurrentText( + "..." if different_encodings else message.decoder.name + ) self.ui.cbDecoding.blockSignals(False) self.updateUI(ignore_table_model=True, resize_table=False) @@ -1419,29 +1775,39 @@ def on_ref_index_changed(self, new_ref_index: int): if new_ref_index != -1 and self.protocol_model.row_count: hide_correction = 0 for i in range(0, self.protocol_model.row_count): - if self.ui.tblViewProtocol.isRowHidden((new_ref_index + i) % self.protocol_model.row_count): + if self.ui.tblViewProtocol.isRowHidden( + (new_ref_index + i) % self.protocol_model.row_count + ): hide_correction = 0 else: hide_correction = i break - self.protocol_model.refindex = (new_ref_index + hide_correction) % self.protocol_model.row_count + self.protocol_model.refindex = ( + new_ref_index + hide_correction + ) % self.protocol_model.row_count self.set_show_only_status() @pyqtSlot(QModelIndex, QModelIndex) - def on_tbl_view_message_current_row_changed(self, current: QModelIndex, previous: QModelIndex): + def on_tbl_view_message_current_row_changed( + self, current: QModelIndex, previous: QModelIndex + ): row = current.row() if row == -1: return self.active_message_type = self.proto_analyzer.message_types[row] - self.ui.lblLabelValues.setText("Labels of {}".format(self.active_message_type.name)) + self.ui.lblLabelValues.setText( + "Labels of {}".format(self.active_message_type.name) + ) self.label_value_model.show_label_values = False self.label_value_model.update() @pyqtSlot(MessageType, list) - def on_message_type_selected(self, message_type: MessageType, selected_messages: list): + def on_message_type_selected( + self, message_type: MessageType, selected_messages: list + ): for msg in selected_messages: msg.message_type = message_type self.active_message_type = message_type diff --git a/src/urh/controller/GeneratorTabController.py b/src/urh/controller/GeneratorTabController.py index e9900d38e2..934f39edd6 100644 --- a/src/urh/controller/GeneratorTabController.py +++ b/src/urh/controller/GeneratorTabController.py @@ -15,7 +15,9 @@ from urh.models.GeneratorListModel import GeneratorListModel from urh.models.GeneratorTableModel import GeneratorTableModel from urh.models.GeneratorTreeModel import GeneratorTreeModel -from urh.plugins.NetworkSDRInterface.NetworkSDRInterfacePlugin import NetworkSDRInterfacePlugin +from urh.plugins.NetworkSDRInterface.NetworkSDRInterfacePlugin import ( + NetworkSDRInterfacePlugin, +) from urh.plugins.PluginManager import PluginManager from urh.plugins.RfCat.RfCatPlugin import RfCatPlugin from urh.plugins.FlipperZeroSub.FlipperZeroSubPlugin import FlipperZeroSubPlugin @@ -35,7 +37,12 @@ class GeneratorTabController(QWidget): - def __init__(self, compare_frame_controller: CompareFrameController, project_manager: ProjectManager, parent=None): + def __init__( + self, + compare_frame_controller: CompareFrameController, + project_manager: ProjectManager, + parent=None, + ): super().__init__(parent) self.ui = Ui_GeneratorTab() self.ui.setupUi(self) @@ -45,12 +52,16 @@ def __init__(self, compare_frame_controller: CompareFrameController, project_man self.ui.treeProtocols.setHeaderHidden(True) self.tree_model = GeneratorTreeModel(compare_frame_controller) - self.tree_model.set_root_item(compare_frame_controller.proto_tree_model.rootItem) + self.tree_model.set_root_item( + compare_frame_controller.proto_tree_model.rootItem + ) self.tree_model.controller = self self.ui.treeProtocols.setModel(self.tree_model) - self.table_model = GeneratorTableModel(compare_frame_controller.proto_tree_model.rootItem, - compare_frame_controller.decodings) + self.table_model = GeneratorTableModel( + compare_frame_controller.proto_tree_model.rootItem, + compare_frame_controller.decodings, + ) self.table_model.controller = self self.ui.tableMessages.setModel(self.table_model) @@ -91,7 +102,9 @@ def selected_message_index(self) -> int: @property def selected_message(self) -> Message: selected_msg_index = self.selected_message_index - if selected_msg_index == -1 or selected_msg_index >= len(self.table_model.protocol.messages): + if selected_msg_index == -1 or selected_msg_index >= len( + self.table_model.protocol.messages + ): return None return self.table_model.protocol.messages[selected_msg_index] @@ -106,8 +119,14 @@ def modulators(self): @property def total_modulated_samples(self) -> int: - return sum(int(len(msg.encoded_bits) * self.__get_modulator_of_message(msg).samples_per_symbol + msg.pause) - for msg in self.table_model.protocol.messages) + return sum( + int( + len(msg.encoded_bits) + * self.__get_modulator_of_message(msg).samples_per_symbol + + msg.pause + ) + for msg in self.table_model.protocol.messages + ) @modulators.setter def modulators(self, value): @@ -116,19 +135,36 @@ def modulators(self, value): def create_connects(self, compare_frame_controller): compare_frame_controller.proto_tree_model.modelReset.connect(self.refresh_tree) - compare_frame_controller.participant_changed.connect(self.table_model.refresh_vertical_header) + compare_frame_controller.participant_changed.connect( + self.table_model.refresh_vertical_header + ) self.ui.btnEditModulation.clicked.connect(self.show_modulation_dialog) - self.ui.cBoxModulations.currentIndexChanged.connect(self.on_selected_modulation_changed) - self.ui.tableMessages.selectionModel().selectionChanged.connect(self.on_table_selection_changed) + self.ui.cBoxModulations.currentIndexChanged.connect( + self.on_selected_modulation_changed + ) + self.ui.tableMessages.selectionModel().selectionChanged.connect( + self.on_table_selection_changed + ) self.ui.tableMessages.encodings_updated.connect(self.on_table_selection_changed) - self.table_model.undo_stack.indexChanged.connect(self.on_undo_stack_index_changed) - self.table_model.protocol.qt_signals.line_duplicated.connect(self.refresh_pause_list) - self.table_model.protocol.qt_signals.fuzzing_started.connect(self.on_fuzzing_started) + self.table_model.undo_stack.indexChanged.connect( + self.on_undo_stack_index_changed + ) + self.table_model.protocol.qt_signals.line_duplicated.connect( + self.refresh_pause_list + ) + self.table_model.protocol.qt_signals.fuzzing_started.connect( + self.on_fuzzing_started + ) self.table_model.protocol.qt_signals.current_fuzzing_message_changed.connect( - self.on_current_fuzzing_message_changed) - self.table_model.protocol.qt_signals.fuzzing_finished.connect(self.on_fuzzing_finished) + self.on_current_fuzzing_message_changed + ) + self.table_model.protocol.qt_signals.fuzzing_finished.connect( + self.on_fuzzing_finished + ) self.table_model.first_protocol_added.connect(self.on_first_protocol_added) - self.label_list_model.protolabel_fuzzing_status_changed.connect(self.set_fuzzing_ui_status) + self.label_list_model.protolabel_fuzzing_status_changed.connect( + self.set_fuzzing_ui_status + ) self.ui.cbViewType.currentIndexChanged.connect(self.on_view_type_changed) self.ui.btnSend.clicked.connect(self.on_btn_send_clicked) self.ui.btnSave.clicked.connect(self.on_btn_save_clicked) @@ -137,29 +173,46 @@ def create_connects(self, compare_frame_controller): self.project_manager.project_updated.connect(self.on_project_updated) self.table_model.vertical_header_color_status_changed.connect( - self.ui.tableMessages.on_vertical_header_color_status_changed) + self.ui.tableMessages.on_vertical_header_color_status_changed + ) - self.label_list_model.protolabel_removed.connect(self.handle_proto_label_removed) + self.label_list_model.protolabel_removed.connect( + self.handle_proto_label_removed + ) self.ui.lWPauses.item_edit_clicked.connect(self.edit_pause_item) self.ui.lWPauses.edit_all_items_clicked.connect(self.edit_all_pause_items) - self.ui.lWPauses.itemSelectionChanged.connect(self.on_lWpauses_selection_changed) + self.ui.lWPauses.itemSelectionChanged.connect( + self.on_lWpauses_selection_changed + ) self.ui.lWPauses.lost_focus.connect(self.on_lWPauses_lost_focus) self.ui.lWPauses.doubleClicked.connect(self.on_lWPauses_double_clicked) self.ui.btnGenerate.clicked.connect(self.generate_file) - self.label_list_model.protolabel_fuzzing_status_changed.connect(self.handle_plabel_fuzzing_state_changed) + self.label_list_model.protolabel_fuzzing_status_changed.connect( + self.handle_plabel_fuzzing_state_changed + ) self.ui.btnFuzz.clicked.connect(self.on_btn_fuzzing_clicked) self.ui.tableMessages.create_label_triggered.connect(self.create_fuzzing_label) self.ui.tableMessages.edit_label_triggered.connect(self.show_fuzzing_dialog) - self.ui.listViewProtoLabels.selection_changed.connect(self.handle_label_selection_changed) - self.ui.listViewProtoLabels.edit_on_item_triggered.connect(self.show_fuzzing_dialog) + self.ui.listViewProtoLabels.selection_changed.connect( + self.handle_label_selection_changed + ) + self.ui.listViewProtoLabels.edit_on_item_triggered.connect( + self.show_fuzzing_dialog + ) self.ui.btnNetworkSDRSend.clicked.connect(self.on_btn_network_sdr_clicked) self.ui.btnRfCatSend.clicked.connect(self.on_btn_rfcat_clicked) - self.network_sdr_plugin.sending_status_changed.connect(self.on_network_sdr_sending_status_changed) - self.network_sdr_plugin.sending_stop_requested.connect(self.on_network_sdr_sending_stop_requested) - self.network_sdr_plugin.current_send_message_changed.connect(self.on_send_message_changed) + self.network_sdr_plugin.sending_status_changed.connect( + self.on_network_sdr_sending_status_changed + ) + self.network_sdr_plugin.sending_stop_requested.connect( + self.on_network_sdr_sending_stop_requested + ) + self.network_sdr_plugin.current_send_message_changed.connect( + self.on_send_message_changed + ) # Flipper Zero self.ui.btnFZSave.clicked.connect(self.on_btn_FZSave_clicked) @@ -174,7 +227,10 @@ def refresh_tree(self): def refresh_table(self): self.table_model.update() self.ui.tableMessages.resize_columns() - is_data_there = self.table_model.display_data is not None and len(self.table_model.display_data) > 0 + is_data_there = ( + self.table_model.display_data is not None + and len(self.table_model.display_data) > 0 + ) self.ui.btnSend.setEnabled(is_data_there) self.ui.btnGenerate.setEnabled(is_data_there) @@ -256,16 +312,27 @@ def prepare_modulation_dialog(self) -> (ModulatorDialog, Message): selected_message = self.table_model.protocol.messages[min_row] preselected_index = selected_message.modulator_index except IndexError: - selected_message = Message([1, 0, 1, 0, 1, 0, 1, 0, 1, 1, 0, 1, 0, 0], 0, [], MessageType("empty")) + selected_message = Message( + [1, 0, 1, 0, 1, 0, 1, 0, 1, 1, 0, 1, 0, 0], + 0, + [], + MessageType("empty"), + ) else: - selected_message = Message([1, 0, 1, 0, 1, 0, 1, 0, 1, 1, 0, 1, 0, 0], 0, [], MessageType("empty")) + selected_message = Message( + [1, 0, 1, 0, 1, 0, 1, 0, 1, 1, 0, 1, 0, 0], 0, [], MessageType("empty") + ) if len(self.table_model.protocol.messages) > 0: - selected_message.samples_per_symbol = self.table_model.protocol.messages[0].samples_per_symbol + selected_message.samples_per_symbol = ( + self.table_model.protocol.messages[0].samples_per_symbol + ) for m in self.modulators: m.default_sample_rate = self.project_manager.device_conf["sample_rate"] - modulator_dialog = ModulatorDialog(self.modulators, tree_model=self.tree_model, parent=self.parent()) + modulator_dialog = ModulatorDialog( + self.modulators, tree_model=self.tree_model, parent=self.parent() + ) modulator_dialog.ui.comboBoxCustomModulations.setCurrentIndex(preselected_index) modulator_dialog.finished.connect(self.refresh_modulators) @@ -280,7 +347,9 @@ def set_modulation_profile_status(self): def init_rfcat_plugin(self): self.set_rfcat_button_visibility() self.rfcat_plugin = RfCatPlugin() - self.rfcat_plugin.current_send_message_changed.connect(self.on_send_message_changed) + self.rfcat_plugin.current_send_message_changed.connect( + self.on_send_message_changed + ) self.ui.btnRfCatSend.setEnabled(self.rfcat_plugin.rfcat_is_found) @pyqtSlot() @@ -314,7 +383,9 @@ def on_table_selection_changed(self): self.label_list_model.message = message decoder_name = message.decoder.name metrics = QFontMetrics(self.ui.lEncodingValue.font()) - elidedName = metrics.elidedText(decoder_name, Qt.ElideRight, self.ui.lEncodingValue.width()) + elidedName = metrics.elidedText( + decoder_name, Qt.ElideRight, self.ui.lEncodingValue.width() + ) self.ui.lEncodingValue.setText(elidedName) self.ui.lEncodingValue.setToolTip(decoder_name) self.ui.cBoxModulations.blockSignals(True) @@ -326,8 +397,13 @@ def on_table_selection_changed(self): def edit_pause_item(self, index: int): message = self.table_model.protocol.messages[index] cur_len = message.pause - new_len, ok = QInputDialog.getInt(self, self.tr("Enter new Pause Length"), - self.tr("Pause Length:"), cur_len, 0) + new_len, ok = QInputDialog.getInt( + self, + self.tr("Enter new Pause Length"), + self.tr("Pause Length:"), + cur_len, + 0, + ) if ok: message.pause = new_len self.refresh_pause_list() @@ -336,8 +412,13 @@ def edit_pause_item(self, index: int): def edit_all_pause_items(self): message = self.table_model.protocol.messages[0] cur_len = message.pause - new_len, ok = QInputDialog.getInt(self, self.tr("Enter new Pause Length"), - self.tr("Pause Length:"), cur_len, 0) + new_len, ok = QInputDialog.getInt( + self, + self.tr("Enter new Pause Length"), + self.tr("Pause Length:"), + cur_len, + 0, + ) if ok: for message in self.table_model.protocol.messages: message.pause = new_len @@ -356,8 +437,12 @@ def refresh_pause_list(self): fmt_str = "Pause ({1:d}-{2:d}) <{0:d} samples ({3})>" for i, pause in enumerate(self.table_model.protocol.pauses): - sr = self.__get_modulator_of_message(self.table_model.protocol.messages[i]).sample_rate - item = fmt_str.format(pause, i + 1, i + 2, Formatter.science_time(pause / sr)) + sr = self.__get_modulator_of_message( + self.table_model.protocol.messages[i] + ).sample_rate + item = fmt_str.format( + pause, i + 1, i + 2, Formatter.science_time(pause / sr) + ) self.ui.lWPauses.addItem(item) self.refresh_estimated_time() @@ -383,7 +468,10 @@ def generate_file(self): total_samples = self.total_modulated_samples buffer = self.prepare_modulation_buffer(total_samples, show_error=False) if buffer is None: - Errors.generic_error(self.tr("File too big"), self.tr("This file would get too big to save.")) + Errors.generic_error( + self.tr("File too big"), + self.tr("This file would get too big to save."), + ) self.unsetCursor() return modulated_samples = self.modulate_data(buffer) @@ -392,7 +480,9 @@ def generate_file(self): except Exception as e: logger.exception(e) sample_rate = 1e6 - FileOperator.ask_signal_file_name_and_save("generated", modulated_samples, sample_rate=sample_rate, parent=self) + FileOperator.ask_signal_file_name_and_save( + "generated", modulated_samples, sample_rate=sample_rate, parent=self + ) except Exception as e: Errors.exception(e) self.unsetCursor() @@ -402,23 +492,27 @@ def prepare_modulation_buffer(self, total_samples: int, show_error=True) -> IQAr n = 2 if dtype == np.int8 else 4 if dtype == np.int16 else 8 memory_size_for_buffer = total_samples * n - logger.debug("Allocating {0:.2f}MB for modulated samples".format(memory_size_for_buffer / (1024 ** 2))) + logger.debug( + "Allocating {0:.2f}MB for modulated samples".format( + memory_size_for_buffer / (1024**2) + ) + ) try: # allocate it three times as we need the same amount for the sending process - IQArray(None, dtype=dtype, n=3*total_samples) + IQArray(None, dtype=dtype, n=3 * total_samples) except MemoryError: # will go into continuous mode in this case if show_error: - Errors.not_enough_ram_for_sending_precache(3*memory_size_for_buffer) + Errors.not_enough_ram_for_sending_precache(3 * memory_size_for_buffer) return None return IQArray(None, dtype=dtype, n=total_samples) def modulate_data(self, buffer: IQArray) -> IQArray: """ - + :param buffer: Buffer in which the modulated data shall be written, initialized with zeros - :return: + :return: """ self.ui.prBarGeneration.show() self.ui.prBarGeneration.setValue(0) @@ -431,7 +525,7 @@ def modulate_data(self, buffer: IQArray) -> IQArray: modulator = self.__get_modulator_of_message(message) # We do not need to modulate the pause extra, as result is already initialized with zeros modulated = modulator.modulate(start=0, data=message.encoded_bits, pause=0) - buffer[pos:pos + len(modulated)] = modulated + buffer[pos : pos + len(modulated)] = modulated pos += len(modulated) + message.pause self.modulation_msg_indices.append(pos) self.ui.prBarGeneration.setValue(i + 1) @@ -445,9 +539,16 @@ def show_fuzzing_dialog(self, label_index: int): view = self.ui.cbViewType.currentIndex() if self.label_list_model.message is not None: - msg_index = self.table_model.protocol.messages.index(self.label_list_model.message) - fdc = FuzzingDialog(protocol=self.table_model.protocol, label_index=label_index, - msg_index=msg_index, proto_view=view, parent=self) + msg_index = self.table_model.protocol.messages.index( + self.label_list_model.message + ) + fdc = FuzzingDialog( + protocol=self.table_model.protocol, + label_index=label_index, + msg_index=msg_index, + proto_view=view, + parent=self, + ) fdc.show() fdc.finished.connect(self.on_fuzzing_dialog_finished) @@ -488,7 +589,11 @@ def on_btn_fuzzing_clicked(self): @pyqtSlot() def set_fuzzing_ui_status(self): btn_was_enabled = self.ui.btnFuzz.isEnabled() - fuzz_active = any(lbl.active_fuzzing for msg in self.table_model.protocol.messages for lbl in msg.message_type) + fuzz_active = any( + lbl.active_fuzzing + for msg in self.table_model.protocol.messages + for lbl in msg.message_type + ) self.ui.btnFuzz.setEnabled(fuzz_active) if self.ui.btnFuzz.isEnabled() and not btn_was_enabled: font = self.ui.btnFuzz.font() @@ -514,7 +619,14 @@ def refresh_existing_encodings(self, encodings_from_file): update = False for msg in self.table_model.protocol.messages: - i = next((i for i, d in enumerate(encodings_from_file) if d.name == msg.decoder.name), 0) + i = next( + ( + i + for i, d in enumerate(encodings_from_file) + if d.name == msg.decoder.name + ), + 0, + ) if msg.decoder != encodings_from_file[i]: update = True msg.decoder = encodings_from_file[i] @@ -533,18 +645,25 @@ def refresh_estimated_time(self): return avg_msg_len = numpy.mean([len(msg.encoded_bits) for msg in c.messages]) - avg_samples_per_symbol = numpy.mean([m.samples_per_symbol for m in self.modulators]) + avg_samples_per_symbol = numpy.mean( + [m.samples_per_symbol for m in self.modulators] + ) avg_sample_rate = numpy.mean([m.sample_rate for m in self.modulators]) pause_samples = sum(c.pauses) nsamples = c.num_messages * avg_msg_len * avg_samples_per_symbol + pause_samples self.ui.lEstimatedTime.setText( - locale.format_string("Estimated Time: %.04f seconds", nsamples / avg_sample_rate)) + locale.format_string( + "Estimated Time: %.04f seconds", nsamples / avg_sample_rate + ) + ) @pyqtSlot(int, int, int) def create_fuzzing_label(self, msg_index: int, start: int, end: int): con = self.table_model.protocol - start, end = con.convert_range(start, end - 1, self.ui.cbViewType.currentIndex(), 0, False, msg_index) + start, end = con.convert_range( + start, end - 1, self.ui.cbViewType.currentIndex(), 0, False, msg_index + ) lbl = con.create_fuzzing_label(start, end, msg_index) self.show_fuzzing_dialog(con.protocol_labels.index(lbl)) @@ -561,8 +680,9 @@ def handle_label_selection_changed(self): except IndexError: return if label.show and self.selected_message: - start, end = self.selected_message.get_label_range(lbl=label, view=self.table_model.proto_view, - decode=False) + start, end = self.selected_message.get_label_range( + lbl=label, view=self.table_model.proto_view, decode=False + ) indx = self.table_model.index(0, int((start + end) / 2)) self.ui.tableMessages.scrollTo(indx) @@ -587,18 +707,31 @@ def on_btn_send_clicked(self): try: if modulated_data is not None: try: - dialog = SendDialog(self.project_manager, modulated_data=modulated_data, - modulation_msg_indices=self.modulation_msg_indices, parent=self) + dialog = SendDialog( + self.project_manager, + modulated_data=modulated_data, + modulation_msg_indices=self.modulation_msg_indices, + parent=self, + ) except MemoryError: # Not enough memory for device buffer so we need to create a continuous send dialog del modulated_data Errors.not_enough_ram_for_sending_precache(None) - dialog = ContinuousSendDialog(self.project_manager, - self.table_model.protocol.messages, - self.modulators, total_samples, parent=self) + dialog = ContinuousSendDialog( + self.project_manager, + self.table_model.protocol.messages, + self.modulators, + total_samples, + parent=self, + ) else: - dialog = ContinuousSendDialog(self.project_manager, self.table_model.protocol.messages, - self.modulators, total_samples, parent=self) + dialog = ContinuousSendDialog( + self.project_manager, + self.table_model.protocol.messages, + self.modulators, + total_samples, + parent=self, + ) except OSError as e: logger.exception(e) return @@ -607,7 +740,9 @@ def on_btn_send_clicked(self): dialog.close() return - dialog.device_parameters_changed.connect(self.project_manager.set_device_parameters) + dialog.device_parameters_changed.connect( + self.project_manager.set_device_parameters + ) dialog.show() dialog.graphics_view.show_full_scene(reinitialize=True) except Exception as e: @@ -616,16 +751,22 @@ def on_btn_send_clicked(self): @pyqtSlot() def on_btn_save_clicked(self): - filename = FileOperator.ask_save_file_name("profile.fuzz.xml", caption="Save fuzzing profile") + filename = FileOperator.ask_save_file_name( + "profile.fuzz.xml", caption="Save fuzzing profile" + ) if filename: - self.table_model.protocol.to_xml_file(filename, - decoders=self.project_manager.decodings, - participants=self.project_manager.participants, - modulators=self.modulators) + self.table_model.protocol.to_xml_file( + filename, + decoders=self.project_manager.decodings, + participants=self.project_manager.participants, + modulators=self.modulators, + ) @pyqtSlot() def on_btn_open_clicked(self): - dialog = FileOperator.get_open_dialog(directory_mode=False, parent=self, name_filter="fuzz") + dialog = FileOperator.get_open_dialog( + directory_mode=False, parent=self, name_filter="fuzz" + ) if dialog.exec_(): for filename in dialog.selectedFiles(): self.load_from_file(filename) @@ -661,15 +802,23 @@ def set_FZSave_button_visibility(self): @pyqtSlot() def on_btn_FZSave_clicked(self): - filename, _ = QFileDialog.getSaveFileName(self, self.tr("Choose file"), directory=FileOperator.RECENT_PATH, - filter="SUB files (*.sub);;All files (*.*)") + filename, _ = QFileDialog.getSaveFileName( + self, + self.tr("Choose file"), + directory=FileOperator.RECENT_PATH, + filter="SUB files (*.sub);;All files (*.*)", + ) if len(filename) > 0: if not filename.endswith(".sub"): - filename = filename+".sub" + filename = filename + ".sub" messages = self.table_model.protocol.messages - sample_rates = [self.__get_modulator_of_message(msg).sample_rate for msg in messages] - self.flipperzerosub_plugin.write_sub_file(filename, messages, sample_rates, self.modulators, self.project_manager) + sample_rates = [ + self.__get_modulator_of_message(msg).sample_rate for msg in messages + ] + self.flipperzerosub_plugin.write_sub_file( + filename, messages, sample_rates, self.modulators, self.project_manager + ) else: logger.debug("Filename was empty!") @@ -677,7 +826,9 @@ def on_btn_FZSave_clicked(self): def on_btn_network_sdr_clicked(self): if not self.network_sdr_plugin.is_sending: messages = self.table_model.protocol.messages - sample_rates = [self.__get_modulator_of_message(msg).sample_rate for msg in messages] + sample_rates = [ + self.__get_modulator_of_message(msg).sample_rate for msg in messages + ] self.network_sdr_plugin.start_message_sending_thread(messages, sample_rates) else: self.network_sdr_plugin.stop_sending_thread() @@ -687,7 +838,10 @@ def on_network_sdr_sending_status_changed(self, is_sending: bool): self.ui.btnNetworkSDRSend.setChecked(is_sending) self.ui.btnNetworkSDRSend.setEnabled(True) self.ui.btnNetworkSDRSend.setToolTip( - "Sending in progress" if is_sending else self.network_sdr_button_orig_tooltip) + "Sending in progress" + if is_sending + else self.network_sdr_button_orig_tooltip + ) if not is_sending: self.ui.tableMessages.clearSelection() @@ -704,9 +858,12 @@ def on_send_message_changed(self, message_index: int): def on_btn_rfcat_clicked(self): if not self.rfcat_plugin.is_sending: messages = self.table_model.protocol.messages - sample_rates = [self.__get_modulator_of_message(msg).sample_rate for msg in messages] - self.rfcat_plugin.start_message_sending_thread(messages, sample_rates, self.modulators, - self.project_manager) + sample_rates = [ + self.__get_modulator_of_message(msg).sample_rate for msg in messages + ] + self.rfcat_plugin.start_message_sending_thread( + messages, sample_rates, self.modulators, self.project_manager + ) else: self.rfcat_plugin.stop_sending_thread() diff --git a/src/urh/controller/MainController.py b/src/urh/controller/MainController.py index e1ff624ba4..01b302bbdf 100644 --- a/src/urh/controller/MainController.py +++ b/src/urh/controller/MainController.py @@ -3,7 +3,16 @@ from PyQt5.QtCore import QDir, Qt, pyqtSlot, QTimer from PyQt5.QtGui import QIcon, QCloseEvent, QKeySequence -from PyQt5.QtWidgets import QMainWindow, QUndoGroup, QActionGroup, QHeaderView, QAction, QMessageBox, QApplication, qApp +from PyQt5.QtWidgets import ( + QMainWindow, + QUndoGroup, + QActionGroup, + QHeaderView, + QAction, + QMessageBox, + QApplication, + qApp, +) from urh import settings, version from urh.controller.CompareFrameController import CompareFrameController @@ -45,24 +54,31 @@ def __init__(self, *args): self.project_save_timer = QTimer() self.project_manager = ProjectManager(self) self.plugin_manager = PluginManager() - self.signal_tab_controller = SignalTabController(self.project_manager, - parent=self.ui.tab_interpretation) + self.signal_tab_controller = SignalTabController( + self.project_manager, parent=self.ui.tab_interpretation + ) self.ui.tab_interpretation.layout().addWidget(self.signal_tab_controller) - self.compare_frame_controller = CompareFrameController(parent=self.ui.tab_protocol, - plugin_manager=self.plugin_manager, - project_manager=self.project_manager) + self.compare_frame_controller = CompareFrameController( + parent=self.ui.tab_protocol, + plugin_manager=self.plugin_manager, + project_manager=self.project_manager, + ) self.compare_frame_controller.ui.splitter.setSizes([1, 1000000]) self.ui.tab_protocol.layout().addWidget(self.compare_frame_controller) - self.generator_tab_controller = GeneratorTabController(self.compare_frame_controller, - self.project_manager, - parent=self.ui.tab_generator) + self.generator_tab_controller = GeneratorTabController( + self.compare_frame_controller, + self.project_manager, + parent=self.ui.tab_generator, + ) - self.simulator_tab_controller = SimulatorTabController(parent=self.ui.tab_simulator, - compare_frame_controller=self.compare_frame_controller, - generator_tab_controller=self.generator_tab_controller, - project_manager=self.project_manager) + self.simulator_tab_controller = SimulatorTabController( + parent=self.ui.tab_simulator, + compare_frame_controller=self.compare_frame_controller, + generator_tab_controller=self.generator_tab_controller, + project_manager=self.project_manager, + ) self.ui.tab_simulator.layout().addWidget(self.simulator_tab_controller) @@ -73,15 +89,21 @@ def __init__(self, *args): self.undo_group.setActiveStack(self.signal_tab_controller.signal_undo_stack) self.cancel_action = QAction(self.tr("Cancel"), self) - self.cancel_action.setShortcut(QKeySequence.Cancel if hasattr(QKeySequence, "Cancel") else "Esc") + self.cancel_action.setShortcut( + QKeySequence.Cancel if hasattr(QKeySequence, "Cancel") else "Esc" + ) self.cancel_action.triggered.connect(self.on_cancel_triggered) self.cancel_action.setShortcutContext(Qt.WidgetWithChildrenShortcut) self.cancel_action.setIcon(QIcon.fromTheme("dialog-cancel")) self.addAction(self.cancel_action) - self.ui.actionAuto_detect_new_signals.setChecked(settings.read("auto_detect_new_signals", True, bool)) + self.ui.actionAuto_detect_new_signals.setChecked( + settings.read("auto_detect_new_signals", True, bool) + ) - self.participant_legend_model = ParticipantLegendListModel(self.project_manager.participants) + self.participant_legend_model = ParticipantLegendListModel( + self.project_manager.participants + ) self.ui.listViewParticipants.setModel(self.participant_legend_model) gtc = self.generator_tab_controller @@ -102,7 +124,9 @@ def __init__(self, *args): noise_threshold_setting = settings.read("default_noise_threshold", "automatic") noise_threshold_group = QActionGroup(self) self.ui.actionAutomaticNoiseThreshold.setActionGroup(noise_threshold_group) - self.ui.actionAutomaticNoiseThreshold.setChecked(noise_threshold_setting == "automatic") + self.ui.actionAutomaticNoiseThreshold.setChecked( + noise_threshold_setting == "automatic" + ) self.ui.action1NoiseThreshold.setActionGroup(noise_threshold_group) self.ui.action1NoiseThreshold.setChecked(noise_threshold_setting == "1") self.ui.action5NoiseThreshold.setActionGroup(noise_threshold_group) @@ -125,7 +149,9 @@ def __init__(self, *args): self.file_proxy_model.setSourceModel(self.filemodel) self.ui.fileTree.setModel(self.file_proxy_model) - self.ui.fileTree.setRootIndex(self.file_proxy_model.mapFromSource(self.filemodel.index(path))) + self.ui.fileTree.setRootIndex( + self.file_proxy_model.mapFromSource(self.filemodel.index(path)) + ) self.ui.fileTree.setToolTip(path) self.ui.fileTree.header().setSectionResizeMode(0, QHeaderView.ResizeToContents) self.ui.fileTree.header().setSectionResizeMode(1, QHeaderView.Stretch) @@ -146,24 +172,33 @@ def __init__(self, *args): self.ui.menuEdit.insertAction(self.ui.actionDecoding, redo_action) self.ui.menuEdit.insertSeparator(self.ui.actionDecoding) - self.ui.actionAbout_Qt.setIcon(QIcon(":/qt-project.org/qmessagebox/images/qtlogo-64.png")) + self.ui.actionAbout_Qt.setIcon( + QIcon(":/qt-project.org/qmessagebox/images/qtlogo-64.png") + ) self.__set_non_project_warning_visibility() self.ui.splitter.setSizes([0, 1]) self.refresh_main_menu() - self.apply_default_view(settings.read('default_view', type=int)) - self.project_save_timer.start(ProjectManager.AUTOSAVE_INTERVAL_MINUTES * 60 * 1000) + self.apply_default_view(settings.read("default_view", type=int)) + self.project_save_timer.start( + ProjectManager.AUTOSAVE_INTERVAL_MINUTES * 60 * 1000 + ) self.ui.actionProject_settings.setVisible(False) self.ui.actionSave_project.setVisible(False) self.ui.actionClose_project.setVisible(False) - self.restoreGeometry(settings.read("{}/geometry".format(self.__class__.__name__), type=bytes)) + self.restoreGeometry( + settings.read("{}/geometry".format(self.__class__.__name__), type=bytes) + ) def __set_non_project_warning_visibility(self): - show = settings.read("show_non_project_warning", True, bool) and not self.project_manager.project_loaded + show = ( + settings.read("show_non_project_warning", True, bool) + and not self.project_manager.project_loaded + ) self.ui.labelNonProjectMode.setVisible(show) def create_connects(self): @@ -173,78 +208,149 @@ def create_connects(self): self.ui.menuEdit.aboutToShow.connect(self.on_edit_menu_about_to_show) - self.ui.actionNew_Project.triggered.connect(self.on_new_project_action_triggered) + self.ui.actionNew_Project.triggered.connect( + self.on_new_project_action_triggered + ) self.ui.actionNew_Project.setShortcut(QKeySequence.New) - self.ui.actionProject_settings.triggered.connect(self.on_project_settings_action_triggered) + self.ui.actionProject_settings.triggered.connect( + self.on_project_settings_action_triggered + ) self.ui.actionSave_project.triggered.connect(self.save_project) self.ui.actionClose_project.triggered.connect(self.close_project) - self.ui.actionAbout_AutomaticHacker.triggered.connect(self.on_show_about_clicked) - self.ui.actionRecord.triggered.connect(self.on_show_record_dialog_action_triggered) - - self.ui.actionFullscreen_mode.triggered.connect(self.on_fullscreen_action_triggered) - self.ui.actionSaveAllSignals.triggered.connect(self.signal_tab_controller.save_all) - self.ui.actionCloseAllFiles.triggered.connect(self.on_close_all_files_action_triggered) + self.ui.actionAbout_AutomaticHacker.triggered.connect( + self.on_show_about_clicked + ) + self.ui.actionRecord.triggered.connect( + self.on_show_record_dialog_action_triggered + ) + + self.ui.actionFullscreen_mode.triggered.connect( + self.on_fullscreen_action_triggered + ) + self.ui.actionSaveAllSignals.triggered.connect( + self.signal_tab_controller.save_all + ) + self.ui.actionCloseAllFiles.triggered.connect( + self.on_close_all_files_action_triggered + ) self.ui.actionOpen.triggered.connect(self.on_open_file_action_triggered) - self.ui.actionOpen_directory.triggered.connect(self.on_open_directory_action_triggered) + self.ui.actionOpen_directory.triggered.connect( + self.on_open_directory_action_triggered + ) self.ui.actionDecoding.triggered.connect(self.on_show_decoding_dialog_triggered) - self.ui.actionSpectrum_Analyzer.triggered.connect(self.on_show_spectrum_dialog_action_triggered) - self.ui.actionOptions.triggered.connect(self.show_options_dialog_action_triggered) + self.ui.actionSpectrum_Analyzer.triggered.connect( + self.on_show_spectrum_dialog_action_triggered + ) + self.ui.actionOptions.triggered.connect( + self.show_options_dialog_action_triggered + ) self.ui.actionSniff_protocol.triggered.connect(self.show_proto_sniff_dialog) self.ui.actionAbout_Qt.triggered.connect(QApplication.instance().aboutQt) - self.ui.actionSamples_from_csv.triggered.connect(self.on_import_samples_from_csv_action_triggered) - self.ui.actionAuto_detect_new_signals.triggered.connect(self.on_auto_detect_new_signals_action_triggered) - - self.ui.actionAutomaticNoiseThreshold.triggered.connect(self.on_action_automatic_noise_threshold_triggered) - self.ui.action1NoiseThreshold.triggered.connect(self.on_action_1_noise_threshold_triggered) - self.ui.action5NoiseThreshold.triggered.connect(self.on_action_5_noise_threshold_triggered) - self.ui.action10NoiseThreshold.triggered.connect(self.on_action_10_noise_threshold_triggered) - self.ui.action100NoiseThreshold.triggered.connect(self.on_action_100_noise_threshold_triggered) + self.ui.actionSamples_from_csv.triggered.connect( + self.on_import_samples_from_csv_action_triggered + ) + self.ui.actionAuto_detect_new_signals.triggered.connect( + self.on_auto_detect_new_signals_action_triggered + ) + + self.ui.actionAutomaticNoiseThreshold.triggered.connect( + self.on_action_automatic_noise_threshold_triggered + ) + self.ui.action1NoiseThreshold.triggered.connect( + self.on_action_1_noise_threshold_triggered + ) + self.ui.action5NoiseThreshold.triggered.connect( + self.on_action_5_noise_threshold_triggered + ) + self.ui.action10NoiseThreshold.triggered.connect( + self.on_action_10_noise_threshold_triggered + ) + self.ui.action100NoiseThreshold.triggered.connect( + self.on_action_100_noise_threshold_triggered + ) self.ui.btnFileTreeGoUp.clicked.connect(self.on_btn_file_tree_go_up_clicked) - self.ui.fileTree.directory_open_wanted.connect(self.project_manager.set_project_folder) + self.ui.fileTree.directory_open_wanted.connect( + self.project_manager.set_project_folder + ) self.signal_tab_controller.frame_closed.connect(self.close_signal_frame) self.signal_tab_controller.signal_created.connect(self.on_signal_created) - self.signal_tab_controller.ui.scrollArea.files_dropped.connect(self.on_files_dropped) + self.signal_tab_controller.ui.scrollArea.files_dropped.connect( + self.on_files_dropped + ) self.signal_tab_controller.files_dropped.connect(self.on_files_dropped) self.signal_tab_controller.frame_was_dropped.connect(self.set_frame_numbers) - self.simulator_tab_controller.open_in_analysis_requested.connect(self.on_simulator_open_in_analysis_requested) - self.simulator_tab_controller.rx_file_saved.connect(self.adjust_for_current_file) + self.simulator_tab_controller.open_in_analysis_requested.connect( + self.on_simulator_open_in_analysis_requested + ) + self.simulator_tab_controller.rx_file_saved.connect( + self.adjust_for_current_file + ) self.compare_frame_controller.show_interpretation_clicked.connect( - self.show_protocol_selection_in_interpretation) + self.show_protocol_selection_in_interpretation + ) self.compare_frame_controller.files_dropped.connect(self.on_files_dropped) - self.compare_frame_controller.show_decoding_clicked.connect(self.on_show_decoding_dialog_triggered) + self.compare_frame_controller.show_decoding_clicked.connect( + self.on_show_decoding_dialog_triggered + ) self.compare_frame_controller.ui.treeViewProtocols.files_dropped_on_group.connect( - self.on_files_dropped_on_group) - self.compare_frame_controller.participant_changed.connect(self.signal_tab_controller.on_participant_changed) - self.compare_frame_controller.ui.treeViewProtocols.close_wanted.connect(self.on_cfc_close_wanted) + self.on_files_dropped_on_group + ) + self.compare_frame_controller.participant_changed.connect( + self.signal_tab_controller.on_participant_changed + ) + self.compare_frame_controller.ui.treeViewProtocols.close_wanted.connect( + self.on_cfc_close_wanted + ) self.compare_frame_controller.show_config_field_types_triggered.connect( - self.on_show_field_types_config_action_triggered) + self.on_show_field_types_config_action_triggered + ) - self.compare_frame_controller.load_protocol_clicked.connect(self.on_compare_frame_controller_load_protocol_clicked) - self.compare_frame_controller.ui.listViewParticipants.doubleClicked.connect(self.on_project_settings_action_triggered) + self.compare_frame_controller.load_protocol_clicked.connect( + self.on_compare_frame_controller_load_protocol_clicked + ) + self.compare_frame_controller.ui.listViewParticipants.doubleClicked.connect( + self.on_project_settings_action_triggered + ) - self.ui.lnEdtTreeFilter.textChanged.connect(self.on_file_tree_filter_text_changed) + self.ui.lnEdtTreeFilter.textChanged.connect( + self.on_file_tree_filter_text_changed + ) self.ui.tabWidget.currentChanged.connect(self.on_selected_tab_changed) self.project_save_timer.timeout.connect(self.save_project) - self.ui.actionConvert_Folder_to_Project.triggered.connect(self.project_manager.convert_folder_to_project) - self.project_manager.project_loaded_status_changed.connect(self.on_project_loaded_status_changed) + self.ui.actionConvert_Folder_to_Project.triggered.connect( + self.project_manager.convert_folder_to_project + ) + self.project_manager.project_loaded_status_changed.connect( + self.on_project_loaded_status_changed + ) self.project_manager.project_updated.connect(self.on_project_updated) - self.ui.textEditProjectDescription.textChanged.connect(self.on_text_edit_project_description_text_changed) - self.ui.tabWidget_Project.tabBarDoubleClicked.connect(self.on_project_tab_bar_double_clicked) + self.ui.textEditProjectDescription.textChanged.connect( + self.on_text_edit_project_description_text_changed + ) + self.ui.tabWidget_Project.tabBarDoubleClicked.connect( + self.on_project_tab_bar_double_clicked + ) - self.ui.listViewParticipants.doubleClicked.connect(self.on_project_settings_action_triggered) + self.ui.listViewParticipants.doubleClicked.connect( + self.on_project_settings_action_triggered + ) - self.ui.actionShowFileTree.triggered.connect(self.on_action_show_filetree_triggered) + self.ui.actionShowFileTree.triggered.connect( + self.on_action_show_filetree_triggered + ) self.ui.actionShowFileTree.setShortcut(QKeySequence("F10")) - self.ui.labelNonProjectMode.linkActivated.connect(self.on_label_non_project_mode_link_activated) + self.ui.labelNonProjectMode.linkActivated.connect( + self.on_label_non_project_mode_link_activated + ) self.ui.menuFile.addSeparator() for i in range(settings.MAX_RECENT_FILE_NR): @@ -287,9 +393,13 @@ def add_simulator_profile(self, filename): def add_signalfile(self, filename: str, group_id=0, enforce_sample_rate=None): if not os.path.exists(filename): - QMessageBox.critical(self, self.tr("File not Found"), - self.tr("The file {0} could not be found. Was it moved or renamed?").format( - filename)) + QMessageBox.critical( + self, + self.tr("File not Found"), + self.tr( + "The file {0} could not be found. Was it moved or renamed?" + ).format(filename), + ) return sig_name = os.path.splitext(os.path.basename(filename))[0] @@ -315,7 +425,11 @@ def add_signal(self, signal, group_id=0, index=-1): signal.blockSignals(True) has_entry = self.project_manager.read_project_file_for_signal(signal) - if self.ui.actionAuto_detect_new_signals.isChecked() and not has_entry and not signal.changed: + if ( + self.ui.actionAuto_detect_new_signals.isChecked() + and not has_entry + and not signal.changed + ): sig_frame.ui.stackedWidget.setCurrentWidget(sig_frame.ui.pageLoading) qApp.processEvents() if not signal.already_demodulated: @@ -351,7 +465,9 @@ def close_protocol(self, protocol): def close_signal_frame(self, signal_frame: SignalFrame): try: - self.project_manager.write_signal_information_to_project_file(signal_frame.signal) + self.project_manager.write_signal_information_to_project_file( + signal_frame.signal + ) try: proto = self.signal_protocol_dict[signal_frame] except KeyError: @@ -361,9 +477,14 @@ def close_signal_frame(self, signal_frame: SignalFrame): self.close_protocol(proto) del self.signal_protocol_dict[signal_frame] - if self.signal_tab_controller.ui.scrlAreaSignals.minimumHeight() > signal_frame.height(): + if ( + self.signal_tab_controller.ui.scrlAreaSignals.minimumHeight() + > signal_frame.height() + ): self.signal_tab_controller.ui.scrlAreaSignals.setMinimumHeight( - self.signal_tab_controller.ui.scrlAreaSignals.minimumHeight() - signal_frame.height()) + self.signal_tab_controller.ui.scrlAreaSignals.minimumHeight() + - signal_frame.height() + ) if signal_frame.signal is not None: # Non-Empty Frame (when a signal and not a protocol is opened) @@ -398,20 +519,35 @@ def add_files(self, filepaths, group_id=0, enforce_sample_rate=None): FileOperator.RECENT_PATH = os.path.split(filename)[0] if filename.endswith(".complex"): - self.add_signalfile(filename, group_id, enforce_sample_rate=enforce_sample_rate) + self.add_signalfile( + filename, group_id, enforce_sample_rate=enforce_sample_rate + ) elif filename.endswith(".coco"): - self.add_signalfile(filename, group_id, enforce_sample_rate=enforce_sample_rate) - elif filename.endswith(".proto") or filename.endswith(".proto.xml") or filename.endswith(".bin"): + self.add_signalfile( + filename, group_id, enforce_sample_rate=enforce_sample_rate + ) + elif ( + filename.endswith(".proto") + or filename.endswith(".proto.xml") + or filename.endswith(".bin") + ): self.add_protocol_file(filename) elif filename.endswith(".wav"): try: import wave + w = wave.open(filename) w.close() except wave.Error as e: - Errors.generic_error("Unsupported WAV type", "Only uncompressed WAVs (PCM) are supported.", str(e)) + Errors.generic_error( + "Unsupported WAV type", + "Only uncompressed WAVs (PCM) are supported.", + str(e), + ) continue - self.add_signalfile(filename, group_id, enforce_sample_rate=enforce_sample_rate) + self.add_signalfile( + filename, group_id, enforce_sample_rate=enforce_sample_rate + ) elif filename.endswith(".fuzz") or filename.endswith(".fuzz.xml"): self.add_fuzz_profile(filename) elif filename.endswith(".sim") or filename.endswith(".sim.xml"): @@ -424,7 +560,9 @@ def add_files(self, filepaths, group_id=0, enforce_sample_rate=None): elif os.path.basename(filename) == settings.PROJECT_FILE: self.project_manager.set_project_folder(os.path.split(filename)[0]) else: - self.add_signalfile(filename, group_id, enforce_sample_rate=enforce_sample_rate) + self.add_signalfile( + filename, group_id, enforce_sample_rate=enforce_sample_rate + ) if self.project_manager.project_file is None: self.adjust_for_current_file(filename) @@ -436,7 +574,9 @@ def set_frame_numbers(self): def closeEvent(self, event: QCloseEvent): self.save_project() - settings.write("{}/geometry".format(self.__class__.__name__), self.saveGeometry()) + settings.write( + "{}/geometry".format(self.__class__.__name__), self.saveGeometry() + ) super().closeEvent(event) def close_all_files(self): @@ -472,14 +612,18 @@ def apply_default_view(self, view_index: int): sig_frame.ui.cbProtoView.setCurrentIndex(view_index) def show_project_settings(self): - pdc = ProjectDialog(new_project=False, project_manager=self.project_manager, parent=self) + pdc = ProjectDialog( + new_project=False, project_manager=self.project_manager, parent=self + ) pdc.finished.connect(self.on_project_dialog_finished) pdc.show() def collapse_project_tab_bar(self): self.ui.tabParticipants.hide() self.ui.tabDescription.hide() - self.ui.tabWidget_Project.setMaximumHeight(self.ui.tabWidget_Project.tabBar().height()) + self.ui.tabWidget_Project.setMaximumHeight( + self.ui.tabWidget_Project.tabBar().height() + ) def expand_project_tab_bar(self): self.ui.tabDescription.show() @@ -487,7 +631,9 @@ def expand_project_tab_bar(self): self.ui.tabWidget_Project.setMaximumHeight(9000) def save_project(self): - self.project_manager.save_project(simulator_config=self.simulator_tab_controller.simulator_config) + self.project_manager.save_project( + simulator_config=self.simulator_tab_controller.simulator_config + ) def close_project(self): self.save_project() @@ -499,7 +645,9 @@ def close_project(self): self.participant_legend_model.update() self.filemodel.setRootPath(QDir.homePath()) - self.ui.fileTree.setRootIndex(self.file_proxy_model.mapFromSource(self.filemodel.index(QDir.homePath()))) + self.ui.fileTree.setRootIndex( + self.file_proxy_model.mapFromSource(self.filemodel.index(QDir.homePath())) + ) self.hide_file_tree() self.project_manager.project_path = "" @@ -533,10 +681,16 @@ def adjust_for_current_file(self, file_path): file_path = copy.copy(FileOperator.archives[file_path]) recent_file_paths = settings.read("recentFiles", [], list) - recent_file_paths = [] if recent_file_paths is None else recent_file_paths # check None for OSX - recent_file_paths = [p for p in recent_file_paths if p != file_path and p is not None and os.path.exists(p)] + recent_file_paths = ( + [] if recent_file_paths is None else recent_file_paths + ) # check None for OSX + recent_file_paths = [ + p + for p in recent_file_paths + if p != file_path and p is not None and os.path.exists(p) + ] recent_file_paths.insert(0, file_path) - recent_file_paths = recent_file_paths[:settings.MAX_RECENT_FILE_NR] + recent_file_paths = recent_file_paths[: settings.MAX_RECENT_FILE_NR] self.init_recent_file_action_list(recent_file_paths) @@ -580,7 +734,9 @@ def on_open_recent_action_triggered(self): self.project_manager.set_project_folder(action.data()) elif os.path.isfile(action.data()): self.setCursor(Qt.WaitCursor) - self.add_files(FileOperator.uncompress_archives([action.data()], QDir.tempPath())) + self.add_files( + FileOperator.uncompress_archives([action.data()], QDir.tempPath()) + ) self.unsetCursor() except Exception as e: Errors.exception(e) @@ -588,17 +744,21 @@ def on_open_recent_action_triggered(self): @pyqtSlot() def on_show_about_clicked(self): - descr = "

Universal Radio Hacker

Version: {0}
" \ - "GitHub: https://github.com/jopohl/urh

" \ - "Creators:".format(version.VERSION) + descr = ( + "

Universal Radio Hacker

Version: {0}
" + "GitHub: https://github.com/jopohl/urh

" + "Creators:".format(version.VERSION) + ) QMessageBox.about(self, self.tr("About"), self.tr(descr)) @pyqtSlot(int, int, int, int) - def show_protocol_selection_in_interpretation(self, start_message, start, end_message, end): + def show_protocol_selection_in_interpretation( + self, start_message, start, end_message, end + ): try: cfc = self.compare_frame_controller msg_total = 0 @@ -608,20 +768,37 @@ def show_protocol_selection_in_interpretation(self, start_message, start, end_me continue n = protocol.num_messages view_type = cfc.ui.cbProtoView.currentIndex() - messages = [i - msg_total for i in range(msg_total, msg_total + n) if start_message <= i <= end_message] + messages = [ + i - msg_total + for i in range(msg_total, msg_total + n) + if start_message <= i <= end_message + ] if len(messages) > 0: try: - signal_frame = next((sf for sf, pf in self.signal_protocol_dict.items() if pf == protocol)) + signal_frame = next( + ( + sf + for sf, pf in self.signal_protocol_dict.items() + if pf == protocol + ) + ) except StopIteration: - QMessageBox.critical(self, self.tr("Error"), - self.tr("Could not find corresponding signal frame.")) + QMessageBox.critical( + self, + self.tr("Error"), + self.tr("Could not find corresponding signal frame."), + ) return - signal_frame.set_roi_from_protocol_analysis(min(messages), start, max(messages), end + 1, view_type) + signal_frame.set_roi_from_protocol_analysis( + min(messages), start, max(messages), end + 1, view_type + ) last_sig_frame = signal_frame msg_total += n focus_frame = last_sig_frame if last_sig_frame is not None: - self.signal_tab_controller.ui.scrollArea.ensureWidgetVisible(last_sig_frame, 0, 0) + self.signal_tab_controller.ui.scrollArea.ensureWidgetVisible( + last_sig_frame, 0, 0 + ) QApplication.instance().processEvents() self.ui.tabWidget.setCurrentIndex(0) @@ -641,8 +818,11 @@ def on_file_tree_filter_text_changed(self, text: str): def on_show_decoding_dialog_triggered(self): signals = [sf.signal for sf in self.signal_tab_controller.signal_frames] decoding_controller = DecoderDialog( - self.compare_frame_controller.decodings, signals, - self.project_manager, parent=self) + self.compare_frame_controller.decodings, + signals, + self.project_manager, + parent=self, + ) decoding_controller.finished.connect(self.update_decodings) decoding_controller.show() decoding_controller.decoder_update() @@ -653,32 +833,46 @@ def update_decodings(self): self.compare_frame_controller.fill_decoding_combobox() self.compare_frame_controller.refresh_existing_encodings() - self.generator_tab_controller.refresh_existing_encodings(self.compare_frame_controller.decodings) + self.generator_tab_controller.refresh_existing_encodings( + self.compare_frame_controller.decodings + ) @pyqtSlot(int) def on_selected_tab_changed(self, index: int): if index == 0: self.undo_group.setActiveStack(self.signal_tab_controller.signal_undo_stack) elif index == 1: - self.undo_group.setActiveStack(self.compare_frame_controller.protocol_undo_stack) + self.undo_group.setActiveStack( + self.compare_frame_controller.protocol_undo_stack + ) self.compare_frame_controller.ui.tblViewProtocol.resize_columns() self.compare_frame_controller.ui.tblViewProtocol.resize_vertical_header() - h = max(self.compare_frame_controller.ui.btnSaveProto.height(), - self.generator_tab_controller.ui.btnSave.height()) + h = max( + self.compare_frame_controller.ui.btnSaveProto.height(), + self.generator_tab_controller.ui.btnSave.height(), + ) self.compare_frame_controller.ui.btnSaveProto.setMinimumHeight(h) th = self.compare_frame_controller.ui.tabWidget.tabBar().height() for i in range(self.compare_frame_controller.ui.tabWidget.count()): - self.compare_frame_controller.ui.tabWidget.widget(i).layout().setContentsMargins(0, 7 + h - th, 0, 0) + self.compare_frame_controller.ui.tabWidget.widget( + i + ).layout().setContentsMargins(0, 7 + h - th, 0, 0) elif index == 2: - self.undo_group.setActiveStack(self.generator_tab_controller.generator_undo_stack) - h = max(self.compare_frame_controller.ui.btnSaveProto.height(), - self.generator_tab_controller.ui.btnSave.height()) + self.undo_group.setActiveStack( + self.generator_tab_controller.generator_undo_stack + ) + h = max( + self.compare_frame_controller.ui.btnSaveProto.height(), + self.generator_tab_controller.ui.btnSave.height(), + ) self.generator_tab_controller.ui.btnSave.setMinimumHeight(h) th = self.generator_tab_controller.ui.tabWidget.tabBar().height() for i in range(self.generator_tab_controller.ui.tabWidget.count()): - self.generator_tab_controller.ui.tabWidget.widget(i).layout().setContentsMargins(0, 7 + h - th, 0, 0) + self.generator_tab_controller.ui.tabWidget.widget( + i + ).layout().setContentsMargins(0, 7 + h - th, 0, 0) # Modulators may got changed from Simulator Dialog self.generator_tab_controller.refresh_modulators() # Signals may got reordered in analysis @@ -705,11 +899,21 @@ def on_show_record_dialog_action_triggered(self): def create_protocol_sniff_dialog(self, testing_mode=False): pm = self.project_manager - signal = next((proto.signal for proto in self.compare_frame_controller.protocol_list), None) - signals = [f.signal for f in self.signal_tab_controller.signal_frames if f.signal] - - psd = ProtocolSniffDialog(project_manager=pm, signal=signal, signals=signals, - testing_mode=testing_mode, parent=self) + signal = next( + (proto.signal for proto in self.compare_frame_controller.protocol_list), + None, + ) + signals = [ + f.signal for f in self.signal_tab_controller.signal_frames if f.signal + ] + + psd = ProtocolSniffDialog( + project_manager=pm, + signal=signal, + signals=signals, + testing_mode=testing_mode, + parent=self, + ) if psd.has_empty_device_list: Errors.no_device() @@ -717,7 +921,9 @@ def create_protocol_sniff_dialog(self, testing_mode=False): return None else: psd.device_parameters_changed.connect(pm.set_device_parameters) - psd.protocol_accepted.connect(self.compare_frame_controller.add_sniffed_protocol_messages) + psd.protocol_accepted.connect( + self.compare_frame_controller.add_sniffed_protocol_messages + ) return psd @pyqtSlot() @@ -791,7 +997,9 @@ def on_open_directory_action_triggered(self): self.show_open_dialog(directory=True) def show_open_dialog(self, directory=False): - dialog = FileOperator.get_open_dialog(directory_mode=directory, parent=self, name_filter="full") + dialog = FileOperator.get_open_dialog( + directory_mode=directory, parent=self, name_filter="full" + ) if dialog.exec_(): try: file_names = dialog.selectedFiles() @@ -805,7 +1013,9 @@ def show_open_dialog(self, directory=False): self.project_manager.set_project_folder(folder) else: self.setCursor(Qt.WaitCursor) - file_names = FileOperator.uncompress_archives(file_names, QDir.tempPath()) + file_names = FileOperator.uncompress_archives( + file_names, QDir.tempPath() + ) self.add_files(file_names) self.unsetCursor() except Exception as e: @@ -832,21 +1042,31 @@ def on_files_dropped_on_group(self, files, group_id: int): self.__add_urls_to_group(files, group_id=group_id) def __add_urls_to_group(self, file_urls, group_id=0): - local_files = [file_url.toLocalFile() for file_url in file_urls if file_url.isLocalFile()] + local_files = [ + file_url.toLocalFile() for file_url in file_urls if file_url.isLocalFile() + ] if len(local_files) > 0: self.setCursor(Qt.WaitCursor) - self.add_files(FileOperator.uncompress_archives(local_files, QDir.tempPath()), group_id=group_id) + self.add_files( + FileOperator.uncompress_archives(local_files, QDir.tempPath()), + group_id=group_id, + ) self.unsetCursor() @pyqtSlot(list) def on_cfc_close_wanted(self, protocols: list): - frame_protos = {sframe: protocol for sframe, protocol in self.signal_protocol_dict.items() if - protocol in protocols} + frame_protos = { + sframe: protocol + for sframe, protocol in self.signal_protocol_dict.items() + if protocol in protocols + } for frame in frame_protos: self.close_signal_frame(frame) - for proto in (proto for proto in protocols if proto not in frame_protos.values()): + for proto in ( + proto for proto in protocols if proto not in frame_protos.values() + ): # close protocols without associated signal frame self.close_protocol(proto) @@ -870,7 +1090,9 @@ def on_options_changed(self, changed_options: dict): self.generator_tab_controller.set_FZSave_button_visibility() if "num_sending_repeats" in changed_options: - self.project_manager.device_conf["num_sending_repeats"] = changed_options["num_sending_repeats"] + self.project_manager.device_conf["num_sending_repeats"] = changed_options[ + "num_sending_repeats" + ] if "default_view" in changed_options: self.apply_default_view(int(changed_options["default_view"])) @@ -880,7 +1102,9 @@ def on_options_changed(self, changed_options: dict): @pyqtSlot() def on_text_edit_project_description_text_changed(self): - self.project_manager.description = self.ui.textEditProjectDescription.toPlainText() + self.project_manager.description = ( + self.ui.textEditProjectDescription.toPlainText() + ) @pyqtSlot() def on_btn_file_tree_go_up_clicked(self): @@ -888,7 +1112,9 @@ def on_btn_file_tree_go_up_clicked(self): if cur_dir.cdUp(): path = cur_dir.path() self.filemodel.setRootPath(path) - self.ui.fileTree.setRootIndex(self.file_proxy_model.mapFromSource(self.filemodel.index(path))) + self.ui.fileTree.setRootIndex( + self.file_proxy_model.mapFromSource(self.filemodel.index(path)) + ) @pyqtSlot(int, Signal) def on_signal_created(self, index: int, signal: Signal): @@ -910,7 +1136,9 @@ def on_auto_detect_new_signals_action_triggered(self, checked: bool): def __import_csv(self, file_name, group_id=0): def on_data_imported(complex_file, sample_rate): sample_rate = None if sample_rate == 0 else sample_rate - self.add_files([complex_file], group_id=group_id, enforce_sample_rate=sample_rate) + self.add_files( + [complex_file], group_id=group_id, enforce_sample_rate=sample_rate + ) dialog = CSVImportDialog(file_name, parent=self) dialog.data_imported.connect(on_data_imported) @@ -934,7 +1162,9 @@ def on_project_loaded_status_changed(self, project_loaded: bool): @pyqtSlot() def on_compare_frame_controller_load_protocol_clicked(self): - dialog = FileOperator.get_open_dialog(directory_mode=False, parent=self, name_filter="proto") + dialog = FileOperator.get_open_dialog( + directory_mode=False, parent=self, name_filter="proto" + ) if dialog.exec_(): for filename in dialog.selectedFiles(): self.add_protocol_file(filename) diff --git a/src/urh/controller/SignalTabController.py b/src/urh/controller/SignalTabController.py index 44b8cf9222..f0aefdce94 100644 --- a/src/urh/controller/SignalTabController.py +++ b/src/urh/controller/SignalTabController.py @@ -26,8 +26,11 @@ def signal_frames(self): :rtype: list of SignalFrame """ splitter = self.ui.splitter - return [splitter.widget(i) for i in range(splitter.count()) - if isinstance(splitter.widget(i), SignalFrame)] + return [ + splitter.widget(i) + for i in range(splitter.count()) + if isinstance(splitter.widget(i), SignalFrame) + ] @property def signal_undo_stack(self): @@ -52,12 +55,14 @@ def __init__(self, project_manager, parent=None): def on_files_dropped(self, files): self.files_dropped.emit(files) - def close_frame(self, frame:SignalFrame): + def close_frame(self, frame: SignalFrame): self.frame_closed.emit(frame) def add_signal_frame(self, proto_analyzer, index=-1): self.__set_getting_started_status(False) - sig_frame = SignalFrame(proto_analyzer, self.undo_stack, self.project_manager, parent=self) + sig_frame = SignalFrame( + proto_analyzer, self.undo_stack, self.project_manager, parent=self + ) sframes = self.signal_frames if len(proto_analyzer.signal.filename) == 0: @@ -67,12 +72,16 @@ def add_signal_frame(self, proto_analyzer, index=-1): self.__create_connects_for_signal_frame(signal_frame=sig_frame) sig_frame.signal_created.connect(self.emit_signal_created) sig_frame.not_show_again_changed.connect(self.not_show_again_changed.emit) - sig_frame.ui.lineEditSignalName.setToolTip(self.tr("Sourcefile: ") + proto_analyzer.signal.filename) + sig_frame.ui.lineEditSignalName.setToolTip( + self.tr("Sourcefile: ") + proto_analyzer.signal.filename + ) sig_frame.apply_to_all_clicked.connect(self.on_apply_to_all_clicked) prev_signal_frame = sframes[-1] if len(sframes) > 0 else None if prev_signal_frame is not None and hasattr(prev_signal_frame, "ui"): - sig_frame.ui.cbProtoView.setCurrentIndex(prev_signal_frame.ui.cbProtoView.currentIndex()) + sig_frame.ui.cbProtoView.setCurrentIndex( + prev_signal_frame.ui.cbProtoView.currentIndex() + ) sig_frame.blockSignals(True) @@ -80,15 +89,19 @@ def add_signal_frame(self, proto_analyzer, index=-1): self.ui.splitter.insertWidget(index, sig_frame) sig_frame.blockSignals(False) - default_view = settings.read('default_view', 0, int) + default_view = settings.read("default_view", 0, int) sig_frame.ui.cbProtoView.setCurrentIndex(default_view) return sig_frame def add_empty_frame(self, filename: str, proto): self.__set_getting_started_status(False) - sig_frame = SignalFrame(proto_analyzer=proto, undo_stack=self.undo_stack, project_manager=self.project_manager, - parent=self) + sig_frame = SignalFrame( + proto_analyzer=proto, + undo_stack=self.undo_stack, + project_manager=self.project_manager, + parent=self, + ) sig_frame.ui.lineEditSignalName.setText(filename) self.__create_connects_for_signal_frame(signal_frame=sig_frame) @@ -110,7 +123,7 @@ def __set_getting_started_status(self, getting_started: bool): self.ui.splitter.addWidget(w) def __create_connects_for_signal_frame(self, signal_frame: SignalFrame): - signal_frame.hold_shift = settings.read('hold_shift_to_drag', True, type=bool) + signal_frame.hold_shift = settings.read("hold_shift_to_drag", True, type=bool) signal_frame.drag_started.connect(self.frame_dragged) signal_frame.frame_dropped.connect(self.frame_dropped) signal_frame.files_dropped.connect(self.on_files_dropped) @@ -126,14 +139,17 @@ def save_all(self): return try: - not_show = settings.read('not_show_save_dialog', False, type=bool) + not_show = settings.read("not_show_save_dialog", False, type=bool) except TypeError: not_show = False if not not_show: cb = QCheckBox("Don't ask me again.") - msg_box = QMessageBox(QMessageBox.Question, self.tr("Confirm saving all signals"), - self.tr("All changed signal files will be overwritten. OK?")) + msg_box = QMessageBox( + QMessageBox.Question, + self.tr("Confirm saving all signals"), + self.tr("All changed signal files will be overwritten. OK?"), + ) msg_box.addButton(QMessageBox.Yes) msg_box.addButton(QMessageBox.No) msg_box.setCheckBox(cb) @@ -179,7 +195,9 @@ def on_apply_to_all_clicked(self, signal: Signal): proto_needs_update = True if frame.signal.noise_threshold != signal.noise_threshold: - frame.signal.noise_threshold_relative = signal.noise_threshold_relative + frame.signal.noise_threshold_relative = ( + signal.noise_threshold_relative + ) proto_needs_update = True if frame.signal.samples_per_symbol != signal.samples_per_symbol: diff --git a/src/urh/controller/SimulatorTabController.py b/src/urh/controller/SimulatorTabController.py index 1ec7f07ca7..758ecbda5c 100644 --- a/src/urh/controller/SimulatorTabController.py +++ b/src/urh/controller/SimulatorTabController.py @@ -3,8 +3,16 @@ import numpy from PyQt5.QtCore import pyqtSlot, Qt, QDir, QStringListModel, pyqtSignal from PyQt5.QtGui import QIcon -from PyQt5.QtWidgets import QWidget, QFileDialog, QCompleter, QMessageBox, QFrame, \ - QHBoxLayout, QToolButton, QDialog +from PyQt5.QtWidgets import ( + QWidget, + QFileDialog, + QCompleter, + QMessageBox, + QFrame, + QHBoxLayout, + QToolButton, + QDialog, +) from urh.controller.CompareFrameController import CompareFrameController from urh.controller.GeneratorTabController import GeneratorTabController @@ -43,9 +51,13 @@ class SimulatorTabController(QWidget): open_in_analysis_requested = pyqtSignal(str) rx_file_saved = pyqtSignal(str) - def __init__(self, compare_frame_controller: CompareFrameController, - generator_tab_controller: GeneratorTabController, - project_manager: ProjectManager, parent): + def __init__( + self, + compare_frame_controller: CompareFrameController, + generator_tab_controller: GeneratorTabController, + project_manager: ProjectManager, + parent, + ): super().__init__(parent) self.project_manager = project_manager @@ -69,42 +81,69 @@ def __init__(self, compare_frame_controller: CompareFrameController, self.tree_model = self.generator_tab_controller.tree_model self.ui.treeProtocols.setModel(self.tree_model) - self.participant_table_model = ParticipantTableModel(project_manager.participants) + self.participant_table_model = ParticipantTableModel( + project_manager.participants + ) self.ui.tableViewParticipants.setModel(self.participant_table_model) self.participant_table_model.update() self.simulator_message_field_model = SimulatorMessageFieldModel(self) self.ui.tblViewFieldValues.setModel(self.simulator_message_field_model) - self.ui.tblViewFieldValues.setItemDelegateForColumn(1, ComboBoxDelegate(ProtocolLabel.DISPLAY_FORMATS, - parent=self.ui.tblViewFieldValues)) - self.ui.tblViewFieldValues.setItemDelegateForColumn(2, ComboBoxDelegate(SimulatorProtocolLabel.VALUE_TYPES, - parent=self.ui.tblViewFieldValues)) - self.ui.tblViewFieldValues.setItemDelegateForColumn(3, ProtocolValueDelegate(controller=self, - parent=self.ui.tblViewFieldValues)) + self.ui.tblViewFieldValues.setItemDelegateForColumn( + 1, + ComboBoxDelegate( + ProtocolLabel.DISPLAY_FORMATS, parent=self.ui.tblViewFieldValues + ), + ) + self.ui.tblViewFieldValues.setItemDelegateForColumn( + 2, + ComboBoxDelegate( + SimulatorProtocolLabel.VALUE_TYPES, parent=self.ui.tblViewFieldValues + ), + ) + self.ui.tblViewFieldValues.setItemDelegateForColumn( + 3, ProtocolValueDelegate(controller=self, parent=self.ui.tblViewFieldValues) + ) self.project_manager.reload_field_types() self.update_field_name_column() - self.simulator_message_table_model = SimulatorMessageTableModel(self.project_manager, self) + self.simulator_message_table_model = SimulatorMessageTableModel( + self.project_manager, self + ) self.ui.tblViewMessage.setModel(self.simulator_message_table_model) - self.ui.ruleCondLineEdit.setValidator(RuleExpressionValidator(self.sim_expression_parser, is_formula=False)) + self.ui.ruleCondLineEdit.setValidator( + RuleExpressionValidator(self.sim_expression_parser, is_formula=False) + ) self.completer_model = QStringListModel([]) - self.ui.ruleCondLineEdit.setCompleter(QCompleter(self.completer_model, self.ui.ruleCondLineEdit)) - self.ui.ruleCondLineEdit.setToolTip(self.sim_expression_parser.rule_condition_help) - - self.simulator_scene = SimulatorScene(mode=0, simulator_config=self.simulator_config) - self.simulator_scene.tree_root_item = compare_frame_controller.proto_tree_model.rootItem + self.ui.ruleCondLineEdit.setCompleter( + QCompleter(self.completer_model, self.ui.ruleCondLineEdit) + ) + self.ui.ruleCondLineEdit.setToolTip( + self.sim_expression_parser.rule_condition_help + ) + + self.simulator_scene = SimulatorScene( + mode=0, simulator_config=self.simulator_config + ) + self.simulator_scene.tree_root_item = ( + compare_frame_controller.proto_tree_model.rootItem + ) self.ui.gvSimulator.setScene(self.simulator_scene) self.ui.gvSimulator.setAlignment(Qt.AlignLeft | Qt.AlignTop) self.ui.gvSimulator.proto_analyzer = compare_frame_controller.proto_analyzer self.__active_item = None - self.ui.listViewSimulate.setModel(SimulatorParticipantListModel(self.simulator_config)) + self.ui.listViewSimulate.setModel( + SimulatorParticipantListModel(self.simulator_config) + ) self.ui.spinBoxNRepeat.setValue(self.project_manager.simulator_num_repeat) self.ui.spinBoxTimeout.setValue(self.project_manager.simulator_timeout_ms) self.ui.spinBoxRetries.setValue(self.project_manager.simulator_retries) - self.ui.comboBoxError.setCurrentIndex(self.project_manager.simulator_error_handling_index) + self.ui.comboBoxError.setCurrentIndex( + self.project_manager.simulator_error_handling_index + ) # place save/load button at corner of tab widget frame = QFrame(parent=self) @@ -120,15 +159,18 @@ def __init__(self, compare_frame_controller: CompareFrameController, frame.layout().setContentsMargins(0, 0, 0, 0) self.ui.tabWidget.setCornerWidget(frame) - self.ui.splitterLeftRight.setSizes([int(0.2 * self.width()), int(0.8 * self.width())]) + self.ui.splitterLeftRight.setSizes( + [int(0.2 * self.width()), int(0.8 * self.width())] + ) self.create_connects() def refresh_field_types_for_labels(self): for msg in self.simulator_config.get_all_messages(): for lbl in (lbl for lbl in msg.message_type if lbl.field_type is not None): - msg.message_type.change_field_type_of_label(lbl, self.field_types_by_caption.get(lbl.field_type.caption, - None)) + msg.message_type.change_field_type_of_label( + lbl, self.field_types_by_caption.get(lbl.field_type.caption, None) + ) self.update_field_name_column() self.update_ui() @@ -143,43 +185,83 @@ def field_types_by_caption(self): def update_field_name_column(self): field_types = [ft.caption for ft in self.field_types] - self.ui.tblViewFieldValues.setItemDelegateForColumn(0, ComboBoxDelegate(field_types, is_editable=True, - return_index=False, - parent=self.ui.tblViewFieldValues)) + self.ui.tblViewFieldValues.setItemDelegateForColumn( + 0, + ComboBoxDelegate( + field_types, + is_editable=True, + return_index=False, + parent=self.ui.tblViewFieldValues, + ), + ) def create_connects(self): self.ui.btnChooseCommand.clicked.connect(self.on_btn_choose_command_clicked) - self.ui.lineEditTriggerCommand.textChanged.connect(self.on_line_edit_trigger_command_text_changed) - self.ui.checkBoxPassTranscriptSTDIN.clicked.connect(self.on_check_box_pass_transcript_STDIN_clicked) - self.ui.doubleSpinBoxSleep.editingFinished.connect(self.on_spinbox_sleep_editing_finished) - self.ui.ruleCondLineEdit.textChanged.connect(self.on_rule_cond_line_edit_text_changed) + self.ui.lineEditTriggerCommand.textChanged.connect( + self.on_line_edit_trigger_command_text_changed + ) + self.ui.checkBoxPassTranscriptSTDIN.clicked.connect( + self.on_check_box_pass_transcript_STDIN_clicked + ) + self.ui.doubleSpinBoxSleep.editingFinished.connect( + self.on_spinbox_sleep_editing_finished + ) + self.ui.ruleCondLineEdit.textChanged.connect( + self.on_rule_cond_line_edit_text_changed + ) self.ui.btnStartSim.clicked.connect(self.on_btn_simulate_clicked) - self.ui.goto_combobox.currentIndexChanged.connect(self.on_goto_combobox_index_changed) + self.ui.goto_combobox.currentIndexChanged.connect( + self.on_goto_combobox_index_changed + ) self.ui.spinBoxRepeat.valueChanged.connect(self.on_repeat_value_changed) self.ui.cbViewType.currentIndexChanged.connect(self.on_view_type_changed) - self.ui.tblViewMessage.create_label_triggered.connect(self.create_simulator_label) - self.ui.tblViewMessage.open_modulator_dialog_clicked.connect(self.open_modulator_dialog) - self.ui.tblViewMessage.selectionModel().selectionChanged.connect(self.on_table_selection_changed) + self.ui.tblViewMessage.create_label_triggered.connect( + self.create_simulator_label + ) + self.ui.tblViewMessage.open_modulator_dialog_clicked.connect( + self.open_modulator_dialog + ) + self.ui.tblViewMessage.selectionModel().selectionChanged.connect( + self.on_table_selection_changed + ) self.ui.tabWidget.currentChanged.connect(self.on_selected_tab_changed) self.ui.btnSave.clicked.connect(self.on_btn_save_clicked) self.ui.btnLoad.clicked.connect(self.on_btn_load_clicked) - self.ui.listViewSimulate.model().participant_simulate_changed.connect(self.on_participant_simulate_changed) - - self.ui.btnAddParticipant.clicked.connect(self.ui.tableViewParticipants.on_add_action_triggered) - self.ui.btnRemoveParticipant.clicked.connect(self.ui.tableViewParticipants.on_remove_action_triggered) - self.ui.btnUp.clicked.connect(self.ui.tableViewParticipants.on_move_up_action_triggered) - self.ui.btnDown.clicked.connect(self.ui.tableViewParticipants.on_move_down_action_triggered) - self.participant_table_model.participant_edited.connect(self.on_participant_edited) + self.ui.listViewSimulate.model().participant_simulate_changed.connect( + self.on_participant_simulate_changed + ) + + self.ui.btnAddParticipant.clicked.connect( + self.ui.tableViewParticipants.on_add_action_triggered + ) + self.ui.btnRemoveParticipant.clicked.connect( + self.ui.tableViewParticipants.on_remove_action_triggered + ) + self.ui.btnUp.clicked.connect( + self.ui.tableViewParticipants.on_move_up_action_triggered + ) + self.ui.btnDown.clicked.connect( + self.ui.tableViewParticipants.on_move_down_action_triggered + ) + self.participant_table_model.participant_edited.connect( + self.on_participant_edited + ) self.tree_model.modelReset.connect(self.refresh_tree) - self.simulator_scene.selectionChanged.connect(self.on_simulator_scene_selection_changed) + self.simulator_scene.selectionChanged.connect( + self.on_simulator_scene_selection_changed + ) self.simulator_scene.files_dropped.connect(self.on_files_dropped) - self.simulator_message_field_model.protocol_label_updated.connect(self.item_updated) + self.simulator_message_field_model.protocol_label_updated.connect( + self.item_updated + ) self.ui.gvSimulator.message_updated.connect(self.item_updated) - self.ui.gvSimulator.consolidate_messages_clicked.connect(self.consolidate_messages) + self.ui.gvSimulator.consolidate_messages_clicked.connect( + self.consolidate_messages + ) self.simulator_config.items_added.connect(self.refresh_message_table) self.simulator_config.items_updated.connect(self.refresh_message_table) @@ -187,20 +269,40 @@ def create_connects(self): self.simulator_config.items_deleted.connect(self.refresh_message_table) self.simulator_config.participants_changed.connect(self.on_participants_changed) self.simulator_config.item_dict_updated.connect(self.on_item_dict_updated) - self.simulator_config.active_participants_updated.connect(self.on_active_participants_updated) - - self.ui.gvSimulator.message_updated.connect(self.on_message_source_or_destination_updated) - - self.ui.spinBoxNRepeat.valueChanged.connect(self.on_spinbox_num_repeat_value_changed) - self.ui.spinBoxTimeout.valueChanged.connect(self.on_spinbox_timeout_value_changed) - self.ui.comboBoxError.currentIndexChanged.connect(self.on_combobox_error_handling_index_changed) - self.ui.spinBoxRetries.valueChanged.connect(self.on_spinbox_retries_value_changed) - - self.ui.tblViewFieldValues.item_link_clicked.connect(self.on_table_item_link_clicked) - self.ui.tblViewMessage.edit_label_triggered.connect(self.on_edit_label_triggered) - - self.ui.spinBoxCounterStart.editingFinished.connect(self.on_spinbox_counter_start_editing_finished) - self.ui.spinBoxCounterStep.editingFinished.connect(self.on_spinbox_counter_step_editing_finished) + self.simulator_config.active_participants_updated.connect( + self.on_active_participants_updated + ) + + self.ui.gvSimulator.message_updated.connect( + self.on_message_source_or_destination_updated + ) + + self.ui.spinBoxNRepeat.valueChanged.connect( + self.on_spinbox_num_repeat_value_changed + ) + self.ui.spinBoxTimeout.valueChanged.connect( + self.on_spinbox_timeout_value_changed + ) + self.ui.comboBoxError.currentIndexChanged.connect( + self.on_combobox_error_handling_index_changed + ) + self.ui.spinBoxRetries.valueChanged.connect( + self.on_spinbox_retries_value_changed + ) + + self.ui.tblViewFieldValues.item_link_clicked.connect( + self.on_table_item_link_clicked + ) + self.ui.tblViewMessage.edit_label_triggered.connect( + self.on_edit_label_triggered + ) + + self.ui.spinBoxCounterStart.editingFinished.connect( + self.on_spinbox_counter_start_editing_finished + ) + self.ui.spinBoxCounterStep.editingFinished.connect( + self.on_spinbox_counter_step_editing_finished + ) def consolidate_messages(self): self.simulator_config.consolidate_messages() @@ -223,7 +325,9 @@ def on_selected_tab_changed(self, index: int): self.update_vertical_table_header() def refresh_message_table(self): - self.simulator_message_table_model.protocol.messages[:] = self.simulator_config.get_all_messages() + self.simulator_message_table_model.protocol.messages[ + : + ] = self.simulator_config.get_all_messages() self.simulator_message_table_model.update() if isinstance(self.active_item, SimulatorMessage): @@ -259,27 +363,39 @@ def close_all(self): @pyqtSlot(int, int, int) def create_simulator_label(self, msg_index: int, start: int, end: int): con = self.simulator_message_table_model.protocol - start, end = con.convert_range(start, end - 1, self.ui.cbViewType.currentIndex(), 0, False, msg_index) - lbl = self.simulator_config.add_label(start=start, end=end, parent_item=con.messages[msg_index]) + start, end = con.convert_range( + start, end - 1, self.ui.cbViewType.currentIndex(), 0, False, msg_index + ) + lbl = self.simulator_config.add_label( + start=start, end=end, parent_item=con.messages[msg_index] + ) try: index = self.simulator_message_field_model.message_type.index(lbl) - self.ui.tblViewFieldValues.edit(self.simulator_message_field_model.createIndex(index, 0)) + self.ui.tblViewFieldValues.edit( + self.simulator_message_field_model.createIndex(index, 0) + ) except ValueError: pass @pyqtSlot() def open_modulator_dialog(self): - selected_message = self.simulator_message_table_model.protocol.messages[self.ui.tblViewMessage.selected_rows[0]] + selected_message = self.simulator_message_table_model.protocol.messages[ + self.ui.tblViewMessage.selected_rows[0] + ] preselected_index = selected_message.modulator_index - modulator_dialog = ModulatorDialog(self.project_manager.modulators, tree_model=self.tree_model, parent=self) + modulator_dialog = ModulatorDialog( + self.project_manager.modulators, tree_model=self.tree_model, parent=self + ) modulator_dialog.ui.comboBoxCustomModulations.setCurrentIndex(preselected_index) modulator_dialog.showMaximized() modulator_dialog.initialize(selected_message.encoded_bits_str[0:16]) modulator_dialog.finished.connect(self.refresh_modulators) - modulator_dialog.finished.connect(self.generator_tab_controller.refresh_pause_list) + modulator_dialog.finished.connect( + self.generator_tab_controller.refresh_pause_list + ) @pyqtSlot() def refresh_modulators(self): @@ -297,7 +413,9 @@ def refresh_modulators(self): index = self.sender().ui.comboBoxCustomModulations.currentIndex() for row in self.ui.tblViewMessage.selected_rows: - self.simulator_message_table_model.protocol.messages[row].modulator_index = index + self.simulator_message_table_model.protocol.messages[ + row + ].modulator_index = index def update_goto_combobox(self, active_item: SimulatorGotoAction): assert isinstance(active_item, SimulatorGotoAction) @@ -341,7 +459,9 @@ def on_rule_cond_line_edit_text_changed(self): @pyqtSlot() def on_view_type_changed(self): - self.simulator_message_table_model.proto_view = self.ui.cbViewType.currentIndex() + self.simulator_message_table_model.proto_view = ( + self.ui.cbViewType.currentIndex() + ) self.simulator_message_table_model.update() self.ui.tblViewMessage.resize_columns() @@ -350,7 +470,11 @@ def on_goto_combobox_index_changed(self): if not isinstance(self.active_item, SimulatorGotoAction): return - self.active_item.goto_target = None if self.ui.goto_combobox.currentIndex() == 0 else self.ui.goto_combobox.currentText() + self.active_item.goto_target = ( + None + if self.ui.goto_combobox.currentIndex() == 0 + else self.ui.goto_combobox.currentText() + ) self.item_updated(self.active_item) @pyqtSlot() @@ -369,7 +493,9 @@ def on_table_selection_changed(self): self.ui.lNumSelectedColumns.setText("0") else: max_row = numpy.max([rng.bottom() for rng in selection]) - self.active_item = self.simulator_message_table_model.protocol.messages[max_row] + self.active_item = self.simulator_message_table_model.protocol.messages[ + max_row + ] _, _, start, end = self.ui.tblViewMessage.selection_range() self.ui.lNumSelectedColumns.setText(str(end - start)) @@ -393,13 +519,17 @@ def active_item(self, value): self.ui.lblEncodingDecoding.setText(self.active_item.decoder.name) self.ui.detail_view_widget.setCurrentIndex(2) - elif (isinstance(self.active_item, SimulatorRuleCondition) and - self.active_item.type != ConditionType.ELSE): + elif ( + isinstance(self.active_item, SimulatorRuleCondition) + and self.active_item.type != ConditionType.ELSE + ): self.ui.ruleCondLineEdit.setText(self.active_item.condition) self.ui.detail_view_widget.setCurrentIndex(3) elif isinstance(self.active_item, SimulatorTriggerCommandAction): self.ui.lineEditTriggerCommand.setText(self.active_item.command) - self.ui.checkBoxPassTranscriptSTDIN.setChecked(self.active_item.pass_transcript) + self.ui.checkBoxPassTranscriptSTDIN.setChecked( + self.active_item.pass_transcript + ) self.ui.detail_view_widget.setCurrentIndex(4) elif isinstance(self.active_item, SimulatorSleepAction): self.ui.doubleSpinBoxSleep.setValue(self.active_item.sleep_time) @@ -416,27 +546,47 @@ def active_item(self, value): @pyqtSlot() def on_btn_simulate_clicked(self): if not self.simulator_config.protocol_valid(): - QMessageBox.critical(self, self.tr("Invalid protocol configuration"), - self.tr( - "There are some problems with your protocol configuration. Please fix them first.")) + QMessageBox.critical( + self, + self.tr("Invalid protocol configuration"), + self.tr( + "There are some problems with your protocol configuration. Please fix them first." + ), + ) return if not len(self.simulator_config.get_all_messages()): - QMessageBox.critical(self, self.tr("No messages found"), self.tr("Please add at least one message.")) + QMessageBox.critical( + self, + self.tr("No messages found"), + self.tr("Please add at least one message."), + ) return - num_simulated = len([p for p in self.project_manager.participants if p.simulate]) + num_simulated = len( + [p for p in self.project_manager.participants if p.simulate] + ) if num_simulated == 0: if self.ui.listViewSimulate.model().rowCount() == 0: - QMessageBox.critical(self, self.tr("No active participants"), - self.tr("You have no active participants.
" - "Please add a participant in the Participants tab and " - "assign it to at least one message as source or destination.")) + QMessageBox.critical( + self, + self.tr("No active participants"), + self.tr( + "You have no active participants.
" + "Please add a participant in the Participants tab and " + "assign it to at least one message as source or destination." + ), + ) return else: - QMessageBox.critical(self, self.tr("No participant for simulation selected"), - self.tr("Please check at least one participant from the " - "Simulate these participants list.")) + QMessageBox.critical( + self, + self.tr("No participant for simulation selected"), + self.tr( + "Please check at least one participant from the " + "Simulate these participants list." + ), + ) return try: @@ -445,16 +595,30 @@ def on_btn_simulate_clicked(self): Errors.exception(e) def get_simulator_dialog(self) -> SimulatorDialog: - protos = [p for proto_list in self.tree_model.protocols.values() for p in proto_list] + protos = [ + p for proto_list in self.tree_model.protocols.values() for p in proto_list + ] signals = [p.signal for p in protos if p.signal is not None] - s = SimulatorDialog(self.simulator_config, self.project_manager.modulators, - self.sim_expression_parser, self.project_manager, signals=signals, - signal_tree_model=self.tree_model, parent=self) - - s.rx_parameters_changed.connect(self.project_manager.on_simulator_rx_parameters_changed) - s.sniff_parameters_changed.connect(self.project_manager.on_simulator_sniff_parameters_changed) - s.tx_parameters_changed.connect(self.project_manager.on_simulator_tx_parameters_changed) + s = SimulatorDialog( + self.simulator_config, + self.project_manager.modulators, + self.sim_expression_parser, + self.project_manager, + signals=signals, + signal_tree_model=self.tree_model, + parent=self, + ) + + s.rx_parameters_changed.connect( + self.project_manager.on_simulator_rx_parameters_changed + ) + s.sniff_parameters_changed.connect( + self.project_manager.on_simulator_sniff_parameters_changed + ) + s.tx_parameters_changed.connect( + self.project_manager.on_simulator_tx_parameters_changed + ) s.open_in_analysis_requested.connect(self.open_in_analysis_requested.emit) s.rx_file_saved.connect(self.rx_file_saved.emit) @@ -462,7 +626,9 @@ def get_simulator_dialog(self) -> SimulatorDialog: @pyqtSlot() def on_btn_choose_command_clicked(self): - file_name, ok = QFileDialog.getOpenFileName(self, self.tr("Choose program"), QDir.homePath()) + file_name, ok = QFileDialog.getOpenFileName( + self, self.tr("Choose program"), QDir.homePath() + ) if file_name is not None and ok: self.ui.lineEditTriggerCommand.setText(file_name) @@ -474,7 +640,9 @@ def on_line_edit_trigger_command_text_changed(self): @pyqtSlot() def on_check_box_pass_transcript_STDIN_clicked(self): - self.active_item.pass_transcript = self.ui.checkBoxPassTranscriptSTDIN.isChecked() + self.active_item.pass_transcript = ( + self.ui.checkBoxPassTranscriptSTDIN.isChecked() + ) self.item_updated(self.active_item) @pyqtSlot() @@ -507,13 +675,17 @@ def refresh_tree(self): @pyqtSlot() def on_btn_save_clicked(self): - filename = FileOperator.ask_save_file_name(initial_name="myprofile.sim.xml", caption="Save simulator profile") + filename = FileOperator.ask_save_file_name( + initial_name="myprofile.sim.xml", caption="Save simulator profile" + ) if filename: self.save_simulator_file(filename) @pyqtSlot() def on_btn_load_clicked(self): - dialog = FileOperator.get_open_dialog(False, parent=self, name_filter="simulator") + dialog = FileOperator.get_open_dialog( + False, parent=self, name_filter="simulator" + ) if dialog.exec_(): self.load_simulator_file(dialog.selectedFiles()[0]) @@ -544,7 +716,9 @@ def on_message_source_or_destination_updated(self): @pyqtSlot(int, int) def on_table_item_link_clicked(self, row: int, column: int): try: - lbl = self.simulator_message_field_model.message_type[row] # type: SimulatorProtocolLabel + lbl = self.simulator_message_field_model.message_type[ + row + ] # type: SimulatorProtocolLabel assert lbl.is_checksum_label assert isinstance(self.active_item, SimulatorMessage) except (IndexError, AssertionError): @@ -552,7 +726,11 @@ def on_table_item_link_clicked(self, row: int, column: int): d = QDialog(parent=self) layout = QHBoxLayout() - layout.addWidget(ChecksumWidget(lbl.label, self.active_item, self.ui.cbViewType.currentIndex())) + layout.addWidget( + ChecksumWidget( + lbl.label, self.active_item, self.ui.cbViewType.currentIndex() + ) + ) d.setLayout(layout) d.show() @@ -567,8 +745,12 @@ def on_active_participants_updated(self): @pyqtSlot(int) def on_edit_label_triggered(self, label_index: int): view_type = self.ui.cbViewType.currentIndex() - protocol_label_dialog = ProtocolLabelDialog(message=self.ui.tblViewMessage.selected_message, - viewtype=view_type, selected_index=label_index, parent=self) + protocol_label_dialog = ProtocolLabelDialog( + message=self.ui.tblViewMessage.selected_message, + viewtype=view_type, + selected_index=label_index, + parent=self, + ) protocol_label_dialog.finished.connect(self.on_protocol_label_dialog_finished) protocol_label_dialog.showMaximized() @@ -580,5 +762,7 @@ def on_protocol_label_dialog_finished(self): @pyqtSlot(list) def on_files_dropped(self, file_urls: list): - for filename in (file_url.toLocalFile() for file_url in file_urls if file_url.isLocalFile()): - self.load_simulator_file(filename) \ No newline at end of file + for filename in ( + file_url.toLocalFile() for file_url in file_urls if file_url.isLocalFile() + ): + self.load_simulator_file(filename) diff --git a/src/urh/controller/dialogs/AdvancedModulationOptionsDialog.py b/src/urh/controller/dialogs/AdvancedModulationOptionsDialog.py index 9864ea2678..dcac5a95f9 100644 --- a/src/urh/controller/dialogs/AdvancedModulationOptionsDialog.py +++ b/src/urh/controller/dialogs/AdvancedModulationOptionsDialog.py @@ -33,6 +33,8 @@ def on_accept_clicked(self): self.pause_threshold_edited.emit(self.ui.spinBoxPauseThreshold.value()) if self.message_length_divisor != self.ui.spinBoxMessageLengthDivisor.value(): - self.message_length_divisor_edited.emit(self.ui.spinBoxMessageLengthDivisor.value()) + self.message_length_divisor_edited.emit( + self.ui.spinBoxMessageLengthDivisor.value() + ) self.accept() diff --git a/src/urh/controller/dialogs/CSVImportDialog.py b/src/urh/controller/dialogs/CSVImportDialog.py index b412a92bc1..84c556eb1a 100644 --- a/src/urh/controller/dialogs/CSVImportDialog.py +++ b/src/urh/controller/dialogs/CSVImportDialog.py @@ -3,7 +3,14 @@ import os import numpy as np from PyQt5.QtCore import Qt, pyqtSlot, pyqtSignal -from PyQt5.QtWidgets import QDialog, QInputDialog, QApplication, QCompleter, QDirModel, QFileDialog +from PyQt5.QtWidgets import ( + QDialog, + QInputDialog, + QApplication, + QCompleter, + QDirModel, + QFileDialog, +) from urh.ui.ui_csv_wizard import Ui_DialogCSVImport from urh.util import FileOperator, util @@ -13,7 +20,6 @@ class CSVImportDialog(QDialog): data_imported = pyqtSignal(str, float) # Complex Filename + Sample Rate - PREVIEW_ROWS = 100 COLUMNS = {"T": 0, "I": 1, "Q": 2} @@ -41,13 +47,23 @@ def __init__(self, filename="", parent=None): def create_connects(self): self.accepted.connect(self.on_accepted) - self.ui.lineEditFilename.editingFinished.connect(self.on_line_edit_filename_editing_finished) + self.ui.lineEditFilename.editingFinished.connect( + self.on_line_edit_filename_editing_finished + ) self.ui.btnChooseFile.clicked.connect(self.on_btn_choose_file_clicked) self.ui.btnAddSeparator.clicked.connect(self.on_btn_add_separator_clicked) - self.ui.comboBoxCSVSeparator.currentIndexChanged.connect(self.on_combobox_csv_separator_current_index_changed) - self.ui.spinBoxIDataColumn.valueChanged.connect(self.on_spinbox_i_data_column_value_changed) - self.ui.spinBoxQDataColumn.valueChanged.connect(self.on_spinbox_q_data_column_value_changed) - self.ui.spinBoxTimestampColumn.valueChanged.connect(self.on_spinbox_timestamp_value_changed) + self.ui.comboBoxCSVSeparator.currentIndexChanged.connect( + self.on_combobox_csv_separator_current_index_changed + ) + self.ui.spinBoxIDataColumn.valueChanged.connect( + self.on_spinbox_i_data_column_value_changed + ) + self.ui.spinBoxQDataColumn.valueChanged.connect( + self.on_spinbox_q_data_column_value_changed + ) + self.ui.spinBoxTimestampColumn.valueChanged.connect( + self.on_spinbox_timestamp_value_changed + ) def update_file(self): filename = self.ui.lineEditFilename.text() @@ -85,18 +101,26 @@ def update_preview(self): self.ui.tableWidgetPreview.setRowCount(self.PREVIEW_ROWS) with open(self.filename, encoding="utf-8-sig") as f: - csv_reader = csv.reader(f, delimiter=self.ui.comboBoxCSVSeparator.currentText()) + csv_reader = csv.reader( + f, delimiter=self.ui.comboBoxCSVSeparator.currentText() + ) row = -1 for line in csv_reader: row += 1 - result = self.parse_csv_line(line, i_data_col, q_data_col, timestamp_col) + result = self.parse_csv_line( + line, i_data_col, q_data_col, timestamp_col + ) if result is not None: for key, value in result.items(): - self.ui.tableWidgetPreview.setItem(row, self.COLUMNS[key], util.create_table_item(value)) + self.ui.tableWidgetPreview.setItem( + row, self.COLUMNS[key], util.create_table_item(value) + ) else: for col in self.COLUMNS.values(): - self.ui.tableWidgetPreview.setItem(row, col, util.create_table_item("Invalid")) + self.ui.tableWidgetPreview.setItem( + row, col, util.create_table_item("Invalid") + ) if row >= self.PREVIEW_ROWS - 1: break @@ -104,7 +128,9 @@ def update_preview(self): self.ui.tableWidgetPreview.setRowCount(row + 1) @staticmethod - def parse_csv_line(csv_line: str, i_data_col: int, q_data_col: int, timestamp_col: int): + def parse_csv_line( + csv_line: str, i_data_col: int, q_data_col: int, timestamp_col: int + ): result = dict() if i_data_col >= 0: @@ -132,13 +158,17 @@ def parse_csv_line(csv_line: str, i_data_col: int, q_data_col: int, timestamp_co return result @staticmethod - def parse_csv_file(filename: str, separator: str, i_data_col: int, q_data_col=-1, t_data_col=-1): + def parse_csv_file( + filename: str, separator: str, i_data_col: int, q_data_col=-1, t_data_col=-1 + ): iq_data = [] timestamps = [] if t_data_col > -1 else None with open(filename, encoding="utf-8-sig") as f: csv_reader = csv.reader(f, delimiter=separator) for line in csv_reader: - parsed = CSVImportDialog.parse_csv_line(line, i_data_col, q_data_col, t_data_col) + parsed = CSVImportDialog.parse_csv_line( + line, i_data_col, q_data_col, t_data_col + ) if parsed is None: continue @@ -158,8 +188,8 @@ def estimate_sample_rate(timestamps): previous_timestamp = timestamps[0] durations = [] - for timestamp in timestamps[1:CSVImportDialog.PREVIEW_ROWS]: - durations.append(abs(timestamp-previous_timestamp)) + for timestamp in timestamps[1 : CSVImportDialog.PREVIEW_ROWS]: + durations.append(abs(timestamp - previous_timestamp)) previous_timestamp = timestamp return 1 / (sum(durations) / len(durations)) @@ -171,8 +201,12 @@ def on_line_edit_filename_editing_finished(self): @pyqtSlot() def on_btn_choose_file_clicked(self): - filename, _ = QFileDialog.getOpenFileName(self, self.tr("Choose file"), directory=FileOperator.RECENT_PATH, - filter="CSV files (*.csv);;All files (*.*)") + filename, _ = QFileDialog.getOpenFileName( + self, + self.tr("Choose file"), + directory=FileOperator.RECENT_PATH, + filter="CSV files (*.csv);;All files (*.*)", + ) if filename: self.ui.lineEditFilename.setText(filename) @@ -181,12 +215,16 @@ def on_btn_choose_file_clicked(self): @pyqtSlot() def on_btn_add_separator_clicked(self): sep, ok = QInputDialog.getText(self, "Enter Separator", "Separator:", text=",") - if ok and sep not in (self.ui.comboBoxCSVSeparator.itemText(i) for i in - range(self.ui.comboBoxCSVSeparator.count())): + if ok and sep not in ( + self.ui.comboBoxCSVSeparator.itemText(i) + for i in range(self.ui.comboBoxCSVSeparator.count()) + ): if len(sep) == 1: self.ui.comboBoxCSVSeparator.addItem(sep) else: - Errors.generic_error("Invalid Separator", "Separator must be exactly one character.") + Errors.generic_error( + "Invalid Separator", "Separator must be exactly one character." + ) @pyqtSlot(int) def on_combobox_csv_separator_current_index_changed(self, index: int): @@ -209,10 +247,13 @@ def on_spinbox_timestamp_value_changed(self, value: int): def on_accepted(self): QApplication.setOverrideCursor(Qt.WaitCursor) - iq_data, sample_rate = self.parse_csv_file(self.filename, self.ui.comboBoxCSVSeparator.currentText(), - self.ui.spinBoxIDataColumn.value()-1, - self.ui.spinBoxQDataColumn.value()-1, - self.ui.spinBoxTimestampColumn.value()-1) + iq_data, sample_rate = self.parse_csv_file( + self.filename, + self.ui.comboBoxCSVSeparator.currentText(), + self.ui.spinBoxIDataColumn.value() - 1, + self.ui.spinBoxQDataColumn.value() - 1, + self.ui.spinBoxTimestampColumn.value() - 1, + ) target_filename = self.filename.rstrip(".csv") if os.path.exists(target_filename + ".complex"): @@ -227,10 +268,13 @@ def on_accepted(self): iq_data.tofile(target_filename) - self.data_imported.emit(target_filename, sample_rate if sample_rate is not None else 0) + self.data_imported.emit( + target_filename, sample_rate if sample_rate is not None else 0 + ) QApplication.restoreOverrideCursor() -if __name__ == '__main__': + +if __name__ == "__main__": app = QApplication(["urh"]) csv_dia = CSVImportDialog() csv_dia.exec_() diff --git a/src/urh/controller/dialogs/ContinuousSendDialog.py b/src/urh/controller/dialogs/ContinuousSendDialog.py index 5865d0f5ef..b24a533e73 100644 --- a/src/urh/controller/dialogs/ContinuousSendDialog.py +++ b/src/urh/controller/dialogs/ContinuousSendDialog.py @@ -9,9 +9,23 @@ class ContinuousSendDialog(SendDialog): - def __init__(self, project_manager, messages, modulators, total_samples: int, parent, testing_mode=False): - super().__init__(project_manager, modulated_data=None, modulation_msg_indices=None, - continuous_send_mode=True, parent=parent, testing_mode=testing_mode) + def __init__( + self, + project_manager, + messages, + modulators, + total_samples: int, + parent, + testing_mode=False, + ): + super().__init__( + project_manager, + modulated_data=None, + modulation_msg_indices=None, + continuous_send_mode=True, + parent=parent, + testing_mode=testing_mode, + ) self.messages = messages self.modulators = modulators @@ -24,8 +38,12 @@ def __init__(self, project_manager, messages, modulators, total_samples: int, pa self.ui.progressBarMessage.setMaximum(len(messages)) num_repeats = self.device_settings_widget.ui.spinBoxNRepeat.value() - self.continuous_modulator = ContinuousModulator(messages, modulators, num_repeats=num_repeats) - self.scene_manager = ContinuousSceneManager(ring_buffer=self.continuous_modulator.ring_buffer, parent=self) + self.continuous_modulator = ContinuousModulator( + messages, modulators, num_repeats=num_repeats + ) + self.scene_manager = ContinuousSceneManager( + ring_buffer=self.continuous_modulator.ring_buffer, parent=self + ) self.scene_manager.init_scene() self.graphics_view.setScene(self.scene_manager.scene) self.graphics_view.scene_manager = self.scene_manager @@ -44,7 +62,9 @@ def _update_send_indicator(self, width: int): def update_view(self): super().update_view() - self.ui.progressBarMessage.setValue(self.continuous_modulator.current_message_index.value + 1) + self.ui.progressBarMessage.setValue( + self.continuous_modulator.current_message_index.value + 1 + ) self.scene_manager.init_scene() self.scene_manager.show_full_scene() self.graphics_view.update() @@ -86,7 +106,9 @@ def on_clear_clicked(self): @pyqtSlot() def on_num_repeats_changed(self): super().on_num_repeats_changed() - self.continuous_modulator.num_repeats = self.device_settings_widget.ui.spinBoxNRepeat.value() + self.continuous_modulator.num_repeats = ( + self.device_settings_widget.ui.spinBoxNRepeat.value() + ) def on_selected_device_changed(self): self.ui.txtEditErrors.clear() @@ -96,13 +118,21 @@ def init_device(self): device_name = self.selected_device_name num_repeats = self.device_settings_widget.ui.spinBoxNRepeat.value() - self.device = VirtualDevice(self.backend_handler, device_name, Mode.send, - device_ip="192.168.10.2", sending_repeats=num_repeats, parent=self) + self.device = VirtualDevice( + self.backend_handler, + device_name, + Mode.send, + device_ip="192.168.10.2", + sending_repeats=num_repeats, + parent=self, + ) self.ui.btnStart.setEnabled(True) try: self.device.is_send_continuous = True - self.device.continuous_send_ring_buffer = self.continuous_modulator.ring_buffer + self.device.continuous_send_ring_buffer = ( + self.continuous_modulator.ring_buffer + ) self.device.num_samples_to_send = self.total_samples self._create_device_connects() diff --git a/src/urh/controller/dialogs/CostaOptionsDialog.py b/src/urh/controller/dialogs/CostaOptionsDialog.py index 39c9709a54..626bf58cdb 100644 --- a/src/urh/controller/dialogs/CostaOptionsDialog.py +++ b/src/urh/controller/dialogs/CostaOptionsDialog.py @@ -20,7 +20,9 @@ def __init__(self, loop_bandwidth, parent=None): def create_connects(self): self.ui.buttonBox.accepted.connect(self.accept) self.ui.buttonBox.rejected.connect(self.reject) - self.ui.doubleSpinBoxLoopBandwidth.valueChanged.connect(self.on_spinbox_loop_bandwidth_value_changed) + self.ui.doubleSpinBoxLoopBandwidth.valueChanged.connect( + self.on_spinbox_loop_bandwidth_value_changed + ) @pyqtSlot(float) def on_spinbox_loop_bandwidth_value_changed(self, value): diff --git a/src/urh/controller/dialogs/DecoderDialog.py b/src/urh/controller/dialogs/DecoderDialog.py index bdf976527a..ed22be29ca 100644 --- a/src/urh/controller/dialogs/DecoderDialog.py +++ b/src/urh/controller/dialogs/DecoderDialog.py @@ -3,8 +3,14 @@ from PyQt5.QtCore import QDir, Qt, pyqtSlot from PyQt5.QtGui import QCloseEvent, QDropEvent, QDragEnterEvent, QIcon -from PyQt5.QtWidgets import QDialog, QTableWidgetItem, QFileDialog, QInputDialog, \ - QLineEdit, QMessageBox +from PyQt5.QtWidgets import ( + QDialog, + QTableWidgetItem, + QFileDialog, + QInputDialog, + QLineEdit, + QMessageBox, +) from urh import settings from urh.signalprocessing.Encoding import Encoding @@ -16,8 +22,9 @@ class DecoderDialog(QDialog): - def __init__(self, decodings, signals, project_manager: ProjectManager, - parent=None): + def __init__( + self, decodings, signals, project_manager: ProjectManager, parent=None + ): """ :type decodings: list of Encoding :type signals: list of Signal @@ -81,7 +88,7 @@ def __init__(self, decodings, signals, project_manager: ProjectManager, self.ui.substitution.setColumnCount(2) self.ui.substitution.setRowCount(self.ui.substitution_rows.value()) - self.ui.substitution.setHorizontalHeaderLabels(['From', 'To']) + self.ui.substitution.setHorizontalHeaderLabels(["From", "To"]) self.ui.substitution.setColumnWidth(0, 190) self.ui.substitution.setColumnWidth(1, 190) @@ -90,13 +97,17 @@ def __init__(self, decodings, signals, project_manager: ProjectManager, # Connects self.create_connects() - self.restoreGeometry(settings.read("{}/geometry".format(self.__class__.__name__), type=bytes)) + self.restoreGeometry( + settings.read("{}/geometry".format(self.__class__.__name__), type=bytes) + ) def create_connects(self): self.ui.inpt.textChanged.connect(self.decoder_update) self.ui.multiple.valueChanged.connect(self.handle_multiple_changed) self.ui.carrier.textChanged.connect(self.handle_carrier_changed) - self.ui.substitution_rows.valueChanged.connect(self.handle_substitution_rows_changed) + self.ui.substitution_rows.valueChanged.connect( + self.handle_substitution_rows_changed + ) self.ui.substitution.itemChanged.connect(self.handle_substitution_changed) self.ui.btnChooseDecoder.clicked.connect(self.choose_decoder) @@ -111,10 +122,18 @@ def create_connects(self): self.ui.decoderchain.itemChanged.connect(self.decoderchainUpdate) self.ui.decoderchain.internalMove.connect(self.decoderchainUpdate) self.ui.decoderchain.deleteElement.connect(self.deleteElement) - self.ui.decoderchain.currentRowChanged.connect(self.on_decoder_chain_current_row_changed) - self.ui.basefunctions.currentRowChanged.connect(self.on_base_functions_current_row_changed) - self.ui.additionalfunctions.currentRowChanged.connect(self.on_additional_functions_current_row_changed) - self.ui.btnAddtoYourDecoding.clicked.connect(self.on_btn_add_to_your_decoding_clicked) + self.ui.decoderchain.currentRowChanged.connect( + self.on_decoder_chain_current_row_changed + ) + self.ui.basefunctions.currentRowChanged.connect( + self.on_base_functions_current_row_changed + ) + self.ui.additionalfunctions.currentRowChanged.connect( + self.on_additional_functions_current_row_changed + ) + self.ui.btnAddtoYourDecoding.clicked.connect( + self.on_btn_add_to_your_decoding_clicked + ) self.ui.combobox_decodings.currentIndexChanged.connect(self.set_e) self.ui.combobox_signals.currentIndexChanged.connect(self.set_signal) @@ -133,17 +152,23 @@ def create_connects(self): self.ui.morse_wait.valueChanged.connect(self.handle_morse_changed) def closeEvent(self, event: QCloseEvent): - settings.write("{}/geometry".format(self.__class__.__name__), self.saveGeometry()) + settings.write( + "{}/geometry".format(self.__class__.__name__), self.saveGeometry() + ) super().closeEvent(event) def choose_decoder(self): - f, ok = QFileDialog.getOpenFileName(self, self.tr("Choose decoder program"), QDir.homePath()) + f, ok = QFileDialog.getOpenFileName( + self, self.tr("Choose decoder program"), QDir.homePath() + ) if f and ok: self.ui.external_decoder.setText(f) self.handle_external() def choose_encoder(self): - f, ok = QFileDialog.getOpenFileName(self, self.tr("Choose encoder program"), QDir.homePath()) + f, ok = QFileDialog.getOpenFileName( + self, self.tr("Choose encoder program"), QDir.homePath() + ) if f and ok: self.ui.external_encoder.setText(f) self.handle_external() @@ -152,7 +177,9 @@ def save_to_file(self): if self.project_manager.project_file: self.project_manager.decodings = self.decodings else: - prefix = os.path.realpath(os.path.join(settings.get_qt_settings_filename(), "..")) + prefix = os.path.realpath( + os.path.join(settings.get_qt_settings_filename(), "..") + ) with open(os.path.join(prefix, settings.DECODINGS_FILE), "w") as f: for i in range(0, self.ui.combobox_decodings.count()): str = "" @@ -163,8 +190,13 @@ def save_to_file(self): def saveas(self): # Ask for a name - name, ok = QInputDialog.getText(self, self.tr("Save decoding"), - self.tr("Please enter a name:"), QLineEdit.Normal, self.e.chain[0]) + name, ok = QInputDialog.getText( + self, + self.tr("Save decoding"), + self.tr("Please enter a name:"), + QLineEdit.Normal, + self.e.chain[0], + ) if ok and name != "": self.e.chain[0] = name @@ -182,17 +214,24 @@ def saveas(self): self.decodings.append(Encoding(self.chainstr)) self.ui.combobox_decodings.addItem(self.chainstr[0]) - self.ui.combobox_decodings.setCurrentIndex(self.ui.combobox_decodings.count() - 1) + self.ui.combobox_decodings.setCurrentIndex( + self.ui.combobox_decodings.count() - 1 + ) self.set_e() self.save_to_file() def delete_decoding(self): num = self.ui.combobox_decodings.currentIndex() if num >= 0: - reply = QMessageBox.question(self, self.tr("Delete Decoding?"), - self.tr("Do you really want to delete " + "'{}'?".format( - self.decodings[num].name)), - QMessageBox.Yes | QMessageBox.No) + reply = QMessageBox.question( + self, + self.tr("Delete Decoding?"), + self.tr( + "Do you really want to delete " + + "'{}'?".format(self.decodings[num].name) + ), + QMessageBox.Yes | QMessageBox.No, + ) if reply == QMessageBox.Yes: self.decodings.pop(num) @@ -203,26 +242,48 @@ def set_e(self): if self.ui.combobox_decodings.count() < 1: # Empty list return - self.e = copy.deepcopy(self.decodings[self.ui.combobox_decodings.currentIndex()]) + self.e = copy.deepcopy( + self.decodings[self.ui.combobox_decodings.currentIndex()] + ) """:type: encoding """ chain = self.e.get_chain() self.ui.decoderchain.clear() self.chainoptions.clear() last_i = "" for i in chain: - if i in [settings.DECODING_INVERT, settings.DECODING_ENOCEAN, settings.DECODING_DIFFERENTIAL, - settings.DECODING_REDUNDANCY, settings.DECODING_CARRIER, settings.DECODING_BITORDER, - settings.DECODING_EDGE, settings.DECODING_DATAWHITENING, settings.DECODING_SUBSTITUTION, - settings.DECODING_EXTERNAL, settings.DECODING_CUT, settings.DECODING_MORSE, - settings.DECODING_DISABLED_PREFIX]: + if i in [ + settings.DECODING_INVERT, + settings.DECODING_ENOCEAN, + settings.DECODING_DIFFERENTIAL, + settings.DECODING_REDUNDANCY, + settings.DECODING_CARRIER, + settings.DECODING_BITORDER, + settings.DECODING_EDGE, + settings.DECODING_DATAWHITENING, + settings.DECODING_SUBSTITUTION, + settings.DECODING_EXTERNAL, + settings.DECODING_CUT, + settings.DECODING_MORSE, + settings.DECODING_DISABLED_PREFIX, + ]: self.ui.decoderchain.addItem(i) self.decoderchainUpdate() - last_i = self.ui.decoderchain.item(self.ui.decoderchain.count() - 1).text() + last_i = self.ui.decoderchain.item( + self.ui.decoderchain.count() - 1 + ).text() else: - if any(x in last_i for x in [settings.DECODING_REDUNDANCY, settings.DECODING_CARRIER, - settings.DECODING_SUBSTITUTION, settings.DECODING_EXTERNAL, - settings.DECODING_DATAWHITENING, settings.DECODING_CUT, - settings.DECODING_MORSE]): + if any( + x in last_i + for x in [ + settings.DECODING_REDUNDANCY, + settings.DECODING_CARRIER, + settings.DECODING_SUBSTITUTION, + settings.DECODING_EXTERNAL, + settings.DECODING_DATAWHITENING, + settings.DECODING_CUT, + settings.DECODING_MORSE, + ] + ): self.chainoptions[last_i] = i self.decoderchainUpdate() @@ -321,7 +382,10 @@ def eliminateDuplicates(self): if decoderchain_count > 1 and decoderchain_count > olddecoderchain_count: elem = 0 while elem < olddecoderchain_count: - if self.ui.decoderchain.item(elem).text() == self.old_decoderchain[elem]: + if ( + self.ui.decoderchain.item(elem).text() + == self.old_decoderchain[elem] + ): elem += 1 else: break @@ -454,17 +518,21 @@ def set_information(self, mode: int): # Remove "[Disabled] " for further tasks if settings.DECODING_DISABLED_PREFIX in element: - element = element[len(settings.DECODING_DISABLED_PREFIX):] + element = element[len(settings.DECODING_DISABLED_PREFIX) :] # Write info text and show options if settings.DECODING_EDGE in element: - txt += "Trigger on signal edge, i.e. the transition between low and high.\n" \ - "- Low to High (01) is 1\n" \ - "- High to Low (10) is 0" + txt += ( + "Trigger on signal edge, i.e. the transition between low and high.\n" + "- Low to High (01) is 1\n" + "- High to Low (10) is 0" + ) elif settings.DECODING_SUBSTITUTION in element: - txt += "A set of manual defined signal sequences FROM (e.g. 110, 100) is replaced by another set of " \ - "sequences TO (e.g. 01, 10). Note that all FROM entries must have the same length, otherwise " \ - "the result is unpredictable! (For TX: all TO entries must have the same length)" + txt += ( + "A set of manual defined signal sequences FROM (e.g. 110, 100) is replaced by another set of " + "sequences TO (e.g. 01, 10). Note that all FROM entries must have the same length, otherwise " + "the result is unpredictable! (For TX: all TO entries must have the same length)" + ) self.ui.optionWidget.setCurrentIndex(3) # Values can only be changed when editing decoder, otherwise default value if not decoderEdit: @@ -484,8 +552,12 @@ def set_information(self, mode: int): self.ui.substitution_rows.setValue(len(arrs[0])) self.ui.substitution.setRowCount(len(arrs[0])) for i in range(0, len(arrs[0])): - self.ui.substitution.setItem(i, 0, QTableWidgetItem(self.e.bit2str(arrs[0][i]))) - self.ui.substitution.setItem(i, 1, QTableWidgetItem(self.e.bit2str(arrs[1][i]))) + self.ui.substitution.setItem( + i, 0, QTableWidgetItem(self.e.bit2str(arrs[0][i])) + ) + self.ui.substitution.setItem( + i, 1, QTableWidgetItem(self.e.bit2str(arrs[1][i])) + ) else: self.ui.substitution_rows.setValue(4) self.ui.substitution.setRowCount(0) @@ -494,9 +566,11 @@ def set_information(self, mode: int): self.ui.substitution_rows.setEnabled(decoderEdit) elif settings.DECODING_EXTERNAL in element: - txt += "The decoding (and encoding) process is delegated to external programs or scripts via parameter.\n" \ - "Example: Given the signal 10010110, your program is called as './decoder 10010110'. Your program " \ - "computes and prints a corresponding set of 0s and 1s which is fed back into the decoding process. " + txt += ( + "The decoding (and encoding) process is delegated to external programs or scripts via parameter.\n" + "Example: Given the signal 10010110, your program is called as './decoder 10010110'. Your program " + "computes and prints a corresponding set of 0s and 1s which is fed back into the decoding process. " + ) self.ui.optionWidget.setCurrentIndex(4) # Values can only be changed when editing decoder, otherwise default value if not decoderEdit: @@ -525,15 +599,21 @@ def set_information(self, mode: int): elif settings.DECODING_ENOCEAN in element: txt += "Remove Wireless Short-Packet (WSP) encoding that is used by EnOcean standard." elif settings.DECODING_DIFFERENTIAL in element: - txt += "Every transition between low and high (0->1 or 1->0) becomes 1, no transition (0->0 or 1->1) remains 0.\n" \ - "The first signal bit is regarded as start value and directly copied.\n" \ - "Example: 0011 becomes 0010 [0|(0->0)|(0->1)|(1->1)]." + txt += ( + "Every transition between low and high (0->1 or 1->0) becomes 1, no transition (0->0 or 1->1) remains 0.\n" + "The first signal bit is regarded as start value and directly copied.\n" + "Example: 0011 becomes 0010 [0|(0->0)|(0->1)|(1->1)]." + ) elif settings.DECODING_BITORDER in element: - txt += "Every byte (8 bit) is reversed, i.e. the order of the bits 01234567 (e.g. least significant bit first) " \ - "is changed to 76543210 (e.g. most significant bit first)." + txt += ( + "Every byte (8 bit) is reversed, i.e. the order of the bits 01234567 (e.g. least significant bit first) " + "is changed to 76543210 (e.g. most significant bit first)." + ) elif settings.DECODING_REDUNDANCY in element: - txt += "If the source signal always has multiple redundant bits for one bit (e.g. 1111=1, 0000=0), the " \ - "redundancy is removed here. You have to define the number of redundant bits." + txt += ( + "If the source signal always has multiple redundant bits for one bit (e.g. 1111=1, 0000=0), the " + "redundancy is removed here. You have to define the number of redundant bits." + ) self.ui.optionWidget.setCurrentIndex(1) # Values can only be changed when editing decoder, otherwise default value if not decoderEdit: @@ -549,9 +629,11 @@ def set_information(self, mode: int): self.ui.multiple.setValue(2) self.ui.multiple.setEnabled(decoderEdit) elif settings.DECODING_MORSE in element: - txt += "If the signal is a morse code, e.g. 00111001001110011100, where information are " \ - "transported with long and short sequences of 1 (0 just for padding), then this " \ - "decoding evaluates those sequences (Example output: 1011)." + txt += ( + "If the signal is a morse code, e.g. 00111001001110011100, where information are " + "transported with long and short sequences of 1 (0 just for padding), then this " + "decoding evaluates those sequences (Example output: 1011)." + ) self.ui.optionWidget.setCurrentIndex(7) # # Values can only be changed when editing decoder, otherwise default value if not decoderEdit: @@ -583,11 +665,13 @@ def set_information(self, mode: int): self.ui.morse_high.setEnabled(decoderEdit) self.ui.morse_wait.setEnabled(decoderEdit) elif settings.DECODING_CARRIER in element: - txt += "A carrier is a fixed pattern like 1_1_1_1 where the actual data lies in between, e.g. 1a1a1b1. This " \ - "function extracts the actual bit information (here: aab) from the signal at '_'/'.' positions.\n" \ - "Examples:\n" \ - "- Carrier = '1_' means 1_1_1_...\n" \ - "- Carrier = '01_' means 01_01_01_01..." + txt += ( + "A carrier is a fixed pattern like 1_1_1_1 where the actual data lies in between, e.g. 1a1a1b1. This " + "function extracts the actual bit information (here: aab) from the signal at '_'/'.' positions.\n" + "Examples:\n" + "- Carrier = '1_' means 1_1_1_...\n" + "- Carrier = '01_' means 01_01_01_01..." + ) self.ui.optionWidget.setCurrentIndex(2) # Values can only be changed when editing decoder, otherwise default value if not decoderEdit: @@ -603,10 +687,12 @@ def set_information(self, mode: int): self.ui.carrier.setText("1_") self.ui.carrier.setEnabled(decoderEdit) elif settings.DECODING_DATAWHITENING in element: - txt += "Texas Instruments CC110x chips allow a data whitening that is applied before sending the signals to HF. " \ - "After a preamble (1010...) there is a fixed 16/32 bit sync word. The following data (incl. 16 bit CRC) " \ - "is masked (XOR) with the output of a LFSR.\n" \ - "This unmasks the data." + txt += ( + "Texas Instruments CC110x chips allow a data whitening that is applied before sending the signals to HF. " + "After a preamble (1010...) there is a fixed 16/32 bit sync word. The following data (incl. 16 bit CRC) " + "is masked (XOR) with the output of a LFSR.\n" + "This unmasks the data." + ) self.ui.optionWidget.setCurrentIndex(5) # Values can only be changed when editing decoder, otherwise default value if not decoderEdit: @@ -622,10 +708,18 @@ def set_information(self, mode: int): self.ui.datawhitening_overwrite_crc.setChecked(False) else: try: - whitening_sync, whitening_polynomial, whitening_overwrite_crc = value.split(";") + ( + whitening_sync, + whitening_polynomial, + whitening_overwrite_crc, + ) = value.split(";") self.ui.datawhitening_sync.setText(whitening_sync) - self.ui.datawhitening_polynomial.setText(whitening_polynomial) - self.ui.datawhitening_overwrite_crc.setChecked(True if whitening_overwrite_crc == "1" else False) + self.ui.datawhitening_polynomial.setText( + whitening_polynomial + ) + self.ui.datawhitening_overwrite_crc.setChecked( + True if whitening_overwrite_crc == "1" else False + ) except ValueError: self.ui.datawhitening_sync.setText("0xe9cae9ca") @@ -637,11 +731,13 @@ def set_information(self, mode: int): self.ui.datawhitening_overwrite_crc.setEnabled(decoderEdit) elif settings.DECODING_CUT in element: - txt += "This function enables you to cut data from your messages, in order to shorten or align them for a " \ - "better view. Note that this decoding does NOT support encoding, because cut data is gone!\n" \ - "Example:\n" \ - "- Cut before '1010' would delete everything before first '1010' bits.\n" \ - "- Cut before Position = 3 (in bit) would delete the first three bits.\n" + txt += ( + "This function enables you to cut data from your messages, in order to shorten or align them for a " + "better view. Note that this decoding does NOT support encoding, because cut data is gone!\n" + "Example:\n" + "- Cut before '1010' would delete everything before first '1010' bits.\n" + "- Cut before Position = 3 (in bit) would delete the first three bits.\n" + ) self.ui.optionWidget.setCurrentIndex(6) # Values can only be changed when editing decoder, otherwise default value if not decoderEdit: @@ -721,15 +817,22 @@ def set_information(self, mode: int): @pyqtSlot() def handle_datawhitening(self): - datawhiteningstr = self.ui.datawhitening_sync.text() + ";" + self.ui.datawhitening_polynomial.text() + ";" + \ - ("1" if self.ui.datawhitening_overwrite_crc.isChecked() else "0") + datawhiteningstr = ( + self.ui.datawhitening_sync.text() + + ";" + + self.ui.datawhitening_polynomial.text() + + ";" + + ("1" if self.ui.datawhitening_overwrite_crc.isChecked() else "0") + ) if settings.DECODING_DATAWHITENING in self.active_message: self.chainoptions[self.active_message] = datawhiteningstr self.decoderchainUpdate() @pyqtSlot() def handle_external(self): - externalstr = self.ui.external_decoder.text() + ";" + self.ui.external_encoder.text() + externalstr = ( + self.ui.external_decoder.text() + ";" + self.ui.external_encoder.text() + ) if settings.DECODING_EXTERNAL in self.active_message: self.chainoptions[self.active_message] = externalstr self.decoderchainUpdate() @@ -739,7 +842,12 @@ def handle_substitution_changed(self): subststr = "" for i in range(0, self.ui.substitution_rows.value()): if self.ui.substitution.item(i, 0) and self.ui.substitution.item(i, 1): - subststr += self.ui.substitution.item(i, 0).text() + ":" + self.ui.substitution.item(i, 1).text() + ";" + subststr += ( + self.ui.substitution.item(i, 0).text() + + ":" + + self.ui.substitution.item(i, 1).text() + + ";" + ) if settings.DECODING_SUBSTITUTION in self.active_message: self.chainoptions[self.active_message] = subststr self.decoderchainUpdate() @@ -773,15 +881,18 @@ def handle_morse_changed(self): self.old_morse = (val_low, val_high) if settings.DECODING_MORSE in self.active_message: - self.chainoptions[self.active_message] = "{};{};{}".format(val_low, val_high, val_wait) + self.chainoptions[self.active_message] = "{};{};{}".format( + val_low, val_high, val_wait + ) self.decoderchainUpdate() @pyqtSlot() def handle_carrier_changed(self): # Only allow {0, 1} carrier_txt = self.ui.carrier.text() - if carrier_txt.count("0") + carrier_txt.count("1") + carrier_txt.count("_") + carrier_txt.count( - ".") + carrier_txt.count("*") < len(carrier_txt): + if carrier_txt.count("0") + carrier_txt.count("1") + carrier_txt.count( + "_" + ) + carrier_txt.count(".") + carrier_txt.count("*") < len(carrier_txt): self.ui.carrier.setText(self.old_carrier_txt) else: self.old_carrier_txt = carrier_txt @@ -830,7 +941,7 @@ def on_btn_add_to_your_decoding_clicked(self): if self.last_selected_item != "": self.ui.decoderchain.addItem(self.last_selected_item) self.decoderchainUpdate() - self.ui.decoderchain.setCurrentRow(self.ui.decoderchain.count()-1) + self.ui.decoderchain.setCurrentRow(self.ui.decoderchain.count() - 1) def dragEnterEvent(self, event: QDragEnterEvent): event.accept() @@ -864,9 +975,10 @@ def set_signal(self): last_message = pa.messages[-1] lookup = {i: msg.bit_sample_pos for i, msg in enumerate(pa.messages)} - plot_data = signal.qad[lookup[0][0]:lookup[pa.num_messages - 1][len(last_message) - 1]] + plot_data = signal.qad[ + lookup[0][0] : lookup[pa.num_messages - 1][len(last_message) - 1] + ] self.ui.graphicsView_signal.plot_data(plot_data) self.ui.graphicsView_signal.centerOn(0, 0) self.unsetCursor() - diff --git a/src/urh/controller/dialogs/FilterBandwidthDialog.py b/src/urh/controller/dialogs/FilterBandwidthDialog.py index 5ccae1b6e3..191a5ad6f9 100644 --- a/src/urh/controller/dialogs/FilterBandwidthDialog.py +++ b/src/urh/controller/dialogs/FilterBandwidthDialog.py @@ -20,22 +20,44 @@ def __init__(self, parent=None): item = getattr(self.ui, item) if isinstance(item, QLabel): name = item.objectName().replace("label", "") - key = next((key for key in Filter.BANDWIDTHS.keys() if name.startswith(key.replace(" ", ""))), None) + key = next( + ( + key + for key in Filter.BANDWIDTHS.keys() + if name.startswith(key.replace(" ", "")) + ), + None, + ) if key is not None and name.endswith("Bandwidth"): item.setText("{0:n}".format(Filter.BANDWIDTHS[key])) elif key is not None and name.endswith("KernelLength"): - item.setText(str(Filter.get_filter_length_from_bandwidth(Filter.BANDWIDTHS[key]))) + item.setText( + str( + Filter.get_filter_length_from_bandwidth( + Filter.BANDWIDTHS[key] + ) + ) + ) elif isinstance(item, QRadioButton): - item.setChecked(bw_type.replace(" ", "_") == item.objectName().replace("radioButton", "")) + item.setChecked( + bw_type.replace(" ", "_") + == item.objectName().replace("radioButton", "") + ) self.ui.doubleSpinBoxCustomBandwidth.setValue(custom_bw) - self.ui.spinBoxCustomKernelLength.setValue(Filter.get_filter_length_from_bandwidth(custom_bw)) + self.ui.spinBoxCustomKernelLength.setValue( + Filter.get_filter_length_from_bandwidth(custom_bw) + ) self.create_connects() def create_connects(self): - self.ui.doubleSpinBoxCustomBandwidth.valueChanged.connect(self.on_spin_box_custom_bandwidth_value_changed) - self.ui.spinBoxCustomKernelLength.valueChanged.connect(self.on_spin_box_custom_kernel_length_value_changed) + self.ui.doubleSpinBoxCustomBandwidth.valueChanged.connect( + self.on_spin_box_custom_bandwidth_value_changed + ) + self.ui.spinBoxCustomKernelLength.valueChanged.connect( + self.on_spin_box_custom_kernel_length_value_changed + ) self.ui.buttonBox.accepted.connect(self.on_accepted) @property @@ -49,19 +71,29 @@ def checked_radiobutton(self): @pyqtSlot(float) def on_spin_box_custom_bandwidth_value_changed(self, bw: float): self.ui.spinBoxCustomKernelLength.blockSignals(True) - self.ui.spinBoxCustomKernelLength.setValue(Filter.get_filter_length_from_bandwidth(bw)) + self.ui.spinBoxCustomKernelLength.setValue( + Filter.get_filter_length_from_bandwidth(bw) + ) self.ui.spinBoxCustomKernelLength.blockSignals(False) @pyqtSlot(int) def on_spin_box_custom_kernel_length_value_changed(self, filter_len: int): self.ui.doubleSpinBoxCustomBandwidth.blockSignals(True) - self.ui.doubleSpinBoxCustomBandwidth.setValue(Filter.get_bandwidth_from_filter_length(filter_len)) + self.ui.doubleSpinBoxCustomBandwidth.setValue( + Filter.get_bandwidth_from_filter_length(filter_len) + ) self.ui.doubleSpinBoxCustomBandwidth.blockSignals(False) @pyqtSlot() def on_accepted(self): if self.checked_radiobutton is not None: - bw_type = self.checked_radiobutton.objectName().replace("radioButton", "").replace("_", " ") + bw_type = ( + self.checked_radiobutton.objectName() + .replace("radioButton", "") + .replace("_", " ") + ) settings.write("bandpass_filter_bw_type", bw_type) - settings.write("bandpass_filter_custom_bw", self.ui.doubleSpinBoxCustomBandwidth.value()) + settings.write( + "bandpass_filter_custom_bw", self.ui.doubleSpinBoxCustomBandwidth.value() + ) diff --git a/src/urh/controller/dialogs/FilterDialog.py b/src/urh/controller/dialogs/FilterDialog.py index bf60d68cbb..f2ad87367c 100644 --- a/src/urh/controller/dialogs/FilterDialog.py +++ b/src/urh/controller/dialogs/FilterDialog.py @@ -34,9 +34,15 @@ def set_dsp_filter_status(self, dsp_filter_type: FilterType): self.ui.lineEditCustomTaps.setEnabled(True) def create_connects(self): - self.ui.radioButtonMovingAverage.clicked.connect(self.on_radio_button_moving_average_clicked) - self.ui.radioButtonCustomTaps.clicked.connect(self.on_radio_button_custom_taps_clicked) - self.ui.radioButtonDCcorrection.clicked.connect(self.on_radio_button_dc_correction_clicked) + self.ui.radioButtonMovingAverage.clicked.connect( + self.on_radio_button_moving_average_clicked + ) + self.ui.radioButtonCustomTaps.clicked.connect( + self.on_radio_button_custom_taps_clicked + ) + self.ui.radioButtonDCcorrection.clicked.connect( + self.on_radio_button_dc_correction_clicked + ) self.ui.spinBoxNumTaps.valueChanged.connect(self.set_error_status) self.ui.lineEditCustomTaps.textEdited.connect(self.set_error_status) @@ -46,7 +52,9 @@ def create_connects(self): def build_filter(self) -> Filter: if self.ui.radioButtonMovingAverage.isChecked(): n = self.ui.spinBoxNumTaps.value() - return Filter([1/n for _ in range(n)], filter_type=FilterType.moving_average) + return Filter( + [1 / n for _ in range(n)], filter_type=FilterType.moving_average + ) elif self.ui.radioButtonDCcorrection.isChecked(): return Filter([], filter_type=FilterType.dc_correction) else: @@ -72,7 +80,9 @@ def set_error_status(self): self.ui.lineEditCustomTaps.setToolTip(self.error_message) elif len(dsp_filter.taps) != self.ui.spinBoxNumTaps.value(): self.ui.lineEditCustomTaps.setStyleSheet("background: yellow") - self.ui.lineEditCustomTaps.setToolTip("The number of the filter taps does not match the configured number of taps. I will use your configured filter taps.") + self.ui.lineEditCustomTaps.setToolTip( + "The number of the filter taps does not match the configured number of taps. I will use your configured filter taps." + ) else: self.ui.lineEditCustomTaps.setStyleSheet("") self.ui.lineEditCustomTaps.setToolTip("") diff --git a/src/urh/controller/dialogs/FuzzingDialog.py b/src/urh/controller/dialogs/FuzzingDialog.py index f06543589d..63df280b60 100644 --- a/src/urh/controller/dialogs/FuzzingDialog.py +++ b/src/urh/controller/dialogs/FuzzingDialog.py @@ -12,8 +12,14 @@ class FuzzingDialog(QDialog): - def __init__(self, protocol: ProtocolAnalyzerContainer, label_index: int, msg_index: int, proto_view: int, - parent=None): + def __init__( + self, + protocol: ProtocolAnalyzerContainer, + label_index: int, + msg_index: int, + proto_view: int, + parent=None, + ): super().__init__(parent) self.ui = Ui_FuzzingDialog() self.ui.setupUi(self) @@ -26,12 +32,16 @@ def __init__(self, protocol: ProtocolAnalyzerContainer, label_index: int, msg_in self.ui.spinBoxFuzzMessage.setMinimum(1) self.ui.spinBoxFuzzMessage.setMaximum(self.protocol.num_messages) - self.ui.comboBoxFuzzingLabel.addItems([l.name for l in self.message.message_type]) + self.ui.comboBoxFuzzingLabel.addItems( + [l.name for l in self.message.message_type] + ) self.ui.comboBoxFuzzingLabel.setCurrentIndex(label_index) self.proto_view = proto_view self.fuzz_table_model = FuzzingTableModel(self.current_label, proto_view) - self.fuzz_table_model.remove_duplicates = self.ui.chkBRemoveDuplicates.isChecked() + self.fuzz_table_model.remove_duplicates = ( + self.ui.chkBRemoveDuplicates.isChecked() + ) self.ui.tblFuzzingValues.setModel(self.fuzz_table_model) self.fuzz_table_model.update() @@ -44,7 +54,9 @@ def __init__(self, protocol: ProtocolAnalyzerContainer, label_index: int, msg_in self.ui.tblFuzzingValues.resize_me() self.create_connects() - self.restoreGeometry(settings.read("{}/geometry".format(self.__class__.__name__), type=bytes)) + self.restoreGeometry( + settings.read("{}/geometry".format(self.__class__.__name__), type=bytes) + ) @property def message(self): @@ -61,23 +73,31 @@ def current_label(self) -> ProtocolLabel: cur_label = self.message.message_type[self.current_label_index].get_copy() self.message.message_type[self.current_label_index] = cur_label - cur_label.fuzz_values = [fv for fv in cur_label.fuzz_values if fv] # Remove empty strings + cur_label.fuzz_values = [ + fv for fv in cur_label.fuzz_values if fv + ] # Remove empty strings if len(cur_label.fuzz_values) == 0: - cur_label.fuzz_values.append(self.message.plain_bits_str[cur_label.start:cur_label.end]) + cur_label.fuzz_values.append( + self.message.plain_bits_str[cur_label.start : cur_label.end] + ) return cur_label @property def current_label_start(self): if self.current_label and self.message: - return self.message.get_label_range(self.current_label, self.proto_view, False)[0] + return self.message.get_label_range( + self.current_label, self.proto_view, False + )[0] else: return -1 @property def current_label_end(self): if self.current_label and self.message: - return self.message.get_label_range(self.current_label, self.proto_view, False)[1] + return self.message.get_label_range( + self.current_label, self.proto_view, False + )[1] else: return -1 @@ -95,23 +115,41 @@ def message_data(self): def create_connects(self): self.ui.spinBoxFuzzingStart.valueChanged.connect(self.on_fuzzing_start_changed) self.ui.spinBoxFuzzingEnd.valueChanged.connect(self.on_fuzzing_end_changed) - self.ui.comboBoxFuzzingLabel.currentIndexChanged.connect(self.on_combo_box_fuzzing_label_current_index_changed) + self.ui.comboBoxFuzzingLabel.currentIndexChanged.connect( + self.on_combo_box_fuzzing_label_current_index_changed + ) self.ui.btnRepeatValues.clicked.connect(self.on_btn_repeat_values_clicked) self.ui.btnAddRow.clicked.connect(self.on_btn_add_row_clicked) self.ui.btnDelRow.clicked.connect(self.on_btn_del_row_clicked) self.ui.tblFuzzingValues.deletion_wanted.connect(self.delete_lines) - self.ui.chkBRemoveDuplicates.stateChanged.connect(self.on_remove_duplicates_state_changed) - self.ui.sBAddRangeStart.valueChanged.connect(self.on_fuzzing_range_start_changed) + self.ui.chkBRemoveDuplicates.stateChanged.connect( + self.on_remove_duplicates_state_changed + ) + self.ui.sBAddRangeStart.valueChanged.connect( + self.on_fuzzing_range_start_changed + ) self.ui.sBAddRangeEnd.valueChanged.connect(self.on_fuzzing_range_end_changed) - self.ui.checkBoxLowerBound.stateChanged.connect(self.on_lower_bound_checked_changed) - self.ui.checkBoxUpperBound.stateChanged.connect(self.on_upper_bound_checked_changed) + self.ui.checkBoxLowerBound.stateChanged.connect( + self.on_lower_bound_checked_changed + ) + self.ui.checkBoxUpperBound.stateChanged.connect( + self.on_upper_bound_checked_changed + ) self.ui.spinBoxLowerBound.valueChanged.connect(self.on_lower_bound_changed) self.ui.spinBoxUpperBound.valueChanged.connect(self.on_upper_bound_changed) - self.ui.spinBoxRandomMinimum.valueChanged.connect(self.on_random_range_min_changed) - self.ui.spinBoxRandomMaximum.valueChanged.connect(self.on_random_range_max_changed) + self.ui.spinBoxRandomMinimum.valueChanged.connect( + self.on_random_range_min_changed + ) + self.ui.spinBoxRandomMaximum.valueChanged.connect( + self.on_random_range_max_changed + ) self.ui.spinBoxFuzzMessage.valueChanged.connect(self.on_fuzz_msg_changed) - self.ui.btnAddFuzzingValues.clicked.connect(self.on_btn_add_fuzzing_values_clicked) - self.ui.comboBoxFuzzingLabel.editTextChanged.connect(self.set_current_label_name) + self.ui.btnAddFuzzingValues.clicked.connect( + self.on_btn_add_fuzzing_values_clicked + ) + self.ui.comboBoxFuzzingLabel.editTextChanged.connect( + self.set_current_label_name + ) def update_message_data_string(self): fuz_start = self.current_label_start @@ -136,13 +174,19 @@ def update_message_data_string(self): fuz_end = fuz_start + num_fuz_bits fuzamble = "..." - self.ui.lPreBits.setText(preambel + self.message_data[proto_start:self.current_label_start]) + self.ui.lPreBits.setText( + preambel + self.message_data[proto_start : self.current_label_start] + ) self.ui.lFuzzedBits.setText(self.message_data[fuz_start:fuz_end] + fuzamble) - self.ui.lPostBits.setText(self.message_data[self.current_label_end:proto_end] + postambel) + self.ui.lPostBits.setText( + self.message_data[self.current_label_end : proto_end] + postambel + ) self.set_add_spinboxes_maximum_on_label_change() def closeEvent(self, event: QCloseEvent): - settings.write("{}/geometry".format(self.__class__.__name__), self.saveGeometry()) + settings.write( + "{}/geometry".format(self.__class__.__name__), self.saveGeometry() + ) super().closeEvent(event) @pyqtSlot(int) @@ -158,7 +202,9 @@ def on_fuzzing_start_changed(self, value: int): @pyqtSlot(int) def on_fuzzing_end_changed(self, value: int): self.ui.spinBoxFuzzingStart.setMaximum(self.ui.spinBoxFuzzingEnd.value()) - new_end = self.message.convert_index(value - 1, self.proto_view, 0, False)[1] + 1 + new_end = ( + self.message.convert_index(value - 1, self.proto_view, 0, False)[1] + 1 + ) self.current_label.end = new_end self.current_label.fuzz_values[:] = [] self.update_message_data_string() @@ -195,8 +241,10 @@ def delete_lines(self, min_row, max_row): if min_row == -1: self.current_label.fuzz_values = self.current_label.fuzz_values[:-1] else: - self.current_label.fuzz_values = self.current_label.fuzz_values[:min_row] + self.current_label.fuzz_values[ - max_row + 1:] + self.current_label.fuzz_values = ( + self.current_label.fuzz_values[:min_row] + + self.current_label.fuzz_values[max_row + 1 :] + ) _ = self.current_label # if user deleted all, this will restore a fuzz value @@ -204,16 +252,20 @@ def delete_lines(self, min_row, max_row): @pyqtSlot() def on_remove_duplicates_state_changed(self): - self.fuzz_table_model.remove_duplicates = self.ui.chkBRemoveDuplicates.isChecked() + self.fuzz_table_model.remove_duplicates = ( + self.ui.chkBRemoveDuplicates.isChecked() + ) self.fuzz_table_model.update() self.remove_duplicates() @pyqtSlot() def set_add_spinboxes_maximum_on_label_change(self): - nbits = self.current_label.end - self.current_label.start # Use Bit Start/End for maximum calc. + nbits = ( + self.current_label.end - self.current_label.start + ) # Use Bit Start/End for maximum calc. if nbits >= 32: nbits = 31 - max_val = 2 ** nbits - 1 + max_val = 2**nbits - 1 self.ui.sBAddRangeStart.setMaximum(max_val - 1) self.ui.sBAddRangeEnd.setMaximum(max_val) self.ui.sBAddRangeEnd.setValue(max_val) @@ -261,14 +313,22 @@ def on_upper_bound_checked_changed(self): @pyqtSlot() def on_lower_bound_changed(self): self.ui.spinBoxUpperBound.setMinimum(self.ui.spinBoxLowerBound.value()) - self.ui.spinBoxBoundaryNumber.setMaximum(math.ceil((self.ui.spinBoxUpperBound.value() - - self.ui.spinBoxLowerBound.value()) / 2)) + self.ui.spinBoxBoundaryNumber.setMaximum( + math.ceil( + (self.ui.spinBoxUpperBound.value() - self.ui.spinBoxLowerBound.value()) + / 2 + ) + ) @pyqtSlot() def on_upper_bound_changed(self): self.ui.spinBoxLowerBound.setMaximum(self.ui.spinBoxUpperBound.value() - 1) - self.ui.spinBoxBoundaryNumber.setMaximum(math.ceil((self.ui.spinBoxUpperBound.value() - - self.ui.spinBoxLowerBound.value()) / 2)) + self.ui.spinBoxBoundaryNumber.setMaximum( + math.ceil( + (self.ui.spinBoxUpperBound.value() - self.ui.spinBoxLowerBound.value()) + / 2 + ) + ) @pyqtSlot() def on_random_range_min_changed(self): @@ -276,7 +336,9 @@ def on_random_range_min_changed(self): @pyqtSlot() def on_random_range_max_changed(self): - self.ui.spinBoxRandomMinimum.setMaximum(self.ui.spinBoxRandomMaximum.value() - 1) + self.ui.spinBoxRandomMinimum.setMaximum( + self.ui.spinBoxRandomMaximum.value() - 1 + ) @pyqtSlot() def on_btn_add_fuzzing_values_clicked(self): @@ -322,7 +384,9 @@ def remove_duplicates(self): @pyqtSlot() def set_current_label_name(self): self.current_label.name = self.ui.comboBoxFuzzingLabel.currentText() - self.ui.comboBoxFuzzingLabel.setItemText(self.ui.comboBoxFuzzingLabel.currentIndex(), self.current_label.name) + self.ui.comboBoxFuzzingLabel.setItemText( + self.ui.comboBoxFuzzingLabel.currentIndex(), self.current_label.name + ) @pyqtSlot(int) def on_fuzz_msg_changed(self, index: int): @@ -336,7 +400,9 @@ def on_fuzz_msg_changed(self, index: int): self.ui.comboBoxFuzzingLabel.setDisabled(True) return - self.ui.comboBoxFuzzingLabel.addItems([lbl.name for lbl in self.message.message_type]) + self.ui.comboBoxFuzzingLabel.addItems( + [lbl.name for lbl in self.message.message_type] + ) self.ui.comboBoxFuzzingLabel.blockSignals(False) if sel_label_ind < self.ui.comboBoxFuzzingLabel.count(): @@ -350,8 +416,13 @@ def on_fuzz_msg_changed(self, index: int): @pyqtSlot() def on_btn_repeat_values_clicked(self): - num_repeats, ok = QInputDialog.getInt(self, self.tr("How many times shall values be repeated?"), - self.tr("Number of repeats:"), 1, 1) + num_repeats, ok = QInputDialog.getInt( + self, + self.tr("How many times shall values be repeated?"), + self.tr("Number of repeats:"), + 1, + 1, + ) if ok: self.ui.chkBRemoveDuplicates.setChecked(False) min_row, max_row, _, _ = self.ui.tblFuzzingValues.selection_range() diff --git a/src/urh/controller/dialogs/MessageTypeDialog.py b/src/urh/controller/dialogs/MessageTypeDialog.py index f1431329e9..b95b0b1e5d 100644 --- a/src/urh/controller/dialogs/MessageTypeDialog.py +++ b/src/urh/controller/dialogs/MessageTypeDialog.py @@ -14,7 +14,6 @@ class MessageTypeDialog(QDialog): - def __init__(self, message_type: MessageType, parent=None): super().__init__(parent) self.ui = Ui_DialogMessageType() @@ -29,7 +28,9 @@ def __init__(self, message_type: MessageType, parent=None): self.message_type = message_type self.original_ruleset = copy.deepcopy(message_type.ruleset) self.original_assigned_status = message_type.assigned_by_ruleset - self.ruleset_table_model = RulesetTableModel(message_type.ruleset, operator_descriptions, parent=self) + self.ruleset_table_model = RulesetTableModel( + message_type.ruleset, operator_descriptions, parent=self + ) self.ui.tblViewRuleset.setModel(self.ruleset_table_model) self.ui.btnRemoveRule.setEnabled(len(message_type.ruleset) > 0) @@ -38,8 +39,12 @@ def __init__(self, message_type: MessageType, parent=None): self.ui.rbAssignAutomatically.setChecked(self.message_type.assigned_by_ruleset) self.ui.rbAssignManually.setChecked(self.message_type.assign_manually) - self.ui.tblViewRuleset.setItemDelegateForColumn(2, ComboBoxDelegate(["Bit", "Hex", "ASCII"], parent=self)) - self.ui.tblViewRuleset.setItemDelegateForColumn(3, ComboBoxDelegate(operator_descriptions, parent=self)) + self.ui.tblViewRuleset.setItemDelegateForColumn( + 2, ComboBoxDelegate(["Bit", "Hex", "ASCII"], parent=self) + ) + self.ui.tblViewRuleset.setItemDelegateForColumn( + 3, ComboBoxDelegate(operator_descriptions, parent=self) + ) for i in range(len(message_type.ruleset)): self.open_editors(i) @@ -47,32 +52,46 @@ def __init__(self, message_type: MessageType, parent=None): self.ui.cbRulesetMode.setCurrentIndex(self.message_type.ruleset.mode.value) self.create_connects() - self.restoreGeometry(settings.read("{}/geometry".format(self.__class__.__name__), type=bytes)) + self.restoreGeometry( + settings.read("{}/geometry".format(self.__class__.__name__), type=bytes) + ) def create_connects(self): self.ui.btnAddRule.clicked.connect(self.on_btn_add_rule_clicked) self.ui.btnRemoveRule.clicked.connect(self.on_btn_remove_rule_clicked) - self.ui.rbAssignAutomatically.clicked.connect(self.on_rb_assign_automatically_clicked) + self.ui.rbAssignAutomatically.clicked.connect( + self.on_rb_assign_automatically_clicked + ) self.ui.rbAssignManually.clicked.connect(self.on_rb_assign_manually_clicked) - self.ui.cbRulesetMode.currentIndexChanged.connect(self.on_cb_rulesetmode_current_index_changed) + self.ui.cbRulesetMode.currentIndexChanged.connect( + self.on_cb_rulesetmode_current_index_changed + ) self.ui.buttonBox.accepted.connect(self.accept) self.ui.buttonBox.rejected.connect(self.on_rejected) def set_ruleset_ui_status(self): self.ui.tblViewRuleset.setEnabled(self.message_type.assigned_by_ruleset) - self.ui.btnRemoveRule.setEnabled(self.message_type.assigned_by_ruleset and len(self.message_type.ruleset) > 0) + self.ui.btnRemoveRule.setEnabled( + self.message_type.assigned_by_ruleset and len(self.message_type.ruleset) > 0 + ) self.ui.btnAddRule.setEnabled(self.message_type.assigned_by_ruleset) self.ui.cbRulesetMode.setEnabled(self.message_type.assigned_by_ruleset) def open_editors(self, row): - self.ui.tblViewRuleset.openPersistentEditor(self.ruleset_table_model.index(row, 2)) - self.ui.tblViewRuleset.openPersistentEditor(self.ruleset_table_model.index(row, 3)) + self.ui.tblViewRuleset.openPersistentEditor( + self.ruleset_table_model.index(row, 2) + ) + self.ui.tblViewRuleset.openPersistentEditor( + self.ruleset_table_model.index(row, 3) + ) def closeEvent(self, event: QCloseEvent): self.ui.tblViewRuleset.setItemDelegateForColumn(2, None) self.ui.tblViewRuleset.setItemDelegateForColumn(3, None) - settings.write("{}/geometry".format(self.__class__.__name__), self.saveGeometry()) + settings.write( + "{}/geometry".format(self.__class__.__name__), self.saveGeometry() + ) super().closeEvent(event) @pyqtSlot() @@ -84,7 +103,9 @@ def on_rejected(self): @pyqtSlot() def on_btn_add_rule_clicked(self): self.ui.btnRemoveRule.setEnabled(True) - self.message_type.ruleset.append(Rule(start=0, end=0, operator="=", target_value="1", value_type=0)) + self.message_type.ruleset.append( + Rule(start=0, end=0, operator="=", target_value="1", value_type=0) + ) self.ruleset_table_model.update() for i in range(len(self.message_type.ruleset)): diff --git a/src/urh/controller/dialogs/ModulationParametersDialog.py b/src/urh/controller/dialogs/ModulationParametersDialog.py index 468a3a2a69..042c55374d 100644 --- a/src/urh/controller/dialogs/ModulationParametersDialog.py +++ b/src/urh/controller/dialogs/ModulationParametersDialog.py @@ -20,13 +20,21 @@ def __init__(self, parameters: list, modulation_type: str, parent=None): self.num_bits = int(math.log2(len(parameters))) if "FSK" in modulation_type: - self.ui.tblSymbolParameters.setItemDelegateForColumn(1, KillerSpinBoxDelegate(-1e12, 1e12, self)) - self.ui.tblSymbolParameters.horizontalHeaderItem(1).setText("Frequency in Hz") + self.ui.tblSymbolParameters.setItemDelegateForColumn( + 1, KillerSpinBoxDelegate(-1e12, 1e12, self) + ) + self.ui.tblSymbolParameters.horizontalHeaderItem(1).setText( + "Frequency in Hz" + ) elif "ASK" in modulation_type: self.ui.tblSymbolParameters.horizontalHeaderItem(1).setText("Amplitude") - self.ui.tblSymbolParameters.setItemDelegateForColumn(1, SpinBoxDelegate(0, 100, self, "%")) + self.ui.tblSymbolParameters.setItemDelegateForColumn( + 1, SpinBoxDelegate(0, 100, self, "%") + ) elif "PSK" in modulation_type: - self.ui.tblSymbolParameters.setItemDelegateForColumn(1, SpinBoxDelegate(-360, 360, self, "°")) + self.ui.tblSymbolParameters.setItemDelegateForColumn( + 1, SpinBoxDelegate(-360, 360, self, "°") + ) self.ui.tblSymbolParameters.horizontalHeaderItem(1).setText("Phase") fmt = "{0:0" + str(self.num_bits) + "b}" @@ -42,7 +50,9 @@ def __init__(self, parameters: list, modulation_type: str, parent=None): item = QTableWidgetItem() item.setData(Qt.DisplayRole, self.parameters[i]) self.ui.tblSymbolParameters.setItem(i, 1, item) - self.ui.tblSymbolParameters.openPersistentEditor(self.ui.tblSymbolParameters.item(i, 1)) + self.ui.tblSymbolParameters.openPersistentEditor( + self.ui.tblSymbolParameters.item(i, 1) + ) self.create_connects() @@ -58,8 +68,9 @@ def on_accepted(self): self.accept() -if __name__ == '__main__': +if __name__ == "__main__": from PyQt5.QtWidgets import QApplication + app = QApplication(["urh"]) dialog = ModulationParametersDialog([0, 100.0], "ASK") diff --git a/src/urh/controller/dialogs/ModulatorDialog.py b/src/urh/controller/dialogs/ModulatorDialog.py index 318b7a0883..306704b7c7 100644 --- a/src/urh/controller/dialogs/ModulatorDialog.py +++ b/src/urh/controller/dialogs/ModulatorDialog.py @@ -55,15 +55,19 @@ def __init__(self, modulators, tree_model=None, parent=None): self.original_bits = "" - self.restore_bits_action = self.ui.linEdDataBits.addAction(QIcon.fromTheme("edit-undo"), - QLineEdit.TrailingPosition) + self.restore_bits_action = self.ui.linEdDataBits.addAction( + QIcon.fromTheme("edit-undo"), QLineEdit.TrailingPosition + ) self.restore_bits_action.setEnabled(False) - self.configure_parameters_action = self.ui.lineEditParameters.addAction(QIcon.fromTheme("configure"), - QLineEdit.TrailingPosition) + self.configure_parameters_action = self.ui.lineEditParameters.addAction( + QIcon.fromTheme("configure"), QLineEdit.TrailingPosition + ) self.create_connects() - self.restoreGeometry(settings.read("{}/geometry".format(self.__class__.__name__), type=bytes)) + self.restoreGeometry( + settings.read("{}/geometry".format(self.__class__.__name__), type=bytes) + ) self.set_bits_per_symbol_enabled_status() self.set_modulation_profile_status() @@ -73,7 +77,7 @@ def __init__(self, modulators, tree_model=None, parent=None): def __cur_selected_mod_type(self): s = self.ui.comboBoxModulationType.currentText() - return s[s.rindex("(") + 1:s.rindex(")")] + return s[s.rindex("(") + 1 : s.rindex(")")] @staticmethod def __trim_number(number): @@ -103,14 +107,23 @@ def __set_gauss_ui_visibility(self, show: bool): self.ui.spinBoxGaussBT.setVisible(show) self.ui.spinBoxGaussFilterWidth.setVisible(show) - self.ui.spinBoxGaussFilterWidth.setValue(self.current_modulator.gauss_filter_width) + self.ui.spinBoxGaussFilterWidth.setValue( + self.current_modulator.gauss_filter_width + ) self.ui.spinBoxGaussBT.setValue(self.current_modulator.gauss_bt) def closeEvent(self, event: QCloseEvent): self.ui.lineEditParameters.editingFinished.emit() - settings.write("{}/geometry".format(self.__class__.__name__), self.saveGeometry()) - - for gv in (self.ui.gVCarrier, self.ui.gVData, self.ui.gVModulated, self.ui.gVOriginalSignal): + settings.write( + "{}/geometry".format(self.__class__.__name__), self.saveGeometry() + ) + + for gv in ( + self.ui.gVCarrier, + self.ui.gVData, + self.ui.gVModulated, + self.ui.gVOriginalSignal, + ): # Eliminate graphic views to prevent segfaults gv.eliminate() @@ -121,49 +134,84 @@ def current_modulator(self): return self.modulators[self.ui.comboBoxCustomModulations.currentIndex()] def set_ui_for_current_modulator(self): - index = self.ui.comboBoxModulationType.findText("*(" + self.current_modulator.modulation_type + ")", - Qt.MatchWildcard) + index = self.ui.comboBoxModulationType.findText( + "*(" + self.current_modulator.modulation_type + ")", Qt.MatchWildcard + ) self.ui.comboBoxModulationType.setCurrentIndex(index) - self.ui.doubleSpinBoxCarrierFreq.setValue(self.current_modulator.carrier_freq_hz) - self.ui.doubleSpinBoxCarrierPhase.setValue(self.current_modulator.carrier_phase_deg) - self.ui.spinBoxSamplesPerSymbol.setValue(self.current_modulator.samples_per_symbol) + self.ui.doubleSpinBoxCarrierFreq.setValue( + self.current_modulator.carrier_freq_hz + ) + self.ui.doubleSpinBoxCarrierPhase.setValue( + self.current_modulator.carrier_phase_deg + ) + self.ui.spinBoxSamplesPerSymbol.setValue( + self.current_modulator.samples_per_symbol + ) self.ui.spinBoxSampleRate.setValue(self.current_modulator.sample_rate) self.ui.spinBoxBitsPerSymbol.setValue(self.current_modulator.bits_per_symbol) self.update_modulation_parameters() def create_connects(self): - self.ui.doubleSpinBoxCarrierFreq.valueChanged.connect(self.on_carrier_freq_changed) - self.ui.doubleSpinBoxCarrierPhase.valueChanged.connect(self.on_carrier_phase_changed) - self.ui.spinBoxSamplesPerSymbol.valueChanged.connect(self.on_samples_per_symbol_changed) + self.ui.doubleSpinBoxCarrierFreq.valueChanged.connect( + self.on_carrier_freq_changed + ) + self.ui.doubleSpinBoxCarrierPhase.valueChanged.connect( + self.on_carrier_phase_changed + ) + self.ui.spinBoxSamplesPerSymbol.valueChanged.connect( + self.on_samples_per_symbol_changed + ) self.ui.spinBoxSampleRate.valueChanged.connect(self.on_sample_rate_changed) self.ui.linEdDataBits.textChanged.connect(self.on_data_bits_changed) - self.ui.spinBoxBitsPerSymbol.valueChanged.connect(self.on_bits_per_symbol_changed) - self.ui.comboBoxModulationType.currentIndexChanged.connect(self.on_modulation_type_changed) + self.ui.spinBoxBitsPerSymbol.valueChanged.connect( + self.on_bits_per_symbol_changed + ) + self.ui.comboBoxModulationType.currentIndexChanged.connect( + self.on_modulation_type_changed + ) self.ui.gVOriginalSignal.zoomed.connect(self.on_orig_signal_zoomed) - self.ui.cbShowDataBitsOnly.stateChanged.connect(self.on_show_data_bits_only_changed) + self.ui.cbShowDataBitsOnly.stateChanged.connect( + self.on_show_data_bits_only_changed + ) self.ui.btnSearchNext.clicked.connect(self.on_btn_next_search_result_clicked) self.ui.btnSearchPrev.clicked.connect(self.on_btn_prev_search_result_clicked) - self.ui.comboBoxCustomModulations.editTextChanged.connect(self.on_custom_modulation_name_edited) - self.ui.comboBoxCustomModulations.currentIndexChanged.connect(self.on_custom_modulation_index_changed) + self.ui.comboBoxCustomModulations.editTextChanged.connect( + self.on_custom_modulation_name_edited + ) + self.ui.comboBoxCustomModulations.currentIndexChanged.connect( + self.on_custom_modulation_index_changed + ) self.ui.btnAddModulation.clicked.connect(self.add_modulator) self.ui.btnRemoveModulation.clicked.connect(self.on_remove_modulator_clicked) self.ui.gVModulated.zoomed.connect(self.on_carrier_data_modulated_zoomed) self.ui.gVCarrier.zoomed.connect(self.on_carrier_data_modulated_zoomed) self.ui.gVData.zoomed.connect(self.on_carrier_data_modulated_zoomed) - self.ui.gVModulated.selection_width_changed.connect(self.on_modulated_selection_changed) - self.ui.gVOriginalSignal.selection_width_changed.connect(self.on_original_selection_changed) + self.ui.gVModulated.selection_width_changed.connect( + self.on_modulated_selection_changed + ) + self.ui.gVOriginalSignal.selection_width_changed.connect( + self.on_original_selection_changed + ) self.ui.spinBoxGaussBT.valueChanged.connect(self.on_gauss_bt_changed) - self.ui.spinBoxGaussFilterWidth.valueChanged.connect(self.on_gauss_filter_width_changed) + self.ui.spinBoxGaussFilterWidth.valueChanged.connect( + self.on_gauss_filter_width_changed + ) self.ui.chkBoxLockSIV.stateChanged.connect(self.on_lock_siv_changed) self.ui.gVOriginalSignal.signal_loaded.connect(self.handle_signal_loaded) self.ui.btnAutoDetect.clicked.connect(self.on_btn_autodetect_clicked) - self.restore_bits_action.triggered.connect(self.on_restore_bits_action_triggered) - self.configure_parameters_action.triggered.connect(self.on_configure_parameters_action_triggered) - self.ui.lineEditParameters.editingFinished.connect(self.on_line_edit_parameters_editing_finished) + self.restore_bits_action.triggered.connect( + self.on_restore_bits_action_triggered + ) + self.configure_parameters_action.triggered.connect( + self.on_configure_parameters_action_triggered + ) + self.ui.lineEditParameters.editingFinished.connect( + self.on_line_edit_parameters_editing_finished + ) def draw_carrier(self): self.ui.gVCarrier.plot_data(self.current_modulator.carrier_data) @@ -207,7 +255,10 @@ def update_views(self): self.ui.gVOriginalSignal.update() def search_data_sequence(self): - if not self.ui.cbShowDataBitsOnly.isEnabled() or not self.ui.cbShowDataBitsOnly.isChecked(): + if ( + not self.ui.cbShowDataBitsOnly.isEnabled() + or not self.ui.cbShowDataBitsOnly.isChecked() + ): return search_seq = self.ui.linEdDataBits.text() @@ -235,7 +286,9 @@ def show_search_result(self, i: int): message, start_index, end_index = self.search_results[i] - start, nsamples = self.protocol.get_samplepos_of_bitseq(message, start_index, message, end_index, False) + start, nsamples = self.protocol.get_samplepos_of_bitseq( + message, start_index, message, end_index, False + ) self.draw_original_signal(start=start, end=start + nsamples) self.ui.lCurrentSearchResult.setText(str(i + 1)) @@ -255,7 +308,9 @@ def add_modulator(self): self.ui.btnRemoveModulation.setEnabled(True) def adjust_samples_in_view(self, target_siv: float): - self.ui.gVOriginalSignal.scale(self.ui.gVOriginalSignal.view_rect().width() / target_siv, 1) + self.ui.gVOriginalSignal.scale( + self.ui.gVOriginalSignal.view_rect().width() / target_siv, 1 + ) mod_zoom_factor = self.ui.gVModulated.view_rect().width() / target_siv self.ui.gVModulated.scale(mod_zoom_factor, 1) self.ui.gVCarrier.scale(mod_zoom_factor, 1) @@ -271,8 +326,12 @@ def detect_fsk_frequencies(self): if not self.current_modulator.is_binary_modulation: raise NotImplementedError() - zero_freq = self.protocol.estimate_frequency_for_zero(self.current_modulator.sample_rate) - one_freq = self.protocol.estimate_frequency_for_one(self.current_modulator.sample_rate) + zero_freq = self.protocol.estimate_frequency_for_zero( + self.current_modulator.sample_rate + ) + one_freq = self.protocol.estimate_frequency_for_one( + self.current_modulator.sample_rate + ) zero_freq = self.__trim_number(zero_freq) one_freq = self.__trim_number(one_freq) zero_freq, one_freq = self.__ensure_multitude(zero_freq, one_freq) @@ -297,7 +356,9 @@ def handle_signal_loaded(self, protocol): self.protocol = protocol # Apply bit length of original signal to current modulator - self.ui.spinBoxSamplesPerSymbol.setValue(self.ui.gVOriginalSignal.signal.samples_per_symbol) + self.ui.spinBoxSamplesPerSymbol.setValue( + self.ui.gVOriginalSignal.signal.samples_per_symbol + ) # https://github.com/jopohl/urh/issues/130 self.ui.gVModulated.show_full_scene(reinitialize=True) @@ -307,15 +368,21 @@ def handle_signal_loaded(self, protocol): self.unsetCursor() def mark_samples_in_view(self): - self.ui.lSamplesInViewModulated.setText(str(int(self.ui.gVModulated.view_rect().width()))) + self.ui.lSamplesInViewModulated.setText( + str(int(self.ui.gVModulated.view_rect().width())) + ) if self.ui.gVOriginalSignal.scene_manager is not None: - self.ui.lSamplesInViewOrigSignal.setText(str(int(self.ui.gVOriginalSignal.view_rect().width()))) + self.ui.lSamplesInViewOrigSignal.setText( + str(int(self.ui.gVOriginalSignal.view_rect().width())) + ) else: self.ui.lSamplesInViewOrigSignal.setText("-") return - if int(self.ui.gVOriginalSignal.view_rect().width()) != int(self.ui.gVModulated.view_rect().width()): + if int(self.ui.gVOriginalSignal.view_rect().width()) != int( + self.ui.gVModulated.view_rect().width() + ): font = self.ui.lSamplesInViewModulated.font() font.setBold(False) self.ui.lSamplesInViewModulated.setFont(font) @@ -333,7 +400,9 @@ def mark_samples_in_view(self): self.ui.lSamplesInViewModulated.setStyleSheet("") def set_default_modulation_parameters(self): - self.current_modulator.parameters = self.current_modulator.get_default_parameters() + self.current_modulator.parameters = ( + self.current_modulator.get_default_parameters() + ) self.update_modulation_parameters() def set_modulation_profile_status(self): @@ -393,19 +462,25 @@ def show_full_scene(self): @pyqtSlot() def on_carrier_freq_changed(self): - self.current_modulator.carrier_freq_hz = self.ui.doubleSpinBoxCarrierFreq.value() + self.current_modulator.carrier_freq_hz = ( + self.ui.doubleSpinBoxCarrierFreq.value() + ) self.draw_carrier() self.draw_modulated() @pyqtSlot() def on_carrier_phase_changed(self): - self.current_modulator.carrier_phase_deg = self.ui.doubleSpinBoxCarrierPhase.value() + self.current_modulator.carrier_phase_deg = ( + self.ui.doubleSpinBoxCarrierPhase.value() + ) self.draw_carrier() self.draw_modulated() @pyqtSlot() def on_samples_per_symbol_changed(self): - self.current_modulator.samples_per_symbol = self.ui.spinBoxSamplesPerSymbol.value() + self.current_modulator.samples_per_symbol = ( + self.ui.spinBoxSamplesPerSymbol.value() + ) self.draw_carrier() self.draw_data_bits() self.draw_modulated() @@ -414,7 +489,7 @@ def on_samples_per_symbol_changed(self): @pyqtSlot() def on_data_bits_changed(self): text = self.ui.linEdDataBits.text() - text = ''.join(c for c in text if c == "1" or c == "0") + text = "".join(c for c in text if c == "1" or c == "0") self.ui.linEdDataBits.blockSignals(True) self.ui.linEdDataBits.setText(text) self.ui.linEdDataBits.blockSignals(False) @@ -428,7 +503,9 @@ def on_data_bits_changed(self): else: display_text = text self.ui.cbShowDataBitsOnly.setToolTip(text) - self.ui.cbShowDataBitsOnly.setText(self.tr("Show Only Data Sequence\n") + "(" + display_text + ")") + self.ui.cbShowDataBitsOnly.setText( + self.tr("Show Only Data Sequence\n") + "(" + display_text + ")" + ) else: self.ui.cbShowDataBitsOnly.setToolTip("") self.ui.cbShowDataBitsOnly.setText(self.tr("Show Only Data Sequence\n")) @@ -451,22 +528,28 @@ def on_gauss_bt_changed(self): @pyqtSlot() def on_gauss_filter_width_changed(self): - self.current_modulator.gauss_filter_width = self.ui.spinBoxGaussFilterWidth.value() + self.current_modulator.gauss_filter_width = ( + self.ui.spinBoxGaussFilterWidth.value() + ) self.draw_modulated() @pyqtSlot() def on_bits_per_symbol_changed(self): - if self.current_modulator.bits_per_symbol == self.ui.spinBoxBitsPerSymbol.value(): + if ( + self.current_modulator.bits_per_symbol + == self.ui.spinBoxBitsPerSymbol.value() + ): return self.current_modulator.bits_per_symbol = self.ui.spinBoxBitsPerSymbol.value() self.set_default_modulation_parameters() self.draw_modulated() self.show_full_scene() - @pyqtSlot() def on_modulation_type_changed(self): - write_default_parameters = self.current_modulator.modulation_type != self.__cur_selected_mod_type() + write_default_parameters = ( + self.current_modulator.modulation_type != self.__cur_selected_mod_type() + ) self.current_modulator.modulation_type = self.__cur_selected_mod_type() self.__set_gauss_ui_visibility(self.__cur_selected_mod_type() == "GFSK") @@ -490,7 +573,10 @@ def on_orig_signal_zoomed(self): if self.lock_samples_in_view: self.adjust_samples_in_view(self.ui.gVOriginalSignal.view_rect().width()) - x = self.ui.gVOriginalSignal.view_rect().x() + self.ui.gVOriginalSignal.view_rect().width() / 2 + x = ( + self.ui.gVOriginalSignal.view_rect().x() + + self.ui.gVOriginalSignal.view_rect().width() / 2 + ) y = 0 self.ui.gVModulated.centerOn(x, y) @@ -501,7 +587,6 @@ def on_orig_signal_zoomed(self): @pyqtSlot(float) def on_carrier_data_modulated_zoomed(self, factor: float): - x = self.sender().view_rect().x() + self.sender().view_rect().width() / 2 y = 0 for gv in (self.ui.gVCarrier, self.ui.gVData, self.ui.gVModulated): @@ -582,8 +667,11 @@ def on_btn_autodetect_clicked(self): freq = self.current_modulator.estimate_carrier_frequency(signal, self.protocol) if freq is None or freq == 0: - QMessageBox.information(self, self.tr("No results"), - self.tr("Unable to detect parameters from current signal")) + QMessageBox.information( + self, + self.tr("No results"), + self.tr("Unable to detect parameters from current signal"), + ) return self.ui.doubleSpinBoxCarrierFreq.setValue(freq) @@ -600,8 +688,11 @@ def on_original_selection_changed(self, new_width: int): @pyqtSlot() def on_configure_parameters_action_triggered(self): self.ui.lineEditParameters.editingFinished.emit() - dialog = ModulationParametersDialog(self.current_modulator.parameters, self.current_modulator.modulation_type, - self) + dialog = ModulationParametersDialog( + self.current_modulator.parameters, + self.current_modulator.modulation_type, + self, + ) dialog.accepted.connect(self.update_modulation_parameters) dialog.show() @@ -616,13 +707,13 @@ def on_line_edit_parameters_editing_finished(self): param = param.upper().replace(",", ".") factor = 1 if param.endswith("G"): - factor = 10 ** 9 + factor = 10**9 param = param[:-1] elif param.endswith("M"): - factor = 10 ** 6 + factor = 10**6 param = param[:-1] elif param.endswith("K"): - factor = 10 ** 3 + factor = 10**3 param = param[:-1] try: diff --git a/src/urh/controller/dialogs/OptionsDialog.py b/src/urh/controller/dialogs/OptionsDialog.py index 8a0d543869..450df8c2e1 100644 --- a/src/urh/controller/dialogs/OptionsDialog.py +++ b/src/urh/controller/dialogs/OptionsDialog.py @@ -5,10 +5,26 @@ import time import numpy as np -from PyQt5.QtCore import Qt, pyqtSlot, pyqtSignal, QSize, QAbstractTableModel, QModelIndex +from PyQt5.QtCore import ( + Qt, + pyqtSlot, + pyqtSignal, + QSize, + QAbstractTableModel, + QModelIndex, +) from PyQt5.QtGui import QCloseEvent, QIcon, QPixmap -from PyQt5.QtWidgets import QDialog, QHBoxLayout, QCompleter, QDirModel, QApplication, QHeaderView, QRadioButton, \ - QFileDialog, qApp +from PyQt5.QtWidgets import ( + QDialog, + QHBoxLayout, + QCompleter, + QDirModel, + QApplication, + QHeaderView, + QRadioButton, + QFileDialog, + qApp, +) from urh import settings, colormaps from urh.controller.widgets.PluginFrame import PluginFrame @@ -25,7 +41,12 @@ class DeviceOptionsTableModel(QAbstractTableModel): - header_labels = ["Software Defined Radio", "Info", "Native backend (recommended)", "GNU Radio backend"] + header_labels = [ + "Software Defined Radio", + "Info", + "Native backend (recommended)", + "GNU Radio backend", + ] def __init__(self, backend_handler: BackendHandler, parent=None): self.backend_handler = backend_handler @@ -48,7 +69,9 @@ def headerData(self, section, orientation, role=Qt.DisplayRole): return super().headerData(section, orientation, role) def get_device_at(self, index: int): - dev_key = self.backend_handler.get_key_from_device_display_text(self.backend_handler.DEVICE_NAMES[index]) + dev_key = self.backend_handler.get_key_from_device_display_text( + self.backend_handler.DEVICE_NAMES[index] + ) return self.backend_handler.device_backends[dev_key] def data(self, index: QModelIndex, role=Qt.DisplayRole): @@ -83,9 +106,17 @@ def data(self, index: QModelIndex, role=Qt.DisplayRole): if j == 0 and (device.has_native_backend or device.has_gnuradio_backend): return Qt.Checked if device.is_enabled else Qt.Unchecked elif j == 2 and device.has_native_backend: - return Qt.Checked if device.selected_backend == Backends.native else Qt.Unchecked + return ( + Qt.Checked + if device.selected_backend == Backends.native + else Qt.Unchecked + ) elif j == 3 and device.has_gnuradio_backend: - return Qt.Checked if device.selected_backend == Backends.grc else Qt.Unchecked + return ( + Qt.Checked + if device.selected_backend == Backends.grc + else Qt.Unchecked + ) def setData(self, index: QModelIndex, value, role=None): if not index.isValid(): @@ -155,11 +186,15 @@ def __init__(self, installed_plugins, highlighted_plugins=None, parent=None): self.ui.tblDevices.setModel(self.device_options_model) self.ui.tblDevices.horizontalHeader().setSectionResizeMode(QHeaderView.Stretch) - self.ui.tblDevices.setItemDelegateForColumn(1, ComboBoxDelegate(["native", "GNU Radio"])) + self.ui.tblDevices.setItemDelegateForColumn( + 1, ComboBoxDelegate(["native", "GNU Radio"]) + ) self.setAttribute(Qt.WA_DeleteOnClose) layout = QHBoxLayout(self.ui.tab_plugins) - self.plugin_controller = PluginFrame(installed_plugins, highlighted_plugins, parent=self) + self.plugin_controller = PluginFrame( + installed_plugins, highlighted_plugins, parent=self + ) layout.addWidget(self.plugin_controller) self.ui.tab_plugins.setLayout(layout) @@ -172,26 +207,52 @@ def __init__(self, installed_plugins, highlighted_plugins=None, parent=None): self.ui.comboBoxIconTheme.setVisible(sys.platform == "linux") self.ui.comboBoxTheme.setCurrentIndex(settings.read("theme_index", 0, int)) - self.ui.comboBoxIconTheme.setCurrentIndex(settings.read("icon_theme_index", 0, int)) - self.ui.checkBoxShowConfirmCloseDialog.setChecked(not settings.read('not_show_close_dialog', False, bool)) - self.ui.checkBoxHoldShiftToDrag.setChecked(settings.read('hold_shift_to_drag', True, bool)) - self.ui.checkBoxDefaultFuzzingPause.setChecked(settings.read('use_default_fuzzing_pause', True, bool)) - - self.ui.checkBoxAlignLabels.setChecked(settings.read('align_labels', True, bool)) - - self.ui.doubleSpinBoxRAMThreshold.setValue(100 * settings.read('ram_threshold', 0.6, float)) + self.ui.comboBoxIconTheme.setCurrentIndex( + settings.read("icon_theme_index", 0, int) + ) + self.ui.checkBoxShowConfirmCloseDialog.setChecked( + not settings.read("not_show_close_dialog", False, bool) + ) + self.ui.checkBoxHoldShiftToDrag.setChecked( + settings.read("hold_shift_to_drag", True, bool) + ) + self.ui.checkBoxDefaultFuzzingPause.setChecked( + settings.read("use_default_fuzzing_pause", True, bool) + ) + + self.ui.checkBoxAlignLabels.setChecked( + settings.read("align_labels", True, bool) + ) + + self.ui.doubleSpinBoxRAMThreshold.setValue( + 100 * settings.read("ram_threshold", 0.6, float) + ) if self.backend_handler.gr_python_interpreter: - self.ui.lineEditGRPythonInterpreter.setText(self.backend_handler.gr_python_interpreter) - - self.ui.doubleSpinBoxFuzzingPause.setValue(settings.read("default_fuzzing_pause", 10 ** 6, int)) - self.ui.doubleSpinBoxFuzzingPause.setEnabled(settings.read('use_default_fuzzing_pause', True, bool)) - - self.ui.checkBoxMultipleModulations.setChecked(settings.read("multiple_modulations", False, bool)) - - self.ui.radioButtonLowModulationAccuracy.setChecked(Modulator.get_dtype() == np.int8) - self.ui.radioButtonMediumModulationAccuracy.setChecked(Modulator.get_dtype() == np.int16) - self.ui.radioButtonHighModulationAccuracy.setChecked(Modulator.get_dtype() == np.float32) + self.ui.lineEditGRPythonInterpreter.setText( + self.backend_handler.gr_python_interpreter + ) + + self.ui.doubleSpinBoxFuzzingPause.setValue( + settings.read("default_fuzzing_pause", 10**6, int) + ) + self.ui.doubleSpinBoxFuzzingPause.setEnabled( + settings.read("use_default_fuzzing_pause", True, bool) + ) + + self.ui.checkBoxMultipleModulations.setChecked( + settings.read("multiple_modulations", False, bool) + ) + + self.ui.radioButtonLowModulationAccuracy.setChecked( + Modulator.get_dtype() == np.int8 + ) + self.ui.radioButtonMediumModulationAccuracy.setChecked( + Modulator.get_dtype() == np.int16 + ) + self.ui.radioButtonHighModulationAccuracy.setChecked( + Modulator.get_dtype() == np.float32 + ) completer = QCompleter() completer.setModel(QDirModel(completer)) @@ -206,11 +267,19 @@ def __init__(self, installed_plugins, highlighted_plugins=None, parent=None): self.field_type_table_model = FieldTypeTableModel([], parent=self) self.ui.tblLabeltypes.setModel(self.field_type_table_model) - self.ui.tblLabeltypes.horizontalHeader().setSectionResizeMode(QHeaderView.Stretch) - - self.ui.tblLabeltypes.setItemDelegateForColumn(1, ComboBoxDelegate([f.name for f in FieldType.Function], - return_index=False, parent=self)) - self.ui.tblLabeltypes.setItemDelegateForColumn(2, ComboBoxDelegate(ProtocolLabel.DISPLAY_FORMATS, parent=self)) + self.ui.tblLabeltypes.horizontalHeader().setSectionResizeMode( + QHeaderView.Stretch + ) + + self.ui.tblLabeltypes.setItemDelegateForColumn( + 1, + ComboBoxDelegate( + [f.name for f in FieldType.Function], return_index=False, parent=self + ), + ) + self.ui.tblLabeltypes.setItemDelegateForColumn( + 2, ComboBoxDelegate(ProtocolLabel.DISPLAY_FORMATS, parent=self) + ) self.read_options() @@ -219,46 +288,98 @@ def __init__(self, installed_plugins, highlighted_plugins=None, parent=None): self.ui.labelRebuildNativeStatus.setText("") self.show_available_colormaps() - self.restoreGeometry(settings.read("{}/geometry".format(self.__class__.__name__), type=bytes)) + self.restoreGeometry( + settings.read("{}/geometry".format(self.__class__.__name__), type=bytes) + ) def create_connects(self): - self.ui.doubleSpinBoxFuzzingPause.valueChanged.connect(self.on_spinbox_fuzzing_pause_value_changed) - self.ui.lineEditGRPythonInterpreter.editingFinished.connect(self.on_gr_python_interpreter_path_edited) - self.ui.btnChooseGRPythonInterpreter.clicked.connect(self.on_btn_choose_gr_python_interpreter_clicked) - self.ui.comboBoxTheme.currentIndexChanged.connect(self.on_combo_box_theme_index_changed) - self.ui.checkBoxShowConfirmCloseDialog.clicked.connect(self.on_checkbox_confirm_close_dialog_clicked) - self.ui.checkBoxHoldShiftToDrag.clicked.connect(self.on_checkbox_hold_shift_to_drag_clicked) - self.ui.checkBoxAlignLabels.clicked.connect(self.on_checkbox_align_labels_clicked) - self.ui.checkBoxDefaultFuzzingPause.clicked.connect(self.on_checkbox_default_fuzzing_pause_clicked) + self.ui.doubleSpinBoxFuzzingPause.valueChanged.connect( + self.on_spinbox_fuzzing_pause_value_changed + ) + self.ui.lineEditGRPythonInterpreter.editingFinished.connect( + self.on_gr_python_interpreter_path_edited + ) + self.ui.btnChooseGRPythonInterpreter.clicked.connect( + self.on_btn_choose_gr_python_interpreter_clicked + ) + self.ui.comboBoxTheme.currentIndexChanged.connect( + self.on_combo_box_theme_index_changed + ) + self.ui.checkBoxShowConfirmCloseDialog.clicked.connect( + self.on_checkbox_confirm_close_dialog_clicked + ) + self.ui.checkBoxHoldShiftToDrag.clicked.connect( + self.on_checkbox_hold_shift_to_drag_clicked + ) + self.ui.checkBoxAlignLabels.clicked.connect( + self.on_checkbox_align_labels_clicked + ) + self.ui.checkBoxDefaultFuzzingPause.clicked.connect( + self.on_checkbox_default_fuzzing_pause_clicked + ) self.ui.btnAddLabelType.clicked.connect(self.on_btn_add_label_type_clicked) - self.ui.btnRemoveLabeltype.clicked.connect(self.on_btn_remove_label_type_clicked) - self.ui.radioButtonLowModulationAccuracy.clicked.connect(self.on_radio_button_low_modulation_accuracy_clicked) - self.ui.radioButtonMediumModulationAccuracy.clicked.connect(self.on_radio_button_medium_modulation_accuracy_clicked) - self.ui.radioButtonHighModulationAccuracy.clicked.connect(self.on_radio_button_high_modulation_accuracy_clicked) - - self.ui.doubleSpinBoxRAMThreshold.valueChanged.connect(self.on_double_spinbox_ram_threshold_value_changed) + self.ui.btnRemoveLabeltype.clicked.connect( + self.on_btn_remove_label_type_clicked + ) + self.ui.radioButtonLowModulationAccuracy.clicked.connect( + self.on_radio_button_low_modulation_accuracy_clicked + ) + self.ui.radioButtonMediumModulationAccuracy.clicked.connect( + self.on_radio_button_medium_modulation_accuracy_clicked + ) + self.ui.radioButtonHighModulationAccuracy.clicked.connect( + self.on_radio_button_high_modulation_accuracy_clicked + ) + + self.ui.doubleSpinBoxRAMThreshold.valueChanged.connect( + self.on_double_spinbox_ram_threshold_value_changed + ) self.ui.btnRebuildNative.clicked.connect(self.on_btn_rebuild_native_clicked) - self.ui.comboBoxIconTheme.currentIndexChanged.connect(self.on_combobox_icon_theme_index_changed) - self.ui.checkBoxMultipleModulations.clicked.connect(self.on_checkbox_multiple_modulations_clicked) + self.ui.comboBoxIconTheme.currentIndexChanged.connect( + self.on_combobox_icon_theme_index_changed + ) + self.ui.checkBoxMultipleModulations.clicked.connect( + self.on_checkbox_multiple_modulations_clicked + ) self.ui.btnViewBuildLog.clicked.connect(self.on_btn_view_build_log_clicked) - self.ui.labelDeviceMissingInfo.linkActivated.connect(self.on_label_device_missing_info_link_activated) - self.ui.doubleSpinBoxFontSize.editingFinished.connect(self.on_spin_box_font_size_editing_finished) + self.ui.labelDeviceMissingInfo.linkActivated.connect( + self.on_label_device_missing_info_link_activated + ) + self.ui.doubleSpinBoxFontSize.editingFinished.connect( + self.on_spin_box_font_size_editing_finished + ) def show_gnuradio_infos(self): - self.ui.lineEditGRPythonInterpreter.setText(self.backend_handler.gr_python_interpreter) + self.ui.lineEditGRPythonInterpreter.setText( + self.backend_handler.gr_python_interpreter + ) if self.backend_handler.gnuradio_is_installed: - self.ui.lineEditGRPythonInterpreter.setStyleSheet("background-color: lightgreen") - self.ui.lineEditGRPythonInterpreter.setToolTip("GNU Radio interface is working.") + self.ui.lineEditGRPythonInterpreter.setStyleSheet( + "background-color: lightgreen" + ) + self.ui.lineEditGRPythonInterpreter.setToolTip( + "GNU Radio interface is working." + ) else: - self.ui.lineEditGRPythonInterpreter.setStyleSheet("background-color: orange") - self.ui.lineEditGRPythonInterpreter.setToolTip("GNU Radio is not installed or incompatible with " - "the configured python interpreter.") + self.ui.lineEditGRPythonInterpreter.setStyleSheet( + "background-color: orange" + ) + self.ui.lineEditGRPythonInterpreter.setToolTip( + "GNU Radio is not installed or incompatible with " + "the configured python interpreter." + ) def read_options(self): - self.ui.comboBoxDefaultView.setCurrentIndex(settings.read('default_view', 0, type=int)) - self.ui.spinBoxNumSendingRepeats.setValue(settings.read('num_sending_repeats', 0, type=int)) - self.ui.checkBoxPauseTime.setChecked(settings.read('show_pause_as_time', False, type=bool)) + self.ui.comboBoxDefaultView.setCurrentIndex( + settings.read("default_view", 0, type=int) + ) + self.ui.spinBoxNumSendingRepeats.setValue( + settings.read("num_sending_repeats", 0, type=int) + ) + self.ui.checkBoxPauseTime.setChecked( + settings.read("show_pause_as_time", False, type=bool) + ) self.old_show_pause_as_time = bool(self.ui.checkBoxPauseTime.isChecked()) @@ -286,55 +407,80 @@ def show_available_colormaps(self): def closeEvent(self, event: QCloseEvent): changed_values = {} if bool(self.ui.checkBoxPauseTime.isChecked()) != self.old_show_pause_as_time: - changed_values['show_pause_as_time'] = bool(self.ui.checkBoxPauseTime.isChecked()) + changed_values["show_pause_as_time"] = bool( + self.ui.checkBoxPauseTime.isChecked() + ) if self.old_default_view != self.ui.comboBoxDefaultView.currentIndex(): - changed_values['default_view'] = self.ui.comboBoxDefaultView.currentIndex() + changed_values["default_view"] = self.ui.comboBoxDefaultView.currentIndex() if self.old_num_sending_repeats != self.ui.spinBoxNumSendingRepeats.value(): - changed_values["num_sending_repeats"] = self.ui.spinBoxNumSendingRepeats.value() + changed_values[ + "num_sending_repeats" + ] = self.ui.spinBoxNumSendingRepeats.value() - settings.write('default_view', self.ui.comboBoxDefaultView.currentIndex()) - settings.write('num_sending_repeats', self.ui.spinBoxNumSendingRepeats.value()) - settings.write('show_pause_as_time', self.ui.checkBoxPauseTime.isChecked()) + settings.write("default_view", self.ui.comboBoxDefaultView.currentIndex()) + settings.write("num_sending_repeats", self.ui.spinBoxNumSendingRepeats.value()) + settings.write("show_pause_as_time", self.ui.checkBoxPauseTime.isChecked()) FieldType.save_to_xml(self.field_type_table_model.field_types) self.plugin_controller.save_enabled_states() for plugin in self.plugin_controller.model.plugins: plugin.destroy_settings_frame() - for i in range(self.ui.scrollAreaWidgetSpectrogramColormapContents.layout().count()): - widget = self.ui.scrollAreaWidgetSpectrogramColormapContents.layout().itemAt(i).widget() + for i in range( + self.ui.scrollAreaWidgetSpectrogramColormapContents.layout().count() + ): + widget = ( + self.ui.scrollAreaWidgetSpectrogramColormapContents.layout() + .itemAt(i) + .widget() + ) if isinstance(widget, QRadioButton) and widget.isChecked(): selected_colormap_name = widget.objectName() - if selected_colormap_name != colormaps.read_selected_colormap_name_from_settings(): + if ( + selected_colormap_name + != colormaps.read_selected_colormap_name_from_settings() + ): colormaps.choose_colormap(selected_colormap_name) - colormaps.write_selected_colormap_to_settings(selected_colormap_name) + colormaps.write_selected_colormap_to_settings( + selected_colormap_name + ) changed_values["spectrogram_colormap"] = selected_colormap_name break self.values_changed.emit(changed_values) - settings.write("{}/geometry".format(self.__class__.__name__), self.saveGeometry()) + settings.write( + "{}/geometry".format(self.__class__.__name__), self.saveGeometry() + ) super().closeEvent(event) def set_gnuradio_status(self): - self.backend_handler.gr_python_interpreter = self.ui.lineEditGRPythonInterpreter.text() + self.backend_handler.gr_python_interpreter = ( + self.ui.lineEditGRPythonInterpreter.text() + ) self.refresh_device_tab() @pyqtSlot() def on_btn_add_label_type_clicked(self): suffix = 1 - field_type_names = {ft.caption for ft in self.field_type_table_model.field_types} + field_type_names = { + ft.caption for ft in self.field_type_table_model.field_types + } while "New Fieldtype #" + str(suffix) in field_type_names: suffix += 1 caption = "New Fieldtype #" + str(suffix) - self.field_type_table_model.field_types.append(FieldType(caption, FieldType.Function.CUSTOM)) + self.field_type_table_model.field_types.append( + FieldType(caption, FieldType.Function.CUSTOM) + ) self.field_type_table_model.update() @pyqtSlot() def on_btn_remove_label_type_clicked(self): if self.field_type_table_model.field_types: - selected_indices = {i.row() for i in self.ui.tblLabeltypes.selectedIndexes()} + selected_indices = { + i.row() for i in self.ui.tblLabeltypes.selectedIndexes() + } if selected_indices: for i in reversed(sorted(selected_indices)): @@ -355,11 +501,11 @@ def on_checkbox_confirm_close_dialog_clicked(self, checked: bool): @pyqtSlot(int) def on_combo_box_theme_index_changed(self, index: int): - settings.write('theme_index', index) + settings.write("theme_index", index) @pyqtSlot(int) def on_combobox_icon_theme_index_changed(self, index: int): - settings.write('icon_theme_index', index) + settings.write("icon_theme_index", index) util.set_icon_theme() @pyqtSlot(bool) @@ -368,7 +514,7 @@ def on_checkbox_hold_shift_to_drag_clicked(self, checked: bool): @pyqtSlot(bool) def on_checkbox_default_fuzzing_pause_clicked(self, checked: bool): - settings.write('use_default_fuzzing_pause', checked) + settings.write("use_default_fuzzing_pause", checked) self.ui.doubleSpinBoxFuzzingPause.setEnabled(checked) @pyqtSlot(float) @@ -385,7 +531,9 @@ def on_btn_choose_gr_python_interpreter_clicked(self): dialog_filter = "Executable (*.exe);;All files (*.*)" else: dialog_filter = "" - filename, _ = QFileDialog.getOpenFileName(self, self.tr("Choose python interpreter"), filter=dialog_filter) + filename, _ = QFileDialog.getOpenFileName( + self, self.tr("Choose python interpreter"), filter=dialog_filter + ) if filename: self.ui.lineEditGRPythonInterpreter.setText(filename) self.set_gnuradio_status() @@ -396,28 +544,55 @@ def on_checkbox_align_labels_clicked(self, checked: bool): @pyqtSlot() def on_btn_rebuild_native_clicked(self): - library_dirs = None if not self.ui.lineEditLibDirs.text() \ + library_dirs = ( + None + if not self.ui.lineEditLibDirs.text() else list(map(str.strip, self.ui.lineEditLibDirs.text().split(","))) - include_dirs = None if not self.ui.lineEditIncludeDirs.text() \ + ) + include_dirs = ( + None + if not self.ui.lineEditIncludeDirs.text() else list(map(str.strip, self.ui.lineEditIncludeDirs.text().split(","))) + ) - extensions, _ = ExtensionHelper.get_device_extensions_and_extras(library_dirs=library_dirs, include_dirs=include_dirs) + extensions, _ = ExtensionHelper.get_device_extensions_and_extras( + library_dirs=library_dirs, include_dirs=include_dirs + ) - self.ui.labelRebuildNativeStatus.setText(self.tr("Rebuilding device extensions...")) + self.ui.labelRebuildNativeStatus.setText( + self.tr("Rebuilding device extensions...") + ) QApplication.instance().processEvents() - build_cmd = [sys.executable, os.path.realpath(ExtensionHelper.__file__), - "build_ext", "--inplace", "-t", tempfile.gettempdir()] + build_cmd = [ + sys.executable, + os.path.realpath(ExtensionHelper.__file__), + "build_ext", + "--inplace", + "-t", + tempfile.gettempdir(), + ] if library_dirs: build_cmd.extend(["-L", ":".join(library_dirs)]) if include_dirs: build_cmd.extend(["-I", ":".join(include_dirs)]) - subprocess.call([sys.executable, os.path.realpath(ExtensionHelper.__file__), "clean", "--all"]) - p = subprocess.Popen(build_cmd, stdout=subprocess.PIPE, stderr=subprocess.STDOUT) + subprocess.call( + [ + sys.executable, + os.path.realpath(ExtensionHelper.__file__), + "clean", + "--all", + ] + ) + p = subprocess.Popen( + build_cmd, stdout=subprocess.PIPE, stderr=subprocess.STDOUT + ) num_dots = 1 while p.poll() is None: - self.ui.labelRebuildNativeStatus.setText(self.tr("Rebuilding device extensions" + ". " * num_dots)) + self.ui.labelRebuildNativeStatus.setText( + self.tr("Rebuilding device extensions" + ". " * num_dots) + ) QApplication.instance().processEvents() time.sleep(0.1) num_dots %= 10 @@ -425,23 +600,33 @@ def on_btn_rebuild_native_clicked(self): rc = p.returncode if rc == 0: - self.ui.labelRebuildNativeStatus.setText(self.tr("" - "Rebuilt {0} device extensions. " - "" - "Please restart URH.".format(len(extensions)))) + self.ui.labelRebuildNativeStatus.setText( + self.tr( + "" + "Rebuilt {0} device extensions. " + "" + "Please restart URH.".format(len(extensions)) + ) + ) else: - self.ui.labelRebuildNativeStatus.setText(self.tr("" - "Failed to rebuild {0} device extensions. " - "" - "Run URH as root (sudo urh) " - "and try again.".format(len(extensions)))) + self.ui.labelRebuildNativeStatus.setText( + self.tr( + "" + "Failed to rebuild {0} device extensions. " + "" + "Run URH as root (sudo urh) " + "and try again.".format(len(extensions)) + ) + ) self.build_log = p.stdout.read().decode() self.ui.btnViewBuildLog.show() @pyqtSlot() def on_checkbox_multiple_modulations_clicked(self): - settings.write("multiple_modulations", self.ui.checkBoxMultipleModulations.isChecked()) + settings.write( + "multiple_modulations", self.ui.checkBoxMultipleModulations.isChecked() + ) @pyqtSlot() def on_btn_view_build_log_clicked(self): @@ -459,11 +644,18 @@ def on_label_device_missing_info_link_activated(self, link: str): if util.get_shared_library_path(): if sys.platform == "win32": - info += "\n\n[INFO] Used DLLs from " + util.get_shared_library_path() + info += ( + "\n\n[INFO] Used DLLs from " + util.get_shared_library_path() + ) else: - info += "\n\n[INFO] Used shared libraries from " + util.get_shared_library_path() - - d = util.create_textbox_dialog(info, "Health check for native extensions", self) + info += ( + "\n\n[INFO] Used shared libraries from " + + util.get_shared_library_path() + ) + + d = util.create_textbox_dialog( + info, "Health check for native extensions", self + ) d.show() @pyqtSlot() @@ -492,14 +684,14 @@ def on_radio_button_low_modulation_accuracy_clicked(self, checked): def write_default_options(): keys = settings.all_keys() - if 'default_view' not in keys: - settings.write('default_view', 0) + if "default_view" not in keys: + settings.write("default_view", 0) - if 'num_sending_repeats' not in keys: - settings.write('num_sending_repeats', 0) + if "num_sending_repeats" not in keys: + settings.write("num_sending_repeats", 0) - if 'show_pause_as_time' not in keys: - settings.write('show_pause_as_time', False) + if "show_pause_as_time" not in keys: + settings.write("show_pause_as_time", False) settings.sync() # Ensure conf dir is created to have field types in place diff --git a/src/urh/controller/dialogs/ProjectDialog.py b/src/urh/controller/dialogs/ProjectDialog.py index b78c29693b..7431dd125b 100644 --- a/src/urh/controller/dialogs/ProjectDialog.py +++ b/src/urh/controller/dialogs/ProjectDialog.py @@ -17,7 +17,9 @@ class ProjectDialog(QDialog): - def __init__(self, new_project=True, project_manager: ProjectManager = None, parent=None): + def __init__( + self, new_project=True, project_manager: ProjectManager = None, parent=None + ): super().__init__(parent) if not new_project: assert project_manager is not None @@ -29,15 +31,23 @@ def __init__(self, new_project=True, project_manager: ProjectManager = None, par if new_project: self.participant_table_model = ParticipantTableModel([]) else: - self.participant_table_model = ParticipantTableModel(project_manager.participants) + self.participant_table_model = ParticipantTableModel( + project_manager.participants + ) - self.ui.spinBoxSampleRate.setValue(project_manager.device_conf["sample_rate"]) + self.ui.spinBoxSampleRate.setValue( + project_manager.device_conf["sample_rate"] + ) self.ui.spinBoxFreq.setValue(project_manager.device_conf["frequency"]) self.ui.spinBoxBandwidth.setValue(project_manager.device_conf["bandwidth"]) - self.ui.spinBoxGain.setValue(project_manager.device_conf.get("gain", config.DEFAULT_GAIN)) + self.ui.spinBoxGain.setValue( + project_manager.device_conf.get("gain", config.DEFAULT_GAIN) + ) self.ui.txtEdDescription.setPlainText(project_manager.description) self.ui.lineEdit_Path.setText(project_manager.project_path) - self.ui.lineEditBroadcastAddress.setText(project_manager.broadcast_address_hex) + self.ui.lineEditBroadcastAddress.setText( + project_manager.broadcast_address_hex + ) self.ui.btnSelectPath.hide() self.ui.lineEdit_Path.setDisabled(True) @@ -47,7 +57,9 @@ def __init__(self, new_project=True, project_manager: ProjectManager = None, par self.ui.tblParticipants.setModel(self.participant_table_model) self.participant_table_model.update() - self.ui.lineEditBroadcastAddress.setValidator(QRegExpValidator(QRegExp("([a-fA-F ]|[0-9]){,}"))) + self.ui.lineEditBroadcastAddress.setValidator( + QRegExpValidator(QRegExp("([a-fA-F ]|[0-9]){,}")) + ) self.sample_rate = self.ui.spinBoxSampleRate.value() self.freq = self.ui.spinBoxFreq.value() @@ -72,10 +84,14 @@ def __init__(self, new_project=True, project_manager: ProjectManager = None, par self.ui.btnAddParticipant.click() if new_project: - self.ui.lineEdit_Path.setText(os.path.realpath(os.path.join(os.curdir, "new"))) + self.ui.lineEdit_Path.setText( + os.path.realpath(os.path.join(os.curdir, "new")) + ) self.on_line_edit_path_text_edited() - self.restoreGeometry(settings.read("{}/geometry".format(self.__class__.__name__), type=bytes)) + self.restoreGeometry( + settings.read("{}/geometry".format(self.__class__.__name__), type=bytes) + ) @property def participants(self): @@ -86,23 +102,43 @@ def participants(self): return self.participant_table_model.participants def create_connects(self): - self.ui.spinBoxFreq.valueChanged.connect(self.on_spin_box_frequency_value_changed) - self.ui.spinBoxSampleRate.valueChanged.connect(self.on_spin_box_sample_rate_value_changed) - self.ui.spinBoxBandwidth.valueChanged.connect(self.on_spin_box_bandwidth_value_changed) + self.ui.spinBoxFreq.valueChanged.connect( + self.on_spin_box_frequency_value_changed + ) + self.ui.spinBoxSampleRate.valueChanged.connect( + self.on_spin_box_sample_rate_value_changed + ) + self.ui.spinBoxBandwidth.valueChanged.connect( + self.on_spin_box_bandwidth_value_changed + ) self.ui.spinBoxGain.valueChanged.connect(self.on_spin_box_gain_value_changed) - self.ui.txtEdDescription.textChanged.connect(self.on_txt_edit_description_text_changed) - self.ui.lineEditBroadcastAddress.textEdited.connect(self.on_line_edit_broadcast_address_text_edited) - - self.ui.btnAddParticipant.clicked.connect(self.ui.tblParticipants.on_add_action_triggered) - self.ui.btnRemoveParticipant.clicked.connect(self.ui.tblParticipants.on_remove_action_triggered) - self.ui.btnUp.clicked.connect(self.ui.tblParticipants.on_move_up_action_triggered) - self.ui.btnDown.clicked.connect(self.ui.tblParticipants.on_move_down_action_triggered) + self.ui.txtEdDescription.textChanged.connect( + self.on_txt_edit_description_text_changed + ) + self.ui.lineEditBroadcastAddress.textEdited.connect( + self.on_line_edit_broadcast_address_text_edited + ) + + self.ui.btnAddParticipant.clicked.connect( + self.ui.tblParticipants.on_add_action_triggered + ) + self.ui.btnRemoveParticipant.clicked.connect( + self.ui.tblParticipants.on_remove_action_triggered + ) + self.ui.btnUp.clicked.connect( + self.ui.tblParticipants.on_move_up_action_triggered + ) + self.ui.btnDown.clicked.connect( + self.ui.tblParticipants.on_move_down_action_triggered + ) self.ui.lineEdit_Path.textEdited.connect(self.on_line_edit_path_text_edited) self.ui.buttonBox.accepted.connect(self.on_button_box_accepted) self.ui.buttonBox.rejected.connect(self.reject) self.ui.btnSelectPath.clicked.connect(self.on_btn_select_path_clicked) - self.ui.lOpenSpectrumAnalyzer.linkActivated.connect(self.on_spectrum_analyzer_link_activated) + self.ui.lOpenSpectrumAnalyzer.linkActivated.connect( + self.on_spectrum_analyzer_link_activated + ) def set_path(self, path): self.path = path @@ -113,7 +149,9 @@ def set_path(self, path): self.ui.lblNewPath.setVisible(not os.path.isdir(self.path)) def closeEvent(self, event: QCloseEvent): - settings.write("{}/geometry".format(self.__class__.__name__), self.saveGeometry()) + settings.write( + "{}/geometry".format(self.__class__.__name__), self.saveGeometry() + ) super().closeEvent(event) @pyqtSlot(float) @@ -183,5 +221,7 @@ def on_spectrum_analyzer_link_activated(self, link: str): r.close() return - r.device_parameters_changed.connect(self.set_recording_params_from_spectrum_analyzer_link) + r.device_parameters_changed.connect( + self.set_recording_params_from_spectrum_analyzer_link + ) r.show() diff --git a/src/urh/controller/dialogs/ProtocolLabelDialog.py b/src/urh/controller/dialogs/ProtocolLabelDialog.py index e6db628917..ea86795c2d 100644 --- a/src/urh/controller/dialogs/ProtocolLabelDialog.py +++ b/src/urh/controller/dialogs/ProtocolLabelDialog.py @@ -24,7 +24,9 @@ class ProtocolLabelDialog(QDialog): SPECIAL_CONFIG_TYPES = [FieldType.Function.CHECKSUM] - def __init__(self, message: Message, viewtype: int, selected_index=None, parent=None): + def __init__( + self, message: Message, viewtype: int, selected_index=None, parent=None + ): super().__init__(parent) self.ui = Ui_DialogLabels() self.ui.setupUi(self) @@ -33,24 +35,43 @@ def __init__(self, message: Message, viewtype: int, selected_index=None, parent= field_types = FieldType.load_from_xml() self.model = PLabelTableModel(message, field_types) - self.ui.tblViewProtoLabels.setItemDelegateForColumn(0, ComboBoxDelegate([ft.caption for ft in field_types], - is_editable=True, - return_index=False, parent=self)) - self.ui.tblViewProtoLabels.setItemDelegateForColumn(1, SpinBoxDelegate(1, len(message), self)) - self.ui.tblViewProtoLabels.setItemDelegateForColumn(2, SpinBoxDelegate(1, len(message), self)) - self.ui.tblViewProtoLabels.setItemDelegateForColumn(3, - ComboBoxDelegate([""] * len(settings.LABEL_COLORS), - colors=settings.LABEL_COLORS, - parent=self)) + self.ui.tblViewProtoLabels.setItemDelegateForColumn( + 0, + ComboBoxDelegate( + [ft.caption for ft in field_types], + is_editable=True, + return_index=False, + parent=self, + ), + ) + self.ui.tblViewProtoLabels.setItemDelegateForColumn( + 1, SpinBoxDelegate(1, len(message), self) + ) + self.ui.tblViewProtoLabels.setItemDelegateForColumn( + 2, SpinBoxDelegate(1, len(message), self) + ) + self.ui.tblViewProtoLabels.setItemDelegateForColumn( + 3, + ComboBoxDelegate( + [""] * len(settings.LABEL_COLORS), + colors=settings.LABEL_COLORS, + parent=self, + ), + ) self.ui.tblViewProtoLabels.setItemDelegateForColumn(4, CheckBoxDelegate(self)) self.ui.tblViewProtoLabels.setModel(self.model) self.ui.tblViewProtoLabels.setEditTriggers(QAbstractItemView.AllEditTriggers) - self.ui.tblViewProtoLabels.horizontalHeader().setSectionResizeMode(QHeaderView.Stretch) + self.ui.tblViewProtoLabels.horizontalHeader().setSectionResizeMode( + QHeaderView.Stretch + ) self.ui.tblViewProtoLabels.resizeColumnsToContents() self.setWindowFlags(Qt.Window) - self.setWindowTitle(self.tr("Edit Protocol Labels From Message Type %s") % message.message_type.name) + self.setWindowTitle( + self.tr("Edit Protocol Labels From Message Type %s") + % message.message_type.name + ) self.configure_special_config_tabs() self.ui.splitter.setSizes([int(self.height() / 2), int(self.height() / 2)]) @@ -58,13 +79,17 @@ def __init__(self, message: Message, viewtype: int, selected_index=None, parent= self.create_connects() if selected_index is not None: - self.ui.tblViewProtoLabels.setCurrentIndex(self.model.index(selected_index, 0)) + self.ui.tblViewProtoLabels.setCurrentIndex( + self.model.index(selected_index, 0) + ) self.ui.cbProtoView.setCurrentIndex(viewtype) self.setAttribute(Qt.WA_DeleteOnClose) self.setWindowFlags(Qt.Window) - self.restoreGeometry(settings.read("{}/geometry".format(self.__class__.__name__), type=bytes)) + self.restoreGeometry( + settings.read("{}/geometry".format(self.__class__.__name__), type=bytes) + ) for i in range(self.model.rowCount()): self.open_editors(i) @@ -75,24 +100,34 @@ def configure_special_config_tabs(self): if isinstance(lbl, SimulatorProtocolLabel): lbl = lbl.label - if lbl.field_type is not None and lbl.field_type.function in self.SPECIAL_CONFIG_TYPES: + if ( + lbl.field_type is not None + and lbl.field_type.function in self.SPECIAL_CONFIG_TYPES + ): if isinstance(lbl, ChecksumLabel): w = ChecksumWidget(lbl, self.model.message, self.model.proto_view) self.ui.tabWidgetAdvancedSettings.addTab(w, lbl.name) else: - logger.error("No Special Config Dialog for field type " + lbl.field_type.caption) + logger.error( + "No Special Config Dialog for field type " + + lbl.field_type.caption + ) if self.ui.tabWidgetAdvancedSettings.count() > 0: self.ui.tabWidgetAdvancedSettings.setCurrentIndex(0) self.ui.tabWidgetAdvancedSettings.setFocus() - self.ui.groupBoxAdvancedSettings.setVisible(self.ui.tabWidgetAdvancedSettings.count() > 0) + self.ui.groupBoxAdvancedSettings.setVisible( + self.ui.tabWidgetAdvancedSettings.count() > 0 + ) def create_connects(self): self.ui.btnConfirm.clicked.connect(self.confirm) self.ui.cbProtoView.currentIndexChanged.connect(self.set_view_index) self.model.apply_decoding_changed.connect(self.on_apply_decoding_changed) - self.model.special_status_label_changed.connect(self.on_label_special_status_changed) + self.model.special_status_label_changed.connect( + self.on_label_special_status_changed + ) def open_editors(self, row): self.ui.tblViewProtoLabels.openPersistentEditor(self.model.index(row, 4)) @@ -104,7 +139,9 @@ def keyPressEvent(self, event: QKeyEvent): event.accept() def closeEvent(self, event: QCloseEvent): - settings.write("{}/geometry".format(self.__class__.__name__), self.saveGeometry()) + settings.write( + "{}/geometry".format(self.__class__.__name__), self.saveGeometry() + ) super().closeEvent(event) @pyqtSlot() diff --git a/src/urh/controller/dialogs/ProtocolSniffDialog.py b/src/urh/controller/dialogs/ProtocolSniffDialog.py index f0e6ca8942..8801fd9161 100644 --- a/src/urh/controller/dialogs/ProtocolSniffDialog.py +++ b/src/urh/controller/dialogs/ProtocolSniffDialog.py @@ -12,8 +12,17 @@ class ProtocolSniffDialog(SendRecvDialog): protocol_accepted = pyqtSignal(list) - def __init__(self, project_manager, signal=None, signals=None, parent=None, testing_mode=False): - super().__init__(project_manager, is_tx=False, parent=parent, testing_mode=testing_mode) + def __init__( + self, + project_manager, + signal=None, + signals=None, + parent=None, + testing_mode=False, + ): + super().__init__( + project_manager, is_tx=False, parent=parent, testing_mode=testing_mode + ) self.graphics_view = self.ui.graphicsView_sniff_Preview self.ui.stackedWidget.setCurrentWidget(self.ui.page_sniff) @@ -24,11 +33,16 @@ def __init__(self, project_manager, signal=None, signals=None, parent=None, test signals = [] if signals is None else signals - self.sniff_settings_widget = SniffSettingsWidget(project_manager=project_manager, - device_name=self.selected_device_name, - signal=signal, signals=signals, - backend_handler=self.backend_handler) - self.ui.scrollAreaWidgetContents_2.layout().insertWidget(1, self.sniff_settings_widget) + self.sniff_settings_widget = SniffSettingsWidget( + project_manager=project_manager, + device_name=self.selected_device_name, + signal=signal, + signals=signals, + backend_handler=self.backend_handler, + ) + self.ui.scrollAreaWidgetContents_2.layout().insertWidget( + 1, self.sniff_settings_widget + ) self.sniff_settings_widget.ui.btn_sniff_use_signal.setAutoDefault(False) self.sniffer = self.sniff_settings_widget.sniffer @@ -57,19 +71,27 @@ def closeEvent(self, event: QCloseEvent): def create_connects(self): super().create_connects() self.ui.btnAccept.clicked.connect(self.on_btn_accept_clicked) - self.sniff_settings_widget.sniff_parameters_changed.connect(self.device_parameters_changed.emit) + self.sniff_settings_widget.sniff_parameters_changed.connect( + self.device_parameters_changed.emit + ) - self.sniff_settings_widget.sniff_setting_edited.connect(self.on_sniff_setting_edited) + self.sniff_settings_widget.sniff_setting_edited.connect( + self.on_sniff_setting_edited + ) self.sniff_settings_widget.sniff_file_edited.connect(self.on_sniff_file_edited) self.sniffer.message_sniffed.connect(self.on_message_sniffed) - self.sniffer.qt_signals.sniff_device_errors_changed.connect(self.on_device_errors_changed) + self.sniffer.qt_signals.sniff_device_errors_changed.connect( + self.on_device_errors_changed + ) def init_device(self): self.sniffer.device_name = self.selected_device_name self.device = self.sniffer.rcv_device self._create_device_connects() - self.scene_manager = SniffSceneManager(np.array([], dtype=self.device.data_type), parent=self) + self.scene_manager = SniffSceneManager( + np.array([], dtype=self.device.data_type), parent=self + ) def emit_editing_finished_signals(self): super().emit_editing_finished_signals() @@ -84,7 +106,9 @@ def update_view(self): @pyqtSlot() def on_device_started(self): - self.scene_manager.data_array = self.device.data.real if hasattr(self.device.data, "real") else None + self.scene_manager.data_array = ( + self.device.data.real if hasattr(self.device.data, "real") else None + ) super().on_device_started() @@ -93,8 +117,11 @@ def on_device_started(self): @pyqtSlot() def on_sniff_setting_edited(self): - self.ui.txtEd_sniff_Preview.setPlainText(self.sniffer.decoded_to_string(self.view_type, - include_timestamps=self.show_timestamp)) + self.ui.txtEd_sniff_Preview.setPlainText( + self.sniffer.decoded_to_string( + self.view_type, include_timestamps=self.show_timestamp + ) + ) @pyqtSlot() def on_start_clicked(self): @@ -118,11 +145,14 @@ def on_message_sniffed(self, index: int): msg = self.sniffer.messages[index] except IndexError: return - new_data = self.sniffer.message_to_string(msg, self.view_type, include_timestamps=self.show_timestamp) + new_data = self.sniffer.message_to_string( + msg, self.view_type, include_timestamps=self.show_timestamp + ) if new_data.strip(): self.ui.txtEd_sniff_Preview.appendPlainText(new_data) self.ui.txtEd_sniff_Preview.verticalScrollBar().setValue( - self.ui.txtEd_sniff_Preview.verticalScrollBar().maximum()) + self.ui.txtEd_sniff_Preview.verticalScrollBar().maximum() + ) @pyqtSlot() def on_btn_accept_clicked(self): diff --git a/src/urh/controller/dialogs/ReceiveDialog.py b/src/urh/controller/dialogs/ReceiveDialog.py index 4338b3aa5c..d319fbe1eb 100644 --- a/src/urh/controller/dialogs/ReceiveDialog.py +++ b/src/urh/controller/dialogs/ReceiveDialog.py @@ -10,12 +10,15 @@ from urh.util.Formatter import Formatter from datetime import datetime + class ReceiveDialog(SendRecvDialog): files_recorded = pyqtSignal(list, float) def __init__(self, project_manager, parent=None, testing_mode=False): try: - super().__init__(project_manager, is_tx=False, parent=parent, testing_mode=testing_mode) + super().__init__( + project_manager, is_tx=False, parent=parent, testing_mode=testing_mode + ) except ValueError: return @@ -39,9 +42,12 @@ def create_connects(self): def save_before_close(self): if not self.already_saved and self.device.current_index > 0: - reply = QMessageBox.question(self, self.tr("Save data?"), - self.tr("Do you want to save the data you have captured so far?"), - QMessageBox.Yes | QMessageBox.No | QMessageBox.Abort) + reply = QMessageBox.question( + self, + self.tr("Save data?"), + self.tr("Do you want to save the data you have captured so far?"), + QMessageBox.Yes | QMessageBox.No | QMessageBox.Abort, + ) if reply == QMessageBox.Yes: self.on_save_clicked() elif reply == QMessageBox.Abort: @@ -63,10 +69,17 @@ def update_view(self): self.graphics_view.update() def init_device(self): - self.device = VirtualDevice(self.backend_handler, self.selected_device_name, Mode.receive, - device_ip="192.168.10.2", parent=self) + self.device = VirtualDevice( + self.backend_handler, + self.selected_device_name, + Mode.receive, + device_ip="192.168.10.2", + parent=self, + ) self._create_device_connects() - self.scene_manager = LiveSceneManager(np.array([], dtype=self.device.data_type), parent=self) + self.scene_manager = LiveSceneManager( + np.array([], dtype=self.device.data_type), parent=self + ) @pyqtSlot() def on_start_clicked(self): @@ -75,7 +88,9 @@ def on_start_clicked(self): @pyqtSlot() def on_device_started(self): - self.scene_manager.plot_data = self.device.data.real if self.device.data is not None else None + self.scene_manager.plot_data = ( + self.device.data.real if self.device.data is not None else None + ) super().on_device_started() @@ -90,21 +105,25 @@ def on_clear_clicked(self): @pyqtSlot() def on_save_clicked(self): - data = self.device.data[:self.device.current_index] + data = self.device.data[: self.device.current_index] dev = self.device big_val = Formatter.big_value_with_suffix timestamp = datetime.now().strftime("%Y%m%d_%H%M%S") - initial_name = "{0}-{1}-{2}Hz-{3}Sps".format(dev.name, timestamp, - big_val(dev.frequency), big_val(dev.sample_rate)) + initial_name = "{0}-{1}-{2}Hz-{3}Sps".format( + dev.name, timestamp, big_val(dev.frequency), big_val(dev.sample_rate) + ) if dev.bandwidth_is_adjustable: initial_name += "-{}Hz".format(big_val(dev.bandwidth)) - initial_name = initial_name.replace(Formatter.local_decimal_seperator(), "_").replace("_000", "") + initial_name = initial_name.replace( + Formatter.local_decimal_seperator(), "_" + ).replace("_000", "") - filename = FileOperator.ask_signal_file_name_and_save(initial_name, data, - sample_rate=dev.sample_rate, parent=self) + filename = FileOperator.ask_signal_file_name_and_save( + initial_name, data, sample_rate=dev.sample_rate, parent=self + ) self.already_saved = True if filename is not None and filename not in self.recorded_files: self.recorded_files.append(filename) diff --git a/src/urh/controller/dialogs/SendDialog.py b/src/urh/controller/dialogs/SendDialog.py index 550b59fc76..13df0fd465 100644 --- a/src/urh/controller/dialogs/SendDialog.py +++ b/src/urh/controller/dialogs/SendDialog.py @@ -13,10 +13,22 @@ class SendDialog(SendRecvDialog): - def __init__(self, project_manager, modulated_data, modulation_msg_indices=None, continuous_send_mode=False, - parent=None, testing_mode=False): - super().__init__(project_manager, is_tx=True, continuous_send_mode=continuous_send_mode, - parent=parent, testing_mode=testing_mode) + def __init__( + self, + project_manager, + modulated_data, + modulation_msg_indices=None, + continuous_send_mode=False, + parent=None, + testing_mode=False, + ): + super().__init__( + project_manager, + is_tx=True, + continuous_send_mode=continuous_send_mode, + parent=parent, + testing_mode=testing_mode, + ) self.graphics_view = self.ui.graphicsViewSend self.ui.stackedWidget.setCurrentWidget(self.ui.page_send) @@ -44,9 +56,14 @@ def __init__(self, project_manager, modulated_data, modulation_msg_indices=None, signal = Signal("", "Modulated Preview", sample_rate=samp_rate) signal.iq_array = modulated_data self.scene_manager = SignalSceneManager(signal, parent=self) - self.send_indicator = self.scene_manager.scene.addRect(0, -2, 0, 4, - QPen(QColor(Qt.transparent), 0), - QBrush(settings.SEND_INDICATOR_COLOR)) + self.send_indicator = self.scene_manager.scene.addRect( + 0, + -2, + 0, + 4, + QPen(QColor(Qt.transparent), 0), + QBrush(settings.SEND_INDICATOR_COLOR), + ) self.send_indicator.stackBefore(self.scene_manager.scene.selection_area) self.scene_manager.init_scene() self.graphics_view.set_signal(signal) @@ -58,17 +75,28 @@ def __init__(self, project_manager, modulated_data, modulation_msg_indices=None, def create_connects(self): super().create_connects() - self.graphics_view.save_as_clicked.connect(self.on_graphics_view_save_as_clicked) + self.graphics_view.save_as_clicked.connect( + self.on_graphics_view_save_as_clicked + ) self.scene_manager.signal.data_edited.connect(self.on_signal_data_edited) def _update_send_indicator(self, width: int): - y, h = self.ui.graphicsViewSend.view_rect().y(), self.ui.graphicsViewSend.view_rect().height() + y, h = ( + self.ui.graphicsViewSend.view_rect().y(), + self.ui.graphicsViewSend.view_rect().height(), + ) self.send_indicator.setRect(0, y - h, width, 2 * h + abs(y)) def set_current_message_progress_bar_value(self, current_sample: int): if self.modulation_msg_indices is not None: - msg_index = next((i for i, sample in enumerate(self.modulation_msg_indices) if sample >= current_sample), - len(self.modulation_msg_indices)) + msg_index = next( + ( + i + for i, sample in enumerate(self.modulation_msg_indices) + if sample >= current_sample + ), + len(self.modulation_msg_indices), + ) self.ui.progressBarMessage.setValue(msg_index + 1) def update_view(self): @@ -78,7 +106,9 @@ def update_view(self): self.set_current_message_progress_bar_value(self.device.current_index) if not self.device.sending_finished: - self.ui.lblCurrentRepeatValue.setText(str(self.device.current_iteration + 1)) + self.ui.lblCurrentRepeatValue.setText( + str(self.device.current_iteration + 1) + ) else: self.ui.btnStop.click() self.ui.lblCurrentRepeatValue.setText("Sending finished") @@ -88,8 +118,15 @@ def init_device(self): num_repeats = self.device_settings_widget.ui.spinBoxNRepeat.value() sts = self.scene_manager.signal.iq_array - self.device = VirtualDevice(self.backend_handler, device_name, Mode.send, samples_to_send=sts, - device_ip="192.168.10.2", sending_repeats=num_repeats, parent=self) + self.device = VirtualDevice( + self.backend_handler, + device_name, + Mode.send, + samples_to_send=sts, + device_ip="192.168.10.2", + sending_repeats=num_repeats, + parent=self, + ) self._create_device_connects() @pyqtSlot() diff --git a/src/urh/controller/dialogs/SendRecvDialog.py b/src/urh/controller/dialogs/SendRecvDialog.py index fe66a13123..c97c29f410 100644 --- a/src/urh/controller/dialogs/SendRecvDialog.py +++ b/src/urh/controller/dialogs/SendRecvDialog.py @@ -9,7 +9,9 @@ from urh.controller.widgets.DeviceSettingsWidget import DeviceSettingsWidget from urh.dev.BackendHandler import BackendHandler, Backends from urh.dev.VirtualDevice import VirtualDevice -from urh.plugins.NetworkSDRInterface.NetworkSDRInterfacePlugin import NetworkSDRInterfacePlugin +from urh.plugins.NetworkSDRInterface.NetworkSDRInterfacePlugin import ( + NetworkSDRInterfacePlugin, +) from urh.ui.ui_send_recv import Ui_SendRecvDialog from urh.util import util from urh.util.Errors import Errors @@ -21,7 +23,14 @@ class SendRecvDialog(QDialog): device_parameters_changed = pyqtSignal(dict) - def __init__(self, project_manager: ProjectManager, is_tx: bool, continuous_send_mode=False, parent=None, testing_mode=False): + def __init__( + self, + project_manager: ProjectManager, + is_tx: bool, + continuous_send_mode=False, + parent=None, + testing_mode=False, + ): super().__init__(parent) self.is_tx = is_tx self.update_interval = 25 @@ -47,16 +56,25 @@ def __init__(self, project_manager: ProjectManager, is_tx: bool, continuous_send self.start = 0 - self.device_settings_widget = DeviceSettingsWidget(project_manager, is_tx, - backend_handler=self.backend_handler, - continuous_send_mode=continuous_send_mode) - self.ui.scrollAreaWidgetContents_2.layout().insertWidget(0, self.device_settings_widget) + self.device_settings_widget = DeviceSettingsWidget( + project_manager, + is_tx, + backend_handler=self.backend_handler, + continuous_send_mode=continuous_send_mode, + ) + self.ui.scrollAreaWidgetContents_2.layout().insertWidget( + 0, self.device_settings_widget + ) if testing_mode: - self.device_settings_widget.ui.cbDevice.setCurrentText(NetworkSDRInterfacePlugin.NETWORK_SDR_NAME) + self.device_settings_widget.ui.cbDevice.setCurrentText( + NetworkSDRInterfacePlugin.NETWORK_SDR_NAME + ) self.timer = QTimer(self) - self.restoreGeometry(settings.read("{}/geometry".format(self.__class__.__name__), type=bytes)) + self.restoreGeometry( + settings.read("{}/geometry".format(self.__class__.__name__), type=bytes) + ) self.ui.splitter.setSizes([int(0.4 * self.width()), int(0.6 * self.width())]) @@ -89,13 +107,28 @@ def _eliminate_graphic_view(self): self.graphics_view = None def hide_send_ui_items(self): - for item in ("lblCurrentRepeatValue", "progressBarMessage", - "lblRepeatText", "lSamplesSentText", "progressBarSample", "labelCurrentMessage"): + for item in ( + "lblCurrentRepeatValue", + "progressBarMessage", + "lblRepeatText", + "lSamplesSentText", + "progressBarSample", + "labelCurrentMessage", + ): getattr(self.ui, item).hide() def hide_receive_ui_items(self): - for item in ("lSamplesCaptured", "lSamplesCapturedText", "lSignalSize", "lSignalSizeText", - "lTime", "lTimeText", "btnSave", "labelReceiveBufferFull", "lReceiveBufferFullText"): + for item in ( + "lSamplesCaptured", + "lSamplesCapturedText", + "lSignalSize", + "lSignalSizeText", + "lTime", + "lTimeText", + "btnSave", + "labelReceiveBufferFull", + "lReceiveBufferFullText", + ): getattr(self.ui, item).hide() def set_device_ui_items_enabled(self, enabled: bool): @@ -109,8 +142,12 @@ def create_connects(self): self.timer.timeout.connect(self.update_view) self.ui.sliderYscale.valueChanged.connect(self.on_slider_y_scale_value_changed) - self.device_settings_widget.selected_device_changed.connect(self.on_selected_device_changed) - self.device_settings_widget.device_parameters_changed.connect(self.device_parameters_changed.emit) + self.device_settings_widget.selected_device_changed.connect( + self.on_selected_device_changed + ) + self.device_settings_widget.device_parameters_changed.connect( + self.device_parameters_changed.emit + ) def _create_device_connects(self): self.device.stopped.connect(self.on_device_stopped) @@ -191,7 +228,9 @@ def __parse_error_messages(self, messages): Errors.usrp_found() self.on_clear_clicked() - elif any(e in messages for e in ("hackrf_error_not_found", "hackrf_error_libusb")): + elif any( + e in messages for e in ("hackrf_error_not_found", "hackrf_error_libusb") + ): self.device.stop_on_error("Could not establish connection to HackRF") Errors.hackrf_not_found() self.on_clear_clicked() @@ -222,13 +261,24 @@ def update_view(self): if len(new_messages) > 1: self.ui.txtEditErrors.setPlainText(txt + new_messages) - self.ui.lSamplesCaptured.setText(Formatter.big_value_with_suffix(self.device.current_index, decimals=1)) - self.ui.lSignalSize.setText(locale.format_string("%.2f", (8 * self.device.current_index) / (1024 ** 2))) - self.ui.lTime.setText(locale.format_string("%.2f", self.device.current_index / self.device.sample_rate)) + self.ui.lSamplesCaptured.setText( + Formatter.big_value_with_suffix(self.device.current_index, decimals=1) + ) + self.ui.lSignalSize.setText( + locale.format_string("%.2f", (8 * self.device.current_index) / (1024**2)) + ) + self.ui.lTime.setText( + locale.format_string( + "%.2f", self.device.current_index / self.device.sample_rate + ) + ) if self.is_rx and self.device.data is not None and len(self.device.data) > 0: - self.ui.labelReceiveBufferFull.setText("{0}%".format(int(100 * self.device.current_index / - len(self.device.data)))) + self.ui.labelReceiveBufferFull.setText( + "{0}%".format( + int(100 * self.device.current_index / len(self.device.data)) + ) + ) if self.device.current_index == 0: return False @@ -269,7 +319,9 @@ def closeEvent(self, event: QCloseEvent): logger.debug("Successfully cleaned up device") self.device_settings_widget.emit_device_parameters_changed() - settings.write("{}/geometry".format(self.__class__.__name__), self.saveGeometry()) + settings.write( + "{}/geometry".format(self.__class__.__name__), self.saveGeometry() + ) if self.device is not None: self.device.free_data() diff --git a/src/urh/controller/dialogs/SignalDetailsDialog.py b/src/urh/controller/dialogs/SignalDetailsDialog.py index 894fdf6904..67c81fc8c3 100644 --- a/src/urh/controller/dialogs/SignalDetailsDialog.py +++ b/src/urh/controller/dialogs/SignalDetailsDialog.py @@ -26,22 +26,32 @@ def __init__(self, signal, parent=None): if os.path.isfile(file): self.ui.lblFile.setText(file) - self.ui.lblFileSize.setText(locale.format_string("%.2fMB", os.path.getsize(file) / (1024 ** 2))) + self.ui.lblFileSize.setText( + locale.format_string("%.2fMB", os.path.getsize(file) / (1024**2)) + ) self.ui.lFileCreated.setText(time.ctime(os.path.getctime(file))) else: self.ui.lblFile.setText(self.tr("signal file not found")) self.ui.lblFileSize.setText("-") self.ui.lFileCreated.setText("-") - self.ui.lblSamplesTotal.setText("{0:n}".format(self.signal.num_samples).replace(",", " ")) + self.ui.lblSamplesTotal.setText( + "{0:n}".format(self.signal.num_samples).replace(",", " ") + ) self.ui.dsb_sample_rate.setValue(self.signal.sample_rate) self.set_duration() - self.ui.dsb_sample_rate.valueChanged.connect(self.on_dsb_sample_rate_value_changed) - self.restoreGeometry(settings.read("{}/geometry".format(self.__class__.__name__), type=bytes)) + self.ui.dsb_sample_rate.valueChanged.connect( + self.on_dsb_sample_rate_value_changed + ) + self.restoreGeometry( + settings.read("{}/geometry".format(self.__class__.__name__), type=bytes) + ) def closeEvent(self, event: QCloseEvent): - settings.write("{}/geometry".format(self.__class__.__name__), self.saveGeometry()) + settings.write( + "{}/geometry".format(self.__class__.__name__), self.saveGeometry() + ) super().closeEvent(event) @pyqtSlot(float) diff --git a/src/urh/controller/dialogs/SimulatorDialog.py b/src/urh/controller/dialogs/SimulatorDialog.py index 24bf478642..e5a4ecdb7f 100644 --- a/src/urh/controller/dialogs/SimulatorDialog.py +++ b/src/urh/controller/dialogs/SimulatorDialog.py @@ -31,10 +31,16 @@ class SimulatorDialog(QDialog): open_in_analysis_requested = pyqtSignal(str) rx_file_saved = pyqtSignal(str) - def __init__(self, simulator_config, modulators, - expression_parser, project_manager: ProjectManager, signals: list = None, - signal_tree_model=None, - parent=None): + def __init__( + self, + simulator_config, + modulators, + expression_parser, + project_manager: ProjectManager, + signals: list = None, + signal_tree_model=None, + parent=None, + ): super().__init__(parent) self.ui = Ui_DialogSimulator() self.ui.setupUi(self) @@ -48,8 +54,9 @@ def __init__(self, simulator_config, modulators, self.current_transcript_index = 0 - self.simulator_scene = SimulatorScene(mode=1, - simulator_config=self.simulator_config) + self.simulator_scene = SimulatorScene( + mode=1, simulator_config=self.simulator_config + ) self.ui.gvSimulator.setScene(self.simulator_scene) self.project_manager = project_manager @@ -59,17 +66,22 @@ def __init__(self, simulator_config, modulators, self.backend_handler = BackendHandler() if self.rx_needed: - self.device_settings_rx_widget = DeviceSettingsWidget(project_manager, - is_tx=False, - backend_handler=self.backend_handler) - - self.sniff_settings_widget = SniffSettingsWidget(self.device_settings_rx_widget.ui.cbDevice.currentText(), - project_manager, - signal=None, - backend_handler=self.backend_handler, - network_raw_mode=True, signals=signals) - - self.device_settings_rx_widget.device = self.sniff_settings_widget.sniffer.rcv_device + self.device_settings_rx_widget = DeviceSettingsWidget( + project_manager, is_tx=False, backend_handler=self.backend_handler + ) + + self.sniff_settings_widget = SniffSettingsWidget( + self.device_settings_rx_widget.ui.cbDevice.currentText(), + project_manager, + signal=None, + backend_handler=self.backend_handler, + network_raw_mode=True, + signals=signals, + ) + + self.device_settings_rx_widget.device = ( + self.sniff_settings_widget.sniffer.rcv_device + ) self.sniff_settings_widget.ui.lineEdit_sniff_OutputFile.hide() self.sniff_settings_widget.ui.label_sniff_OutputFile.hide() @@ -77,15 +89,23 @@ def __init__(self, simulator_config, modulators, self.sniff_settings_widget.ui.checkBox_sniff_Timestamp.hide() self.sniff_settings_widget.ui.comboBox_sniff_viewtype.hide() - self.ui.scrollAreaWidgetContentsRX.layout().insertWidget(0, self.device_settings_rx_widget) - self.ui.scrollAreaWidgetContentsRX.layout().insertWidget(1, self.sniff_settings_widget) + self.ui.scrollAreaWidgetContentsRX.layout().insertWidget( + 0, self.device_settings_rx_widget + ) + self.ui.scrollAreaWidgetContentsRX.layout().insertWidget( + 1, self.sniff_settings_widget + ) sniffer = self.sniff_settings_widget.sniffer - self.scene_manager = SniffSceneManager(np.array([], dtype=sniffer.rcv_device.data_type), parent=self) + self.scene_manager = SniffSceneManager( + np.array([], dtype=sniffer.rcv_device.data_type), parent=self + ) self.ui.graphicsViewPreview.setScene(self.scene_manager.scene) else: - self.device_settings_rx_widget = self.sniff_settings_widget = self.scene_manager = None + self.device_settings_rx_widget = ( + self.sniff_settings_widget + ) = self.scene_manager = None self.ui.tabWidgetSimulatorSettings.setTabEnabled(1, False) self.ui.graphicsViewPreview.hide() self.ui.btnSaveRX.hide() @@ -94,17 +114,25 @@ def __init__(self, simulator_config, modulators, sniffer = None if self.tx_needed: - self.device_settings_tx_widget = DeviceSettingsWidget(project_manager, is_tx=True, - backend_handler=self.backend_handler, - continuous_send_mode=True) + self.device_settings_tx_widget = DeviceSettingsWidget( + project_manager, + is_tx=True, + backend_handler=self.backend_handler, + continuous_send_mode=True, + ) self.device_settings_tx_widget.ui.spinBoxNRepeat.hide() self.device_settings_tx_widget.ui.labelNRepeat.hide() - self.modulation_settings_widget = ModulationSettingsWidget(modulators, signal_tree_model=signal_tree_model, - parent=None) + self.modulation_settings_widget = ModulationSettingsWidget( + modulators, signal_tree_model=signal_tree_model, parent=None + ) - self.ui.scrollAreaWidgetContentsTX.layout().insertWidget(0, self.device_settings_tx_widget) - self.ui.scrollAreaWidgetContentsTX.layout().insertWidget(1, self.modulation_settings_widget) + self.ui.scrollAreaWidgetContentsTX.layout().insertWidget( + 0, self.device_settings_tx_widget + ) + self.ui.scrollAreaWidgetContentsTX.layout().insertWidget( + 1, self.modulation_settings_widget + ) send_device = self.device_settings_tx_widget.ui.cbDevice.currentText() sender = EndlessSender(self.backend_handler, send_device) else: @@ -113,8 +141,14 @@ def __init__(self, simulator_config, modulators, sender = None - self.simulator = Simulator(self.simulator_config, modulators, expression_parser, project_manager, - sniffer=sniffer, sender=sender) + self.simulator = Simulator( + self.simulator_config, + modulators, + expression_parser, + project_manager, + sniffer=sniffer, + sender=sender, + ) if self.device_settings_tx_widget: self.device_settings_tx_widget.device = self.simulator.sender.device @@ -130,28 +164,48 @@ def __init__(self, simulator_config, modulators, self.ui.textEditTranscript.setFont(util.get_monospace_font()) - if settings.read('default_view', 0, int) == 1: + if settings.read("default_view", 0, int) == 1: self.ui.radioButtonTranscriptHex.setChecked(True) def create_connects(self): if self.rx_needed: - self.device_settings_rx_widget.selected_device_changed.connect(self.on_selected_rx_device_changed) - self.device_settings_rx_widget.device_parameters_changed.connect(self.rx_parameters_changed.emit) + self.device_settings_rx_widget.selected_device_changed.connect( + self.on_selected_rx_device_changed + ) + self.device_settings_rx_widget.device_parameters_changed.connect( + self.rx_parameters_changed.emit + ) - self.sniff_settings_widget.sniff_parameters_changed.connect(self.sniff_parameters_changed.emit) + self.sniff_settings_widget.sniff_parameters_changed.connect( + self.sniff_parameters_changed.emit + ) self.ui.btnSaveRX.clicked.connect(self.on_btn_save_rx_clicked) - self.ui.checkBoxCaptureFullRX.clicked.connect(self.on_checkbox_capture_full_rx_clicked) + self.ui.checkBoxCaptureFullRX.clicked.connect( + self.on_checkbox_capture_full_rx_clicked + ) - self.ui.btnTestSniffSettings.clicked.connect(self.on_btn_test_sniff_settings_clicked) - self.ui.btnOpenInAnalysis.clicked.connect(self.on_btn_open_in_analysis_clicked) + self.ui.btnTestSniffSettings.clicked.connect( + self.on_btn_test_sniff_settings_clicked + ) + self.ui.btnOpenInAnalysis.clicked.connect( + self.on_btn_open_in_analysis_clicked + ) if self.tx_needed: - self.device_settings_tx_widget.selected_device_changed.connect(self.on_selected_tx_device_changed) - self.device_settings_tx_widget.device_parameters_changed.connect(self.tx_parameters_changed.emit) - - self.ui.radioButtonTranscriptBit.clicked.connect(self.on_radio_button_transcript_bit_clicked) - self.ui.radioButtonTranscriptHex.clicked.connect(self.on_radio_button_transcript_hex_clicked) + self.device_settings_tx_widget.selected_device_changed.connect( + self.on_selected_tx_device_changed + ) + self.device_settings_tx_widget.device_parameters_changed.connect( + self.tx_parameters_changed.emit + ) + + self.ui.radioButtonTranscriptBit.clicked.connect( + self.on_radio_button_transcript_bit_clicked + ) + self.ui.radioButtonTranscriptHex.clicked.connect( + self.on_radio_button_transcript_hex_clicked + ) self.simulator_scene.selectionChanged.connect(self.update_buttons) self.simulator_config.items_updated.connect(self.update_buttons) @@ -169,32 +223,47 @@ def create_connects(self): def update_buttons(self): selectable_items = self.simulator_scene.selectable_items() - all_items_selected = all(item.model_item.logging_active for item in selectable_items) - any_item_selected = any(item.model_item.logging_active for item in selectable_items) + all_items_selected = all( + item.model_item.logging_active for item in selectable_items + ) + any_item_selected = any( + item.model_item.logging_active for item in selectable_items + ) self.ui.btnToggleLog.setEnabled(len(self.simulator_scene.selectedItems())) self.ui.btnLogAll.setEnabled(not all_items_selected) self.ui.btnLogNone.setEnabled(any_item_selected) def __get_full_transcript(self) -> list: - return self.simulator.transcript.get_for_all_participants(all_rounds=True, - use_bit=self.ui.radioButtonTranscriptBit.isChecked()) + return self.simulator.transcript.get_for_all_participants( + all_rounds=True, use_bit=self.ui.radioButtonTranscriptBit.isChecked() + ) def update_view(self): - for device_message in filter(None, map(str.rstrip, self.simulator.device_messages())): + for device_message in filter( + None, map(str.rstrip, self.simulator.device_messages()) + ): self.ui.textEditDevices.append(device_message) - for log_msg in filter(None, map(str.rstrip, self.simulator.read_log_messages())): + for log_msg in filter( + None, map(str.rstrip, self.simulator.read_log_messages()) + ): self.ui.textEditSimulation.append(log_msg) transcript = self.__get_full_transcript() - for line in transcript[self.current_transcript_index:]: + for line in transcript[self.current_transcript_index :]: self.ui.textEditTranscript.append(line) self.current_transcript_index = len(transcript) - current_repeat = str(self.simulator.current_repeat + 1) if self.simulator.is_simulating else "-" + current_repeat = ( + str(self.simulator.current_repeat + 1) + if self.simulator.is_simulating + else "-" + ) self.ui.lblCurrentRepeatValue.setText(current_repeat) - current_item = self.simulator.current_item.index() if self.simulator.is_simulating else "-" + current_item = ( + self.simulator.current_item.index() if self.simulator.is_simulating else "-" + ) self.ui.lblCurrentItemValue.setText(current_item) def update_rx_graphics_view(self): @@ -301,7 +370,9 @@ def on_btn_toggle_clicked(self): @pyqtSlot() def on_btn_save_log_clicked(self): - file_path = QFileDialog.getSaveFileName(self, "Save log", "", "Log file (*.log)") + file_path = QFileDialog.getSaveFileName( + self, "Save log", "", "Log file (*.log)" + ) if file_path[0] == "": return @@ -316,7 +387,9 @@ def on_btn_save_log_clicked(self): @pyqtSlot() def on_btn_save_transcript_clicked(self): - file_path = QFileDialog.getSaveFileName(self, "Save transcript", "", "Text file (*.txt)") + file_path = QFileDialog.getSaveFileName( + self, "Save transcript", "", "Text file (*.txt)" + ) if file_path[0] == "": return @@ -339,7 +412,9 @@ def on_btn_start_stop_clicked(self): self.sniff_settings_widget.emit_editing_finished_signals() self.simulator.sniffer.rcv_device.current_index = 0 - self.simulator.sniffer.rcv_device.resume_on_full_receive_buffer = not self.ui.checkBoxCaptureFullRX.isChecked() + self.simulator.sniffer.rcv_device.resume_on_full_receive_buffer = ( + not self.ui.checkBoxCaptureFullRX.isChecked() + ) if self.tx_needed: self.device_settings_tx_widget.emit_editing_finished_signals() @@ -372,16 +447,26 @@ def on_selected_tx_device_changed(self): @pyqtSlot() def on_btn_test_sniff_settings_clicked(self): def on_dialog_finished(): - self.device_settings_rx_widget.bootstrap(self.project_manager.simulator_rx_conf) + self.device_settings_rx_widget.bootstrap( + self.project_manager.simulator_rx_conf + ) self.sniff_settings_widget.bootstrap(self.project_manager.device_conf) self.device_settings_rx_widget.emit_device_parameters_changed() self.sniff_settings_widget.emit_sniff_parameters_changed() - psd = ProtocolSniffDialog(self.project_manager, signals=self.sniff_settings_widget.signals, parent=self) + psd = ProtocolSniffDialog( + self.project_manager, + signals=self.sniff_settings_widget.signals, + parent=self, + ) psd.device_settings_widget.bootstrap(self.project_manager.simulator_rx_conf) - psd.device_settings_widget.device_parameters_changed.connect(self.rx_parameters_changed.emit) - psd.sniff_settings_widget.sniff_parameters_changed.connect(self.sniff_parameters_changed.emit) + psd.device_settings_widget.device_parameters_changed.connect( + self.rx_parameters_changed.emit + ) + psd.sniff_settings_widget.sniff_parameters_changed.connect( + self.sniff_parameters_changed.emit + ) psd.finished.connect(on_dialog_finished) psd.ui.btnAccept.hide() psd.show() @@ -399,27 +484,39 @@ def __set_rx_scene(self): return if self.ui.checkBoxCaptureFullRX.isChecked(): - self.scene_manager = LiveSceneManager(np.array([], dtype=self.simulator.sniffer.rcv_device.data_type), - parent=self) + self.scene_manager = LiveSceneManager( + np.array([], dtype=self.simulator.sniffer.rcv_device.data_type), + parent=self, + ) self.ui.graphicsViewPreview.setScene(self.scene_manager.scene) else: - self.scene_manager = SniffSceneManager(np.array([], dtype=self.simulator.sniffer.rcv_device.data_type), - parent=self) + self.scene_manager = SniffSceneManager( + np.array([], dtype=self.simulator.sniffer.rcv_device.data_type), + parent=self, + ) self.ui.graphicsViewPreview.setScene(self.scene_manager.scene) @pyqtSlot() def on_checkbox_capture_full_rx_clicked(self): - self.simulator.sniffer.rcv_device.resume_on_full_receive_buffer = not self.ui.checkBoxCaptureFullRX.isChecked() + self.simulator.sniffer.rcv_device.resume_on_full_receive_buffer = ( + not self.ui.checkBoxCaptureFullRX.isChecked() + ) self.__set_rx_scene() @pyqtSlot() def on_btn_save_rx_clicked(self): rx_device = self.simulator.sniffer.rcv_device - if isinstance(rx_device.data, np.ndarray) or isinstance(rx_device.data, IQArray): - data = IQArray(rx_device.data[:rx_device.current_index]) - filename = FileOperator.ask_signal_file_name_and_save("simulation_capture", data, - sample_rate=rx_device.sample_rate, parent=self) + if isinstance(rx_device.data, np.ndarray) or isinstance( + rx_device.data, IQArray + ): + data = IQArray(rx_device.data[: rx_device.current_index]) + filename = FileOperator.ask_signal_file_name_and_save( + "simulation_capture", + data, + sample_rate=rx_device.sample_rate, + parent=self, + ) if filename: data.tofile(filename) self.rx_file_saved.emit(filename) diff --git a/src/urh/controller/dialogs/SpectrumDialogController.py b/src/urh/controller/dialogs/SpectrumDialogController.py index ab27115e27..079e9c80e4 100644 --- a/src/urh/controller/dialogs/SpectrumDialogController.py +++ b/src/urh/controller/dialogs/SpectrumDialogController.py @@ -10,7 +10,9 @@ class SpectrumDialogController(SendRecvDialog): def __init__(self, project_manager, parent=None, testing_mode=False): - super().__init__(project_manager, is_tx=False, parent=parent, testing_mode=testing_mode) + super().__init__( + project_manager, is_tx=False, parent=parent, testing_mode=testing_mode + ) self.graphics_view = self.ui.graphicsViewFFT self.update_interval = 1 @@ -23,7 +25,9 @@ def __init__(self, project_manager, parent=None, testing_mode=False): self.ui.btnStart.setToolTip(self.tr("Start")) self.ui.btnStop.setToolTip(self.tr("Stop")) - self.scene_manager = FFTSceneManager(parent=self, graphic_view=self.graphics_view) + self.scene_manager = FFTSceneManager( + parent=self, graphic_view=self.graphics_view + ) self.graphics_view.setScene(self.scene_manager.scene) self.graphics_view.scene_manager = self.scene_manager @@ -46,9 +50,13 @@ def __init__(self, project_manager, parent=None, testing_mode=False): def __clear_spectrogram(self): self.ui.graphicsViewSpectrogram.scene().clear() window_size = Spectrogram.DEFAULT_FFT_WINDOW_SIZE - self.ui.graphicsViewSpectrogram.scene().setSceneRect(0, 0, window_size, 20 * window_size) + self.ui.graphicsViewSpectrogram.scene().setSceneRect( + 0, 0, window_size, 20 * window_size + ) self.spectrogram_y_pos = 0 - self.ui.graphicsViewSpectrogram.fitInView(self.ui.graphicsViewSpectrogram.sceneRect()) + self.ui.graphicsViewSpectrogram.fitInView( + self.ui.graphicsViewSpectrogram.sceneRect() + ) def __update_spectrogram(self): spectrogram = Spectrogram(self.device.data) @@ -60,12 +68,17 @@ def __update_spectrogram(self): pixmap_item.moveBy(0, self.spectrogram_y_pos) self.spectrogram_y_pos += pixmap.height() if self.spectrogram_y_pos >= scene.sceneRect().height(): - scene.setSceneRect(0, 0, Spectrogram.DEFAULT_FFT_WINDOW_SIZE, self.spectrogram_y_pos) + scene.setSceneRect( + 0, 0, Spectrogram.DEFAULT_FFT_WINDOW_SIZE, self.spectrogram_y_pos + ) self.ui.graphicsViewSpectrogram.ensureVisible(pixmap_item) def _eliminate_graphic_view(self): super()._eliminate_graphic_view() - if self.ui.graphicsViewSpectrogram and self.ui.graphicsViewSpectrogram.scene() is not None: + if ( + self.ui.graphicsViewSpectrogram + and self.ui.graphicsViewSpectrogram.scene() is not None + ): self.ui.graphicsViewSpectrogram.scene().clear() self.ui.graphicsViewSpectrogram.scene().setParent(None) self.ui.graphicsViewSpectrogram.setScene(None) @@ -75,21 +88,41 @@ def _eliminate_graphic_view(self): def create_connects(self): super().create_connects() self.graphics_view.freq_clicked.connect(self.on_graphics_view_freq_clicked) - self.graphics_view.wheel_event_triggered.connect(self.on_graphics_view_wheel_event_triggered) + self.graphics_view.wheel_event_triggered.connect( + self.on_graphics_view_wheel_event_triggered + ) - self.device_settings_widget.ui.sliderGain.valueChanged.connect(self.on_slider_gain_value_changed) + self.device_settings_widget.ui.sliderGain.valueChanged.connect( + self.on_slider_gain_value_changed + ) self.device_settings_widget.ui.sliderBasebandGain.valueChanged.connect( - self.on_slider_baseband_gain_value_changed) - self.device_settings_widget.ui.sliderIFGain.valueChanged.connect(self.on_slider_if_gain_value_changed) - self.device_settings_widget.ui.spinBoxFreq.editingFinished.connect(self.on_spinbox_frequency_editing_finished) - - self.gain_timer.timeout.connect(self.device_settings_widget.ui.spinBoxGain.editingFinished.emit) - self.if_gain_timer.timeout.connect(self.device_settings_widget.ui.spinBoxIFGain.editingFinished.emit) - self.bb_gain_timer.timeout.connect(self.device_settings_widget.ui.spinBoxBasebandGain.editingFinished.emit) + self.on_slider_baseband_gain_value_changed + ) + self.device_settings_widget.ui.sliderIFGain.valueChanged.connect( + self.on_slider_if_gain_value_changed + ) + self.device_settings_widget.ui.spinBoxFreq.editingFinished.connect( + self.on_spinbox_frequency_editing_finished + ) + + self.gain_timer.timeout.connect( + self.device_settings_widget.ui.spinBoxGain.editingFinished.emit + ) + self.if_gain_timer.timeout.connect( + self.device_settings_widget.ui.spinBoxIFGain.editingFinished.emit + ) + self.bb_gain_timer.timeout.connect( + self.device_settings_widget.ui.spinBoxBasebandGain.editingFinished.emit + ) def resizeEvent(self, event: QResizeEvent): - if self.ui.graphicsViewSpectrogram and self.ui.graphicsViewSpectrogram.sceneRect(): - self.ui.graphicsViewSpectrogram.fitInView(self.ui.graphicsViewSpectrogram.sceneRect()) + if ( + self.ui.graphicsViewSpectrogram + and self.ui.graphicsViewSpectrogram.sceneRect() + ): + self.ui.graphicsViewSpectrogram.fitInView( + self.ui.graphicsViewSpectrogram.sceneRect() + ) def update_view(self): if super().update_view(): @@ -109,9 +142,13 @@ def update_view(self): self.__update_spectrogram() def init_device(self): - self.device = VirtualDevice(self.backend_handler, self.selected_device_name, - Mode.spectrum, - device_ip="192.168.10.2", parent=self) + self.device = VirtualDevice( + self.backend_handler, + self.selected_device_name, + Mode.spectrum, + device_ip="192.168.10.2", + parent=self, + ) self._create_device_connects() @pyqtSlot(QWheelEvent) @@ -138,7 +175,9 @@ def on_start_clicked(self): @pyqtSlot() def on_device_started(self): - self.ui.graphicsViewSpectrogram.fitInView(self.ui.graphicsViewSpectrogram.scene().sceneRect()) + self.ui.graphicsViewSpectrogram.fitInView( + self.ui.graphicsViewSpectrogram.scene().sceneRect() + ) super().on_device_started() self.device_settings_widget.ui.spinBoxPort.setEnabled(False) self.device_settings_widget.ui.lineEditIP.setEnabled(False) diff --git a/src/urh/controller/widgets/ChecksumWidget.py b/src/urh/controller/widgets/ChecksumWidget.py index 9cac49e4bf..5ecacf6c9f 100644 --- a/src/urh/controller/widgets/ChecksumWidget.py +++ b/src/urh/controller/widgets/ChecksumWidget.py @@ -17,15 +17,22 @@ class ChecksumWidget(QWidget): - SPECIAL_CRCS = OrderedDict([ - ("CC1101", GenericCRC(polynomial="16_standard", start_value=True)), - ]) - + SPECIAL_CRCS = OrderedDict( + [ + ("CC1101", GenericCRC(polynomial="16_standard", start_value=True)), + ] + ) class RangeTableModel(QAbstractTableModel): header_labels = ["Start", "End"] - def __init__(self, checksum_label: ChecksumLabel, message: Message, proto_view: int, parent=None): + def __init__( + self, + checksum_label: ChecksumLabel, + message: Message, + proto_view: int, + parent=None, + ): """ :param message: @@ -62,9 +69,16 @@ def data(self, index: QModelIndex, role=Qt.DisplayRole): if role == Qt.DisplayRole: data_range = self.checksum_label.data_ranges[i] if j == 0: - return self.message.convert_index(data_range[0], 0, self.proto_view, True)[0] + 1 + return ( + self.message.convert_index( + data_range[0], 0, self.proto_view, True + )[0] + + 1 + ) elif j == 1: - return self.message.convert_index(data_range[1], 0, self.proto_view, True)[0] + return self.message.convert_index( + data_range[1], 0, self.proto_view, True + )[0] return None def setData(self, index: QModelIndex, value, role: int = ...): @@ -81,11 +95,15 @@ def setData(self, index: QModelIndex, value, role: int = ...): data_range = self.checksum_label.data_ranges[i] if j == 0: - converted_index = self.message.convert_index(int_val - 1, self.proto_view, 0, True)[0] + converted_index = self.message.convert_index( + int_val - 1, self.proto_view, 0, True + )[0] if converted_index < data_range[1]: data_range[0] = converted_index elif j == 1: - converted_index = self.message.convert_index(int_val, self.proto_view, 0, True)[0] + converted_index = self.message.convert_index( + int_val, self.proto_view, 0, True + )[0] if converted_index > data_range[0]: data_range[1] = converted_index @@ -102,21 +120,41 @@ def flags(self, index): return Qt.ItemIsEditable | Qt.ItemIsEnabled | Qt.ItemIsSelectable - def __init__(self, checksum_label: ChecksumLabel, message: Message, proto_view: int, parent=None): + def __init__( + self, + checksum_label: ChecksumLabel, + message: Message, + proto_view: int, + parent=None, + ): super().__init__(parent) self.ui = Ui_ChecksumOptions() self.ui.setupUi(self) self.checksum_label = checksum_label - self.data_range_table_model = self.RangeTableModel(checksum_label, message, proto_view, parent=self) - self.ui.tableViewDataRanges.setItemDelegateForColumn(0, SpinBoxDelegate(1, 999999, self)) - self.ui.tableViewDataRanges.setItemDelegateForColumn(1, SpinBoxDelegate(1, 999999, self)) - self.ui.tableViewDataRanges.horizontalHeader().setSectionResizeMode(QHeaderView.Stretch) + self.data_range_table_model = self.RangeTableModel( + checksum_label, message, proto_view, parent=self + ) + self.ui.tableViewDataRanges.setItemDelegateForColumn( + 0, SpinBoxDelegate(1, 999999, self) + ) + self.ui.tableViewDataRanges.setItemDelegateForColumn( + 1, SpinBoxDelegate(1, 999999, self) + ) + self.ui.tableViewDataRanges.horizontalHeader().setSectionResizeMode( + QHeaderView.Stretch + ) self.ui.tableViewDataRanges.setModel(self.data_range_table_model) self.ui.tableViewDataRanges.setEditTriggers(QAbstractItemView.AllEditTriggers) self.display_crc_data_ranges_in_table() - self.ui.comboBoxCRCFunction.addItems([crc_name for crc_name in GenericCRC.DEFAULT_POLYNOMIALS]) - self.ui.comboBoxCRCFunction.addItems([special_crc_name for special_crc_name in self.SPECIAL_CRCS]) - self.ui.lineEditCRCPolynomial.setValidator(QRegExpValidator(QRegExp("[0-9,a-f]*"))) + self.ui.comboBoxCRCFunction.addItems( + [crc_name for crc_name in GenericCRC.DEFAULT_POLYNOMIALS] + ) + self.ui.comboBoxCRCFunction.addItems( + [special_crc_name for special_crc_name in self.SPECIAL_CRCS] + ) + self.ui.lineEditCRCPolynomial.setValidator( + QRegExpValidator(QRegExp("[0-9,a-f]*")) + ) self.ui.comboBoxCategory.clear() for _, member in self.checksum_label.Category.__members__.items(): self.ui.comboBoxCategory.addItem(member.value) @@ -135,25 +173,49 @@ def proto_view(self, value): self.data_range_table_model.update() def create_connects(self): - self.ui.comboBoxCRCFunction.currentIndexChanged.connect(self.on_combobox_crc_function_current_index_changed) + self.ui.comboBoxCRCFunction.currentIndexChanged.connect( + self.on_combobox_crc_function_current_index_changed + ) self.ui.btnAddRange.clicked.connect(self.on_btn_add_range_clicked) self.ui.btnRemoveRange.clicked.connect(self.on_btn_remove_range_clicked) - self.ui.lineEditCRCPolynomial.editingFinished.connect(self.on_line_edit_crc_polynomial_editing_finished) - self.ui.lineEditStartValue.editingFinished.connect(self.on_line_edit_start_value_editing_finished) - self.ui.lineEditFinalXOR.editingFinished.connect(self.on_line_edit_final_xor_editing_finished) - self.ui.comboBoxCategory.currentIndexChanged.connect(self.on_combobox_category_current_index_changed) - self.ui.radioButtonWSPAuto.clicked.connect(self.on_radio_button_wsp_auto_clicked) - self.ui.radioButtonWSPChecksum4.clicked.connect(self.on_radio_button_wsp_checksum4_clicked) - self.ui.radioButtonWSPChecksum8.clicked.connect(self.on_radio_button_wsp_checksum8_clicked) - self.ui.radioButtonWSPCRC8.clicked.connect(self.on_radio_button_wsp_crc8_clicked) + self.ui.lineEditCRCPolynomial.editingFinished.connect( + self.on_line_edit_crc_polynomial_editing_finished + ) + self.ui.lineEditStartValue.editingFinished.connect( + self.on_line_edit_start_value_editing_finished + ) + self.ui.lineEditFinalXOR.editingFinished.connect( + self.on_line_edit_final_xor_editing_finished + ) + self.ui.comboBoxCategory.currentIndexChanged.connect( + self.on_combobox_category_current_index_changed + ) + self.ui.radioButtonWSPAuto.clicked.connect( + self.on_radio_button_wsp_auto_clicked + ) + self.ui.radioButtonWSPChecksum4.clicked.connect( + self.on_radio_button_wsp_checksum4_clicked + ) + self.ui.radioButtonWSPChecksum8.clicked.connect( + self.on_radio_button_wsp_checksum8_clicked + ) + self.ui.radioButtonWSPCRC8.clicked.connect( + self.on_radio_button_wsp_crc8_clicked + ) self.ui.checkBoxRefIn.clicked.connect(self.on_check_box_ref_in_clicked) self.ui.checkBoxRefOut.clicked.connect(self.on_check_box_ref_out_clicked) def set_checksum_ui_elements(self): if self.checksum_label.is_generic_crc: - self.ui.lineEditCRCPolynomial.setText(self.checksum_label.checksum.polynomial_as_hex_str) - self.ui.lineEditStartValue.setText(util.bit2hex(self.checksum_label.checksum.start_value)) - self.ui.lineEditFinalXOR.setText(util.bit2hex(self.checksum_label.checksum.final_xor)) + self.ui.lineEditCRCPolynomial.setText( + self.checksum_label.checksum.polynomial_as_hex_str + ) + self.ui.lineEditStartValue.setText( + util.bit2hex(self.checksum_label.checksum.start_value) + ) + self.ui.lineEditFinalXOR.setText( + util.bit2hex(self.checksum_label.checksum.final_xor) + ) self.ui.checkBoxRefIn.setChecked(self.checksum_label.checksum.lsb_first) self.ui.checkBoxRefOut.setChecked(self.checksum_label.checksum.reverse_all) self.__set_crc_function_index() @@ -162,9 +224,13 @@ def set_checksum_ui_elements(self): elif self.checksum_label.category == self.checksum_label.Category.wsp: if self.checksum_label.checksum.mode == WSPChecksum.ChecksumMode.auto: self.ui.radioButtonWSPAuto.setChecked(True) - elif self.checksum_label.checksum.mode == WSPChecksum.ChecksumMode.checksum4: + elif ( + self.checksum_label.checksum.mode == WSPChecksum.ChecksumMode.checksum4 + ): self.ui.radioButtonWSPChecksum4.setChecked(True) - elif self.checksum_label.checksum.mode == WSPChecksum.ChecksumMode.checksum8: + elif ( + self.checksum_label.checksum.mode == WSPChecksum.ChecksumMode.checksum8 + ): self.ui.radioButtonWSPChecksum8.setChecked(True) elif self.checksum_label.checksum.mode == WSPChecksum.ChecksumMode.crc8: self.ui.radioButtonWSPCRC8.setChecked(True) @@ -202,33 +268,63 @@ def __set_crc_function_index(self): if not crc_found: self.__add_and_select_custom_item() - elif "Custom" in [self.ui.comboBoxCRCFunction.itemText(i) for i in range(self.ui.comboBoxCRCFunction.count())]: - self.ui.comboBoxCRCFunction.removeItem(self.ui.comboBoxCRCFunction.count() - 1) - + elif "Custom" in [ + self.ui.comboBoxCRCFunction.itemText(i) + for i in range(self.ui.comboBoxCRCFunction.count()) + ]: + self.ui.comboBoxCRCFunction.removeItem( + self.ui.comboBoxCRCFunction.count() - 1 + ) def __set_crc_info_label(self): crc = self.checksum_label.checksum # type: GenericCRC - self.ui.label_crc_info.setText("CRC Summary:".format(crc.polynomial_to_html, crc.poly_order-1, - len(crc.start_value), len(crc.final_xor))) + self.ui.label_crc_info.setText( + "CRC Summary:".format( + crc.polynomial_to_html, + crc.poly_order - 1, + len(crc.start_value), + len(crc.final_xor), + ) + ) def __ensure_same_length(self): - for dependant_line_edit in [self.ui.lineEditStartValue, self.ui.lineEditFinalXOR]: # type: QLineEdit - if len(self.ui.lineEditCRCPolynomial.text()) < len(dependant_line_edit.text()): - dependant_line_edit.setText(dependant_line_edit.text()[:len(self.ui.lineEditCRCPolynomial.text())]) + for dependant_line_edit in [ + self.ui.lineEditStartValue, + self.ui.lineEditFinalXOR, + ]: # type: QLineEdit + if len(self.ui.lineEditCRCPolynomial.text()) < len( + dependant_line_edit.text() + ): + dependant_line_edit.setText( + dependant_line_edit.text()[ + : len(self.ui.lineEditCRCPolynomial.text()) + ] + ) dependant_line_edit.editingFinished.emit() - elif len(self.ui.lineEditCRCPolynomial.text()) > len(dependant_line_edit.text()): + elif len(self.ui.lineEditCRCPolynomial.text()) > len( + dependant_line_edit.text() + ): # pad zeros at front - dependant_line_edit.setText("0" * (len(self.ui.lineEditCRCPolynomial.text()) - len(dependant_line_edit.text())) - + dependant_line_edit.text()) + dependant_line_edit.setText( + "0" + * ( + len(self.ui.lineEditCRCPolynomial.text()) + - len(dependant_line_edit.text()) + ) + + dependant_line_edit.text() + ) dependant_line_edit.editingFinished.emit() def __add_and_select_custom_item(self): - if "Custom" not in [self.ui.comboBoxCRCFunction.itemText(i) for i in range(self.ui.comboBoxCRCFunction.count())]: + if "Custom" not in [ + self.ui.comboBoxCRCFunction.itemText(i) + for i in range(self.ui.comboBoxCRCFunction.count()) + ]: self.ui.comboBoxCRCFunction.addItem("Custom") self.ui.comboBoxCRCFunction.blockSignals(True) self.ui.comboBoxCRCFunction.setCurrentText("Custom") @@ -249,23 +345,37 @@ def on_btn_remove_range_clicked(self): def on_combobox_crc_function_current_index_changed(self, index: int): poly_str = self.ui.comboBoxCRCFunction.itemText(index) if poly_str in GenericCRC.DEFAULT_POLYNOMIALS: - self.checksum_label.checksum.polynomial = self.checksum_label.checksum.choose_polynomial(poly_str) - self.checksum_label.checksum.start_value = array.array("B", [0] * (self.checksum_label.checksum.poly_order - 1)) - self.checksum_label.checksum.final_xor = array.array("B", [0] * (self.checksum_label.checksum.poly_order - 1)) + self.checksum_label.checksum.polynomial = ( + self.checksum_label.checksum.choose_polynomial(poly_str) + ) + self.checksum_label.checksum.start_value = array.array( + "B", [0] * (self.checksum_label.checksum.poly_order - 1) + ) + self.checksum_label.checksum.final_xor = array.array( + "B", [0] * (self.checksum_label.checksum.poly_order - 1) + ) elif poly_str in self.SPECIAL_CRCS: self.checksum_label.checksum = copy.deepcopy(self.SPECIAL_CRCS[poly_str]) else: logger.error("Unknown CRC") return - self.ui.lineEditCRCPolynomial.setText(self.checksum_label.checksum.polynomial_as_hex_str) - self.ui.lineEditStartValue.setText(util.bit2hex(self.checksum_label.checksum.start_value)) - self.ui.lineEditFinalXOR.setText(util.bit2hex(self.checksum_label.checksum.final_xor)) + self.ui.lineEditCRCPolynomial.setText( + self.checksum_label.checksum.polynomial_as_hex_str + ) + self.ui.lineEditStartValue.setText( + util.bit2hex(self.checksum_label.checksum.start_value) + ) + self.ui.lineEditFinalXOR.setText( + util.bit2hex(self.checksum_label.checksum.final_xor) + ) self.ui.lineEditCRCPolynomial.editingFinished.emit() @pyqtSlot() def on_line_edit_crc_polynomial_editing_finished(self): - self.checksum_label.checksum.set_polynomial_from_hex(self.ui.lineEditCRCPolynomial.text()) + self.checksum_label.checksum.set_polynomial_from_hex( + self.ui.lineEditCRCPolynomial.text() + ) self.__ensure_same_length() self.__set_crc_info_label() self.__set_crc_function_index() @@ -283,8 +393,11 @@ def on_line_edit_start_value_editing_finished(self): crc = self.checksum_label.checksum start_value = util.hex2bit(self.ui.lineEditStartValue.text()) # pad with zeros at front - start_value = array.array("B", [0]*(crc.poly_order - 1 - len(start_value))) + start_value - crc.start_value = start_value[0:crc.poly_order-1] + start_value = ( + array.array("B", [0] * (crc.poly_order - 1 - len(start_value))) + + start_value + ) + crc.start_value = start_value[0 : crc.poly_order - 1] self.ui.lineEditStartValue.setText(util.bit2hex(crc.start_value)) self.__set_crc_info_label() self.__set_crc_function_index() @@ -293,15 +406,19 @@ def on_line_edit_start_value_editing_finished(self): def on_line_edit_final_xor_editing_finished(self): crc = self.checksum_label.checksum final_xor = util.hex2bit(self.ui.lineEditFinalXOR.text()) - final_xor = array.array("B", [0] * (crc.poly_order - 1 - len(final_xor))) + final_xor - crc.final_xor = final_xor[0:crc.poly_order-1] + final_xor = ( + array.array("B", [0] * (crc.poly_order - 1 - len(final_xor))) + final_xor + ) + crc.final_xor = final_xor[0 : crc.poly_order - 1] self.ui.lineEditFinalXOR.setText(util.bit2hex(crc.final_xor)) self.__set_crc_info_label() self.__set_crc_function_index() @pyqtSlot(int) def on_combobox_category_current_index_changed(self, index: int): - self.checksum_label.category = self.checksum_label.Category(self.ui.comboBoxCategory.currentText()) + self.checksum_label.category = self.checksum_label.Category( + self.ui.comboBoxCategory.currentText() + ) self.set_ui_for_category() @pyqtSlot() diff --git a/src/urh/controller/widgets/DeviceSettingsWidget.py b/src/urh/controller/widgets/DeviceSettingsWidget.py index 7f462ba80d..363c2869c9 100644 --- a/src/urh/controller/widgets/DeviceSettingsWidget.py +++ b/src/urh/controller/widgets/DeviceSettingsWidget.py @@ -9,7 +9,9 @@ from urh.dev import config from urh.dev.BackendHandler import BackendHandler, Backends from urh.dev.VirtualDevice import VirtualDevice -from urh.plugins.NetworkSDRInterface.NetworkSDRInterfacePlugin import NetworkSDRInterfacePlugin +from urh.plugins.NetworkSDRInterface.NetworkSDRInterfacePlugin import ( + NetworkSDRInterfacePlugin, +) from urh.plugins.PluginManager import PluginManager from urh.ui.ui_send_recv_device_settings import Ui_FormDeviceSettings from urh.util.ProjectManager import ProjectManager @@ -20,8 +22,14 @@ class DeviceSettingsWidget(QWidget): gain_edited = pyqtSignal() device_parameters_changed = pyqtSignal(dict) - def __init__(self, project_manager: ProjectManager, is_tx: bool, backend_handler: BackendHandler = None, - continuous_send_mode=False, parent=None): + def __init__( + self, + project_manager: ProjectManager, + is_tx: bool, + backend_handler: BackendHandler = None, + continuous_send_mode=False, + parent=None, + ): super().__init__(parent) self.ui = Ui_FormDeviceSettings() self.ui.setupUi(self) @@ -52,10 +60,17 @@ def __init__(self, project_manager: ProjectManager, is_tx: bool, backend_handler self.on_btn_lock_bw_sr_clicked() ip_range = "(?:[0-1]?[0-9]?[0-9]|2[0-4][0-9]|25[0-5])" - ip_regex = QRegExp("^" + ip_range - + "\\." + ip_range - + "\\." + ip_range - + "\\." + ip_range + "$") + ip_regex = QRegExp( + "^" + + ip_range + + "\\." + + ip_range + + "\\." + + ip_range + + "\\." + + ip_range + + "$" + ) self.ui.lineEditIP.setValidator(QRegExpValidator(ip_regex)) self.create_connects() @@ -81,15 +96,31 @@ def set_val(ui_widget, key: str, default): set_val(self.ui.spinBoxSampleRate, "sample_rate", config.DEFAULT_SAMPLE_RATE) set_val(self.ui.spinBoxBandwidth, "bandwidth", config.DEFAULT_BANDWIDTH) set_val(self.ui.spinBoxGain, self.rx_tx_prefix + "gain", config.DEFAULT_GAIN) - set_val(self.ui.spinBoxIFGain, self.rx_tx_prefix + "if_gain", config.DEFAULT_IF_GAIN) - set_val(self.ui.spinBoxBasebandGain, self.rx_tx_prefix + "baseband_gain", config.DEFAULT_BB_GAIN) - set_val(self.ui.spinBoxFreqCorrection, "freq_correction", config.DEFAULT_FREQ_CORRECTION) - set_val(self.ui.spinBoxNRepeat, "num_sending_repeats", settings.read('num_sending_repeats', 1, type=int)) + set_val( + self.ui.spinBoxIFGain, self.rx_tx_prefix + "if_gain", config.DEFAULT_IF_GAIN + ) + set_val( + self.ui.spinBoxBasebandGain, + self.rx_tx_prefix + "baseband_gain", + config.DEFAULT_BB_GAIN, + ) + set_val( + self.ui.spinBoxFreqCorrection, + "freq_correction", + config.DEFAULT_FREQ_CORRECTION, + ) + set_val( + self.ui.spinBoxNRepeat, + "num_sending_repeats", + settings.read("num_sending_repeats", 1, type=int), + ) self.ui.lineEditSubdevice.setText(conf_dict.get("subdevice", "")) if self.rx_tx_prefix + "antenna_index" in conf_dict: - self.ui.comboBoxAntenna.setCurrentIndex(conf_dict[self.rx_tx_prefix + "antenna_index"]) + self.ui.comboBoxAntenna.setCurrentIndex( + conf_dict[self.rx_tx_prefix + "antenna_index"] + ) if self.rx_tx_prefix + "gain" not in conf_dict: self.set_default_rf_gain() @@ -132,45 +163,86 @@ def selected_device_conf(self) -> dict: return config.DEVICE_CONFIG[key] def create_connects(self): - self.ui.spinBoxFreq.editingFinished.connect(self.on_spinbox_frequency_editing_finished) - self.ui.spinBoxSampleRate.editingFinished.connect(self.on_spinbox_sample_rate_editing_finished) - - self.ui.spinBoxGain.editingFinished.connect(self.on_spinbox_gain_editing_finished) + self.ui.spinBoxFreq.editingFinished.connect( + self.on_spinbox_frequency_editing_finished + ) + self.ui.spinBoxSampleRate.editingFinished.connect( + self.on_spinbox_sample_rate_editing_finished + ) + + self.ui.spinBoxGain.editingFinished.connect( + self.on_spinbox_gain_editing_finished + ) self.ui.spinBoxGain.valueChanged.connect(self.on_spinbox_gain_value_changed) self.ui.sliderGain.valueChanged.connect(self.on_slider_gain_value_changed) - self.ui.spinBoxIFGain.editingFinished.connect(self.on_spinbox_if_gain_editing_finished) - self.ui.spinBoxIFGain.valueChanged.connect(self.on_spinbox_if_gain_value_changed) + self.ui.spinBoxIFGain.editingFinished.connect( + self.on_spinbox_if_gain_editing_finished + ) + self.ui.spinBoxIFGain.valueChanged.connect( + self.on_spinbox_if_gain_value_changed + ) self.ui.sliderIFGain.valueChanged.connect(self.on_slider_if_gain_value_changed) - self.ui.spinBoxBasebandGain.editingFinished.connect(self.on_spinbox_baseband_gain_editing_finished) - self.ui.spinBoxBasebandGain.valueChanged.connect(self.on_spinbox_baseband_gain_value_changed) - self.ui.sliderBasebandGain.valueChanged.connect(self.on_slider_baseband_gain_value_changed) - - self.ui.spinBoxBandwidth.editingFinished.connect(self.on_spinbox_bandwidth_editing_finished) - self.ui.spinBoxPort.editingFinished.connect(self.on_spinbox_port_editing_finished) - self.ui.lineEditIP.editingFinished.connect(self.on_line_edit_ip_editing_finished) - self.ui.lineEditSubdevice.editingFinished.connect(self.on_line_edit_subdevice_editing_finished) - - self.ui.comboBoxAntenna.currentIndexChanged.connect(self.on_combobox_antenna_current_index_changed) - self.ui.comboBoxChannel.currentIndexChanged.connect(self.on_combobox_channel_current_index_changed) - - self.ui.spinBoxFreqCorrection.editingFinished.connect(self.on_spinbox_freq_correction_editing_finished) - self.ui.comboBoxDirectSampling.currentIndexChanged.connect(self.on_combobox_direct_sampling_index_changed) - - self.ui.cbDevice.currentIndexChanged.connect(self.on_cb_device_current_index_changed) + self.ui.spinBoxBasebandGain.editingFinished.connect( + self.on_spinbox_baseband_gain_editing_finished + ) + self.ui.spinBoxBasebandGain.valueChanged.connect( + self.on_spinbox_baseband_gain_value_changed + ) + self.ui.sliderBasebandGain.valueChanged.connect( + self.on_slider_baseband_gain_value_changed + ) + + self.ui.spinBoxBandwidth.editingFinished.connect( + self.on_spinbox_bandwidth_editing_finished + ) + self.ui.spinBoxPort.editingFinished.connect( + self.on_spinbox_port_editing_finished + ) + self.ui.lineEditIP.editingFinished.connect( + self.on_line_edit_ip_editing_finished + ) + self.ui.lineEditSubdevice.editingFinished.connect( + self.on_line_edit_subdevice_editing_finished + ) + + self.ui.comboBoxAntenna.currentIndexChanged.connect( + self.on_combobox_antenna_current_index_changed + ) + self.ui.comboBoxChannel.currentIndexChanged.connect( + self.on_combobox_channel_current_index_changed + ) + + self.ui.spinBoxFreqCorrection.editingFinished.connect( + self.on_spinbox_freq_correction_editing_finished + ) + self.ui.comboBoxDirectSampling.currentIndexChanged.connect( + self.on_combobox_direct_sampling_index_changed + ) + + self.ui.cbDevice.currentIndexChanged.connect( + self.on_cb_device_current_index_changed + ) self.ui.spinBoxNRepeat.editingFinished.connect(self.on_num_repeats_changed) self.ui.btnLockBWSR.clicked.connect(self.on_btn_lock_bw_sr_clicked) - self.ui.btnRefreshDeviceIdentifier.clicked.connect(self.on_btn_refresh_device_identifier_clicked) + self.ui.btnRefreshDeviceIdentifier.clicked.connect( + self.on_btn_refresh_device_identifier_clicked + ) self.ui.comboBoxDeviceIdentifier.currentIndexChanged.connect( - self.on_combo_box_device_identifier_current_index_changed) + self.on_combo_box_device_identifier_current_index_changed + ) - self.ui.comboBoxDeviceIdentifier.editTextChanged.connect(self.on_combo_box_device_identifier_edit_text_changed) + self.ui.comboBoxDeviceIdentifier.editTextChanged.connect( + self.on_combo_box_device_identifier_edit_text_changed + ) self.ui.checkBoxBiasTee.clicked.connect(self.on_check_box_bias_tee_clicked) - self.ui.checkBoxDCCorrection.clicked.connect(self.on_check_box_dc_correction_clicked) + self.ui.checkBoxDCCorrection.clicked.connect( + self.on_check_box_dc_correction_clicked + ) def set_gain_defaults(self): self.set_default_rf_gain() @@ -198,18 +270,26 @@ def set_default_bb_gain(self): prefix = self.rx_tx_prefix if prefix + "baseband_gain" in conf: key = prefix + "baseband_gain" - baseband_gain = conf[key][int(np.percentile(list(range(len(conf[key]))), 25))] + baseband_gain = conf[key][ + int(np.percentile(list(range(len(conf[key]))), 25)) + ] self.ui.spinBoxBasebandGain.setValue(baseband_gain) def sync_gain_sliders(self): self.ui.spinBoxGain.valueChanged.emit(self.ui.spinBoxGain.value()) self.ui.spinBoxIFGain.valueChanged.emit(self.ui.spinBoxIFGain.value()) - self.ui.spinBoxBasebandGain.valueChanged.emit(self.ui.spinBoxBasebandGain.value()) + self.ui.spinBoxBasebandGain.valueChanged.emit( + self.ui.spinBoxBasebandGain.value() + ) def set_device_ui_items_visibility(self, device_name: str, overwrite_settings=True): key = device_name if device_name in config.DEVICE_CONFIG.keys() else "Fallback" conf = config.DEVICE_CONFIG[key] - key_ui_dev_param_map = {"center_freq": "Freq", "sample_rate": "SampleRate", "bandwidth": "Bandwidth"} + key_ui_dev_param_map = { + "center_freq": "Freq", + "sample_rate": "SampleRate", + "bandwidth": "Bandwidth", + } for key, ui_item in key_ui_dev_param_map.items(): spinbox = getattr(self.ui, "spinBox" + ui_item) # type: QSpinBox @@ -253,7 +333,10 @@ def set_device_ui_items_visibility(self, device_name: str, overwrite_settings=Tr if "direct_sampling" in conf: self.ui.labelDirectSampling.setVisible(True) self.ui.comboBoxDirectSampling.setVisible(True) - items = [self.ui.comboBoxDirectSampling.itemText(i) for i in range(self.ui.comboBoxDirectSampling.count())] + items = [ + self.ui.comboBoxDirectSampling.itemText(i) + for i in range(self.ui.comboBoxDirectSampling.count()) + ] if items != conf["direct_sampling"]: self.ui.comboBoxDirectSampling.clear() self.ui.comboBoxDirectSampling.addItems(conf["direct_sampling"]) @@ -262,8 +345,11 @@ def set_device_ui_items_visibility(self, device_name: str, overwrite_settings=Tr self.ui.comboBoxDirectSampling.setVisible(False) prefix = self.rx_tx_prefix - key_ui_gain_map = {prefix + "rf_gain": "Gain", prefix + "if_gain": "IFGain", - prefix + "baseband_gain": "BasebandGain"} + key_ui_gain_map = { + prefix + "rf_gain": "Gain", + prefix + "if_gain": "IFGain", + prefix + "baseband_gain": "BasebandGain", + } for conf_key, ui_element in key_ui_gain_map.items(): getattr(self.ui, "label" + ui_element).setVisible(conf_key in conf) @@ -287,7 +373,10 @@ def set_device_ui_items_visibility(self, device_name: str, overwrite_settings=Tr getattr(self.ui, "slider" + ui_element).setVisible(conf_key in conf) if overwrite_settings: - key_ui_channel_ant_map = {prefix + "antenna": "Antenna", prefix + "channel": "Channel"} + key_ui_channel_ant_map = { + prefix + "antenna": "Antenna", + prefix + "channel": "Channel", + } for conf_key, ui_element in key_ui_channel_ant_map.items(): getattr(self.ui, "label" + ui_element).setVisible(conf_key in conf) combobox = getattr(self.ui, "comboBox" + ui_element) # type: QComboBox @@ -301,7 +390,10 @@ def set_device_ui_items_visibility(self, device_name: str, overwrite_settings=Tr else: combobox.setVisible(False) - multi_dev_support = hasattr(self.device, "has_multi_device_support") and self.device.has_multi_device_support + multi_dev_support = ( + hasattr(self.device, "has_multi_device_support") + and self.device.has_multi_device_support + ) self.ui.labelDeviceIdentifier.setVisible(multi_dev_support) self.ui.btnRefreshDeviceIdentifier.setVisible(multi_dev_support) self.ui.comboBoxDeviceIdentifier.setVisible(multi_dev_support) @@ -309,11 +401,19 @@ def set_device_ui_items_visibility(self, device_name: str, overwrite_settings=Tr self.ui.labelIP.setVisible("ip" in conf) self.ui.spinBoxPort.setVisible("port" in conf) self.ui.labelPort.setVisible("port" in conf) - show_dc_correction = self.is_rx and self.device is not None and self.device.apply_dc_correction is not None + show_dc_correction = ( + self.is_rx + and self.device is not None + and self.device.apply_dc_correction is not None + ) self.ui.checkBoxDCCorrection.setVisible(show_dc_correction) self.ui.labelDCCorrection.setVisible(show_dc_correction) - show_bias_tee = "bias_tee_enabled" in conf and self.device is not None and self.device.bias_tee_enabled is not None + show_bias_tee = ( + "bias_tee_enabled" in conf + and self.device is not None + and self.device.bias_tee_enabled is not None + ) self.ui.labelBiasTee.setVisible(show_bias_tee) self.ui.checkBoxBiasTee.setVisible(show_bias_tee) @@ -335,15 +435,23 @@ def get_devices_for_combobox(self, continuous_send_mode): return items def set_bandwidth_status(self): - if hasattr(self, "device") and self.device is not None and self.device.backend != Backends.none: + if ( + hasattr(self, "device") + and self.device is not None + and self.device.backend != Backends.none + ): self.ui.spinBoxBandwidth.setEnabled(self.device.bandwidth_is_adjustable) self.ui.btnLockBWSR.setEnabled(self.device.bandwidth_is_adjustable) if not self.device.bandwidth_is_adjustable: self.bw_sr_are_locked = False - self.ui.spinBoxBandwidth.setToolTip(self.tr("Your driver of RTL-SDR does not support " - "setting the bandwidth. " - "If you need this feature, install a recent version.")) + self.ui.spinBoxBandwidth.setToolTip( + self.tr( + "Your driver of RTL-SDR does not support " + "setting the bandwidth. " + "If you need this feature, install a recent version." + ) + ) else: self.ui.spinBoxBandwidth.setToolTip("") self.bw_sr_are_locked = self.ui.btnLockBWSR.isChecked() @@ -360,15 +468,33 @@ def emit_editing_finished_signals(self): self.ui.lineEditIP.editingFinished.emit() self.ui.lineEditSubdevice.editingFinished.emit() self.ui.spinBoxPort.editingFinished.emit() - self.ui.comboBoxAntenna.currentIndexChanged.emit(self.ui.comboBoxAntenna.currentIndex()) - self.ui.comboBoxChannel.currentIndexChanged.emit(self.ui.comboBoxChannel.currentIndex()) - self.ui.checkBoxDCCorrection.clicked.emit(self.ui.checkBoxDCCorrection.isChecked()) + self.ui.comboBoxAntenna.currentIndexChanged.emit( + self.ui.comboBoxAntenna.currentIndex() + ) + self.ui.comboBoxChannel.currentIndexChanged.emit( + self.ui.comboBoxChannel.currentIndex() + ) + self.ui.checkBoxDCCorrection.clicked.emit( + self.ui.checkBoxDCCorrection.isChecked() + ) self.ui.checkBoxBiasTee.clicked.emit(self.ui.checkBoxBiasTee.isChecked()) def emit_device_parameters_changed(self): settings = {"name": str(self.device.name)} - for attrib in ("frequency", "sample_rate", "bandwidth", "gain", "if_gain", "baseband_gain", "freq_correction", - "antenna_index", "num_sending_repeats", "apply_dc_correction", "subdevice", "bias_tee_enabled"): + for attrib in ( + "frequency", + "sample_rate", + "bandwidth", + "gain", + "if_gain", + "baseband_gain", + "freq_correction", + "antenna_index", + "num_sending_repeats", + "apply_dc_correction", + "subdevice", + "bias_tee_enabled", + ): try: value = getattr(self.device, attrib, None) if value is not None: @@ -445,7 +571,9 @@ def on_spinbox_gain_editing_finished(self): def on_spinbox_gain_value_changed(self, value: int): dev_conf = self.selected_device_conf try: - self.ui.sliderGain.setValue(dev_conf[self.rx_tx_prefix + "rf_gain"].index(value)) + self.ui.sliderGain.setValue( + dev_conf[self.rx_tx_prefix + "rf_gain"].index(value) + ) except (ValueError, KeyError): pass @@ -467,7 +595,9 @@ def on_slider_if_gain_value_changed(self, value: int): def on_spinbox_if_gain_value_changed(self, value: int): dev_conf = self.selected_device_conf try: - self.ui.sliderIFGain.setValue(dev_conf[self.rx_tx_prefix + "if_gain"].index(value)) + self.ui.sliderIFGain.setValue( + dev_conf[self.rx_tx_prefix + "if_gain"].index(value) + ) except (ValueError, KeyError): pass @@ -482,13 +612,17 @@ def on_spinbox_baseband_gain_editing_finished(self): @pyqtSlot(int) def on_slider_baseband_gain_value_changed(self, value: int): dev_conf = self.selected_device_conf - self.ui.spinBoxBasebandGain.setValue(dev_conf[self.rx_tx_prefix + "baseband_gain"][value]) + self.ui.spinBoxBasebandGain.setValue( + dev_conf[self.rx_tx_prefix + "baseband_gain"][value] + ) @pyqtSlot(int) def on_spinbox_baseband_gain_value_changed(self, value: int): dev_conf = self.selected_device_conf try: - self.ui.sliderBasebandGain.setValue(dev_conf[self.rx_tx_prefix + "baseband_gain"].index(value)) + self.ui.sliderBasebandGain.setValue( + dev_conf[self.rx_tx_prefix + "baseband_gain"].index(value) + ) except (ValueError, KeyError): pass @@ -500,7 +634,9 @@ def update_for_new_device(self, overwrite_settings=True): self.selected_device_changed.emit() dev_name = self.ui.cbDevice.currentText() - self.set_device_ui_items_visibility(dev_name, overwrite_settings=overwrite_settings) + self.set_device_ui_items_visibility( + dev_name, overwrite_settings=overwrite_settings + ) if overwrite_settings: self.set_gain_defaults() @@ -541,7 +677,7 @@ def on_combo_box_device_identifier_edit_text_changed(self, new_text: str): self.device.device_serial = new_text -if __name__ == '__main__': +if __name__ == "__main__": from PyQt5.QtWidgets import QApplication from urh.controller.MainController import MainController diff --git a/src/urh/controller/widgets/ModulationSettingsWidget.py b/src/urh/controller/widgets/ModulationSettingsWidget.py index 6328133475..4836678898 100644 --- a/src/urh/controller/widgets/ModulationSettingsWidget.py +++ b/src/urh/controller/widgets/ModulationSettingsWidget.py @@ -8,7 +8,9 @@ class ModulationSettingsWidget(QWidget): - def __init__(self, modulators, selected_index=0, signal_tree_model=None, parent=None): + def __init__( + self, modulators, selected_index=0, signal_tree_model=None, parent=None + ): """ :type modulators: list of Modulator @@ -18,8 +20,12 @@ def __init__(self, modulators, selected_index=0, signal_tree_model=None, parent= self.ui = Ui_ModulationSettings() self.ui.setupUi(self) - self.ui.labelModulationProfile.setVisible(settings.read("multiple_modulations", False, bool)) - self.ui.comboBoxModulationProfiles.setVisible(settings.read("multiple_modulations", False, bool)) + self.ui.labelModulationProfile.setVisible( + settings.read("multiple_modulations", False, bool) + ) + self.ui.comboBoxModulationProfiles.setVisible( + settings.read("multiple_modulations", False, bool) + ) self.signal_tree_model = signal_tree_model self.modulators = modulators # type: list[Modulator] @@ -38,11 +44,17 @@ def selected_modulator(self) -> Modulator: @selected_modulator.setter def selected_modulator(self, value: Modulator): if value in self.modulators: - self.ui.comboBoxModulationProfiles.setCurrentIndex(self.modulators.index(value)) + self.ui.comboBoxModulationProfiles.setCurrentIndex( + self.modulators.index(value) + ) def create_connects(self): - self.ui.comboBoxModulationProfiles.currentIndexChanged.connect(self.on_cb_modulation_type_current_index_changed) - self.ui.btnConfigurationDialog.clicked.connect(self.on_btn_configuration_dialog_clicked) + self.ui.comboBoxModulationProfiles.currentIndexChanged.connect( + self.on_cb_modulation_type_current_index_changed + ) + self.ui.btnConfigurationDialog.clicked.connect( + self.on_btn_configuration_dialog_clicked + ) def show_selected_modulation_infos(self): modulator = self.selected_modulator @@ -61,8 +73,12 @@ def on_cb_modulation_type_current_index_changed(self): @pyqtSlot() def on_btn_configuration_dialog_clicked(self): - dialog = ModulatorDialog(self.modulators, tree_model=self.signal_tree_model, parent=self) - dialog.ui.comboBoxCustomModulations.setCurrentIndex(self.ui.comboBoxModulationProfiles.currentIndex()) + dialog = ModulatorDialog( + self.modulators, tree_model=self.signal_tree_model, parent=self + ) + dialog.ui.comboBoxCustomModulations.setCurrentIndex( + self.ui.comboBoxModulationProfiles.currentIndex() + ) dialog.finished.connect(self.refresh_modulators_from_dialog) dialog.show() dialog.initialize("10101011010010") @@ -80,9 +96,11 @@ def refresh_modulators_from_dialog(self): self.ui.comboBoxModulationProfiles.setCurrentIndex(current_index) self.show_selected_modulation_infos() -if __name__ == '__main__': + +if __name__ == "__main__": from PyQt5.QtWidgets import QApplication + app = QApplication([""]) w = ModulationSettingsWidget([Modulator("test")]) w.show() - app.exec() \ No newline at end of file + app.exec() diff --git a/src/urh/controller/widgets/PluginFrame.py b/src/urh/controller/widgets/PluginFrame.py index 936e3e706f..f6113273e3 100644 --- a/src/urh/controller/widgets/PluginFrame.py +++ b/src/urh/controller/widgets/PluginFrame.py @@ -21,14 +21,19 @@ def __init__(self, plugins, highlighted_plugins=None, parent=None): self.ui.groupBoxSettings.setLayout(self.settings_layout) self.create_connects() - self.restoreGeometry(settings.read("{}/geometry".format(self.__class__.__name__), type=bytes)) - + self.restoreGeometry( + settings.read("{}/geometry".format(self.__class__.__name__), type=bytes) + ) def create_connects(self): - self.ui.listViewPlugins.selectionModel().selectionChanged.connect(self.on_list_selection_changed) + self.ui.listViewPlugins.selectionModel().selectionChanged.connect( + self.on_list_selection_changed + ) for plugin in self.model.plugins: if hasattr(plugin, "show_proto_sniff_dialog_clicked"): - plugin.show_proto_sniff_dialog_clicked.connect(self.parent().parent().show_proto_sniff_dialog) + plugin.show_proto_sniff_dialog_clicked.connect( + self.parent().parent().show_proto_sniff_dialog + ) def save_enabled_states(self): for plugin in self.model.plugins: diff --git a/src/urh/controller/widgets/SignalFrame.py b/src/urh/controller/widgets/SignalFrame.py index 01f4fa9768..f216a07118 100644 --- a/src/urh/controller/widgets/SignalFrame.py +++ b/src/urh/controller/widgets/SignalFrame.py @@ -4,12 +4,31 @@ import numpy as np from PyQt5.QtCore import pyqtSignal, QPoint, Qt, QMimeData, pyqtSlot, QTimer -from PyQt5.QtGui import QIcon, QDrag, QPixmap, QRegion, QDropEvent, QTextCursor, QContextMenuEvent, \ - QResizeEvent -from PyQt5.QtWidgets import QFrame, QMessageBox, QMenu, QWidget, QUndoStack, QCheckBox, QApplication, qApp +from PyQt5.QtGui import ( + QIcon, + QDrag, + QPixmap, + QRegion, + QDropEvent, + QTextCursor, + QContextMenuEvent, + QResizeEvent, +) +from PyQt5.QtWidgets import ( + QFrame, + QMessageBox, + QMenu, + QWidget, + QUndoStack, + QCheckBox, + QApplication, + qApp, +) from urh import settings -from urh.controller.dialogs.AdvancedModulationOptionsDialog import AdvancedModulationOptionsDialog +from urh.controller.dialogs.AdvancedModulationOptionsDialog import ( + AdvancedModulationOptionsDialog, +) from urh.controller.dialogs.CostaOptionsDialog import CostaOptionsDialog from urh.controller.dialogs.FilterDialog import FilterDialog from urh.controller.dialogs.SendDialog import SendDialog @@ -31,7 +50,9 @@ def perform_filter(result_array: Array, data, f_low, f_high, filter_bw): result_array = np.frombuffer(result_array.get_obj(), dtype=np.complex64) - result_array[:] = Filter.apply_bandpass_filter(data, f_low, f_high, filter_bw=filter_bw) + result_array[:] = Filter.apply_bandpass_filter( + data, f_low, f_high, filter_bw=filter_bw + ) class SignalFrame(QFrame): @@ -49,7 +70,13 @@ class SignalFrame(QFrame): def proto_view(self): return self.ui.txtEdProto.cur_view - def __init__(self, proto_analyzer: ProtocolAnalyzer, undo_stack: QUndoStack, project_manager, parent=None): + def __init__( + self, + proto_analyzer: ProtocolAnalyzer, + undo_stack: QUndoStack, + project_manager, + parent=None, + ): super().__init__(parent) self.undo_stack = undo_stack @@ -74,12 +101,20 @@ def __init__(self, proto_analyzer: ProtocolAnalyzer, undo_stack: QUndoStack, pro self.project_manager = project_manager self.proto_analyzer = proto_analyzer - self.signal = proto_analyzer.signal if self.proto_analyzer is not None else None # type: Signal + self.signal = ( + proto_analyzer.signal if self.proto_analyzer is not None else None + ) # type: Signal self.ui.gvSignal.protocol = self.proto_analyzer self.ui.gvSignal.set_signal(self.signal) - self.ui.sliderFFTWindowSize.setValue(int(math.log2(Spectrogram.DEFAULT_FFT_WINDOW_SIZE))) - self.ui.sliderSpectrogramMin.setValue(self.ui.gvSpectrogram.scene_manager.spectrogram.data_min) - self.ui.sliderSpectrogramMax.setValue(self.ui.gvSpectrogram.scene_manager.spectrogram.data_max) + self.ui.sliderFFTWindowSize.setValue( + int(math.log2(Spectrogram.DEFAULT_FFT_WINDOW_SIZE)) + ) + self.ui.sliderSpectrogramMin.setValue( + self.ui.gvSpectrogram.scene_manager.spectrogram.data_min + ) + self.ui.sliderSpectrogramMax.setValue( + self.ui.gvSpectrogram.scene_manager.spectrogram.data_max + ) self.dsp_filter = Filter([0.1] * 10, FilterType.moving_average) self.set_filter_button_caption() @@ -98,25 +133,34 @@ def __init__(self, proto_analyzer: ProtocolAnalyzer, undo_stack: QUndoStack, pro if self.signal is not None: self.filter_menu = QMenu() - self.apply_filter_to_selection_only = self.filter_menu.addAction(self.tr("Apply only to selection")) + self.apply_filter_to_selection_only = self.filter_menu.addAction( + self.tr("Apply only to selection") + ) self.apply_filter_to_selection_only.setCheckable(True) self.apply_filter_to_selection_only.setChecked(False) - self.configure_filter_action = self.filter_menu.addAction("Configure filter...") + self.configure_filter_action = self.filter_menu.addAction( + "Configure filter..." + ) self.configure_filter_action.setIcon(QIcon.fromTheme("configure")) - self.configure_filter_action.triggered.connect(self.on_configure_filter_action_triggered) + self.configure_filter_action.triggered.connect( + self.on_configure_filter_action_triggered + ) self.ui.btnFilter.setMenu(self.filter_menu) if not self.signal.already_demodulated: self.auto_detect_menu = QMenu() - self.detect_noise_action = self.auto_detect_menu.addAction(self.tr("Additionally detect noise")) + self.detect_noise_action = self.auto_detect_menu.addAction( + self.tr("Additionally detect noise") + ) self.detect_noise_action.setCheckable(True) self.detect_noise_action.setChecked(False) - self.detect_modulation_action = self.auto_detect_menu.addAction(self.tr("Additionally detect modulation")) + self.detect_modulation_action = self.auto_detect_menu.addAction( + self.tr("Additionally detect modulation") + ) self.detect_modulation_action.setCheckable(True) self.detect_modulation_action.setChecked(False) self.ui.btnAutoDetect.setMenu(self.auto_detect_menu) - if self.signal.wav_mode: if self.signal.already_demodulated: self.ui.lSignalTyp.setText("Demodulated (1-channel *.wav)") @@ -181,46 +225,86 @@ def create_connects(self): self.ui.btnReplay.clicked.connect(self.on_btn_replay_clicked) self.ui.btnAutoDetect.clicked.connect(self.on_btn_autodetect_clicked) self.ui.btnInfo.clicked.connect(self.on_info_btn_clicked) - self.ui.btnShowHideStartEnd.clicked.connect(self.on_btn_show_hide_start_end_clicked) - self.filter_dialog.filter_accepted.connect(self.on_filter_dialog_filter_accepted) - self.ui.sliderFFTWindowSize.valueChanged.connect(self.on_slider_fft_window_size_value_changed) - self.ui.sliderSpectrogramMin.valueChanged.connect(self.on_slider_spectrogram_min_value_changed) - self.ui.sliderSpectrogramMax.valueChanged.connect(self.on_slider_spectrogram_max_value_changed) - self.ui.gvSpectrogram.y_scale_changed.connect(self.on_gv_spectrogram_y_scale_changed) - self.ui.gvSpectrogram.bandpass_filter_triggered.connect(self.on_bandpass_filter_triggered) + self.ui.btnShowHideStartEnd.clicked.connect( + self.on_btn_show_hide_start_end_clicked + ) + self.filter_dialog.filter_accepted.connect( + self.on_filter_dialog_filter_accepted + ) + self.ui.sliderFFTWindowSize.valueChanged.connect( + self.on_slider_fft_window_size_value_changed + ) + self.ui.sliderSpectrogramMin.valueChanged.connect( + self.on_slider_spectrogram_min_value_changed + ) + self.ui.sliderSpectrogramMax.valueChanged.connect( + self.on_slider_spectrogram_max_value_changed + ) + self.ui.gvSpectrogram.y_scale_changed.connect( + self.on_gv_spectrogram_y_scale_changed + ) + self.ui.gvSpectrogram.bandpass_filter_triggered.connect( + self.on_bandpass_filter_triggered + ) self.ui.gvSpectrogram.export_fta_wanted.connect(self.on_export_fta_wanted) - self.ui.btnAdvancedModulationSettings.clicked.connect(self.on_btn_advanced_modulation_settings_clicked) + self.ui.btnAdvancedModulationSettings.clicked.connect( + self.on_btn_advanced_modulation_settings_clicked + ) if self.signal is not None: self.ui.gvSignal.save_clicked.connect(self.save_signal) - self.signal.samples_per_symbol_changed.connect(self.ui.spinBoxSamplesPerSymbol.setValue) + self.signal.samples_per_symbol_changed.connect( + self.ui.spinBoxSamplesPerSymbol.setValue + ) self.signal.center_changed.connect(self.on_signal_center_changed) self.signal.noise_threshold_changed.connect(self.on_noise_threshold_changed) - self.signal.modulation_type_changed.connect(self.ui.cbModulationType.setCurrentText) + self.signal.modulation_type_changed.connect( + self.ui.cbModulationType.setCurrentText + ) self.signal.tolerance_changed.connect(self.ui.spinBoxTolerance.setValue) self.signal.protocol_needs_update.connect(self.refresh_protocol) - self.signal.data_edited.connect(self.on_signal_data_edited) # Crop/Delete Mute etc. - self.signal.bits_per_symbol_changed.connect(self.ui.spinBoxBitsPerSymbol.setValue) - self.signal.center_spacing_changed.connect(self.on_signal_center_spacing_changed) + self.signal.data_edited.connect( + self.on_signal_data_edited + ) # Crop/Delete Mute etc. + self.signal.bits_per_symbol_changed.connect( + self.ui.spinBoxBitsPerSymbol.setValue + ) + self.signal.center_spacing_changed.connect( + self.on_signal_center_spacing_changed + ) self.signal.sample_rate_changed.connect(self.on_signal_sample_rate_changed) - self.signal.saved_status_changed.connect(self.on_signal_data_changed_before_save) + self.signal.saved_status_changed.connect( + self.on_signal_data_changed_before_save + ) self.ui.btnSaveSignal.clicked.connect(self.save_signal) self.signal.name_changed.connect(self.ui.lineEditSignalName.setText) - self.ui.gvSignal.selection_width_changed.connect(self.start_proto_selection_timer) - self.ui.gvSignal.sel_area_start_end_changed.connect(self.start_proto_selection_timer) - self.proto_selection_timer.timeout.connect(self.update_protocol_selection_from_roi) - self.spectrogram_update_timer.timeout.connect(self.on_spectrogram_update_timer_timeout) + self.ui.gvSignal.selection_width_changed.connect( + self.start_proto_selection_timer + ) + self.ui.gvSignal.sel_area_start_end_changed.connect( + self.start_proto_selection_timer + ) + self.proto_selection_timer.timeout.connect( + self.update_protocol_selection_from_roi + ) + self.spectrogram_update_timer.timeout.connect( + self.on_spectrogram_update_timer_timeout + ) self.ui.lineEditSignalName.editingFinished.connect(self.change_signal_name) - self.proto_analyzer.qt_signals.protocol_updated.connect(self.on_protocol_updated) + self.proto_analyzer.qt_signals.protocol_updated.connect( + self.on_protocol_updated + ) self.ui.btnFilter.clicked.connect(self.on_btn_filter_clicked) - self.ui.gvSignal.set_noise_clicked.connect(self.on_set_noise_in_graphic_view_clicked) + self.ui.gvSignal.set_noise_clicked.connect( + self.on_set_noise_in_graphic_view_clicked + ) self.ui.gvSignal.save_as_clicked.connect(self.save_signal_as) self.ui.gvSignal.export_demodulated_clicked.connect(self.export_demodulated) @@ -228,8 +312,12 @@ def create_connects(self): self.ui.gvSignal.zoomed.connect(self.on_signal_zoomed) self.ui.gvSpectrogram.zoomed.connect(self.on_spectrum_zoomed) self.ui.gvSignal.sel_area_start_end_changed.connect(self.update_selection_area) - self.ui.gvSpectrogram.sel_area_start_end_changed.connect(self.update_selection_area) - self.ui.gvSpectrogram.selection_height_changed.connect(self.update_number_selected_samples) + self.ui.gvSpectrogram.sel_area_start_end_changed.connect( + self.update_selection_area + ) + self.ui.gvSpectrogram.selection_height_changed.connect( + self.update_number_selected_samples + ) self.ui.gvSignal.sep_area_changed.connect(self.set_center) self.ui.sliderYScale.valueChanged.connect(self.on_slider_y_scale_value_changed) @@ -241,28 +329,60 @@ def create_connects(self): self.proto_selection_timer.timeout.connect(self.update_number_selected_samples) - self.ui.cbSignalView.currentIndexChanged.connect(self.on_cb_signal_view_index_changed) - self.ui.cbModulationType.currentTextChanged.connect(self.on_combobox_modulation_type_text_changed) - self.ui.cbProtoView.currentIndexChanged.connect(self.on_combo_box_proto_view_index_changed) + self.ui.cbSignalView.currentIndexChanged.connect( + self.on_cb_signal_view_index_changed + ) + self.ui.cbModulationType.currentTextChanged.connect( + self.on_combobox_modulation_type_text_changed + ) + self.ui.cbProtoView.currentIndexChanged.connect( + self.on_combo_box_proto_view_index_changed + ) self.ui.chkBoxShowProtocol.stateChanged.connect(self.set_protocol_visibility) - self.ui.chkBoxSyncSelection.stateChanged.connect(self.handle_protocol_sync_changed) + self.ui.chkBoxSyncSelection.stateChanged.connect( + self.handle_protocol_sync_changed + ) self.ui.txtEdProto.proto_view_changed.connect(self.show_protocol) - self.ui.txtEdProto.show_proto_clicked.connect(self.update_roi_from_protocol_selection) + self.ui.txtEdProto.show_proto_clicked.connect( + self.update_roi_from_protocol_selection + ) self.ui.txtEdProto.show_proto_clicked.connect(self.zoom_to_roi) - self.ui.txtEdProto.selectionChanged.connect(self.update_roi_from_protocol_selection) - self.ui.txtEdProto.deletion_wanted.connect(self.ui.gvSignal.on_delete_action_triggered) - - self.ui.spinBoxSelectionStart.valueChanged.connect(self.on_spinbox_selection_start_value_changed) - self.ui.spinBoxSelectionEnd.valueChanged.connect(self.on_spinbox_selection_end_value_changed) - self.ui.spinBoxCenterOffset.editingFinished.connect(self.on_spinbox_center_editing_finished) - self.ui.spinBoxCenterSpacing.valueChanged.connect(self.on_spinbox_spacing_value_changed) - self.ui.spinBoxCenterSpacing.editingFinished.connect(self.on_spinbox_spacing_editing_finished) - self.ui.spinBoxTolerance.editingFinished.connect(self.on_spinbox_tolerance_editing_finished) - self.ui.spinBoxNoiseTreshold.editingFinished.connect(self.on_spinbox_noise_threshold_editing_finished) - self.ui.spinBoxSamplesPerSymbol.editingFinished.connect(self.on_spinbox_samples_per_symbol_editing_finished) - self.ui.spinBoxBitsPerSymbol.editingFinished.connect(self.on_spinbox_bits_per_symbol_editing_finished) + self.ui.txtEdProto.selectionChanged.connect( + self.update_roi_from_protocol_selection + ) + self.ui.txtEdProto.deletion_wanted.connect( + self.ui.gvSignal.on_delete_action_triggered + ) + + self.ui.spinBoxSelectionStart.valueChanged.connect( + self.on_spinbox_selection_start_value_changed + ) + self.ui.spinBoxSelectionEnd.valueChanged.connect( + self.on_spinbox_selection_end_value_changed + ) + self.ui.spinBoxCenterOffset.editingFinished.connect( + self.on_spinbox_center_editing_finished + ) + self.ui.spinBoxCenterSpacing.valueChanged.connect( + self.on_spinbox_spacing_value_changed + ) + self.ui.spinBoxCenterSpacing.editingFinished.connect( + self.on_spinbox_spacing_editing_finished + ) + self.ui.spinBoxTolerance.editingFinished.connect( + self.on_spinbox_tolerance_editing_finished + ) + self.ui.spinBoxNoiseTreshold.editingFinished.connect( + self.on_spinbox_noise_threshold_editing_finished + ) + self.ui.spinBoxSamplesPerSymbol.editingFinished.connect( + self.on_spinbox_samples_per_symbol_editing_finished + ) + self.ui.spinBoxBitsPerSymbol.editingFinished.connect( + self.on_spinbox_bits_per_symbol_editing_finished + ) def refresh_signal_information(self, block=True): self.ui.spinBoxTolerance.blockSignals(block) @@ -277,7 +397,9 @@ def refresh_signal_information(self, block=True): self.ui.spinBoxSamplesPerSymbol.setValue(self.signal.samples_per_symbol) self.ui.spinBoxNoiseTreshold.setValue(self.signal.noise_threshold_relative) self.ui.cbModulationType.setCurrentText(self.signal.modulation_type) - self.ui.btnAdvancedModulationSettings.setVisible(self.ui.cbModulationType.currentText() in ("ASK", "PSK")) + self.ui.btnAdvancedModulationSettings.setVisible( + self.ui.cbModulationType.currentText() in ("ASK", "PSK") + ) self.ui.spinBoxCenterSpacing.setValue(self.signal.center_spacing) self.ui.spinBoxBitsPerSymbol.setValue(self.signal.bits_per_symbol) @@ -293,8 +415,12 @@ def refresh_signal_information(self, block=True): def set_empty_frame_visibilities(self): for widget in dir(self.ui): w = getattr(self.ui, widget) - if hasattr(w, "hide") and w not in (self.ui.lSignalNr, self.ui.lSignalTyp, - self.ui.btnCloseSignal, self.ui.lineEditSignalName): + if hasattr(w, "hide") and w not in ( + self.ui.lSignalNr, + self.ui.lSignalTyp, + self.ui.btnCloseSignal, + self.ui.lineEditSignalName, + ): w.hide() self.adjustSize() @@ -304,20 +430,30 @@ def cancel_filtering(self): def update_number_selected_samples(self): if self.spectrogram_is_active: - self.ui.lNumSelectedSamples.setText(str(abs(int(self.ui.gvSpectrogram.selection_area.length)))) + self.ui.lNumSelectedSamples.setText( + str(abs(int(self.ui.gvSpectrogram.selection_area.length))) + ) self.__set_selected_bandwidth() return else: - self.ui.lNumSelectedSamples.setText(str(abs(int(self.ui.gvSignal.selection_area.length)))) + self.ui.lNumSelectedSamples.setText( + str(abs(int(self.ui.gvSignal.selection_area.length))) + ) self.__set_duration() try: - start, end = int(self.ui.gvSignal.selection_area.start), int(self.ui.gvSignal.selection_area.end) + start, end = int(self.ui.gvSignal.selection_area.start), int( + self.ui.gvSignal.selection_area.end + ) power_str = "-\u221e" # minus infinity if start < end: - max_window_size = 10 ** 5 + max_window_size = 10**5 step_size = int(math.ceil((end - start) / max_window_size)) - power = np.mean(self.signal.iq_array.subarray(start, end, step_size).magnitudes_normalized) + power = np.mean( + self.signal.iq_array.subarray( + start, end, step_size + ).magnitudes_normalized + ) if power > 0: power_str = Formatter.big_value_with_suffix(10 * np.log10(power), 2) @@ -336,8 +472,12 @@ def __set_spectrogram_adjust_widgets_visibility(self): self.ui.sliderFFTWindowSize.setVisible(self.ui.cbSignalView.currentIndex() == 2) self.ui.labelSpectrogramMin.setVisible(self.ui.cbSignalView.currentIndex() == 2) self.ui.labelSpectrogramMax.setVisible(self.ui.cbSignalView.currentIndex() == 2) - self.ui.sliderSpectrogramMin.setVisible(self.ui.cbSignalView.currentIndex() == 2) - self.ui.sliderSpectrogramMax.setVisible(self.ui.cbSignalView.currentIndex() == 2) + self.ui.sliderSpectrogramMin.setVisible( + self.ui.cbSignalView.currentIndex() == 2 + ) + self.ui.sliderSpectrogramMax.setVisible( + self.ui.cbSignalView.currentIndex() == 2 + ) def __set_selected_bandwidth(self): try: @@ -346,7 +486,9 @@ def __set_selected_bandwidth(self): return if self.ui.gvSpectrogram.height_spectrogram and self.signal: - bw = (num_samples / self.ui.gvSpectrogram.height_spectrogram) * self.signal.sample_rate + bw = ( + num_samples / self.ui.gvSpectrogram.height_spectrogram + ) * self.signal.sample_rate self.ui.lDuration.setText(Formatter.big_value_with_suffix(bw) + "Hz") def __set_duration(self): # On Signal Sample Rate changed @@ -361,7 +503,11 @@ def __set_duration(self): # On Signal Sample Rate changed def on_slider_y_scale_value_changed(self): try: - gv = self.ui.gvSignal if self.ui.stackedWidget.currentIndex() == 0 else self.ui.gvSpectrogram + gv = ( + self.ui.gvSignal + if self.ui.stackedWidget.currentIndex() == 0 + else self.ui.gvSpectrogram + ) yscale = self.ui.sliderYScale.value() current_factor = gv.sceneRect().height() / gv.view_rect().height() gv.scale(1, yscale / current_factor) @@ -399,7 +545,9 @@ def mousePressEvent(self, event): drag.exec_() def set_filter_button_caption(self): - self.ui.btnFilter.setText("Filter ({0})".format(self.dsp_filter.filter_type.value)) + self.ui.btnFilter.setText( + "Filter ({0})".format(self.dsp_filter.filter_type.value) + ) def dragMoveEvent(self, event): event.accept() @@ -421,11 +569,13 @@ def create_new_signal(self, start, end): Errors.empty_selection() def my_close(self): - not_show = settings.read('not_show_close_dialog', False, type=bool) + not_show = settings.read("not_show_close_dialog", False, type=bool) if not not_show: cb = QCheckBox("Do not show this again.") - msgbox = QMessageBox(QMessageBox.Question, "Confirm close", "Are you sure you want to close?") + msgbox = QMessageBox( + QMessageBox.Question, "Confirm close", "Are you sure you want to close?" + ) msgbox.addButton(QMessageBox.Yes) msgbox.addButton(QMessageBox.No) msgbox.setDefaultButton(QMessageBox.No) @@ -449,8 +599,12 @@ def save_signal(self): def save_signal_as(self): try: - FileOperator.ask_signal_file_name_and_save(self.signal.name, self.signal.iq_array, self.signal.sample_rate, - self.signal.wav_mode) + FileOperator.ask_signal_file_name_and_save( + self.signal.name, + self.signal.iq_array, + self.signal.sample_rate, + self.signal.wav_mode, + ) except Exception as e: Errors.exception(e) @@ -461,7 +615,9 @@ def export_demodulated(self): logger.exception(e) initial_name = "demodulated.wav" - filename = FileOperator.ask_save_file_name(initial_name, caption="Export demodulated") + filename = FileOperator.ask_save_file_name( + initial_name, caption="Export demodulated" + ) if filename: try: self.setCursor(Qt.WaitCursor) @@ -469,11 +625,17 @@ def export_demodulated(self): if filename.endswith(".wav") or filename.endswith(".sub"): data = self.signal.qad.astype(np.float32) data /= np.max(np.abs(data)) - FileOperator.save_data(IQArray(data, skip_conversion=True), filename, self.signal.sample_rate, - num_channels=1) + FileOperator.save_data( + IQArray(data, skip_conversion=True), + filename, + self.signal.sample_rate, + num_channels=1, + ) self.unsetCursor() except Exception as e: - QMessageBox.critical(self, self.tr("Error exporting demodulated data"), e.args[0]) + QMessageBox.critical( + self, self.tr("Error exporting demodulated data"), e.args[0] + ) def draw_signal(self, full_signal=False): self.scene_manager.scene_type = self.ui.cbSignalView.currentIndex() @@ -485,13 +647,25 @@ def draw_signal(self, full_signal=False): self.ui.gvSignal.y_sep = -self.signal.center - def restore_protocol_selection(self, sel_start, sel_end, start_message, end_message, old_protoview): + def restore_protocol_selection( + self, sel_start, sel_end, start_message, end_message, old_protoview + ): if old_protoview == self.proto_view: return self.protocol_selection_is_updateable = False - sel_start = int(self.proto_analyzer.convert_index(sel_start, old_protoview, self.proto_view, True)[0]) - sel_end = int(math.ceil(self.proto_analyzer.convert_index(sel_end, old_protoview, self.proto_view, True)[1])) + sel_start = int( + self.proto_analyzer.convert_index( + sel_start, old_protoview, self.proto_view, True + )[0] + ) + sel_end = int( + math.ceil( + self.proto_analyzer.convert_index( + sel_end, old_protoview, self.proto_view, True + )[1] + ) + ) c = self.ui.txtEdProto.textCursor() @@ -569,7 +743,9 @@ def show_protocol(self, old_view=-1, refresh=False): read_pause = False sel_end = self.ui.txtEdProto.textCursor().selectionEnd() - text = self.ui.txtEdProto.toPlainText()[self.ui.txtEdProto.textCursor().selectionStart():sel_end] + text = self.ui.txtEdProto.toPlainText()[ + self.ui.txtEdProto.textCursor().selectionStart() : sel_end + ] end_message = 0 sel_end = 0 read_pause = False @@ -585,9 +761,13 @@ def show_protocol(self, old_view=-1, refresh=False): end_message += 1 read_pause = False - self.ui.txtEdProto.setHtml(self.proto_analyzer.plain_to_html(self.proto_view)) + self.ui.txtEdProto.setHtml( + self.proto_analyzer.plain_to_html(self.proto_view) + ) try: - self.restore_protocol_selection(sel_start, sel_end, start_message, end_message, old_view) + self.restore_protocol_selection( + sel_start, sel_end, start_message, end_message, old_view + ) except TypeError: # Without try/except: segfault (TypeError) when changing sample_rate in info dialog of signal pass @@ -597,11 +777,17 @@ def show_protocol(self, old_view=-1, refresh=False): def draw_spectrogram(self, show_full_scene=False, force_redraw=False): self.setCursor(Qt.WaitCursor) window_size = 2 ** self.ui.sliderFFTWindowSize.value() - data_min, data_max = self.ui.sliderSpectrogramMin.value(), self.ui.sliderSpectrogramMax.value() - - redraw_needed = self.ui.gvSpectrogram.scene_manager.set_parameters(self.signal.iq_array.data, - window_size=window_size, - data_min=data_min, data_max=data_max) + data_min, data_max = ( + self.ui.sliderSpectrogramMin.value(), + self.ui.sliderSpectrogramMax.value(), + ) + + redraw_needed = self.ui.gvSpectrogram.scene_manager.set_parameters( + self.signal.iq_array.data, + window_size=window_size, + data_min=data_min, + data_max=data_max, + ) self.ui.gvSpectrogram.scene_manager.update_scene_rect() if show_full_scene: @@ -641,9 +827,17 @@ def eliminate(self): self.deleteLater() def __handle_graphic_view_zoomed(self, graphic_view): - self.ui.lSamplesInView.setText("{0:n}".format(int(graphic_view.view_rect().width()))) + self.ui.lSamplesInView.setText( + "{0:n}".format(int(graphic_view.view_rect().width())) + ) self.ui.spinBoxXZoom.blockSignals(True) - self.ui.spinBoxXZoom.setValue(int(graphic_view.sceneRect().width() / graphic_view.view_rect().width() * 100)) + self.ui.spinBoxXZoom.setValue( + int( + graphic_view.sceneRect().width() + / graphic_view.view_rect().width() + * 100 + ) + ) self.ui.spinBoxXZoom.blockSignals(False) @pyqtSlot() @@ -656,9 +850,13 @@ def on_spectrum_zoomed(self): @pyqtSlot(int) def on_spinbox_x_zoom_value_changed(self, value: int): - graphic_view = self.ui.gvSpectrogram if self.spectrogram_is_active else self.ui.gvSignal + graphic_view = ( + self.ui.gvSpectrogram if self.spectrogram_is_active else self.ui.gvSignal + ) zoom_factor = value / 100 - current_factor = graphic_view.sceneRect().width() / graphic_view.view_rect().width() + current_factor = ( + graphic_view.sceneRect().width() / graphic_view.view_rect().width() + ) graphic_view.zoom(zoom_factor / current_factor) @pyqtSlot() @@ -687,14 +885,19 @@ def on_noise_threshold_changed(self): self.ui.spinBoxNoiseTreshold.setValue(self.signal.noise_threshold_relative) minimum = self.signal.noise_min_plot maximum = self.signal.noise_max_plot - if self.ui.cbSignalView.currentIndex() == 0 or self.ui.cbSignalView.currentIndex() == 3: + if ( + self.ui.cbSignalView.currentIndex() == 0 + or self.ui.cbSignalView.currentIndex() == 3 + ): # Draw Noise only in analog and I/Q view self.ui.gvSignal.scene().draw_noise_area(minimum, maximum - minimum) @pyqtSlot(int) def on_spinbox_selection_start_value_changed(self, value: int): if self.spectrogram_is_active: - self.ui.gvSpectrogram.set_vertical_selection(y=self.ui.gvSpectrogram.sceneRect().height() - value) + self.ui.gvSpectrogram.set_vertical_selection( + y=self.ui.gvSpectrogram.sceneRect().height() - value + ) self.ui.gvSpectrogram.emit_selection_size_changed() self.ui.gvSpectrogram.selection_area.finished = True else: @@ -705,11 +908,15 @@ def on_spinbox_selection_start_value_changed(self, value: int): @pyqtSlot(int) def on_spinbox_selection_end_value_changed(self, value: int): if self.spectrogram_is_active: - self.ui.gvSpectrogram.set_vertical_selection(h=self.ui.spinBoxSelectionStart.value() - value) + self.ui.gvSpectrogram.set_vertical_selection( + h=self.ui.spinBoxSelectionStart.value() - value + ) self.ui.gvSpectrogram.emit_selection_size_changed() self.ui.gvSpectrogram.selection_area.finished = True else: - self.ui.gvSignal.set_horizontal_selection(w=value - self.ui.spinBoxSelectionStart.value()) + self.ui.gvSignal.set_horizontal_selection( + w=value - self.ui.spinBoxSelectionStart.value() + ) self.ui.gvSignal.selection_area.finished = True self.ui.gvSignal.emit_selection_size_changed() @@ -782,19 +989,25 @@ def on_btn_autodetect_clicked(self): detect_noise = self.detect_noise_action.isChecked() except AttributeError: detect_noise = False - success = self.signal.auto_detect(detect_modulation=detect_modulation, detect_noise=detect_noise) + success = self.signal.auto_detect( + detect_modulation=detect_modulation, detect_noise=detect_noise + ) self.ui.btnAutoDetect.setEnabled(True) self.unsetCursor() if not success: - Errors.generic_error(self.tr("Autodetection failed"), - self.tr("Failed to autodetect parameters for this signal.")) + Errors.generic_error( + self.tr("Autodetection failed"), + self.tr("Failed to autodetect parameters for this signal."), + ) @pyqtSlot() def on_btn_replay_clicked(self): project_manager = self.project_manager try: - dialog = SendDialog(project_manager, modulated_data=self.signal.iq_array, parent=self) + dialog = SendDialog( + project_manager, modulated_data=self.signal.iq_array, parent=self + ) except OSError as e: logger.error(repr(e)) return @@ -833,7 +1046,9 @@ def set_center(self, th): self.ui.spinBoxCenterOffset.setValue(th) self.ui.spinBoxCenterOffset.editingFinished.emit() - def set_roi_from_protocol_analysis(self, start_message, start_pos, end_message, end_pos, view_type): + def set_roi_from_protocol_analysis( + self, start_message, start_pos, end_message, end_pos, view_type + ): if not self.proto_analyzer: return @@ -852,15 +1067,17 @@ def set_roi_from_protocol_analysis(self, start_message, start_pos, end_message, start_pos *= 8 end_pos *= 8 - sample_pos, num_samples = self.proto_analyzer.get_samplepos_of_bitseq(start_message, start_pos, - end_message, end_pos, - True) + sample_pos, num_samples = self.proto_analyzer.get_samplepos_of_bitseq( + start_message, start_pos, end_message, end_pos, True + ) self.protocol_selection_is_updateable = False if sample_pos != -1: if self.jump_sync and self.sync_protocol: self.ui.gvSignal.centerOn(sample_pos, self.ui.gvSignal.y_center) self.ui.gvSignal.set_horizontal_selection(sample_pos, num_samples) - self.ui.gvSignal.centerOn(sample_pos + num_samples, self.ui.gvSignal.y_center) + self.ui.gvSignal.centerOn( + sample_pos + num_samples, self.ui.gvSignal.y_center + ) else: self.ui.gvSignal.set_horizontal_selection(sample_pos, num_samples) @@ -874,11 +1091,16 @@ def set_roi_from_protocol_analysis(self, start_message, start_pos, end_message, @pyqtSlot() def update_roi_from_protocol_selection(self): text_edit = self.ui.txtEdProto - start_pos, end_pos = text_edit.textCursor().selectionStart(), text_edit.textCursor().selectionEnd() + start_pos, end_pos = ( + text_edit.textCursor().selectionStart(), + text_edit.textCursor().selectionEnd(), + ) if start_pos == end_pos == -1: return - forward_selection = text_edit.textCursor().anchor() <= text_edit.textCursor().position() + forward_selection = ( + text_edit.textCursor().anchor() <= text_edit.textCursor().position() + ) if start_pos > end_pos: start_pos, end_pos = end_pos, start_pos @@ -890,11 +1112,11 @@ def update_roi_from_protocol_selection(self): newline_pos = text[:start_pos].rfind("\n") if newline_pos != -1: - start_pos -= (newline_pos + 1) + start_pos -= newline_pos + 1 newline_pos = text[:end_pos].rfind("\n") if newline_pos != -1: - end_pos -= (newline_pos + 1) + end_pos -= newline_pos + 1 factor = 1 if text_edit.cur_view == 0 else 4 if text_edit.cur_view == 1 else 8 start_pos *= factor @@ -921,8 +1143,9 @@ def update_roi_from_protocol_selection(self): if "[" in selected_text[last_newline:]: include_last_pause = True - sample_pos, num_samples = self.proto_analyzer.get_samplepos_of_bitseq(start_message, start_pos, end_message, - end_pos, include_last_pause) + sample_pos, num_samples = self.proto_analyzer.get_samplepos_of_bitseq( + start_message, start_pos, end_message, end_pos, include_last_pause + ) except IndexError: return @@ -932,8 +1155,12 @@ def update_roi_from_protocol_selection(self): if self.jump_sync and self.sync_protocol: self.ui.gvSignal.centerOn(sample_pos, self.ui.gvSignal.y_center) self.ui.gvSignal.set_horizontal_selection(sample_pos, num_samples) - if forward_selection: # Forward Selection --> Center ROI to End of Selection - self.ui.gvSignal.centerOn(sample_pos + num_samples, self.ui.gvSignal.y_center) + if ( + forward_selection + ): # Forward Selection --> Center ROI to End of Selection + self.ui.gvSignal.centerOn( + sample_pos + num_samples, self.ui.gvSignal.y_center + ) else: # Backward Selection --> Center ROI to Start of Selection self.ui.gvSignal.centerOn(sample_pos, self.ui.gvSignal.y_center) else: @@ -957,7 +1184,11 @@ def start_proto_selection_timer(self): def update_protocol_selection_from_roi(self): protocol = self.proto_analyzer - if protocol is None or protocol.messages is None or not self.ui.chkBoxShowProtocol.isChecked(): + if ( + protocol is None + or protocol.messages is None + or not self.ui.chkBoxShowProtocol.isChecked() + ): return start = self.ui.gvSignal.selection_area.x @@ -972,7 +1203,12 @@ def update_protocol_selection_from_roi(self): self.ui.txtEdProto.blockSignals(True) try: - start_message, start_index, end_message, end_index = protocol.get_bitseq_from_selection(start, w) + ( + start_message, + start_index, + end_message, + end_index, + ) = protocol.get_bitseq_from_selection(start, w) except IndexError: c.clearSelection() self.ui.txtEdProto.setTextCursor(c) @@ -980,15 +1216,29 @@ def update_protocol_selection_from_roi(self): self.ui.txtEdProto.blockSignals(False) return - if start_message == -1 or end_index == -1 or start_index == -1 or end_message == -1: + if ( + start_message == -1 + or end_index == -1 + or start_index == -1 + or end_message == -1 + ): c.clearSelection() self.ui.txtEdProto.setTextCursor(c) self.jump_sync = True self.ui.txtEdProto.blockSignals(False) return - start_index = int(protocol.convert_index(start_index, 0, self.proto_view, True)[0]) - end_index = int(math.ceil(protocol.convert_index(end_index, 0, self.proto_view, True)[1])) + 1 + start_index = int( + protocol.convert_index(start_index, 0, self.proto_view, True)[0] + ) + end_index = ( + int( + math.ceil( + protocol.convert_index(end_index, 0, self.proto_view, True)[1] + ) + ) + + 1 + ) text = self.ui.txtEdProto.toPlainText() n = 0 message_pos = 0 @@ -1013,10 +1263,16 @@ def update_protocol_selection_from_roi(self): def __set_samples_in_view(self): if self.spectrogram_is_active: - self.ui.lSamplesInView.setText("{0:n}".format(int(self.ui.gvSpectrogram.view_rect().width()))) - self.ui.lSamplesTotal.setText("{0:n}".format(self.ui.gvSpectrogram.width_spectrogram)) + self.ui.lSamplesInView.setText( + "{0:n}".format(int(self.ui.gvSpectrogram.view_rect().width())) + ) + self.ui.lSamplesTotal.setText( + "{0:n}".format(self.ui.gvSpectrogram.width_spectrogram) + ) else: - self.ui.lSamplesInView.setText("{0:n}".format(int(self.ui.gvSignal.view_rect().width()))) + self.ui.lSamplesInView.setText( + "{0:n}".format(int(self.ui.gvSignal.view_rect().width())) + ) self.ui.lSamplesTotal.setText("{0:n}".format(self.signal.num_samples)) def refresh_signal(self, draw_full_signal=False): @@ -1036,10 +1292,17 @@ def on_signal_center_changed(self, center): self.ui.spinBoxCenterOffset.setValue(center) def on_spinbox_noise_threshold_editing_finished(self): - if self.signal is not None and self.signal.noise_threshold_relative != self.ui.spinBoxNoiseTreshold.value(): - noise_action = ChangeSignalParameter(signal=self.signal, protocol=self.proto_analyzer, - parameter_name="noise_threshold_relative", - parameter_value=self.ui.spinBoxNoiseTreshold.value()) + if ( + self.signal is not None + and self.signal.noise_threshold_relative + != self.ui.spinBoxNoiseTreshold.value() + ): + noise_action = ChangeSignalParameter( + signal=self.signal, + protocol=self.proto_analyzer, + parameter_name="noise_threshold_relative", + parameter_value=self.ui.spinBoxNoiseTreshold.value(), + ) self.undo_stack.push(noise_action) def contextMenuEvent(self, event: QContextMenuEvent): @@ -1047,7 +1310,9 @@ def contextMenuEvent(self, event: QContextMenuEvent): return menu = QMenu() - apply_to_all_action = menu.addAction(self.tr("Apply values (BitLen, 0/1-Threshold, Tolerance) to all signals")) + apply_to_all_action = menu.addAction( + self.tr("Apply values (BitLen, 0/1-Threshold, Tolerance) to all signals") + ) menu.addSeparator() auto_detect_action = menu.addAction(self.tr("Auto-Detect signal parameters")) action = menu.exec_(self.mapToGlobal(event.pos())) @@ -1070,7 +1335,9 @@ def on_participant_changed(self): self.proto_analyzer.qt_signals.protocol_updated.emit() def resizeEvent(self, event: QResizeEvent): - old_width, new_width = max(1, event.oldSize().width()), max(1, event.size().width()) + old_width, new_width = max(1, event.oldSize().width()), max( + 1, event.size().width() + ) super().resizeEvent(event) self.on_slider_y_scale_value_changed() @@ -1091,9 +1358,12 @@ def on_info_btn_clicked(self): @pyqtSlot(str) def on_combobox_modulation_type_text_changed(self, txt: str): if txt != self.signal.modulation_type: - modulation_action = ChangeSignalParameter(signal=self.signal, protocol=self.proto_analyzer, - parameter_name="modulation_type", - parameter_value=txt) + modulation_action = ChangeSignalParameter( + signal=self.signal, + protocol=self.proto_analyzer, + parameter_name="modulation_type", + parameter_value=txt, + ) self.undo_stack.push(modulation_action) @@ -1102,7 +1372,9 @@ def on_combobox_modulation_type_text_changed(self, txt: str): self.scene_manager.init_scene() self.on_slider_y_scale_value_changed() - self.ui.btnAdvancedModulationSettings.setVisible(self.ui.cbModulationType.currentText() in ("ASK", "PSK")) + self.ui.btnAdvancedModulationSettings.setVisible( + self.ui.cbModulationType.currentText() in ("ASK", "PSK") + ) @pyqtSlot() def on_signal_data_changed_before_save(self): @@ -1146,9 +1418,12 @@ def on_btn_show_hide_start_end_clicked(self): def on_spinbox_tolerance_editing_finished(self): if self.signal.tolerance != self.ui.spinBoxTolerance.value(): self.ui.spinBoxTolerance.blockSignals(True) - tolerance_action = ChangeSignalParameter(signal=self.signal, protocol=self.proto_analyzer, - parameter_name="tolerance", - parameter_value=self.ui.spinBoxTolerance.value()) + tolerance_action = ChangeSignalParameter( + signal=self.signal, + protocol=self.proto_analyzer, + parameter_name="tolerance", + parameter_value=self.ui.spinBoxTolerance.value(), + ) self.undo_stack.push(tolerance_action) self.ui.spinBoxTolerance.blockSignals(False) @@ -1156,9 +1431,12 @@ def on_spinbox_tolerance_editing_finished(self): def on_spinbox_samples_per_symbol_editing_finished(self): if self.signal.samples_per_symbol != self.ui.spinBoxSamplesPerSymbol.value(): self.ui.spinBoxSamplesPerSymbol.blockSignals(True) - action = ChangeSignalParameter(signal=self.signal, protocol=self.proto_analyzer, - parameter_name="samples_per_symbol", - parameter_value=self.ui.spinBoxSamplesPerSymbol.value()) + action = ChangeSignalParameter( + signal=self.signal, + protocol=self.proto_analyzer, + parameter_name="samples_per_symbol", + parameter_value=self.ui.spinBoxSamplesPerSymbol.value(), + ) self.undo_stack.push(action) self.ui.spinBoxSamplesPerSymbol.blockSignals(False) @@ -1166,9 +1444,12 @@ def on_spinbox_samples_per_symbol_editing_finished(self): def on_spinbox_bits_per_symbol_editing_finished(self): if self.signal.bits_per_symbol != self.ui.spinBoxBitsPerSymbol.value(): self.ui.spinBoxBitsPerSymbol.blockSignals(True) - bits_per_symbol_action = ChangeSignalParameter(signal=self.signal, protocol=self.proto_analyzer, - parameter_name="bits_per_symbol", - parameter_value=self.ui.spinBoxBitsPerSymbol.value()) + bits_per_symbol_action = ChangeSignalParameter( + signal=self.signal, + protocol=self.proto_analyzer, + parameter_name="bits_per_symbol", + parameter_value=self.ui.spinBoxBitsPerSymbol.value(), + ) self.undo_stack.push(bits_per_symbol_action) self.ui.spinBoxBitsPerSymbol.blockSignals(False) @@ -1181,25 +1462,33 @@ def on_spinbox_bits_per_symbol_editing_finished(self): def on_spinbox_center_editing_finished(self): if self.signal.center != self.ui.spinBoxCenterOffset.value(): self.ui.spinBoxCenterOffset.blockSignals(True) - center_action = ChangeSignalParameter(signal=self.signal, protocol=self.proto_analyzer, - parameter_name="center", - parameter_value=self.ui.spinBoxCenterOffset.value()) + center_action = ChangeSignalParameter( + signal=self.signal, + protocol=self.proto_analyzer, + parameter_name="center", + parameter_value=self.ui.spinBoxCenterOffset.value(), + ) self.undo_stack.push(center_action) self.ui.spinBoxCenterOffset.blockSignals(False) @pyqtSlot() def on_spinbox_spacing_value_changed(self): if self.ui.gvSignal.scene_type == 1: - thresholds = self.signal.get_thresholds_for_center(self.signal.center, self.ui.spinBoxCenterSpacing.value()) + thresholds = self.signal.get_thresholds_for_center( + self.signal.center, self.ui.spinBoxCenterSpacing.value() + ) self.ui.gvSignal.scene().draw_sep_area(-thresholds) @pyqtSlot() def on_spinbox_spacing_editing_finished(self): if self.signal.center_spacing != self.ui.spinBoxCenterSpacing.value(): self.ui.spinBoxCenterSpacing.blockSignals(True) - center_spacing_action = ChangeSignalParameter(signal=self.signal, protocol=self.proto_analyzer, - parameter_name="center_spacing", - parameter_value=self.ui.spinBoxCenterSpacing.value()) + center_spacing_action = ChangeSignalParameter( + signal=self.signal, + protocol=self.proto_analyzer, + parameter_name="center_spacing", + parameter_value=self.ui.spinBoxCenterSpacing.value(), + ) self.undo_stack.push(center_spacing_action) self.ui.spinBoxCenterSpacing.blockSignals(False) @@ -1215,12 +1504,21 @@ def refresh(self, draw_full_signal=False): @pyqtSlot() def on_btn_filter_clicked(self): if self.apply_filter_to_selection_only.isChecked(): - start, end = self.ui.gvSignal.selection_area.start, self.ui.gvSignal.selection_area.end + start, end = ( + self.ui.gvSignal.selection_area.start, + self.ui.gvSignal.selection_area.end, + ) else: start, end = 0, self.signal.num_samples - filter_action = EditSignalAction(signal=self.signal, mode=EditAction.filter, start=start, end=end, - dsp_filter=self.dsp_filter, protocol=self.proto_analyzer) + filter_action = EditSignalAction( + signal=self.signal, + mode=EditAction.filter, + start=start, + end=end, + dsp_filter=self.dsp_filter, + protocol=self.proto_analyzer, + ) self.undo_stack.push(filter_action) @pyqtSlot() @@ -1251,8 +1549,16 @@ def on_bandpass_filter_triggered(self, f_low: float, f_high: float): QApplication.instance().setOverrideCursor(Qt.WaitCursor) filter_bw = Filter.read_configured_filter_bw() filtered = Array("f", 2 * self.signal.num_samples) - p = Process(target=perform_filter, - args=(filtered, self.signal.iq_array.as_complex64(), f_low, f_high, filter_bw)) + p = Process( + target=perform_filter, + args=( + filtered, + self.signal.iq_array.as_complex64(), + f_low, + f_high, + filter_bw, + ), + ) p.daemon = True p.start() @@ -1269,8 +1575,12 @@ def on_bandpass_filter_triggered(self, f_low: float, f_high: float): filtered = np.frombuffer(filtered.get_obj(), dtype=np.complex64) signal = self.signal.create_new(new_data=filtered.astype(np.complex64)) - signal.name = self.signal.name + " filtered with f_low={0:.4n} f_high={1:.4n} bw={2:.4n}".format(f_low, f_high, - filter_bw) + signal.name = ( + self.signal.name + + " filtered with f_low={0:.4n} f_high={1:.4n} bw={2:.4n}".format( + f_low, f_high, filter_bw + ) + ) self.signal_created.emit(signal) QApplication.instance().restoreOverrideCursor() @@ -1290,24 +1600,33 @@ def on_signal_sample_rate_changed(self): @pyqtSlot(int) def on_pause_threshold_edited(self, pause_threshold: int): if self.signal.pause_threshold != pause_threshold: - pause_threshold_action = ChangeSignalParameter(signal=self.signal, protocol=self.proto_analyzer, - parameter_name="pause_threshold", - parameter_value=pause_threshold) + pause_threshold_action = ChangeSignalParameter( + signal=self.signal, + protocol=self.proto_analyzer, + parameter_name="pause_threshold", + parameter_value=pause_threshold, + ) self.undo_stack.push(pause_threshold_action) @pyqtSlot(int) def on_message_length_divisor_edited(self, message_length_divisor: int): if self.signal.message_length_divisor != message_length_divisor: - message_length_divisor_action = ChangeSignalParameter(signal=self.signal, protocol=self.proto_analyzer, - parameter_name="message_length_divisor", - parameter_value=message_length_divisor) + message_length_divisor_action = ChangeSignalParameter( + signal=self.signal, + protocol=self.proto_analyzer, + parameter_name="message_length_divisor", + parameter_value=message_length_divisor, + ) self.undo_stack.push(message_length_divisor_action) def get_advanced_modulation_settings_dialog(self): - dialog = AdvancedModulationOptionsDialog(self.signal.pause_threshold, self.signal.message_length_divisor, - parent=self) + dialog = AdvancedModulationOptionsDialog( + self.signal.pause_threshold, self.signal.message_length_divisor, parent=self + ) dialog.pause_threshold_edited.connect(self.on_pause_threshold_edited) - dialog.message_length_divisor_edited.connect(self.on_message_length_divisor_edited) + dialog.message_length_divisor_edited.connect( + self.on_message_length_divisor_edited + ) return dialog def get_costas_dialog(self): @@ -1339,14 +1658,18 @@ def on_export_fta_wanted(self): logger.exception(e) initial_name = "spectrogram.ft" - filename = FileOperator.ask_save_file_name(initial_name, caption="Export spectrogram") + filename = FileOperator.ask_save_file_name( + initial_name, caption="Export spectrogram" + ) if not filename: return QApplication.setOverrideCursor(Qt.WaitCursor) try: - self.ui.gvSpectrogram.scene_manager.spectrogram.export_to_fta(sample_rate=self.signal.sample_rate, - filename=filename, - include_amplitude=filename.endswith(".fta")) + self.ui.gvSpectrogram.scene_manager.spectrogram.export_to_fta( + sample_rate=self.signal.sample_rate, + filename=filename, + include_amplitude=filename.endswith(".fta"), + ) except Exception as e: Errors.exception(e) finally: diff --git a/src/urh/controller/widgets/SniffSettingsWidget.py b/src/urh/controller/widgets/SniffSettingsWidget.py index 62eb5ec6e4..9921b40498 100644 --- a/src/urh/controller/widgets/SniffSettingsWidget.py +++ b/src/urh/controller/widgets/SniffSettingsWidget.py @@ -15,8 +15,16 @@ class SniffSettingsWidget(QWidget): sniff_file_edited = pyqtSignal() sniff_parameters_changed = pyqtSignal(dict) - def __init__(self, device_name: str, project_manager: ProjectManager, signal=None, backend_handler=None, - network_raw_mode=False, signals=None, parent=None): + def __init__( + self, + device_name: str, + project_manager: ProjectManager, + signal=None, + backend_handler=None, + network_raw_mode=False, + signals=None, + parent=None, + ): super().__init__(parent) self.ui = Ui_SniffSettings() self.ui.setupUi(self) @@ -29,16 +37,20 @@ def __init__(self, device_name: str, project_manager: ProjectManager, signal=Non self.bootstrap(project_manager.device_conf, signal, enforce_default=True) - self.sniffer = ProtocolSniffer(samples_per_symbol=self.ui.spinbox_sniff_SamplesPerSymbol.value(), - center=self.ui.spinbox_sniff_Center.value(), - center_spacing=self.ui.spinBoxCenterSpacing.value(), - noise=self.ui.spinbox_sniff_Noise.value(), - tolerance=self.ui.spinbox_sniff_ErrorTolerance.value(), - modulation_type=self.ui.combox_sniff_Modulation.currentText(), - bits_per_symbol=self.ui.spinBoxBitsPerSymbol.value(), - device=device_name, - backend_handler=BackendHandler() if backend_handler is None else backend_handler, - network_raw_mode=network_raw_mode) + self.sniffer = ProtocolSniffer( + samples_per_symbol=self.ui.spinbox_sniff_SamplesPerSymbol.value(), + center=self.ui.spinbox_sniff_Center.value(), + center_spacing=self.ui.spinBoxCenterSpacing.value(), + noise=self.ui.spinbox_sniff_Noise.value(), + tolerance=self.ui.spinbox_sniff_ErrorTolerance.value(), + modulation_type=self.ui.combox_sniff_Modulation.currentText(), + bits_per_symbol=self.ui.spinBoxBitsPerSymbol.value(), + device=device_name, + backend_handler=BackendHandler() + if backend_handler is None + else backend_handler, + network_raw_mode=network_raw_mode, + ) self.sniffer.adaptive_noise = self.ui.checkBoxAdaptiveNoise.isChecked() self.sniffer.automatic_center = self.ui.checkBoxAutoCenter.isChecked() @@ -46,8 +58,12 @@ def __init__(self, device_name: str, project_manager: ProjectManager, signal=Non self.__set_center_offset_visibility() self.create_connects() - self.ui.comboBox_sniff_encoding.currentIndexChanged.emit(self.ui.comboBox_sniff_encoding.currentIndex()) - self.ui.comboBox_sniff_viewtype.setCurrentIndex(settings.read('default_view', 0, int)) + self.ui.comboBox_sniff_encoding.currentIndexChanged.emit( + self.ui.comboBox_sniff_encoding.currentIndex() + ) + self.ui.comboBox_sniff_viewtype.setCurrentIndex( + settings.read("default_view", 0, int) + ) # Auto Complete like a Boss completer = QCompleter() @@ -82,16 +98,48 @@ def set_val(widget, key: str, default): elif hasattr(widget, "setCurrentIndex"): widget.setCurrentIndex(value) - set_val(self.ui.spinbox_sniff_SamplesPerSymbol, "samples_per_symbol", signal.samples_per_symbol if signal else 100) - set_val(self.ui.spinbox_sniff_Center, "center", signal.center if signal else 0.02) - set_val(self.ui.spinBoxCenterSpacing, "center_spacing", signal.center_spacing if signal else 0.1) - set_val(self.ui.spinbox_sniff_ErrorTolerance, "tolerance", signal.tolerance if signal else 5) - set_val(self.ui.spinbox_sniff_Noise, "noise", signal.noise_threshold_relative if signal else 0.001) - self.ui.combox_sniff_Modulation.setCurrentText(conf_dict.get("modulation_type", signal.modulation_type if signal else "FSK")) - set_val(self.ui.spinBoxBitsPerSymbol, "bits_per_symbol", signal.bits_per_symbol if signal else 1) - self.ui.comboBox_sniff_encoding.setCurrentText(conf_dict.get("decoding_name", "")) - self.ui.checkBoxAdaptiveNoise.setChecked(bool(conf_dict.get("adaptive_noise", False))) - self.ui.checkBoxAutoCenter.setChecked(bool(conf_dict.get("automatic_center", False))) + set_val( + self.ui.spinbox_sniff_SamplesPerSymbol, + "samples_per_symbol", + signal.samples_per_symbol if signal else 100, + ) + set_val( + self.ui.spinbox_sniff_Center, "center", signal.center if signal else 0.02 + ) + set_val( + self.ui.spinBoxCenterSpacing, + "center_spacing", + signal.center_spacing if signal else 0.1, + ) + set_val( + self.ui.spinbox_sniff_ErrorTolerance, + "tolerance", + signal.tolerance if signal else 5, + ) + set_val( + self.ui.spinbox_sniff_Noise, + "noise", + signal.noise_threshold_relative if signal else 0.001, + ) + self.ui.combox_sniff_Modulation.setCurrentText( + conf_dict.get( + "modulation_type", signal.modulation_type if signal else "FSK" + ) + ) + set_val( + self.ui.spinBoxBitsPerSymbol, + "bits_per_symbol", + signal.bits_per_symbol if signal else 1, + ) + self.ui.comboBox_sniff_encoding.setCurrentText( + conf_dict.get("decoding_name", "") + ) + self.ui.checkBoxAdaptiveNoise.setChecked( + bool(conf_dict.get("adaptive_noise", False)) + ) + self.ui.checkBoxAutoCenter.setChecked( + bool(conf_dict.get("automatic_center", False)) + ) self.ui.spinbox_sniff_Center.setDisabled(self.ui.checkBoxAutoCenter.isChecked()) self.emit_editing_finished_signals() @@ -99,19 +147,43 @@ def set_val(widget, key: str, default): def create_connects(self): self.ui.spinbox_sniff_Noise.editingFinished.connect(self.on_noise_edited) self.ui.spinbox_sniff_Center.editingFinished.connect(self.on_center_edited) - self.ui.spinBoxCenterSpacing.editingFinished.connect(self.on_center_spacing_edited) - self.ui.spinbox_sniff_SamplesPerSymbol.editingFinished.connect(self.on_samples_per_symbol_edited) - self.ui.spinbox_sniff_ErrorTolerance.editingFinished.connect(self.on_tolerance_edited) - self.ui.combox_sniff_Modulation.currentTextChanged.connect(self.on_modulation_changed) - self.ui.spinBoxBitsPerSymbol.editingFinished.connect(self.on_spin_box_bits_per_symbol_editing_finished) - - self.ui.comboBox_sniff_viewtype.currentIndexChanged.connect(self.on_view_type_changed) - self.ui.lineEdit_sniff_OutputFile.editingFinished.connect(self.on_line_edit_output_file_editing_finished) - self.ui.comboBox_sniff_encoding.currentIndexChanged.connect(self.on_combobox_sniff_encoding_index_changed) - self.ui.checkBox_sniff_Timestamp.clicked.connect(self.on_checkbox_sniff_timestamp_clicked) - self.ui.btn_sniff_use_signal.clicked.connect(self.on_btn_sniff_use_signal_clicked) - self.ui.checkBoxAdaptiveNoise.clicked.connect(self.on_check_box_adaptive_noise_clicked) - self.ui.checkBoxAutoCenter.clicked.connect(self.on_check_box_auto_center_clicked) + self.ui.spinBoxCenterSpacing.editingFinished.connect( + self.on_center_spacing_edited + ) + self.ui.spinbox_sniff_SamplesPerSymbol.editingFinished.connect( + self.on_samples_per_symbol_edited + ) + self.ui.spinbox_sniff_ErrorTolerance.editingFinished.connect( + self.on_tolerance_edited + ) + self.ui.combox_sniff_Modulation.currentTextChanged.connect( + self.on_modulation_changed + ) + self.ui.spinBoxBitsPerSymbol.editingFinished.connect( + self.on_spin_box_bits_per_symbol_editing_finished + ) + + self.ui.comboBox_sniff_viewtype.currentIndexChanged.connect( + self.on_view_type_changed + ) + self.ui.lineEdit_sniff_OutputFile.editingFinished.connect( + self.on_line_edit_output_file_editing_finished + ) + self.ui.comboBox_sniff_encoding.currentIndexChanged.connect( + self.on_combobox_sniff_encoding_index_changed + ) + self.ui.checkBox_sniff_Timestamp.clicked.connect( + self.on_checkbox_sniff_timestamp_clicked + ) + self.ui.btn_sniff_use_signal.clicked.connect( + self.on_btn_sniff_use_signal_clicked + ) + self.ui.checkBoxAdaptiveNoise.clicked.connect( + self.on_check_box_adaptive_noise_clicked + ) + self.ui.checkBoxAutoCenter.clicked.connect( + self.on_check_box_auto_center_clicked + ) def emit_editing_finished_signals(self): self.ui.spinbox_sniff_Noise.editingFinished.emit() @@ -124,20 +196,26 @@ def emit_editing_finished_signals(self): self.ui.checkBoxAdaptiveNoise.clicked.emit() def emit_sniff_parameters_changed(self): - self.sniff_parameters_changed.emit(dict(samples_per_symbol=self.sniffer.signal.samples_per_symbol, - center=self.sniffer.signal.center, - center_spacing=self.sniffer.signal.center_spacing, - noise=self.sniffer.signal.noise_threshold, - tolerance=self.sniffer.signal.tolerance, - modulation_type=self.sniffer.signal.modulation_type, - bits_per_symbol=self.sniffer.signal.bits_per_symbol, - decoding_name=self.sniffer.decoder.name, - adaptive_noise=self.sniffer.adaptive_noise, - automatic_center=self.sniffer.automatic_center)) + self.sniff_parameters_changed.emit( + dict( + samples_per_symbol=self.sniffer.signal.samples_per_symbol, + center=self.sniffer.signal.center, + center_spacing=self.sniffer.signal.center_spacing, + noise=self.sniffer.signal.noise_threshold, + tolerance=self.sniffer.signal.tolerance, + modulation_type=self.sniffer.signal.modulation_type, + bits_per_symbol=self.sniffer.signal.bits_per_symbol, + decoding_name=self.sniffer.decoder.name, + adaptive_noise=self.sniffer.adaptive_noise, + automatic_center=self.sniffer.automatic_center, + ) + ) @pyqtSlot() def on_noise_edited(self): - self.sniffer.signal.noise_threshold_relative = self.ui.spinbox_sniff_Noise.value() + self.sniffer.signal.noise_threshold_relative = ( + self.ui.spinbox_sniff_Noise.value() + ) self.sniff_setting_edited.emit() @pyqtSlot() @@ -152,7 +230,9 @@ def on_center_spacing_edited(self): @pyqtSlot() def on_samples_per_symbol_edited(self): - self.sniffer.signal.samples_per_symbol = self.ui.spinbox_sniff_SamplesPerSymbol.value() + self.sniffer.signal.samples_per_symbol = ( + self.ui.spinbox_sniff_SamplesPerSymbol.value() + ) self.sniff_setting_edited.emit() @pyqtSlot() diff --git a/src/urh/cythonext/analyze.py b/src/urh/cythonext/analyze.py index 37ee5b6590..6ec926bd80 100644 --- a/src/urh/cythonext/analyze.py +++ b/src/urh/cythonext/analyze.py @@ -1,14 +1,26 @@ from subprocess import call, Popen MODULES = ["path_creator", "signal_functions", "util", "auto_interpretation"] -COMPILER_DIRECTIVES = {'language_level': 3, - 'cdivision': True, - 'wraparound': False, - 'boundscheck': False, - 'initializedcheck': False, - } +COMPILER_DIRECTIVES = { + "language_level": 3, + "cdivision": True, + "wraparound": False, + "boundscheck": False, + "initializedcheck": False, +} for module in MODULES: - call(["cython", "-a", "-X", ",".join("{}={}".format(key, val) for key, val in COMPILER_DIRECTIVES.items()), - "--cplus", "-3", module + ".pyx"]) + call( + [ + "cython", + "-a", + "-X", + ",".join( + "{}={}".format(key, val) for key, val in COMPILER_DIRECTIVES.items() + ), + "--cplus", + "-3", + module + ".pyx", + ] + ) Popen(["firefox", module + ".html"]) diff --git a/src/urh/cythonext/build.py b/src/urh/cythonext/build.py index 35494ef3ae..dacc0e4899 100644 --- a/src/urh/cythonext/build.py +++ b/src/urh/cythonext/build.py @@ -10,7 +10,15 @@ def main(): cur_dir = os.path.realpath(__file__) os.chdir(os.path.realpath(os.path.join(cur_dir, "..", "..", "..", ".."))) # call([sys.executable, "setup.py", "clean", "--all"]) - rc = call([sys.executable, "setup.py", "build_ext", "--inplace", "-j{}".format(os.cpu_count())]) + rc = call( + [ + sys.executable, + "setup.py", + "build_ext", + "--inplace", + "-j{}".format(os.cpu_count()), + ] + ) return rc diff --git a/src/urh/dev/BackendHandler.py b/src/urh/dev/BackendHandler.py index 805b69db12..a20a02314d 100644 --- a/src/urh/dev/BackendHandler.py +++ b/src/urh/dev/BackendHandler.py @@ -18,7 +18,9 @@ class BackendContainer(object): def __init__(self, name, avail_backends: set, supports_rx: bool, supports_tx: bool): self.name = name self.avail_backends = avail_backends - self.selected_backend = Backends[settings.read(name + "_selected_backend", "none")] + self.selected_backend = Backends[ + settings.read(name + "_selected_backend", "none") + ] if self.selected_backend not in self.avail_backends: self.selected_backend = Backends.none @@ -35,7 +37,12 @@ def __init__(self, name, avail_backends: set, supports_rx: bool, supports_tx: bo self.is_enabled = False def __repr__(self): - return "avail backends: " + str(self.avail_backends) + "| selected backend:" + str(self.selected_backend) + return ( + "avail backends: " + + str(self.avail_backends) + + "| selected backend:" + + str(self.selected_backend) + ) @property def supports_rx(self) -> bool: @@ -81,18 +88,31 @@ class BackendHandler(object): 3) Manage the selection of devices backend """ - DEVICE_NAMES = ("AirSpy R2", "AirSpy Mini", "BladeRF", "FUNcube", "HackRF", "Rad1o", - "LimeSDR", "PlutoSDR", "RTL-SDR", "RTL-TCP", "SDRPlay", "SoundCard", "USRP") - def __init__(self): + DEVICE_NAMES = ( + "AirSpy R2", + "AirSpy Mini", + "BladeRF", + "FUNcube", + "HackRF", + "Rad1o", + "LimeSDR", + "PlutoSDR", + "RTL-SDR", + "RTL-TCP", + "SDRPlay", + "SoundCard", + "USRP", + ) - self.__gr_python_interpreter = settings.read('gr_python_interpreter', '') + def __init__(self): + self.__gr_python_interpreter = settings.read("gr_python_interpreter", "") if not self.__gr_python_interpreter: - self.__gr_python_interpreter = settings.read("python2_exe", '') # legacy + self.__gr_python_interpreter = settings.read("python2_exe", "") # legacy self.set_gnuradio_installed_status() - if not hasattr(sys, 'frozen'): + if not hasattr(sys, "frozen"): self.path = os.path.dirname(os.path.realpath(__file__)) else: self.path = os.path.dirname(sys.executable) @@ -115,13 +135,20 @@ def gr_python_interpreter(self, value): @property def num_native_backends(self): - return len([dev for dev, backend_container in self.device_backends.items() - if Backends.native in backend_container.avail_backends and dev.lower() != "rtl-tcp"]) + return len( + [ + dev + for dev, backend_container in self.device_backends.items() + if Backends.native in backend_container.avail_backends + and dev.lower() != "rtl-tcp" + ] + ) @property def __plutosdr_native_enabled(self) -> bool: try: from urh.dev.native.lib import plutosdr + return True except ImportError: return False @@ -130,6 +157,7 @@ def __plutosdr_native_enabled(self) -> bool: def __bladerf_native_enabled(self) -> bool: try: from urh.dev.native.lib import bladerf + return True except ImportError: return False @@ -138,6 +166,7 @@ def __bladerf_native_enabled(self) -> bool: def __hackrf_native_enabled(self) -> bool: try: from urh.dev.native.lib import hackrf + return True except ImportError: return False @@ -148,13 +177,14 @@ def __usrp_native_enabled(self) -> bool: try: try: # Redirect stderr to /dev/null to hide USRP messages - devnull = open(os.devnull, 'w') + devnull = open(os.devnull, "w") old_stdout = os.dup(sys.stdout.fileno()) os.dup2(devnull.fileno(), sys.stdout.fileno()) except: pass from urh.dev.native.lib import usrp + return True except ImportError: return False @@ -168,6 +198,7 @@ def __usrp_native_enabled(self) -> bool: def __soundcard_enabled(self) -> bool: try: import pyaudio + return True except ImportError: return False @@ -176,6 +207,7 @@ def __soundcard_enabled(self) -> bool: def __airspy_native_enabled(self) -> bool: try: from urh.dev.native.lib import airspy + return True except ImportError: return False @@ -184,6 +216,7 @@ def __airspy_native_enabled(self) -> bool: def __lime_native_enabled(self) -> bool: try: from urh.dev.native.lib import limesdr + return True except ImportError: return False @@ -192,6 +225,7 @@ def __lime_native_enabled(self) -> bool: def __rtlsdr_native_enabled(self) -> bool: try: from urh.dev.native.lib import rtlsdr + return True except ImportError: return False @@ -200,23 +234,35 @@ def __rtlsdr_native_enabled(self) -> bool: def __sdrplay_native_enabled(self) -> bool: try: from urh.dev.native.lib import sdrplay + return True except ImportError: return False def __check_gr_python_interpreter(self, interpreter): # Use shell=True to prevent console window popping up on windows - return call('"{0}" -c "import gnuradio"'.format(interpreter), shell=True, stderr=DEVNULL) == 0 + return ( + call( + '"{0}" -c "import gnuradio"'.format(interpreter), + shell=True, + stderr=DEVNULL, + ) + == 0 + ) def set_gnuradio_installed_status(self, force=False): - current_setting = settings.read('gnuradio_is_installed', -1, int) + current_setting = settings.read("gnuradio_is_installed", -1, int) if not force and current_setting != -1: self.gnuradio_is_installed = bool(current_setting) return - if os.path.isfile(self.gr_python_interpreter) and os.access(self.gr_python_interpreter, os.X_OK): + if os.path.isfile(self.gr_python_interpreter) and os.access( + self.gr_python_interpreter, os.X_OK + ): try: - self.gnuradio_is_installed = self.__check_gr_python_interpreter(self.gr_python_interpreter) + self.gnuradio_is_installed = self.__check_gr_python_interpreter( + self.gr_python_interpreter + ) except OSError: self.gnuradio_is_installed = False else: @@ -274,7 +320,10 @@ def __avail_backends_for_device(self, devname: str): supports_rx, supports_tx = True, False backends.add(Backends.native) - if devname.lower().replace("-", "") == "rtlsdr" and self.__rtlsdr_native_enabled: + if ( + devname.lower().replace("-", "") == "rtlsdr" + and self.__rtlsdr_native_enabled + ): supports_rx, supports_tx = True, False backends.add(Backends.native) @@ -312,6 +361,7 @@ def perform_soundcard_health_check(): result = "SoundCard -- " try: import pyaudio + return result + "OK" except Exception as e: return result + str(e) diff --git a/src/urh/dev/EndlessSender.py b/src/urh/dev/EndlessSender.py index 26958bcdfa..e0a3f06fce 100644 --- a/src/urh/dev/EndlessSender.py +++ b/src/urh/dev/EndlessSender.py @@ -11,8 +11,13 @@ class EndlessSender(object): """ def __init__(self, backend_handler, name: str): - self.__device = VirtualDevice(backend_handler=backend_handler, name=name, mode=Mode.send) - self.ringbuffer = RingBuffer(int(settings.CONTINUOUS_BUFFER_SIZE_MB * 10 ** 6) // 8, self.__device.data_type) + self.__device = VirtualDevice( + backend_handler=backend_handler, name=name, mode=Mode.send + ) + self.ringbuffer = RingBuffer( + int(settings.CONTINUOUS_BUFFER_SIZE_MB * 10**6) // 8, + self.__device.data_type, + ) self.__device.continuous_send_ring_buffer = self.ringbuffer self.__device.is_send_continuous = True @@ -24,7 +29,10 @@ def device(self) -> VirtualDevice: def device(self, value: VirtualDevice): self.__device = value self.__device.is_send_continuous = True - self.ringbuffer = RingBuffer(int(settings.CONTINUOUS_BUFFER_SIZE_MB * 10 ** 6) // 8, self.__device.data_type) + self.ringbuffer = RingBuffer( + int(settings.CONTINUOUS_BUFFER_SIZE_MB * 10**6) // 8, + self.__device.data_type, + ) self.__device.continuous_send_ring_buffer = self.ringbuffer @property @@ -34,7 +42,9 @@ def device_name(self) -> str: @device_name.setter def device_name(self, value: str): if value != self.device_name: - self.device = VirtualDevice(backend_handler=self.device.backend_handler, name=value, mode=Mode.send) + self.device = VirtualDevice( + backend_handler=self.device.backend_handler, name=value, mode=Mode.send + ) def start(self): self.device.num_sending_repeats = 0 @@ -47,7 +57,7 @@ def push_data(self, data: np.ndarray): self.ringbuffer.push(data) -if __name__ == '__main__': +if __name__ == "__main__": from urh.dev.BackendHandler import BackendHandler from urh.signalprocessing.Message import Message from urh.signalprocessing.MessageType import MessageType @@ -56,8 +66,14 @@ def push_data(self, data: np.ndarray): import time endless_sender = EndlessSender(BackendHandler(), "HackRF") - msg = Message([1, 0] * 16 + [1, 1, 0, 0] * 8 + [0, 0, 1, 1] * 8 + [1, 0, 1, 1, 1, 0, 0, 1, 1, 1] * 4, 0, - MessageType("empty_message_type")) + msg = Message( + [1, 0] * 16 + + [1, 1, 0, 0] * 8 + + [0, 0, 1, 1] * 8 + + [1, 0, 1, 1, 1, 0, 0, 1, 1, 1] * 4, + 0, + MessageType("empty_message_type"), + ) modulator = Modulator("test_modulator") modulator.samples_per_symbol = 1000 modulator.carrier_freq_hz = 55e3 diff --git a/src/urh/dev/PCAP.py b/src/urh/dev/PCAP.py index dce6fecf4a..56522d5de0 100644 --- a/src/urh/dev/PCAP.py +++ b/src/urh/dev/PCAP.py @@ -17,7 +17,7 @@ def reset_timestamp(self): self.timestamp_nsec = None def build_global_header(self) -> bytes: - MAGIC_NUMBER = 0xa1b23c4d # Nanosecond resolution + MAGIC_NUMBER = 0xA1B23C4D # Nanosecond resolution VERSION_MAJOR, VERSION_MINOR = 2, 4 THISZONE = 0 SIGFIGS = 0 @@ -26,11 +26,22 @@ def build_global_header(self) -> bytes: self.reset_timestamp() - return struct.pack(">IHHiIII", MAGIC_NUMBER, VERSION_MAJOR, VERSION_MINOR, THISZONE, SIGFIGS, SNAPLEN, NETWORK) + return struct.pack( + ">IHHiIII", + MAGIC_NUMBER, + VERSION_MAJOR, + VERSION_MINOR, + THISZONE, + SIGFIGS, + SNAPLEN, + NETWORK, + ) def build_packet(self, ts_sec: int, ts_nsec: int, data: bytes) -> bytes: if self.timestamp_nsec is None or self.timestamp_sec is None: - self.timestamp_sec, self.timestamp_nsec = self.get_seconds_nseconds(time.time()) + self.timestamp_sec, self.timestamp_nsec = self.get_seconds_nseconds( + time.time() + ) self.timestamp_sec += int(ts_sec) self.timestamp_nsec += int(ts_nsec) @@ -39,7 +50,9 @@ def build_packet(self, ts_sec: int, ts_nsec: int, data: bytes) -> bytes: self.timestamp_nsec = int(self.timestamp_nsec % 1e9) l = len(data) - return struct.pack(">IIII", self.timestamp_sec, self.timestamp_nsec, l, l) + data + return ( + struct.pack(">IIII", self.timestamp_sec, self.timestamp_nsec, l, l) + data + ) def write_packets(self, packets, filename: str, sample_rate: int): """ @@ -57,11 +70,13 @@ def write_packets(self, packets, filename: str, sample_rate: int): with open(filename, "ab") as f: rel_time_offset_ns = 0 for pkt in packets: - f.write(self.build_packet(0, rel_time_offset_ns, pkt.decoded_bits_buffer)) - rel_time_offset_ns = pkt.get_duration(sample_rate) * 10 ** 9 + f.write( + self.build_packet(0, rel_time_offset_ns, pkt.decoded_bits_buffer) + ) + rel_time_offset_ns = pkt.get_duration(sample_rate) * 10**9 @staticmethod def get_seconds_nseconds(timestamp): seconds = int(timestamp) - nseconds = int((timestamp - seconds) * 10 ** 9) + nseconds = int((timestamp - seconds) * 10**9) return seconds, nseconds diff --git a/src/urh/dev/PCAPNG.py b/src/urh/dev/PCAPNG.py index 5011137780..9935e0d443 100644 --- a/src/urh/dev/PCAPNG.py +++ b/src/urh/dev/PCAPNG.py @@ -8,6 +8,7 @@ # Refer to PCAPNG spec # https://www.ietf.org/staging/draft-tuexen-opsawg-pcapng-02.html + def _build_pcapng_shb(shb_userappl: str = "", shb_hardware: str = "") -> bytes: BLOCKTYPE = 0x0A0D0D0A HEADERS_BLOCK_LENGTH = 28 @@ -25,39 +26,41 @@ def _build_pcapng_shb(shb_userappl: str = "", shb_hardware: str = "") -> bytes: if shb_hardware_padded_len > 0: total_block_len += shb_hardware_padded_len + 4 - shb = struct.pack(">IIIHHQ", - BLOCKTYPE, - total_block_len, - MAGIC_NUMBER, - VERSION_MAJOR, VERSION_MINOR, - SECTIONLENGTH) + shb = struct.pack( + ">IIIHHQ", + BLOCKTYPE, + total_block_len, + MAGIC_NUMBER, + VERSION_MAJOR, + VERSION_MINOR, + SECTIONLENGTH, + ) if shb_userappl != "": SHB_USERAPPL = 4 strpad = shb_userappl.ljust(shb_userappl_padded_len, "\0") shb += struct.pack(">HH", SHB_USERAPPL, shb_userappl_padded_len) - shb += bytes(strpad, 'ascii') + shb += bytes(strpad, "ascii") if shb_hardware != "": SHB_HARDWARE = 2 strpad = shb_hardware.ljust(shb_hardware_padded_len, "\0") shb += struct.pack(">HH", SHB_HARDWARE, shb_hardware_padded_len) - shb += bytes(strpad, 'ascii') + shb += bytes(strpad, "ascii") shb += struct.pack(">I", total_block_len) return shb + def _build_pcapng_idb(link_type) -> bytes: BLOCKTYPE = 0x00000001 BLOCKLENGTH = 20 SNAP_LEN = 0 - return struct.pack(">IIHHII", - BLOCKTYPE, - BLOCKLENGTH, - link_type, 0, - SNAP_LEN, - BLOCKLENGTH) + return struct.pack( + ">IIHHII", BLOCKTYPE, BLOCKLENGTH, link_type, 0, SNAP_LEN, BLOCKLENGTH + ) + def _build_pcapng_epb(packet: bytes, timestamp: float) -> bytes: BLOCKTYPE = 0x00000006 @@ -74,20 +77,24 @@ def _build_pcapng_epb(packet: bytes, timestamp: float) -> bytes: timestamp_high = timestamp_int >> 32 timestamp_low = timestamp_int & 0x00000000FFFFFFFF - epb = struct.pack(">IIIIIII", - BLOCKTYPE, - block_total_length, - INTERFACE_ID, - timestamp_high, - timestamp_low, - captured_packet_len, - original_packet_len) + epb = struct.pack( + ">IIIIIII", + BLOCKTYPE, + block_total_length, + INTERFACE_ID, + timestamp_high, + timestamp_low, + captured_packet_len, + original_packet_len, + ) epb += padded_packet epb += struct.pack(">I", block_total_length) return epb -def create_pcapng_file(filename: str, shb_userappl: str = "", shb_hardware: str = "", - link_type: int = 147) -> bytes: + +def create_pcapng_file( + filename: str, shb_userappl: str = "", shb_hardware: str = "", link_type: int = 147 +) -> bytes: if filename == "": return @@ -101,6 +108,7 @@ def create_pcapng_file(filename: str, shb_userappl: str = "", shb_hardware: str f.write(shb_bytes) f.write(idb_bytes) + def append_packets_to_pcapng(filename: str, packets: list, timestamps: list): with open(filename, "ab") as f: for packet, timestamp in zip(packets, timestamps): diff --git a/src/urh/dev/VirtualDevice.py b/src/urh/dev/VirtualDevice.py index 4deef77ee1..13ccc44c83 100644 --- a/src/urh/dev/VirtualDevice.py +++ b/src/urh/dev/VirtualDevice.py @@ -7,7 +7,9 @@ from urh.dev import config from urh.dev.BackendHandler import Backends, BackendHandler from urh.dev.native.Device import Device -from urh.plugins.NetworkSDRInterface.NetworkSDRInterfacePlugin import NetworkSDRInterfacePlugin +from urh.plugins.NetworkSDRInterface.NetworkSDRInterfacePlugin import ( + NetworkSDRInterfacePlugin, +) from urh.util.Logger import logger @@ -22,6 +24,7 @@ class VirtualDevice(QObject): Wrapper class for providing sending methods for grc and native devices """ + started = pyqtSignal() stopped = pyqtSignal() sender_needs_restart = pyqtSignal() @@ -29,13 +32,30 @@ class VirtualDevice(QObject): fatal_error_occurred = pyqtSignal(str) ready_for_action = pyqtSignal() - continuous_send_msg = "Continuous send mode is not supported for GNU Radio backend. " \ - "You can change the configured device backend in options." - - def __init__(self, backend_handler, name: str, mode: Mode, freq=None, sample_rate=None, bandwidth=None, - gain=None, if_gain=None, baseband_gain=None, samples_to_send=None, - device_ip=None, sending_repeats=1, parent=None, resume_on_full_receive_buffer=False, raw_mode=True, - portnumber=1234): + continuous_send_msg = ( + "Continuous send mode is not supported for GNU Radio backend. " + "You can change the configured device backend in options." + ) + + def __init__( + self, + backend_handler, + name: str, + mode: Mode, + freq=None, + sample_rate=None, + bandwidth=None, + gain=None, + if_gain=None, + baseband_gain=None, + samples_to_send=None, + device_ip=None, + sending_repeats=1, + parent=None, + resume_on_full_receive_buffer=False, + raw_mode=True, + portnumber=1234, + ): super().__init__(parent) self.name = name self.mode = mode @@ -46,15 +66,21 @@ def __init__(self, backend_handler, name: str, mode: Mode, freq=None, sample_rat bandwidth = config.DEFAULT_BANDWIDTH if bandwidth is None else bandwidth gain = config.DEFAULT_GAIN if gain is None else gain if_gain = config.DEFAULT_IF_GAIN if if_gain is None else if_gain - baseband_gain = config.DEFAULT_BB_GAIN if baseband_gain is None else baseband_gain + baseband_gain = ( + config.DEFAULT_BB_GAIN if baseband_gain is None else baseband_gain + ) - resume_on_full_receive_buffer = self.mode == Mode.spectrum or resume_on_full_receive_buffer + resume_on_full_receive_buffer = ( + self.mode == Mode.spectrum or resume_on_full_receive_buffer + ) if self.name == NetworkSDRInterfacePlugin.NETWORK_SDR_NAME: self.backend = Backends.network else: try: - self.backend = self.backend_handler.device_backends[name.lower()].selected_backend + self.backend = self.backend_handler.device_backends[ + name.lower() + ].selected_backend except KeyError: logger.warning("Invalid device name: {0}".format(name)) self.backend = Backends.none @@ -64,18 +90,45 @@ def __init__(self, backend_handler, name: str, mode: Mode, freq=None, sample_rat if self.backend == Backends.grc: if mode == Mode.receive: from urh.dev.gr.ReceiverThread import ReceiverThread - self.__dev = ReceiverThread(freq, sample_rate, bandwidth, gain, if_gain, baseband_gain, - parent=parent, resume_on_full_receive_buffer=resume_on_full_receive_buffer) + + self.__dev = ReceiverThread( + freq, + sample_rate, + bandwidth, + gain, + if_gain, + baseband_gain, + parent=parent, + resume_on_full_receive_buffer=resume_on_full_receive_buffer, + ) elif mode == Mode.send: from urh.dev.gr.SenderThread import SenderThread - self.__dev = SenderThread(freq, sample_rate, bandwidth, gain, if_gain, baseband_gain, - parent=parent) + + self.__dev = SenderThread( + freq, + sample_rate, + bandwidth, + gain, + if_gain, + baseband_gain, + parent=parent, + ) self.__dev.data = samples_to_send - self.__dev.samples_per_transmission = len(samples_to_send) if samples_to_send is not None else 2 ** 15 + self.__dev.samples_per_transmission = ( + len(samples_to_send) if samples_to_send is not None else 2**15 + ) elif mode == Mode.spectrum: from urh.dev.gr.SpectrumThread import SpectrumThread - self.__dev = SpectrumThread(freq, sample_rate, bandwidth, gain, if_gain, baseband_gain, - parent=parent) + + self.__dev = SpectrumThread( + freq, + sample_rate, + bandwidth, + gain, + if_gain, + baseband_gain, + parent=parent, + ) else: raise ValueError("Unknown mode") self.__dev.device = name @@ -87,60 +140,135 @@ def __init__(self, backend_handler, name: str, mode: Mode, freq=None, sample_rat if name in map(str.lower, BackendHandler.DEVICE_NAMES): if name == "hackrf": from urh.dev.native.HackRF import HackRF - self.__dev = HackRF(center_freq=freq, sample_rate=sample_rate, bandwidth=bandwidth, - gain=gain, if_gain=if_gain, baseband_gain=baseband_gain, - resume_on_full_receive_buffer=resume_on_full_receive_buffer) + + self.__dev = HackRF( + center_freq=freq, + sample_rate=sample_rate, + bandwidth=bandwidth, + gain=gain, + if_gain=if_gain, + baseband_gain=baseband_gain, + resume_on_full_receive_buffer=resume_on_full_receive_buffer, + ) elif name == "rad1o": from urh.dev.native.Rad1o import Rad1o - self.__dev = Rad1o(center_freq=freq, sample_rate=sample_rate, bandwidth=bandwidth, - gain=gain, if_gain=if_gain, baseband_gain=baseband_gain, - resume_on_full_receive_buffer=resume_on_full_receive_buffer) + + self.__dev = Rad1o( + center_freq=freq, + sample_rate=sample_rate, + bandwidth=bandwidth, + gain=gain, + if_gain=if_gain, + baseband_gain=baseband_gain, + resume_on_full_receive_buffer=resume_on_full_receive_buffer, + ) elif name.replace("-", "") == "rtlsdr": from urh.dev.native.RTLSDR import RTLSDR - self.__dev = RTLSDR(freq=freq, gain=gain, srate=sample_rate, device_number=0, - resume_on_full_receive_buffer=resume_on_full_receive_buffer) + + self.__dev = RTLSDR( + freq=freq, + gain=gain, + srate=sample_rate, + device_number=0, + resume_on_full_receive_buffer=resume_on_full_receive_buffer, + ) elif name.replace("-", "") == "rtltcp": from urh.dev.native.RTLSDRTCP import RTLSDRTCP - self.__dev = RTLSDRTCP(freq=freq, gain=gain, srate=sample_rate, bandwidth=bandwidth, - device_number=0, - resume_on_full_receive_buffer=resume_on_full_receive_buffer) + + self.__dev = RTLSDRTCP( + freq=freq, + gain=gain, + srate=sample_rate, + bandwidth=bandwidth, + device_number=0, + resume_on_full_receive_buffer=resume_on_full_receive_buffer, + ) elif name == "limesdr": from urh.dev.native.LimeSDR import LimeSDR - self.__dev = LimeSDR(center_freq=freq, sample_rate=sample_rate, bandwidth=bandwidth, gain=gain, - resume_on_full_receive_buffer=resume_on_full_receive_buffer) + + self.__dev = LimeSDR( + center_freq=freq, + sample_rate=sample_rate, + bandwidth=bandwidth, + gain=gain, + resume_on_full_receive_buffer=resume_on_full_receive_buffer, + ) elif name == "bladerf": from urh.dev.native.BladeRF import BladeRF - self.__dev = BladeRF(center_freq=freq, sample_rate=sample_rate, bandwidth=bandwidth, gain=gain, - resume_on_full_receive_buffer=resume_on_full_receive_buffer) + + self.__dev = BladeRF( + center_freq=freq, + sample_rate=sample_rate, + bandwidth=bandwidth, + gain=gain, + resume_on_full_receive_buffer=resume_on_full_receive_buffer, + ) elif name == "plutosdr": from urh.dev.native.PlutoSDR import PlutoSDR - self.__dev = PlutoSDR(center_freq=freq, sample_rate=sample_rate, bandwidth=bandwidth, gain=gain, - resume_on_full_receive_buffer=resume_on_full_receive_buffer) + + self.__dev = PlutoSDR( + center_freq=freq, + sample_rate=sample_rate, + bandwidth=bandwidth, + gain=gain, + resume_on_full_receive_buffer=resume_on_full_receive_buffer, + ) elif name.startswith("airspy"): from urh.dev.native.AirSpy import AirSpy - self.__dev = AirSpy(center_freq=freq, sample_rate=sample_rate, bandwidth=bandwidth, - gain=gain, if_gain=if_gain, baseband_gain=baseband_gain, - resume_on_full_receive_buffer=resume_on_full_receive_buffer) + + self.__dev = AirSpy( + center_freq=freq, + sample_rate=sample_rate, + bandwidth=bandwidth, + gain=gain, + if_gain=if_gain, + baseband_gain=baseband_gain, + resume_on_full_receive_buffer=resume_on_full_receive_buffer, + ) elif name.startswith("usrp"): from urh.dev.native.USRP import USRP - self.__dev = USRP(center_freq=freq, sample_rate=sample_rate, bandwidth=bandwidth, gain=gain, - resume_on_full_receive_buffer=resume_on_full_receive_buffer) + + self.__dev = USRP( + center_freq=freq, + sample_rate=sample_rate, + bandwidth=bandwidth, + gain=gain, + resume_on_full_receive_buffer=resume_on_full_receive_buffer, + ) elif name.startswith("sdrplay"): from urh.dev.native.SDRPlay import SDRPlay - self.__dev = SDRPlay(center_freq=freq, sample_rate=sample_rate, bandwidth=bandwidth, - gain=gain, if_gain=if_gain, - resume_on_full_receive_buffer=resume_on_full_receive_buffer) + + self.__dev = SDRPlay( + center_freq=freq, + sample_rate=sample_rate, + bandwidth=bandwidth, + gain=gain, + if_gain=if_gain, + resume_on_full_receive_buffer=resume_on_full_receive_buffer, + ) elif name == "soundcard": from urh.dev.native.SoundCard import SoundCard - self.__dev = SoundCard(sample_rate=sample_rate, - resume_on_full_receive_buffer=resume_on_full_receive_buffer) + + self.__dev = SoundCard( + sample_rate=sample_rate, + resume_on_full_receive_buffer=resume_on_full_receive_buffer, + ) else: - raise NotImplementedError("Native Backend for {0} not yet implemented".format(name)) + raise NotImplementedError( + "Native Backend for {0} not yet implemented".format(name) + ) elif name == "test": # For Unittests Only - self.__dev = Device(freq, sample_rate, bandwidth, gain, if_gain, baseband_gain, - resume_on_full_receive_buffer) + self.__dev = Device( + freq, + sample_rate, + bandwidth, + gain, + if_gain, + baseband_gain, + resume_on_full_receive_buffer, + ) else: raise ValueError("Unknown device name {0}".format(name)) self.__dev.portnumber = portnumber @@ -148,9 +276,12 @@ def __init__(self, backend_handler, name: str, mode: Mode, freq=None, sample_rat if mode == Mode.send: self.__dev.init_send_parameters(samples_to_send, sending_repeats) elif self.backend == Backends.network: - self.__dev = NetworkSDRInterfacePlugin(raw_mode=raw_mode, - resume_on_full_receive_buffer=resume_on_full_receive_buffer, - spectrum=self.mode == Mode.spectrum, sending=self.mode == Mode.send) + self.__dev = NetworkSDRInterfacePlugin( + raw_mode=raw_mode, + resume_on_full_receive_buffer=resume_on_full_receive_buffer, + spectrum=self.mode == Mode.spectrum, + sending=self.mode == Mode.send, + ) self.__dev.send_connection_established.connect(self.emit_ready_for_action) self.__dev.receive_server_started.connect(self.emit_ready_for_action) self.__dev.error_occurred.connect(self.emit_fatal_error_occurred) @@ -176,7 +307,10 @@ def data_type(self): @property def has_multi_device_support(self): - return hasattr(self.__dev, "has_multi_device_support") and self.__dev.has_multi_device_support + return ( + hasattr(self.__dev, "has_multi_device_support") + and self.__dev.has_multi_device_support + ) @property def device_serial(self): @@ -493,7 +627,9 @@ def data(self, value): else: self.__dev.receive_buffer = value else: - logger.warning("{}:{} has no data".format(self.__class__.__name__, self.backend.name)) + logger.warning( + "{}:{} has no data".format(self.__class__.__name__, self.backend.name) + ) def free_data(self): if self.backend == Backends.grc: @@ -691,7 +827,7 @@ def read_messages(self) -> str: errors = self.__dev.read_errors() if "FATAL: " in errors: - self.fatal_error_occurred.emit(errors[errors.index("FATAL: "):]) + self.fatal_error_occurred.emit(errors[errors.index("FATAL: ") :]) return errors elif self.backend == Backends.native: @@ -704,7 +840,9 @@ def read_messages(self) -> str: if "successfully started" in messages: self.ready_for_action.emit() elif "failed to start" in messages: - self.fatal_error_occurred.emit(messages[messages.index("failed to start"):]) + self.fatal_error_occurred.emit( + messages[messages.index("failed to start") :] + ) return messages elif self.backend == Backends.network: diff --git a/src/urh/dev/config.py b/src/urh/dev/config.py index 7533132953..f8c66ab659 100644 --- a/src/urh/dev/config.py +++ b/src/urh/dev/config.py @@ -1,7 +1,9 @@ import copy from collections import OrderedDict, namedtuple -from urh.plugins.NetworkSDRInterface.NetworkSDRInterfacePlugin import NetworkSDRInterfacePlugin +from urh.plugins.NetworkSDRInterface.NetworkSDRInterfacePlugin import ( + NetworkSDRInterfacePlugin, +) DEFAULT_FREQUENCY = 433.92e6 DEFAULT_SAMPLE_RATE = 1e6 @@ -16,9 +18,9 @@ dev_range = namedtuple("dev_range", ["start", "stop", "step"]) -K = 10 ** 3 -M = 10 ** 6 -G = 10 ** 9 +K = 10**3 +M = 10**6 +G = 10**9 DEVICE_CONFIG["PlutoSDR"] = { "center_freq": dev_range(start=70 * M, stop=6 * G, step=1), @@ -31,13 +33,15 @@ # http://www.nuand.com/bladeRF-brief.pdf DEVICE_CONFIG["BladeRF"] = { "center_freq": dev_range(start=47 * M, stop=6 * G, step=1), - "sample_rate": dev_range(start=520.834 * K, stop=61.44 * M, step=1), # https://github.com/jopohl/urh/issues/930 + "sample_rate": dev_range( + start=520.834 * K, stop=61.44 * M, step=1 + ), # https://github.com/jopohl/urh/issues/930 "bandwidth": dev_range(start=1.5 * M, stop=28 * M, step=1), "rx_channel": ["RX1", "RX2"], "tx_channel": ["TX1", "TX2"], "tx_rf_gain": list(range(0, 61)), "rx_rf_gain": list(range(0, 61)), - "bias_tee_enabled": [False, True] + "bias_tee_enabled": [False, True], } # https://github.com/mossmann/hackrf/wiki/HackRF-One#features @@ -50,7 +54,7 @@ "rx_if_gain": [0, 8, 16, 24, 32, 40], "tx_if_gain": list(range(0, 48)), "rx_baseband_gain": list(range(0, 63, 2)), # only available in RX - "bias_tee_enabled": [False, True] + "bias_tee_enabled": [False, True], } DEVICE_CONFIG["Rad1o"] = { @@ -61,7 +65,7 @@ "rx_rf_gain": [0, 14], "rx_if_gain": [0, 8, 16, 24, 32, 40], "tx_if_gain": list(range(0, 48)), - "rx_baseband_gain": list(range(0, 63, 2)) # only available in RX + "rx_baseband_gain": list(range(0, 63, 2)), # only available in RX } # https://kb.ettus.com/About_USRP_Bandwidths_and_Sampling_Rates @@ -73,7 +77,7 @@ "rx_rf_gain": list(range(0, 101)), "tx_rf_gain": list(range(0, 101)), "rx_antenna": ["Antenna 1", "Antenna 2", "Antenna 3"], - "tx_antenna": ["Antenna 1", "Antenna 2", "Antenna 3"] + "tx_antenna": ["Antenna 1", "Antenna 2", "Antenna 3"], } # https://myriadrf.org/projects/limesdr/ @@ -88,7 +92,7 @@ "rx_antenna": ["None", "High (RX_H)", "Low (RX_L)", "Wide (RX_W)"], "rx_antenna_default_index": 2, "tx_antenna": ["None", "Band 1 (TX_1)", "Band 2 (TX_2)"], - "tx_antenna_default_index": 1 + "tx_antenna_default_index": 1, } # http://osmocom.org/projects/sdr/wiki/rtl-sdr @@ -99,8 +103,8 @@ "bandwidth": dev_range(start=1, stop=int(3.2 * M), step=1), "rx_rf_gain": list(range(-100, 500)), "direct_sampling": ["disabled", "I-ADC input enabled", "Q-ADC input enabled"], - "freq_correction": dev_range(start=-1 * 10 ** 3, stop=1 * 10 ** 3, step=1), - "bias_tee_enabled": [False, True] + "freq_correction": dev_range(start=-1 * 10**3, stop=1 * 10**3, step=1), + "bias_tee_enabled": [False, True], } DEVICE_CONFIG["RTL-TCP"] = copy.deepcopy(DEVICE_CONFIG["RTL-SDR"]) @@ -113,7 +117,10 @@ # https://airspy.com/products/ DEVICE_CONFIG["AirSpy R2"] = { "center_freq": dev_range(start=24, stop=1800 * M, step=1), - "sample_rate": [10 * M, 10 * M], # This device always uses 10M, no matter what is configured. + "sample_rate": [ + 10 * M, + 10 * M, + ], # This device always uses 10M, no matter what is configured. "bandwidth": [10 * M, 10 * M], "rx_rf_gain": list(range(0, 16)), "rx_if_gain": list(range(0, 16)), diff --git a/src/urh/dev/gr/AbstractBaseThread.py b/src/urh/dev/gr/AbstractBaseThread.py index 51bda3d73a..79200b0a4b 100644 --- a/src/urh/dev/gr/AbstractBaseThread.py +++ b/src/urh/dev/gr/AbstractBaseThread.py @@ -12,7 +12,7 @@ from urh import settings from urh.util.Logger import logger -ON_POSIX = 'posix' in sys.builtin_module_names +ON_POSIX = "posix" in sys.builtin_module_names class AbstractBaseThread(QThread): @@ -20,8 +20,18 @@ class AbstractBaseThread(QThread): stopped = pyqtSignal() sender_needs_restart = pyqtSignal() - def __init__(self, frequency, sample_rate, bandwidth, gain, if_gain, baseband_gain, receiving: bool, - ip='127.0.0.1', parent=None): + def __init__( + self, + frequency, + sample_rate, + bandwidth, + gain, + if_gain, + baseband_gain, + receiving: bool, + ip="127.0.0.1", + parent=None, + ): super().__init__(parent) self.ip = ip self.gr_port = 1337 @@ -60,7 +70,7 @@ def sample_rate(self, value): self._sample_rate = value if self.gr_process: try: - self.gr_process.stdin.write(b'SR:' + bytes(str(value), "utf8") + b'\n') + self.gr_process.stdin.write(b"SR:" + bytes(str(value), "utf8") + b"\n") self.gr_process.stdin.flush() except BrokenPipeError: pass @@ -74,7 +84,7 @@ def frequency(self, value): self._frequency = value if self.gr_process: try: - self.gr_process.stdin.write(b'F:' + bytes(str(value), "utf8") + b'\n') + self.gr_process.stdin.write(b"F:" + bytes(str(value), "utf8") + b"\n") self.gr_process.stdin.flush() except BrokenPipeError: pass @@ -88,7 +98,7 @@ def gain(self, value): self._gain = value if self.gr_process: try: - self.gr_process.stdin.write(b'G:' + bytes(str(value), "utf8") + b'\n') + self.gr_process.stdin.write(b"G:" + bytes(str(value), "utf8") + b"\n") self.gr_process.stdin.flush() except BrokenPipeError: pass @@ -102,7 +112,7 @@ def if_gain(self, value): self._if_gain = value if self.gr_process: try: - self.gr_process.stdin.write(b'IFG:' + bytes(str(value), "utf8") + b'\n') + self.gr_process.stdin.write(b"IFG:" + bytes(str(value), "utf8") + b"\n") self.gr_process.stdin.flush() except BrokenPipeError: pass @@ -116,7 +126,7 @@ def baseband_gain(self, value): self._baseband_gain = value if self.gr_process: try: - self.gr_process.stdin.write(b'BBG:' + bytes(str(value), "utf8") + b'\n') + self.gr_process.stdin.write(b"BBG:" + bytes(str(value), "utf8") + b"\n") self.gr_process.stdin.flush() except BrokenPipeError: pass @@ -130,7 +140,7 @@ def bandwidth(self, value): self._bandwidth = value if self.gr_process: try: - self.gr_process.stdin.write(b'BW:' + bytes(str(value), "utf8") + b'\n') + self.gr_process.stdin.write(b"BW:" + bytes(str(value), "utf8") + b"\n") self.gr_process.stdin.flush() except BrokenPipeError: pass @@ -144,7 +154,7 @@ def freq_correction(self, value): self._freq_correction = value if self.gr_process: try: - self.gr_process.stdin.write(b'FC:' + bytes(str(value), "utf8") + b'\n') + self.gr_process.stdin.write(b"FC:" + bytes(str(value), "utf8") + b"\n") self.gr_process.stdin.flush() except BrokenPipeError: pass @@ -174,7 +184,7 @@ def direct_sampling_mode(self, value): self._direct_sampling_mode = value if self.gr_process: try: - self.gr_process.stdin.write(b'DSM:' + bytes(str(value), "utf8") + b'\n') + self.gr_process.stdin.write(b"DSM:" + bytes(str(value), "utf8") + b"\n") self.gr_process.stdin.flush() except BrokenPipeError: pass @@ -182,7 +192,7 @@ def direct_sampling_mode(self, value): def initialize_process(self): self.started.emit() - if not hasattr(sys, 'frozen'): + if not hasattr(sys, "frozen"): rp = os.path.realpath(os.path.join(os.path.dirname(__file__), "scripts")) else: rp = os.path.realpath(os.path.dirname(sys.executable)) @@ -193,21 +203,44 @@ def initialize_process(self): if not self.gr_python_interpreter: self.stop( "FATAL: Could not find a GR compatible Python interpreter. " - "Make sure you have a running GNU Radio installation.") + "Make sure you have a running GNU Radio installation." + ) return - options = [self.gr_python_interpreter, os.path.join(rp, filename), - "--sample-rate", str(int(self.sample_rate)), "--frequency", str(int(self.frequency)), - "--gain", str(self.gain), "--if-gain", str(self.if_gain), "--bb-gain", str(self.baseband_gain), - "--bandwidth", str(int(self.bandwidth)), "--freq-correction", str(self.freq_correction), - "--direct-sampling", str(self.direct_sampling_mode), "--channel-index", str(self.channel_index), - "--port", str(self.gr_port)] + options = [ + self.gr_python_interpreter, + os.path.join(rp, filename), + "--sample-rate", + str(int(self.sample_rate)), + "--frequency", + str(int(self.frequency)), + "--gain", + str(self.gain), + "--if-gain", + str(self.if_gain), + "--bb-gain", + str(self.baseband_gain), + "--bandwidth", + str(int(self.bandwidth)), + "--freq-correction", + str(self.freq_correction), + "--direct-sampling", + str(self.direct_sampling_mode), + "--channel-index", + str(self.channel_index), + "--port", + str(self.gr_port), + ] logger.info("Starting GNU Radio") logger.debug(" ".join(options)) - self.gr_process = Popen(options, stdout=PIPE, stderr=PIPE, stdin=PIPE, bufsize=1) + self.gr_process = Popen( + options, stdout=PIPE, stderr=PIPE, stdin=PIPE, bufsize=1 + ) logger.info("Started GNU Radio") - t = Thread(target=self.enqueue_output, args=(self.gr_process.stderr, self.queue)) + t = Thread( + target=self.enqueue_output, args=(self.gr_process.stderr, self.queue) + ) t.daemon = True # thread dies with the program t.start() @@ -248,7 +281,7 @@ def read_errors(self, initial_errors=None): return "Could not decode device message" def enqueue_output(self, out, queue): - for line in iter(out.readline, b''): + for line in iter(out.readline, b""): queue.put(line) out.close() diff --git a/src/urh/dev/gr/ReceiverThread.py b/src/urh/dev/gr/ReceiverThread.py index e360aa9f6c..4a5114dec3 100644 --- a/src/urh/dev/gr/ReceiverThread.py +++ b/src/urh/dev/gr/ReceiverThread.py @@ -6,15 +6,39 @@ class ReceiverThread(AbstractBaseThread): - def __init__(self, frequency, sample_rate, bandwidth, gain, if_gain, baseband_gain, ip='127.0.0.1', - parent=None, resume_on_full_receive_buffer=False): - super().__init__(frequency, sample_rate, bandwidth, gain, if_gain, baseband_gain, True, ip, parent) + def __init__( + self, + frequency, + sample_rate, + bandwidth, + gain, + if_gain, + baseband_gain, + ip="127.0.0.1", + parent=None, + resume_on_full_receive_buffer=False, + ): + super().__init__( + frequency, + sample_rate, + bandwidth, + gain, + if_gain, + baseband_gain, + True, + ip, + parent, + ) - self.resume_on_full_receive_buffer = resume_on_full_receive_buffer # for Live Sniffing + self.resume_on_full_receive_buffer = ( + resume_on_full_receive_buffer # for Live Sniffing + ) self.data = None def init_recv_buffer(self): - n_samples = settings.get_receive_buffer_size(self.resume_on_full_receive_buffer, self.is_in_spectrum_mode) + n_samples = settings.get_receive_buffer_size( + self.resume_on_full_receive_buffer, self.is_in_spectrum_mode + ) self.data = np.zeros(n_samples, dtype=np.complex64) def run(self): @@ -58,7 +82,9 @@ def run(self): else: self.stop("Receiving Buffer is full.") return - self.data[self.current_index:self.current_index + num_samples] = tmp + self.data[ + self.current_index : self.current_index + num_samples + ] = tmp self.current_index += num_samples rcvd = b"" except ValueError: diff --git a/src/urh/dev/gr/SenderThread.py b/src/urh/dev/gr/SenderThread.py index ae64be88c6..42d780e01c 100644 --- a/src/urh/dev/gr/SenderThread.py +++ b/src/urh/dev/gr/SenderThread.py @@ -12,8 +12,28 @@ class SenderThread(AbstractBaseThread): MAX_SAMPLES_PER_TRANSMISSION = 4096 - def __init__(self, frequency, sample_rate, bandwidth, gain, if_gain, baseband_gain, ip='127.0.0.1', parent=None): - super().__init__(frequency, sample_rate, bandwidth, gain, if_gain, baseband_gain, False, ip, parent) + def __init__( + self, + frequency, + sample_rate, + bandwidth, + gain, + if_gain, + baseband_gain, + ip="127.0.0.1", + parent=None, + ): + super().__init__( + frequency, + sample_rate, + bandwidth, + gain, + if_gain, + baseband_gain, + False, + ip, + parent, + ) self.data = numpy.empty(1, dtype=numpy.complex64) self.socket = socket.socket(socket.AF_INET, socket.SOCK_DGRAM) @@ -44,15 +64,21 @@ def samples_per_transmission(self, val: int): def run(self): self.initialize_process() len_data = len(self.data) - self.current_iteration = self.current_iteration if self.current_iteration is not None else 0 + self.current_iteration = ( + self.current_iteration if self.current_iteration is not None else 0 + ) time.sleep(1) try: while self.current_index < len_data and not self.isInterruptionRequested(): time.sleep(self.samples_per_transmission / self.sample_rate) self.socket.sendto( - self.data[self.current_index:self.current_index + self.samples_per_transmission].tostring(), - (self.ip, self.gr_port)) + self.data[ + self.current_index : self.current_index + + self.samples_per_transmission + ].tostring(), + (self.ip, self.gr_port), + ) self.current_index += self.samples_per_transmission if self.current_index >= len_data: diff --git a/src/urh/dev/gr/SpectrumThread.py b/src/urh/dev/gr/SpectrumThread.py index 1a6e80271e..06aff0b0a0 100644 --- a/src/urh/dev/gr/SpectrumThread.py +++ b/src/urh/dev/gr/SpectrumThread.py @@ -6,8 +6,28 @@ class SpectrumThread(AbstractBaseThread): - def __init__(self, frequency, sample_rate, bandwidth, gain, if_gain, baseband_gain, ip='127.0.0.1', parent=None): - super().__init__(frequency, sample_rate, bandwidth, gain, if_gain, baseband_gain, True, ip, parent) + def __init__( + self, + frequency, + sample_rate, + bandwidth, + gain, + if_gain, + baseband_gain, + ip="127.0.0.1", + parent=None, + ): + super().__init__( + frequency, + sample_rate, + bandwidth, + gain, + if_gain, + baseband_gain, + True, + ip, + parent, + ) self.buf_size = settings.SPECTRUM_BUFFER_SIZE self.data = np.zeros(self.buf_size, dtype=np.complex64) self.x = None @@ -44,11 +64,15 @@ def run(self): len_tmp = len(tmp) if self.data is None: - self.data = np.zeros(self.buf_size, dtype=np.complex64) # type: np.ndarray + self.data = np.zeros( + self.buf_size, dtype=np.complex64 + ) # type: np.ndarray if self.current_index + len_tmp >= len(self.data): - self.data[self.current_index:] = tmp[:len(self.data) - self.current_index] - tmp = tmp[len(self.data) - self.current_index:] + self.data[self.current_index :] = tmp[ + : len(self.data) - self.current_index + ] + tmp = tmp[len(self.data) - self.current_index :] w = np.abs(np.fft.fft(self.data)) freqs = np.fft.fftfreq(len(w), 1 / self.sample_rate) idx = np.argsort(freqs) @@ -56,11 +80,11 @@ def run(self): self.y = w[idx].astype(np.float32) self.data = np.zeros(len(self.data), dtype=np.complex64) - self.data[0:len(tmp)] = tmp + self.data[0 : len(tmp)] = tmp self.current_index = len(tmp) continue - self.data[self.current_index:self.current_index + len_tmp] = tmp + self.data[self.current_index : self.current_index + len_tmp] = tmp self.current_index += len_tmp rcvd = b"" except ValueError: diff --git a/src/urh/dev/gr/scripts/InputHandlerThread.py b/src/urh/dev/gr/scripts/InputHandlerThread.py index baa306b0fc..9b090ec6d5 100644 --- a/src/urh/dev/gr/scripts/InputHandlerThread.py +++ b/src/urh/dev/gr/scripts/InputHandlerThread.py @@ -1,4 +1,5 @@ import sys + if sys.version_info[0] >= 3: from queue import Queue, Empty else: @@ -15,12 +16,18 @@ def __init__(self, device): self.device = device self.daemon = True - t = Thread(target=self.enqueue_input, args=(sys.stdin, self.queue,)) + t = Thread( + target=self.enqueue_input, + args=( + sys.stdin, + self.queue, + ), + ) t.daemon = True # thread dies with the program t.start() def enqueue_input(self, inp, queue): - for line in iter(inp.readline, b''): + for line in iter(inp.readline, b""): queue.put(line) inp.close() @@ -84,7 +91,8 @@ def run(self): v = 1 self.device.set_freq_correction(v) elif i.startswith("DSM:"): - print("GNU Radio does not support setting direct sampling mode live.") + print( + "GNU Radio does not support setting direct sampling mode live." + ) time.sleep(0.1) - diff --git a/src/urh/dev/gr/scripts/__create_gr_script.py b/src/urh/dev/gr/scripts/__create_gr_script.py index e953814d39..d46c60b52e 100644 --- a/src/urh/dev/gr/scripts/__create_gr_script.py +++ b/src/urh/dev/gr/scripts/__create_gr_script.py @@ -1,7 +1,7 @@ import re import sys -#TARGET = sys.argv[1] # e.g. airspy_recv.py +# TARGET = sys.argv[1] # e.g. airspy_recv.py TARGET = "funcube_recv.py" variables = [] @@ -19,7 +19,9 @@ start_vars, start_blocks = False, True elif start_blocks and line.strip().startswith("self."): try: - used_variables.append(re.search(r"\(([a-z\_0-9]*)[\)\,]", line).group(1)) + used_variables.append( + re.search(r"\(([a-z\_0-9]*)[\)\,]", line).group(1) + ) except AttributeError: pass elif line.strip().startswith("# Connections"): @@ -51,7 +53,7 @@ elif start_vars and line.strip().startswith("self."): var_name = re.search("= (.*) =", line).group(1) if var_name in used_variables: - f.write(line[:line.rindex("=")]+"\n") + f.write(line[: line.rindex("=")] + "\n") continue elif line.strip().startswith("# Blocks"): @@ -60,19 +62,43 @@ if line.strip().startswith("def main("): f.write("if __name__ == '__main__':\n") f.write(" parser = OptionParser(usage='%prog: [options]')\n") - f.write(" parser.add_option('-s', '--sample-rate', dest='sample_rate', default=100000)\n") - f.write(" parser.add_option('-f', '--frequency', dest='frequency', default=433000)\n") - f.write(" parser.add_option('-g', '--gain', dest='rf_gain', default=30)\n") - f.write(" parser.add_option('-i', '--if-gain', dest='if_gain', default=30)\n") - f.write(" parser.add_option('-b', '--bb-gain', dest='bb_gain', default=30)\n") - f.write(" parser.add_option('-w', '--bandwidth', dest='bandwidth', default=250000)\n") - f.write(" parser.add_option('-c', '--freq-correction', dest='freq_correction', default=0)\n") - f.write(" parser.add_option('-d', '--direct-sampling', dest='direct_sampling', default=0)\n") - f.write(" parser.add_option('-n', '--channel-index', dest='channel_index', default=0)\n") - f.write(" parser.add_option('-a', '--antenna-index', dest='antenna_index', default=0)\n") - f.write(" parser.add_option('-p', '--port', dest='port', default=1234)\n\n") + f.write( + " parser.add_option('-s', '--sample-rate', dest='sample_rate', default=100000)\n" + ) + f.write( + " parser.add_option('-f', '--frequency', dest='frequency', default=433000)\n" + ) + f.write( + " parser.add_option('-g', '--gain', dest='rf_gain', default=30)\n" + ) + f.write( + " parser.add_option('-i', '--if-gain', dest='if_gain', default=30)\n" + ) + f.write( + " parser.add_option('-b', '--bb-gain', dest='bb_gain', default=30)\n" + ) + f.write( + " parser.add_option('-w', '--bandwidth', dest='bandwidth', default=250000)\n" + ) + f.write( + " parser.add_option('-c', '--freq-correction', dest='freq_correction', default=0)\n" + ) + f.write( + " parser.add_option('-d', '--direct-sampling', dest='direct_sampling', default=0)\n" + ) + f.write( + " parser.add_option('-n', '--channel-index', dest='channel_index', default=0)\n" + ) + f.write( + " parser.add_option('-a', '--antenna-index', dest='antenna_index', default=0)\n" + ) + f.write( + " parser.add_option('-p', '--port', dest='port', default=1234)\n\n" + ) f.write(" (options, args) = parser.parse_args()\n") - args = ", ".join(["int(options.{})".format(var) for var in used_variables]) + args = ", ".join( + ["int(options.{})".format(var) for var in used_variables] + ) f.write(" tb = top_block({})\n".format(args)) f.write(" iht = InputHandlerThread(tb)\n") f.write(" iht.start()\n") diff --git a/src/urh/dev/gr/scripts/airspy_recv.py b/src/urh/dev/gr/scripts/airspy_recv.py index 3258782ae3..39b82d3f4f 100644 --- a/src/urh/dev/gr/scripts/airspy_recv.py +++ b/src/urh/dev/gr/scripts/airspy_recv.py @@ -14,21 +14,30 @@ class top_block(gr.top_block): - - def __init__(self, sample_rate, frequency, freq_correction, rf_gain, if_gain, bb_gain, bandwidth, port): + def __init__( + self, + sample_rate, + frequency, + freq_correction, + rf_gain, + if_gain, + bb_gain, + bandwidth, + port, + ): gr.top_block.__init__(self, "Top Block") - self.sample_rate = sample_rate - self.rf_gain = rf_gain - self.port = port - self.if_gain = if_gain - self.frequency = frequency - self.freq_correction = freq_correction - self.bb_gain = bb_gain - self.bandwidth = bandwidth + self.sample_rate = sample_rate + self.rf_gain = rf_gain + self.port = port + self.if_gain = if_gain + self.frequency = frequency + self.freq_correction = freq_correction + self.bb_gain = bb_gain + self.bandwidth = bandwidth self.osmosdr_source_0 = osmosdr.source( - args="numchan=" + str(1) + " " + 'airspy' + args="numchan=" + str(1) + " " + "airspy" ) self.osmosdr_source_0.set_time_unknown_pps(osmosdr.time_spec_t()) self.osmosdr_source_0.set_sample_rate(sample_rate) @@ -37,9 +46,11 @@ def __init__(self, sample_rate, frequency, freq_correction, rf_gain, if_gain, bb self.osmosdr_source_0.set_gain(rf_gain, 0) self.osmosdr_source_0.set_if_gain(if_gain, 0) self.osmosdr_source_0.set_bb_gain(bb_gain, 0) - self.osmosdr_source_0.set_antenna('', 0) + self.osmosdr_source_0.set_antenna("", 0) self.osmosdr_source_0.set_bandwidth(bandwidth, 0) - self.blocks_tcp_server_sink_0 = blocks.tcp_server_sink(gr.sizeof_gr_complex * 1, '127.0.0.1', port, False) + self.blocks_tcp_server_sink_0 = blocks.tcp_server_sink( + gr.sizeof_gr_complex * 1, "127.0.0.1", port, False + ) self.connect((self.osmosdr_source_0, 0), (self.blocks_tcp_server_sink_0, 0)) @@ -117,22 +128,31 @@ def set_antenna_index(self, antenna_index): self.antenna_index = antenna_index -if __name__ == '__main__': - parser = OptionParser(usage='%prog: [options]') - parser.add_option('-s', '--sample-rate', dest='sample_rate', default=100000) - parser.add_option('-f', '--frequency', dest='frequency', default=433000) - parser.add_option('-g', '--gain', dest='rf_gain', default=30) - parser.add_option('-i', '--if-gain', dest='if_gain', default=30) - parser.add_option('-b', '--bb-gain', dest='bb_gain', default=30) - parser.add_option('-w', '--bandwidth', dest='bandwidth', default=250000) - parser.add_option('-c', '--freq-correction', dest='freq_correction', default=0) - parser.add_option('-d', '--direct-sampling', dest='direct_sampling', default=0) - parser.add_option('-n', '--channel-index', dest='channel_index', default=0) - parser.add_option('-a', '--antenna-index', dest='antenna_index', default=0) - parser.add_option('-p', '--port', dest='port', default=1234) +if __name__ == "__main__": + parser = OptionParser(usage="%prog: [options]") + parser.add_option("-s", "--sample-rate", dest="sample_rate", default=100000) + parser.add_option("-f", "--frequency", dest="frequency", default=433000) + parser.add_option("-g", "--gain", dest="rf_gain", default=30) + parser.add_option("-i", "--if-gain", dest="if_gain", default=30) + parser.add_option("-b", "--bb-gain", dest="bb_gain", default=30) + parser.add_option("-w", "--bandwidth", dest="bandwidth", default=250000) + parser.add_option("-c", "--freq-correction", dest="freq_correction", default=0) + parser.add_option("-d", "--direct-sampling", dest="direct_sampling", default=0) + parser.add_option("-n", "--channel-index", dest="channel_index", default=0) + parser.add_option("-a", "--antenna-index", dest="antenna_index", default=0) + parser.add_option("-p", "--port", dest="port", default=1234) (options, args) = parser.parse_args() - tb = top_block(int(options.sample_rate), int(options.frequency), int(options.freq_correction), int(options.rf_gain), int(options.if_gain), int(options.bb_gain), int(options.bandwidth), int(options.port)) + tb = top_block( + int(options.sample_rate), + int(options.frequency), + int(options.freq_correction), + int(options.rf_gain), + int(options.if_gain), + int(options.bb_gain), + int(options.bandwidth), + int(options.port), + ) iht = InputHandlerThread(tb) iht.start() tb.start() diff --git a/src/urh/dev/gr/scripts/bladerf_recv.py b/src/urh/dev/gr/scripts/bladerf_recv.py index df83c4e747..5fb426a6b0 100644 --- a/src/urh/dev/gr/scripts/bladerf_recv.py +++ b/src/urh/dev/gr/scripts/bladerf_recv.py @@ -11,8 +11,17 @@ class top_block(gr.top_block): - - def __init__(self, sample_rate, frequency, freq_correction, rf_gain, if_gain, bb_gain, bandwidth, port): + def __init__( + self, + sample_rate, + frequency, + freq_correction, + rf_gain, + if_gain, + bb_gain, + bandwidth, + port, + ): gr.top_block.__init__(self, "Top Block") self.sample_rate = sample_rate @@ -25,7 +34,7 @@ def __init__(self, sample_rate, frequency, freq_correction, rf_gain, if_gain, bb self.bandwidth = bandwidth self.osmosdr_source_0 = osmosdr.source( - args="numchan=" + str(1) + " " + 'bladerf' + args="numchan=" + str(1) + " " + "bladerf" ) self.osmosdr_source_0.set_time_unknown_pps(osmosdr.time_spec_t()) self.osmosdr_source_0.set_sample_rate(sample_rate) @@ -34,9 +43,11 @@ def __init__(self, sample_rate, frequency, freq_correction, rf_gain, if_gain, bb self.osmosdr_source_0.set_gain(rf_gain, 0) self.osmosdr_source_0.set_if_gain(if_gain, 0) self.osmosdr_source_0.set_bb_gain(bb_gain, 0) - self.osmosdr_source_0.set_antenna('', 0) + self.osmosdr_source_0.set_antenna("", 0) self.osmosdr_source_0.set_bandwidth(bandwidth, 0) - self.blocks_tcp_server_sink_0 = blocks.tcp_server_sink(gr.sizeof_gr_complex * 1, '127.0.0.1', port, False) + self.blocks_tcp_server_sink_0 = blocks.tcp_server_sink( + gr.sizeof_gr_complex * 1, "127.0.0.1", port, False + ) self.connect((self.osmosdr_source_0, 0), (self.blocks_tcp_server_sink_0, 0)) @@ -114,23 +125,31 @@ def set_antenna_index(self, antenna_index): self.antenna_index = antenna_index -if __name__ == '__main__': - parser = OptionParser(usage='%prog: [options]') - parser.add_option('-s', '--sample-rate', dest='sample_rate', default=100000) - parser.add_option('-f', '--frequency', dest='frequency', default=433000) - parser.add_option('-g', '--gain', dest='rf_gain', default=30) - parser.add_option('-i', '--if-gain', dest='if_gain', default=30) - parser.add_option('-b', '--bb-gain', dest='bb_gain', default=30) - parser.add_option('-w', '--bandwidth', dest='bandwidth', default=250000) - parser.add_option('-c', '--freq-correction', dest='freq_correction', default=0) - parser.add_option('-d', '--direct-sampling', dest='direct_sampling', default=0) - parser.add_option('-n', '--channel-index', dest='channel_index', default=0) - parser.add_option('-a', '--antenna-index', dest='antenna_index', default=0) - parser.add_option('-p', '--port', dest='port', default=1234) +if __name__ == "__main__": + parser = OptionParser(usage="%prog: [options]") + parser.add_option("-s", "--sample-rate", dest="sample_rate", default=100000) + parser.add_option("-f", "--frequency", dest="frequency", default=433000) + parser.add_option("-g", "--gain", dest="rf_gain", default=30) + parser.add_option("-i", "--if-gain", dest="if_gain", default=30) + parser.add_option("-b", "--bb-gain", dest="bb_gain", default=30) + parser.add_option("-w", "--bandwidth", dest="bandwidth", default=250000) + parser.add_option("-c", "--freq-correction", dest="freq_correction", default=0) + parser.add_option("-d", "--direct-sampling", dest="direct_sampling", default=0) + parser.add_option("-n", "--channel-index", dest="channel_index", default=0) + parser.add_option("-a", "--antenna-index", dest="antenna_index", default=0) + parser.add_option("-p", "--port", dest="port", default=1234) (options, args) = parser.parse_args() - tb = top_block(int(options.sample_rate), int(options.frequency), int(options.freq_correction), int(options.rf_gain), - int(options.if_gain), int(options.bb_gain), int(options.bandwidth), int(options.port)) + tb = top_block( + int(options.sample_rate), + int(options.frequency), + int(options.freq_correction), + int(options.rf_gain), + int(options.if_gain), + int(options.bb_gain), + int(options.bandwidth), + int(options.port), + ) iht = InputHandlerThread(tb) iht.start() tb.start() diff --git a/src/urh/dev/gr/scripts/bladerf_send.py b/src/urh/dev/gr/scripts/bladerf_send.py index b847bc4126..5fbb914842 100644 --- a/src/urh/dev/gr/scripts/bladerf_send.py +++ b/src/urh/dev/gr/scripts/bladerf_send.py @@ -11,8 +11,17 @@ class top_block(gr.top_block): - - def __init__(self, sample_rate, frequency, freq_correction, rf_gain, if_gain, bb_gain, bandwidth, port): + def __init__( + self, + sample_rate, + frequency, + freq_correction, + rf_gain, + if_gain, + bb_gain, + bandwidth, + port, + ): gr.top_block.__init__(self, "Top Block") self.sample_rate = sample_rate @@ -24,9 +33,7 @@ def __init__(self, sample_rate, frequency, freq_correction, rf_gain, if_gain, bb self.bb_gain = bb_gain self.bandwidth = bandwidth - self.osmosdr_sink_0 = osmosdr.sink( - args="numchan=" + str(1) + " " + 'bladerf' - ) + self.osmosdr_sink_0 = osmosdr.sink(args="numchan=" + str(1) + " " + "bladerf") self.osmosdr_sink_0.set_time_unknown_pps(osmosdr.time_spec_t()) self.osmosdr_sink_0.set_sample_rate(sample_rate) self.osmosdr_sink_0.set_center_freq(frequency, 0) @@ -34,9 +41,11 @@ def __init__(self, sample_rate, frequency, freq_correction, rf_gain, if_gain, bb self.osmosdr_sink_0.set_gain(rf_gain, 0) self.osmosdr_sink_0.set_if_gain(if_gain, 0) self.osmosdr_sink_0.set_bb_gain(bb_gain, 0) - self.osmosdr_sink_0.set_antenna('', 0) + self.osmosdr_sink_0.set_antenna("", 0) self.osmosdr_sink_0.set_bandwidth(bandwidth, 0) - self.blocks_udp_source_0 = blocks.udp_source(gr.sizeof_gr_complex * 1, '127.0.0.1', port, 65536, False) + self.blocks_udp_source_0 = blocks.udp_source( + gr.sizeof_gr_complex * 1, "127.0.0.1", port, 65536, False + ) self.connect((self.blocks_udp_source_0, 0), (self.osmosdr_sink_0, 0)) @@ -114,23 +123,31 @@ def set_antenna_index(self, antenna_index): self.antenna_index = antenna_index -if __name__ == '__main__': - parser = OptionParser(usage='%prog: [options]') - parser.add_option('-s', '--sample-rate', dest='sample_rate', default=100000) - parser.add_option('-f', '--frequency', dest='frequency', default=433000) - parser.add_option('-g', '--gain', dest='rf_gain', default=30) - parser.add_option('-i', '--if-gain', dest='if_gain', default=30) - parser.add_option('-b', '--bb-gain', dest='bb_gain', default=30) - parser.add_option('-w', '--bandwidth', dest='bandwidth', default=250000) - parser.add_option('-c', '--freq-correction', dest='freq_correction', default=0) - parser.add_option('-d', '--direct-sampling', dest='direct_sampling', default=0) - parser.add_option('-n', '--channel-index', dest='channel_index', default=0) - parser.add_option('-a', '--antenna-index', dest='antenna_index', default=0) - parser.add_option('-p', '--port', dest='port', default=1234) +if __name__ == "__main__": + parser = OptionParser(usage="%prog: [options]") + parser.add_option("-s", "--sample-rate", dest="sample_rate", default=100000) + parser.add_option("-f", "--frequency", dest="frequency", default=433000) + parser.add_option("-g", "--gain", dest="rf_gain", default=30) + parser.add_option("-i", "--if-gain", dest="if_gain", default=30) + parser.add_option("-b", "--bb-gain", dest="bb_gain", default=30) + parser.add_option("-w", "--bandwidth", dest="bandwidth", default=250000) + parser.add_option("-c", "--freq-correction", dest="freq_correction", default=0) + parser.add_option("-d", "--direct-sampling", dest="direct_sampling", default=0) + parser.add_option("-n", "--channel-index", dest="channel_index", default=0) + parser.add_option("-a", "--antenna-index", dest="antenna_index", default=0) + parser.add_option("-p", "--port", dest="port", default=1234) (options, args) = parser.parse_args() - tb = top_block(int(options.sample_rate), int(options.frequency), int(options.freq_correction), int(options.rf_gain), - int(options.if_gain), int(options.bb_gain), int(options.bandwidth), int(options.port)) + tb = top_block( + int(options.sample_rate), + int(options.frequency), + int(options.freq_correction), + int(options.rf_gain), + int(options.if_gain), + int(options.bb_gain), + int(options.bandwidth), + int(options.port), + ) iht = InputHandlerThread(tb) iht.start() tb.start() diff --git a/src/urh/dev/gr/scripts/funcube_recv.py b/src/urh/dev/gr/scripts/funcube_recv.py index d71bde55d8..32d8ed7c9d 100755 --- a/src/urh/dev/gr/scripts/funcube_recv.py +++ b/src/urh/dev/gr/scripts/funcube_recv.py @@ -11,8 +11,17 @@ class top_block(gr.top_block): - - def __init__(self, sample_rate, frequency, freq_correction, rf_gain, if_gain, bb_gain, bandwidth, port): + def __init__( + self, + sample_rate, + frequency, + freq_correction, + rf_gain, + if_gain, + bb_gain, + bandwidth, + port, + ): gr.top_block.__init__(self, "Top Block") self.sample_rate = sample_rate @@ -24,9 +33,7 @@ def __init__(self, sample_rate, frequency, freq_correction, rf_gain, if_gain, bb self.bb_gain = bb_gain self.bandwidth = bandwidth - self.osmosdr_source_0 = osmosdr.source( - args="numchan=" + str(1) + " " + 'fcd' - ) + self.osmosdr_source_0 = osmosdr.source(args="numchan=" + str(1) + " " + "fcd") self.osmosdr_source_0.set_time_unknown_pps(osmosdr.time_spec_t()) self.osmosdr_source_0.set_sample_rate(sample_rate) self.osmosdr_source_0.set_center_freq(frequency, 0) @@ -34,9 +41,11 @@ def __init__(self, sample_rate, frequency, freq_correction, rf_gain, if_gain, bb self.osmosdr_source_0.set_gain(rf_gain, 0) self.osmosdr_source_0.set_if_gain(if_gain, 0) self.osmosdr_source_0.set_bb_gain(bb_gain, 0) - self.osmosdr_source_0.set_antenna('', 0) + self.osmosdr_source_0.set_antenna("", 0) self.osmosdr_source_0.set_bandwidth(bandwidth, 0) - self.blocks_tcp_server_sink_0 = blocks.tcp_server_sink(gr.sizeof_gr_complex * 1, '127.0.0.1', port, False) + self.blocks_tcp_server_sink_0 = blocks.tcp_server_sink( + gr.sizeof_gr_complex * 1, "127.0.0.1", port, False + ) self.connect((self.osmosdr_source_0, 0), (self.blocks_tcp_server_sink_0, 0)) @@ -114,23 +123,31 @@ def set_antenna_index(self, antenna_index): self.antenna_index = antenna_index -if __name__ == '__main__': - parser = OptionParser(usage='%prog: [options]') - parser.add_option('-s', '--sample-rate', dest='sample_rate', default=100000) - parser.add_option('-f', '--frequency', dest='frequency', default=433000) - parser.add_option('-g', '--gain', dest='rf_gain', default=30) - parser.add_option('-i', '--if-gain', dest='if_gain', default=30) - parser.add_option('-b', '--bb-gain', dest='bb_gain', default=30) - parser.add_option('-w', '--bandwidth', dest='bandwidth', default=250000) - parser.add_option('-c', '--freq-correction', dest='freq_correction', default=0) - parser.add_option('-d', '--direct-sampling', dest='direct_sampling', default=0) - parser.add_option('-n', '--channel-index', dest='channel_index', default=0) - parser.add_option('-a', '--antenna-index', dest='antenna_index', default=0) - parser.add_option('-p', '--port', dest='port', default=1234) +if __name__ == "__main__": + parser = OptionParser(usage="%prog: [options]") + parser.add_option("-s", "--sample-rate", dest="sample_rate", default=100000) + parser.add_option("-f", "--frequency", dest="frequency", default=433000) + parser.add_option("-g", "--gain", dest="rf_gain", default=30) + parser.add_option("-i", "--if-gain", dest="if_gain", default=30) + parser.add_option("-b", "--bb-gain", dest="bb_gain", default=30) + parser.add_option("-w", "--bandwidth", dest="bandwidth", default=250000) + parser.add_option("-c", "--freq-correction", dest="freq_correction", default=0) + parser.add_option("-d", "--direct-sampling", dest="direct_sampling", default=0) + parser.add_option("-n", "--channel-index", dest="channel_index", default=0) + parser.add_option("-a", "--antenna-index", dest="antenna_index", default=0) + parser.add_option("-p", "--port", dest="port", default=1234) (options, args) = parser.parse_args() - tb = top_block(int(options.sample_rate), int(options.frequency), int(options.freq_correction), int(options.rf_gain), - int(options.if_gain), int(options.bb_gain), int(options.bandwidth), int(options.port)) + tb = top_block( + int(options.sample_rate), + int(options.frequency), + int(options.freq_correction), + int(options.rf_gain), + int(options.if_gain), + int(options.bb_gain), + int(options.bandwidth), + int(options.port), + ) iht = InputHandlerThread(tb) iht.start() tb.start() diff --git a/src/urh/dev/gr/scripts/hackrf_recv.py b/src/urh/dev/gr/scripts/hackrf_recv.py index 9b22c5e73e..58ebc6c53a 100755 --- a/src/urh/dev/gr/scripts/hackrf_recv.py +++ b/src/urh/dev/gr/scripts/hackrf_recv.py @@ -11,8 +11,17 @@ class top_block(gr.top_block): - - def __init__(self, sample_rate, frequency, freq_correction, rf_gain, if_gain, bb_gain, bandwidth, port): + def __init__( + self, + sample_rate, + frequency, + freq_correction, + rf_gain, + if_gain, + bb_gain, + bandwidth, + port, + ): gr.top_block.__init__(self, "Top Block") self.sample_rate = sample_rate @@ -25,7 +34,7 @@ def __init__(self, sample_rate, frequency, freq_correction, rf_gain, if_gain, bb self.bandwidth = bandwidth self.osmosdr_source_0 = osmosdr.source( - args="numchan=" + str(1) + " " + 'hackrf' + args="numchan=" + str(1) + " " + "hackrf" ) self.osmosdr_source_0.set_time_unknown_pps(osmosdr.time_spec_t()) self.osmosdr_source_0.set_sample_rate(sample_rate) @@ -34,9 +43,11 @@ def __init__(self, sample_rate, frequency, freq_correction, rf_gain, if_gain, bb self.osmosdr_source_0.set_gain(rf_gain, 0) self.osmosdr_source_0.set_if_gain(if_gain, 0) self.osmosdr_source_0.set_bb_gain(bb_gain, 0) - self.osmosdr_source_0.set_antenna('', 0) + self.osmosdr_source_0.set_antenna("", 0) self.osmosdr_source_0.set_bandwidth(bandwidth, 0) - self.blocks_tcp_server_sink_0 = blocks.tcp_server_sink(gr.sizeof_gr_complex * 1, '127.0.0.1', port, False) + self.blocks_tcp_server_sink_0 = blocks.tcp_server_sink( + gr.sizeof_gr_complex * 1, "127.0.0.1", port, False + ) self.connect((self.osmosdr_source_0, 0), (self.blocks_tcp_server_sink_0, 0)) @@ -114,23 +125,31 @@ def set_antenna_index(self, antenna_index): self.antenna_index = antenna_index -if __name__ == '__main__': - parser = OptionParser(usage='%prog: [options]') - parser.add_option('-s', '--sample-rate', dest='sample_rate', default=100000) - parser.add_option('-f', '--frequency', dest='frequency', default=433000) - parser.add_option('-g', '--gain', dest='rf_gain', default=30) - parser.add_option('-i', '--if-gain', dest='if_gain', default=30) - parser.add_option('-b', '--bb-gain', dest='bb_gain', default=30) - parser.add_option('-w', '--bandwidth', dest='bandwidth', default=250000) - parser.add_option('-c', '--freq-correction', dest='freq_correction', default=0) - parser.add_option('-d', '--direct-sampling', dest='direct_sampling', default=0) - parser.add_option('-n', '--channel-index', dest='channel_index', default=0) - parser.add_option('-a', '--antenna-index', dest='antenna_index', default=0) - parser.add_option('-p', '--port', dest='port', default=1234) +if __name__ == "__main__": + parser = OptionParser(usage="%prog: [options]") + parser.add_option("-s", "--sample-rate", dest="sample_rate", default=100000) + parser.add_option("-f", "--frequency", dest="frequency", default=433000) + parser.add_option("-g", "--gain", dest="rf_gain", default=30) + parser.add_option("-i", "--if-gain", dest="if_gain", default=30) + parser.add_option("-b", "--bb-gain", dest="bb_gain", default=30) + parser.add_option("-w", "--bandwidth", dest="bandwidth", default=250000) + parser.add_option("-c", "--freq-correction", dest="freq_correction", default=0) + parser.add_option("-d", "--direct-sampling", dest="direct_sampling", default=0) + parser.add_option("-n", "--channel-index", dest="channel_index", default=0) + parser.add_option("-a", "--antenna-index", dest="antenna_index", default=0) + parser.add_option("-p", "--port", dest="port", default=1234) (options, args) = parser.parse_args() - tb = top_block(int(options.sample_rate), int(options.frequency), int(options.freq_correction), int(options.rf_gain), - int(options.if_gain), int(options.bb_gain), int(options.bandwidth), int(options.port)) + tb = top_block( + int(options.sample_rate), + int(options.frequency), + int(options.freq_correction), + int(options.rf_gain), + int(options.if_gain), + int(options.bb_gain), + int(options.bandwidth), + int(options.port), + ) iht = InputHandlerThread(tb) iht.start() tb.start() diff --git a/src/urh/dev/gr/scripts/hackrf_send.py b/src/urh/dev/gr/scripts/hackrf_send.py index 281b12a597..d9cec0a6fc 100755 --- a/src/urh/dev/gr/scripts/hackrf_send.py +++ b/src/urh/dev/gr/scripts/hackrf_send.py @@ -11,8 +11,17 @@ class top_block(gr.top_block): - - def __init__(self, sample_rate, frequency, freq_correction, rf_gain, if_gain, bb_gain, bandwidth, port): + def __init__( + self, + sample_rate, + frequency, + freq_correction, + rf_gain, + if_gain, + bb_gain, + bandwidth, + port, + ): gr.top_block.__init__(self, "Top Block") self.sample_rate = sample_rate @@ -24,9 +33,7 @@ def __init__(self, sample_rate, frequency, freq_correction, rf_gain, if_gain, bb self.bb_gain = bb_gain self.bandwidth = bandwidth - self.osmosdr_sink_0 = osmosdr.sink( - args="numchan=" + str(1) + " " + 'hackrf' - ) + self.osmosdr_sink_0 = osmosdr.sink(args="numchan=" + str(1) + " " + "hackrf") self.osmosdr_sink_0.set_time_unknown_pps(osmosdr.time_spec_t()) self.osmosdr_sink_0.set_sample_rate(sample_rate) self.osmosdr_sink_0.set_center_freq(frequency, 0) @@ -34,9 +41,11 @@ def __init__(self, sample_rate, frequency, freq_correction, rf_gain, if_gain, bb self.osmosdr_sink_0.set_gain(rf_gain, 0) self.osmosdr_sink_0.set_if_gain(if_gain, 0) self.osmosdr_sink_0.set_bb_gain(bb_gain, 0) - self.osmosdr_sink_0.set_antenna('', 0) + self.osmosdr_sink_0.set_antenna("", 0) self.osmosdr_sink_0.set_bandwidth(bandwidth, 0) - self.blocks_udp_source_0 = blocks.udp_source(gr.sizeof_gr_complex * 1, '127.0.0.1', port, 65536, False) + self.blocks_udp_source_0 = blocks.udp_source( + gr.sizeof_gr_complex * 1, "127.0.0.1", port, 65536, False + ) self.connect((self.blocks_udp_source_0, 0), (self.osmosdr_sink_0, 0)) @@ -114,23 +123,31 @@ def set_antenna_index(self, antenna_index): self.antenna_index = antenna_index -if __name__ == '__main__': - parser = OptionParser(usage='%prog: [options]') - parser.add_option('-s', '--sample-rate', dest='sample_rate', default=100000) - parser.add_option('-f', '--frequency', dest='frequency', default=433000) - parser.add_option('-g', '--gain', dest='rf_gain', default=30) - parser.add_option('-i', '--if-gain', dest='if_gain', default=30) - parser.add_option('-b', '--bb-gain', dest='bb_gain', default=30) - parser.add_option('-w', '--bandwidth', dest='bandwidth', default=250000) - parser.add_option('-c', '--freq-correction', dest='freq_correction', default=0) - parser.add_option('-d', '--direct-sampling', dest='direct_sampling', default=0) - parser.add_option('-n', '--channel-index', dest='channel_index', default=0) - parser.add_option('-a', '--antenna-index', dest='antenna_index', default=0) - parser.add_option('-p', '--port', dest='port', default=1234) +if __name__ == "__main__": + parser = OptionParser(usage="%prog: [options]") + parser.add_option("-s", "--sample-rate", dest="sample_rate", default=100000) + parser.add_option("-f", "--frequency", dest="frequency", default=433000) + parser.add_option("-g", "--gain", dest="rf_gain", default=30) + parser.add_option("-i", "--if-gain", dest="if_gain", default=30) + parser.add_option("-b", "--bb-gain", dest="bb_gain", default=30) + parser.add_option("-w", "--bandwidth", dest="bandwidth", default=250000) + parser.add_option("-c", "--freq-correction", dest="freq_correction", default=0) + parser.add_option("-d", "--direct-sampling", dest="direct_sampling", default=0) + parser.add_option("-n", "--channel-index", dest="channel_index", default=0) + parser.add_option("-a", "--antenna-index", dest="antenna_index", default=0) + parser.add_option("-p", "--port", dest="port", default=1234) (options, args) = parser.parse_args() - tb = top_block(int(options.sample_rate), int(options.frequency), int(options.freq_correction), int(options.rf_gain), - int(options.if_gain), int(options.bb_gain), int(options.bandwidth), int(options.port)) + tb = top_block( + int(options.sample_rate), + int(options.frequency), + int(options.freq_correction), + int(options.rf_gain), + int(options.if_gain), + int(options.bb_gain), + int(options.bandwidth), + int(options.port), + ) iht = InputHandlerThread(tb) iht.start() tb.start() diff --git a/src/urh/dev/gr/scripts/rtl-sdr_recv.py b/src/urh/dev/gr/scripts/rtl-sdr_recv.py index cb9e1c1c22..7083fdf4e8 100755 --- a/src/urh/dev/gr/scripts/rtl-sdr_recv.py +++ b/src/urh/dev/gr/scripts/rtl-sdr_recv.py @@ -11,8 +11,17 @@ class top_block(gr.top_block): - - def __init__(self, sample_rate, frequency, freq_correction, rf_gain, if_gain, bb_gain, bandwidth, port): + def __init__( + self, + sample_rate, + frequency, + freq_correction, + rf_gain, + if_gain, + bb_gain, + bandwidth, + port, + ): gr.top_block.__init__(self, "Top Block") self.sample_rate = sample_rate @@ -24,9 +33,7 @@ def __init__(self, sample_rate, frequency, freq_correction, rf_gain, if_gain, bb self.bb_gain = bb_gain self.bandwidth = bandwidth - self.osmosdr_source_0 = osmosdr.source( - args="numchan=" + str(1) + " " + 'rtl' - ) + self.osmosdr_source_0 = osmosdr.source(args="numchan=" + str(1) + " " + "rtl") self.osmosdr_source_0.set_time_unknown_pps(osmosdr.time_spec_t()) self.osmosdr_source_0.set_sample_rate(sample_rate) self.osmosdr_source_0.set_center_freq(frequency, 0) @@ -34,9 +41,11 @@ def __init__(self, sample_rate, frequency, freq_correction, rf_gain, if_gain, bb self.osmosdr_source_0.set_gain(rf_gain, 0) self.osmosdr_source_0.set_if_gain(if_gain, 0) self.osmosdr_source_0.set_bb_gain(bb_gain, 0) - self.osmosdr_source_0.set_antenna('', 0) + self.osmosdr_source_0.set_antenna("", 0) self.osmosdr_source_0.set_bandwidth(bandwidth, 0) - self.blocks_tcp_server_sink_0 = blocks.tcp_server_sink(gr.sizeof_gr_complex * 1, '127.0.0.1', port, False) + self.blocks_tcp_server_sink_0 = blocks.tcp_server_sink( + gr.sizeof_gr_complex * 1, "127.0.0.1", port, False + ) self.connect((self.osmosdr_source_0, 0), (self.blocks_tcp_server_sink_0, 0)) @@ -114,23 +123,31 @@ def set_antenna_index(self, antenna_index): self.antenna_index = antenna_index -if __name__ == '__main__': - parser = OptionParser(usage='%prog: [options]') - parser.add_option('-s', '--sample-rate', dest='sample_rate', default=100000) - parser.add_option('-f', '--frequency', dest='frequency', default=433000) - parser.add_option('-g', '--gain', dest='rf_gain', default=30) - parser.add_option('-i', '--if-gain', dest='if_gain', default=30) - parser.add_option('-b', '--bb-gain', dest='bb_gain', default=30) - parser.add_option('-w', '--bandwidth', dest='bandwidth', default=250000) - parser.add_option('-c', '--freq-correction', dest='freq_correction', default=0) - parser.add_option('-d', '--direct-sampling', dest='direct_sampling', default=0) - parser.add_option('-n', '--channel-index', dest='channel_index', default=0) - parser.add_option('-a', '--antenna-index', dest='antenna_index', default=0) - parser.add_option('-p', '--port', dest='port', default=1234) +if __name__ == "__main__": + parser = OptionParser(usage="%prog: [options]") + parser.add_option("-s", "--sample-rate", dest="sample_rate", default=100000) + parser.add_option("-f", "--frequency", dest="frequency", default=433000) + parser.add_option("-g", "--gain", dest="rf_gain", default=30) + parser.add_option("-i", "--if-gain", dest="if_gain", default=30) + parser.add_option("-b", "--bb-gain", dest="bb_gain", default=30) + parser.add_option("-w", "--bandwidth", dest="bandwidth", default=250000) + parser.add_option("-c", "--freq-correction", dest="freq_correction", default=0) + parser.add_option("-d", "--direct-sampling", dest="direct_sampling", default=0) + parser.add_option("-n", "--channel-index", dest="channel_index", default=0) + parser.add_option("-a", "--antenna-index", dest="antenna_index", default=0) + parser.add_option("-p", "--port", dest="port", default=1234) (options, args) = parser.parse_args() - tb = top_block(int(options.sample_rate), int(options.frequency), int(options.freq_correction), int(options.rf_gain), - int(options.if_gain), int(options.bb_gain), int(options.bandwidth), int(options.port)) + tb = top_block( + int(options.sample_rate), + int(options.frequency), + int(options.freq_correction), + int(options.rf_gain), + int(options.if_gain), + int(options.bb_gain), + int(options.bandwidth), + int(options.port), + ) iht = InputHandlerThread(tb) iht.start() tb.start() diff --git a/src/urh/dev/gr/scripts/sdrplay_recv.py b/src/urh/dev/gr/scripts/sdrplay_recv.py index 83a25e1466..1225a8d4a1 100644 --- a/src/urh/dev/gr/scripts/sdrplay_recv.py +++ b/src/urh/dev/gr/scripts/sdrplay_recv.py @@ -11,8 +11,17 @@ class top_block(gr.top_block): - - def __init__(self, sample_rate, frequency, freq_correction, rf_gain, if_gain, bb_gain, bandwidth, port): + def __init__( + self, + sample_rate, + frequency, + freq_correction, + rf_gain, + if_gain, + bb_gain, + bandwidth, + port, + ): gr.top_block.__init__(self, "Top Block") self.sample_rate = sample_rate @@ -25,7 +34,7 @@ def __init__(self, sample_rate, frequency, freq_correction, rf_gain, if_gain, bb self.bandwidth = bandwidth self.osmosdr_source_0 = osmosdr.source( - args="numchan=" + str(1) + " " + 'sdrplay' + args="numchan=" + str(1) + " " + "sdrplay" ) self.osmosdr_source_0.set_time_unknown_pps(osmosdr.time_spec_t()) self.osmosdr_source_0.set_sample_rate(sample_rate) @@ -34,9 +43,11 @@ def __init__(self, sample_rate, frequency, freq_correction, rf_gain, if_gain, bb self.osmosdr_source_0.set_gain(rf_gain, 0) self.osmosdr_source_0.set_if_gain(if_gain, 0) self.osmosdr_source_0.set_bb_gain(bb_gain, 0) - self.osmosdr_source_0.set_antenna('', 0) + self.osmosdr_source_0.set_antenna("", 0) self.osmosdr_source_0.set_bandwidth(bandwidth, 0) - self.blocks_tcp_server_sink_0 = blocks.tcp_server_sink(gr.sizeof_gr_complex * 1, '127.0.0.1', port, False) + self.blocks_tcp_server_sink_0 = blocks.tcp_server_sink( + gr.sizeof_gr_complex * 1, "127.0.0.1", port, False + ) self.connect((self.osmosdr_source_0, 0), (self.blocks_tcp_server_sink_0, 0)) @@ -114,23 +125,31 @@ def set_antenna_index(self, antenna_index): self.antenna_index = antenna_index -if __name__ == '__main__': - parser = OptionParser(usage='%prog: [options]') - parser.add_option('-s', '--sample-rate', dest='sample_rate', default=100000) - parser.add_option('-f', '--frequency', dest='frequency', default=433000) - parser.add_option('-g', '--gain', dest='rf_gain', default=30) - parser.add_option('-i', '--if-gain', dest='if_gain', default=30) - parser.add_option('-b', '--bb-gain', dest='bb_gain', default=30) - parser.add_option('-w', '--bandwidth', dest='bandwidth', default=250000) - parser.add_option('-c', '--freq-correction', dest='freq_correction', default=0) - parser.add_option('-d', '--direct-sampling', dest='direct_sampling', default=0) - parser.add_option('-n', '--channel-index', dest='channel_index', default=0) - parser.add_option('-a', '--antenna-index', dest='antenna_index', default=0) - parser.add_option('-p', '--port', dest='port', default=1234) +if __name__ == "__main__": + parser = OptionParser(usage="%prog: [options]") + parser.add_option("-s", "--sample-rate", dest="sample_rate", default=100000) + parser.add_option("-f", "--frequency", dest="frequency", default=433000) + parser.add_option("-g", "--gain", dest="rf_gain", default=30) + parser.add_option("-i", "--if-gain", dest="if_gain", default=30) + parser.add_option("-b", "--bb-gain", dest="bb_gain", default=30) + parser.add_option("-w", "--bandwidth", dest="bandwidth", default=250000) + parser.add_option("-c", "--freq-correction", dest="freq_correction", default=0) + parser.add_option("-d", "--direct-sampling", dest="direct_sampling", default=0) + parser.add_option("-n", "--channel-index", dest="channel_index", default=0) + parser.add_option("-a", "--antenna-index", dest="antenna_index", default=0) + parser.add_option("-p", "--port", dest="port", default=1234) (options, args) = parser.parse_args() - tb = top_block(int(options.sample_rate), int(options.frequency), int(options.freq_correction), int(options.rf_gain), - int(options.if_gain), int(options.bb_gain), int(options.bandwidth), int(options.port)) + tb = top_block( + int(options.sample_rate), + int(options.frequency), + int(options.freq_correction), + int(options.rf_gain), + int(options.if_gain), + int(options.bb_gain), + int(options.bandwidth), + int(options.port), + ) iht = InputHandlerThread(tb) iht.start() tb.start() diff --git a/src/urh/dev/gr/scripts/usrp_recv.py b/src/urh/dev/gr/scripts/usrp_recv.py index 75dbaa1efe..2a2ef4db1a 100755 --- a/src/urh/dev/gr/scripts/usrp_recv.py +++ b/src/urh/dev/gr/scripts/usrp_recv.py @@ -12,22 +12,29 @@ class top_block(gr.top_block): - - def __init__(self, sample_rate, frequency, freq_correction, rf_gain, if_gain, bb_gain, bandwidth, port): + def __init__( + self, + sample_rate, + frequency, + freq_correction, + rf_gain, + if_gain, + bb_gain, + bandwidth, + port, + ): gr.top_block.__init__(self, "Top Block") - self.sample_rate = sample_rate - self.rf_gain = rf_gain - self.port = port - self.if_gain = if_gain - self.frequency = frequency - self.freq_correction = freq_correction - self.bb_gain = bb_gain - self.bandwidth = bandwidth - - self.osmosdr_source_0 = osmosdr.source( - args="numchan=" + str(1) + " " + 'uhd' - ) + self.sample_rate = sample_rate + self.rf_gain = rf_gain + self.port = port + self.if_gain = if_gain + self.frequency = frequency + self.freq_correction = freq_correction + self.bb_gain = bb_gain + self.bandwidth = bandwidth + + self.osmosdr_source_0 = osmosdr.source(args="numchan=" + str(1) + " " + "uhd") self.osmosdr_source_0.set_time_unknown_pps(osmosdr.time_spec_t()) self.osmosdr_source_0.set_sample_rate(sample_rate) self.osmosdr_source_0.set_center_freq(frequency, 0) @@ -35,11 +42,11 @@ def __init__(self, sample_rate, frequency, freq_correction, rf_gain, if_gain, bb self.osmosdr_source_0.set_gain(rf_gain, 0) self.osmosdr_source_0.set_if_gain(if_gain, 0) self.osmosdr_source_0.set_bb_gain(bb_gain, 0) - self.osmosdr_source_0.set_antenna('', 0) + self.osmosdr_source_0.set_antenna("", 0) self.osmosdr_source_0.set_bandwidth(bandwidth, 0) - self.blocks_tcp_server_sink_0 = blocks.tcp_server_sink(gr.sizeof_gr_complex*1, '127.0.0.1', port, False) - - + self.blocks_tcp_server_sink_0 = blocks.tcp_server_sink( + gr.sizeof_gr_complex * 1, "127.0.0.1", port, False + ) self.connect((self.osmosdr_source_0, 0), (self.blocks_tcp_server_sink_0, 0)) @@ -117,23 +124,31 @@ def set_antenna_index(self, antenna_index): self.antenna_index = antenna_index - -if __name__ == '__main__': - parser = OptionParser(usage='%prog: [options]') - parser.add_option('-s', '--sample-rate', dest='sample_rate', default=100000) - parser.add_option('-f', '--frequency', dest='frequency', default=433000) - parser.add_option('-g', '--gain', dest='rf_gain', default=30) - parser.add_option('-i', '--if-gain', dest='if_gain', default=30) - parser.add_option('-b', '--bb-gain', dest='bb_gain', default=30) - parser.add_option('-w', '--bandwidth', dest='bandwidth', default=250000) - parser.add_option('-c', '--freq-correction', dest='freq_correction', default=0) - parser.add_option('-d', '--direct-sampling', dest='direct_sampling', default=0) - parser.add_option('-n', '--channel-index', dest='channel_index', default=0) - parser.add_option('-a', '--antenna-index', dest='antenna_index', default=0) - parser.add_option('-p', '--port', dest='port', default=1234) +if __name__ == "__main__": + parser = OptionParser(usage="%prog: [options]") + parser.add_option("-s", "--sample-rate", dest="sample_rate", default=100000) + parser.add_option("-f", "--frequency", dest="frequency", default=433000) + parser.add_option("-g", "--gain", dest="rf_gain", default=30) + parser.add_option("-i", "--if-gain", dest="if_gain", default=30) + parser.add_option("-b", "--bb-gain", dest="bb_gain", default=30) + parser.add_option("-w", "--bandwidth", dest="bandwidth", default=250000) + parser.add_option("-c", "--freq-correction", dest="freq_correction", default=0) + parser.add_option("-d", "--direct-sampling", dest="direct_sampling", default=0) + parser.add_option("-n", "--channel-index", dest="channel_index", default=0) + parser.add_option("-a", "--antenna-index", dest="antenna_index", default=0) + parser.add_option("-p", "--port", dest="port", default=1234) (options, args) = parser.parse_args() - tb = top_block(int(options.sample_rate), int(options.frequency), int(options.freq_correction), int(options.rf_gain), int(options.if_gain), int(options.bb_gain), int(options.bandwidth), int(options.port)) + tb = top_block( + int(options.sample_rate), + int(options.frequency), + int(options.freq_correction), + int(options.rf_gain), + int(options.if_gain), + int(options.bb_gain), + int(options.bandwidth), + int(options.port), + ) iht = InputHandlerThread(tb) iht.start() tb.start() diff --git a/src/urh/dev/gr/scripts/usrp_send.py b/src/urh/dev/gr/scripts/usrp_send.py index b030d8abe8..98b43df633 100755 --- a/src/urh/dev/gr/scripts/usrp_send.py +++ b/src/urh/dev/gr/scripts/usrp_send.py @@ -11,8 +11,17 @@ class top_block(gr.top_block): - - def __init__(self, sample_rate, frequency, freq_correction, rf_gain, if_gain, bb_gain, bandwidth, port): + def __init__( + self, + sample_rate, + frequency, + freq_correction, + rf_gain, + if_gain, + bb_gain, + bandwidth, + port, + ): gr.top_block.__init__(self, "Top Block") self.sample_rate = sample_rate @@ -24,9 +33,7 @@ def __init__(self, sample_rate, frequency, freq_correction, rf_gain, if_gain, bb self.bb_gain = bb_gain self.bandwidth = bandwidth - self.osmosdr_sink_0 = osmosdr.sink( - args="numchan=" + str(1) + " " + 'uhd' - ) + self.osmosdr_sink_0 = osmosdr.sink(args="numchan=" + str(1) + " " + "uhd") self.osmosdr_sink_0.set_time_unknown_pps(osmosdr.time_spec_t()) self.osmosdr_sink_0.set_sample_rate(sample_rate) self.osmosdr_sink_0.set_center_freq(frequency, 0) @@ -34,9 +41,11 @@ def __init__(self, sample_rate, frequency, freq_correction, rf_gain, if_gain, bb self.osmosdr_sink_0.set_gain(rf_gain, 0) self.osmosdr_sink_0.set_if_gain(if_gain, 0) self.osmosdr_sink_0.set_bb_gain(bb_gain, 0) - self.osmosdr_sink_0.set_antenna('', 0) + self.osmosdr_sink_0.set_antenna("", 0) self.osmosdr_sink_0.set_bandwidth(bandwidth, 0) - self.blocks_udp_source_0 = blocks.udp_source(gr.sizeof_gr_complex * 1, '127.0.0.1', port, 65536, False) + self.blocks_udp_source_0 = blocks.udp_source( + gr.sizeof_gr_complex * 1, "127.0.0.1", port, 65536, False + ) self.connect((self.blocks_udp_source_0, 0), (self.osmosdr_sink_0, 0)) @@ -114,23 +123,31 @@ def set_antenna_index(self, antenna_index): self.antenna_index = antenna_index -if __name__ == '__main__': - parser = OptionParser(usage='%prog: [options]') - parser.add_option('-s', '--sample-rate', dest='sample_rate', default=100000) - parser.add_option('-f', '--frequency', dest='frequency', default=433000) - parser.add_option('-g', '--gain', dest='rf_gain', default=30) - parser.add_option('-i', '--if-gain', dest='if_gain', default=30) - parser.add_option('-b', '--bb-gain', dest='bb_gain', default=30) - parser.add_option('-w', '--bandwidth', dest='bandwidth', default=250000) - parser.add_option('-c', '--freq-correction', dest='freq_correction', default=0) - parser.add_option('-d', '--direct-sampling', dest='direct_sampling', default=0) - parser.add_option('-n', '--channel-index', dest='channel_index', default=0) - parser.add_option('-a', '--antenna-index', dest='antenna_index', default=0) - parser.add_option('-p', '--port', dest='port', default=1234) +if __name__ == "__main__": + parser = OptionParser(usage="%prog: [options]") + parser.add_option("-s", "--sample-rate", dest="sample_rate", default=100000) + parser.add_option("-f", "--frequency", dest="frequency", default=433000) + parser.add_option("-g", "--gain", dest="rf_gain", default=30) + parser.add_option("-i", "--if-gain", dest="if_gain", default=30) + parser.add_option("-b", "--bb-gain", dest="bb_gain", default=30) + parser.add_option("-w", "--bandwidth", dest="bandwidth", default=250000) + parser.add_option("-c", "--freq-correction", dest="freq_correction", default=0) + parser.add_option("-d", "--direct-sampling", dest="direct_sampling", default=0) + parser.add_option("-n", "--channel-index", dest="channel_index", default=0) + parser.add_option("-a", "--antenna-index", dest="antenna_index", default=0) + parser.add_option("-p", "--port", dest="port", default=1234) (options, args) = parser.parse_args() - tb = top_block(int(options.sample_rate), int(options.frequency), int(options.freq_correction), int(options.rf_gain), - int(options.if_gain), int(options.bb_gain), int(options.bandwidth), int(options.port)) + tb = top_block( + int(options.sample_rate), + int(options.frequency), + int(options.freq_correction), + int(options.rf_gain), + int(options.if_gain), + int(options.bb_gain), + int(options.bandwidth), + int(options.port), + ) iht = InputHandlerThread(tb) iht.start() tb.start() diff --git a/src/urh/dev/native/AirSpy.py b/src/urh/dev/native/AirSpy.py index 1d6c2cb61d..90a50faaf0 100644 --- a/src/urh/dev/native/AirSpy.py +++ b/src/urh/dev/native/AirSpy.py @@ -11,9 +11,11 @@ class AirSpy(Device): DEVICE_LIB = airspy ASYNCHRONOUS = True DEVICE_METHODS = Device.DEVICE_METHODS.copy() - DEVICE_METHODS.update({ - Device.Command.SET_FREQUENCY.name: "set_center_frequency", - }) + DEVICE_METHODS.update( + { + Device.Command.SET_FREQUENCY.name: "set_center_frequency", + } + ) del DEVICE_METHODS[Device.Command.SET_BANDWIDTH.name] DATA_TYPE = np.float32 @@ -36,16 +38,32 @@ def shutdown_device(cls, ctrl_connection, is_tx=False): return True @classmethod - def enter_async_receive_mode(cls, data_connection: Connection, ctrl_connection: Connection): + def enter_async_receive_mode( + cls, data_connection: Connection, ctrl_connection: Connection + ): ret = airspy.start_rx(data_connection.send_bytes) ctrl_connection.send("Start RX MODE:" + str(ret)) return ret - def __init__(self, center_freq, sample_rate, bandwidth, gain, if_gain=1, baseband_gain=1, - resume_on_full_receive_buffer=False): - super().__init__(center_freq=center_freq, sample_rate=sample_rate, bandwidth=bandwidth, - gain=gain, if_gain=if_gain, baseband_gain=baseband_gain, - resume_on_full_receive_buffer=resume_on_full_receive_buffer) + def __init__( + self, + center_freq, + sample_rate, + bandwidth, + gain, + if_gain=1, + baseband_gain=1, + resume_on_full_receive_buffer=False, + ): + super().__init__( + center_freq=center_freq, + sample_rate=sample_rate, + bandwidth=bandwidth, + gain=gain, + if_gain=if_gain, + baseband_gain=baseband_gain, + resume_on_full_receive_buffer=resume_on_full_receive_buffer, + ) self.success = 0 self.bandwidth_is_adjustable = False diff --git a/src/urh/dev/native/BladeRF.py b/src/urh/dev/native/BladeRF.py index 3eb746e941..4c4cd6d301 100644 --- a/src/urh/dev/native/BladeRF.py +++ b/src/urh/dev/native/BladeRF.py @@ -15,11 +15,13 @@ class BladeRF(Device): DEVICE_LIB = bladerf ASYNCHRONOUS = False DEVICE_METHODS = Device.DEVICE_METHODS.copy() - DEVICE_METHODS.update({ - Device.Command.SET_RF_GAIN.name: "set_gain", - Device.Command.SET_CHANNEL_INDEX.name: "set_channel", - Device.Command.SET_BIAS_TEE_ENABLED.name: "set_bias_tee" - }) + DEVICE_METHODS.update( + { + Device.Command.SET_RF_GAIN.name: "set_gain", + Device.Command.SET_CHANNEL_INDEX.name: "set_channel", + Device.Command.SET_BIAS_TEE_ENABLED.name: "set_bias_tee", + } + ) DATA_TYPE = np.int16 @@ -42,14 +44,18 @@ def setup_device(cls, ctrl_connection: Connection, device_identifier): else: ctrl_connection.send("OPEN ({}):{}".format(device_identifier, ret)) - ctrl_connection.send("If you experience problems, make sure you place a rbf file matching your device" - " at the correct location. See http://www.nuand.com/fpga_images/" - " and https://github.com/Nuand/bladeRF/wiki/FPGA-Autoloading") + ctrl_connection.send( + "If you experience problems, make sure you place a rbf file matching your device" + " at the correct location. See http://www.nuand.com/fpga_images/" + " and https://github.com/Nuand/bladeRF/wiki/FPGA-Autoloading" + ) return ret == 0 @classmethod - def init_device(cls, ctrl_connection: Connection, is_tx: bool, parameters: OrderedDict) -> bool: + def init_device( + cls, ctrl_connection: Connection, is_tx: bool, parameters: OrderedDict + ) -> bool: bladerf.set_tx(is_tx) return super().init_device(ctrl_connection, is_tx, parameters) @@ -79,11 +85,25 @@ def prepare_sync_send(cls, ctrl_connection: Connection): def send_sync(cls, data): bladerf.send_sync(data) - def __init__(self, center_freq, sample_rate, bandwidth, gain, if_gain=1, baseband_gain=1, - resume_on_full_receive_buffer=False): - super().__init__(center_freq=center_freq, sample_rate=sample_rate, bandwidth=bandwidth, - gain=gain, if_gain=if_gain, baseband_gain=baseband_gain, - resume_on_full_receive_buffer=resume_on_full_receive_buffer) + def __init__( + self, + center_freq, + sample_rate, + bandwidth, + gain, + if_gain=1, + baseband_gain=1, + resume_on_full_receive_buffer=False, + ): + super().__init__( + center_freq=center_freq, + sample_rate=sample_rate, + bandwidth=bandwidth, + gain=gain, + if_gain=if_gain, + baseband_gain=baseband_gain, + resume_on_full_receive_buffer=resume_on_full_receive_buffer, + ) self.success = 0 @property @@ -92,13 +112,17 @@ def has_multi_device_support(self): @property def device_parameters(self): - return OrderedDict([(self.Command.SET_CHANNEL_INDEX.name, self.channel_index), - (self.Command.SET_FREQUENCY.name, self.frequency), - (self.Command.SET_SAMPLE_RATE.name, self.sample_rate), - (self.Command.SET_BANDWIDTH.name, self.bandwidth), - (self.Command.SET_RF_GAIN.name, self.gain), - (self.Command.SET_BIAS_TEE_ENABLED.name, self.bias_tee_enabled), - ("identifier", self.device_serial)]) + return OrderedDict( + [ + (self.Command.SET_CHANNEL_INDEX.name, self.channel_index), + (self.Command.SET_FREQUENCY.name, self.frequency), + (self.Command.SET_SAMPLE_RATE.name, self.sample_rate), + (self.Command.SET_BANDWIDTH.name, self.bandwidth), + (self.Command.SET_RF_GAIN.name, self.gain), + (self.Command.SET_BIAS_TEE_ENABLED.name, self.bias_tee_enabled), + ("identifier", self.device_serial), + ] + ) @staticmethod def bytes_to_iq(buffer) -> np.ndarray: diff --git a/src/urh/dev/native/Device.py b/src/urh/dev/native/Device.py index 484a95a61b..e2cf49bced 100644 --- a/src/urh/dev/native/Device.py +++ b/src/urh/dev/native/Device.py @@ -50,7 +50,7 @@ class Command(Enum): Command.SET_BANDWIDTH.name: "set_bandwidth", Command.SET_RF_GAIN.name: "set_rf_gain", Command.SET_IF_GAIN.name: {"rx": "set_if_rx_gain", "tx": "set_if_tx_gain"}, - Command.SET_BB_GAIN.name: {"rx": "set_baseband_gain"} + Command.SET_BB_GAIN.name: {"rx": "set_baseband_gain"}, } @classmethod @@ -82,9 +82,11 @@ def process_command(cls, command, ctrl_connection, is_tx: bool): allowed_values = getattr(cls.DEVICE_LIB, check_method_name)() next_allowed = min(allowed_values, key=lambda x: abs(x - value)) if value != next_allowed: - ctrl_connection.send("{}: {} not in range of supported values. Assuming {}".format( - tag, value, next_allowed - )) + ctrl_connection.send( + "{}: {} not in range of supported values. Assuming {}".format( + tag, value, next_allowed + ) + ) value = next_allowed except (KeyError, AttributeError): pass @@ -101,8 +103,12 @@ def setup_device(cls, ctrl_connection: Connection, device_identifier): raise NotImplementedError("Overwrite this method in subclass!") @classmethod - def init_device(cls, ctrl_connection: Connection, is_tx: bool, parameters: OrderedDict) -> bool: - if cls.setup_device(ctrl_connection, device_identifier=parameters["identifier"]): + def init_device( + cls, ctrl_connection: Connection, is_tx: bool, parameters: OrderedDict + ) -> bool: + if cls.setup_device( + ctrl_connection, device_identifier=parameters["identifier"] + ): for parameter, value in parameters.items(): cls.process_command((parameter, value), ctrl_connection, is_tx) return True @@ -118,7 +124,9 @@ def shutdown_device(cls, ctrl_connection, is_tx: bool): raise NotImplementedError("Overwrite this method in subclass!") @classmethod - def enter_async_receive_mode(cls, data_connection: Connection, ctrl_connection: Connection) -> int: + def enter_async_receive_mode( + cls, data_connection: Connection, ctrl_connection: Connection + ) -> int: raise NotImplementedError("Overwrite this method in subclass!") @classmethod @@ -142,13 +150,20 @@ def send_sync(cls, data): raise NotImplementedError("Overwrite this method in subclass!") @classmethod - def device_receive(cls, data_connection: Connection, ctrl_connection: Connection, dev_parameters: OrderedDict): + def device_receive( + cls, + data_connection: Connection, + ctrl_connection: Connection, + dev_parameters: OrderedDict, + ): if not cls.init_device(ctrl_connection, is_tx=False, parameters=dev_parameters): ctrl_connection.send("failed to start rx mode") return False try: - cls.adapt_num_read_samples_to_sample_rate(dev_parameters[cls.Command.SET_SAMPLE_RATE.name]) + cls.adapt_num_read_samples_to_sample_rate( + dev_parameters[cls.Command.SET_SAMPLE_RATE.name] + ) except NotImplementedError: # Many SDRs like HackRF or AirSpy do not need to calculate SYNC_RX_CHUNK_SIZE # as default values are either fine or given by the hardware @@ -175,7 +190,9 @@ def device_receive(cls, data_connection: Connection, ctrl_connection: Connection else: cls.receive_sync(data_connection) while ctrl_connection.poll(): - result = cls.process_command(ctrl_connection.recv(), ctrl_connection, is_tx=False) + result = cls.process_command( + ctrl_connection.recv(), ctrl_connection, is_tx=False + ) if result == cls.Command.STOP.name: exit_requested = True break @@ -185,7 +202,12 @@ def device_receive(cls, data_connection: Connection, ctrl_connection: Connection ctrl_connection.close() @classmethod - def device_send(cls, ctrl_connection: Connection, send_config: SendConfig, dev_parameters: OrderedDict): + def device_send( + cls, + ctrl_connection: Connection, + send_config: SendConfig, + dev_parameters: OrderedDict, + ): if not cls.init_device(ctrl_connection, is_tx=True, parameters=dev_parameters): ctrl_connection.send("failed to start tx mode") return False @@ -200,7 +222,11 @@ def device_send(cls, ctrl_connection: Connection, send_config: SendConfig, dev_p return False exit_requested = False - buffer_size = cls.CONTINUOUS_TX_CHUNK_SIZE if send_config.continuous else cls.SYNC_TX_CHUNK_SIZE + buffer_size = ( + cls.CONTINUOUS_TX_CHUNK_SIZE + if send_config.continuous + else cls.SYNC_TX_CHUNK_SIZE + ) if not cls.ASYNCHRONOUS and buffer_size == 0: logger.warning("Send buffer size is zero!") @@ -216,7 +242,9 @@ def device_send(cls, ctrl_connection: Connection, send_config: SendConfig, dev_p cls.send_sync(send_config.get_data_to_send(buffer_size)) while ctrl_connection.poll(): - result = cls.process_command(ctrl_connection.recv(), ctrl_connection, is_tx=True) + result = cls.process_command( + ctrl_connection.recv(), ctrl_connection, is_tx=True + ) if result == cls.Command.STOP.name: exit_requested = True break @@ -227,15 +255,25 @@ def device_send(cls, ctrl_connection: Connection, send_config: SendConfig, dev_p time.sleep(0.75) if exit_requested: - logger.debug("{}: exit requested. Stopping sending".format(cls.__class__.__name__)) + logger.debug( + "{}: exit requested. Stopping sending".format(cls.__class__.__name__) + ) if send_config.sending_is_finished(): logger.debug("{}: sending is finished.".format(cls.__class__.__name__)) cls.shutdown_device(ctrl_connection, is_tx=True) ctrl_connection.close() - def __init__(self, center_freq, sample_rate, bandwidth, gain, if_gain=1, baseband_gain=1, - resume_on_full_receive_buffer=False): + def __init__( + self, + center_freq, + sample_rate, + bandwidth, + gain, + if_gain=1, + baseband_gain=1, + resume_on_full_receive_buffer=False, + ): super().__init__() self.error_not_open = -4242 @@ -278,9 +316,13 @@ def __init__(self, center_freq, sample_rate, bandwidth, gain, if_gain=1, baseban self.device_number = 0 self.samples_to_send = np.array([], dtype=self.DATA_TYPE) - self.sending_repeats = 1 # How often shall the sending sequence be repeated? 0 = forever + self.sending_repeats = ( + 1 # How often shall the sending sequence be repeated? 0 = forever + ) - self.resume_on_full_receive_buffer = resume_on_full_receive_buffer # for Spectrum Analyzer or Protocol Sniffing + self.resume_on_full_receive_buffer = ( + resume_on_full_receive_buffer # for Spectrum Analyzer or Protocol Sniffing + ) self.current_recv_index = 0 self.is_receiving = False self.is_transmitting = False @@ -295,7 +337,9 @@ def __init__(self, center_freq, sample_rate, bandwidth, gain, if_gain=1, baseban self.apply_dc_correction = False def _start_read_rcv_buffer_thread(self): - self.read_recv_buffer_thread = threading.Thread(target=self.read_receiving_queue) + self.read_recv_buffer_thread = threading.Thread( + target=self.read_receiving_queue + ) self.read_recv_buffer_thread.daemon = True self.read_recv_buffer_thread.start() @@ -326,13 +370,17 @@ def current_sending_repeat(self, value: int): @property def device_parameters(self) -> OrderedDict: - return OrderedDict([(self.Command.SET_FREQUENCY.name, self.frequency), - (self.Command.SET_SAMPLE_RATE.name, self.sample_rate), - (self.Command.SET_BANDWIDTH.name, self.bandwidth), - (self.Command.SET_RF_GAIN.name, self.gain), - (self.Command.SET_IF_GAIN.name, self.if_gain), - (self.Command.SET_BB_GAIN.name, self.baseband_gain), - ("identifier", self.device_serial)]) + return OrderedDict( + [ + (self.Command.SET_FREQUENCY.name, self.frequency), + (self.Command.SET_SAMPLE_RATE.name, self.sample_rate), + (self.Command.SET_BANDWIDTH.name, self.bandwidth), + (self.Command.SET_RF_GAIN.name, self.gain), + (self.Command.SET_IF_GAIN.name, self.if_gain), + (self.Command.SET_BB_GAIN.name, self.baseband_gain), + ("identifier", self.device_serial), + ] + ) @property def send_config(self) -> SendConfig: @@ -340,10 +388,16 @@ def send_config(self) -> SendConfig: total_samples = len(self.send_buffer) else: total_samples = 2 * self.num_samples_to_send - return SendConfig(self.send_buffer, self._current_sent_sample, self._current_sending_repeat, - total_samples, self.sending_repeats, continuous=self.sending_is_continuous, - iq_to_bytes_method=self.iq_to_bytes, - continuous_send_ring_buffer=self.continuous_send_ring_buffer) + return SendConfig( + self.send_buffer, + self._current_sent_sample, + self._current_sending_repeat, + total_samples, + self.sending_repeats, + continuous=self.sending_is_continuous, + iq_to_bytes_method=self.iq_to_bytes, + continuous_send_ring_buffer=self.continuous_send_ring_buffer, + ) @property def receive_process_arguments(self): @@ -355,37 +409,51 @@ def send_process_arguments(self): def init_recv_buffer(self): if self.receive_buffer is None: - num_samples = settings.get_receive_buffer_size(self.resume_on_full_receive_buffer, - self.is_in_spectrum_mode) - self.receive_buffer = IQArray(None, dtype=self.DATA_TYPE, n=int(num_samples)) + num_samples = settings.get_receive_buffer_size( + self.resume_on_full_receive_buffer, self.is_in_spectrum_mode + ) + self.receive_buffer = IQArray( + None, dtype=self.DATA_TYPE, n=int(num_samples) + ) def log_retcode(self, retcode: int, action: str, msg=""): msg = str(msg) - error_code_msg = self.error_codes[retcode] if retcode in self.error_codes else "Error Code: " + str(retcode) + error_code_msg = ( + self.error_codes[retcode] + if retcode in self.error_codes + else "Error Code: " + str(retcode) + ) if retcode == self.success: if msg: - formatted_message = "{0}-{1} ({2}): Success".format(type(self).__name__, action, msg) + formatted_message = "{0}-{1} ({2}): Success".format( + type(self).__name__, action, msg + ) else: - formatted_message = "{0}-{1}: Success".format(type(self).__name__, action) + formatted_message = "{0}-{1}: Success".format( + type(self).__name__, action + ) logger.info(formatted_message) else: if msg: - formatted_message = "{0}-{1} ({4}): {2} ({3})".format(type(self).__name__, action, error_code_msg, - retcode, msg) + formatted_message = "{0}-{1} ({4}): {2} ({3})".format( + type(self).__name__, action, error_code_msg, retcode, msg + ) else: - formatted_message = "{0}-{1}: {2} ({3})".format(type(self).__name__, action, error_code_msg, retcode) + formatted_message = "{0}-{1}: {2} ({3})".format( + type(self).__name__, action, error_code_msg, retcode + ) logger.error(formatted_message) self.device_messages.append(formatted_message) @property def received_data(self): - return self.receive_buffer[:self.current_recv_index] + return self.receive_buffer[: self.current_recv_index] @property def sent_data(self): - return self.samples_to_send[:self.current_sent_sample] + return self.samples_to_send[: self.current_sent_sample] @property def sending_finished(self): @@ -489,7 +557,9 @@ def sample_rate(self, value): def set_device_sample_rate(self, sample_rate): try: - self.parent_ctrl_conn.send((self.Command.SET_SAMPLE_RATE.name, int(sample_rate))) + self.parent_ctrl_conn.send( + (self.Command.SET_SAMPLE_RATE.name, int(sample_rate)) + ) except (BrokenPipeError, OSError): pass @@ -505,7 +575,9 @@ def channel_index(self, value: int): def set_device_channel_index(self, value): try: - self.parent_ctrl_conn.send((self.Command.SET_CHANNEL_INDEX.name, int(value))) + self.parent_ctrl_conn.send( + (self.Command.SET_CHANNEL_INDEX.name, int(value)) + ) except (BrokenPipeError, OSError): pass @@ -521,7 +593,9 @@ def antenna_index(self, value): def set_device_antenna_index(self, value): try: - self.parent_ctrl_conn.send((self.Command.SET_ANTENNA_INDEX.name, int(value))) + self.parent_ctrl_conn.send( + (self.Command.SET_ANTENNA_INDEX.name, int(value)) + ) except (BrokenPipeError, OSError): pass @@ -538,7 +612,9 @@ def bias_tee_enabled(self, value: bool): def set_device_bias_tee_enabled(self, value): try: - self.parent_ctrl_conn.send((self.Command.SET_BIAS_TEE_ENABLED.name, int(value))) + self.parent_ctrl_conn.send( + (self.Command.SET_BIAS_TEE_ENABLED.name, int(value)) + ) except (BrokenPipeError, OSError): pass @@ -554,7 +630,9 @@ def freq_correction(self, value): def set_device_freq_correction(self, value): try: - self.parent_ctrl_conn.send((self.Command.SET_FREQUENCY_CORRECTION.name, int(value))) + self.parent_ctrl_conn.send( + (self.Command.SET_FREQUENCY_CORRECTION.name, int(value)) + ) except (BrokenPipeError, OSError): pass @@ -570,7 +648,9 @@ def direct_sampling_mode(self, value): def set_device_direct_sampling_mode(self, value): try: - self.parent_ctrl_conn.send((self.Command.SET_DIRECT_SAMPLING_MODE.name, int(value))) + self.parent_ctrl_conn.send( + (self.Command.SET_DIRECT_SAMPLING_MODE.name, int(value)) + ) except (BrokenPipeError, OSError): pass @@ -581,8 +661,9 @@ def start_rx_mode(self): self.is_receiving = True logger.info("{0}: Starting RX Mode".format(self.__class__.__name__)) - self.receive_process = Process(target=self.receive_process_function, - args=self.receive_process_arguments) + self.receive_process = Process( + target=self.receive_process_function, args=self.receive_process_arguments + ) self.receive_process.daemon = True self._start_read_rcv_buffer_thread() self._start_read_message_thread() @@ -603,26 +684,38 @@ def stop_rx_mode(self, msg): if hasattr(self, "receive_process") and self.receive_process.is_alive(): self.receive_process.join(self.JOIN_TIMEOUT) if self.receive_process.is_alive(): - logger.warning("{0}: Receive process is still alive, terminating it".format(self.__class__.__name__)) + logger.warning( + "{0}: Receive process is still alive, terminating it".format( + self.__class__.__name__ + ) + ) self.receive_process.terminate() self.receive_process.join() self.is_receiving = False - for connection in (self.parent_ctrl_conn, self.parent_data_conn, self.child_ctrl_conn, self.child_data_conn): + for connection in ( + self.parent_ctrl_conn, + self.parent_data_conn, + self.child_ctrl_conn, + self.child_data_conn, + ): try: connection.close() except OSError as e: logger.exception(e) - def start_tx_mode(self, samples_to_send: np.ndarray = None, repeats=None, resume=False): + def start_tx_mode( + self, samples_to_send: np.ndarray = None, repeats=None, resume=False + ): self.is_transmitting = True self.parent_ctrl_conn, self.child_ctrl_conn = Pipe() self.init_send_parameters(samples_to_send, repeats, resume=resume) logger.info("{0}: Starting TX Mode".format(self.__class__.__name__)) - self.transmit_process = Process(target=self.send_process_function, - args=self.send_process_arguments) + self.transmit_process = Process( + target=self.send_process_function, args=self.send_process_arguments + ) self.transmit_process.daemon = True self._start_read_message_thread() @@ -639,7 +732,11 @@ def stop_tx_mode(self, msg): if hasattr(self, "transmit_process") and self.transmit_process.is_alive(): self.transmit_process.join(self.JOIN_TIMEOUT) if self.transmit_process.is_alive(): - logger.warning("{0}: Transmit process is still alive, terminating it".format(self.__class__.__name__)) + logger.warning( + "{0}: Transmit process is still alive, terminating it".format( + self.__class__.__name__ + ) + ) self.transmit_process.terminate() self.transmit_process.join() @@ -672,7 +769,9 @@ def read_device_messages(self): return_code = splitted[-1] self.log_retcode(int(return_code), action) except ValueError: - self.device_messages.append("{0}: {1}".format(self.__class__.__name__, message)) + self.device_messages.append( + "{0}: {1}".format(self.__class__.__name__, message) + ) except (EOFError, UnpicklingError, OSError, ConnectionResetError) as e: logger.info("Exiting read device message thread due to " + str(e)) break @@ -706,16 +805,23 @@ def read_receiving_queue(self): n_samples = len(self.receive_buffer) - 1 else: self.stop_rx_mode( - "Receiving buffer is full {0}/{1}".format(self.current_recv_index + n_samples, - len(self.receive_buffer))) + "Receiving buffer is full {0}/{1}".format( + self.current_recv_index + n_samples, + len(self.receive_buffer), + ) + ) return - self.receive_buffer[self.current_recv_index:self.current_recv_index + n_samples] = samples[:n_samples] + self.receive_buffer[ + self.current_recv_index : self.current_recv_index + n_samples + ] = samples[:n_samples] self.current_recv_index += n_samples logger.debug("Exiting read_receive_queue thread.") - def init_send_parameters(self, samples_to_send: IQArray = None, repeats: int = None, resume=False): + def init_send_parameters( + self, samples_to_send: IQArray = None, repeats: int = None, resume=False + ): if samples_to_send is not None: if isinstance(samples_to_send, IQArray): samples_to_send = samples_to_send.convert_to(self.DATA_TYPE) diff --git a/src/urh/dev/native/ExtensionHelper.py b/src/urh/dev/native/ExtensionHelper.py index 776453bcd1..ab32273b5f 100644 --- a/src/urh/dev/native/ExtensionHelper.py +++ b/src/urh/dev/native/ExtensionHelper.py @@ -11,19 +11,21 @@ USE_RELATIVE_PATHS = False -COMPILER_DIRECTIVES = {'language_level': 3, - 'cdivision': True, - 'wraparound': False, - 'boundscheck': False, - 'initializedcheck': False, - } +COMPILER_DIRECTIVES = { + "language_level": 3, + "cdivision": True, + "wraparound": False, + "boundscheck": False, + "initializedcheck": False, +} DEVICES = { "airspy": {"lib": "airspy", "test_function": "open"}, - "bladerf": {"lib": "bladeRF", "test_function": "bladerf_open", - "api_header_include": "libbladeRF.h", - "api_version_check_code": - """ + "bladerf": { + "lib": "bladeRF", + "test_function": "bladerf_open", + "api_header_include": "libbladeRF.h", + "api_version_check_code": """ #include #include @@ -31,40 +33,55 @@ struct bladerf_version result; bladerf_version(&result); printf("%f", result.major + result.minor/10.0 + result.patch/100.0); return 0;} - """}, - "hackrf": {"lib": "hackrf", "test_function": "hackrf_init", - "extras": {"HACKRF_MULTI_DEVICE_SUPPORT": "hackrf_open_by_serial"}}, + """, + }, + "hackrf": { + "lib": "hackrf", + "test_function": "hackrf_init", + "extras": {"HACKRF_MULTI_DEVICE_SUPPORT": "hackrf_open_by_serial"}, + }, "limesdr": {"lib": "LimeSuite", "test_function": "LMS_GetDeviceList"}, "plutosdr": {"lib": "iio", "test_function": "iio_create_default_context"}, - "rtlsdr": {"lib": "rtlsdr", "test_function": "rtlsdr_get_device_name", - "extras": {"RTLSDR_BANDWIDTH_SUPPORT": "rtlsdr_set_tuner_bandwidth"}}, + "rtlsdr": { + "lib": "rtlsdr", + "test_function": "rtlsdr_get_device_name", + "extras": {"RTLSDR_BANDWIDTH_SUPPORT": "rtlsdr_set_tuner_bandwidth"}, + }, # Use C only for USRP to avoid boost dependency "usrp": {"lib": "uhd", "test_function": "uhd_usrp_find", "language": "c"}, - "sdrplay": {"lib": "mir_sdr_api" if sys.platform == "win32" else "mirsdrapi-rsp", - "test_function": "mir_sdr_ApiVersion"} + "sdrplay": { + "lib": "mir_sdr_api" if sys.platform == "win32" else "mirsdrapi-rsp", + "test_function": "mir_sdr_ApiVersion", + }, } -def compiler_has_function(compiler, function_name, libraries, library_dirs, include_dirs) -> bool: - tmp_dir = tempfile.mkdtemp(prefix='urh-') +def compiler_has_function( + compiler, function_name, libraries, library_dirs, include_dirs +) -> bool: + tmp_dir = tempfile.mkdtemp(prefix="urh-") devnull = old_stderr = None try: try: - file_name = os.path.join(tmp_dir, '{}.c'.format(function_name)) - with open(file_name, 'w') as f: + file_name = os.path.join(tmp_dir, "{}.c".format(function_name)) + with open(file_name, "w") as f: # declare function in order to prevent Clang 12 error (https://github.com/jopohl/urh/issues/811) - f.write('void %s();\n' % function_name) - f.write('int main(void) {\n') - f.write(' %s();\n' % function_name) - f.write('}\n') + f.write("void %s();\n" % function_name) + f.write("int main(void) {\n") + f.write(" %s();\n" % function_name) + f.write("}\n") # Redirect stderr to /dev/null to hide any error messages from the compiler. - devnull = open(os.devnull, 'w') + devnull = open(os.devnull, "w") old_stderr = os.dup(sys.stderr.fileno()) os.dup2(devnull.fileno(), sys.stderr.fileno()) objects = compiler.compile([file_name], include_dirs=include_dirs) - compiler.link_executable(objects, os.path.join(tmp_dir, "a.out"), library_dirs=library_dirs, - libraries=libraries) + compiler.link_executable( + objects, + os.path.join(tmp_dir, "a.out"), + library_dirs=library_dirs, + libraries=libraries, + ) except Exception as e: return False return True @@ -76,20 +93,29 @@ def compiler_has_function(compiler, function_name, libraries, library_dirs, incl shutil.rmtree(tmp_dir) -def check_api_version(compiler, api_version_code, libraries, library_dirs, include_dirs) -> float: - tmp_dir = tempfile.mkdtemp(prefix='urh-') +def check_api_version( + compiler, api_version_code, libraries, library_dirs, include_dirs +) -> float: + tmp_dir = tempfile.mkdtemp(prefix="urh-") try: try: - file_name = os.path.join(tmp_dir, 'get_api_version.c') - with open(file_name, 'w') as f: + file_name = os.path.join(tmp_dir, "get_api_version.c") + with open(file_name, "w") as f: f.write(api_version_code) objects = compiler.compile([file_name], include_dirs=include_dirs) check_api_program = os.path.join(tmp_dir, "check_api") - compiler.link_executable(objects, check_api_program, library_dirs=library_dirs, libraries=libraries) + compiler.link_executable( + objects, + check_api_program, + library_dirs=library_dirs, + libraries=libraries, + ) env = os.environ.copy() - env["PATH"] = os.pathsep.join(library_dirs) + os.pathsep + os.environ.get("PATH", "") + env["PATH"] = ( + os.pathsep.join(library_dirs) + os.pathsep + os.environ.get("PATH", "") + ) result = float(check_output(check_api_program, env=env)) print(" Automatic API version check succeeded.") @@ -111,7 +137,9 @@ def get_device_extensions_and_extras(library_dirs=None, include_dirs=None): if os.path.isdir(os.path.join(cur_dir, "lib/shared")): # Device libs are packaged, so we are in release mode - include_dirs.insert(0, os.path.realpath(os.path.join(cur_dir, "lib/shared/include"))) + include_dirs.insert( + 0, os.path.realpath(os.path.join(cur_dir, "lib/shared/include")) + ) library_dirs.insert(0, os.path.realpath(os.path.join(cur_dir, "lib/shared"))) if sys.platform == "darwin": @@ -150,13 +178,27 @@ def get_device_extensions_and_extras(library_dirs=None, include_dirs=None): if build_device_extensions[dev_name] == 1: print("Enforcing native {0} support".format(dev_name)) - elif compiler_has_function(compiler, params["test_function"], (params["lib"],), library_dirs, include_dirs): - print("Found {0} lib. Will compile with native {1} support".format(params["lib"], dev_name)) + elif compiler_has_function( + compiler, + params["test_function"], + (params["lib"],), + library_dirs, + include_dirs, + ): + print( + "Found {0} lib. Will compile with native {1} support".format( + params["lib"], dev_name + ) + ) else: print("Skipping native support for {0}".format(dev_name)) continue - device_extras.update(get_device_extras(compiler, dev_name, [params["lib"]], library_dirs, include_dirs)) + device_extras.update( + get_device_extras( + compiler, dev_name, [params["lib"]], library_dirs, include_dirs + ) + ) if "api_version_check_code" in params: env_name = dev_name.upper() + "_API_VERSION" ver = os.getenv(env_name) @@ -164,19 +206,34 @@ def get_device_extensions_and_extras(library_dirs=None, include_dirs=None): try: ver = float(ver) except Exception as e: - print(" Could not convert content of {} to float: {}".format(env_name, e)) + print( + " Could not convert content of {} to float: {}".format( + env_name, e + ) + ) print(" Will now try to automatically detect API version.") ver = None else: - print(" Environment variable {} is unset, try to automatically detect API version".format(env_name)) + print( + " Environment variable {} is unset, try to automatically detect API version".format( + env_name + ) + ) if ver is None: - ver = check_api_version(compiler, params["api_version_check_code"], (params["lib"],), - library_dirs, include_dirs) + ver = check_api_version( + compiler, + params["api_version_check_code"], + (params["lib"],), + library_dirs, + include_dirs, + ) device_extras[env_name] = ver print(" Using {}={}".format(env_name, ver)) - extension = get_device_extension(dev_name, [params["lib"]], library_dirs, include_dirs) + extension = get_device_extension( + dev_name, [params["lib"]], library_dirs, include_dirs + ) result.append(extension) return result, device_extras @@ -191,7 +248,9 @@ def get_device_extras(compiler, dev_name, libraries, library_dirs, include_dirs) result = dict() for extra, func_name in extras.items(): - if compiler_has_function(compiler, func_name, libraries, library_dirs, include_dirs): + if compiler_has_function( + compiler, func_name, libraries, library_dirs, include_dirs + ): result[extra] = 1 else: print("Skipping {} as installed driver does not support it".format(extra)) @@ -200,7 +259,9 @@ def get_device_extras(compiler, dev_name, libraries, library_dirs, include_dirs) return result -def get_device_extension(dev_name: str, libraries: list, library_dirs: list, include_dirs: list): +def get_device_extension( + dev_name: str, libraries: list, library_dirs: list, include_dirs: list +): try: language = DEVICES[dev_name]["language"] except KeyError: @@ -213,10 +274,14 @@ def get_device_extension(dev_name: str, libraries: list, library_dirs: list, inc else: cpp_file_path = os.path.join(cur_dir, "lib", "{0}.pyx".format(dev_name)) - return Extension("urh.dev.native.lib." + dev_name, - [cpp_file_path], - libraries=libraries, library_dirs=library_dirs, - include_dirs=include_dirs, language=language) + return Extension( + "urh.dev.native.lib." + dev_name, + [cpp_file_path], + libraries=libraries, + library_dirs=library_dirs, + include_dirs=include_dirs, + language=language, + ) def perform_health_check() -> str: @@ -254,16 +319,22 @@ def perform_health_check() -> str: try: from Cython.Build import cythonize except ImportError: - print("You need Cython to rebuild URH's device extensions. " - "You can get it e.g. with python3 -m pip install cython.", - file=sys.stderr) + print( + "You need Cython to rebuild URH's device extensions. " + "You can get it e.g. with python3 -m pip install cython.", + file=sys.stderr, + ) sys.exit(1) - dev_extensions, dev_extras = get_device_extensions_and_extras(library_dirs=library_directories, - include_dirs=include_directories) + dev_extensions, dev_extras = get_device_extensions_and_extras( + library_dirs=library_directories, include_dirs=include_directories + ) setup( name="urh", - ext_modules=cythonize(dev_extensions, force=True, - compile_time_env=dev_extras, compiler_directives=COMPILER_DIRECTIVES, - ) + ext_modules=cythonize( + dev_extensions, + force=True, + compile_time_env=dev_extras, + compiler_directives=COMPILER_DIRECTIVES, + ), ) diff --git a/src/urh/dev/native/HackRF.py b/src/urh/dev/native/HackRF.py index bbeecc3dcd..c056db2fa9 100644 --- a/src/urh/dev/native/HackRF.py +++ b/src/urh/dev/native/HackRF.py @@ -12,11 +12,13 @@ class HackRF(Device): DEVICE_LIB = hackrf ASYNCHRONOUS = True DEVICE_METHODS = Device.DEVICE_METHODS.copy() - DEVICE_METHODS.update({ - Device.Command.SET_FREQUENCY.name: "set_freq", - Device.Command.SET_BANDWIDTH.name: "set_baseband_filter_bandwidth", - Device.Command.SET_BIAS_TEE_ENABLED.name: "set_bias_tee" - }) + DEVICE_METHODS.update( + { + Device.Command.SET_FREQUENCY.name: "set_freq", + Device.Command.SET_BANDWIDTH.name: "set_baseband_filter_bandwidth", + Device.Command.SET_BIAS_TEE_ENABLED.name: "set_bias_tee", + } + ) DATA_TYPE = np.int8 @@ -56,7 +58,9 @@ def shutdown_device(cls, ctrl_conn: Connection, is_tx: bool): return True @classmethod - def enter_async_receive_mode(cls, data_connection: Connection, ctrl_connection: Connection): + def enter_async_receive_mode( + cls, data_connection: Connection, ctrl_connection: Connection + ): ret = hackrf.start_rx_mode(data_connection.send_bytes) ctrl_connection.send("Start RX MODE:" + str(ret)) return ret @@ -65,11 +69,25 @@ def enter_async_receive_mode(cls, data_connection: Connection, ctrl_connection: def enter_async_send_mode(cls, callback): return hackrf.start_tx_mode(callback) - def __init__(self, center_freq, sample_rate, bandwidth, gain, if_gain=1, baseband_gain=1, - resume_on_full_receive_buffer=False): - super().__init__(center_freq=center_freq, sample_rate=sample_rate, bandwidth=bandwidth, - gain=gain, if_gain=if_gain, baseband_gain=baseband_gain, - resume_on_full_receive_buffer=resume_on_full_receive_buffer) + def __init__( + self, + center_freq, + sample_rate, + bandwidth, + gain, + if_gain=1, + baseband_gain=1, + resume_on_full_receive_buffer=False, + ): + super().__init__( + center_freq=center_freq, + sample_rate=sample_rate, + bandwidth=bandwidth, + gain=gain, + if_gain=if_gain, + baseband_gain=baseband_gain, + resume_on_full_receive_buffer=resume_on_full_receive_buffer, + ) self.success = 0 self.error_codes = { @@ -86,19 +104,23 @@ def __init__(self, center_freq, sample_rate, bandwidth, gain, if_gain=1, baseban -1003: "HACKRF_ERROR_STREAMING_STOPPED", -1004: "HACKRF_ERROR_STREAMING_EXIT_CALLED", -4242: "HACKRF NOT OPEN", - -9999: "HACKRF_ERROR_OTHER" + -9999: "HACKRF_ERROR_OTHER", } @property def device_parameters(self) -> OrderedDict: - return OrderedDict([(self.Command.SET_FREQUENCY.name, self.frequency), - (self.Command.SET_SAMPLE_RATE.name, self.sample_rate), - (self.Command.SET_BANDWIDTH.name, self.bandwidth), - (self.Command.SET_RF_GAIN.name, self.gain), - (self.Command.SET_IF_GAIN.name, self.if_gain), - (self.Command.SET_BB_GAIN.name, self.baseband_gain), - (self.Command.SET_BIAS_TEE_ENABLED.name, self.bias_tee_enabled), - ("identifier", self.device_serial)]) + return OrderedDict( + [ + (self.Command.SET_FREQUENCY.name, self.frequency), + (self.Command.SET_SAMPLE_RATE.name, self.sample_rate), + (self.Command.SET_BANDWIDTH.name, self.bandwidth), + (self.Command.SET_RF_GAIN.name, self.gain), + (self.Command.SET_IF_GAIN.name, self.if_gain), + (self.Command.SET_BB_GAIN.name, self.baseband_gain), + (self.Command.SET_BIAS_TEE_ENABLED.name, self.bias_tee_enabled), + ("identifier", self.device_serial), + ] + ) @property def has_multi_device_support(self): diff --git a/src/urh/dev/native/LimeSDR.py b/src/urh/dev/native/LimeSDR.py index 6da59f82a6..91aae85b41 100644 --- a/src/urh/dev/native/LimeSDR.py +++ b/src/urh/dev/native/LimeSDR.py @@ -22,13 +22,15 @@ class LimeSDR(Device): DEVICE_LIB = limesdr ASYNCHRONOUS = False DEVICE_METHODS = Device.DEVICE_METHODS.copy() - DEVICE_METHODS.update({ - Device.Command.SET_FREQUENCY.name: "set_center_frequency", - Device.Command.SET_BANDWIDTH.name: "set_lpf_bandwidth", - Device.Command.SET_RF_GAIN.name: "set_normalized_gain", - Device.Command.SET_CHANNEL_INDEX.name: "set_channel", - Device.Command.SET_ANTENNA_INDEX.name: "set_antenna" - }) + DEVICE_METHODS.update( + { + Device.Command.SET_FREQUENCY.name: "set_center_frequency", + Device.Command.SET_BANDWIDTH.name: "set_lpf_bandwidth", + Device.Command.SET_RF_GAIN.name: "set_normalized_gain", + Device.Command.SET_CHANNEL_INDEX.name: "set_channel", + Device.Command.SET_ANTENNA_INDEX.name: "set_antenna", + } + ) DATA_TYPE = np.float32 @@ -58,20 +60,34 @@ def setup_device(cls, ctrl_connection: Connection, device_identifier): return ret == 0 @classmethod - def init_device(cls, ctrl_connection: Connection, is_tx: bool, parameters: OrderedDict): - if not cls.setup_device(ctrl_connection, device_identifier=parameters["identifier"]): + def init_device( + cls, ctrl_connection: Connection, is_tx: bool, parameters: OrderedDict + ): + if not cls.setup_device( + ctrl_connection, device_identifier=parameters["identifier"] + ): return False - limesdr.enable_channel(True, is_tx, parameters[cls.Command.SET_CHANNEL_INDEX.name]) + limesdr.enable_channel( + True, is_tx, parameters[cls.Command.SET_CHANNEL_INDEX.name] + ) limesdr.set_tx(is_tx) for parameter, value in parameters.items(): cls.process_command((parameter, value), ctrl_connection, is_tx) antennas = limesdr.get_antenna_list() - ctrl_connection.send("Current normalized gain is {0:.2f}".format(limesdr.get_normalized_gain())) - ctrl_connection.send("Current antenna is {0}".format(antennas[limesdr.get_antenna()])) - ctrl_connection.send("Current chip temperature is {0:.2f}°C".format(limesdr.get_chip_temperature())) + ctrl_connection.send( + "Current normalized gain is {0:.2f}".format(limesdr.get_normalized_gain()) + ) + ctrl_connection.send( + "Current antenna is {0}".format(antennas[limesdr.get_antenna()]) + ) + ctrl_connection.send( + "Current chip temperature is {0:.2f}°C".format( + limesdr.get_chip_temperature() + ) + ) return True @@ -94,7 +110,9 @@ def prepare_sync_receive(cls, ctrl_connection: Connection): @classmethod def receive_sync(cls, data_conn: Connection): - limesdr.recv_stream(data_conn, cls.SYNC_RX_CHUNK_SIZE, cls.LIME_TIMEOUT_RECEIVE_MS) + limesdr.recv_stream( + data_conn, cls.SYNC_RX_CHUNK_SIZE, cls.LIME_TIMEOUT_RECEIVE_MS + ) @classmethod def prepare_sync_send(cls, ctrl_connection: Connection): @@ -108,11 +126,25 @@ def prepare_sync_send(cls, ctrl_connection: Connection): def send_sync(cls, data): limesdr.send_stream(data, cls.LIME_TIMEOUT_SEND_MS) - def __init__(self, center_freq, sample_rate, bandwidth, gain, if_gain=1, baseband_gain=1, - resume_on_full_receive_buffer=False): - super().__init__(center_freq=center_freq, sample_rate=sample_rate, bandwidth=bandwidth, - gain=gain, if_gain=if_gain, baseband_gain=baseband_gain, - resume_on_full_receive_buffer=resume_on_full_receive_buffer) + def __init__( + self, + center_freq, + sample_rate, + bandwidth, + gain, + if_gain=1, + baseband_gain=1, + resume_on_full_receive_buffer=False, + ): + super().__init__( + center_freq=center_freq, + sample_rate=sample_rate, + bandwidth=bandwidth, + gain=gain, + if_gain=if_gain, + baseband_gain=baseband_gain, + resume_on_full_receive_buffer=resume_on_full_receive_buffer, + ) self.success = 0 def set_device_gain(self, gain): @@ -124,14 +156,18 @@ def has_multi_device_support(self): @property def device_parameters(self): - return OrderedDict([(self.Command.SET_CHANNEL_INDEX.name, self.channel_index), - # Set Antenna needs to be called before other stuff!!! - (self.Command.SET_ANTENNA_INDEX.name, self.antenna_index), - (self.Command.SET_FREQUENCY.name, self.frequency), - (self.Command.SET_SAMPLE_RATE.name, self.sample_rate), - (self.Command.SET_BANDWIDTH.name, self.bandwidth), - (self.Command.SET_RF_GAIN.name, self.gain * 0.01), - ("identifier", self.device_serial)]) + return OrderedDict( + [ + (self.Command.SET_CHANNEL_INDEX.name, self.channel_index), + # Set Antenna needs to be called before other stuff!!! + (self.Command.SET_ANTENNA_INDEX.name, self.antenna_index), + (self.Command.SET_FREQUENCY.name, self.frequency), + (self.Command.SET_SAMPLE_RATE.name, self.sample_rate), + (self.Command.SET_BANDWIDTH.name, self.bandwidth), + (self.Command.SET_RF_GAIN.name, self.gain * 0.01), + ("identifier", self.device_serial), + ] + ) @staticmethod def bytes_to_iq(buffer): diff --git a/src/urh/dev/native/PlutoSDR.py b/src/urh/dev/native/PlutoSDR.py index 96ebe2b438..063c457749 100644 --- a/src/urh/dev/native/PlutoSDR.py +++ b/src/urh/dev/native/PlutoSDR.py @@ -29,9 +29,13 @@ def adapt_num_read_samples_to_sample_rate(cls, sample_rate): @classmethod def setup_device(cls, ctrl_connection: Connection, device_identifier): - device_identifier = device_identifier if isinstance(device_identifier, str) else "" + device_identifier = ( + device_identifier if isinstance(device_identifier, str) else "" + ) try: - device_identifier = re.search(r"(?<=\[).+?(?=\])", device_identifier).group(0) + device_identifier = re.search(r"(?<=\[).+?(?=\])", device_identifier).group( + 0 + ) except (IndexError, AttributeError): pass @@ -48,7 +52,9 @@ def setup_device(cls, ctrl_connection: Connection, device_identifier): return ret == 0 @classmethod - def init_device(cls, ctrl_connection: Connection, is_tx: bool, parameters: OrderedDict) -> bool: + def init_device( + cls, ctrl_connection: Connection, is_tx: bool, parameters: OrderedDict + ) -> bool: plutosdr.set_tx(is_tx) return super().init_device(ctrl_connection, is_tx, parameters) @@ -78,11 +84,25 @@ def prepare_sync_send(cls, ctrl_connection: Connection): def send_sync(cls, data): plutosdr.send_sync(data) - def __init__(self, center_freq, sample_rate, bandwidth, gain, if_gain=1, baseband_gain=1, - resume_on_full_receive_buffer=False): - super().__init__(center_freq=center_freq, sample_rate=sample_rate, bandwidth=bandwidth, - gain=gain, if_gain=if_gain, baseband_gain=baseband_gain, - resume_on_full_receive_buffer=resume_on_full_receive_buffer) + def __init__( + self, + center_freq, + sample_rate, + bandwidth, + gain, + if_gain=1, + baseband_gain=1, + resume_on_full_receive_buffer=False, + ): + super().__init__( + center_freq=center_freq, + sample_rate=sample_rate, + bandwidth=bandwidth, + gain=gain, + if_gain=if_gain, + baseband_gain=baseband_gain, + resume_on_full_receive_buffer=resume_on_full_receive_buffer, + ) self.success = 0 @property @@ -91,11 +111,15 @@ def has_multi_device_support(self): @property def device_parameters(self): - return OrderedDict([(self.Command.SET_FREQUENCY.name, self.frequency), - (self.Command.SET_SAMPLE_RATE.name, self.sample_rate), - (self.Command.SET_BANDWIDTH.name, self.bandwidth), - (self.Command.SET_RF_GAIN.name, self.gain), - ("identifier", self.device_serial)]) + return OrderedDict( + [ + (self.Command.SET_FREQUENCY.name, self.frequency), + (self.Command.SET_SAMPLE_RATE.name, self.sample_rate), + (self.Command.SET_BANDWIDTH.name, self.bandwidth), + (self.Command.SET_RF_GAIN.name, self.gain), + ("identifier", self.device_serial), + ] + ) @staticmethod def bytes_to_iq(buffer) -> np.ndarray: diff --git a/src/urh/dev/native/RTLSDR.py b/src/urh/dev/native/RTLSDR.py index 9aa0a496d0..d0f924b3b7 100644 --- a/src/urh/dev/native/RTLSDR.py +++ b/src/urh/dev/native/RTLSDR.py @@ -13,14 +13,16 @@ class RTLSDR(Device): DEVICE_LIB = rtlsdr ASYNCHRONOUS = False DEVICE_METHODS = Device.DEVICE_METHODS.copy() - DEVICE_METHODS.update({ - Device.Command.SET_RF_GAIN.name: "set_tuner_gain", - Device.Command.SET_RF_GAIN.name+"_get_allowed_values": "get_tuner_gains", - Device.Command.SET_BANDWIDTH.name: "set_tuner_bandwidth", - Device.Command.SET_FREQUENCY_CORRECTION.name: "set_freq_correction", - Device.Command.SET_DIRECT_SAMPLING_MODE.name: "set_direct_sampling", - Device.Command.SET_BIAS_TEE_ENABLED.name: "set_bias_tee" - }) + DEVICE_METHODS.update( + { + Device.Command.SET_RF_GAIN.name: "set_tuner_gain", + Device.Command.SET_RF_GAIN.name + "_get_allowed_values": "get_tuner_gains", + Device.Command.SET_BANDWIDTH.name: "set_tuner_bandwidth", + Device.Command.SET_FREQUENCY_CORRECTION.name: "set_freq_correction", + Device.Command.SET_DIRECT_SAMPLING_MODE.name: "set_direct_sampling", + Device.Command.SET_BIAS_TEE_ENABLED.name: "set_bias_tee", + } + ) DATA_TYPE = np.int8 @@ -52,19 +54,27 @@ def shutdown_device(cls, ctrl_connection, is_tx: bool): ret = rtlsdr.close() ctrl_connection.send("CLOSE:" + str(ret)) - def __init__(self, freq, gain, srate, device_number, resume_on_full_receive_buffer=False): - super().__init__(center_freq=freq, sample_rate=srate, bandwidth=0, - gain=gain, if_gain=1, baseband_gain=1, - resume_on_full_receive_buffer=resume_on_full_receive_buffer) + def __init__( + self, freq, gain, srate, device_number, resume_on_full_receive_buffer=False + ): + super().__init__( + center_freq=freq, + sample_rate=srate, + bandwidth=0, + gain=gain, + if_gain=1, + baseband_gain=1, + resume_on_full_receive_buffer=resume_on_full_receive_buffer, + ) self.success = 0 - self.bandwidth_is_adjustable = self.get_bandwidth_is_adjustable() # e.g. not in Manjaro Linux / Ubuntu 14.04 + self.bandwidth_is_adjustable = ( + self.get_bandwidth_is_adjustable() + ) # e.g. not in Manjaro Linux / Ubuntu 14.04 self.device_number = device_number - self.error_codes = { - -100: "Method not available in installed driver." - } + self.error_codes = {-100: "Method not available in installed driver."} @staticmethod def get_bandwidth_is_adjustable(): @@ -72,14 +82,18 @@ def get_bandwidth_is_adjustable(): @property def device_parameters(self): - return OrderedDict([(self.Command.SET_FREQUENCY.name, self.frequency), - (self.Command.SET_SAMPLE_RATE.name, self.sample_rate), - (self.Command.SET_BANDWIDTH.name, self.bandwidth), - (self.Command.SET_FREQUENCY_CORRECTION.name, self.freq_correction), - (self.Command.SET_DIRECT_SAMPLING_MODE.name, self.direct_sampling_mode), - (self.Command.SET_RF_GAIN.name, self.gain), - (self.Command.SET_BIAS_TEE_ENABLED.name, self.bias_tee_enabled), - ("identifier", self.device_number)]) + return OrderedDict( + [ + (self.Command.SET_FREQUENCY.name, self.frequency), + (self.Command.SET_SAMPLE_RATE.name, self.sample_rate), + (self.Command.SET_BANDWIDTH.name, self.bandwidth), + (self.Command.SET_FREQUENCY_CORRECTION.name, self.freq_correction), + (self.Command.SET_DIRECT_SAMPLING_MODE.name, self.direct_sampling_mode), + (self.Command.SET_RF_GAIN.name, self.gain), + (self.Command.SET_BIAS_TEE_ENABLED.name, self.bias_tee_enabled), + ("identifier", self.device_number), + ] + ) @property def has_multi_device_support(self): @@ -89,8 +103,12 @@ def set_device_bandwidth(self, bandwidth): if self.bandwidth_is_adjustable: super().set_device_bandwidth(bandwidth) else: - logger.warning("Setting the bandwidth is not supported by your RTL-SDR driver version.") + logger.warning( + "Setting the bandwidth is not supported by your RTL-SDR driver version." + ) @staticmethod def bytes_to_iq(buffer): - return np.subtract(np.frombuffer(buffer, dtype=np.int8), 127).reshape((-1, 2), order="C") + return np.subtract(np.frombuffer(buffer, dtype=np.int8), 127).reshape( + (-1, 2), order="C" + ) diff --git a/src/urh/dev/native/RTLSDRTCP.py b/src/urh/dev/native/RTLSDRTCP.py index 5f88a9b4f7..a08a8bb4cf 100644 --- a/src/urh/dev/native/RTLSDRTCP.py +++ b/src/urh/dev/native/RTLSDRTCP.py @@ -10,16 +10,41 @@ class RTLSDRTCP(Device): MAXDATASIZE = 65536 ENDIAN = "big" - RTL_TCP_CONSTS = ["NULL", "centerFreq", "sampleRate", "tunerGainMode", "tunerGain", "freqCorrection", "tunerIFGain", - "testMode", "agcMode", "directSampling", "offsetTuning", "rtlXtalFreq", "tunerXtalFreq", - "gainByIndex", "bandwidth", "biasTee"] + RTL_TCP_CONSTS = [ + "NULL", + "centerFreq", + "sampleRate", + "tunerGainMode", + "tunerGain", + "freqCorrection", + "tunerIFGain", + "testMode", + "agcMode", + "directSampling", + "offsetTuning", + "rtlXtalFreq", + "tunerXtalFreq", + "gainByIndex", + "bandwidth", + "biasTee", + ] DATA_TYPE = np.uint8 @staticmethod - def receive_sync(data_connection, ctrl_connection, device_number: int, center_freq: int, sample_rate: int, - bandwidth: int, gain: int, freq_correction: int, direct_sampling_mode: int, device_ip: str, - port: int): + def receive_sync( + data_connection, + ctrl_connection, + device_number: int, + center_freq: int, + sample_rate: int, + bandwidth: int, + gain: int, + freq_correction: int, + direct_sampling_mode: int, + device_ip: str, + port: int, + ): # connect and initialize rtl_tcp sdr = RTLSDRTCP(center_freq, gain, sample_rate, bandwidth, device_number) sdr.open(ctrl_connection, device_ip, port) @@ -29,14 +54,18 @@ def receive_sync(data_connection, ctrl_connection, device_number: int, center_fr sdr.set_parameter("sampleRate", int(sample_rate), ctrl_connection) sdr.set_parameter("bandwidth", int(bandwidth), ctrl_connection) sdr.set_parameter("freqCorrection", int(freq_correction), ctrl_connection) - sdr.set_parameter("directSampling", int(direct_sampling_mode), ctrl_connection) + sdr.set_parameter( + "directSampling", int(direct_sampling_mode), ctrl_connection + ) # Gain has to be set last, otherwise it does not get considered by RTL-SDR sdr.set_parameter("tunerGain", int(gain), ctrl_connection) exit_requested = False while not exit_requested: while ctrl_connection.poll(): - result = sdr.process_command(ctrl_connection.recv(), ctrl_connection) + result = sdr.process_command( + ctrl_connection.recv(), ctrl_connection + ) if result == "stop": exit_requested = True break @@ -86,10 +115,24 @@ def process_command(self, command, ctrl_connection, is_tx=False): logger.info("RTLSDRTCP: Set direct sampling mode to {0}".format(int(value))) return self.set_parameter("directSampling", int(value), ctrl_connection) - def __init__(self, freq, gain, srate, bandwidth, device_number, resume_on_full_receive_buffer=False): - super().__init__(center_freq=freq, sample_rate=srate, bandwidth=bandwidth, - gain=gain, if_gain=1, baseband_gain=1, - resume_on_full_receive_buffer=resume_on_full_receive_buffer) + def __init__( + self, + freq, + gain, + srate, + bandwidth, + device_number, + resume_on_full_receive_buffer=False, + ): + super().__init__( + center_freq=freq, + sample_rate=srate, + bandwidth=bandwidth, + gain=gain, + if_gain=1, + baseband_gain=1, + resume_on_full_receive_buffer=resume_on_full_receive_buffer, + ) # default class parameters self.receive_process_function = self.receive_sync @@ -99,20 +142,41 @@ def __init__(self, freq, gain, srate, bandwidth, device_number, resume_on_full_r @property def receive_process_arguments(self): - return self.child_data_conn, self.child_ctrl_conn, self.device_number, self.frequency, self.sample_rate, \ - self.bandwidth, self.gain, self.freq_correction, self.direct_sampling_mode, self.device_ip, self.port + return ( + self.child_data_conn, + self.child_ctrl_conn, + self.device_number, + self.frequency, + self.sample_rate, + self.bandwidth, + self.gain, + self.freq_correction, + self.direct_sampling_mode, + self.device_ip, + self.port, + ) def open(self, ctrl_connection, hostname="127.0.0.1", port=1234): if not self.socket_is_open: try: # Create socket and connect - self.sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM, socket.IPPROTO_TCP) + self.sock = socket.socket( + socket.AF_INET, socket.SOCK_STREAM, socket.IPPROTO_TCP + ) # self.sock.settimeout(1.0) # Timeout 1s self.sock.connect((hostname, port)) except Exception as e: self.socket_is_open = False - logger.info("Could not connect to rtl_tcp at {0}:{1} ({2})".format(hostname, port, e)) - ctrl_connection.send("Could not connect to rtl_tcp at {0} [{1}] ({2}):1".format(hostname, port, e)) + logger.info( + "Could not connect to rtl_tcp at {0}:{1} ({2})".format( + hostname, port, e + ) + ) + ctrl_connection.send( + "Could not connect to rtl_tcp at {0} [{1}] ({2}):1".format( + hostname, port, e + ) + ) return False try: @@ -121,7 +185,7 @@ def open(self, ctrl_connection, hostname="127.0.0.1", port=1234): if len(init_data) != 12: return False - if init_data[0:4] != b'RTL0': + if init_data[0:4] != b"RTL0": return False # Extract tuner name @@ -146,18 +210,22 @@ def open(self, ctrl_connection, hostname="127.0.0.1", port=1234): self.rf_gain = int.from_bytes(init_data[10:12], self.ENDIAN) logger.info( - "Connected to rtl_tcp at {0}:{1} (Tuner: {2}, RF-Gain: {3}, IF-Gain: {4})".format(hostname, port, - self.tuner, - self.rf_gain, - self.if_gain)) + "Connected to rtl_tcp at {0}:{1} (Tuner: {2}, RF-Gain: {3}, IF-Gain: {4})".format( + hostname, port, self.tuner, self.rf_gain, self.if_gain + ) + ) ctrl_connection.send( - "Connected to rtl_tcp at {0}[{1}] (Tuner={2}, RF-Gain={3}, IF-Gain={4}):0".format(hostname, port, - self.tuner, - self.rf_gain, - self.if_gain)) + "Connected to rtl_tcp at {0}[{1}] (Tuner={2}, RF-Gain={3}, IF-Gain={4}):0".format( + hostname, port, self.tuner, self.rf_gain, self.if_gain + ) + ) except Exception as e: self.socket_is_open = False - logger.info("This is not a valid rtl_tcp server at {0}:{1} ({2})".format(hostname, port, e)) + logger.info( + "This is not a valid rtl_tcp server at {0}:{1} ({2})".format( + hostname, port, e + ) + ) return False self.socket_is_open = True @@ -167,26 +235,36 @@ def close(self): self.socket_is_open = False return self.sock.close() - def set_parameter(self, param: str, value: int, ctrl_connection): # returns error (True/False) + def set_parameter( + self, param: str, value: int, ctrl_connection + ): # returns error (True/False) if self.socket_is_open: - msg = self.RTL_TCP_CONSTS.index(param).to_bytes(1, self.ENDIAN) # Set param at bits 0-7 + msg = self.RTL_TCP_CONSTS.index(param).to_bytes( + 1, self.ENDIAN + ) # Set param at bits 0-7 msg += value.to_bytes(4, self.ENDIAN) # Set value at bits 8-39 try: self.sock.sendall(msg) # Send data to rtl_tcp except OSError as e: self.sock.close() - logger.info("Could not set parameter {0}:{1} ({2})".format(param, value, e)) - ctrl_connection.send("Could not set parameter {0} {1} ({2}):1".format(param, value, e)) + logger.info( + "Could not set parameter {0}:{1} ({2})".format(param, value, e) + ) + ctrl_connection.send( + "Could not set parameter {0} {1} ({2}):1".format(param, value, e) + ) return True return False def read_sync(self): - s_read, _, _ = select.select([self.sock], [], [], .1) + s_read, _, _ = select.select([self.sock], [], [], 0.1) if self.sock in s_read: return self.sock.recv(self.MAXDATASIZE) else: - return b'' + return b"" @staticmethod def bytes_to_iq(buffer): - return np.subtract(np.frombuffer(buffer, dtype=np.int8), 127).reshape((-1, 2), order="C") + return np.subtract(np.frombuffer(buffer, dtype=np.int8), 127).reshape( + (-1, 2), order="C" + ) diff --git a/src/urh/dev/native/Rad1o.py b/src/urh/dev/native/Rad1o.py index 7ed9d8f2e8..de2e20932c 100644 --- a/src/urh/dev/native/Rad1o.py +++ b/src/urh/dev/native/Rad1o.py @@ -12,10 +12,12 @@ class Rad1o(Device): DEVICE_LIB = hackrf ASYNCHRONOUS = True DEVICE_METHODS = Device.DEVICE_METHODS.copy() - DEVICE_METHODS.update({ - Device.Command.SET_FREQUENCY.name: "set_freq", - Device.Command.SET_BANDWIDTH.name: "set_baseband_filter_bandwidth" - }) + DEVICE_METHODS.update( + { + Device.Command.SET_FREQUENCY.name: "set_freq", + Device.Command.SET_BANDWIDTH.name: "set_baseband_filter_bandwidth", + } + ) DATA_TYPE = np.int8 @@ -55,7 +57,9 @@ def shutdown_device(cls, ctrl_conn: Connection, is_tx: bool): return True @classmethod - def enter_async_receive_mode(cls, data_connection: Connection, ctrl_connection: Connection): + def enter_async_receive_mode( + cls, data_connection: Connection, ctrl_connection: Connection + ): ret = hackrf.start_rx_mode(data_connection.send_bytes) ctrl_connection.send("Start RX MODE:" + str(ret)) return ret @@ -64,11 +68,25 @@ def enter_async_receive_mode(cls, data_connection: Connection, ctrl_connection: def enter_async_send_mode(cls, callback): return hackrf.start_tx_mode(callback) - def __init__(self, center_freq, sample_rate, bandwidth, gain, if_gain=1, baseband_gain=1, - resume_on_full_receive_buffer=False): - super().__init__(center_freq=center_freq, sample_rate=sample_rate, bandwidth=bandwidth, - gain=gain, if_gain=if_gain, baseband_gain=baseband_gain, - resume_on_full_receive_buffer=resume_on_full_receive_buffer) + def __init__( + self, + center_freq, + sample_rate, + bandwidth, + gain, + if_gain=1, + baseband_gain=1, + resume_on_full_receive_buffer=False, + ): + super().__init__( + center_freq=center_freq, + sample_rate=sample_rate, + bandwidth=bandwidth, + gain=gain, + if_gain=if_gain, + baseband_gain=baseband_gain, + resume_on_full_receive_buffer=resume_on_full_receive_buffer, + ) self.success = 0 self.error_codes = { @@ -85,18 +103,22 @@ def __init__(self, center_freq, sample_rate, bandwidth, gain, if_gain=1, baseban -1003: "Rad1o_ERROR_STREAMING_STOPPED", -1004: "Rad1o_ERROR_STREAMING_EXIT_CALLED", -4242: "Rad1o NOT OPEN", - -9999: "Rad1o_ERROR_OTHER" + -9999: "Rad1o_ERROR_OTHER", } @property def device_parameters(self) -> OrderedDict: - return OrderedDict([(self.Command.SET_FREQUENCY.name, self.frequency), - (self.Command.SET_SAMPLE_RATE.name, self.sample_rate), - (self.Command.SET_BANDWIDTH.name, self.bandwidth), - (self.Command.SET_RF_GAIN.name, self.gain), - (self.Command.SET_IF_GAIN.name, self.if_gain), - (self.Command.SET_BB_GAIN.name, self.baseband_gain), - ("identifier", self.device_serial)]) + return OrderedDict( + [ + (self.Command.SET_FREQUENCY.name, self.frequency), + (self.Command.SET_SAMPLE_RATE.name, self.sample_rate), + (self.Command.SET_BANDWIDTH.name, self.bandwidth), + (self.Command.SET_RF_GAIN.name, self.gain), + (self.Command.SET_IF_GAIN.name, self.if_gain), + (self.Command.SET_BB_GAIN.name, self.baseband_gain), + ("identifier", self.device_serial), + ] + ) @property def has_multi_device_support(self): diff --git a/src/urh/dev/native/SDRPlay.py b/src/urh/dev/native/SDRPlay.py index 20494a41df..3762a3edfd 100644 --- a/src/urh/dev/native/SDRPlay.py +++ b/src/urh/dev/native/SDRPlay.py @@ -18,11 +18,25 @@ class SDRPlay(Device): DATA_TYPE = np.int16 - def __init__(self, center_freq, sample_rate, bandwidth, gain, if_gain=1, baseband_gain=1, - resume_on_full_receive_buffer=False): - super().__init__(center_freq=center_freq, sample_rate=sample_rate, bandwidth=bandwidth, - gain=gain, if_gain=if_gain, baseband_gain=baseband_gain, - resume_on_full_receive_buffer=resume_on_full_receive_buffer) + def __init__( + self, + center_freq, + sample_rate, + bandwidth, + gain, + if_gain=1, + baseband_gain=1, + resume_on_full_receive_buffer=False, + ): + super().__init__( + center_freq=center_freq, + sample_rate=sample_rate, + bandwidth=bandwidth, + gain=gain, + if_gain=if_gain, + baseband_gain=baseband_gain, + resume_on_full_receive_buffer=resume_on_full_receive_buffer, + ) self.success = 0 self.error_codes = { 0: "SUCCESS", @@ -38,7 +52,7 @@ def __init__(self, center_freq, sample_rate, bandwidth, gain, if_gain=1, baseban 10: "NOT INITIALIZED", 11: "NOT ENABLED", 12: "HARDWARE VERSION ERROR", - 13: "OUT OF MEMORY ERROR" + 13: "OUT OF MEMORY ERROR", } @staticmethod @@ -49,13 +63,17 @@ def device_dict_to_string(d): @property def device_parameters(self): - return OrderedDict([(self.Command.SET_ANTENNA_INDEX.name, self.antenna_index), - (self.Command.SET_FREQUENCY.name, self.frequency), - (self.Command.SET_SAMPLE_RATE.name, self.sample_rate), - (self.Command.SET_BANDWIDTH.name, self.bandwidth), - (self.Command.SET_RF_GAIN.name, self.gain), - (self.Command.SET_IF_GAIN.name, self.if_gain), - ("identifier", self.device_number)]) + return OrderedDict( + [ + (self.Command.SET_ANTENNA_INDEX.name, self.antenna_index), + (self.Command.SET_FREQUENCY.name, self.frequency), + (self.Command.SET_SAMPLE_RATE.name, self.sample_rate), + (self.Command.SET_BANDWIDTH.name, self.bandwidth), + (self.Command.SET_RF_GAIN.name, self.gain), + (self.Command.SET_IF_GAIN.name, self.if_gain), + ("identifier", self.device_number), + ] + ) @property def has_multi_device_support(self): @@ -66,26 +84,49 @@ def get_device_list(cls): return [cls.device_dict_to_string(d) for d in sdrplay.get_devices()] @classmethod - def enter_async_receive_mode(cls, data_connection: Connection, ctrl_connection: Connection): - ret = sdrplay.init_stream(cls.sdrplay_initial_gain, cls.sdrplay_initial_sample_rate, cls.sdrplay_initial_freq, - cls.sdrplay_initial_bandwidth, cls.sdrplay_initial_if_gain, data_connection) + def enter_async_receive_mode( + cls, data_connection: Connection, ctrl_connection: Connection + ): + ret = sdrplay.init_stream( + cls.sdrplay_initial_gain, + cls.sdrplay_initial_sample_rate, + cls.sdrplay_initial_freq, + cls.sdrplay_initial_bandwidth, + cls.sdrplay_initial_if_gain, + data_connection, + ) ctrl_connection.send( "Start RX MODE with \n FREQUENCY={}\n SAMPLE_RATE={}\n BANDWIDTH={}\n GAIN={}\n IF_GAIN={}:{}".format( - cls.sdrplay_initial_freq, cls.sdrplay_initial_sample_rate, cls.sdrplay_initial_bandwidth, cls.sdrplay_initial_gain, cls.sdrplay_initial_if_gain, ret)) + cls.sdrplay_initial_freq, + cls.sdrplay_initial_sample_rate, + cls.sdrplay_initial_bandwidth, + cls.sdrplay_initial_gain, + cls.sdrplay_initial_if_gain, + ret, + ) + ) return ret @classmethod - def init_device(cls, ctrl_connection: Connection, is_tx: bool, parameters: OrderedDict) -> bool: + def init_device( + cls, ctrl_connection: Connection, is_tx: bool, parameters: OrderedDict + ) -> bool: identifier = parameters["identifier"] try: device_list = sdrplay.get_devices() device_number = int(identifier) - ctrl_connection.send("CONNECTED DEVICES: {}".format(", ".join(map(cls.device_dict_to_string, device_list)))) + ctrl_connection.send( + "CONNECTED DEVICES: {}".format( + ", ".join(map(cls.device_dict_to_string, device_list)) + ) + ) ret = sdrplay.set_device_index(device_number) - ctrl_connection.send("SET DEVICE NUMBER to {}:{}".format(device_number, ret)) + ctrl_connection.send( + "SET DEVICE NUMBER to {}:{}".format(device_number, ret) + ) except (TypeError, ValueError) as e: logger.exception(e) return False @@ -94,7 +135,11 @@ def init_device(cls, ctrl_connection: Connection, is_tx: bool, parameters: Order sdrplay.set_gr_mode_for_dev_model(device_model) if device_model == 2: antenna = parameters[cls.Command.SET_ANTENNA_INDEX.name] - cls.process_command((cls.Command.SET_ANTENNA_INDEX.name, antenna), ctrl_connection, is_tx=False) + cls.process_command( + (cls.Command.SET_ANTENNA_INDEX.name, antenna), + ctrl_connection, + is_tx=False, + ) else: ctrl_connection.send("Skipping antenna selection for RSP1 device") diff --git a/src/urh/dev/native/SendConfig.py b/src/urh/dev/native/SendConfig.py index e1dcec8c88..de741f022b 100644 --- a/src/urh/dev/native/SendConfig.py +++ b/src/urh/dev/native/SendConfig.py @@ -6,9 +6,17 @@ class SendConfig(object): - def __init__(self, send_buffer, current_sent_index: Value, current_sending_repeat: Value, - total_samples: int, sending_repeats: int, continuous: bool = False, - iq_to_bytes_method: callable = None, continuous_send_ring_buffer: RingBuffer = None): + def __init__( + self, + send_buffer, + current_sent_index: Value, + current_sending_repeat: Value, + total_samples: int, + sending_repeats: int, + continuous: bool = False, + iq_to_bytes_method: callable = None, + continuous_send_ring_buffer: RingBuffer = None, + ): self.send_buffer = send_buffer self.current_sent_index = current_sent_index self.current_sending_repeat = current_sending_repeat @@ -24,14 +32,18 @@ def get_data_to_send(self, buffer_length: int): return np.zeros(1, dtype=self.send_buffer._type_._type_) if self.continuous: - result = self.iq_to_bytes_method(self.continuous_send_ring_buffer.pop(buffer_length // 2)) + result = self.iq_to_bytes_method( + self.continuous_send_ring_buffer.pop(buffer_length // 2) + ) if len(result) == 0: # avoid empty arrays which will not work with cython API return np.zeros(1, dtype=self.send_buffer._type_._type_) else: index = self.current_sent_index.value - np_view = np.frombuffer(self.send_buffer, dtype=self.send_buffer._type_._type_) - result = np_view[index:index + buffer_length] + np_view = np.frombuffer( + self.send_buffer, dtype=self.send_buffer._type_._type_ + ) + result = np_view[index : index + buffer_length] self.progress_send_status(len(result)) return result @@ -42,14 +54,19 @@ def sending_is_finished(self): if self.sending_repeats == 0: # 0 = infinity return False - return self.current_sending_repeat.value >= self.sending_repeats \ - and self.current_sent_index.value >= self.total_samples + return ( + self.current_sending_repeat.value >= self.sending_repeats + and self.current_sent_index.value >= self.total_samples + ) def progress_send_status(self, buffer_length: int): self.current_sent_index.value += buffer_length if self.current_sent_index.value >= self.total_samples - 1: self.current_sending_repeat.value += 1 - if self.current_sending_repeat.value < self.sending_repeats or self.sending_repeats == 0: # 0 = infinity + if ( + self.current_sending_repeat.value < self.sending_repeats + or self.sending_repeats == 0 + ): # 0 = infinity self.current_sent_index.value = 0 else: self.current_sent_index.value = self.total_samples diff --git a/src/urh/dev/native/SoundCard.py b/src/urh/dev/native/SoundCard.py index 4735337542..a1080c1cb5 100644 --- a/src/urh/dev/native/SoundCard.py +++ b/src/urh/dev/native/SoundCard.py @@ -26,7 +26,9 @@ class SoundCard(Device): DATA_TYPE = np.float32 @classmethod - def init_device(cls, ctrl_connection: Connection, is_tx: bool, parameters: OrderedDict) -> bool: + def init_device( + cls, ctrl_connection: Connection, is_tx: bool, parameters: OrderedDict + ) -> bool: try: cls.SAMPLE_RATE = int(parameters[cls.Command.SET_SAMPLE_RATE.name]) except (KeyError, ValueError): @@ -47,11 +49,13 @@ def setup_device(cls, ctrl_connection: Connection, device_identifier): @classmethod def prepare_sync_receive(cls, ctrl_connection: Connection): try: - cls.pyaudio_stream = cls.pyaudio_handle.open(format=pyaudio.paFloat32, - channels=2, - rate=cls.SAMPLE_RATE, - input=True, - frames_per_buffer=cls.CHUNK_SIZE) + cls.pyaudio_stream = cls.pyaudio_handle.open( + format=pyaudio.paFloat32, + channels=2, + rate=cls.SAMPLE_RATE, + input=True, + frames_per_buffer=cls.CHUNK_SIZE, + ) ctrl_connection.send("Successfully started pyaudio stream") return 0 except Exception as e: @@ -61,11 +65,13 @@ def prepare_sync_receive(cls, ctrl_connection: Connection): @classmethod def prepare_sync_send(cls, ctrl_connection: Connection): try: - cls.pyaudio_stream = cls.pyaudio_handle.open(format=pyaudio.paFloat32, - channels=2, - rate=cls.SAMPLE_RATE, - frames_per_buffer=cls.CHUNK_SIZE, - output=True) + cls.pyaudio_stream = cls.pyaudio_handle.open( + format=pyaudio.paFloat32, + channels=2, + rate=cls.SAMPLE_RATE, + frames_per_buffer=cls.CHUNK_SIZE, + output=True, + ) ctrl_connection.send("Successfully started pyaudio stream") return 0 except Exception as e: @@ -75,14 +81,18 @@ def prepare_sync_send(cls, ctrl_connection: Connection): @classmethod def receive_sync(cls, data_conn: Connection): if cls.pyaudio_stream: - data_conn.send_bytes(cls.pyaudio_stream.read(cls.CHUNK_SIZE, exception_on_overflow=False)) + data_conn.send_bytes( + cls.pyaudio_stream.read(cls.CHUNK_SIZE, exception_on_overflow=False) + ) @classmethod def send_sync(cls, data): if cls.pyaudio_stream: - data_bytes = data.tostring() if isinstance(data, np.ndarray) else bytes(data) + data_bytes = ( + data.tostring() if isinstance(data, np.ndarray) else bytes(data) + ) # pad with zeros if smaller than chunk size - cls.pyaudio_stream.write(data_bytes.ljust(cls.CHUNK_SIZE*8, b'\0')) + cls.pyaudio_stream.write(data_bytes.ljust(cls.CHUNK_SIZE * 8, b"\0")) @classmethod def shutdown_device(cls, ctrl_connection, is_tx: bool): @@ -99,17 +109,27 @@ def shutdown_device(cls, ctrl_connection, is_tx: bool): ctrl_connection.send("Failed to shut down pyaudio") def __init__(self, sample_rate, resume_on_full_receive_buffer=False): - super().__init__(center_freq=0, sample_rate=sample_rate, bandwidth=0, - gain=1, if_gain=1, baseband_gain=1, - resume_on_full_receive_buffer=resume_on_full_receive_buffer) + super().__init__( + center_freq=0, + sample_rate=sample_rate, + bandwidth=0, + gain=1, + if_gain=1, + baseband_gain=1, + resume_on_full_receive_buffer=resume_on_full_receive_buffer, + ) self.success = 0 self.bandwidth_is_adjustable = False @property def device_parameters(self) -> OrderedDict: - return OrderedDict([(self.Command.SET_SAMPLE_RATE.name, self.sample_rate), - ("identifier", None)]) + return OrderedDict( + [ + (self.Command.SET_SAMPLE_RATE.name, self.sample_rate), + ("identifier", None), + ] + ) @staticmethod def bytes_to_iq(buffer): diff --git a/src/urh/dev/native/USRP.py b/src/urh/dev/native/USRP.py index b1f9a95650..f1349a07cd 100644 --- a/src/urh/dev/native/USRP.py +++ b/src/urh/dev/native/USRP.py @@ -10,7 +10,12 @@ class USRP(Device): DEVICE_METHODS = Device.DEVICE_METHODS.copy() - DEVICE_METHODS.update({"SET_SUBDEVICE": "set_subdevice", Device.Command.SET_ANTENNA_INDEX.name: "set_antenna"}) + DEVICE_METHODS.update( + { + "SET_SUBDEVICE": "set_subdevice", + Device.Command.SET_ANTENNA_INDEX.name: "set_antenna", + } + ) SYNC_RX_CHUNK_SIZE = 16384 SYNC_TX_CHUNK_SIZE = 16384 * 2 @@ -47,12 +52,17 @@ def setup_device(cls, ctrl_connection: Connection, device_identifier): return success @classmethod - def init_device(cls, ctrl_connection: Connection, is_tx: bool, parameters: OrderedDict): + def init_device( + cls, ctrl_connection: Connection, is_tx: bool, parameters: OrderedDict + ): usrp.set_tx(is_tx) success = super().init_device(ctrl_connection, is_tx, parameters) if success: - ctrl_connection.send("Current antenna is {} (possible antennas: {})".format(usrp.get_antenna(), - ", ".join(usrp.get_antennas()))) + ctrl_connection.send( + "Current antenna is {} (possible antennas: {})".format( + usrp.get_antenna(), ", ".join(usrp.get_antennas()) + ) + ) return success @classmethod @@ -85,11 +95,25 @@ def prepare_sync_send(cls, ctrl_connection: Connection): def send_sync(cls, data): usrp.send_stream(data) - def __init__(self, center_freq, sample_rate, bandwidth, gain, if_gain=1, baseband_gain=1, - resume_on_full_receive_buffer=False): - super().__init__(center_freq=center_freq, sample_rate=sample_rate, bandwidth=bandwidth, - gain=gain, if_gain=if_gain, baseband_gain=baseband_gain, - resume_on_full_receive_buffer=resume_on_full_receive_buffer) + def __init__( + self, + center_freq, + sample_rate, + bandwidth, + gain, + if_gain=1, + baseband_gain=1, + resume_on_full_receive_buffer=False, + ): + super().__init__( + center_freq=center_freq, + sample_rate=sample_rate, + bandwidth=bandwidth, + gain=gain, + if_gain=if_gain, + baseband_gain=baseband_gain, + resume_on_full_receive_buffer=resume_on_full_receive_buffer, + ) self.success = 0 self.error_codes = {4711: "Antenna index not supported on this device"} @@ -105,15 +129,17 @@ def has_multi_device_support(self): @property def device_parameters(self): - return OrderedDict([ - ("SET_SUBDEVICE", self.subdevice), - (self.Command.SET_ANTENNA_INDEX.name, self.antenna_index), - (self.Command.SET_FREQUENCY.name, self.frequency), - (self.Command.SET_SAMPLE_RATE.name, self.sample_rate), - (self.Command.SET_BANDWIDTH.name, self.bandwidth), - (self.Command.SET_RF_GAIN.name, self.gain * 0.01), - ("identifier", self.device_serial), - ]) + return OrderedDict( + [ + ("SET_SUBDEVICE", self.subdevice), + (self.Command.SET_ANTENNA_INDEX.name, self.antenna_index), + (self.Command.SET_FREQUENCY.name, self.frequency), + (self.Command.SET_SAMPLE_RATE.name, self.sample_rate), + (self.Command.SET_BANDWIDTH.name, self.bandwidth), + (self.Command.SET_RF_GAIN.name, self.gain * 0.01), + ("identifier", self.device_serial), + ] + ) @staticmethod def bytes_to_iq(buffer): diff --git a/src/urh/main.py b/src/urh/main.py index bfae2dc811..9d7381eb8c 100755 --- a/src/urh/main.py +++ b/src/urh/main.py @@ -11,7 +11,7 @@ from PyQt5.QtWidgets import QApplication, QWidget, QStyleFactory try: - locale.setlocale(locale.LC_ALL, '') + locale.setlocale(locale.LC_ALL, "") except locale.Error as e: print("Ignoring locale error {}".format(e)) @@ -30,19 +30,33 @@ def fix_windows_stdout_stderr(): sys.stdout.write("\n") sys.stdout.flush() except: + class DummyStream(object): - def __init__(self): pass + def __init__(self): + pass - def write(self, data): pass + def write(self, data): + pass - def read(self, data): pass + def read(self, data): + pass - def flush(self): pass + def flush(self): + pass - def close(self): pass + def close(self): + pass - sys.stdout, sys.stderr, sys.stdin = DummyStream(), DummyStream(), DummyStream() - sys.__stdout__, sys.__stderr__, sys.__stdin__ = DummyStream(), DummyStream(), DummyStream() + sys.stdout, sys.stderr, sys.stdin = ( + DummyStream(), + DummyStream(), + DummyStream(), + ) + sys.__stdout__, sys.__stderr__, sys.__stdin__ = ( + DummyStream(), + DummyStream(), + DummyStream(), + ) def main(): @@ -52,32 +66,39 @@ def main(): print("You need at least Python 3.4 for this application!") sys.exit(1) - urh_exe = sys.executable if hasattr(sys, 'frozen') else sys.argv[0] + urh_exe = sys.executable if hasattr(sys, "frozen") else sys.argv[0] urh_exe = os.readlink(urh_exe) if os.path.islink(urh_exe) else urh_exe urh_dir = os.path.join(os.path.dirname(os.path.realpath(urh_exe)), "..", "..") prefix = os.path.abspath(os.path.normpath(urh_dir)) src_dir = os.path.join(prefix, "src") - if os.path.exists(src_dir) and not prefix.startswith("/usr") and not re.match(r"(?i)c:\\program", prefix): + if ( + os.path.exists(src_dir) + and not prefix.startswith("/usr") + and not re.match(r"(?i)c:\\program", prefix) + ): # Started locally, not installed -> add directory to path sys.path.insert(0, src_dir) if len(sys.argv) > 1 and sys.argv[1] == "--version": import urh.version + print(urh.version.VERSION) sys.exit(0) - if GENERATE_UI and not hasattr(sys, 'frozen'): + if GENERATE_UI and not hasattr(sys, "frozen"): try: sys.path.insert(0, prefix) from data import generate_ui + generate_ui.gen() except (ImportError, FileNotFoundError): # The generate UI script cannot be found so we are most likely in release mode, no problem here. pass from urh.util import util + util.set_shared_library_path() try: @@ -93,6 +114,7 @@ def main(): os.chdir(os.path.join(src_dir, "urh", "cythonext")) from urh.cythonext import build + build.main() os.chdir(old_dir) @@ -101,7 +123,7 @@ def main(): from urh import settings if settings.read("theme_index", 0, int) > 0: - os.environ['QT_QPA_PLATFORMTHEME'] = 'fusion' + os.environ["QT_QPA_PLATFORMTHEME"] = "fusion" app = QApplication(["URH"] + sys.argv[1:]) app.setWindowIcon(QIcon(":/icons/icons/appicon.png")) @@ -164,6 +186,7 @@ def main(): if sys.platform == "win32": # Ensure we get the app icon in windows taskbar import ctypes + ctypes.windll.shell32.SetCurrentProcessExplicitAppUserModelID("jopohl.urh") if settings.read("MainController/geometry", type=bytes): @@ -179,7 +202,9 @@ def main(): return_code = app.exec_() app.closeAllWindows() - os._exit(return_code) # sys.exit() is not enough on Windows and will result in crash on exit + os._exit( + return_code + ) # sys.exit() is not enough on Windows and will result in crash on exit if __name__ == "__main__": diff --git a/src/urh/models/FieldTypeTableModel.py b/src/urh/models/FieldTypeTableModel.py index 6585fd38b5..3e4cc8e799 100644 --- a/src/urh/models/FieldTypeTableModel.py +++ b/src/urh/models/FieldTypeTableModel.py @@ -5,7 +5,7 @@ class FieldTypeTableModel(QAbstractTableModel): - header_labels = ["Caption", 'Function', "Default display type"] + header_labels = ["Caption", "Function", "Default display type"] def __init__(self, fieldtypes, parent=None): """ diff --git a/src/urh/models/FileIconProvider.py b/src/urh/models/FileIconProvider.py index 8ba0e349da..47658b075f 100644 --- a/src/urh/models/FileIconProvider.py +++ b/src/urh/models/FileIconProvider.py @@ -14,8 +14,12 @@ def __init__(self): def icon(self, arg): if isinstance(arg, QFileInfo): try: - if (arg.isDir() and os.path.isfile(os.path.join(arg.filePath(), settings.PROJECT_FILE))) \ - or (arg.isFile() and arg.fileName() == settings.PROJECT_FILE): + if ( + arg.isDir() + and os.path.isfile( + os.path.join(arg.filePath(), settings.PROJECT_FILE) + ) + ) or (arg.isFile() and arg.fileName() == settings.PROJECT_FILE): return QIcon(":/icons/icons/appicon.png") except: # In some environments (e.g. docker) there tend to be encoding errors diff --git a/src/urh/models/FuzzingTableModel.py b/src/urh/models/FuzzingTableModel.py index 2fd1fe1853..d333e4c4a7 100644 --- a/src/urh/models/FuzzingTableModel.py +++ b/src/urh/models/FuzzingTableModel.py @@ -24,7 +24,9 @@ def update(self): seq = self.fuzzing_label.fuzz_values[:] seen = set() add_seen = seen.add - self.fuzzing_label.fuzz_values = [l for l in seq if not (l in seen or add_seen(l))] + self.fuzzing_label.fuzz_values = [ + l for l in seq if not (l in seen or add_seen(l)) + ] self.data = self.fuzzing_label.fuzz_values if self.proto_view == 0: @@ -58,9 +60,9 @@ def data(self, index: QModelIndex, role=None): if self.proto_view == 0: return self.data[i][j] elif self.proto_view == 1: - return "{0:x}".format(int(self.data[i][4 * j:4 * (j + 1)], 2)) + return "{0:x}".format(int(self.data[i][4 * j : 4 * (j + 1)], 2)) elif self.proto_view == 2: - return chr(int(self.data[i][8 * j:8 * (j + 1)], 2)) + return chr(int(self.data[i][8 * j : 8 * (j + 1)], 2)) elif role == Qt.FontRole: if i == 0: @@ -73,21 +75,38 @@ def data(self, index: QModelIndex, role=None): def setData(self, index: QModelIndex, value, role=None): i = index.row() j = index.column() - hex_chars = ("0", "1", "2", "3", "4", "5", "6", "7", "8", "9", "a", "b", "c", "d", "e", "f") + hex_chars = ( + "0", + "1", + "2", + "3", + "4", + "5", + "6", + "7", + "8", + "9", + "a", + "b", + "c", + "d", + "e", + "f", + ) if self.proto_view == 0 and value in ("0", "1"): l = list(self.data[i]) l[j] = value - self.data[i] = ''.join(l) + self.data[i] = "".join(l) self.update() elif self.proto_view == 1 and value in hex_chars: l = list(self.data[i]) - l[4*j : 4 * (j + 1)] = "{0:04b}".format(int(value, 16)) - self.data[i] = ''.join(l) + l[4 * j : 4 * (j + 1)] = "{0:04b}".format(int(value, 16)) + self.data[i] = "".join(l) self.update() elif self.proto_view == 2 and len(value) == 1: l = list(self.data[i]) - l[8*j : 8 * (j + 1)] = "{0:08b}".format(ord(value)) - self.data[i] = ''.join(l) + l[8 * j : 8 * (j + 1)] = "{0:08b}".format(ord(value)) + self.data[i] = "".join(l) self.update() return True @@ -103,11 +122,15 @@ def add_range(self, start: int, end: int, step: int): self.update() - def add_boundaries(self, lower: int, upper: int, num_vals:int): + def add_boundaries(self, lower: int, upper: int, num_vals: int): lbl = self.fuzzing_label if lower > -1: - low = lower if lower < lbl.fuzz_maximum + num_vals else lbl.fuzz_maximum - num_vals + low = ( + lower + if lower < lbl.fuzz_maximum + num_vals + else lbl.fuzz_maximum - num_vals + ) for i in range(low, low + num_vals): lbl.add_decimal_fuzz_value(i) @@ -137,4 +160,3 @@ def repeat_fuzzing_values(self, start: int, end: int, times: int): lbl.fuzz_values.insert(i, val) self.update() - diff --git a/src/urh/models/GeneratorListModel.py b/src/urh/models/GeneratorListModel.py index 21cae49607..da50509896 100644 --- a/src/urh/models/GeneratorListModel.py +++ b/src/urh/models/GeneratorListModel.py @@ -12,14 +12,14 @@ class GeneratorListModel(QAbstractListModel): def __init__(self, message: Message, parent=None): super().__init__(parent) self.__message = message - + @property def labels(self): if self.message: return self.message.message_type else: return [] - + @property def message(self): return self.__message @@ -53,7 +53,6 @@ def data(self, index, role=Qt.DisplayRole): elif role == Qt.BackgroundColorRole: return settings.LABEL_COLORS[self.labels[row].color_index] - def setData(self, index: QModelIndex, value, role=Qt.DisplayRole): if role == Qt.CheckStateRole: proto_label = self.labels[index.row()] diff --git a/src/urh/models/GeneratorTableModel.py b/src/urh/models/GeneratorTableModel.py index c9b725aaf3..23c544b8be 100644 --- a/src/urh/models/GeneratorTableModel.py +++ b/src/urh/models/GeneratorTableModel.py @@ -22,7 +22,7 @@ class GeneratorTableModel(TableModel): first_protocol_added = pyqtSignal(ProtocolAnalyzer) - def __init__(self, tree_root_item: ProtocolTreeItem, decodings, parent = None): + def __init__(self, tree_root_item: ProtocolTreeItem, decodings, parent=None): super().__init__(participants=[], parent=parent) self.protocol = ProtocolAnalyzerContainer() self.tree_root_item = tree_root_item @@ -48,26 +48,50 @@ def refresh_fonts(self): for i, message in enumerate(pac.messages): if message.fuzz_created: for lbl in (lbl for lbl in message.message_type if lbl.fuzz_created): - for j in range(*message.get_label_range(lbl=lbl, view=self.proto_view, decode=False)): + for j in range( + *message.get_label_range( + lbl=lbl, view=self.proto_view, decode=False + ) + ): self.bold_fonts[i, j] = True for lbl in message.active_fuzzing_labels: - for j in range(*message.get_label_range(lbl=lbl, view=self.proto_view, decode=False)): + for j in range( + *message.get_label_range( + lbl=lbl, view=self.proto_view, decode=False + ) + ): self.bold_fonts[i, j] = True self.text_colors[i, j] = QColor("orange") - for lbl in (lbl for lbl in message.message_type if isinstance(lbl, ChecksumLabel)): - if lbl not in self.edited_checksum_labels_by_row[i] and not lbl.fuzz_created: - self.__set_italic_font_for_label_range(row=i, label=lbl, italic=True) - - def delete_range(self, msg_start: int, msg_end: int, index_start: int, index_end: int): + for lbl in ( + lbl for lbl in message.message_type if isinstance(lbl, ChecksumLabel) + ): + if ( + lbl not in self.edited_checksum_labels_by_row[i] + and not lbl.fuzz_created + ): + self.__set_italic_font_for_label_range( + row=i, label=lbl, italic=True + ) + + def delete_range( + self, msg_start: int, msg_end: int, index_start: int, index_end: int + ): if msg_start > msg_end: msg_start, msg_end = msg_end, msg_start if index_start > index_end: index_start, index_end = index_end, index_start - remove_action = DeleteBitsAndPauses(self.protocol, msg_start, msg_end, index_start, - index_end, self.proto_view, False) + remove_action = DeleteBitsAndPauses( + self.protocol, + msg_start, + msg_end, + index_start, + index_end, + self.proto_view, + False, + ) ########## Delete according pauses self.undo_stack.push(remove_action) @@ -75,7 +99,13 @@ def flags(self, index: QModelIndex): if not index.isValid(): return Qt.ItemIsEnabled - return Qt.ItemIsEnabled | Qt.ItemIsDropEnabled | Qt.ItemIsSelectable | Qt.ItemIsDragEnabled | Qt.ItemIsEditable + return ( + Qt.ItemIsEnabled + | Qt.ItemIsDropEnabled + | Qt.ItemIsSelectable + | Qt.ItemIsDragEnabled + | Qt.ItemIsEditable + ) def supportedDropActions(self): return Qt.CopyAction | Qt.MoveAction @@ -109,12 +139,16 @@ def dropMimeData(self, mimedata, action, row, column, parentIndex): for group_node in group_nodes: nodes_to_add.extend(group_node.children) - nodes_to_add.extend([file_node for file_node in file_nodes if file_node not in nodes_to_add]) + nodes_to_add.extend( + [file_node for file_node in file_nodes if file_node not in nodes_to_add] + ) is_empty = self.row_count == 0 for node in reversed(nodes_to_add): - undo_action = InsertBitsAndPauses(self.protocol, self.dropped_row, node.protocol) + undo_action = InsertBitsAndPauses( + self.protocol, self.dropped_row, node.protocol + ) self.undo_stack.push(undo_action) if is_empty and self.row_count > 0: @@ -131,13 +165,15 @@ def duplicate_rows(self, rows: list): self.update() def add_empty_row_behind(self, row_index: int, num_bits: int): - message = Message(plain_bits=[0]*num_bits, - pause=settings.read("default_fuzzing_pause", 10**6, int), - message_type=self.protocol.default_message_type) + message = Message( + plain_bits=[0] * num_bits, + pause=settings.read("default_fuzzing_pause", 10**6, int), + message_type=self.protocol.default_message_type, + ) tmp_protocol = ProtocolAnalyzer(None) tmp_protocol.messages = [message] - undo_action = InsertBitsAndPauses(self.protocol, row_index+1, tmp_protocol) + undo_action = InsertBitsAndPauses(self.protocol, row_index + 1, tmp_protocol) self.undo_stack.push(undo_action) def generate_de_bruijn(self, row_index: int, start: int, end: int): @@ -147,23 +183,27 @@ def generate_de_bruijn(self, row_index: int, start: int, end: int): f = 1 if self.proto_view == 0 else 4 if self.proto_view == 1 else 8 start, end = f * start, f * end - de_bruijn_seq = c_util.de_bruijn(end-start) + de_bruijn_seq = c_util.de_bruijn(end - start) tmp_protocol = ProtocolAnalyzer(None) tmp_protocol.messages = [] LINE_BREAK_AFTER = 5000 * f for i in range(0, len(de_bruijn_seq), LINE_BREAK_AFTER): - message = Message(plain_bits=de_bruijn_seq[i:i+LINE_BREAK_AFTER], - pause=0, - message_type=self.protocol.default_message_type) + message = Message( + plain_bits=de_bruijn_seq[i : i + LINE_BREAK_AFTER], + pause=0, + message_type=self.protocol.default_message_type, + ) tmp_protocol.messages.append(message) - undo_action = InsertBitsAndPauses(self.protocol, row_index+1, tmp_protocol) + undo_action = InsertBitsAndPauses(self.protocol, row_index + 1, tmp_protocol) self.undo_stack.push(undo_action) def __set_italic_font_for_label_range(self, row, label, italic: bool): message = self.protocol.messages[row] - for j in range(*message.get_label_range(lbl=label, view=self.proto_view, decode=False)): + for j in range( + *message.get_label_range(lbl=label, view=self.proto_view, decode=False) + ): self.italic_fonts[row, j] = italic def update_checksums_for_row(self, row: int): @@ -175,12 +215,18 @@ def update_checksums_for_row(self, row: int): self.__set_italic_font_for_label_range(row, lbl, italic=True) self.edited_checksum_labels_by_row[row].discard(lbl) - calculated_checksum = lbl.calculate_checksum_for_message(msg, use_decoded_bits=False) + calculated_checksum = lbl.calculate_checksum_for_message( + msg, use_decoded_bits=False + ) label_range = msg.get_label_range(lbl=lbl, view=0, decode=False) start, end = label_range[0], label_range[1] - msg[start:end] = calculated_checksum + array.array("B", [0] * ((end - start) - len(calculated_checksum))) + msg[start:end] = calculated_checksum + array.array( + "B", [0] * ((end - start) - len(calculated_checksum)) + ) - label_range = msg.get_label_range(lbl=lbl, view=self.proto_view, decode=False) + label_range = msg.get_label_range( + lbl=lbl, view=self.proto_view, decode=False + ) start, end = label_range[0], label_range[1] if self.proto_view == 0: data = calculated_checksum @@ -191,19 +237,28 @@ def update_checksums_for_row(self, row: int): else: data = array.array("B", []) - self.display_data[row][start:end] = data + array.array("B", [0] * ((end - start) - len(data))) + self.display_data[row][start:end] = data + array.array( + "B", [0] * ((end - start) - len(data)) + ) @pyqtSlot(int, int) def on_data_edited(self, row: int, column: int): - edited_range = range(column, column+1) + edited_range = range(column, column + 1) message = self.protocol.messages[row] checksum_labels = message.message_type.checksum_labels if checksum_labels: - edited_checksum_labels = [lbl for lbl in checksum_labels - if any(j in edited_range - for j in range(*message.get_label_range(lbl=lbl, - view=self.proto_view, - decode=False)))] + edited_checksum_labels = [ + lbl + for lbl in checksum_labels + if any( + j in edited_range + for j in range( + *message.get_label_range( + lbl=lbl, view=self.proto_view, decode=False + ) + ) + ) + ] if edited_checksum_labels: for lbl in edited_checksum_labels: @@ -214,4 +269,3 @@ def on_data_edited(self, row: int, column: int): self.edited_checksum_labels_by_row[row].add(lbl) else: self.update_checksums_for_row(row) - diff --git a/src/urh/models/GeneratorTreeModel.py b/src/urh/models/GeneratorTreeModel.py index fc276c0449..51cc6d6139 100644 --- a/src/urh/models/GeneratorTreeModel.py +++ b/src/urh/models/GeneratorTreeModel.py @@ -15,14 +15,19 @@ def flags(self, index: QModelIndex): if not index.isValid(): return Qt.ItemIsEnabled - return Qt.ItemIsEnabled | Qt.ItemIsSelectable | Qt.ItemIsDragEnabled | Qt.ItemIsDropEnabled + return ( + Qt.ItemIsEnabled + | Qt.ItemIsSelectable + | Qt.ItemIsDragEnabled + | Qt.ItemIsDropEnabled + ) def mimeTypes(self): - return [] # Prohibit Drag Drop in Generator + return [] # Prohibit Drag Drop in Generator def data(self, index: QModelIndex, role=None): item = self.getItem(index) - if role == Qt.DisplayRole:# + if role == Qt.DisplayRole: # return item.data() elif role == Qt.DecorationRole and item.is_group: - return QIcon.fromTheme("folder") \ No newline at end of file + return QIcon.fromTheme("folder") diff --git a/src/urh/models/LabelValueTableModel.py b/src/urh/models/LabelValueTableModel.py index c4529d9a3d..b370167b51 100644 --- a/src/urh/models/LabelValueTableModel.py +++ b/src/urh/models/LabelValueTableModel.py @@ -34,21 +34,28 @@ def __display_data(self, lbl: ProtocolLabel, expected_checksum: array = None): return "-" try: - data = self.message.decoded_bits[lbl.start:lbl.end] + data = self.message.decoded_bits[lbl.start : lbl.end] except IndexError: return None lsb = lbl.display_bit_order_index == 1 lsd = lbl.display_bit_order_index == 2 - data = util.convert_bits_to_string(data, lbl.display_format_index, pad_zeros=True, lsb=lsb, lsd=lsd, - endianness=lbl.display_endianness) + data = util.convert_bits_to_string( + data, + lbl.display_format_index, + pad_zeros=True, + lsb=lsb, + lsd=lsd, + endianness=lbl.display_endianness, + ) if data is None: return None if expected_checksum is not None: data += " (should be {0})".format( - util.convert_bits_to_string(expected_checksum, lbl.display_format_index)) + util.convert_bits_to_string(expected_checksum, lbl.display_format_index) + ) return data @@ -63,7 +70,9 @@ def message_index(self, value): @property def message(self): - if self.message_index != -1 and self.message_index < len(self.proto_analyzer.messages): + if self.message_index != -1 and self.message_index < len( + self.proto_analyzer.messages + ): return self.proto_analyzer.messages[self.message_index] else: return None @@ -99,7 +108,9 @@ def data(self, index: QModelIndex, role=Qt.DisplayRole): return None if isinstance(lbl, ChecksumLabel) and self.message is not None: - calculated_crc = lbl.calculate_checksum_for_message(self.message, use_decoded_bits=True) + calculated_crc = lbl.calculate_checksum_for_message( + self.message, use_decoded_bits=True + ) else: calculated_crc = None @@ -129,21 +140,25 @@ def data(self, index: QModelIndex, role=Qt.DisplayRole): elif role == Qt.ToolTipRole: if j == 2: - return self.tr("Choose display type for the value of the label:" - "") + return self.tr( + "Choose display type for the value of the label:" + "" + ) if j == 3: - return self.tr("Choose bit order for the displayed value:" - "") + return self.tr( + "Choose bit order for the displayed value:" + "" + ) elif role == Qt.FontRole and j == 0: font = QFont() font.setBold(i in self.selected_label_indices) @@ -156,7 +171,9 @@ def setData(self, index: QModelIndex, value, role=None): if index.column() == 0: lbl.name = value new_field_type = self.controller.field_types_by_caption.get(value, None) - self.controller.active_message_type.change_field_type_of_label(lbl, new_field_type) + self.controller.active_message_type.change_field_type_of_label( + lbl, new_field_type + ) elif index.column() == 1: lbl.color_index = value self.label_color_changed.emit(lbl) @@ -165,17 +182,20 @@ def setData(self, index: QModelIndex, value, role=None): elif index.column() == 3: lbl.display_order_str = value - self.dataChanged.emit(self.index(row, 0), - self.index(row, self.columnCount())) + self.dataChanged.emit( + self.index(row, 0), self.index(row, self.columnCount()) + ) elif role == Qt.CheckStateRole and index.column() == 0: lbl.show = value self.protolabel_visibility_changed.emit(lbl) return True def add_labels_to_message_type(self, start: int, end: int, message_type_id: int): - for lbl in self.display_labels[start:end + 1]: + for lbl in self.display_labels[start : end + 1]: if lbl not in self.controller.proto_analyzer.message_types[message_type_id]: - self.controller.proto_analyzer.message_types[message_type_id].add_label(lbl) + self.controller.proto_analyzer.message_types[message_type_id].add_label( + lbl + ) self.controller.updateUI(resize_table=False) def delete_label_at(self, index: int): diff --git a/src/urh/models/MessageTypeTableModel.py b/src/urh/models/MessageTypeTableModel.py index ec0a166c53..0b55a67b40 100644 --- a/src/urh/models/MessageTypeTableModel.py +++ b/src/urh/models/MessageTypeTableModel.py @@ -92,4 +92,9 @@ def delete_message_types_at(self, start: int, end: int): self.delete_message_type_at(row) def flags(self, index): - return Qt.ItemIsEnabled | Qt.ItemIsSelectable | Qt.ItemIsUserCheckable | Qt.ItemIsEditable + return ( + Qt.ItemIsEnabled + | Qt.ItemIsSelectable + | Qt.ItemIsUserCheckable + | Qt.ItemIsEditable + ) diff --git a/src/urh/models/PLabelTableModel.py b/src/urh/models/PLabelTableModel.py index 785b012641..c19d52a085 100644 --- a/src/urh/models/PLabelTableModel.py +++ b/src/urh/models/PLabelTableModel.py @@ -72,9 +72,16 @@ def data(self, index: QModelIndex, role=Qt.DisplayRole): if j == 0: return lbl.name elif j == 1: - return self.message.get_label_range(lbl, view=self.proto_view, decode=True)[0] + 1 + return ( + self.message.get_label_range( + lbl, view=self.proto_view, decode=True + )[0] + + 1 + ) elif j == 2: - return self.message.get_label_range(lbl, view=self.proto_view, decode=True)[1] + return self.message.get_label_range( + lbl, view=self.proto_view, decode=True + )[1] elif j == 3: return lbl.color_index elif j == 4: @@ -98,7 +105,9 @@ def setData(self, index: QModelIndex, value, role=Qt.EditRole): if j == 0: lbl.name = value type_before = type(lbl) - self.message_type.change_field_type_of_label(lbl, self.field_types_by_caption.get(value, None)) + self.message_type.change_field_type_of_label( + lbl, self.field_types_by_caption.get(value, None) + ) lbl = self.__get_label_at(i) @@ -106,10 +115,13 @@ def setData(self, index: QModelIndex, value, role=Qt.EditRole): self.special_status_label_changed.emit(lbl) elif j == 1: - lbl.start = self.message.convert_index(int(value - 1), from_view=self.proto_view, to_view=0, decoded=True)[ - 0] + lbl.start = self.message.convert_index( + int(value - 1), from_view=self.proto_view, to_view=0, decoded=True + )[0] elif j == 2: - lbl.end = self.message.convert_index(int(value), from_view=self.proto_view, to_view=0, decoded=True)[0] + lbl.end = self.message.convert_index( + int(value), from_view=self.proto_view, to_view=0, decoded=True + )[0] elif j == 3: lbl.color_index = value elif j == 4: diff --git a/src/urh/models/ParticipantLegendListModel.py b/src/urh/models/ParticipantLegendListModel.py index dd6acf7fd5..69005b14a3 100644 --- a/src/urh/models/ParticipantLegendListModel.py +++ b/src/urh/models/ParticipantLegendListModel.py @@ -5,7 +5,6 @@ class ParticipantLegendListModel(QAbstractListModel): - def __init__(self, participants, parent=None): """ @@ -24,21 +23,29 @@ def data(self, index: QModelIndex, role=None): return "not assigned" else: try: - return str(self.participants[row-1]) + return str(self.participants[row - 1]) except IndexError: return None elif role == Qt.BackgroundColorRole: if row > 0: try: - return settings.PARTICIPANT_COLORS[self.participants[row - 1].color_index] + return settings.PARTICIPANT_COLORS[ + self.participants[row - 1].color_index + ] except IndexError: return None elif role == Qt.TextColorRole: if row > 0: try: - bgcolor = settings.PARTICIPANT_COLORS[self.participants[row - 1].color_index] + bgcolor = settings.PARTICIPANT_COLORS[ + self.participants[row - 1].color_index + ] red, green, blue = bgcolor.red(), bgcolor.green(), bgcolor.blue() - return QColor("black") if (red * 0.299 + green * 0.587 + blue * 0.114) > 186 else QColor("white") + return ( + QColor("black") + if (red * 0.299 + green * 0.587 + blue * 0.114) > 186 + else QColor("white") + ) except IndexError: return None @@ -47,4 +54,4 @@ def flags(self, index): def update(self): self.beginResetModel() - self.endResetModel() \ No newline at end of file + self.endResetModel() diff --git a/src/urh/models/ParticipantListModel.py b/src/urh/models/ParticipantListModel.py index aa5fe038a1..624326ac6f 100644 --- a/src/urh/models/ParticipantListModel.py +++ b/src/urh/models/ParticipantListModel.py @@ -24,7 +24,7 @@ def data(self, index: QModelIndex, role=None): return "not assigned" else: try: - return str(self.participants[row-1]) + return str(self.participants[row - 1]) except IndexError: return None @@ -33,7 +33,9 @@ def data(self, index: QModelIndex, role=None): return Qt.Checked if self.show_unassigned else Qt.Unchecked else: try: - return Qt.Checked if self.participants[row-1].show else Qt.Unchecked + return ( + Qt.Checked if self.participants[row - 1].show else Qt.Unchecked + ) except IndexError: return None @@ -45,8 +47,8 @@ def setData(self, index: QModelIndex, value, role=None): elif role == Qt.CheckStateRole: try: - if self.participants[index.row()-1].show != value: - self.participants[index.row()-1].show = value + if self.participants[index.row() - 1].show != value: + self.participants[index.row() - 1].show = value self.show_state_changed.emit() except IndexError: return False @@ -58,4 +60,4 @@ def flags(self, index): def update(self): self.beginResetModel() - self.endResetModel() \ No newline at end of file + self.endResetModel() diff --git a/src/urh/models/ParticipantTableModel.py b/src/urh/models/ParticipantTableModel.py index 0425a24d08..f8668ad667 100644 --- a/src/urh/models/ParticipantTableModel.py +++ b/src/urh/models/ParticipantTableModel.py @@ -1,15 +1,37 @@ import itertools import random -from PyQt5.QtCore import QAbstractTableModel, pyqtSignal, QModelIndex, Qt, QItemSelection +from PyQt5.QtCore import ( + QAbstractTableModel, + pyqtSignal, + QModelIndex, + Qt, + QItemSelection, +) from urh import settings from urh.signalprocessing.Participant import Participant class ParticipantTableModel(QAbstractTableModel): - INITIAL_NAMES = ["Alice", "Bob", "Carl", "Dave", "Eve", "Frank", "Grace", "Heidi", "Judy", "Mallory", "Oscar", - "Peggy", "Sybil", "Trudy", "Victor", "Walter"] + INITIAL_NAMES = [ + "Alice", + "Bob", + "Carl", + "Dave", + "Eve", + "Frank", + "Grace", + "Heidi", + "Judy", + "Mallory", + "Oscar", + "Peggy", + "Sybil", + "Trudy", + "Victor", + "Walter", + ] updated = pyqtSignal() participant_edited = pyqtSignal() @@ -17,7 +39,13 @@ class ParticipantTableModel(QAbstractTableModel): def __init__(self, participants): super().__init__() self.participants = participants - self.header_labels = ["Name", "Shortname", "Color", "Relative RSSI", "Address (hex)"] + self.header_labels = [ + "Name", + "Shortname", + "Color", + "Relative RSSI", + "Address (hex)", + ] def update(self): self.beginResetModel() @@ -87,11 +115,20 @@ def flags(self, index: QModelIndex): def __get_initial_name(self) -> (str, str): given_names = set(p.name for p in self.participants) - name = next((name for name in self.INITIAL_NAMES if name not in given_names), None) + name = next( + (name for name in self.INITIAL_NAMES if name not in given_names), None + ) if name is not None: return name, name[0] - name = next(("P" + str(i) for i in itertools.count() if "P" + str(i) not in given_names), None) + name = next( + ( + "P" + str(i) + for i in itertools.count() + if "P" + str(i) not in given_names + ), + None, + ) if name is not None: return name, name[1:] @@ -118,11 +155,16 @@ def remove_participants(self, selection: QItemSelection): return if selection.isEmpty(): - start, end = len(self.participants) - 1, len(self.participants) - 1 # delete last element + start, end = ( + len(self.participants) - 1, + len(self.participants) - 1, + ) # delete last element else: - start, end = min([rng.top() for rng in selection]), max([rng.bottom() for rng in selection]) + start, end = min([rng.top() for rng in selection]), max( + [rng.bottom() for rng in selection] + ) - del self.participants[start:end + 1] + del self.participants[start : end + 1] num_removed = (end + 1) - start for participant in self.participants: if participant.relative_rssi > len(self.participants) - 1: @@ -132,9 +174,14 @@ def remove_participants(self, selection: QItemSelection): n = len(self.participants) for p1, p2 in itertools.combinations(self.participants, 2): if p1.relative_rssi == p2.relative_rssi: - p1.relative_rssi = next((i for i in range(n) - if i not in set(p.relative_rssi for p in self.participants)), - 0) + p1.relative_rssi = next( + ( + i + for i in range(n) + if i not in set(p.relative_rssi for p in self.participants) + ), + 0, + ) self.update() self.participant_edited.emit() @@ -143,12 +190,17 @@ def move_up(self, selection: QItemSelection): if selection.isEmpty() or len(self.participants) < 1: return None, None - start, end = min([rng.top() for rng in selection]), max([rng.bottom() for rng in selection]) + start, end = min([rng.top() for rng in selection]), max( + [rng.bottom() for rng in selection] + ) if start == 0: return None, None for i in range(start, end + 1): - self.participants[i], self.participants[i - 1] = self.participants[i - 1], self.participants[i] + self.participants[i], self.participants[i - 1] = ( + self.participants[i - 1], + self.participants[i], + ) self.update() self.participant_edited.emit() @@ -159,12 +211,17 @@ def move_down(self, selection: QItemSelection): if selection.isEmpty() or len(self.participants) < 1: return None, None - start, end = min([rng.top() for rng in selection]), max([rng.bottom() for rng in selection]) + start, end = min([rng.top() for rng in selection]), max( + [rng.bottom() for rng in selection] + ) if end >= len(self.participants) - 1: return None, None for i in reversed(range(start, end + 1)): - self.participants[i], self.participants[i + 1] = self.participants[i + 1], self.participants[i] + self.participants[i], self.participants[i + 1] = ( + self.participants[i + 1], + self.participants[i], + ) self.update() self.participant_edited.emit() diff --git a/src/urh/models/PluginListModel.py b/src/urh/models/PluginListModel.py index 72685c3681..c7f0c8e2e5 100644 --- a/src/urh/models/PluginListModel.py +++ b/src/urh/models/PluginListModel.py @@ -6,14 +6,16 @@ class PluginListModel(QAbstractListModel): - def __init__(self, plugins, highlighted_plugins = None, parent=None): + def __init__(self, plugins, highlighted_plugins=None, parent=None): """ :type plugins: list of Plugin :type highlighted_plugins: list of Plugin """ super().__init__(parent) self.plugins = plugins - self.highlighted_plugins = highlighted_plugins if highlighted_plugins is not None else [] + self.highlighted_plugins = ( + highlighted_plugins if highlighted_plugins is not None else [] + ) def rowCount(self, QModelIndex_parent=None, *args, **kwargs): return len(self.plugins) @@ -26,7 +28,10 @@ def data(self, index: QModelIndex, role=None): return self.plugins[row].enabled elif role == Qt.TextColorRole and self.plugins[row] in self.highlighted_plugins: return settings.HIGHLIGHT_TEXT_FOREGROUND_COLOR - elif role == Qt.BackgroundColorRole and self.plugins[row] in self.highlighted_plugins: + elif ( + role == Qt.BackgroundColorRole + and self.plugins[row] in self.highlighted_plugins + ): return settings.HIGHLIGHT_TEXT_BACKGROUND_COLOR elif role == Qt.FontRole and self.plugins[row] in self.highlighted_plugins: font = QFont() @@ -39,4 +44,4 @@ def setData(self, index: QModelIndex, value, role=None): return True def flags(self, index): - return Qt.ItemIsEnabled | Qt.ItemIsSelectable | Qt.ItemIsUserCheckable \ No newline at end of file + return Qt.ItemIsEnabled | Qt.ItemIsSelectable | Qt.ItemIsUserCheckable diff --git a/src/urh/models/ProtocolTableModel.py b/src/urh/models/ProtocolTableModel.py index 2d8010b93a..cfa50cdc47 100644 --- a/src/urh/models/ProtocolTableModel.py +++ b/src/urh/models/ProtocolTableModel.py @@ -11,10 +11,14 @@ class ProtocolTableModel(TableModel): ref_index_changed = pyqtSignal(int) - def __init__(self, proto_analyzer: ProtocolAnalyzer, participants, controller, parent=None): + def __init__( + self, proto_analyzer: ProtocolAnalyzer, participants, controller, parent=None + ): super().__init__(participants=participants, parent=parent) - self.controller = controller # type: urh.controller.CompareFrameController.CompareFrameController + self.controller = ( + controller + ) # type: urh.controller.CompareFrameController.CompareFrameController self.protocol = proto_analyzer self.active_group_ids = [0] @@ -50,9 +54,17 @@ def delete_range(self, min_row: int, max_row: int, start: int, end: int): if not self.is_writeable: return - del_action = DeleteBitsAndPauses(proto_analyzer=self.protocol, start_message=min_row, end_message=max_row, - start=start, end=end, view=self.proto_view, decoded=True, - subprotos=self.controller.protocol_list, update_label_ranges=False) + del_action = DeleteBitsAndPauses( + proto_analyzer=self.protocol, + start_message=min_row, + end_message=max_row, + start=start, + end=end, + view=self.proto_view, + decoded=True, + subprotos=self.controller.protocol_list, + update_label_ranges=False, + ) self.undo_stack.push(del_action) def flags(self, index: QModelIndex): diff --git a/src/urh/models/ProtocolTreeItem.py b/src/urh/models/ProtocolTreeItem.py index cd623639a0..a3c64863b4 100644 --- a/src/urh/models/ProtocolTreeItem.py +++ b/src/urh/models/ProtocolTreeItem.py @@ -18,7 +18,9 @@ def __init__(self, data: ProtocolAnalyzer or ProtocolGroup, parent): """ self.__itemData = data self.__parentItem = parent - self.__childItems = data.items if type(data) == ProtocolGroup else [] # type: list[ProtocolTreeItem] + self.__childItems = ( + data.items if type(data) == ProtocolGroup else [] + ) # type: list[ProtocolTreeItem] self.copy_data = False # For Writeable Mode in CFC self.__data_copy = None # For Writeable Mode in CFC @@ -28,18 +30,24 @@ def protocol(self): if isinstance(self.__itemData, ProtocolAnalyzer): if self.copy_data: if self.__data_copy is None: - self.__data_copy = copy.deepcopy(self.__itemData) # type: ProtocolAnalyzer + self.__data_copy = copy.deepcopy( + self.__itemData + ) # type: ProtocolAnalyzer # keep message types self.__data_copy.message_types = self.__itemData.message_types nrz = Encoding([""]) - for i, message in enumerate(self.__data_copy.messages): # type: Message + for i, message in enumerate( + self.__data_copy.messages + ): # type: Message decoded_bits = message.decoded_bits message.decoder = nrz message.plain_bits = decoded_bits message.message_type = self.__itemData.messages[i].message_type - self.__data_copy.qt_signals.show_state_changed.connect(self.__itemData.qt_signals.show_state_changed.emit) + self.__data_copy.qt_signals.show_state_changed.connect( + self.__itemData.qt_signals.show_state_changed.emit + ) return self.__data_copy else: @@ -141,7 +149,7 @@ def appendChild(self, child): def addProtocol(self, proto): try: - assert (isinstance(proto, ProtocolAnalyzer)) + assert isinstance(proto, ProtocolAnalyzer) self.__childItems.append(ProtocolTreeItem(proto, self)) except AssertionError: return @@ -177,15 +185,22 @@ def index_of(self, child): def swapChildren(self, child1, child2): i1 = self.__childItems.index(child1) i2 = self.__childItems.index(child2) - self.__childItems[i1], self.__childItems[i2] = self.__childItems[i2], self.__childItems[i1] + self.__childItems[i1], self.__childItems[i2] = ( + self.__childItems[i2], + self.__childItems[i1], + ) def bringChildsToFront(self, childs): for child in childs: - self.__childItems.insert(0, self.__childItems.pop(self.__childItems.index(child))) + self.__childItems.insert( + 0, self.__childItems.pop(self.__childItems.index(child)) + ) def bringChildsToIndex(self, index, childs): for child in reversed(childs): - self.__childItems.insert(index, self.__childItems.pop(self.__childItems.index(child))) + self.__childItems.insert( + index, self.__childItems.pop(self.__childItems.index(child)) + ) def containsChilds(self, childs): for child in childs: diff --git a/src/urh/models/ProtocolTreeModel.py b/src/urh/models/ProtocolTreeModel.py index 9f69bf5c2c..01cd213ffe 100644 --- a/src/urh/models/ProtocolTreeModel.py +++ b/src/urh/models/ProtocolTreeModel.py @@ -121,7 +121,10 @@ def data(self, index: QModelIndex, role=None): elif role == Qt.CheckStateRole: return item.show elif role == Qt.FontRole: - if item.is_group and self.rootItem.index_of(item) in self.controller.active_group_ids: + if ( + item.is_group + and self.rootItem.index_of(item) in self.controller.active_group_ids + ): font = QFont() font.setBold(True) return font @@ -166,23 +169,31 @@ def remove_protocol(self, protocol: ProtocolAnalyzer): def flags(self, index: QModelIndex): if not index.isValid(): return Qt.ItemIsDropEnabled - return Qt.ItemIsEditable | Qt.ItemIsEnabled | Qt.ItemIsSelectable | \ - Qt.ItemIsUserCheckable | Qt.ItemIsDragEnabled | Qt.ItemIsDropEnabled + return ( + Qt.ItemIsEditable + | Qt.ItemIsEnabled + | Qt.ItemIsSelectable + | Qt.ItemIsUserCheckable + | Qt.ItemIsDragEnabled + | Qt.ItemIsDropEnabled + ) def supportedDragActions(self): return Qt.MoveAction | Qt.CopyAction def mimeTypes(self): - return ['text/plain', 'text/uri-list'] + return ["text/plain", "text/uri-list"] def mimeData(self, indexes): - data = '' + data = "" for index in indexes: parent_item = self.getItem(index.parent()) if parent_item == self.rootItem: data += "{0},{1},{2}/".format(index.row(), index.column(), -1) else: - data += "{0},{1},{2}/".format(index.row(), index.column(), self.rootItem.index_of(parent_item)) + data += "{0},{1},{2}/".format( + index.row(), index.column(), self.rootItem.index_of(parent_item) + ) mime_data = QMimeData() mime_data.setText(data) return mime_data @@ -216,8 +227,13 @@ def dropMimeData(self, mimedata, action, row, column, parentIndex): continue if contains_files and contains_groups: - QMessageBox.information(QWidget(), self.tr("Drag not supported"), - self.tr("You can only drag/drop groups or protocols, no mixtures of both.")) + QMessageBox.information( + QWidget(), + self.tr("Drag not supported"), + self.tr( + "You can only drag/drop groups or protocols, no mixtures of both." + ), + ) return False drag_nodes.append(node) @@ -261,7 +277,10 @@ def dropMimeData(self, mimedata, action, row, column, parentIndex): # Can't drop groups on files return False - elif parent_node.containsChilds(drag_nodes) and drop_node in parent_node.children: + elif ( + parent_node.containsChilds(drag_nodes) + and drop_node in parent_node.children + ): # "Nodes on node in parent folder dropped" pos = parent_node.index_of(drop_node) parent_node.bringChildsToIndex(pos, drag_nodes) @@ -300,13 +319,19 @@ def removeRows(self, row, count, parentIndex=None, *args, **kwargs): def addGroup(self, name="New group"): self.rootItem.addGroup(name) child_nr = self.rootItem.childCount() - 1 - self.group_added.emit(self.createIndex(child_nr, 0, self.rootItem.child(child_nr))) + self.group_added.emit( + self.createIndex(child_nr, 0, self.rootItem.child(child_nr)) + ) def delete_group(self, group_item: ProtocolTreeItem): if self.rootItem.childCount() == 1: - QMessageBox.critical(self.controller, self.tr("Group not deletable"), - self.tr( - "You can't delete the last group. Think about the children, they would be homeless!")) + QMessageBox.critical( + self.controller, + self.tr("Group not deletable"), + self.tr( + "You can't delete the last group. Think about the children, they would be homeless!" + ), + ) return group_id = self.rootItem.index_of(group_item) diff --git a/src/urh/models/RulesetTableModel.py b/src/urh/models/RulesetTableModel.py index 34f437ccb3..559ee72efc 100644 --- a/src/urh/models/RulesetTableModel.py +++ b/src/urh/models/RulesetTableModel.py @@ -4,7 +4,7 @@ class RulesetTableModel(QAbstractTableModel): - header_labels = ["Start", 'End', "Viewtype", "Operator", 'Value'] + header_labels = ["Start", "End", "Viewtype", "Operator", "Value"] def __init__(self, ruleset: Ruleset, operator_descriptions: list, parent=None): self.ruleset = ruleset @@ -15,10 +15,10 @@ def update(self): self.beginResetModel() self.endResetModel() - def columnCount(self, parent: QModelIndex=None, *args, **kwargs): + def columnCount(self, parent: QModelIndex = None, *args, **kwargs): return len(self.header_labels) - def rowCount(self, parent: QModelIndex=None, *args, **kwargs): + def rowCount(self, parent: QModelIndex = None, *args, **kwargs): return len(self.ruleset) def headerData(self, section, orientation, role=Qt.DisplayRole): diff --git a/src/urh/models/SimulatorMessageFieldModel.py b/src/urh/models/SimulatorMessageFieldModel.py index 70835b473e..f45472b065 100644 --- a/src/urh/models/SimulatorMessageFieldModel.py +++ b/src/urh/models/SimulatorMessageFieldModel.py @@ -11,14 +11,14 @@ class SimulatorMessageFieldModel(QAbstractTableModel): - header_labels = ['Name', 'Display format', 'Value type', 'Value'] + header_labels = ["Name", "Display format", "Value type", "Value"] protocol_label_updated = pyqtSignal(SimulatorProtocolLabel) def __init__(self, controller, parent=None): super().__init__(parent) - self.controller = controller # type: SimulatorTabController + self.controller = controller # type: SimulatorTabController self.message_type = None # type: MessageType def update(self): @@ -26,10 +26,10 @@ def update(self): self.message_type = self.controller.active_item.message_type self.endResetModel() - def columnCount(self, parent: QModelIndex=None, *args, **kwargs): + def columnCount(self, parent: QModelIndex = None, *args, **kwargs): return len(self.header_labels) - def rowCount(self, parent: QModelIndex=None, *args, **kwargs): + def rowCount(self, parent: QModelIndex = None, *args, **kwargs): return len(self.message_type) if self.message_type is not None else 0 def headerData(self, section, orientation, role=Qt.DisplayRole): @@ -59,11 +59,13 @@ def data(self, index: QModelIndex, role=Qt.DisplayRole): message = lbl.parent() try: - data = message.plain_bits[lbl.start:lbl.end] + data = message.plain_bits[lbl.start : lbl.end] except IndexError: return None - return util.convert_bits_to_string(data, lbl.display_format_index, pad_zeros=True) + return util.convert_bits_to_string( + data, lbl.display_format_index, pad_zeros=True + ) elif lbl.value_type_index == 1: return "-" elif lbl.value_type_index == 2: @@ -71,7 +73,12 @@ def data(self, index: QModelIndex, role=Qt.DisplayRole): elif lbl.value_type_index == 3: return lbl.external_program elif lbl.value_type_index == 4: - return "Range (Decimal): " + str(lbl.random_min) + " - " + str(lbl.random_max) + return ( + "Range (Decimal): " + + str(lbl.random_min) + + " - " + + str(lbl.random_max) + ) elif role == Qt.EditRole: if j == 0: return lbl.name @@ -99,8 +106,12 @@ def data(self, index: QModelIndex, role=Qt.DisplayRole): if j == 0: return settings.LABEL_COLORS[lbl.color_index] elif j == 3: - if (lbl.value_type_index == 2 and - not self.controller.sim_expression_parser.validate_expression(lbl.formula)[0]): + if ( + lbl.value_type_index == 2 + and not self.controller.sim_expression_parser.validate_expression( + lbl.formula + )[0] + ): return settings.ERROR_BG_COLOR elif role == Qt.TextColorRole: if self.link_index(index): @@ -122,7 +133,9 @@ def setData(self, index: QModelIndex, value, role=None): if j == 0: label.name = value - ft = self.controller.field_types_by_caption.get(value, FieldType("Custom", FieldType.Function.CUSTOM)) + ft = self.controller.field_types_by_caption.get( + value, FieldType("Custom", FieldType.Function.CUSTOM) + ) label.field_type = ft elif j == 1: label.display_format_index = value @@ -132,10 +145,13 @@ def setData(self, index: QModelIndex, value, role=None): if label.value_type_index == 0: message = label.parent() try: - bits = util.convert_string_to_bits(value, label.display_format_index, - target_num_bits=label.end-label.start) + bits = util.convert_string_to_bits( + value, + label.display_format_index, + target_num_bits=label.end - label.start, + ) - message.plain_bits[label.start:label.end] = bits + message.plain_bits[label.start : label.end] = bits except ValueError: pass elif label.value_type_index == 2: @@ -145,8 +161,7 @@ def setData(self, index: QModelIndex, value, role=None): elif label.value_type_index == 4: label.random_min = value[0] label.random_max = value[1] - self.dataChanged.emit(self.index(i, 0), - self.index(i, self.columnCount())) + self.dataChanged.emit(self.index(i, 0), self.index(i, self.columnCount())) self.protocol_label_updated.emit(label) return True @@ -160,7 +175,7 @@ def flags(self, index: QModelIndex): flags = Qt.ItemIsEnabled | Qt.ItemIsSelectable - if not(col == 3 and label.value_type_index == 1): + if not (col == 3 and label.value_type_index == 1): flags |= Qt.ItemIsEditable return flags diff --git a/src/urh/models/SimulatorMessageTableModel.py b/src/urh/models/SimulatorMessageTableModel.py index 757555dda7..c2f7790579 100644 --- a/src/urh/models/SimulatorMessageTableModel.py +++ b/src/urh/models/SimulatorMessageTableModel.py @@ -5,6 +5,7 @@ from urh.models.TableModel import TableModel from urh.signalprocessing.ProtocolAnalyzer import ProtocolAnalyzer + class SimulatorMessageTableModel(TableModel): def __init__(self, project_manager, parent=None): super().__init__(None, parent) @@ -40,9 +41,13 @@ def refresh_vertical_header(self): participant_name = msg.participant.shortname if msg.participant else "?" destination_name = msg.destination.shortname if msg.destination else "?" - self.vertical_header_text[i] = "{0} ({1} -> {2})".format(msg.index(), participant_name, destination_name) + self.vertical_header_text[i] = "{0} ({1} -> {2})".format( + msg.index(), participant_name, destination_name + ) - def delete_range(self, msg_start: int, msg_end: int, index_start: int, index_end: int): + def delete_range( + self, msg_start: int, msg_end: int, index_start: int, index_end: int + ): removable_messages = [] if msg_start > msg_end: @@ -53,9 +58,16 @@ def delete_range(self, msg_start: int, msg_end: int, index_start: int, index_end for i in range(msg_start, msg_end + 1): try: - bs, be = self.protocol.convert_range(index_start, index_end, self.proto_view, 0, self.decode, message_indx=i) + bs, be = self.protocol.convert_range( + index_start, + index_end, + self.proto_view, + 0, + self.decode, + message_indx=i, + ) self.protocol.messages[i].clear_decoded_bits() - del self.protocol.messages[i][bs:be + 1] + del self.protocol.messages[i][bs : be + 1] if len(self.protocol.messages[i]) == 0: removable_messages.append(self.protocol.messages[i]) @@ -84,4 +96,4 @@ def flags(self, index: QModelIndex): else: return Qt.ItemIsEnabled | Qt.ItemIsSelectable else: - return Qt.NoItemFlags \ No newline at end of file + return Qt.NoItemFlags diff --git a/src/urh/models/SimulatorParticipantListModel.py b/src/urh/models/SimulatorParticipantListModel.py index f3ed368a0f..c522b21d9a 100644 --- a/src/urh/models/SimulatorParticipantListModel.py +++ b/src/urh/models/SimulatorParticipantListModel.py @@ -5,7 +5,6 @@ class SimulatorParticipantListModel(QAbstractListModel): - participant_simulate_changed = pyqtSignal(Participant) def __init__(self, config: SimulatorConfiguration, parent=None): diff --git a/src/urh/models/TableModel.py b/src/urh/models/TableModel.py index 8d913a92de..c6d2329b3f 100644 --- a/src/urh/models/TableModel.py +++ b/src/urh/models/TableModel.py @@ -78,7 +78,9 @@ def proto_view(self, value): def get_alignment_offset_at(self, index: int): f = 1 if self.proto_view == 0 else 4 if self.proto_view == 1 else 8 - alignment_offset = int(math.ceil(self.protocol.messages[index].alignment_offset / f)) + alignment_offset = int( + math.ceil(self.protocol.messages[index].alignment_offset / f) + ) return alignment_offset def __pad_until_index(self, row: int, bit_pos: int): @@ -87,14 +89,23 @@ def __pad_until_index(self, row: int, bit_pos: int): :return: """ try: - new_bits = array.array("B", [0] * max(0, bit_pos - len(self.protocol.messages[row]))) + new_bits = array.array( + "B", [0] * max(0, bit_pos - len(self.protocol.messages[row])) + ) if len(new_bits) == 0: return True - self.protocol.messages[row].plain_bits = self.protocol.messages[row].plain_bits + new_bits + self.protocol.messages[row].plain_bits = ( + self.protocol.messages[row].plain_bits + new_bits + ) msg = self.protocol.messages[row] - self.display_data[ - row] = msg.plain_bits if self.proto_view == 0 else msg.plain_hex_array if self.proto_view == 1 else msg.plain_ascii_array + self.display_data[row] = ( + msg.plain_bits + if self.proto_view == 0 + else msg.plain_hex_array + if self.proto_view == 1 + else msg.plain_ascii_array + ) except IndexError: return False @@ -110,7 +121,11 @@ def headerData(self, section: int, orientation, role=Qt.DisplayRole): color = self.vertical_header_colors[section] if color: red, green, blue = color.red(), color.green(), color.blue() - return QColor("black") if (red * 0.299 + green * 0.587 + blue * 0.114) > 186 else QColor("white") + return ( + QColor("black") + if (red * 0.299 + green * 0.587 + blue * 0.114) > 186 + else QColor("white") + ) else: return None @@ -122,26 +137,45 @@ def update(self): if self.protocol.num_messages > 0: if self.decode: if self.proto_view == 0: - self.display_data = [msg.decoded_bits for msg in self.protocol.messages] + self.display_data = [ + msg.decoded_bits for msg in self.protocol.messages + ] elif self.proto_view == 1: - self.display_data = [msg.decoded_hex_array for msg in self.protocol.messages] + self.display_data = [ + msg.decoded_hex_array for msg in self.protocol.messages + ] elif self.proto_view == 2: - self.display_data = [msg.decoded_ascii_array for msg in self.protocol.messages] + self.display_data = [ + msg.decoded_ascii_array for msg in self.protocol.messages + ] else: # Generator Model if self.proto_view == 0: - self.display_data = [msg.plain_bits for msg in self.protocol.messages] + self.display_data = [ + msg.plain_bits for msg in self.protocol.messages + ] elif self.proto_view == 1: - self.display_data = [msg.plain_hex_array for msg in self.protocol.messages] + self.display_data = [ + msg.plain_hex_array for msg in self.protocol.messages + ] else: - self.display_data = [msg.plain_ascii_array for msg in self.protocol.messages] - - visible_messages = [msg for i, msg in enumerate(self.display_data) if i not in self.hidden_rows] + self.display_data = [ + msg.plain_ascii_array for msg in self.protocol.messages + ] + + visible_messages = [ + msg + for i, msg in enumerate(self.display_data) + if i not in self.hidden_rows + ] if len(visible_messages) == 0: self.col_count = 0 else: - self.col_count = max(len(msg) + self.get_alignment_offset_at(i) - for i, msg in enumerate(self.display_data) if i not in self.hidden_rows) + self.col_count = max( + len(msg) + self.get_alignment_offset_at(i) + for i, msg in enumerate(self.display_data) + if i not in self.hidden_rows + ) if self._refindex >= 0: self._diffs = self.find_differences(self._refindex) @@ -207,8 +241,12 @@ def refresh_vertical_header(self): except IndexError: participant = None if participant: - self.vertical_header_text[i] = "{0} ({1})".format(i + 1, participant.shortname) - self.vertical_header_colors[i] = settings.PARTICIPANT_COLORS[participant.color_index] + self.vertical_header_text[i] = "{0} ({1})".format( + i + 1, participant.shortname + ) + self.vertical_header_colors[i] = settings.PARTICIPANT_COLORS[ + participant.color_index + ] use_colors = True else: self.vertical_header_text[i] = str(i + 1) @@ -262,19 +300,27 @@ def data(self, index: QModelIndex, role=Qt.DisplayRole): def get_tooltip(self, row: int, column: int) -> str: msg = self.protocol.messages[row] try: - lbl = next(lbl for lbl in msg.message_type - if column in range(*msg.get_label_range(lbl, self.proto_view, self.decode))) + lbl = next( + lbl + for lbl in msg.message_type + if column + in range(*msg.get_label_range(lbl, self.proto_view, self.decode)) + ) except StopIteration: return "" result = lbl.name if isinstance(lbl, ChecksumLabel): - calculated_crc = lbl.calculate_checksum_for_message(msg, use_decoded_bits=self.decode) + calculated_crc = lbl.calculate_checksum_for_message( + msg, use_decoded_bits=self.decode + ) start, end = msg.get_label_range(lbl=lbl, view=0, decode=self.decode) bits = msg.decoded_bits if self.decode else msg.plain_bits color = "green" if bits[start:end] == calculated_crc else "red" expected = util.convert_bits_to_string(calculated_crc, self.proto_view) - result += '
Expected {}'.format(color, expected) + result += '
Expected {}'.format( + color, expected + ) return result @@ -286,22 +332,55 @@ def setData(self, index: QModelIndex, value, role=Qt.DisplayRole): j = index.column() a = self.get_alignment_offset_at(i) j -= a - hex_chars = ("0", "1", "2", "3", "4", "5", "6", "7", "8", "9", "a", "b", "c", "d", "e", "f") + hex_chars = ( + "0", + "1", + "2", + "3", + "4", + "5", + "6", + "7", + "8", + "9", + "a", + "b", + "c", + "d", + "e", + "f", + ) if i >= len(self.protocol.messages): return False - if self.proto_view == 0 and value in ("0", "1") and self.__pad_until_index(i, j + 1): + if ( + self.proto_view == 0 + and value in ("0", "1") + and self.__pad_until_index(i, j + 1) + ): self.protocol.messages[i][j] = bool(int(value)) self.display_data[i][j] = int(value) - elif self.proto_view == 1 and value in hex_chars and self.__pad_until_index(i, (j + 1) * 4): - converted_j = self.protocol.convert_index(j, 1, 0, self.decode, message_indx=i)[0] + elif ( + self.proto_view == 1 + and value in hex_chars + and self.__pad_until_index(i, (j + 1) * 4) + ): + converted_j = self.protocol.convert_index( + j, 1, 0, self.decode, message_indx=i + )[0] bits = "{0:04b}".format(int(value, 16)) for k in range(4): self.protocol.messages[i][converted_j + k] = bool(int(bits[k])) self.display_data[i][j] = int(value, 16) - elif self.proto_view == 2 and len(value) == 1 and self.__pad_until_index(i, (j + 1) * 8): - converted_j = self.protocol.convert_index(j, 2, 0, self.decode, message_indx=i)[0] + elif ( + self.proto_view == 2 + and len(value) == 1 + and self.__pad_until_index(i, (j + 1) * 8) + ): + converted_j = self.protocol.convert_index( + j, 2, 0, self.decode, message_indx=i + )[0] bits = "{0:08b}".format(ord(value)) for k in range(8): self.protocol.messages[i][converted_j + k] = bool(int(bits[k])) @@ -363,10 +442,13 @@ def find_differences(self, refindex: int): continue msg_offset = self.get_alignment_offset_at(i) - short, long = sorted([len(ref_message) + ref_offset, len(message) + msg_offset]) + short, long = sorted( + [len(ref_message) + ref_offset, len(message) + msg_offset] + ) differences[i] = { - j for j in range(max(msg_offset, ref_offset), long) + j + for j in range(max(msg_offset, ref_offset), long) if j >= short or message[j - msg_offset] != ref_message[j - ref_offset] } diff --git a/src/urh/models/__init__.py b/src/urh/models/__init__.py index 3fa5af38d8..813939aaf7 100644 --- a/src/urh/models/__init__.py +++ b/src/urh/models/__init__.py @@ -1 +1 @@ -__author__ = 'joe' +__author__ = "joe" diff --git a/src/urh/plugins/FlipperZeroSub/FlipperZeroSubPlugin.py b/src/urh/plugins/FlipperZeroSub/FlipperZeroSubPlugin.py index 268fbfbf2d..b89cd15475 100644 --- a/src/urh/plugins/FlipperZeroSub/FlipperZeroSubPlugin.py +++ b/src/urh/plugins/FlipperZeroSub/FlipperZeroSubPlugin.py @@ -1,6 +1,7 @@ import os import sys import time + # from subprocess import PIPE, Popen # from threading import Thread @@ -13,6 +14,7 @@ from urh.util.Errors import Errors from urh.util.Logger import logger + class FlipperZeroSubPlugin(SDRPlugin): def __init__(self): super().__init__(name="FlipperZeroSub") @@ -21,7 +23,7 @@ def __init__(self): self.protocol = "RAW" self.max_values_per_line = 512 - def getFuriHalString(self, modulation_type, given_bandwidth_deviation = 0): + def getFuriHalString(self, modulation_type, given_bandwidth_deviation=0): if modulation_type == "ASK": if given_bandwidth_deviation > 500: # OOK, bandwidth 650kHz, asynchronous @@ -53,7 +55,9 @@ def getFuriHalString(self, modulation_type, given_bandwidth_deviation = 0): bandwidth_deviation = 650 return FuriHalString, bandwidth_deviation - def write_sub_file(self, filename, messages, sample_rates, modulators, project_manager): + def write_sub_file( + self, filename, messages, sample_rates, modulators, project_manager + ): # Check whether the message != NULL if len(messages) == 0: logger.debug("Empty signal!") @@ -67,10 +71,12 @@ def write_sub_file(self, filename, messages, sample_rates, modulators, project_m return False # Get Flipper Zero FuriHal Preset and its datarate - frequency = int( project_manager.device_conf['frequency'] ) - #samplerate = sample_rates[0] + frequency = int(project_manager.device_conf["frequency"]) + # samplerate = sample_rates[0] samples_per_symbol = messages[0].samples_per_symbol - preset, bandwidth_deviation = self.getFuriHalString( modulators[messages[0].modulator_index].modulation_type, 1000) # TODO: last parameter is bandwidth/deviation of preset profile. Hardcoded to 1000 until it becomes clear how to find the value from signal data properly + preset, bandwidth_deviation = self.getFuriHalString( + modulators[messages[0].modulator_index].modulation_type, 1000 + ) # TODO: last parameter is bandwidth/deviation of preset profile. Hardcoded to 1000 until it becomes clear how to find the value from signal data properly # Write Flipper Zero SubGHz protocol header file.write(f"Filetype: {self.filetype}\n") @@ -89,7 +95,9 @@ def write_sub_file(self, filename, messages, sample_rates, modulators, project_m current_count += 1 else: # Append to signal when bit changes - signal.append(current_count if current_value == 1 else -current_count) + signal.append( + current_count if current_value == 1 else -current_count + ) current_count = 1 current_value = bit # Last pulse @@ -103,4 +111,4 @@ def write_sub_file(self, filename, messages, sample_rates, modulators, project_m file.write(f" {signal[i] * samples_per_symbol}") # Close file - file.close() \ No newline at end of file + file.close() diff --git a/src/urh/plugins/InsertSine/InsertSinePlugin.py b/src/urh/plugins/InsertSine/InsertSinePlugin.py index 941e55cb61..b354d945c2 100644 --- a/src/urh/plugins/InsertSine/InsertSinePlugin.py +++ b/src/urh/plugins/InsertSine/InsertSinePlugin.py @@ -20,7 +20,6 @@ class InsertSinePlugin(SignalEditorPlugin): INSERT_INDICATOR_COLOR = QColor(0, 255, 0, 80) def __init__(self): - self.__dialog_ui = None # type: QDialog self.complex_wave = None @@ -39,10 +38,16 @@ def __init__(self): @property def dialog_ui(self) -> QDialog: if self.__dialog_ui is None: - dir_name = os.path.dirname(os.readlink(__file__)) if os.path.islink(__file__) else os.path.dirname(__file__) + dir_name = ( + os.path.dirname(os.readlink(__file__)) + if os.path.islink(__file__) + else os.path.dirname(__file__) + ) logging.getLogger().setLevel(logging.WARNING) - self.__dialog_ui = uic.loadUi(os.path.realpath(os.path.join(dir_name, "insert_sine_dialog.ui"))) + self.__dialog_ui = uic.loadUi( + os.path.realpath(os.path.join(dir_name, "insert_sine_dialog.ui")) + ) logging.getLogger().setLevel(logger.level) self.__dialog_ui.setAttribute(Qt.WA_DeleteOnClose) @@ -58,9 +63,14 @@ def dialog_ui(self) -> QDialog: scene_manager = SceneManager(self.dialog_ui.graphicsViewSineWave) self.__dialog_ui.graphicsViewSineWave.scene_manager = scene_manager - self.insert_indicator = scene_manager.scene.addRect(0, -2, 0, 4, - QPen(QColor(Qt.transparent), 0), - QBrush(self.INSERT_INDICATOR_COLOR)) + self.insert_indicator = scene_manager.scene.addRect( + 0, + -2, + 0, + 4, + QPen(QColor(Qt.transparent), 0), + QBrush(self.INSERT_INDICATOR_COLOR), + ) self.insert_indicator.stackBefore(scene_manager.scene.selection_area) self.set_time() @@ -125,19 +135,30 @@ def create_connects(self): def create_dialog_connects(self): self.dialog_ui.doubleSpinBoxAmplitude.editingFinished.connect( - self.on_double_spin_box_amplitude_editing_finished) + self.on_double_spin_box_amplitude_editing_finished + ) self.dialog_ui.doubleSpinBoxFrequency.editingFinished.connect( - self.on_double_spin_box_frequency_editing_finished) - self.dialog_ui.doubleSpinBoxPhase.editingFinished.connect(self.on_double_spin_box_phase_editing_finished) + self.on_double_spin_box_frequency_editing_finished + ) + self.dialog_ui.doubleSpinBoxPhase.editingFinished.connect( + self.on_double_spin_box_phase_editing_finished + ) self.dialog_ui.doubleSpinBoxSampleRate.editingFinished.connect( - self.on_double_spin_box_sample_rate_editing_finished) - self.dialog_ui.doubleSpinBoxNSamples.editingFinished.connect(self.on_spin_box_n_samples_editing_finished) - self.dialog_ui.lineEditTime.editingFinished.connect(self.on_line_edit_time_editing_finished) + self.on_double_spin_box_sample_rate_editing_finished + ) + self.dialog_ui.doubleSpinBoxNSamples.editingFinished.connect( + self.on_spin_box_n_samples_editing_finished + ) + self.dialog_ui.lineEditTime.editingFinished.connect( + self.on_line_edit_time_editing_finished + ) self.dialog_ui.buttonBox.accepted.connect(self.on_button_box_accept) self.dialog_ui.buttonBox.rejected.connect(self.on_button_box_reject) self.__dialog_ui.finished.connect(self.on_dialog_finished) - def get_insert_sine_dialog(self, original_data, position, sample_rate=None, num_samples=None) -> QDialog: + def get_insert_sine_dialog( + self, original_data, position, sample_rate=None, num_samples=None + ) -> QDialog: if sample_rate is not None: self.__sample_rate = sample_rate self.dialog_ui.doubleSpinBoxSampleRate.setValue(sample_rate) @@ -168,11 +189,20 @@ def draw_sine_wave(self): self.complex_wave = np.empty(len(arg), dtype=np.complex64) self.complex_wave.real = np.cos(arg) self.complex_wave.imag = np.sin(arg) - self.complex_wave = IQArray(self.amplitude * self.complex_wave).convert_to(self.original_data.dtype) - - self.draw_data = np.insert(self.original_data[:, 0], self.position, self.complex_wave[:, 0]) - y, h = self.dialog_ui.graphicsViewSineWave.view_rect().y(), self.dialog_ui.graphicsViewSineWave.view_rect().height() - self.insert_indicator.setRect(self.position, y - h, self.num_samples, 2 * h + abs(y)) + self.complex_wave = IQArray(self.amplitude * self.complex_wave).convert_to( + self.original_data.dtype + ) + + self.draw_data = np.insert( + self.original_data[:, 0], self.position, self.complex_wave[:, 0] + ) + y, h = ( + self.dialog_ui.graphicsViewSineWave.view_rect().y(), + self.dialog_ui.graphicsViewSineWave.view_rect().height(), + ) + self.insert_indicator.setRect( + self.position, y - h, self.num_samples, 2 * h + abs(y) + ) self.__set_status_of_editable_elements(enabled=True) QApplication.instance().restoreOverrideCursor() @@ -180,13 +210,26 @@ def draw_sine_wave(self): self.dialog_ui.graphicsViewSineWave.show_full_scene() def __set_status_of_editable_elements(self, enabled: bool): - for obj in ("doubleSpinBoxAmplitude", "doubleSpinBoxFrequency", "doubleSpinBoxPhase", - "doubleSpinBoxSampleRate", "doubleSpinBoxNSamples", "lineEditTime", "buttonBox"): + for obj in ( + "doubleSpinBoxAmplitude", + "doubleSpinBoxFrequency", + "doubleSpinBoxPhase", + "doubleSpinBoxSampleRate", + "doubleSpinBoxNSamples", + "lineEditTime", + "buttonBox", + ): getattr(self.dialog_ui, obj).setEnabled(enabled) def set_time(self): - self.dialog_ui.lineEditTime.setText(Formatter.science_time(self.num_samples / self.sample_rate, decimals=3, - append_seconds=False, remove_spaces=True)) + self.dialog_ui.lineEditTime.setText( + Formatter.science_time( + self.num_samples / self.sample_rate, + decimals=3, + append_seconds=False, + remove_spaces=True, + ) + ) @pyqtSlot() def on_double_spin_box_amplitude_editing_finished(self): @@ -221,7 +264,15 @@ def on_line_edit_time_editing_finished(self): except ValueError: return - factor = 10 ** -9 if suffix == "n" else 10 ** -6 if suffix == "µ" else 10 ** -3 if suffix == "m" else 1 + factor = ( + 10**-9 + if suffix == "n" + else 10**-6 + if suffix == "µ" + else 10**-3 + if suffix == "m" + else 1 + ) time_val = t * factor if self.sample_rate * time_val >= 1: diff --git a/src/urh/plugins/MessageBreak/MessageBreakAction.py b/src/urh/plugins/MessageBreak/MessageBreakAction.py index 9cf58b5cb1..4a5a4007e2 100644 --- a/src/urh/plugins/MessageBreak/MessageBreakAction.py +++ b/src/urh/plugins/MessageBreak/MessageBreakAction.py @@ -18,12 +18,22 @@ def __init__(self, proto_analyzer: ProtocolAnalyzer, msg_nr: int, pos: int): def redo(self): message = self.proto_analyzer.messages[self.msg_nr] - message1 = Message(plain_bits=message.plain_bits[:self.pos], pause=0, - rssi=message.rssi, decoder=message.decoder, message_type=message.message_type, - samples_per_symbol=message.samples_per_symbol) - message2 = Message(plain_bits=message.plain_bits[self.pos:], pause=message.pause, - rssi=message.rssi, decoder=message.decoder, message_type=message.message_type, - samples_per_symbol=message.samples_per_symbol) + message1 = Message( + plain_bits=message.plain_bits[: self.pos], + pause=0, + rssi=message.rssi, + decoder=message.decoder, + message_type=message.message_type, + samples_per_symbol=message.samples_per_symbol, + ) + message2 = Message( + plain_bits=message.plain_bits[self.pos :], + pause=message.pause, + rssi=message.rssi, + decoder=message.decoder, + message_type=message.message_type, + samples_per_symbol=message.samples_per_symbol, + ) self.proto_analyzer.messages[self.msg_nr] = message1 self.proto_analyzer.messages.insert(self.msg_nr + 1, message2) diff --git a/src/urh/plugins/MessageBreak/MessageBreakPlugin.py b/src/urh/plugins/MessageBreak/MessageBreakPlugin.py index 3cbbf5b0b9..33e0660cfb 100644 --- a/src/urh/plugins/MessageBreak/MessageBreakPlugin.py +++ b/src/urh/plugins/MessageBreak/MessageBreakPlugin.py @@ -13,7 +13,14 @@ def __init__(self): self.command = None """:type: QUndoAction """ - def get_action(self, parent, undo_stack: QUndoStack, sel_range, protocol: ProtocolAnalyzer, view: int): + def get_action( + self, + parent, + undo_stack: QUndoStack, + sel_range, + protocol: ProtocolAnalyzer, + view: int, + ): """ :type parent: QTableView :type undo_stack: QUndoStack diff --git a/src/urh/plugins/MessageBreak/__init__.py b/src/urh/plugins/MessageBreak/__init__.py index 3fa5af38d8..813939aaf7 100644 --- a/src/urh/plugins/MessageBreak/__init__.py +++ b/src/urh/plugins/MessageBreak/__init__.py @@ -1 +1 @@ -__author__ = 'joe' +__author__ = "joe" diff --git a/src/urh/plugins/NetworkSDRInterface/NetworkSDRInterfacePlugin.py b/src/urh/plugins/NetworkSDRInterface/NetworkSDRInterfacePlugin.py index d80a87661e..8b0ba69dbb 100644 --- a/src/urh/plugins/NetworkSDRInterface/NetworkSDRInterfacePlugin.py +++ b/src/urh/plugins/NetworkSDRInterface/NetworkSDRInterfacePlugin.py @@ -43,34 +43,54 @@ def handle(self): if hasattr(self.server, "received_bits"): for data in filter(None, self.data.split(b"\n")): - self.server.received_bits.append(NetworkSDRInterfacePlugin.bytearray_to_bit_str(data)) + self.server.received_bits.append( + NetworkSDRInterfacePlugin.bytearray_to_bit_str(data) + ) else: while len(self.data) % size != 0: self.data += self.request.recv(len(self.data) % size) - received = np.frombuffer(self.data, dtype=NetworkSDRInterfacePlugin.DATA_TYPE) - received = received.reshape((len(received)//2, 2)) + received = np.frombuffer( + self.data, dtype=NetworkSDRInterfacePlugin.DATA_TYPE + ) + received = received.reshape((len(received) // 2, 2)) - if len(received) + self.server.current_receive_index >= len(self.server.receive_buffer): + if len(received) + self.server.current_receive_index >= len( + self.server.receive_buffer + ): self.server.current_receive_index = 0 self.server.receive_buffer[ - self.server.current_receive_index:self.server.current_receive_index + len(received)] = received + self.server.current_receive_index : self.server.current_receive_index + + len(received) + ] = received self.server.current_receive_index += len(received) - def __init__(self, raw_mode=False, resume_on_full_receive_buffer=False, spectrum=False, sending=False): + def __init__( + self, + raw_mode=False, + resume_on_full_receive_buffer=False, + spectrum=False, + sending=False, + ): """ :param raw_mode: If true, sending and receiving raw samples if false bits are received/sent """ super().__init__(name="NetworkSDRInterface") - self.client_ip = self.qsettings.value("client_ip", defaultValue="127.0.0.1", type=str) + self.client_ip = self.qsettings.value( + "client_ip", defaultValue="127.0.0.1", type=str + ) self.server_ip = "" self.samples_to_send = None # set in virtual device constructor - self.client_port = self.qsettings.value("client_port", defaultValue=2222, type=int) - self.server_port = self.qsettings.value("server_port", defaultValue=4444, type=int) + self.client_port = self.qsettings.value( + "client_port", defaultValue=2222, type=int + ) + self.server_port = self.qsettings.value( + "server_port", defaultValue=4444, type=int + ) self.is_in_spectrum_mode = spectrum self.resume_on_full_receive_buffer = resume_on_full_receive_buffer @@ -88,18 +108,29 @@ def __init__(self, raw_mode=False, resume_on_full_receive_buffer=False, spectrum self.raw_mode = raw_mode if not sending: if self.raw_mode: - num_samples = settings.get_receive_buffer_size(self.resume_on_full_receive_buffer, - self.is_in_spectrum_mode) + num_samples = settings.get_receive_buffer_size( + self.resume_on_full_receive_buffer, self.is_in_spectrum_mode + ) try: - self.receive_buffer = IQArray(None, dtype=self.DATA_TYPE, n=num_samples) + self.receive_buffer = IQArray( + None, dtype=self.DATA_TYPE, n=num_samples + ) except MemoryError: - logger.warning("Could not allocate buffer with {0:d} samples, trying less...") + logger.warning( + "Could not allocate buffer with {0:d} samples, trying less..." + ) i = 0 while True: try: i += 2 - self.receive_buffer = IQArray(None, dtype=self.DATA_TYPE, n=num_samples // i) - logger.debug("Using buffer with {0:d} samples instead.".format(num_samples // i)) + self.receive_buffer = IQArray( + None, dtype=self.DATA_TYPE, n=num_samples // i + ) + logger.debug( + "Using buffer with {0:d} samples instead.".format( + num_samples // i + ) + ) break except MemoryError: continue @@ -118,12 +149,16 @@ def is_sending(self, value: bool): @property def sending_finished(self) -> bool: - return self.current_sending_repeat >= self.sending_repeats if self.sending_repeats > 0 else False + return ( + self.current_sending_repeat >= self.sending_repeats + if self.sending_repeats > 0 + else False + ) @property def received_data(self): if self.raw_mode: - return self.receive_buffer[:self.current_receive_index] + return self.receive_buffer[: self.current_receive_index] else: return self.received_bits @@ -152,15 +187,27 @@ def create_connects(self): self.settings_frame.spinBoxClientPort.setValue(self.client_port) self.settings_frame.spinBoxServerPort.setValue(self.server_port) - self.settings_frame.lineEditClientIP.editingFinished.connect(self.on_linedit_client_ip_editing_finished) - self.settings_frame.lineEditServerIP.editingFinished.connect(self.on_linedit_server_ip_editing_finished) - self.settings_frame.spinBoxClientPort.editingFinished.connect(self.on_spinbox_client_port_editing_finished) - self.settings_frame.spinBoxServerPort.editingFinished.connect(self.on_spinbox_server_port_editing_finished) - - self.settings_frame.lOpenProtoSniffer.linkActivated.connect(self.on_lopenprotosniffer_link_activated) + self.settings_frame.lineEditClientIP.editingFinished.connect( + self.on_linedit_client_ip_editing_finished + ) + self.settings_frame.lineEditServerIP.editingFinished.connect( + self.on_linedit_server_ip_editing_finished + ) + self.settings_frame.spinBoxClientPort.editingFinished.connect( + self.on_spinbox_client_port_editing_finished + ) + self.settings_frame.spinBoxServerPort.editingFinished.connect( + self.on_spinbox_server_port_editing_finished + ) + + self.settings_frame.lOpenProtoSniffer.linkActivated.connect( + self.on_lopenprotosniffer_link_activated + ) def start_tcp_server_for_receiving(self): - self.server = socketserver.TCPServer((self.server_ip, self.server_port), self.MyTCPHandler) + self.server = socketserver.TCPServer( + (self.server_ip, self.server_port), self.MyTCPHandler + ) self.server.socket.setsockopt(socket.IPPROTO_TCP, socket.TCP_NODELAY, 1) if self.raw_mode: self.server.receive_buffer = self.receive_buffer @@ -193,7 +240,9 @@ def send_data(self, data, sock: socket.socket) -> str: def send_raw_data(self, data: IQArray, num_repeats: int): byte_data = data.to_bytes() - rng = iter(int, 1) if num_repeats <= 0 else range(0, num_repeats) # <= 0 = forever + rng = ( + iter(int, 1) if num_repeats <= 0 else range(0, num_repeats) + ) # <= 0 = forever sock = self.prepare_send_connection() if sock is None: @@ -230,8 +279,12 @@ def shutdown_socket(sock): pass sock.close() - def send_raw_data_continuously(self, ring_buffer: RingBuffer, num_samples_to_send: int, num_repeats: int): - rng = iter(int, 1) if num_repeats <= 0 else range(0, num_repeats) # <= 0 = forever + def send_raw_data_continuously( + self, ring_buffer: RingBuffer, num_samples_to_send: int, num_repeats: int + ): + rng = ( + iter(int, 1) if num_repeats <= 0 else range(0, num_repeats) + ) # <= 0 = forever samples_per_iteration = 65536 // 2 sock = self.prepare_send_connection() if sock is None: @@ -239,12 +292,16 @@ def send_raw_data_continuously(self, ring_buffer: RingBuffer, num_samples_to_sen try: for _ in rng: - if self.__sending_interrupt_requested: break - while num_samples_to_send is None or self.current_sent_sample < num_samples_to_send: - while ring_buffer.is_empty and not self.__sending_interrupt_requested: + while ( + num_samples_to_send is None + or self.current_sent_sample < num_samples_to_send + ): + while ( + ring_buffer.is_empty and not self.__sending_interrupt_requested + ): time.sleep(0.1) if self.__sending_interrupt_requested: @@ -253,7 +310,13 @@ def send_raw_data_continuously(self, ring_buffer: RingBuffer, num_samples_to_sen if num_samples_to_send is None: n = samples_per_iteration else: - n = max(0, min(samples_per_iteration, num_samples_to_send - self.current_sent_sample)) + n = max( + 0, + min( + samples_per_iteration, + num_samples_to_send - self.current_sent_sample, + ), + ) data = ring_buffer.pop(n, ensure_even_length=True) if len(data) > 0: @@ -288,7 +351,9 @@ def __send_messages(self, messages, sample_rates): wait_time = msg.pause / sample_rates[i] self.current_send_message_changed.emit(i) - error = self.send_data(self.bit_str_to_bytearray(msg.encoded_bits_str) + b"\n", sock) + error = self.send_data( + self.bit_str_to_bytearray(msg.encoded_bits_str) + b"\n", sock + ) if not error: logger.debug("Sent message {0}/{1}".format(i + 1, len(messages))) logger.debug("Waiting message pause: {0:.2f}s".format(wait_time)) @@ -296,7 +361,11 @@ def __send_messages(self, messages, sample_rates): break time.sleep(wait_time) else: - logger.critical("Could not connect to {0}:{1}".format(self.client_ip, self.client_port)) + logger.critical( + "Could not connect to {0}:{1}".format( + self.client_ip, self.client_port + ) + ) break logger.debug("Sending finished") finally: @@ -313,7 +382,9 @@ def start_message_sending_thread(self, messages, sample_rates): :return: """ self.__sending_interrupt_requested = False - self.sending_thread = threading.Thread(target=self.__send_messages, args=(messages, sample_rates)) + self.sending_thread = threading.Thread( + target=self.__send_messages, args=(messages, sample_rates) + ) self.sending_thread.daemon = True self.sending_thread.start() @@ -322,12 +393,19 @@ def start_message_sending_thread(self, messages, sample_rates): def start_raw_sending_thread(self): self.__sending_interrupt_requested = False if self.sending_is_continuous: - self.sending_thread = threading.Thread(target=self.send_raw_data_continuously, - args=(self.continuous_send_ring_buffer, - self.num_samples_to_send, self.sending_repeats)) + self.sending_thread = threading.Thread( + target=self.send_raw_data_continuously, + args=( + self.continuous_send_ring_buffer, + self.num_samples_to_send, + self.sending_repeats, + ), + ) else: - self.sending_thread = threading.Thread(target=self.send_raw_data, - args=(self.samples_to_send, self.sending_repeats)) + self.sending_thread = threading.Thread( + target=self.send_raw_data, + args=(self.samples_to_send, self.sending_repeats), + ) self.sending_thread.daemon = True self.sending_thread.start() @@ -349,26 +427,26 @@ def bytearray_to_bit_str(arr: bytearray) -> str: @staticmethod def bit_str_to_bytearray(bits: str) -> bytearray: bits += "0" * ((8 - len(bits) % 8) % 8) - return bytearray((int(bits[i:i + 8], 2) for i in range(0, len(bits), 8))) + return bytearray((int(bits[i : i + 8], 2) for i in range(0, len(bits), 8))) def on_linedit_client_ip_editing_finished(self): ip = self.settings_frame.lineEditClientIP.text() self.client_ip = ip - self.qsettings.setValue('client_ip', self.client_ip) + self.qsettings.setValue("client_ip", self.client_ip) def on_linedit_server_ip_editing_finished(self): # Does nothing, because field is disabled ip = self.settings_frame.lineEditServerIP.text() self.server_ip = ip - self.qsettings.setValue('server_ip', self.server_ip) + self.qsettings.setValue("server_ip", self.server_ip) def on_spinbox_client_port_editing_finished(self): self.client_port = self.settings_frame.spinBoxClientPort.value() - self.qsettings.setValue('client_port', str(self.client_port)) + self.qsettings.setValue("client_port", str(self.client_port)) def on_spinbox_server_port_editing_finished(self): self.server_port = self.settings_frame.spinBoxServerPort.value() - self.qsettings.setValue('server_port', str(self.server_port)) + self.qsettings.setValue("server_port", str(self.server_port)) @pyqtSlot(str) def on_lopenprotosniffer_link_activated(self, link: str): diff --git a/src/urh/plugins/Plugin.py b/src/urh/plugins/Plugin.py index 8aeba228b7..a5bbf7edc3 100644 --- a/src/urh/plugins/Plugin.py +++ b/src/urh/plugins/Plugin.py @@ -18,13 +18,17 @@ def __init__(self, name: str): self.plugin_path = "" self.description = "" self.__settings_frame = None - self.qsettings = QSettings(QSettings.IniFormat, QSettings.UserScope, "urh", self.name + "-plugin") + self.qsettings = QSettings( + QSettings.IniFormat, QSettings.UserScope, "urh", self.name + "-plugin" + ) @property def settings_frame(self): if self.__settings_frame is None: logging.getLogger().setLevel(logging.WARNING) - self.__settings_frame = uic.loadUi(os.path.join(self.plugin_path, "settings.ui")) + self.__settings_frame = uic.loadUi( + os.path.join(self.plugin_path, "settings.ui") + ) logging.getLogger().setLevel(logger.level) self.create_connects() @@ -59,8 +63,9 @@ class ProtocolPlugin(Plugin): def __init__(self, name: str): Plugin.__init__(self, name) - def get_action(self, parent, undo_stack: QUndoStack, sel_range, groups, - view: int) -> QUndoCommand: + def get_action( + self, parent, undo_stack: QUndoStack, sel_range, groups, view: int + ) -> QUndoCommand: """ :type parent: QTableView :type undo_stack: QUndoStack diff --git a/src/urh/plugins/PluginManager.py b/src/urh/plugins/PluginManager.py index c8e68914fe..af85952d51 100644 --- a/src/urh/plugins/PluginManager.py +++ b/src/urh/plugins/PluginManager.py @@ -16,9 +16,13 @@ def protocol_plugins(self): return [p for p in self.installed_plugins if isinstance(p, ProtocolPlugin)] def load_installed_plugins(self): - """ :rtype: list of Plugin """ + """:rtype: list of Plugin""" result = [] - plugin_dirs = [d for d in os.listdir(self.plugin_path) if os.path.isdir(os.path.join(self.plugin_path, d))] + plugin_dirs = [ + d + for d in os.listdir(self.plugin_path) + if os.path.isdir(os.path.join(self.plugin_path, d)) + ] for d in plugin_dirs: if d == "__pycache__": continue diff --git a/src/urh/plugins/RfCat/RfCatPlugin.py b/src/urh/plugins/RfCat/RfCatPlugin.py index 0007336dca..843c309547 100644 --- a/src/urh/plugins/RfCat/RfCatPlugin.py +++ b/src/urh/plugins/RfCat/RfCatPlugin.py @@ -36,8 +36,11 @@ # cmd_preamble = "d.setMdmNumPreamble({})".format(num_preamble) # cmd_showconfig = "print d.reprRadioConfig()" + class RfCatPlugin(SDRPlugin): - rcv_index_changed = pyqtSignal(int, int) # int arguments are just for compatibility with native and grc backend + rcv_index_changed = pyqtSignal( + int, int + ) # int arguments are just for compatibility with native and grc backend show_proto_sniff_dialog_clicked = pyqtSignal() sending_status_changed = pyqtSignal(bool) sending_stop_requested = pyqtSignal() @@ -45,7 +48,9 @@ class RfCatPlugin(SDRPlugin): def __init__(self): super().__init__(name="RfCat") - self.rfcat_executable = self.qsettings.value("rfcat_executable", defaultValue="rfcat", type=str) + self.rfcat_executable = self.qsettings.value( + "rfcat_executable", defaultValue="rfcat", type=str + ) self.rfcat_is_open = False self.initialized = False self.ready = True @@ -75,7 +80,9 @@ def rfcat_is_found(self): def is_rfcat_executable(self, rfcat_executable): fpath, fname = os.path.split(rfcat_executable) if fpath: - if os.path.isfile(rfcat_executable) and os.access(rfcat_executable, os.X_OK): + if os.path.isfile(rfcat_executable) and os.access( + rfcat_executable, os.X_OK + ): return True else: for path in os.environ["PATH"].split(os.pathsep): @@ -89,19 +96,23 @@ def enable_or_disable_send_button(self, rfcat_executable): if self.is_rfcat_executable(rfcat_executable): self.settings_frame.info.setText("Info: Executable can be opened.") else: - self.settings_frame.info.setText("Info: Executable cannot be opened! Disabling send button.") + self.settings_frame.info.setText( + "Info: Executable cannot be opened! Disabling send button." + ) logger.debug("RfCat executable cannot be opened! Disabling send button.") def create_connects(self): self.settings_frame.rfcat_executable.setText(self.rfcat_executable) - self.settings_frame.rfcat_executable.editingFinished.connect(self.on_edit_rfcat_executable_editing_finished) + self.settings_frame.rfcat_executable.editingFinished.connect( + self.on_edit_rfcat_executable_editing_finished + ) self.enable_or_disable_send_button(self.rfcat_executable) def on_edit_rfcat_executable_editing_finished(self): rfcat_executable = self.settings_frame.rfcat_executable.text() self.enable_or_disable_send_button(rfcat_executable) self.rfcat_executable = rfcat_executable - self.qsettings.setValue('rfcat_executable', self.rfcat_executable) + self.qsettings.setValue("rfcat_executable", self.rfcat_executable) def free_data(self): if self.raw_mode: @@ -116,9 +127,13 @@ def write_to_rfcat(self, buf): def open_rfcat(self): if not self.rfcat_is_open: try: - self.process = Popen([self.rfcat_executable, '-r'], stdin=PIPE, stdout=PIPE, stderr=PIPE) + self.process = Popen( + [self.rfcat_executable, "-r"], stdin=PIPE, stdout=PIPE, stderr=PIPE + ) self.rfcat_is_open = True - logger.debug("Successfully opened RfCat ({})".format(self.rfcat_executable)) + logger.debug( + "Successfully opened RfCat ({})".format(self.rfcat_executable) + ) return True except Exception as e: logger.debug("Could not open RfCat! ({})".format(e)) @@ -139,7 +154,7 @@ def set_parameter(self, param: str, log=True): # returns error (True/False) self.write_to_rfcat(param) self.ready = False if log: - logger.debug(param) + logger.debug(param) except OSError as e: logger.info("Could not set parameter {0}:{1} ({2})".format(param, e)) return True @@ -148,16 +163,31 @@ def set_parameter(self, param: str, log=True): # returns error (True/False) def read_async(self): self.set_parameter("d.RFrecv({})[0]".format(500), log=False) - def configure_rfcat(self, modulation = "MOD_ASK_OOK", freq = 433920000, sample_rate = 2000000, samples_per_symbol = 500): + def configure_rfcat( + self, + modulation="MOD_ASK_OOK", + freq=433920000, + sample_rate=2000000, + samples_per_symbol=500, + ): self.set_parameter("d.setMdmModulation({})".format(modulation), log=False) self.set_parameter("d.setFreq({})".format(int(freq)), log=False) self.set_parameter("d.setMdmSyncMode(0)", log=False) - self.set_parameter("d.setMdmDRate({})".format(int(sample_rate // samples_per_symbol)), log=False) + self.set_parameter( + "d.setMdmDRate({})".format(int(sample_rate // samples_per_symbol)), + log=False, + ) self.set_parameter("d.setMaxPower()", log=False) - logger.info("Configured RfCat to Modulation={}, Frequency={} Hz, Datarate={} baud".format(modulation, int(freq), int(sample_rate // samples_per_symbol))) + logger.info( + "Configured RfCat to Modulation={}, Frequency={} Hz, Datarate={} baud".format( + modulation, int(freq), int(sample_rate // samples_per_symbol) + ) + ) def send_data(self, data) -> str: - prepared_data = "d.RFxmit(b{})".format(str(data)[11:-1]) #[11:-1] Removes "bytearray(b...) + prepared_data = "d.RFxmit(b{})".format( + str(data)[11:-1] + ) # [11:-1] Removes "bytearray(b...) self.set_parameter(prepared_data, log=False) def __send_messages(self, messages, sample_rates): @@ -178,15 +208,25 @@ def __send_messages(self, messages, sample_rates): modulation = "MOD_GFSK" elif modulation == "PSK": modulation = "MOD_MSK" - else: # Fallback + else: # Fallback modulation = "MOD_ASK_OOK" - self.configure_rfcat(modulation=modulation, freq=self.project_manager.device_conf["frequency"], - sample_rate=sample_rates[0], samples_per_symbol=messages[0].samples_per_symbol) + self.configure_rfcat( + modulation=modulation, + freq=self.project_manager.device_conf["frequency"], + sample_rate=sample_rates[0], + samples_per_symbol=messages[0].samples_per_symbol, + ) - repeats_from_settings = settings.read('num_sending_repeats', type=int) + repeats_from_settings = settings.read("num_sending_repeats", type=int) repeats = repeats_from_settings if repeats_from_settings > 0 else -1 - while (repeats > 0 or repeats == -1) and self.__sending_interrupt_requested == False: - logger.debug("Start iteration ({} left)".format(repeats if repeats > 0 else "infinite")) + while ( + repeats > 0 or repeats == -1 + ) and self.__sending_interrupt_requested == False: + logger.debug( + "Start iteration ({} left)".format( + repeats if repeats > 0 else "infinite" + ) + ) for i, msg in enumerate(messages): if self.__sending_interrupt_requested: break @@ -196,25 +236,34 @@ def __send_messages(self, messages, sample_rates): self.current_send_message_changed.emit(i) error = self.send_data(self.bit_str_to_bytearray(msg.encoded_bits_str)) if not error: - logger.debug("Sent message {0}/{1}".format(i+1, len(messages))) + logger.debug("Sent message {0}/{1}".format(i + 1, len(messages))) logger.debug("Waiting message pause: {0:.2f}s".format(wait_time)) if self.__sending_interrupt_requested: break time.sleep(wait_time) else: self.is_sending = False - Errors.generic_error("Could not connect to {0}:{1}".format(self.client_ip, self.client_port), msg=error) + Errors.generic_error( + "Could not connect to {0}:{1}".format( + self.client_ip, self.client_port + ), + msg=error, + ) break if repeats > 0: repeats -= 1 logger.debug("Sending finished") self.is_sending = False - def start_message_sending_thread(self, messages, sample_rates, modulators, project_manager): + def start_message_sending_thread( + self, messages, sample_rates, modulators, project_manager + ): self.modulators = modulators self.project_manager = project_manager self.__sending_interrupt_requested = False - self.sending_thread = Thread(target=self.__send_messages, args=(messages, sample_rates)) + self.sending_thread = Thread( + target=self.__send_messages, args=(messages, sample_rates) + ) self.sending_thread.daemon = True self.sending_thread.start() @@ -229,4 +278,4 @@ def bytearray_to_bit_str(arr: bytearray) -> str: @staticmethod def bit_str_to_bytearray(bits: str) -> bytearray: bits += "0" * ((8 - len(bits) % 8) % 8) - return bytearray((int(bits[i:i+8], 2) for i in range(0, len(bits), 8))) + return bytearray((int(bits[i : i + 8], 2) for i in range(0, len(bits), 8))) diff --git a/src/urh/plugins/ZeroHide/ZeroHideAction.py b/src/urh/plugins/ZeroHide/ZeroHideAction.py index 87259b146e..abda9abf41 100644 --- a/src/urh/plugins/ZeroHide/ZeroHideAction.py +++ b/src/urh/plugins/ZeroHide/ZeroHideAction.py @@ -4,7 +4,13 @@ class ZeroHideAction(QUndoCommand): - def __init__(self, protocol: ProtocolAnalyzer, following_zeros: int, view: int, zero_hide_offsets: dict): + def __init__( + self, + protocol: ProtocolAnalyzer, + following_zeros: int, + view: int, + zero_hide_offsets: dict, + ): super().__init__() self.protocol = protocol self.following_zeros = following_zeros @@ -34,7 +40,9 @@ def redo(self): zero_sequences = self.__get_zero_seq_indexes(data, self.following_zeros) - self.zero_hide_offsets[i] = {start: end-start for start, end in zero_sequences} + self.zero_hide_offsets[i] = { + start: end - start for start, end in zero_sequences + } for seq in reversed(zero_sequences): full_bits = pa.messages[i].decoded_bits start = seq[0] * factor @@ -60,10 +68,10 @@ def __get_zero_seq_indexes(self, message: str, following_zeros: int): zero_counter += 1 else: if zero_counter >= following_zeros: - result.append((i-zero_counter, i)) + result.append((i - zero_counter, i)) zero_counter = 0 if zero_counter >= following_zeros: result.append((len(message) - zero_counter, len(message))) - return result \ No newline at end of file + return result diff --git a/src/urh/plugins/ZeroHide/ZeroHidePlugin.py b/src/urh/plugins/ZeroHide/ZeroHidePlugin.py index 316b5fa94d..d4c32825e1 100644 --- a/src/urh/plugins/ZeroHide/ZeroHidePlugin.py +++ b/src/urh/plugins/ZeroHide/ZeroHidePlugin.py @@ -8,29 +8,39 @@ class ZeroHidePlugin(ProtocolPlugin): def __init__(self): super().__init__(name="ZeroHide") - self.following_zeros = 5 if 'following_zeros' not in self.qsettings.allKeys() else self.qsettings.value('following_zeros', type=int) + self.following_zeros = ( + 5 + if "following_zeros" not in self.qsettings.allKeys() + else self.qsettings.value("following_zeros", type=int) + ) self.undo_stack = None self.command = None self.zero_hide_offsets = dict() def create_connects(self): self.settings_frame.spinBoxFollowingZeros.setValue(self.following_zeros) - self.settings_frame.spinBoxFollowingZeros.valueChanged.connect(self.set_following_zeros) + self.settings_frame.spinBoxFollowingZeros.valueChanged.connect( + self.set_following_zeros + ) def set_following_zeros(self): self.following_zeros = self.settings_frame.spinBoxFollowingZeros.value() - self.qsettings.setValue('following_zeros', self.following_zeros) + self.qsettings.setValue("following_zeros", self.following_zeros) - def get_action(self, parent, undo_stack: QUndoStack, sel_range, protocol, view: int): + def get_action( + self, parent, undo_stack: QUndoStack, sel_range, protocol, view: int + ): """ :type parent: QTableView :type undo_stack: QUndoStack """ - self.command = ZeroHideAction(protocol, self.following_zeros, view, self.zero_hide_offsets) + self.command = ZeroHideAction( + protocol, self.following_zeros, view, self.zero_hide_offsets + ) action = QAction(self.command.text(), parent) action.triggered.connect(self.action_triggered) self.undo_stack = undo_stack return action def action_triggered(self): - self.undo_stack.push(self.command) \ No newline at end of file + self.undo_stack.push(self.command) diff --git a/src/urh/plugins/ZeroHide/__init__.py b/src/urh/plugins/ZeroHide/__init__.py index 3fa5af38d8..813939aaf7 100644 --- a/src/urh/plugins/ZeroHide/__init__.py +++ b/src/urh/plugins/ZeroHide/__init__.py @@ -1 +1 @@ -__author__ = 'joe' +__author__ = "joe" diff --git a/src/urh/plugins/__init__.py b/src/urh/plugins/__init__.py index 3fa5af38d8..813939aaf7 100644 --- a/src/urh/plugins/__init__.py +++ b/src/urh/plugins/__init__.py @@ -1 +1 @@ -__author__ = 'joe' +__author__ = "joe" diff --git a/src/urh/settings.py b/src/urh/settings.py index 1419eaae5d..303e340bc9 100644 --- a/src/urh/settings.py +++ b/src/urh/settings.py @@ -11,13 +11,17 @@ global __qt_settings + + def __get_qt_settings(): global __qt_settings try: __qt_settings.fileName() except: - __qt_settings = QSettings(QSettings.IniFormat, QSettings.UserScope, 'urh', 'urh') + __qt_settings = QSettings( + QSettings.IniFormat, QSettings.UserScope, "urh", "urh" + ) return __qt_settings @@ -31,8 +35,8 @@ def get_qt_settings_filename(): PIXELS_PER_PATH = 5000 -SPECTRUM_BUFFER_SIZE = 2 ** 15 -SNIFF_BUFFER_SIZE = 5 * 10 ** 7 +SPECTRUM_BUFFER_SIZE = 2**15 +SNIFF_BUFFER_SIZE = 5 * 10**7 CONTINUOUS_BUFFER_SIZE_MB = 50 PAUSE_TRESHOLD = 10 @@ -62,7 +66,7 @@ def get_qt_settings_filename(): ONES_AREA_COLOR = Qt.green ZEROS_AREA_COLOR = Qt.magenta SEPARATION_OPACITY = 0.15 -SEPARATION_PADDING = .05 # percent +SEPARATION_PADDING = 0.05 # percent # PROTOCOL TABLE COLORS SELECTED_ROW_COLOR = QColor.fromRgb(0, 0, 255) @@ -75,7 +79,9 @@ def get_qt_settings_filename(): PROJECT_FILE = "URHProject.xml" DECODINGS_FILE = "decodings.txt" -FIELD_TYPE_SETTINGS = os.path.realpath(os.path.join(get_qt_settings_filename(), "..", "fieldtypes.xml")) +FIELD_TYPE_SETTINGS = os.path.realpath( + os.path.join(get_qt_settings_filename(), "..", "fieldtypes.xml") +) # DEVICE SETTINGS DEFAULT_IP_USRP = "192.168.10.2" @@ -96,35 +102,38 @@ def get_qt_settings_filename(): DECODING_MORSE = "Morse Code" DECODING_DISABLED_PREFIX = "[Disabled] " -LABEL_COLORS = [QColor.fromRgb(217, 240, 27, 125), # yellow - QColor.fromRgb(41, 172, 81, 125), # green - QColor.fromRgb(245, 12, 12, 125), # red - QColor.fromRgb(12, 12, 242, 125), # blue - QColor.fromRgb(67, 44, 14, 125), # brown - QColor.fromRgb(146, 49, 49, 125), # dark red - QColor.fromRgb(9, 9, 54, 125), # dark blue - QColor.fromRgb(17, 49, 27, 125), # dark green - QColor.fromRgb(244, 246, 36, 125), # strong yellow - QColor.fromRgb(61, 67, 67, 125), # gray 3 - QColor.fromRgb(58, 60, 100, 125), # halfdark blue - QColor.fromRgb(139, 148, 148, 125), # gray 2 - QColor.fromRgb(153, 207, 206, 125), # light blue green - QColor.fromRgb(207, 223, 223, 125), # gray 1 - QColor.fromRgb(106, 10, 10, 125), # darker red - QColor.fromRgb(12, 142, 242, 125), # light blue - QColor.fromRgb(213, 212, 134, 125), # light yellow - QColor.fromRgb(240, 238, 244, 125), # gray 0 - QColor.fromRgb(201, 121, 18, 125), # orange - QColor.fromRgb(155, 170, 224, 125), # lighter blue - QColor.fromRgb(12, 242, 201, 125), # blue green - QColor.fromRgb(7, 237, 78, 125), # light green - QColor.fromRgb(154, 37, 111, 125), # pink - QColor.fromRgb(159, 237, 7, 125), # yellow green - QColor.fromRgb(231, 136, 242, 125), # light pink - ] +LABEL_COLORS = [ + QColor.fromRgb(217, 240, 27, 125), # yellow + QColor.fromRgb(41, 172, 81, 125), # green + QColor.fromRgb(245, 12, 12, 125), # red + QColor.fromRgb(12, 12, 242, 125), # blue + QColor.fromRgb(67, 44, 14, 125), # brown + QColor.fromRgb(146, 49, 49, 125), # dark red + QColor.fromRgb(9, 9, 54, 125), # dark blue + QColor.fromRgb(17, 49, 27, 125), # dark green + QColor.fromRgb(244, 246, 36, 125), # strong yellow + QColor.fromRgb(61, 67, 67, 125), # gray 3 + QColor.fromRgb(58, 60, 100, 125), # halfdark blue + QColor.fromRgb(139, 148, 148, 125), # gray 2 + QColor.fromRgb(153, 207, 206, 125), # light blue green + QColor.fromRgb(207, 223, 223, 125), # gray 1 + QColor.fromRgb(106, 10, 10, 125), # darker red + QColor.fromRgb(12, 142, 242, 125), # light blue + QColor.fromRgb(213, 212, 134, 125), # light yellow + QColor.fromRgb(240, 238, 244, 125), # gray 0 + QColor.fromRgb(201, 121, 18, 125), # orange + QColor.fromRgb(155, 170, 224, 125), # lighter blue + QColor.fromRgb(12, 242, 201, 125), # blue green + QColor.fromRgb(7, 237, 78, 125), # light green + QColor.fromRgb(154, 37, 111, 125), # pink + QColor.fromRgb(159, 237, 7, 125), # yellow green + QColor.fromRgb(231, 136, 242, 125), # light pink +] # full alpha for participant colors, since its used in text html view (signal frame) -PARTICIPANT_COLORS = [QColor.fromRgb(lc.red(), lc.green(), lc.blue()) for lc in LABEL_COLORS] +PARTICIPANT_COLORS = [ + QColor.fromRgb(lc.red(), lc.green(), lc.blue()) for lc in LABEL_COLORS +] BG_COLOR_CORRECT = QColor(0, 255, 0, 150) BG_COLOR_WRONG = QColor(255, 0, 0, 150) @@ -176,7 +185,9 @@ def sync(): OVERWRITE_RECEIVE_BUFFER_SIZE = None # for unit tests -def get_receive_buffer_size(resume_on_full_receive_buffer: bool, spectrum_mode: bool) -> int: +def get_receive_buffer_size( + resume_on_full_receive_buffer: bool, spectrum_mode: bool +) -> int: if OVERWRITE_RECEIVE_BUFFER_SIZE: return OVERWRITE_RECEIVE_BUFFER_SIZE @@ -187,7 +198,7 @@ def get_receive_buffer_size(resume_on_full_receive_buffer: bool, spectrum_mode: num_samples = SNIFF_BUFFER_SIZE else: # Take 60% of avail memory - threshold = read('ram_threshold', 0.6, float) + threshold = read("ram_threshold", 0.6, float) num_samples = threshold * (psutil.virtual_memory().available / 8) # Do not let it allocate too much memory on 32 bit @@ -195,5 +206,9 @@ def get_receive_buffer_size(resume_on_full_receive_buffer: bool, spectrum_mode: num_samples = sys.maxsize // (8 * 2 * 1.5) logger.info("Correcting buffer size to {}".format(num_samples)) - logger.info("Allocate receive buffer with {0}B".format(Formatter.big_value_with_suffix(num_samples * 8))) + logger.info( + "Allocate receive buffer with {0}B".format( + Formatter.big_value_with_suffix(num_samples * 8) + ) + ) return int(num_samples) diff --git a/src/urh/signalprocessing/ChecksumLabel.py b/src/urh/signalprocessing/ChecksumLabel.py index 246c0b7561..73a454bbef 100644 --- a/src/urh/signalprocessing/ChecksumLabel.py +++ b/src/urh/signalprocessing/ChecksumLabel.py @@ -16,23 +16,38 @@ class Category(Enum): generic = "generic" wsp = "Wireless Short Packet (WSP)" - def __init__(self, name: str, start: int, end: int, color_index: int, field_type: FieldType, - fuzz_created=False, auto_created=False, data_range_start=0): + def __init__( + self, + name: str, + start: int, + end: int, + color_index: int, + field_type: FieldType, + fuzz_created=False, + auto_created=False, + data_range_start=0, + ): assert field_type.function == FieldType.Function.CHECKSUM - super().__init__(name, start, end, color_index, fuzz_created, auto_created, field_type) + super().__init__( + name, start, end, color_index, fuzz_created, auto_created, field_type + ) self.__category = self.Category.generic - self.__data_ranges = [[data_range_start, self.start]] # type: list[list[int,int]] + self.__data_ranges = [ + [data_range_start, self.start] + ] # type: list[list[int,int]] self.checksum = GenericCRC(polynomial=0) # type: GenericCRC or WSPChecksum def calculate_checksum(self, bits: array.array) -> array.array: return self.checksum.calculate(bits) - def calculate_checksum_for_message(self, message, use_decoded_bits: bool) -> array.array: + def calculate_checksum_for_message( + self, message, use_decoded_bits: bool + ) -> array.array: data = array.array("B", []) bits = message.decoded_bits if use_decoded_bits else message.plain_bits for data_range in self.data_ranges: - data.extend(bits[data_range[0]:data_range[1]]) + data.extend(bits[data_range[0] : data_range[1]]) return self.calculate_checksum(data) @property @@ -66,8 +81,15 @@ def category(self, value: Category): raise ValueError("Unknown Category") def to_label(self, field_type: FieldType) -> ProtocolLabel: - result = ProtocolLabel(name=self.name, start=self.start, end=self.end - 1, color_index=self.color_index, field_type=field_type, - auto_created=self.auto_created, fuzz_created=self.fuzz_created) + result = ProtocolLabel( + name=self.name, + start=self.start, + end=self.end - 1, + color_index=self.color_index, + field_type=field_type, + auto_created=self.auto_created, + fuzz_created=self.fuzz_created, + ) result.apply_decoding = self.apply_decoding result.show = self.show result.fuzz_me = self.fuzz_me @@ -77,9 +99,15 @@ def to_label(self, field_type: FieldType) -> ProtocolLabel: @classmethod def from_label(cls, label: ProtocolLabel): - result = ChecksumLabel(name=label.name, start=label.start, end=label.end - 1, color_index=label.color_index, - field_type=FieldType(label.name, FieldType.Function.CHECKSUM), - fuzz_created=label.fuzz_created, auto_created=label.auto_created) + result = ChecksumLabel( + name=label.name, + start=label.start, + end=label.end - 1, + color_index=label.color_index, + field_type=FieldType(label.name, FieldType.Function.CHECKSUM), + fuzz_created=label.fuzz_created, + auto_created=label.auto_created, + ) result.apply_decoding = label.apply_decoding result.show = label.show result.fuzz_me = label.fuzz_me @@ -90,10 +118,20 @@ def from_label(cls, label: ProtocolLabel): @classmethod def from_xml(cls, tag: ET.Element, field_types_by_caption=None): lbl = super().from_xml(tag, field_types_by_caption) - if lbl.field_type is None or lbl.field_type.function != FieldType.Function.CHECKSUM: + if ( + lbl.field_type is None + or lbl.field_type.function != FieldType.Function.CHECKSUM + ): checksum_field_type = next( - (ft for ft in field_types_by_caption.values() if ft.function == FieldType.Function.CHECKSUM), - FieldType("checksum", FieldType.Function.CHECKSUM, display_format_index=1)) + ( + ft + for ft in field_types_by_caption.values() + if ft.function == FieldType.Function.CHECKSUM + ), + FieldType( + "checksum", FieldType.Function.CHECKSUM, display_format_index=1 + ), + ) lbl.field_type = checksum_field_type result = cls.from_label(lbl) result.data_ranges = ast.literal_eval(tag.get("data_ranges", "[]")) @@ -112,6 +150,8 @@ def from_xml(cls, tag: ET.Element, field_types_by_caption=None): def to_xml(self): result = super().to_xml() result.tag = "checksum_label" - result.attrib.update({"data_ranges": str(self.data_ranges), "category": self.category.name}) + result.attrib.update( + {"data_ranges": str(self.data_ranges), "category": self.category.name} + ) result.append(self.checksum.to_xml()) return result diff --git a/src/urh/signalprocessing/ContinuousModulator.py b/src/urh/signalprocessing/ContinuousModulator.py index e9947f8e31..c1672e3921 100644 --- a/src/urh/signalprocessing/ContinuousModulator.py +++ b/src/urh/signalprocessing/ContinuousModulator.py @@ -13,24 +13,30 @@ class ContinuousModulator(object): You pass a list of messages and modulators to it, and it takes care of modulating the messages sequentially. This avoids running out of RAM for large amounts of messages. """ + WAIT_TIMEOUT = 0.1 def __init__(self, messages, modulators, num_repeats=-1): """ - - :type messages: list of Message - :type modulators: list of Modulator + + :type messages: list of Message + :type modulators: list of Modulator """ self.messages = messages self.modulators = modulators self.num_repeats = num_repeats # -1 or 0 = infinite - self.ring_buffer = RingBuffer(int(settings.CONTINUOUS_BUFFER_SIZE_MB * 1e6) // 8, dtype=Modulator.get_dtype()) + self.ring_buffer = RingBuffer( + int(settings.CONTINUOUS_BUFFER_SIZE_MB * 1e6) // 8, + dtype=Modulator.get_dtype(), + ) self.current_message_index = Value("L", 0) self.abort = Value("i", 0) - self.process = Process(target=self.modulate_continuously, args=(self.num_repeats, ), daemon=True) + self.process = Process( + target=self.modulate_continuously, args=(self.num_repeats,), daemon=True + ) @property def is_running(self): @@ -39,7 +45,9 @@ def is_running(self): def start(self): self.abort.value = 0 try: - self.process = Process(target=self.modulate_continuously, args=(self.num_repeats, ), daemon=True) + self.process = Process( + target=self.modulate_continuously, args=(self.num_repeats,), daemon=True + ) self.process.start() except RuntimeError as e: logger.exception(e) @@ -60,7 +68,9 @@ def stop(self, clear_buffer=True): logger.debug("Stopped continuous modulation") def modulate_continuously(self, num_repeats): - rng = iter(int, 1) if num_repeats <= 0 else range(0, num_repeats) # <= 0 = forever + rng = ( + iter(int, 1) if num_repeats <= 0 else range(0, num_repeats) + ) # <= 0 = forever for _ in rng: if self.abort.value: return @@ -74,7 +84,9 @@ def modulate_continuously(self, num_repeats): message = self.messages[i] self.current_message_index.value = i modulator = self.modulators[message.modulator_index] # type: Modulator - modulated = modulator.modulate(start=0, data=message.encoded_bits, pause=message.pause) + modulated = modulator.modulate( + start=0, data=message.encoded_bits, pause=message.pause + ) while not self.ring_buffer.will_fit(len(modulated)): if self.abort.value: return diff --git a/src/urh/signalprocessing/Encoding.py b/src/urh/signalprocessing/Encoding.py index b04dc181f5..b2995be1ba 100755 --- a/src/urh/signalprocessing/Encoding.py +++ b/src/urh/signalprocessing/Encoding.py @@ -43,10 +43,46 @@ def __init__(self, chain=None): self.cc1101_overwrite_crc = False # Configure CC1101 Date Whitening - polynomial = array.array("B", [False, False, True, False, False, False, False, True]) # x^5+x^0 - sync_bytes = array.array("B", [True, True, True, False, True, False, False, True, True, True, False, False, - True, False, True, False, True, True, True, False, True, False, False, True, - True, True, False, False, True, False, True, False]) # "e9cae9ca" + polynomial = array.array( + "B", [False, False, True, False, False, False, False, True] + ) # x^5+x^0 + sync_bytes = array.array( + "B", + [ + True, + True, + True, + False, + True, + False, + False, + True, + True, + True, + False, + False, + True, + False, + True, + False, + True, + True, + True, + False, + True, + False, + False, + True, + True, + True, + False, + False, + True, + False, + True, + False, + ], + ) # "e9cae9ca" # sync_bytes = self.str2bit("01100111011010000110011101101000") # "67686768" (RWE Default) # sync_bytes = self.str2bit("01101001111101100110100111110111") # "69f669f7" (Special RWE) @@ -254,41 +290,68 @@ def code(self, decoding, inputbits: array.array): elif self.code_externalprogram == operation: if self.chain[i + 1] != "": try: - self.external_decoder, self.external_encoder = self.chain[i + 1].split(";") + self.external_decoder, self.external_encoder = self.chain[ + i + 1 + ].split(";") except ValueError: pass else: self.external_decoder, self.external_encoder = "", "" elif self.code_data_whitening == operation: - if self.chain[i + 1].count(';') == 2: - self.data_whitening_sync, self.data_whitening_polynomial, overwrite_crc = self.chain[i + 1].split(";") - if (len(self.data_whitening_sync) > 0 and len(self.data_whitening_polynomial) > 0 and len(overwrite_crc) > 0): - self.data_whitening_sync = util.hex2bit(self.data_whitening_sync) - self.data_whitening_polynomial = util.hex2bit(self.data_whitening_polynomial) - self.cc1101_overwrite_crc = True if overwrite_crc == "1" else False - elif self.chain[i + 1].count(';') == 1: - self.data_whitening_sync, self.data_whitening_polynomial = self.chain[i + 1].split(";") - if (len(self.data_whitening_sync) > 0 and len(self.data_whitening_polynomial) > 0): - self.data_whitening_sync = util.hex2bit(self.data_whitening_sync) - self.data_whitening_polynomial = util.hex2bit(self.data_whitening_polynomial) + if self.chain[i + 1].count(";") == 2: + ( + self.data_whitening_sync, + self.data_whitening_polynomial, + overwrite_crc, + ) = self.chain[i + 1].split(";") + if ( + len(self.data_whitening_sync) > 0 + and len(self.data_whitening_polynomial) > 0 + and len(overwrite_crc) > 0 + ): + self.data_whitening_sync = util.hex2bit( + self.data_whitening_sync + ) + self.data_whitening_polynomial = util.hex2bit( + self.data_whitening_polynomial + ) + self.cc1101_overwrite_crc = ( + True if overwrite_crc == "1" else False + ) + elif self.chain[i + 1].count(";") == 1: + ( + self.data_whitening_sync, + self.data_whitening_polynomial, + ) = self.chain[i + 1].split(";") + if ( + len(self.data_whitening_sync) > 0 + and len(self.data_whitening_polynomial) > 0 + ): + self.data_whitening_sync = util.hex2bit( + self.data_whitening_sync + ) + self.data_whitening_polynomial = util.hex2bit( + self.data_whitening_polynomial + ) self.cc1101_overwrite_crc = False elif self.code_cut == operation: - if self.chain[i + 1] != "" and self.chain[i + 1].count(';') == 1: + if self.chain[i + 1] != "" and self.chain[i + 1].count(";") == 1: self.cutmode, tmp = self.chain[i + 1].split(";") self.cutmode = int(self.cutmode) if self.cutmode < 0 or self.cutmode > 3: self.cutmode = 0 if self.cutmode == 0 or self.cutmode == 1: self.cutmark = self.str2bit(tmp) - if len(self.cutmark) == 0: self.cutmark = array.array("B", [True, False, True, False]) + if len(self.cutmark) == 0: + self.cutmark = array.array("B", [True, False, True, False]) else: try: self.cutmark = int(tmp) except ValueError: self.cutmark = 1 elif self.code_morse == operation: - if self.chain[i + 1] != "" and self.chain[i + 1].count(';') == 2: + if self.chain[i + 1] != "" and self.chain[i + 1].count(";") == 2: try: l, h, w = self.chain[i + 1].split(";") self.morse_low = int(l) @@ -429,17 +492,25 @@ def code_carrier(self, decoding, inpt): x = 0 for i in inpt: while self.carrier[x % len(self.carrier)] in ("0", "1", "*"): - output.append(False if self.carrier[x % len(self.carrier)] in ( - "0", "*") else True) # Add 0 when there is a wildcard (*) in carrier description + output.append( + False + if self.carrier[x % len(self.carrier)] in ("0", "*") + else True + ) # Add 0 when there is a wildcard (*) in carrier description x += 1 tmp = self.carrier[x % len(self.carrier)] if not tmp in ("0", "1", "*"): output.append(i) x += 1 # Consume the trailing carrier pattern avoiding any wrap around - while x % len(self.carrier) > 0 and self.carrier[x % len(self.carrier)] in ("0", "1", "*"): - output.append(False if self.carrier[x % len(self.carrier)] in ( - "0", "*") else True) # Add 0 when there is a wildcard (*) in carrier description + while x % len(self.carrier) > 0 and self.carrier[ + x % len(self.carrier) + ] in ("0", "1", "*"): + output.append( + False + if self.carrier[x % len(self.carrier)] in ("0", "*") + else True + ) # Add 0 when there is a wildcard (*) in carrier description x += 1 return output, errors, self.ErrorState.SUCCESS @@ -460,10 +531,25 @@ def code_lsb_first(self, decoding, inpt): # Change Byteorder to LSB first <-> LSB last i = 0 while i < len(output) - 7: - output[i + 0], output[i + 1], output[i + 2], output[i + 3], output[i + 4], output[i + 5], output[i + 6], \ - output[i + 7] = \ - output[i + 7], output[i + 6], output[i + 5], output[i + 4], output[i + 3], output[i + 2], output[i + 1], \ - output[i + 0] + ( + output[i + 0], + output[i + 1], + output[i + 2], + output[i + 3], + output[i + 4], + output[i + 5], + output[i + 6], + output[i + 7], + ) = ( + output[i + 7], + output[i + 6], + output[i + 5], + output[i + 4], + output[i + 3], + output[i + 2], + output[i + 1], + output[i + 0], + ) i += 8 return output, errors, self.ErrorState.SUCCESS @@ -505,7 +591,11 @@ def code_redundancy(self, decoding, inpt): def code_invert(self, decoding, inpt): errors = 0 - return array.array("B", [True if not x else False for x in inpt]), errors, self.ErrorState.SUCCESS + return ( + array.array("B", [True if not x else False for x in inpt]), + errors, + self.ErrorState.SUCCESS, + ) def code_differential(self, decoding, inpt): output = array.array("B", [inpt[0]]) @@ -571,18 +661,22 @@ def code_substitution(self, decoding, inpt): # Padding of inpt with zeros to multiple of SRC[0] length (every SRC/DST-length should be the same) minimum_item_size = len(src[0]) - zero_padding = (minimum_item_size - (len(padded_inpt) % minimum_item_size)) % minimum_item_size - padded_inpt.extend([False]*zero_padding) + zero_padding = ( + minimum_item_size - (len(padded_inpt) % minimum_item_size) + ) % minimum_item_size + padded_inpt.extend([False] * zero_padding) errors = zero_padding i = 0 try: while i < len(padded_inpt): - cnt = src.count(padded_inpt[i:i + minimum_item_size]) + cnt = src.count(padded_inpt[i : i + minimum_item_size]) if cnt == 1: - output.extend(dst[src.index(padded_inpt[i:i + minimum_item_size])]) + output.extend( + dst[src.index(padded_inpt[i : i + minimum_item_size])] + ) elif cnt < 1: - output.extend(padded_inpt[i:i + 1]) + output.extend(padded_inpt[i : i + 1]) i += 1 errors += 1 continue @@ -618,7 +712,7 @@ def code_morse(self, decoding, inpt): output.append(False) else: if cnt > 0: - if cnt > (self.morse_high+self.morse_low // 2): + if cnt > (self.morse_high + self.morse_low // 2): output.append(True) else: output.append(False) @@ -641,9 +735,13 @@ def code_externalprogram(self, decoding, inpt): errors = 0 if decoding and self.external_decoder != "": - output = self.charstr2bit(util.run_command(self.external_decoder, self.bit2str(inpt))) + output = self.charstr2bit( + util.run_command(self.external_decoder, self.bit2str(inpt)) + ) elif not decoding and self.external_encoder != "": - output = self.charstr2bit(util.run_command(self.external_encoder, self.bit2str(inpt))) + output = self.charstr2bit( + util.run_command(self.external_encoder, self.bit2str(inpt)) + ) else: return [], 1, self.ErrorState.MISSING_EXTERNAL_PROGRAM @@ -696,7 +794,9 @@ def code_cut(self, decoding, inpt) -> array.array: def code_enocean(self, decoding: bool, inpt): errors = 0 output = array.array("B", []) - preamble = array.array("B", [True, False, True, False, True, False, True, False]) + preamble = array.array( + "B", [True, False, True, False, True, False, True, False] + ) sof = array.array("B", [True, False, False, True]) eof = array.array("B", [True, False, True, True]) @@ -717,19 +817,19 @@ def code_enocean(self, decoding: bool, inpt): return inpt, 0, self.ErrorState.PREAMBLE_NOT_FOUND # check preamble - if inpt[n:n + 8] != preamble: + if inpt[n : n + 8] != preamble: return inpt, 0, self.ErrorState.PREAMBLE_NOT_FOUND # check SoF - if inpt[n + 8:n + 12] != sof: + if inpt[n + 8 : n + 12] != sof: return inpt, 0, self.ErrorState.SYNC_NOT_FOUND - output.extend(inpt[n:n + 12]) + output.extend(inpt[n : n + 12]) # search for data limits start = n + 12 n = len(inpt) - while n > start and inpt[n - 4:n] != eof: + while n > start and inpt[n - 4 : n] != eof: n -= 1 end = n - 4 @@ -738,22 +838,49 @@ def code_enocean(self, decoding: bool, inpt): if decoding: try: for n in range(start, end, 12): - errors += sum([inpt[n + 2] == inpt[n + 3], inpt[n + 6] == inpt[n + 7]]) - errors += sum([inpt[n + 10] != False, inpt[n + 11] != True]) if n < end - 11 else 0 - output.extend([inpt[n], inpt[n + 1], inpt[n + 2], inpt[n + 4], inpt[n + 5], inpt[n + 6], inpt[n + 8], - inpt[n + 9]]) - except IndexError: # compatibility for old project files + errors += sum( + [inpt[n + 2] == inpt[n + 3], inpt[n + 6] == inpt[n + 7]] + ) + errors += ( + sum([inpt[n + 10] != False, inpt[n + 11] != True]) + if n < end - 11 + else 0 + ) + output.extend( + [ + inpt[n], + inpt[n + 1], + inpt[n + 2], + inpt[n + 4], + inpt[n + 5], + inpt[n + 6], + inpt[n + 8], + inpt[n + 9], + ] + ) + except IndexError: # compatibility for old project files return inpt, 0, self.ErrorState.MISC # Finalize output - output.extend(inpt[end:end + 4]) + output.extend(inpt[end : end + 4]) else: for n in range(start, end, 8): try: output.extend( - [inpt[n], inpt[n + 1], inpt[n + 2], not inpt[n + 2], inpt[n + 3], inpt[n + 4], inpt[n + 5], - not inpt[n + 5], inpt[n + 6], inpt[n + 7]]) + [ + inpt[n], + inpt[n + 1], + inpt[n + 2], + not inpt[n + 2], + inpt[n + 3], + inpt[n + 4], + inpt[n + 5], + not inpt[n + 5], + inpt[n + 6], + inpt[n + 7], + ] + ) except IndexError: output.extend([False, True]) break @@ -800,16 +927,16 @@ def str2bit(inpt: str): def charstr2bit(inpt: str): output = array.array("B", []) for i in inpt: - if i == '0': + if i == "0": output.append(False) - elif i == '1': + elif i == "1": output.append(True) return output @staticmethod def hex2str(inpt): bitstring = bin(int(inpt, base=16))[2:] - return "0" * (4 * len(inpt.lstrip('0x')) - len(bitstring)) + bitstring + return "0" * (4 * len(inpt.lstrip("0x")) - len(bitstring)) + bitstring def __eq__(self, other): if other is None: diff --git a/src/urh/signalprocessing/FieldType.py b/src/urh/signalprocessing/FieldType.py index 237f67c837..4d02538b8c 100644 --- a/src/urh/signalprocessing/FieldType.py +++ b/src/urh/signalprocessing/FieldType.py @@ -6,7 +6,6 @@ class FieldType(object): - __slots__ = ["caption", "function", "display_format_index"] class Function(Enum): @@ -21,14 +20,20 @@ class Function(Enum): CHECKSUM = "checksum" CUSTOM = "custom" - def __init__(self, caption: str, function: Function, display_format_index: int = None): + def __init__( + self, caption: str, function: Function, display_format_index: int = None + ): self.caption = caption self.function = function if display_format_index is None: if self.function in (self.Function.PREAMBLE, self.Function.SYNC): self.display_format_index = 0 - elif self.function in (self.Function.DST_ADDRESS, self.Function.SRC_ADDRESS, self.Function.CHECKSUM): + elif self.function in ( + self.Function.DST_ADDRESS, + self.Function.SRC_ADDRESS, + self.Function.CHECKSUM, + ): self.display_format_index = 1 elif self.function in (self.Function.SEQUENCE_NUMBER, self.Function.LENGTH): self.display_format_index = 3 @@ -38,10 +43,16 @@ def __init__(self, caption: str, function: Function, display_format_index: int = self.display_format_index = display_format_index def __eq__(self, other): - return isinstance(other, FieldType) and self.caption == other.caption and self.function == other.function + return ( + isinstance(other, FieldType) + and self.caption == other.caption + and self.function == other.function + ) def __repr__(self): - return "FieldType: {0} - {1} ({2})".format(self.function.name, self.caption, self.display_format_index) + return "FieldType: {0} - {1} ({2})".format( + self.function.name, self.caption, self.display_format_index + ) @staticmethod def from_caption(caption: str): @@ -76,9 +87,15 @@ def load_from_xml(): return result def to_xml(self): - return ET.Element("field_type", attrib={ "caption": self.caption, - "function": self.function.name, - "display_format_index": str(self.display_format_index)}) + return ET.Element( + "field_type", + attrib={ + "caption": self.caption, + "function": self.function.name, + "display_format_index": str(self.display_format_index), + }, + ) + @staticmethod def from_xml(tag): """ @@ -97,11 +114,12 @@ def from_xml(tag): function = FieldType.Function.CUSTOM display_format_index = int(tag.get("display_format_index", -1)) - display_format_index = None if display_format_index == -1 else display_format_index + display_format_index = ( + None if display_format_index == -1 else display_format_index + ) return FieldType(caption, function, display_format_index) - @staticmethod def save_to_xml(field_types): """ diff --git a/src/urh/signalprocessing/Filter.py b/src/urh/signalprocessing/Filter.py index 3e13f70555..c489d886be 100644 --- a/src/urh/signalprocessing/Filter.py +++ b/src/urh/signalprocessing/Filter.py @@ -21,7 +21,7 @@ class Filter(object): "Narrow": 0.01, "Medium": 0.08, "Wide": 0.1, - "Very Wide": 0.42 + "Very Wide": 0.42, } def __init__(self, taps: list, filter_type: FilterType = FilterType.custom): @@ -36,12 +36,14 @@ def work(self, input_signal: np.ndarray) -> np.ndarray: def apply_fir_filter(self, input_signal: np.ndarray) -> np.ndarray: if input_signal.dtype != np.complex64: - tmp = np.empty(len(input_signal)//2, dtype=np.complex64) + tmp = np.empty(len(input_signal) // 2, dtype=np.complex64) tmp.real = input_signal[0::2] tmp.imag = input_signal[1::2] input_signal = tmp - return signal_functions.fir_filter(input_signal, np.array(self.taps, dtype=np.complex64)) + return signal_functions.fir_filter( + input_signal, np.array(self.taps, dtype=np.complex64) + ) @staticmethod def read_configured_filter_bw() -> float: @@ -68,14 +70,16 @@ def get_filter_length_from_bandwidth(bw): def fft_convolve_1d(x: np.ndarray, h: np.ndarray): n = len(x) + len(h) - 1 n_opt = 1 << (n - 1).bit_length() # Get next power of 2 - if np.issubdtype(x.dtype, np.complexfloating) or np.issubdtype(h.dtype, np.complexfloating): + if np.issubdtype(x.dtype, np.complexfloating) or np.issubdtype( + h.dtype, np.complexfloating + ): fft, ifft = np.fft.fft, np.fft.ifft # use complex fft else: fft, ifft = np.fft.rfft, np.fft.irfft # use real fft result = ifft(fft(x, n_opt) * fft(h, n_opt), n_opt)[0:n] too_much = (len(result) - len(x)) // 2 # Center result - return result[too_much: -too_much] + return result[too_much:-too_much] @staticmethod def apply_bandpass_filter(data, f_low, f_high, filter_bw=0.08): @@ -91,7 +95,7 @@ def apply_bandpass_filter(data, f_low, f_high, filter_bw=0.08): # https://softwareengineering.stackexchange.com/questions/171757/computational-complexity-of-correlation-in-time-vs-multiplication-in-frequency-s/ if len(h) < 8 * math.log(math.sqrt(len(data))): logger.debug("Use normal convolve") - return np.convolve(data, h, 'same') + return np.convolve(data, h, "same") else: logger.debug("Use FFT convolve") return Filter.fft_convolve_1d(data, h) @@ -101,7 +105,7 @@ def design_windowed_sinc_lpf(fc, bw): N = Filter.get_filter_length_from_bandwidth(bw) # Compute sinc filter impulse response - h = np.sinc(2 * fc * (np.arange(N) - (N - 1) / 2.)) + h = np.sinc(2 * fc * (np.arange(N) - (N - 1) / 2.0)) # We use blackman window function w = np.blackman(N) @@ -122,5 +126,6 @@ def design_windowed_sinc_bandpass(f_low, f_high, bw): N = Filter.get_filter_length_from_bandwidth(bw) # https://dsp.stackexchange.com/questions/41361/how-to-implement-bandpass-filter-on-complex-valued-signal - return Filter.design_windowed_sinc_lpf(f_c, bw=bw) * \ - np.exp(complex(0, 1) * np.pi * 2 * f_shift * np.arange(0, N, dtype=complex)) + return Filter.design_windowed_sinc_lpf(f_c, bw=bw) * np.exp( + complex(0, 1) * np.pi * 2 * f_shift * np.arange(0, N, dtype=complex) + ) diff --git a/src/urh/signalprocessing/IQArray.py b/src/urh/signalprocessing/IQArray.py index 81ccbb6396..a073397049 100644 --- a/src/urh/signalprocessing/IQArray.py +++ b/src/urh/signalprocessing/IQArray.py @@ -136,7 +136,11 @@ def convert_to(self, target_dtype) -> np.ndarray: elif target_dtype == np.uint16: return self.__data.astype(np.uint16) << 8 elif target_dtype == np.float32: - return np.add(np.multiply(self.__data, 1/128, dtype=np.float32), -1.0, dtype=np.float32) + return np.add( + np.multiply(self.__data, 1 / 128, dtype=np.float32), + -1.0, + dtype=np.float32, + ) if self.__data.dtype == np.int8: if target_dtype == np.uint8: @@ -146,54 +150,76 @@ def convert_to(self, target_dtype) -> np.ndarray: elif target_dtype == np.uint16: return np.add(self.__data, 128, dtype=np.uint16, casting="unsafe") << 8 elif target_dtype == np.float32: - return np.multiply(self.__data, 1/128, dtype=np.float32) + return np.multiply(self.__data, 1 / 128, dtype=np.float32) if self.__data.dtype == np.uint16: if target_dtype == np.int8: - return (np.add(self.__data, -32768, dtype=np.int16, casting="unsafe") >> 8).astype(np.int8) + return ( + np.add(self.__data, -32768, dtype=np.int16, casting="unsafe") >> 8 + ).astype(np.int8) elif target_dtype == np.uint8: return (self.__data >> 8).astype(np.uint8) elif target_dtype == np.int16: return np.add(self.__data, -32768, dtype=np.int16, casting="unsafe") elif target_dtype == np.float32: - return np.add(np.multiply(self.__data, 1/32768, dtype=np.float32), -1.0, dtype=np.float32) + return np.add( + np.multiply(self.__data, 1 / 32768, dtype=np.float32), + -1.0, + dtype=np.float32, + ) if self.__data.dtype == np.int16: if target_dtype == np.int8: return (self.__data >> 8).astype(np.int8) elif target_dtype == np.uint8: - return (np.add(self.__data, 32768, dtype=np.uint16, casting="unsafe") >> 8).astype(np.uint8) + return ( + np.add(self.__data, 32768, dtype=np.uint16, casting="unsafe") >> 8 + ).astype(np.uint8) elif target_dtype == np.uint16: return np.add(self.__data, 32768, dtype=np.uint16, casting="unsafe") elif target_dtype == np.float32: - return np.multiply(self.__data, 1/32768, dtype=np.float32) + return np.multiply(self.__data, 1 / 32768, dtype=np.float32) if self.__data.dtype == np.float32: if target_dtype == np.int8: return np.multiply(self.__data, 127, dtype=np.float32).astype(np.int8) elif target_dtype == np.uint8: - return np.multiply(np.add(self.__data, 1.0, dtype=np.float32), 127, dtype=np.float32).astype(np.uint8) + return np.multiply( + np.add(self.__data, 1.0, dtype=np.float32), 127, dtype=np.float32 + ).astype(np.uint8) elif target_dtype == np.int16: - return np.multiply(self.__data, 32767, dtype=np.float32).astype(np.int16) + return np.multiply(self.__data, 32767, dtype=np.float32).astype( + np.int16 + ) elif target_dtype == np.uint16: - return np.multiply(np.add(self.__data, 1.0, dtype=np.float32), 32767, dtype=np.float32).astype(np.uint16) + return np.multiply( + np.add(self.__data, 1.0, dtype=np.float32), 32767, dtype=np.float32 + ).astype(np.uint16) if target_dtype not in (np.uint8, np.int8, np.uint16, np.int16, np.float32): raise ValueError("Data type {} not supported".format(target_dtype)) - raise NotImplementedError("Conversion from {} to {} not supported", self.__data.dtype, target_dtype) + raise NotImplementedError( + "Conversion from {} to {} not supported", self.__data.dtype, target_dtype + ) @staticmethod def from_file(filename: str): if filename.endswith(".complex16u") or filename.endswith(".cu8"): # two 8 bit unsigned integers - return IQArray(IQArray(data=np.fromfile(filename, dtype=np.uint8)).convert_to(np.int8)) + return IQArray( + IQArray(data=np.fromfile(filename, dtype=np.uint8)).convert_to(np.int8) + ) elif filename.endswith(".complex16s") or filename.endswith(".cs8"): # two 8 bit signed integers return IQArray(data=np.fromfile(filename, dtype=np.int8)) elif filename.endswith(".complex32u") or filename.endswith(".cu16"): # two 16 bit unsigned integers - return IQArray(IQArray(data=np.fromfile(filename, dtype=np.uint16)).convert_to(np.int16)) + return IQArray( + IQArray(data=np.fromfile(filename, dtype=np.uint16)).convert_to( + np.int16 + ) + ) elif filename.endswith(".complex32s") or filename.endswith(".cs16"): # two 16 bit signed integers return IQArray(data=np.fromfile(filename, dtype=np.int16)) @@ -209,7 +235,7 @@ def convert_array_to_iq(arr: np.ndarray) -> np.ndarray: arr = arr.view(np.float64) if len(arr) % 2 == 0: return arr.reshape((-1, 2), order="C") - else: # ignore the last half sample to avoid a conversion error + else: # ignore the last half sample to avoid a conversion error return arr[:-1].reshape((-1, 2), order="C") elif arr.ndim == 2: return arr @@ -225,10 +251,14 @@ def min_max_for_dtype(dtype) -> tuple: @staticmethod def concatenate(*args): - return IQArray(data=np.concatenate([arr.data if isinstance(arr, IQArray) else arr for arr in args[0]])) + return IQArray( + data=np.concatenate( + [arr.data if isinstance(arr, IQArray) else arr for arr in args[0]] + ) + ) def save_compressed(self, filename): - with tarfile.open(filename, 'w:bz2') as tar_write: + with tarfile.open(filename, "w:bz2") as tar_write: tmp_name = tempfile.mkstemp()[1] self.tofile(tmp_name) tar_write.add(tmp_name) @@ -242,13 +272,17 @@ def export_to_wav(self, filename, num_channels, sample_rate): f.writeframes(self.convert_to(np.int16)) f.close() - def export_to_sub(self, filename, frequency=433920000, preset="FuriHalSubGhzPresetOok650Async"): + def export_to_sub( + self, filename, frequency=433920000, preset="FuriHalSubGhzPresetOok650Async" + ): arr = [] counter = 0 for value in self.convert_to(np.uint8): # if origin was a sub-file value is uint8, else value is [uint8, uint8] - if len(value) > 1: # if value has more than one component, use the first component + if ( + len(value) > 1 + ): # if value has more than one component, use the first component value = value[0] # set lastvalue to value for first run @@ -269,12 +303,12 @@ def export_to_sub(self, filename, frequency=433920000, preset="FuriHalSubGhzPres # save last value arr.append(counter if lastvalue > 127 else -counter) - with open(filename, 'w') as subfile: + with open(filename, "w") as subfile: subfile.write("Filetype: Flipper SubGhz RAW File\n") subfile.write("Version: 1\n") subfile.write("Frequency: {}\n".format(frequency)) subfile.write("Preset: {}\n".format(preset)) - subfile.write("Protocol: RAW") # Skip last \n + subfile.write("Protocol: RAW") # Skip last \n # Write data for idx in range(len(arr)): if idx % 512 == 0: @@ -282,4 +316,4 @@ def export_to_sub(self, filename, frequency=433920000, preset="FuriHalSubGhzPres subfile.write("RAW_Data: {}".format(arr[idx])) else: subfile.write(" {}".format(arr[idx])) - subfile.write("\n") \ No newline at end of file + subfile.write("\n") diff --git a/src/urh/signalprocessing/Interval.py b/src/urh/signalprocessing/Interval.py index 9c97b8cca9..3a9bab2ae8 100644 --- a/src/urh/signalprocessing/Interval.py +++ b/src/urh/signalprocessing/Interval.py @@ -41,9 +41,15 @@ def overlaps_with(self, other_interval) -> bool: def find_common_interval(self, other_interval): sorted_intervals = sorted([self, other_interval]) - common_values = set(sorted_intervals[0].range()).intersection(sorted_intervals[1].range()) - return Interval(min(common_values), max(common_values) + 1) if common_values else None + common_values = set(sorted_intervals[0].range()).intersection( + sorted_intervals[1].range() + ) + return ( + Interval(min(common_values), max(common_values) + 1) + if common_values + else None + ) @staticmethod def find_greatest(intervals: list): - return max(intervals, key=len) \ No newline at end of file + return max(intervals, key=len) diff --git a/src/urh/signalprocessing/Message.py b/src/urh/signalprocessing/Message.py index 3acd194a0f..d9c32c6e62 100644 --- a/src/urh/signalprocessing/Message.py +++ b/src/urh/signalprocessing/Message.py @@ -19,13 +19,44 @@ class Message(object): A protocol message is a single line of a protocol. """ - __slots__ = ["__plain_bits", "__bit_alignments", "pause", "modulator_index", "rssi", "participant", "message_type", - "absolute_time", "relative_time", "__decoder", "align_labels", "decoding_state", "timestamp", - "fuzz_created", "__decoded_bits", "__encoded_bits", "decoding_errors", "samples_per_symbol", "bit_sample_pos", - "alignment_offset", "bits_per_symbol"] - - def __init__(self, plain_bits, pause: int, message_type: MessageType, rssi=0, modulator_index=0, decoder=None, - fuzz_created=False, bit_sample_pos=None, samples_per_symbol=100, participant=None, bits_per_symbol=1): + __slots__ = [ + "__plain_bits", + "__bit_alignments", + "pause", + "modulator_index", + "rssi", + "participant", + "message_type", + "absolute_time", + "relative_time", + "__decoder", + "align_labels", + "decoding_state", + "timestamp", + "fuzz_created", + "__decoded_bits", + "__encoded_bits", + "decoding_errors", + "samples_per_symbol", + "bit_sample_pos", + "alignment_offset", + "bits_per_symbol", + ] + + def __init__( + self, + plain_bits, + pause: int, + message_type: MessageType, + rssi=0, + modulator_index=0, + decoder=None, + fuzz_created=False, + bit_sample_pos=None, + samples_per_symbol=100, + participant=None, + bits_per_symbol=1, + ): """ :param pause: pause AFTER the message in samples @@ -41,14 +72,16 @@ def __init__(self, plain_bits, pause: int, message_type: MessageType, rssi=0, mo self.pause = pause self.modulator_index = modulator_index self.rssi = rssi - self.participant = participant # type: Participant + self.participant = participant # type: Participant self.message_type = message_type # type: MessageType self.timestamp = time.time() self.absolute_time = 0 # set in Compare Frame self.relative_time = 0 # set in Compare Frame - self.__decoder = decoder if decoder else Encoding(["Non Return To Zero (NRZ)"]) # type: Encoding + self.__decoder = ( + decoder if decoder else Encoding(["Non Return To Zero (NRZ)"]) + ) # type: Encoding self.align_labels = True self.fuzz_created = fuzz_created @@ -62,7 +95,7 @@ def __init__(self, plain_bits, pause: int, message_type: MessageType, rssi=0, mo self.decoding_state = Encoding.ErrorState.SUCCESS self.samples_per_symbol = samples_per_symbol # to take over in modulator - self.bits_per_symbol = bits_per_symbol # to take over in generator tab (default modulator settings) + self.bits_per_symbol = bits_per_symbol # to take over in generator tab (default modulator settings) if bit_sample_pos is None: self.bit_sample_pos = array.array("L", []) @@ -123,10 +156,12 @@ def _remove_labels_for_range(self, index, instant_remove=True): removed_labels = [] for lbl in self.message_type: # type: ProtocolLabel - if (start <= lbl.start and stop >= lbl.end) \ - or start <= lbl.start <= stop \ - or (start >= lbl.start and stop <= lbl.end) \ - or lbl.start <= start < lbl.end: + if ( + (start <= lbl.start and stop >= lbl.end) + or start <= lbl.start <= stop + or (start >= lbl.start and stop <= lbl.end) + or lbl.start <= start < lbl.end + ): if instant_remove: self.message_type.remove(lbl) removed_labels.append(lbl) @@ -186,7 +221,9 @@ def decoder(self, val: Encoding): self.__decoder = val self.clear_decoded_bits() self.clear_encoded_bits() - self.decoding_errors, self.decoding_state = self.decoder.analyze(self.plain_bits) + self.decoding_errors, self.decoding_state = self.decoder.analyze( + self.plain_bits + ) @property def encoded_bits(self): @@ -201,9 +238,9 @@ def encoded_bits(self): bits = self.plain_bits for label in self.exclude_from_decoding_labels: - self.__encoded_bits.extend(encode(bits[start:label.start])) + self.__encoded_bits.extend(encode(bits[start : label.start])) start = label.start if label.start > start else start # Overlapping - self.__encoded_bits.extend(bits[start:label.end]) + self.__encoded_bits.extend(bits[start : label.end]) start = label.end if label.end > start else start # Overlapping self.__encoded_bits.extend(encode(bits[start:])) @@ -226,7 +263,7 @@ def decoded_bits(self) -> array.array: states = set() self.decoding_state = self.decoder.ErrorState.SUCCESS for label in self.exclude_from_decoding_labels: - decoded, errors, state = code(True, bits[start:label.start]) + decoded, errors, state = code(True, bits[start : label.start]) states.add(state) self.__decoded_bits.extend(decoded) self.decoding_errors += errors @@ -235,9 +272,13 @@ def decoded_bits(self) -> array.array: label.start = len(self.__decoded_bits) label.end = label.start + (label.end - label.start) - start = label.start if label.start > start else start # Überlappende Labels -.- - self.__decoded_bits.extend(bits[start:label.end]) - start = label.end if label.end > start else start # Überlappende Labels FFS >.< + start = ( + label.start if label.start > start else start + ) # Überlappende Labels -.- + self.__decoded_bits.extend(bits[start : label.end]) + start = ( + label.end if label.end > start else start + ) # Überlappende Labels FFS >.< decoded, errors, state = code(True, bits[start:]) states.add(state) @@ -306,16 +347,23 @@ def decoded_ascii_str(self) -> str: def decoded_ascii_buffer(self) -> bytes: return self.decoded_ascii_array.tobytes() - def __get_bit_range_from_hex_or_ascii_index(self, from_index: int, decoded: bool, is_hex: bool) -> tuple: + def __get_bit_range_from_hex_or_ascii_index( + self, from_index: int, decoded: bool, is_hex: bool + ) -> tuple: bits = self.decoded_bits if decoded else self.plain_bits factor = 4 if is_hex else 8 for i in range(len(bits)): - if self.__get_hex_ascii_index_from_bit_index(i, to_hex=is_hex)[0] == from_index: + if ( + self.__get_hex_ascii_index_from_bit_index(i, to_hex=is_hex)[0] + == from_index + ): return i, i + factor - 1 - return factor * from_index, factor * (from_index+1) - 1 + return factor * from_index, factor * (from_index + 1) - 1 - def __get_hex_ascii_index_from_bit_index(self, bit_index: int, to_hex: bool) -> tuple: + def __get_hex_ascii_index_from_bit_index( + self, bit_index: int, to_hex: bool + ) -> tuple: factor = 4 if to_hex else 8 result = 0 @@ -336,23 +384,31 @@ def convert_index(self, index: int, from_view: int, to_view: int, decoded: bool) return index, index if to_view == 0: - return self.__get_bit_range_from_hex_or_ascii_index(index, decoded, is_hex=from_view == 1) + return self.__get_bit_range_from_hex_or_ascii_index( + index, decoded, is_hex=from_view == 1 + ) if to_view == 1: if from_view == 0: return self.__get_hex_ascii_index_from_bit_index(index, to_hex=True) elif from_view == 2: - bi = self.__get_bit_range_from_hex_or_ascii_index(index, decoded, is_hex=True)[0] + bi = self.__get_bit_range_from_hex_or_ascii_index( + index, decoded, is_hex=True + )[0] return self.__get_hex_ascii_index_from_bit_index(bi, to_hex=False) elif to_view == 2: if from_view == 0: return self.__get_hex_ascii_index_from_bit_index(index, to_hex=False) elif from_view == 1: - bi = self.__get_bit_range_from_hex_or_ascii_index(index, decoded, is_hex=False)[0] + bi = self.__get_bit_range_from_hex_or_ascii_index( + index, decoded, is_hex=False + )[0] return self.__get_hex_ascii_index_from_bit_index(bi, to_hex=True) else: raise NotImplementedError("Only Three View Types (Bit/Hex/ASCII)") - def convert_range(self, index1: int, index2: int, from_view: int, to_view: int, decoded: bool): + def convert_range( + self, index1: int, index2: int, from_view: int, to_view: int, decoded: bool + ): start = self.convert_index(index1, from_view, to_view, decoded)[0] end = self.convert_index(index2, from_view, to_view, decoded)[1] @@ -375,8 +431,15 @@ def get_src_address_from_data(self, decoded=True): :param decoded: :return: """ - src_address_label = next((lbl for lbl in self.message_type if lbl.field_type - and lbl.field_type.function == FieldType.Function.SRC_ADDRESS), None) + src_address_label = next( + ( + lbl + for lbl in self.message_type + if lbl.field_type + and lbl.field_type.function == FieldType.Function.SRC_ADDRESS + ), + None, + ) if src_address_label: start, end = self.get_label_range(src_address_label, view=1, decode=decoded) if decoded: @@ -398,7 +461,10 @@ def __bit_chains_to_hex(bit_chains) -> array.array: result = array.array("B", []) for bc in bit_chains: bc += array.array("B", [0] * ((4 - len(bc) % 4) % 4)) # pad hex view - result.extend((8*bc[i]+4*bc[i+1]+2*bc[i+2]+bc[i+3]) for i in range(0, len(bc), 4)) + result.extend( + (8 * bc[i] + 4 * bc[i + 1] + 2 * bc[i + 2] + bc[i + 3]) + for i in range(0, len(bc), 4) + ) return result @@ -412,8 +478,19 @@ def __bit_chains_to_ascii(bit_chains) -> array.array: result = array.array("B", []) for bc in bit_chains: bc += array.array("B", [0] * ((8 - len(bc) % 8) % 8)) # pad ascii view - result.extend((128*bc[i]+64*bc[i+1]+32*bc[i+2]+16*bc[i+3]+8*bc[i+4]+4*bc[i+5]+2*bc[i+6]+bc[i+7]) - for i in range(0, len(bc), 8)) + result.extend( + ( + 128 * bc[i] + + 64 * bc[i + 1] + + 32 * bc[i + 2] + + 16 * bc[i + 3] + + 8 * bc[i + 4] + + 4 * bc[i + 5] + + 2 * bc[i + 6] + + bc[i + 7] + ) + for i in range(0, len(bc), 8) + ) return result def split(self, decode=True): @@ -440,7 +517,9 @@ def split(self, decode=True): result.append(message[start:]) return result - def view_to_string(self, view: int, decoded: bool, show_pauses=True, sample_rate: float = None) -> str: + def view_to_string( + self, view: int, decoded: bool, show_pauses=True, sample_rate: float = None + ) -> str: """ :param view: 0 - Bits ## 1 - Hex ## 2 - ASCII @@ -455,15 +534,17 @@ def view_to_string(self, view: int, decoded: bool, show_pauses=True, sample_rate return None if show_pauses: - return '%s %s' % (proto, self.get_pause_str(sample_rate)) + return "%s %s" % (proto, self.get_pause_str(sample_rate)) else: return proto def get_pause_str(self, sample_rate): if sample_rate: - return ' [Pause: %s]' % (Formatter.science_time(self.pause / sample_rate)) + return " [Pause: %s]" % ( + Formatter.science_time(self.pause / sample_rate) + ) else: - return ' [Pause: %d samples]' % (self.pause) + return " [Pause: %d samples]" % (self.pause) def clear_decoded_bits(self): self.__decoded_bits = None @@ -474,7 +555,9 @@ def clear_encoded_bits(self): @staticmethod def from_plain_bits_str(bits, pause=0): plain_bits = list(map(int, bits)) - return Message(plain_bits=plain_bits, pause=pause, message_type=MessageType("none")) + return Message( + plain_bits=plain_bits, pause=pause, message_type=MessageType("none") + ) @staticmethod def from_plain_hex_str(hex_str, pause=0): @@ -482,7 +565,9 @@ def from_plain_hex_str(hex_str, pause=0): bits = "".join((lut[h] for h in hex_str)) return Message.from_plain_bits_str(bits, pause) - def to_xml(self, decoders=None, include_message_type=False, write_bits=False) -> ET.Element: + def to_xml( + self, decoders=None, include_message_type=False, write_bits=False + ) -> ET.Element: root = ET.Element("message") root.set("message_type_id", self.message_type.id) root.set("modulator_index", str(self.modulator_index)) @@ -496,7 +581,9 @@ def to_xml(self, decoders=None, include_message_type=False, write_bits=False) -> try: decoding_index = decoders.index(self.decoder) except ValueError: - logger.warning("Failed to find '{}' in list of decodings".format(self.decoder.name)) + logger.warning( + "Failed to find '{}' in list of decodings".format(self.decoder.name) + ) decoding_index = 0 root.set("decoding_index", str(decoding_index)) if self.participant is not None: @@ -505,7 +592,9 @@ def to_xml(self, decoders=None, include_message_type=False, write_bits=False) -> root.append(self.message_type.to_xml()) return root - def from_xml(self, tag: ET.Element, participants, decoders=None, message_types=None): + def from_xml( + self, tag: ET.Element, participants, decoders=None, message_types=None + ): timestamp = tag.get("timestamp", None) if timestamp: self.timestamp = float(timestamp) @@ -524,7 +613,9 @@ def from_xml(self, tag: ET.Element, participants, decoders=None, message_types=N if part_id: self.participant = Participant.find_matching(part_id, participants) if self.participant is None: - logger.warning("No participant matched the id {0} from xml".format(part_id)) + logger.warning( + "No participant matched the id {0} from xml".format(part_id) + ) if message_type_id and message_types: for message_type in message_types: @@ -537,14 +628,24 @@ def from_xml(self, tag: ET.Element, participants, decoders=None, message_types=N self.message_type = MessageType.from_xml(message_type_tag) @classmethod - def new_from_xml(cls, tag: ET.Element, participants, decoders=None, message_types=None): + def new_from_xml( + cls, tag: ET.Element, participants, decoders=None, message_types=None + ): assert "bits" in tag.attrib result = cls.from_plain_bits_str(bits=tag.get("bits")) - result.from_xml(tag, participants, decoders=decoders, message_types=message_types) + result.from_xml( + tag, participants, decoders=decoders, message_types=message_types + ) return result - def get_label_range(self, lbl: ProtocolLabel, view: int, decode: bool, consider_alignment=False): + def get_label_range( + self, lbl: ProtocolLabel, view: int, decode: bool, consider_alignment=False + ): a = self.alignment_offset if consider_alignment else 0 - start = self.convert_index(index=lbl.start+a, from_view=0, to_view=view, decoded=decode)[0] - end = self.convert_index(index=lbl.end+a, from_view=0, to_view=view, decoded=decode)[1] + start = self.convert_index( + index=lbl.start + a, from_view=0, to_view=view, decoded=decode + )[0] + end = self.convert_index( + index=lbl.end + a, from_view=0, to_view=view, decoded=decode + )[1] return int(start), int(end) diff --git a/src/urh/signalprocessing/MessageType.py b/src/urh/signalprocessing/MessageType.py index efd62f7b62..951a672634 100644 --- a/src/urh/signalprocessing/MessageType.py +++ b/src/urh/signalprocessing/MessageType.py @@ -19,7 +19,14 @@ class MessageType(list): """ - __slots__ = ["name", "show", "__id", "assigned_by_ruleset", "ruleset", "assigned_by_logic_analyzer"] + __slots__ = [ + "name", + "show", + "__id", + "assigned_by_ruleset", + "ruleset", + "assigned_by_logic_analyzer", + ] def __init__(self, name: str, iterable=None, id=None, ruleset=None): iterable = iterable if iterable else [] @@ -68,12 +75,21 @@ def unlabeled_ranges(self): """ return self.__get_unlabeled_ranges_from_labels(self) - def __create_label(self, name: str, start: int, end: int, color_index: int, auto_created: bool, - field_type: FieldType): + def __create_label( + self, + name: str, + start: int, + end: int, + color_index: int, + auto_created: bool, + field_type: FieldType, + ): if field_type is not None: if field_type.function == FieldType.Function.CHECKSUM: # If we have sync or preamble labels start behind last one: - pre_sync_label_ends = [lbl.end for lbl in self if lbl.is_preamble or lbl.is_sync] + pre_sync_label_ends = [ + lbl.end for lbl in self if lbl.is_preamble or lbl.is_sync + ] if len(pre_sync_label_ends) > 0: range_start = max(pre_sync_label_ends) else: @@ -82,11 +98,24 @@ def __create_label(self, name: str, start: int, end: int, color_index: int, auto if range_start >= start: range_start = 0 - return ChecksumLabel(name=name, start=start, end=end, color_index=color_index, field_type=field_type, - auto_created=auto_created, data_range_start=range_start) - - return ProtocolLabel(name=name, start=start, end=end, color_index=color_index, field_type=field_type, - auto_created=auto_created) + return ChecksumLabel( + name=name, + start=start, + end=end, + color_index=color_index, + field_type=field_type, + auto_created=auto_created, + data_range_start=range_start, + ) + + return ProtocolLabel( + name=name, + start=start, + end=end, + color_index=color_index, + field_type=field_type, + auto_created=auto_created, + ) @staticmethod def __get_unlabeled_ranges_from_labels(labels): @@ -114,11 +143,26 @@ def unlabeled_ranges_with_other_mt(self, other_message_type): labels.sort() return self.__get_unlabeled_ranges_from_labels(labels) - def get_first_label_with_type(self, field_type: FieldType.Function) -> ProtocolLabel: - return next((lbl for lbl in self if lbl.field_type and lbl.field_type.function == field_type), None) + def get_first_label_with_type( + self, field_type: FieldType.Function + ) -> ProtocolLabel: + return next( + ( + lbl + for lbl in self + if lbl.field_type and lbl.field_type.function == field_type + ), + None, + ) def num_labels_with_type(self, field_type: FieldType.Function) -> int: - return len([lbl for lbl in self if lbl.field_type and lbl.field_type.function == field_type]) + return len( + [ + lbl + for lbl in self + if lbl.field_type and lbl.field_type.function == field_type + ] + ) def append(self, lbl: ProtocolLabel): super().append(lbl) @@ -127,12 +171,20 @@ def append(self, lbl: ProtocolLabel): def give_new_id(self): self.__id = str(uuid.uuid4()) - def add_protocol_label(self, start: int, end: int, name=None, color_ind=None, - auto_created=False, type: FieldType = None) -> ProtocolLabel: - + def add_protocol_label( + self, + start: int, + end: int, + name=None, + color_ind=None, + auto_created=False, + type: FieldType = None, + ) -> ProtocolLabel: name = "" if not name else name used_colors = [p.color_index for p in self] - avail_colors = [i for i, _ in enumerate(settings.LABEL_COLORS) if i not in used_colors] + avail_colors = [ + i for i, _ in enumerate(settings.LABEL_COLORS) if i not in used_colors + ] if color_ind is None: if len(avail_colors) > 0: @@ -140,8 +192,14 @@ def add_protocol_label(self, start: int, end: int, name=None, color_ind=None, else: color_ind = random.randint(0, len(settings.LABEL_COLORS) - 1) - proto_label = self.__create_label(name=name, start=start, end=end, color_index=color_ind, - auto_created=auto_created, field_type=type) + proto_label = self.__create_label( + name=name, + start=start, + end=end, + color_index=color_ind, + auto_created=auto_created, + field_type=type, + ) if proto_label not in self: self.append(proto_label) @@ -149,15 +207,28 @@ def add_protocol_label(self, start: int, end: int, name=None, color_ind=None, return proto_label # Return label to set editor focus after adding - def add_protocol_label_start_length(self, start: int, length: int, name=None, color_ind=None, - auto_created=False, type: FieldType = None) -> ProtocolLabel: - return self.add_protocol_label(start, start + length - 1, name, color_ind, auto_created, type) + def add_protocol_label_start_length( + self, + start: int, + length: int, + name=None, + color_ind=None, + auto_created=False, + type: FieldType = None, + ) -> ProtocolLabel: + return self.add_protocol_label( + start, start + length - 1, name, color_ind, auto_created, type + ) def add_label(self, lbl: ProtocolLabel, allow_overlapping=True): if allow_overlapping or not any(lbl.overlaps_with(l) for l in self): - added = self.add_protocol_label(lbl.start, lbl.end - 1, - name=lbl.name, color_ind=lbl.color_index, - type=lbl.field_type) + added = self.add_protocol_label( + lbl.start, + lbl.end - 1, + name=lbl.name, + color_ind=lbl.color_index, + type=lbl.field_type, + ) added.display_format_index = lbl.display_format_index added.display_bit_order_index = lbl.display_bit_order_index if isinstance(lbl, ChecksumLabel) and isinstance(added, ChecksumLabel): @@ -177,17 +248,34 @@ def change_field_type_of_label(self, label: ProtocolLabel, field_type: FieldType label.field_type = field_type return - is_crc_type = field_type is not None and field_type.function == FieldType.Function.CHECKSUM + is_crc_type = ( + field_type is not None + and field_type.function == FieldType.Function.CHECKSUM + ) if is_crc_type != isinstance(label, ChecksumLabel): - self[self.index(label)] = self.__create_label(label.name, label.start, label.end - 1, - label.color_index, label.auto_created, field_type) + self[self.index(label)] = self.__create_label( + label.name, + label.start, + label.end - 1, + label.color_index, + label.auto_created, + field_type, + ) else: label.field_type = field_type def to_xml(self) -> ET.Element: - result = ET.Element("message_type", attrib={"name": self.name, "id": self.id, - "assigned_by_ruleset": "1" if self.assigned_by_ruleset else "0", - "assigned_by_logic_analyzer": "1" if self.assigned_by_logic_analyzer else "0"}) + result = ET.Element( + "message_type", + attrib={ + "name": self.name, + "id": self.id, + "assigned_by_ruleset": "1" if self.assigned_by_ruleset else "0", + "assigned_by_logic_analyzer": "1" + if self.assigned_by_logic_analyzer + else "0", + }, + ) for lbl in self: try: result.append(lbl.to_xml()) @@ -208,10 +296,23 @@ def from_xml(tag: ET.Element): assigned_by_logic_analyzer = bool(int(tag.get("assigned_by_logic_analyzer", 0))) labels = [] for lbl_tag in tag.findall("label"): - labels.append(ProtocolLabel.from_xml(lbl_tag, field_types_by_caption=field_types_by_caption)) + labels.append( + ProtocolLabel.from_xml( + lbl_tag, field_types_by_caption=field_types_by_caption + ) + ) for lbl_tag in tag.findall("checksum_label"): - labels.append(ChecksumLabel.from_xml(lbl_tag, field_types_by_caption=field_types_by_caption)) - result = MessageType(name=name, iterable=labels, id=id, ruleset=Ruleset.from_xml(tag.find("ruleset"))) + labels.append( + ChecksumLabel.from_xml( + lbl_tag, field_types_by_caption=field_types_by_caption + ) + ) + result = MessageType( + name=name, + iterable=labels, + id=id, + ruleset=Ruleset.from_xml(tag.find("ruleset")), + ) result.assigned_by_ruleset = assigned_by_ruleset result.assigned_by_logic_analyzer = assigned_by_logic_analyzer diff --git a/src/urh/signalprocessing/Modulator.py b/src/urh/signalprocessing/Modulator.py index ec67c015a6..b3c766b299 100644 --- a/src/urh/signalprocessing/Modulator.py +++ b/src/urh/signalprocessing/Modulator.py @@ -18,19 +18,21 @@ class Modulator(object): FORCE_DTYPE = None MODULATION_TYPES = ["ASK", "FSK", "PSK", "GFSK", "OQPSK"] - MODULATION_TYPES_VERBOSE = {"ASK": "Amplitude Shift Keying (ASK)", - "FSK": "Frequency Shift Keying (FSK)", - "PSK": "Phase Shift Keying (PSK)", - "OQPSK": "Offset Quadrature Phase Shift Keying (OQPSK)", - "GFSK": "Gaussian Frequeny Shift Keying (GFSK)"} + MODULATION_TYPES_VERBOSE = { + "ASK": "Amplitude Shift Keying (ASK)", + "FSK": "Frequency Shift Keying (FSK)", + "PSK": "Phase Shift Keying (PSK)", + "OQPSK": "Offset Quadrature Phase Shift Keying (OQPSK)", + "GFSK": "Gaussian Frequeny Shift Keying (GFSK)", + } def __init__(self, name: str): - self.carrier_freq_hz = 40 * 10 ** 3 + self.carrier_freq_hz = 40 * 10**3 self.carrier_amplitude = 1 self.carrier_phase_deg = 0 self.data = [True, False, True, False] self.samples_per_symbol = 100 - self.default_sample_rate = 10 ** 6 + self.default_sample_rate = 10**6 self.__sample_rate = None self.__modulation_type = "ASK" @@ -41,18 +43,22 @@ def __init__(self, name: str): self.gauss_bt = 0.5 # bt product for gaussian filter (GFSK) self.gauss_filter_width = 1 # filter width for gaussian filter (GFSK) - self.parameters = array.array("f", [0, 100]) # Freq, Amplitude (0..100%) or Phase (0..360) + self.parameters = array.array( + "f", [0, 100] + ) # Freq, Amplitude (0..100%) or Phase (0..360) def __eq__(self, other): - return self.carrier_freq_hz == other.carrier_freq_hz and \ - self.carrier_amplitude == other.carrier_amplitude and \ - self.carrier_phase_deg == other.carrier_phase_deg and \ - self.name == other.name and \ - self.modulation_type == other.modulation_type and \ - self.samples_per_symbol == other.samples_per_symbol and \ - self.bits_per_symbol == other.bits_per_symbol and \ - self.sample_rate == other.sample_rate and \ - self.parameters == other.parameters + return ( + self.carrier_freq_hz == other.carrier_freq_hz + and self.carrier_amplitude == other.carrier_amplitude + and self.carrier_phase_deg == other.carrier_phase_deg + and self.name == other.name + and self.modulation_type == other.modulation_type + and self.samples_per_symbol == other.samples_per_symbol + and self.bits_per_symbol == other.bits_per_symbol + and self.sample_rate == other.sample_rate + and self.parameters == other.parameters + ) @staticmethod def get_dtype(): @@ -108,7 +114,7 @@ def bits_per_symbol(self, value): @property def modulation_order(self): - return 2 ** self.bits_per_symbol + return 2**self.bits_per_symbol @property def parameter_type_str(self) -> str: @@ -176,7 +182,9 @@ def carrier_data(self): num_samples = len(self.display_bits) * self.samples_per_symbol carrier_phase_rad = self.carrier_phase_deg * (np.pi / 180) t = (np.arange(0, num_samples) / self.sample_rate).astype(np.float32) - arg = (2 * np.pi * self.carrier_freq_hz * t + carrier_phase_rad).astype(np.float32) + arg = (2 * np.pi * self.carrier_freq_hz * t + carrier_phase_rad).astype( + np.float32 + ) y = self.carrier_amplitude * np.sin(arg) # type: np.ndarray return y.astype(np.float32) @@ -188,7 +196,9 @@ def data_scene(self) -> QGraphicsScene: for i, bit in enumerate(self.display_bits): if bit == "0": - y[i*self.samples_per_symbol:(i + 1) * self.samples_per_symbol] = -1.0 + y[ + i * self.samples_per_symbol : (i + 1) * self.samples_per_symbol + ] = -1.0 x = np.arange(0, n).astype(np.int64) @@ -222,16 +232,26 @@ def modulate(self, data=None, pause=0, start=0, dtype=None) -> IQArray: parameters = self.parameters if self.modulation_type == "ASK": - parameters = array.array("f", [a*p/100 for p in parameters]) + parameters = array.array("f", [a * p / 100 for p in parameters]) elif self.modulation_type == "PSK": parameters = array.array("f", [p * (math.pi / 180) for p in parameters]) - result = signal_functions.modulate_c(data, self.samples_per_symbol, - self.modulation_type, parameters, self.bits_per_symbol, - a, self.carrier_freq_hz, - self.carrier_phase_deg * (np.pi / 180), - self.sample_rate, pause, start, dtype, - self.gauss_bt, self.gauss_filter_width) + result = signal_functions.modulate_c( + data, + self.samples_per_symbol, + self.modulation_type, + parameters, + self.bits_per_symbol, + a, + self.carrier_freq_hz, + self.carrier_phase_deg * (np.pi / 180), + self.sample_rate, + pause, + start, + dtype, + self.gauss_bt, + self.gauss_filter_width, + ) return IQArray(result) def get_default_parameters(self) -> array.array: @@ -240,12 +260,16 @@ def get_default_parameters(self) -> array.array: elif self.is_frequency_based: parameters = [] for i in range(self.modulation_order): - parameters.append((i + 1) * self.carrier_freq_hz / self.modulation_order) + parameters.append( + (i + 1) * self.carrier_freq_hz / self.modulation_order + ) elif self.is_phase_based: step = 360 / self.modulation_order parameters = np.arange(step / 2, 360, step) - 180 if self.modulation_type == "OQPSK": - parameters = parameters[(self.__get_gray_code_indices(self.modulation_order))] + parameters = parameters[ + (self.__get_gray_code_indices(self.modulation_order)) + ] else: return None @@ -262,8 +286,14 @@ def to_xml(self, index: int) -> ET.Element: root = ET.Element("modulator") for attr, val in vars(self).items(): - if attr not in ("data", "_Modulator__sample_rate", "_Modulator__modulation_type", - "_Modulator__bits_per_symbol", "default_sample_rate", "parameters"): + if attr not in ( + "data", + "_Modulator__sample_rate", + "_Modulator__modulation_type", + "_Modulator__bits_per_symbol", + "default_sample_rate", + "parameters", + ): root.set(attr, str(val)) root.set("sample_rate", str(self.__sample_rate)) @@ -298,7 +328,9 @@ def from_xml(tag: ET.Element): # samples_per_bit as legacy support for older project files result.samples_per_symbol = Formatter.str2val(value, int, 100) elif attrib == "sample_rate": - result.sample_rate = Formatter.str2val(value, float, 1e6) if value != "None" else None + result.sample_rate = ( + Formatter.str2val(value, float, 1e6) if value != "None" else None + ) elif attrib == "param_for_zero": result.parameters[0] = Formatter.str2val(value, float, 0) # legacy elif attrib == "param_for_one": @@ -341,13 +373,17 @@ def modulators_from_xml_tag(xml_tag: ET.Element) -> list: def get_value_with_suffix(value, unit=""): decimal_point = locale.localeconv()["decimal_point"] - if abs(value) >= 10 ** 9: - target_val, suffix = value / 10 ** 9, "G" - elif abs(value) >= 10 ** 6: - target_val, suffix = value / 10 ** 6, "M" - elif abs(value) >= 10 ** 3: - target_val, suffix = value / 10 ** 3, "k" + if abs(value) >= 10**9: + target_val, suffix = value / 10**9, "G" + elif abs(value) >= 10**6: + target_val, suffix = value / 10**6, "M" + elif abs(value) >= 10**3: + target_val, suffix = value / 10**3, "k" else: target_val, suffix = value, "" - return locale.format_string("%.3f", target_val).rstrip("0").rstrip(decimal_point) + suffix + unit + return ( + locale.format_string("%.3f", target_val).rstrip("0").rstrip(decimal_point) + + suffix + + unit + ) diff --git a/src/urh/signalprocessing/Participant.py b/src/urh/signalprocessing/Participant.py index 00b942f4b7..f591d5c8ba 100644 --- a/src/urh/signalprocessing/Participant.py +++ b/src/urh/signalprocessing/Participant.py @@ -3,12 +3,31 @@ class Participant(object): - __slots__ = ["name", "shortname", "address_hex", "color_index", "show", "simulate", "relative_rssi", "__id"] - - def __init__(self, name: str, shortname: str = None, address_hex: str = None, - color_index=0, id: str = None, relative_rssi=0, simulate=False): + __slots__ = [ + "name", + "shortname", + "address_hex", + "color_index", + "show", + "simulate", + "relative_rssi", + "__id", + ] + + def __init__( + self, + name: str, + shortname: str = None, + address_hex: str = None, + color_index=0, + id: str = None, + relative_rssi=0, + simulate=False, + ): self.name = name if name else "unknown" - self.shortname = shortname if shortname else name[0].upper() if len(name) > 0 else "X" + self.shortname = ( + shortname if shortname else name[0].upper() if len(name) > 0 else "X" + ) self.address_hex = address_hex if address_hex else "" self.color_index = color_index self.show = True @@ -78,8 +97,15 @@ def from_xml(tag: ET.Element): except ValueError: simulate = False - return Participant(name, shortname=shortname, address_hex=address_hex, color_index=color_index, - id=tag.attrib["id"], relative_rssi=relative_rssi, simulate=simulate) + return Participant( + name, + shortname=shortname, + address_hex=address_hex, + color_index=color_index, + id=tag.attrib["id"], + relative_rssi=relative_rssi, + simulate=simulate, + ) @staticmethod def participants_to_xml_tag(participants: list) -> ET.Element: diff --git a/src/urh/signalprocessing/ProtocoLabel.py b/src/urh/signalprocessing/ProtocoLabel.py index ab42e42a33..fda528e7ef 100644 --- a/src/urh/signalprocessing/ProtocoLabel.py +++ b/src/urh/signalprocessing/ProtocoLabel.py @@ -21,12 +21,34 @@ class ProtocolLabel(object): SEARCH_TYPES = ["Number", "Bits", "Hex", "ASCII"] - __slots__ = ("__name", "start", "end", "apply_decoding", "color_index", "show", "__fuzz_me", "fuzz_values", - "fuzz_created", "__field_type", "display_format_index", "display_bit_order_index", - "display_endianness", "auto_created", "copied") - - def __init__(self, name: str, start: int, end: int, color_index: int, fuzz_created=False, - auto_created=False, field_type: FieldType = None): + __slots__ = ( + "__name", + "start", + "end", + "apply_decoding", + "color_index", + "show", + "__fuzz_me", + "fuzz_values", + "fuzz_created", + "__field_type", + "display_format_index", + "display_bit_order_index", + "display_endianness", + "auto_created", + "copied", + ) + + def __init__( + self, + name: str, + start: int, + end: int, + color_index: int, + fuzz_created=False, + auto_created=False, + field_type: FieldType = None, + ): self.__name = name self.start = start self.end = end + 1 @@ -45,7 +67,9 @@ def __init__(self, name: str, start: int, end: int, color_index: int, fuzz_creat else: self.__field_type = field_type # type: FieldType - self.display_format_index = 0 if field_type is None else field_type.display_format_index + self.display_format_index = ( + 0 if field_type is None else field_type.display_format_index + ) self.display_bit_order_index = 0 self.display_endianness = "big" @@ -65,11 +89,17 @@ def fuzz_me(self, value): @property def is_preamble(self) -> bool: - return self.field_type is not None and self.field_type.function == FieldType.Function.PREAMBLE + return ( + self.field_type is not None + and self.field_type.function == FieldType.Function.PREAMBLE + ) @property def is_sync(self) -> bool: - return self.field_type is not None and self.field_type.function == FieldType.Function.SYNC + return ( + self.field_type is not None + and self.field_type.function == FieldType.Function.SYNC + ) @property def length(self) -> int: @@ -123,7 +153,9 @@ def range_complete_fuzzed(self) -> bool: def display_order_str(self) -> str: try: bit_order = self.DISPLAY_BIT_ORDERS[self.display_bit_order_index] - return bit_order + "/{}".format("BE" if self.display_endianness == "big" else "LE") + return bit_order + "/{}".format( + "BE" if self.display_endianness == "big" else "LE" + ) except IndexError: return "" @@ -163,25 +195,33 @@ def __lt__(self, other): return False def __eq__(self, other): - return self.start == other.start and \ - self.end == other.end and \ - self.name == other.name and \ - self.field_type_function == other.field_type_function + return ( + self.start == other.start + and self.end == other.end + and self.name == other.name + and self.field_type_function == other.field_type_function + ) def __hash__(self): return hash((self.start, self.end, self.name, self.field_type_function)) def __repr__(self): - return "Protocol Label - start: {0} end: {1} name: {2}".format(self.start, self.end, self.name) + return "Protocol Label - start: {0} end: {1} name: {2}".format( + self.start, self.end, self.name + ) def overlaps_with(self, other_label): - return Interval(self.start, self.end).overlaps_with(Interval(other_label.start, other_label.end)) + return Interval(self.start, self.end).overlaps_with( + Interval(other_label.start, other_label.end) + ) def add_fuzz_value(self): cur_val = self.fuzz_values[-1] format_string = "{0:0" + str(len(cur_val)) + "b}" maximum = 2 ** len(cur_val) - cur_val = format_string.format((int(str(Formatter.str2val(cur_val, int)), 2) + 1) % maximum) + cur_val = format_string.format( + (int(str(Formatter.str2val(cur_val, int)), 2) + 1) % maximum + ) self.fuzz_values.append(cur_val) @@ -191,14 +231,23 @@ def add_decimal_fuzz_value(self, val: int): self.fuzz_values.append(format_string.format(val)) def to_xml(self) -> ET.Element: - return ET.Element("label", attrib={"name": self.__name, "start": str(self.start), "end": str(self.end), - "color_index": str(self.color_index), - "apply_decoding": str(self.apply_decoding), "show": str(self.show), - "display_format_index": str(self.display_format_index), - "display_bit_order_index": str(self.display_bit_order_index), - "display_endianness": str(self.display_endianness), - "fuzz_me": str(self.fuzz_me), "fuzz_values": ",".join(self.fuzz_values), - "auto_created": str(self.auto_created)}) + return ET.Element( + "label", + attrib={ + "name": self.__name, + "start": str(self.start), + "end": str(self.end), + "color_index": str(self.color_index), + "apply_decoding": str(self.apply_decoding), + "show": str(self.show), + "display_format_index": str(self.display_format_index), + "display_bit_order_index": str(self.display_bit_order_index), + "display_endianness": str(self.display_endianness), + "fuzz_me": str(self.fuzz_me), + "fuzz_values": ",".join(self.fuzz_values), + "auto_created": str(self.auto_created), + }, + ) @classmethod def from_xml(cls, tag: ET.Element, field_types_by_caption=None): @@ -208,18 +257,30 @@ def from_xml(cls, tag: ET.Element, field_types_by_caption=None): :type field_types_by_caption: dict[str, FieldType] :return: """ - field_types_by_caption = dict() if field_types_by_caption is None else field_types_by_caption + field_types_by_caption = ( + dict() if field_types_by_caption is None else field_types_by_caption + ) name = tag.get("name") start, end = int(tag.get("start", 0)), int(tag.get("end", 0)) - 1 color_index = int(tag.get("color_index", 0)) result = ProtocolLabel(name=name, start=start, end=end, color_index=color_index) - result.apply_decoding = True if tag.get("apply_decoding", 'True') == "True" else False - result.show = Qt.Checked if Formatter.str2val(tag.get("show", 0), int) else Qt.Unchecked - result.fuzz_me = Qt.Checked if Formatter.str2val(tag.get("fuzz_me", 0), int) else Qt.Unchecked + result.apply_decoding = ( + True if tag.get("apply_decoding", "True") == "True" else False + ) + result.show = ( + Qt.Checked if Formatter.str2val(tag.get("show", 0), int) else Qt.Unchecked + ) + result.fuzz_me = ( + Qt.Checked + if Formatter.str2val(tag.get("fuzz_me", 0), int) + else Qt.Unchecked + ) result.fuzz_values = tag.get("fuzz_values", "").split(",") - result.auto_created = True if tag.get("auto_created", 'False') == "True" else False + result.auto_created = ( + True if tag.get("auto_created", "False") == "True" else False + ) if result.name in field_types_by_caption: result.field_type = field_types_by_caption[result.name] diff --git a/src/urh/signalprocessing/ProtocolAnalyzer.py b/src/urh/signalprocessing/ProtocolAnalyzer.py index dcb1510767..401b5e7e36 100644 --- a/src/urh/signalprocessing/ProtocolAnalyzer.py +++ b/src/urh/signalprocessing/ProtocolAnalyzer.py @@ -49,12 +49,16 @@ def __init__(self, signal: Signal or None, filename=None): assert signal is None self.filename = filename - self.__name = urh_util.get_name_from_filename(filename) # Fallback if Signal has no Name + self.__name = urh_util.get_name_from_filename( + filename + ) # Fallback if Signal has no Name self.show = Qt.Checked # Show in Compare Frame? self.qt_signals = ProtocolAnalyzerSignals() - self.decoder = Encoding(["Non Return To Zero (NRZ)"]) # For Default Encoding of Protocol + self.decoder = Encoding( + ["Non Return To Zero (NRZ)"] + ) # For Default Encoding of Protocol self.message_types = [MessageType("Default")] @@ -167,18 +171,19 @@ def plain_to_string(self, view: int, show_pauses=True) -> str: :param view: 0 - Bits ## 1 - Hex ## 2 - ASCII """ - time = settings.read('show_pause_as_time', type=bool) + time = settings.read("show_pause_as_time", type=bool) if show_pauses and time and self.signal: srate = self.signal.sample_rate else: srate = None - return '\n'.join(msg.view_to_string(view, False, show_pauses, - sample_rate=srate - ) for msg in self.messages) + return "\n".join( + msg.view_to_string(view, False, show_pauses, sample_rate=srate) + for msg in self.messages + ) def plain_to_html(self, view, show_pauses=True) -> str: - time = settings.read('show_pause_as_time', type=bool) + time = settings.read("show_pause_as_time", type=bool) if show_pauses and time and self.signal: srate = self.signal.sample_rate else: @@ -190,16 +195,23 @@ def plain_to_html(self, view, show_pauses=True) -> str: if message.participant: color = settings.PARTICIPANT_COLORS[message.participant.color_index] red, green, blue = color.red(), color.green(), color.blue() - fgcolor = "#000000" if (red * 0.299 + green * 0.587 + blue * 0.114) > 186 else "#ffffff" - cur_str += ''.format(red, green, blue, - fgcolor) + fgcolor = ( + "#000000" + if (red * 0.299 + green * 0.587 + blue * 0.114) > 186 + else "#ffffff" + ) + cur_str += ''.format( + red, green, blue, fgcolor + ) # cur_str += ''.format(red, green, blue) - cur_str += message.view_to_string(view=view, decoded=False, show_pauses=False, sample_rate=srate) + cur_str += message.view_to_string( + view=view, decoded=False, show_pauses=False, sample_rate=srate + ) if message.participant: - cur_str += '' + cur_str += "" cur_str += message.get_pause_str(sample_rate=srate) result.append(cur_str) @@ -225,31 +237,55 @@ def get_protocol_from_signal(self): samples_per_symbol = signal.samples_per_symbol - ppseq = signal_functions.grab_pulse_lens(signal.qad, signal.center, signal.tolerance, - signal.modulation_type, signal.samples_per_symbol, - signal.bits_per_symbol, signal.center_spacing) - - bit_data, pauses, bit_sample_pos = self._ppseq_to_bits(ppseq, samples_per_symbol, self.signal.bits_per_symbol, - pause_threshold=signal.pause_threshold) + ppseq = signal_functions.grab_pulse_lens( + signal.qad, + signal.center, + signal.tolerance, + signal.modulation_type, + signal.samples_per_symbol, + signal.bits_per_symbol, + signal.center_spacing, + ) + + bit_data, pauses, bit_sample_pos = self._ppseq_to_bits( + ppseq, + samples_per_symbol, + self.signal.bits_per_symbol, + pause_threshold=signal.pause_threshold, + ) if signal.message_length_divisor > 1 and signal.modulation_type == "ASK": - self.__ensure_message_length_multiple(bit_data, signal.samples_per_symbol, pauses, bit_sample_pos, - signal.message_length_divisor) + self.__ensure_message_length_multiple( + bit_data, + signal.samples_per_symbol, + pauses, + bit_sample_pos, + signal.message_length_divisor, + ) i = 0 for bits, pause in zip(bit_data, pauses): middle_bit_pos = bit_sample_pos[i][int(len(bits) / 2)] start, end = middle_bit_pos, middle_bit_pos + samples_per_symbol rssi = np.mean(signal.iq_array.subarray(start, end).magnitudes_normalized) - message = Message(bits, pause, message_type=self.default_message_type, - samples_per_symbol=samples_per_symbol, rssi=rssi, decoder=self.decoder, - bit_sample_pos=bit_sample_pos[i], bits_per_symbol=signal.bits_per_symbol) + message = Message( + bits, + pause, + message_type=self.default_message_type, + samples_per_symbol=samples_per_symbol, + rssi=rssi, + decoder=self.decoder, + bit_sample_pos=bit_sample_pos[i], + bits_per_symbol=signal.bits_per_symbol, + ) self.messages.append(message) i += 1 self.qt_signals.protocol_updated.emit() @staticmethod - def __ensure_message_length_multiple(bit_data, samples_per_symbol: int, pauses, bit_sample_pos, divisor: int): + def __ensure_message_length_multiple( + bit_data, samples_per_symbol: int, pauses, bit_sample_pos, divisor: int + ): """ In case of ASK modulation, this method tries to use pauses after messages as zero bits so that the bit lengths of messages are divisible by divisor @@ -272,10 +308,22 @@ def __ensure_message_length_multiple(bit_data, samples_per_symbol: int, pauses, logger.warning("Error padding message " + str(e)) continue - bit_sample_pos[i].extend([bit_sample_pos[i][-1] + (k + 1) * samples_per_symbol for k in range(missing_bits - 1)]) + bit_sample_pos[i].extend( + [ + bit_sample_pos[i][-1] + (k + 1) * samples_per_symbol + for k in range(missing_bits - 1) + ] + ) bit_sample_pos[i].append(bit_sample_pos[i][-1] + pauses[i]) - def _ppseq_to_bits(self, ppseq, samples_per_symbol: int, bits_per_symbol: int, write_bit_sample_pos=True, pause_threshold=8): + def _ppseq_to_bits( + self, + ppseq, + samples_per_symbol: int, + bits_per_symbol: int, + write_bit_sample_pos=True, + pause_threshold=8, + ): bit_sampl_pos = array.array("L", []) bit_sample_positions = [] @@ -289,7 +337,7 @@ def _ppseq_to_bits(self, ppseq, samples_per_symbol: int, bits_per_symbol: int, w there_was_data = False - samples_per_bit = int(samples_per_symbol/bits_per_symbol) + samples_per_bit = int(samples_per_symbol / bits_per_symbol) if len(ppseq) > 0 and ppseq[0, 0] == pause_type: start = 1 # Starts with Pause @@ -310,8 +358,12 @@ def _ppseq_to_bits(self, ppseq, samples_per_symbol: int, bits_per_symbol: int, w if num_symbols <= pause_threshold or pause_threshold == 0: data_bits.extend([0] * (num_symbols * bits_per_symbol)) if write_bit_sample_pos: - bit_sampl_pos.extend([total_samples + k * samples_per_bit - for k in range(num_symbols*bits_per_symbol)]) + bit_sampl_pos.extend( + [ + total_samples + k * samples_per_bit + for k in range(num_symbols * bits_per_symbol) + ] + ) elif not there_was_data: # Ignore this pause, if there were no information @@ -331,25 +383,40 @@ def _ppseq_to_bits(self, ppseq, samples_per_symbol: int, bits_per_symbol: int, w pauses.append(num_samples) there_was_data = False else: - data_bits.extend(util.number_to_bits(cur_pulse_type, bits_per_symbol) * num_symbols) + data_bits.extend( + util.number_to_bits(cur_pulse_type, bits_per_symbol) * num_symbols + ) if not there_was_data and num_symbols > 0: there_was_data = True if write_bit_sample_pos: - bit_sampl_pos.extend([total_samples + k * samples_per_bit for k in range(num_symbols*bits_per_symbol)]) + bit_sampl_pos.extend( + [ + total_samples + k * samples_per_bit + for k in range(num_symbols * bits_per_symbol) + ] + ) total_samples += num_samples if there_was_data: resulting_data_bits.append(data_bits[:]) if write_bit_sample_pos: - bit_sample_positions.append(bit_sampl_pos[:] + array.array("L", [total_samples])) + bit_sample_positions.append( + bit_sampl_pos[:] + array.array("L", [total_samples]) + ) pause = ppseq[-1, 1] if ppseq[-1, 0] == pause_type else 0 pauses.append(pause) return resulting_data_bits, pauses, bit_sample_positions - def get_samplepos_of_bitseq(self, start_message: int, start_index: int, end_message: int, end_index: int, - include_pause: bool): + def get_samplepos_of_bitseq( + self, + start_message: int, + start_index: int, + end_message: int, + end_index: int, + include_pause: bool, + ): """ Determine on which place (regarding samples) a bit sequence is :rtype: tuple[int,int] @@ -415,16 +482,26 @@ def get_bitseq_from_selection(self, selection_start: int, selection_width: int): last_index = len(self.messages[-1].plain_bits) + 1 return start_message, start_index, last_message, last_index - def delete_messages(self, msg_start: int, msg_end: int, start: int, end: int, view: int, decoded: bool, - update_label_ranges=True): + def delete_messages( + self, + msg_start: int, + msg_end: int, + start: int, + end: int, + view: int, + decoded: bool, + update_label_ranges=True, + ): removable_msg_indices = [] for i in range(msg_start, msg_end + 1): try: - bs, be = self.convert_range(start, end, view, 0, decoded, message_indx=i) + bs, be = self.convert_range( + start, end, view, 0, decoded, message_indx=i + ) self.messages[i].clear_decoded_bits() if update_label_ranges: - del self.messages[i][bs:be + 1] + del self.messages[i][bs : be + 1] else: self.messages[i].delete_range_without_label_range_update(bs, be + 1) if len(self.messages[i]) == 0: @@ -438,7 +515,9 @@ def delete_messages(self, msg_start: int, msg_end: int, start: int, end: int, vi return removable_msg_indices - def convert_index(self, index: int, from_view: int, to_view: int, decoded: bool, message_indx=-1) -> tuple: + def convert_index( + self, index: int, from_view: int, to_view: int, decoded: bool, message_indx=-1 + ) -> tuple: """ Konvertiert einen Index aus der einen Sicht (z.B. Bit) in eine andere (z.B. Hex) @@ -449,25 +528,40 @@ def convert_index(self, index: int, from_view: int, to_view: int, decoded: bool, return 0, 0 if message_indx == -1: - message_indx = self.messages.index(max(self.messages, key=len)) # Longest message + message_indx = self.messages.index( + max(self.messages, key=len) + ) # Longest message if message_indx >= len(self.messages): message_indx = len(self.messages) - 1 - return self.messages[message_indx].convert_index(index, from_view, to_view, decoded) - - def convert_range(self, index1: int, index2: int, from_view: int, - to_view: int, decoded: bool, message_indx=-1): + return self.messages[message_indx].convert_index( + index, from_view, to_view, decoded + ) + + def convert_range( + self, + index1: int, + index2: int, + from_view: int, + to_view: int, + decoded: bool, + message_indx=-1, + ): if len(self.messages) == 0: return 0, 0 if message_indx == -1: - message_indx = self.messages.index(max(self.messages, key=len)) # Longest message + message_indx = self.messages.index( + max(self.messages, key=len) + ) # Longest message if message_indx >= len(self.messages): message_indx = len(self.messages) - 1 - return self.messages[message_indx].convert_range(index1, index2, from_view, to_view, decoded) + return self.messages[message_indx].convert_range( + index1, index2, from_view, to_view, decoded + ) def estimate_frequency_for_one(self, sample_rate: float, nbits=42) -> float: """ @@ -488,8 +582,12 @@ def align_messages(self, pattern: str, view_type: int, use_decoded=True): else: raise ValueError("Unknown view type {}".format(view_type)) - indices = [msg.decoded_bits_str.find(bit_pattern) if use_decoded else msg.plain_bits_str.find(bit_pattern) - for msg in self.messages] + indices = [ + msg.decoded_bits_str.find(bit_pattern) + if use_decoded + else msg.plain_bits_str.find(bit_pattern) + for msg in self.messages + ] max_index = max(indices) for i, msg in enumerate(self.messages): @@ -504,7 +602,9 @@ def estimate_frequency_for_zero(self, sample_rate: float, nbits=42) -> float: """ return self.__estimate_frequency_for_bit(False, sample_rate, nbits) - def __estimate_frequency_for_bit(self, bit: bool, sample_rate: float, nbits: int) -> float: + def __estimate_frequency_for_bit( + self, bit: bool, sample_rate: float, nbits: int + ) -> float: if nbits == 0: return 0 @@ -513,8 +613,12 @@ def __estimate_frequency_for_bit(self, bit: bool, sample_rate: float, nbits: int for i, message in enumerate(self.messages): for j, msg_bit in enumerate(message.plain_bits): if msg_bit == bit: - start, num_samples = self.get_samplepos_of_bitseq(i, j, i, j + 1, False) - freq = self.signal.estimate_frequency(start, start + num_samples, sample_rate) + start, num_samples = self.get_samplepos_of_bitseq( + i, j, i, j + 1, False + ) + freq = self.signal.estimate_frequency( + start, start + num_samples, sample_rate + ) frequencies.append(freq) if len(frequencies) == nbits: return np.mean(frequencies) @@ -537,7 +641,11 @@ def add_new_message_type(self, labels): i += 1 if name + str(i) not in names: self.message_types.append( - MessageType(name=name + str(i), iterable=[copy.deepcopy(lbl) for lbl in labels])) + MessageType( + name=name + str(i), + iterable=[copy.deepcopy(lbl) for lbl in labels], + ) + ) break def to_binary(self, filename: str, use_decoded: bool): @@ -552,8 +660,16 @@ def from_binary(self, filename: str): unaggregated = [int(b) for n in aggregated for b in "{0:08b}".format(n)] self.messages.append(Message(unaggregated, 0, self.default_message_type)) - def to_xml_tag(self, decodings, participants, tag_name="protocol", - include_message_type=False, write_bits=False, messages=None, modulators=None) -> ET.Element: + def to_xml_tag( + self, + decodings, + participants, + tag_name="protocol", + include_message_type=False, + write_bits=False, + messages=None, + modulators=None, + ) -> ET.Element: root = ET.Element(tag_name) messages = self.messages if messages is None else messages @@ -567,9 +683,11 @@ def to_xml_tag(self, decodings, participants, tag_name="protocol", # Save data data_tag = ET.SubElement(root, "messages") for i, message in enumerate(messages): - message_tag = message.to_xml(decoders=decodings, - include_message_type=include_message_type, - write_bits=write_bits) + message_tag = message.to_xml( + decoders=decodings, + include_message_type=include_message_type, + write_bits=write_bits, + ) data_tag.append(message_tag) # Save message types separatively as not saved in messages already @@ -580,11 +698,24 @@ def to_xml_tag(self, decodings, participants, tag_name="protocol", return root - def to_xml_file(self, filename: str, decoders, participants, tag_name="protocol", - include_message_types=False, write_bits=False, modulators=None): - tag = self.to_xml_tag(decodings=decoders, participants=participants, tag_name=tag_name, - include_message_type=include_message_types, write_bits=write_bits, - modulators=modulators) + def to_xml_file( + self, + filename: str, + decoders, + participants, + tag_name="protocol", + include_message_types=False, + write_bits=False, + modulators=None, + ): + tag = self.to_xml_tag( + decodings=decoders, + participants=participants, + tag_name=tag_name, + include_message_type=include_message_types, + write_bits=write_bits, + modulators=modulators, + ) xmlstr = minidom.parseString(ET.tostring(tag)).toprettyxml(indent=" ") with open(filename, "w") as f: @@ -592,11 +723,17 @@ def to_xml_file(self, filename: str, decoders, participants, tag_name="protocol" if line.strip(): f.write(line + "\n") - def from_xml_tag(self, root: ET.Element, read_bits=False, participants=None, decodings=None): + def from_xml_tag( + self, root: ET.Element, read_bits=False, participants=None, decodings=None + ): if not root: return None - decoders = Encoding.read_decoders_from_xml_tag(root) if decodings is None else decodings + decoders = ( + Encoding.read_decoders_from_xml_tag(root) + if decodings is None + else decodings + ) if participants is None: participants = Participant.read_participants_from_xml_tag(root) @@ -619,14 +756,22 @@ def from_xml_tag(self, root: ET.Element, read_bits=False, participants=None, dec message_tags = root.find("messages").findall("message") for i, message_tag in enumerate(message_tags): if read_bits: - self.messages.append(Message.new_from_xml(tag=message_tag, - participants=participants, - decoders=decoders, - message_types=self.message_types)) + self.messages.append( + Message.new_from_xml( + tag=message_tag, + participants=participants, + decoders=decoders, + message_types=self.message_types, + ) + ) else: try: - self.messages[i].from_xml(tag=message_tag, participants=participants, - decoders=decoders, message_types=self.message_types) + self.messages[i].from_xml( + tag=message_tag, + participants=participants, + decoders=decoders, + message_types=self.message_types, + ) except IndexError: pass # Part of signal was copied in last session but signal was not saved @@ -646,12 +791,20 @@ def from_xml_file(self, filename: str, read_bits=False): root = tree.getroot() self.from_xml_tag(root, read_bits=read_bits) - def to_pcapng(self, filename : str, hardware_desc_name: str = "", link_type: int = 147): - PCAPNG.create_pcapng_file(filename=filename, shb_userappl="Universal Radio Hacker", shb_hardware=hardware_desc_name, link_type=link_type) + def to_pcapng( + self, filename: str, hardware_desc_name: str = "", link_type: int = 147 + ): + PCAPNG.create_pcapng_file( + filename=filename, + shb_userappl="Universal Radio Hacker", + shb_hardware=hardware_desc_name, + link_type=link_type, + ) PCAPNG.append_packets_to_pcapng( filename=filename, packets=(msg.decoded_ascii_buffer for msg in self.messages), - timestamps=(msg.timestamp for msg in self.messages)) + timestamps=(msg.timestamp for msg in self.messages), + ) def eliminate(self): self.message_types = None @@ -662,13 +815,17 @@ def eliminate(self): def update_auto_message_types(self): for message in self.messages: - for message_type in filter(lambda m: m.assigned_by_ruleset and len(m.ruleset) > 0, self.message_types): + for message_type in filter( + lambda m: m.assigned_by_ruleset and len(m.ruleset) > 0, + self.message_types, + ): if message_type.ruleset.applies_for_message(message): message.message_type = message_type break def auto_assign_labels(self): from urh.awre.FormatFinder import FormatFinder + format_finder = FormatFinder(self.messages) format_finder.run(max_iterations=10) @@ -678,7 +835,9 @@ def auto_assign_labels(self): self.messages[i].message_type = msg_type @staticmethod - def get_protocol_from_string(message_strings: list, is_hex=None, default_pause=0, sample_rate=1e6): + def get_protocol_from_string( + message_strings: list, is_hex=None, default_pause=0, sample_rate=1e6 + ): """ :param message_strings: @@ -690,7 +849,7 @@ def get_protocol_from_string(message_strings: list, is_hex=None, default_pause=0 def parse_line(line: str): # support transcript files e.g 1 (A->B): 10101111 index = line.rfind(" ") - line = line[index + 1:] + line = line[index + 1 :] # support pauses given like 100101/10s try: @@ -714,7 +873,9 @@ def parse_line(line: str): for line in filter(None, map(str.strip, message_strings)): bits, pause = parse_line(line) try: - protocol.messages.append(Message.from_plain_bits_str(bits, pause=pause)) + protocol.messages.append( + Message.from_plain_bits_str(bits, pause=pause) + ) except ValueError: is_hex = True if is_hex is None else is_hex break @@ -726,6 +887,8 @@ def parse_line(line: str): for line in filter(None, map(str.strip, message_strings)): bits, pause = parse_line(line) bit_str = [lookup[bits[i].lower()] for i in range(0, len(bits))] - protocol.messages.append(Message.from_plain_bits_str("".join(bit_str), pause=pause)) + protocol.messages.append( + Message.from_plain_bits_str("".join(bit_str), pause=pause) + ) return protocol diff --git a/src/urh/signalprocessing/ProtocolAnalyzerContainer.py b/src/urh/signalprocessing/ProtocolAnalyzerContainer.py index 73b2f354a6..6090e95241 100644 --- a/src/urh/signalprocessing/ProtocolAnalyzerContainer.py +++ b/src/urh/signalprocessing/ProtocolAnalyzerContainer.py @@ -36,7 +36,9 @@ def __init__(self): self.fuzz_pause = 10000 self.__group = ProtocolGroup("GeneratorGroup") - self.__group.add_protocol_item(ProtocolTreeItem(self, None)) # Warning: parent is None + self.__group.add_protocol_item( + ProtocolTreeItem(self, None) + ) # Warning: parent is None @property def protocol_labels(self): @@ -50,12 +52,20 @@ def multiple_fuzz_labels_per_message(self): def insert_protocol_analyzer(self, index: int, proto_analyzer: ProtocolAnalyzer): for msg in reversed(proto_analyzer.messages): - self.messages.insert(index, Message(plain_bits=msg.decoded_bits, pause=msg.pause, - message_type=copy.copy(msg.message_type), - rssi=msg.rssi, modulator_index=0, decoder=msg.decoder, - samples_per_symbol=msg.samples_per_symbol, - participant=msg.participant, bits_per_symbol=msg.bits_per_symbol) - ) + self.messages.insert( + index, + Message( + plain_bits=msg.decoded_bits, + pause=msg.pause, + message_type=copy.copy(msg.message_type), + rssi=msg.rssi, + modulator_index=0, + decoder=msg.decoder, + samples_per_symbol=msg.samples_per_symbol, + participant=msg.participant, + bits_per_symbol=msg.bits_per_symbol, + ), + ) if len(self.pauses) > 0: self.fuzz_pause = self.pauses[0] @@ -78,14 +88,24 @@ def fuzz(self, mode: FuzzMode, default_pause=None): appd_result(msg) if mode == FuzzMode.successive: - combinations = [[(l.start, l.end, fuzz_val)] for l in labels for fuzz_val in l.fuzz_values[1:]] + combinations = [ + [(l.start, l.end, fuzz_val)] + for l in labels + for fuzz_val in l.fuzz_values[1:] + ] elif mode == FuzzMode.concurrent: - num_values = numpy.max([len(l.fuzz_values) for l in labels]) if labels else 0 + num_values = ( + numpy.max([len(l.fuzz_values) for l in labels]) if labels else 0 + ) f = lambda index, label: index if index < len(label.fuzz_values) else 0 - combinations = [[(l.start, l.end, l.fuzz_values[f(j, l)]) for l in labels] for j in - range(1, num_values)] + combinations = [ + [(l.start, l.end, l.fuzz_values[f(j, l)]) for l in labels] + for j in range(1, num_values) + ] elif mode == FuzzMode.exhaustive: - pool = [[(l.start, l.end, fv) for fv in l.fuzz_values[1:]] for l in labels] + pool = [ + [(l.start, l.end, fv) for fv in l.fuzz_values[1:]] for l in labels + ] combinations = list(itertools.product(*pool)) if labels else [] else: raise ValueError("Unknown fuzz mode") @@ -105,10 +125,16 @@ def fuzz(self, mode: FuzzMode, default_pause=None): cpy_bits[start:end] = array.array("B", map(int, fuz_val)) pause = default_pause if default_pause is not None else msg.pause - fuz_msg = Message(plain_bits=cpy_bits, pause=pause, - rssi=msg.rssi, message_type=message_type, - modulator_index=msg.modulator_index, - decoder=msg.decoder, fuzz_created=True, participant=msg.participant) + fuz_msg = Message( + plain_bits=cpy_bits, + pause=pause, + rssi=msg.rssi, + message_type=message_type, + modulator_index=msg.modulator_index, + decoder=msg.decoder, + fuzz_created=True, + participant=msg.participant, + ) added_message_indices.append(i + j + 1) appd_result(fuz_msg) if j % 10000 == 0: @@ -142,16 +168,33 @@ def fuzz_exhaustive(self, default_pause=None): return self.fuzz(FuzzMode.exhaustive, default_pause=default_pause) def create_fuzzing_label(self, start, end, msg_index) -> ProtocolLabel: - fuz_lbl = self.messages[msg_index].message_type.add_protocol_label(start=start, end=end) + fuz_lbl = self.messages[msg_index].message_type.add_protocol_label( + start=start, end=end + ) return fuz_lbl def set_decoder_for_messages(self, decoder, messages=None): raise NotImplementedError("Encoding can't be set in Generator!") - def to_xml_file(self, filename: str, decoders, participants, tag_name="fuzz_profile", - include_message_types=True, write_bits=True, modulators=None): - super().to_xml_file(filename=filename, decoders=decoders, participants=participants, tag_name=tag_name, - include_message_types=include_message_types, write_bits=write_bits, modulators=modulators) + def to_xml_file( + self, + filename: str, + decoders, + participants, + tag_name="fuzz_profile", + include_message_types=True, + write_bits=True, + modulators=None, + ): + super().to_xml_file( + filename=filename, + decoders=decoders, + participants=participants, + tag_name=tag_name, + include_message_types=include_message_types, + write_bits=write_bits, + modulators=modulators, + ) def from_xml_file(self, filename: str, read_bits=True): super().from_xml_file(filename=filename, read_bits=read_bits) diff --git a/src/urh/signalprocessing/ProtocolGroup.py b/src/urh/signalprocessing/ProtocolGroup.py index ea7f0c48ab..4f4e264ee6 100644 --- a/src/urh/signalprocessing/ProtocolGroup.py +++ b/src/urh/signalprocessing/ProtocolGroup.py @@ -93,4 +93,4 @@ def add_protocol_item(self, protocol_item): :type protocol: ProtocolTreeItem :return: """ - self.__items.append(protocol_item) # Warning: parent is None! + self.__items.append(protocol_item) # Warning: parent is None! diff --git a/src/urh/signalprocessing/ProtocolSniffer.py b/src/urh/signalprocessing/ProtocolSniffer.py index 494bc84bde..408834e36f 100644 --- a/src/urh/signalprocessing/ProtocolSniffer.py +++ b/src/urh/signalprocessing/ProtocolSniffer.py @@ -22,15 +22,26 @@ class ProtocolSniffer(ProtocolAnalyzer, QObject): This class is used for live sniffing a protocol with certain signal parameters. """ + started = pyqtSignal() stopped = pyqtSignal() message_sniffed = pyqtSignal(int) BUFFER_SIZE_MB = 100 - def __init__(self, samples_per_symbol: int, center: float, center_spacing: float, - noise: float, tolerance: int, modulation_type: str, bits_per_symbol: int, - device: str, backend_handler: BackendHandler, network_raw_mode=False): + def __init__( + self, + samples_per_symbol: int, + center: float, + center_spacing: float, + noise: float, + tolerance: int, + modulation_type: str, + bits_per_symbol: int, + device: str, + backend_handler: BackendHandler, + network_raw_mode=False, + ): signal = Signal("", "LiveSignal") signal.samples_per_symbol = samples_per_symbol signal.center = center @@ -44,8 +55,13 @@ def __init__(self, samples_per_symbol: int, center: float, center_spacing: float self.network_raw_mode = network_raw_mode self.backend_handler = backend_handler - self.rcv_device = VirtualDevice(self.backend_handler, device, Mode.receive, - resume_on_full_receive_buffer=True, raw_mode=network_raw_mode) + self.rcv_device = VirtualDevice( + self.backend_handler, + device, + Mode.receive, + resume_on_full_receive_buffer=True, + raw_mode=network_raw_mode, + ) signal.iq_array = IQArray(None, self.rcv_device.data_type, 0) @@ -76,7 +92,9 @@ def __add_to_buffer(self, data: np.ndarray): n = len(self.__buffer) - self.__current_buffer_index - 1 logger.warning("Buffer of protocol sniffer is full") - self.__buffer[self.__current_buffer_index:self.__current_buffer_index + n] = data[:n] + self.__buffer[ + self.__current_buffer_index : self.__current_buffer_index + n + ] = data[:n] self.__current_buffer_index += n def __clear_buffer(self): @@ -86,7 +104,9 @@ def __buffer_is_full(self): return self.__current_buffer_index >= len(self.__buffer) - 2 def __init_buffer(self): - self.__buffer = IQArray(None, self.rcv_device.data_type, int(self.BUFFER_SIZE_MB * 1000 * 1000 / 8)) + self.__buffer = IQArray( + None, self.rcv_device.data_type, int(self.BUFFER_SIZE_MB * 1000 * 1000 / 8) + ) self.__current_buffer_index = 0 def decoded_to_string(self, view: int, start=0, include_timestamps=True): @@ -100,7 +120,9 @@ def message_to_string(self, message: Message, view: int, include_timestamps=True if include_timestamps: msg_date = datetime.fromtimestamp(message.timestamp) msg_str_data.append(msg_date.strftime("[%Y-%m-%d %H:%M:%S.%f]")) - msg_str_data.append(message.view_to_string(view, decoded=True, show_pauses=False)) + msg_str_data.append( + message.view_to_string(view, decoded=True, show_pauses=False) + ) return " ".join(msg_str_data) @property @@ -121,8 +143,14 @@ def device_name(self): def device_name(self, value: str): if value != self.rcv_device.name: self.rcv_device.free_data() - self.rcv_device = VirtualDevice(self.backend_handler, value, Mode.receive, device_ip="192.168.10.2", - resume_on_full_receive_buffer=True, raw_mode=self.network_raw_mode) + self.rcv_device = VirtualDevice( + self.backend_handler, + value, + Mode.receive, + device_ip="192.168.10.2", + resume_on_full_receive_buffer=True, + raw_mode=self.network_raw_mode, + ) self.rcv_device.started.connect(self.__emit_started) self.rcv_device.stopped.connect(self.__emit_stopped) @@ -142,10 +170,16 @@ def check_for_data(self): time.sleep(0.01) if self.rcv_device.is_raw_mode: if old_index <= self.rcv_device.current_index: - data = self.rcv_device.data[old_index:self.rcv_device.current_index] + data = self.rcv_device.data[ + old_index : self.rcv_device.current_index + ] else: - data = np.concatenate((self.rcv_device.data[old_index:], - self.rcv_device.data[:self.rcv_device.current_index])) + data = np.concatenate( + ( + self.rcv_device.data[old_index:], + self.rcv_device.data[: self.rcv_device.current_index], + ) + ) old_index = self.rcv_device.current_index self.__demodulate_data(data) elif self.rcv_device.backend == Backends.network: @@ -176,11 +210,14 @@ def __demodulate_data(self, data): if len(data) == 0: return - power_spectrum = data.real ** 2.0 + data.imag ** 2.0 + power_spectrum = data.real**2.0 + data.imag**2.0 is_above_noise = np.sqrt(np.mean(power_spectrum)) > self.signal.noise_threshold if self.adaptive_noise and not is_above_noise: - self.signal.noise_threshold = 0.9 * self.signal.noise_threshold + 0.1 * np.sqrt(np.max(power_spectrum)) + self.signal.noise_threshold = ( + 0.9 * self.signal.noise_threshold + + 0.1 * np.sqrt(np.max(power_spectrum)) + ) if is_above_noise: self.__add_to_buffer(data) @@ -198,24 +235,41 @@ def __demodulate_data(self, data): return # clear cache and start a new message - self.signal.iq_array = IQArray(self.__buffer[0:self.__current_buffer_index]) + self.signal.iq_array = IQArray(self.__buffer[0 : self.__current_buffer_index]) self.__clear_buffer() self.signal._qad = None samples_per_symbol = self.signal.samples_per_symbol if self.automatic_center: - self.signal.center = AutoInterpretation.detect_center(self.signal.qad, max_size=150*samples_per_symbol) - - ppseq = grab_pulse_lens(self.signal.qad, self.signal.center, - self.signal.tolerance, self.signal.modulation_type, self.signal.samples_per_symbol, - self.signal.bits_per_symbol, self.signal.center_spacing) - - bit_data, pauses, bit_sample_pos = self._ppseq_to_bits(ppseq, samples_per_symbol, - self.signal.bits_per_symbol, write_bit_sample_pos=False) + self.signal.center = AutoInterpretation.detect_center( + self.signal.qad, max_size=150 * samples_per_symbol + ) + + ppseq = grab_pulse_lens( + self.signal.qad, + self.signal.center, + self.signal.tolerance, + self.signal.modulation_type, + self.signal.samples_per_symbol, + self.signal.bits_per_symbol, + self.signal.center_spacing, + ) + + bit_data, pauses, bit_sample_pos = self._ppseq_to_bits( + ppseq, + samples_per_symbol, + self.signal.bits_per_symbol, + write_bit_sample_pos=False, + ) for bits, pause in zip(bit_data, pauses): - message = Message(bits, pause, samples_per_symbol=samples_per_symbol, message_type=self.default_message_type, - decoder=self.decoder) + message = Message( + bits, + pause, + samples_per_symbol=samples_per_symbol, + message_type=self.default_message_type, + decoder=self.decoder, + ) self.messages.append(message) self.message_sniffed.emit(len(self.messages) - 1) diff --git a/src/urh/signalprocessing/Ruleset.py b/src/urh/signalprocessing/Ruleset.py index b642ebeca0..2f9b5294f8 100644 --- a/src/urh/signalprocessing/Ruleset.py +++ b/src/urh/signalprocessing/Ruleset.py @@ -5,15 +5,23 @@ from urh.util.Logger import logger OPERATIONS = { - '>': operator.gt, - '<': operator.lt, - '>=': operator.ge, - '<=': operator.le, - '=': operator.eq, - '!=': operator.ne - } + ">": operator.gt, + "<": operator.lt, + ">=": operator.ge, + "<=": operator.le, + "=": operator.eq, + "!=": operator.ne, +} + +OPERATION_DESCRIPTION = { + ">": "greater", + "<": "lower", + ">=": "greater equal", + "<=": "lower equal", + "=": "equal", + "!=": "not equal", +} -OPERATION_DESCRIPTION = {">": "greater", "<": "lower", ">=": "greater equal", "<=": "lower equal", "=": "equal", "!=": "not equal"} class Mode(Enum): all_apply = 0 @@ -22,11 +30,13 @@ class Mode(Enum): class Rule(object): - def __init__(self, start: int, end: int, operator: str, target_value: str, value_type: int): + def __init__( + self, start: int, end: int, operator: str, target_value: str, value_type: int + ): assert operator in OPERATIONS self.__start = start self.__end = end + 1 - self.__value_type = value_type # 0 = Bit, 1 = Hex, 2 = ASCII + self.__value_type = value_type # 0 = Bit, 1 = Hex, 2 = ASCII self.operator = operator self.target_value = target_value @@ -64,8 +74,14 @@ def value_type(self, value: int): logger.warning("{} could not be cast to integer".format(value)) def applies_for_message(self, message): - data = message.decoded_bits_str if self.value_type == 0 else message.decoded_hex_str if self.value_type == 1 else message.decoded_ascii_str - return OPERATIONS[self.operator](data[self.start:self.end], self.target_value) + data = ( + message.decoded_bits_str + if self.value_type == 0 + else message.decoded_hex_str + if self.value_type == 1 + else message.decoded_ascii_str + ) + return OPERATIONS[self.operator](data[self.start : self.end], self.target_value) @property def operator_description(self): @@ -96,7 +112,7 @@ def from_xml(tag: ET.Element): class Ruleset(list): - def __init__(self, mode: Mode = Mode.all_apply, rules = None): + def __init__(self, mode: Mode = Mode.all_apply, rules=None): rules = rules if rules is not None else [] self.mode = mode super().__init__(rules) diff --git a/src/urh/signalprocessing/Signal.py b/src/urh/signalprocessing/Signal.py index eb17d245ff..4e021222a6 100644 --- a/src/urh/signalprocessing/Signal.py +++ b/src/urh/signalprocessing/Signal.py @@ -39,7 +39,14 @@ class Signal(QObject): protocol_needs_update = pyqtSignal() data_edited = pyqtSignal() # On Crop/Mute/Delete etc. - def __init__(self, filename: str, name="Signal", modulation: str = None, sample_rate: float = 1e6, parent=None): + def __init__( + self, + filename: str, + name="Signal", + modulation: str = None, + sample_rate: float = 1e6, + parent=None, + ): super().__init__(parent) self.__name = name self.__tolerance = 5 @@ -66,7 +73,10 @@ def __init__(self, filename: str, name="Signal", modulation: str = None, sample_ self.__bits_per_symbol = 1 self.__center_spacing = 1 # required for higher order modulations - self.__parameter_cache = {mod: {"center": None, "samples_per_symbol": None} for mod in self.MODULATION_TYPES} + self.__parameter_cache = { + mod: {"center": None, "samples_per_symbol": None} + for mod in self.MODULATION_TYPES + } self.__already_demodulated = False @@ -82,11 +92,17 @@ def __init__(self, filename: str, name="Signal", modulation: str = None, sample_ self.filename = filename - default_noise_threshold = settings.read("default_noise_threshold", "automatic") + default_noise_threshold = settings.read( + "default_noise_threshold", "automatic" + ) if default_noise_threshold == "automatic": - self.noise_threshold = AutoInterpretation.detect_noise_level(self.iq_array.magnitudes) + self.noise_threshold = AutoInterpretation.detect_noise_level( + self.iq_array.magnitudes + ) else: - self.noise_threshold = float(default_noise_threshold) / 100 * self.max_magnitude + self.noise_threshold = ( + float(default_noise_threshold) / 100 * self.max_magnitude + ) else: self.filename = "" @@ -95,7 +111,14 @@ def __load_complex_file(self, filename: str): def __load_wav_file(self, filename: str): wav = wave.open(filename, "r") - num_channels, sample_width, sample_rate, num_frames, comptype, compname = wav.getparams() + ( + num_channels, + sample_width, + sample_rate, + num_frames, + comptype, + compname, + ) = wav.getparams() if sample_width == 1: params = {"min": 0, "max": 255, "fmt": np.uint8} # Unsigned Byte @@ -116,20 +139,32 @@ def __load_wav_file(self, filename: str): arr = np.empty((num_samples, num_channels, 4), dtype=np.uint8) raw_bytes = np.frombuffer(byte_frames, dtype=np.uint8) arr[:, :, :sample_width] = raw_bytes.reshape(-1, num_channels, sample_width) - arr[:, :, sample_width:] = (arr[:, :, sample_width - 1:sample_width] >> 7) * 255 + arr[:, :, sample_width:] = ( + arr[:, :, sample_width - 1 : sample_width] >> 7 + ) * 255 data = arr.view(np.int32).flatten() else: data = np.frombuffer(byte_frames, dtype=params["fmt"]) self.iq_array = IQArray(None, np.float32, n=num_frames) if num_channels == 1: - self.iq_array.real = np.multiply(1 / params["max"], np.subtract(data, params["center"])) + self.iq_array.real = np.multiply( + 1 / params["max"], np.subtract(data, params["center"]) + ) self.__already_demodulated = True elif num_channels == 2: - self.iq_array.real = np.multiply(1 / params["max"], np.subtract(data[0::2], params["center"])) - self.iq_array.imag = np.multiply(1 / params["max"], np.subtract(data[1::2], params["center"])) + self.iq_array.real = np.multiply( + 1 / params["max"], np.subtract(data[0::2], params["center"]) + ) + self.iq_array.imag = np.multiply( + 1 / params["max"], np.subtract(data[1::2], params["center"]) + ) else: - raise ValueError("Can't handle {0} channels. Only 1 and 2 are supported.".format(num_channels)) + raise ValueError( + "Can't handle {0} channels. Only 1 and 2 are supported.".format( + num_channels + ) + ) wav.close() @@ -141,22 +176,30 @@ def __load_sub_file(self, filename: str): params = {"min": 0, "max": 255, "fmt": np.uint8} params["center"] = (params["min"] + params["max"]) / 2 arr = [] - with open(filename, 'r') as subfile: + with open(filename, "r") as subfile: for line in subfile: - dataline = re.match(r'RAW_Data:\s*([-0-9 ]+)\s*$', line) + dataline = re.match(r"RAW_Data:\s*([-0-9 ]+)\s*$", line) if dataline: - values = dataline[1].strip().split(' ') + values = dataline[1].strip().split(" ") for value in values: try: intval = int(value) if intval > 0: - arr.extend(np.full(intval, params["max"], dtype=params["fmt"])) + arr.extend( + np.full(intval, params["max"], dtype=params["fmt"]) + ) else: arr.extend(np.zeros(-intval, dtype=params["fmt"])) except ValueError: - logger.warning("Skipped invalid value {0} in sub file {1}.\nLine <{2}>\nValues:<{3}>\n".format(value, filename, line, values)) + logger.warning( + "Skipped invalid value {0} in sub file {1}.\nLine <{2}>\nValues:<{3}>\n".format( + value, filename, line, values + ) + ) self.iq_array = IQArray(None, np.float32, n=len(arr)) - self.iq_array.real = np.multiply(1 / params["max"], np.subtract(arr, params["center"])) + self.iq_array.real = np.multiply( + 1 / params["max"], np.subtract(arr, params["center"]) + ) self.__already_demodulated = True def __load_compressed_complex(self, filename: str): @@ -237,7 +280,7 @@ def samples_per_symbol(self, value): @property def modulation_order(self): - return 2 ** self.bits_per_symbol + return 2**self.bits_per_symbol @property def tolerance(self): @@ -339,7 +382,7 @@ def noise_threshold(self, value): self.clear_parameter_cache() self._noise_threshold = value - middle = 0.5*sum(IQArray.min_max_for_dtype(self.iq_array.dtype)) + middle = 0.5 * sum(IQArray.min_max_for_dtype(self.iq_array.dtype)) a = self.max_amplitude * value / self.max_magnitude self.noise_min_plot = middle - a self.noise_max_plot = middle + a @@ -350,7 +393,7 @@ def noise_threshold(self, value): @property def max_magnitude(self): mi, ma = IQArray.min_max_for_dtype(self.iq_array.dtype) - return (2 * max(mi**2, ma**2))**0.5 + return (2 * max(mi**2, ma**2)) ** 0.5 @property def max_amplitude(self): @@ -369,7 +412,9 @@ def noise_threshold_relative(self, value: float): def qad(self): if self._qad is None: if self.already_demodulated: - self._qad = np.ascontiguousarray(self.real_plot_data, dtype=self.real_plot_data.dtype) + self._qad = np.ascontiguousarray( + self.real_plot_data, dtype=self.real_plot_data.dtype + ) else: self._qad = self.quad_demod() @@ -418,13 +463,19 @@ def save_as(self, filename: str): def quad_demod(self): if self.noise_threshold < self.max_magnitude: - return signal_functions.afp_demod(self.iq_array.data, self.noise_threshold, - self.modulation_type, self.modulation_order, - self.costas_loop_bandwidth) + return signal_functions.afp_demod( + self.iq_array.data, + self.noise_threshold, + self.modulation_type, + self.modulation_order, + self.costas_loop_bandwidth, + ) else: return np.zeros(2, dtype=np.float32) - def calc_relative_noise_threshold_from_range(self, noise_start: int, noise_end: int): + def calc_relative_noise_threshold_from_range( + self, noise_start: int, noise_end: int + ): num_digits = 4 noise_start, noise_end = int(noise_start), int(noise_end) @@ -432,10 +483,16 @@ def calc_relative_noise_threshold_from_range(self, noise_start: int, noise_end: noise_start, noise_end = noise_end, noise_start try: - maximum = np.max(self.iq_array.subarray(noise_start, noise_end).magnitudes_normalized) - return np.ceil(maximum * 10 ** num_digits) / 10 ** num_digits + maximum = np.max( + self.iq_array.subarray(noise_start, noise_end).magnitudes_normalized + ) + return np.ceil(maximum * 10**num_digits) / 10**num_digits except ValueError: - logger.warning("Could not calculate noise threshold for range {}-{}".format(noise_start, noise_end)) + logger.warning( + "Could not calculate noise threshold for range {}-{}".format( + noise_start, noise_end + ) + ) return self.noise_threshold_relative def create_new(self, start=0, end=0, new_data=None): @@ -461,13 +518,21 @@ def create_new(self, start=0, end=0, new_data=None): def get_thresholds_for_center(self, center: float, spacing=None): spacing = self.center_spacing if spacing is None else spacing - return signal_functions.get_center_thresholds(center, spacing, self.modulation_order) - - def auto_detect(self, emit_update=True, detect_modulation=True, detect_noise=False) -> bool: - kwargs = {"noise": None if detect_noise else self.noise_threshold, - "modulation": None if detect_modulation - else "OOK" if self.bits_per_symbol == 1 and self.modulation_type == "ASK" - else self.modulation_type} + return signal_functions.get_center_thresholds( + center, spacing, self.modulation_order + ) + + def auto_detect( + self, emit_update=True, detect_modulation=True, detect_noise=False + ) -> bool: + kwargs = { + "noise": None if detect_noise else self.noise_threshold, + "modulation": None + if detect_modulation + else "OOK" + if self.bits_per_symbol == 1 and self.modulation_type == "ASK" + else self.modulation_type, + } estimated_params = AutoInterpretation.estimate(self.iq_array, **kwargs) if estimated_params is None: @@ -509,7 +574,7 @@ def estimate_frequency(self, start: int, end: int, sample_rate: float): """ # ensure power of 2 for faster fft length = 2 ** int(math.log2(end - start)) - data = self.iq_array.as_complex64()[start:start + length] + data = self.iq_array.as_complex64()[start : start + length] try: w = np.fft.fft(data) @@ -564,11 +629,13 @@ def crop_to_range(self, start: int, end: int): def filter_range(self, start: int, end: int, fir_filter: Filter): self.iq_array[start:end] = fir_filter.work(self.iq_array[start:end]) - self._qad[start:end] = signal_functions.afp_demod(self.iq_array[start:end], - self.noise_threshold, - self.modulation_type, - self.modulation_order, - self.costas_loop_bandwidth) + self._qad[start:end] = signal_functions.afp_demod( + self.iq_array[start:end], + self.noise_threshold, + self.modulation_type, + self.modulation_order, + self.costas_loop_bandwidth, + ) self.__invalidate_after_edit() def __invalidate_after_edit(self): diff --git a/src/urh/signalprocessing/Spectrogram.py b/src/urh/signalprocessing/Spectrogram.py index e3148c88fc..95d80d1d5f 100644 --- a/src/urh/signalprocessing/Spectrogram.py +++ b/src/urh/signalprocessing/Spectrogram.py @@ -13,8 +13,13 @@ class Spectrogram(object): MAX_LINES_PER_VIEW = 1000 DEFAULT_FFT_WINDOW_SIZE = 1024 - def __init__(self, samples: np.ndarray, window_size=DEFAULT_FFT_WINDOW_SIZE, - overlap_factor=0.5, window_function=np.hanning): + def __init__( + self, + samples: np.ndarray, + window_size=DEFAULT_FFT_WINDOW_SIZE, + overlap_factor=0.5, + window_function=np.hanning, + ): """ :param samples: Complex samples @@ -105,7 +110,9 @@ def stft(self, samples: np.ndarray): strides = (hop_size * samples.strides[-1], samples.strides[-1]) frames = np.lib.stride_tricks.as_strided(samples, shape=shape, strides=strides) - result = np.fft.fft(frames * window, self.window_size) / np.atleast_1d(self.window_size) + result = np.fft.fft(frames * window, self.window_size) / np.atleast_1d( + self.window_size + ) return result def export_to_fta(self, sample_rate, filename: str, include_amplitude=False): @@ -118,19 +125,29 @@ def export_to_fta(self, sample_rate, filename: str, include_amplitude=False): spectrogram = self.__calculate_spectrogram(self.samples) spectrogram = np.flipud(spectrogram.T) if include_amplitude: - result = np.empty((spectrogram.shape[0], spectrogram.shape[1], 3), - dtype=[('f', np.float64), ('t', np.uint32), ('a', np.float32)]) + result = np.empty( + (spectrogram.shape[0], spectrogram.shape[1], 3), + dtype=[("f", np.float64), ("t", np.uint32), ("a", np.float32)], + ) else: - result = np.empty((spectrogram.shape[0], spectrogram.shape[1], 2), - dtype=[('f', np.float64), ('t', np.uint32)]) - - fft_freqs = np.fft.fftshift(np.fft.fftfreq(spectrogram.shape[0], 1/sample_rate)) + result = np.empty( + (spectrogram.shape[0], spectrogram.shape[1], 2), + dtype=[("f", np.float64), ("t", np.uint32)], + ) + + fft_freqs = np.fft.fftshift( + np.fft.fftfreq(spectrogram.shape[0], 1 / sample_rate) + ) time_width = 1e9 * ((len(self.samples) / sample_rate) / spectrogram.shape[1]) for i in range(spectrogram.shape[0]): for j in range(spectrogram.shape[1]): if include_amplitude: - result[i, j] = (fft_freqs[i], int(j*time_width), spectrogram[i, j]) + result[i, j] = ( + fft_freqs[i], + int(j * time_width), + spectrogram[i, j], + ) else: result[i, j] = (fft_freqs[i], int(j * time_width)) @@ -144,50 +161,76 @@ def __calculate_spectrogram(self, samples: np.ndarray) -> np.ndarray: # Flip Array so Y axis goes from negative to positive return np.fliplr(spectrogram) - def create_spectrogram_image(self, sample_start: int=None, sample_end: int=None, step: int=None, transpose=False): - spectrogram = self.__calculate_spectrogram(self.samples[sample_start:sample_end:step]) + def create_spectrogram_image( + self, + sample_start: int = None, + sample_end: int = None, + step: int = None, + transpose=False, + ): + spectrogram = self.__calculate_spectrogram( + self.samples[sample_start:sample_end:step] + ) if transpose: spectrogram = np.flipud(spectrogram.T) - return self.create_image(spectrogram, colormaps.chosen_colormap_numpy_bgra, self.data_min, self.data_max) + return self.create_image( + spectrogram, + colormaps.chosen_colormap_numpy_bgra, + self.data_min, + self.data_max, + ) def create_image_segments(self): n_segments = max(1, self.time_bins // self.MAX_LINES_PER_VIEW) step = self.time_bins / n_segments - step = max(1, int((step / self.hop_size) * self.hop_size ** 2)) + step = max(1, int((step / self.hop_size) * self.hop_size**2)) for i in range(0, len(self.samples), step): - image = self.create_spectrogram_image(sample_start=i, sample_end=i+step) + image = self.create_spectrogram_image(sample_start=i, sample_end=i + step) yield image @staticmethod - def apply_bgra_lookup(data: np.ndarray, colormap, data_min=None, data_max=None, normalize=True) -> np.ndarray: + def apply_bgra_lookup( + data: np.ndarray, colormap, data_min=None, data_max=None, normalize=True + ) -> np.ndarray: if normalize and (data_min is None or data_max is None): raise ValueError("Can't normalize without data min and data max") if normalize: - normalized_values = (len(colormap) - 1) * ((data.T - data_min) / (data_max - data_min)) + normalized_values = (len(colormap) - 1) * ( + (data.T - data_min) / (data_max - data_min) + ) else: normalized_values = data.T - return np.take(colormap, normalized_values.astype(int), axis=0, mode='clip') + return np.take(colormap, normalized_values.astype(int), axis=0, mode="clip") @staticmethod - def create_image(data: np.ndarray, colormap, data_min=None, data_max=None, normalize=True) -> QImage: + def create_image( + data: np.ndarray, colormap, data_min=None, data_max=None, normalize=True + ) -> QImage: """ Create QImage from ARGB array. The ARGB must have shape (width, height, 4) and dtype=ubyte. NOTE: The order of values in the 3rd axis must be (blue, green, red, alpha). :return: """ - image_data = Spectrogram.apply_bgra_lookup(data, colormap, data_min, data_max, normalize) + image_data = Spectrogram.apply_bgra_lookup( + data, colormap, data_min, data_max, normalize + ) - if not image_data.flags['C_CONTIGUOUS']: + if not image_data.flags["C_CONTIGUOUS"]: logger.debug("Array was not C_CONTIGUOUS. Converting it.") image_data = np.ascontiguousarray(image_data) try: # QImage constructor needs inverted row/column order - image = QImage(image_data.ctypes.data, image_data.shape[1], image_data.shape[0], QImage.Format_ARGB32) + image = QImage( + image_data.ctypes.data, + image_data.shape[1], + image_data.shape[0], + QImage.Format_ARGB32, + ) except Exception as e: logger.error("could not create image " + str(e)) return QImage() diff --git a/src/urh/simulator/ActionItem.py b/src/urh/simulator/ActionItem.py index d4ddc6c5c9..d3d7e71978 100644 --- a/src/urh/simulator/ActionItem.py +++ b/src/urh/simulator/ActionItem.py @@ -20,7 +20,12 @@ def __init__(self, model_item: SimulatorItem, parent=None): def update_flags(self): if self.scene().mode == 0: - self.set_flags(is_selectable=True, is_movable=True, accept_hover_events=True, accept_drops=True) + self.set_flags( + is_selectable=True, + is_movable=True, + accept_hover_events=True, + accept_drops=True, + ) def update_position(self, x_pos, y_pos): self.setPos(x_pos, y_pos) @@ -31,7 +36,9 @@ def update_position(self, x_pos, y_pos): width = self.scene().items_width() self.prepareGeometryChange() - self.bounding_rect = QRectF(0, 0, width, self.childrenBoundingRect().height() + 5) + self.bounding_rect = QRectF( + 0, 0, width, self.childrenBoundingRect().height() + 5 + ) def labels_width(self): width = self.number.boundingRect().width() @@ -46,7 +53,11 @@ def __init__(self, model_item: SimulatorGotoAction, parent=None): def refresh(self): text = "[Goto: " - text += "..." if self.model_item.goto_target is None else self.model_item.goto_target + text += ( + "..." + if self.model_item.goto_target is None + else self.model_item.goto_target + ) text += "]" self.text.setPlainText(text) diff --git a/src/urh/simulator/GraphicsItem.py b/src/urh/simulator/GraphicsItem.py index c39fd2f8c8..93def7faab 100644 --- a/src/urh/simulator/GraphicsItem.py +++ b/src/urh/simulator/GraphicsItem.py @@ -1,7 +1,12 @@ from PyQt5.QtCore import QRectF, Qt, QLineF from PyQt5.QtGui import QFont, QDropEvent, QPen, QColor, QBrush -from PyQt5.QtWidgets import QGraphicsObject, QGraphicsItem, QGraphicsTextItem, QGraphicsSceneDragDropEvent, \ - QAbstractItemView +from PyQt5.QtWidgets import ( + QGraphicsObject, + QGraphicsItem, + QGraphicsTextItem, + QGraphicsSceneDragDropEvent, + QAbstractItemView, +) from urh import settings from urh.simulator.SimulatorItem import SimulatorItem @@ -31,7 +36,13 @@ def __init__(self, model_item: SimulatorItem, parent=None): self.setFlag(QGraphicsItem.ItemIgnoresParentOpacity, True) - def set_flags(self, is_selectable=False, is_movable=False, accept_hover_events=False, accept_drops=False): + def set_flags( + self, + is_selectable=False, + is_movable=False, + accept_hover_events=False, + accept_drops=False, + ): self.setFlag(QGraphicsItem.ItemIsSelectable, is_selectable) self.setFlag(QGraphicsItem.ItemIsMovable, is_movable) self.setAcceptHoverEvents(accept_hover_events) @@ -64,7 +75,9 @@ def dragMoveEvent(self, event: QDropEvent): self.update_drop_indicator(event.pos()) def get_scene_children(self): - return [self.scene().model_to_scene(child) for child in self.model_item.children] + return [ + self.scene().model_to_scene(child) for child in self.model_item.children + ] def is_selectable(self): return self.flags() & QGraphicsItem.ItemIsSelectable @@ -87,8 +100,9 @@ def next(self): while next_item is not None: next_item = next_item.next() - if (not isinstance(next_item, SimulatorProtocolLabel) and - not isinstance(next_item, SimulatorRule)): + if not isinstance(next_item, SimulatorProtocolLabel) and not isinstance( + next_item, SimulatorRule + ): break return self.scene().model_to_scene(next_item) @@ -99,8 +113,9 @@ def prev(self): while prev_item is not None: prev_item = prev_item.prev() - if (not isinstance(prev_item, SimulatorProtocolLabel) and - not isinstance(prev_item, SimulatorRule)): + if not isinstance(prev_item, SimulatorProtocolLabel) and not isinstance( + prev_item, SimulatorRule + ): break return self.scene().model_to_scene(prev_item) @@ -181,7 +196,9 @@ def mouseMoveEvent(self, event): self.item_under_mouse = item self.item_under_mouse.dragEnterEvent(None) elif self.item_under_mouse and self.item_under_mouse == item: - self.item_under_mouse.update_drop_indicator(self.mapToItem(self.item_under_mouse, event.pos())) + self.item_under_mouse.update_drop_indicator( + self.mapToItem(self.item_under_mouse, event.pos()) + ) elif item: self.item_under_mouse = item self.item_under_mouse.dragEnterEvent(None) diff --git a/src/urh/simulator/LabelItem.py b/src/urh/simulator/LabelItem.py index 587af89e2e..9df3dca4d7 100644 --- a/src/urh/simulator/LabelItem.py +++ b/src/urh/simulator/LabelItem.py @@ -42,6 +42,8 @@ def refresh(self): if self.model_item.is_checksum_label: value_type = "Checksum" else: - value_type = SimulatorProtocolLabel.VALUE_TYPES[self.model_item.value_type_index] + value_type = SimulatorProtocolLabel.VALUE_TYPES[ + self.model_item.value_type_index + ] tooltip = "Value type:
{}".format(value_type) self.setToolTip(tooltip) diff --git a/src/urh/simulator/MessageItem.py b/src/urh/simulator/MessageItem.py index 40e873f915..116dd11852 100644 --- a/src/urh/simulator/MessageItem.py +++ b/src/urh/simulator/MessageItem.py @@ -23,7 +23,12 @@ def __init__(self, model_item: SimulatorMessage, parent=None): def update_flags(self): if self.scene().mode == 0: - self.set_flags(is_selectable=True, is_movable=True, accept_hover_events=True, accept_drops=True) + self.set_flags( + is_selectable=True, + is_movable=True, + accept_hover_events=True, + accept_drops=True, + ) def width(self): labels = self.labels() @@ -36,11 +41,17 @@ def width(self): return width def refresh(self): - self.repeat_text.setPlainText("(" + str(self.model_item.repeat) + "x)" if self.model_item.repeat > 1 else "") + self.repeat_text.setPlainText( + "(" + str(self.model_item.repeat) + "x)" + if self.model_item.repeat > 1 + else "" + ) def labels(self): self.refresh_unlabeled_range_marker() - unlabeled_range_items = [uri for uri in self.childItems() if isinstance(uri, UnlabeledRangeItem)] + unlabeled_range_items = [ + uri for uri in self.childItems() if isinstance(uri, UnlabeledRangeItem) + ] result = [] start = 0 @@ -67,7 +78,9 @@ def labels(self): def refresh_unlabeled_range_marker(self): msg = self.model_item - urm = [item for item in self.childItems() if isinstance(item, UnlabeledRangeItem)] + urm = [ + item for item in self.childItems() if isinstance(item, UnlabeledRangeItem) + ] if len(msg): num_unlabeled_ranges = len(msg.message_type.unlabeled_ranges) @@ -89,7 +102,9 @@ def update_position(self, x_pos, y_pos): self.setPos(QPointF(x_pos, y_pos)) p_source = self.mapFromItem(self.source.line, self.source.line.line().p1()) - p_destination = self.mapFromItem(self.destination.line, self.destination.line.line().p1()) + p_destination = self.mapFromItem( + self.destination.line, self.destination.line.line().p1() + ) arrow_width = abs(p_source.x() - p_destination.x()) @@ -147,11 +162,15 @@ def paint(self, painter, option, widget): if self.line().dy() >= 0: angle = (math.pi * 2) - angle - arrow_p1 = self.line().p2() - QPointF(math.sin(angle + math.pi / 2.5) * arrow_size, - math.cos(angle + math.pi / 2.5) * arrow_size) + arrow_p1 = self.line().p2() - QPointF( + math.sin(angle + math.pi / 2.5) * arrow_size, + math.cos(angle + math.pi / 2.5) * arrow_size, + ) - arrow_p2 = self.line().p2() - QPointF(math.sin(angle + math.pi - math.pi / 2.5) * arrow_size, - math.cos(angle + math.pi - math.pi / 2.5) * arrow_size) + arrow_p2 = self.line().p2() - QPointF( + math.sin(angle + math.pi - math.pi / 2.5) * arrow_size, + math.cos(angle + math.pi - math.pi / 2.5) * arrow_size, + ) arrow_head = QPolygonF() arrow_head.append(self.line().p2()) diff --git a/src/urh/simulator/ParticipantItem.py b/src/urh/simulator/ParticipantItem.py index cd90f28fab..d25fd4e645 100644 --- a/src/urh/simulator/ParticipantItem.py +++ b/src/urh/simulator/ParticipantItem.py @@ -36,17 +36,23 @@ def width(self): return self.boundingRect().width() def refresh(self): - self.text.setPlainText("?" if not self.model_item else self.model_item.shortname) + self.text.setPlainText( + "?" if not self.model_item else self.model_item.shortname + ) if hasattr(self.model_item, "simulate") and self.model_item.simulate: font = QFont() font.setBold(True) self.text.setFont(font) self.text.setDefaultTextColor(Qt.darkGreen) - self.line.setPen(QPen(Qt.darkGreen, 2, Qt.SolidLine, Qt.RoundCap, Qt.RoundJoin)) + self.line.setPen( + QPen(Qt.darkGreen, 2, Qt.SolidLine, Qt.RoundCap, Qt.RoundJoin) + ) else: self.text.setFont(QFont()) self.text.setDefaultTextColor(settings.LINECOLOR) - self.line.setPen(QPen(Qt.darkGray, 1, Qt.DashLine, Qt.RoundCap, Qt.RoundJoin)) + self.line.setPen( + QPen(Qt.darkGray, 1, Qt.DashLine, Qt.RoundCap, Qt.RoundJoin) + ) def boundingRect(self): return self.childrenBoundingRect() diff --git a/src/urh/simulator/RuleItem.py b/src/urh/simulator/RuleItem.py index a28c265e01..8d35afe15e 100644 --- a/src/urh/simulator/RuleItem.py +++ b/src/urh/simulator/RuleItem.py @@ -4,7 +4,11 @@ from urh import settings from urh.simulator.GraphicsItem import GraphicsItem -from urh.simulator.SimulatorRule import SimulatorRule, SimulatorRuleCondition, ConditionType +from urh.simulator.SimulatorRule import ( + SimulatorRule, + SimulatorRuleCondition, + ConditionType, +) class RuleItem(GraphicsItem): @@ -55,13 +59,17 @@ def __init__(self, model_item: SimulatorRuleCondition, parent=None): def update_flags(self): if self.scene().mode == 0: - self.set_flags(is_selectable=True, accept_hover_events=True, accept_drops=True) + self.set_flags( + is_selectable=True, accept_hover_events=True, accept_drops=True + ) else: self.set_flags(is_selectable=True, accept_hover_events=True) def labels_width(self): - return max(self.number.boundingRect().width() + self.text.boundingRect().width(), - self.desc.boundingRect().width()) + return max( + self.number.boundingRect().width() + self.text.boundingRect().width(), + self.desc.boundingRect().width(), + ) def refresh(self): if len(self.model_item.condition): @@ -76,13 +84,17 @@ def update_position(self, x_pos, y_pos): self.setPos(x_pos, y_pos) start_y = 0 - start_x = ((self.scene().items_width() + 40) - ( - self.number.boundingRect().width() + self.text.boundingRect().width())) / 2 + start_x = ( + (self.scene().items_width() + 40) + - (self.number.boundingRect().width() + self.text.boundingRect().width()) + ) / 2 self.number.setPos(start_x, start_y) start_x += self.number.boundingRect().width() self.text.setPos(start_x, start_y) start_y += round(self.number.boundingRect().height()) - start_x = ((self.scene().items_width() + 40) - self.desc.boundingRect().width()) / 2 + start_x = ( + (self.scene().items_width() + 40) - self.desc.boundingRect().width() + ) / 2 self.desc.setPos(start_x, start_y) if self.model_item.type != ConditionType.ELSE: @@ -96,7 +108,9 @@ def update_position(self, x_pos, y_pos): width = self.scene().items_width() self.prepareGeometryChange() - self.bounding_rect = QRectF(0, 0, width + 40, self.childrenBoundingRect().height() + 5) + self.bounding_rect = QRectF( + 0, 0, width + 40, self.childrenBoundingRect().height() + 5 + ) def update_drop_indicator(self, pos): rect = self.boundingRect() diff --git a/src/urh/simulator/Simulator.py b/src/urh/simulator/Simulator.py index d470e46724..715f875b34 100644 --- a/src/urh/simulator/Simulator.py +++ b/src/urh/simulator/Simulator.py @@ -21,7 +21,11 @@ from urh.simulator.SimulatorGotoAction import SimulatorGotoAction from urh.simulator.SimulatorMessage import SimulatorMessage from urh.simulator.SimulatorProtocolLabel import SimulatorProtocolLabel -from urh.simulator.SimulatorRule import SimulatorRule, SimulatorRuleCondition, ConditionType +from urh.simulator.SimulatorRule import ( + SimulatorRule, + SimulatorRuleCondition, + ConditionType, +) from urh.simulator.SimulatorSleepAction import SimulatorSleepAction from urh.simulator.SimulatorTriggerCommandAction import SimulatorTriggerCommandAction from urh.simulator.Transcript import Transcript @@ -34,9 +38,15 @@ class Simulator(QObject): simulation_started = pyqtSignal() simulation_stopped = pyqtSignal() - def __init__(self, simulator_config: SimulatorConfiguration, modulators, - expression_parser: SimulatorExpressionParser, project_manager: ProjectManager, - sniffer: ProtocolSniffer, sender: EndlessSender): + def __init__( + self, + simulator_config: SimulatorConfiguration, + modulators, + expression_parser: SimulatorExpressionParser, + project_manager: ProjectManager, + sniffer: ProtocolSniffer, + sender: EndlessSender, + ): super().__init__() self.simulator_config = simulator_config self.project_manager = project_manager @@ -115,7 +125,9 @@ def stop(self, msg=""): self.simulation_stopped.emit() if self.is_simulating: - self.log_message("Stop simulation" + (" ({})".format(msg.strip()) if msg else "")) + self.log_message( + "Stop simulation" + (" ({})".format(msg.strip()) if msg else "") + ) self.is_simulating = False self.do_restart = False self.simulation_thread.join(2.5) @@ -189,7 +201,9 @@ def simulation_is_finished(self): def __wait_for_devices(self): for i in range(10): - if (self.sniffer is None or self.sniffer_ready) and (self.sender is None or self.sender_ready): + if (self.sniffer is None or self.sniffer_ready) and ( + self.sender is None or self.sender_ready + ): return True if self.fatal_device_error_occurred: return False @@ -243,18 +257,34 @@ def simulate(self): command = self.__fill_counter_values(self.current_item.command) self.log_message("Calling {}".format(command)) if self.current_item.pass_transcript: - transcript = "\n".join(self.transcript.get_for_all_participants(all_rounds=False)) - result, rc = util.run_command(command, transcript, use_stdin=True, return_rc=True) + transcript = "\n".join( + self.transcript.get_for_all_participants(all_rounds=False) + ) + result, rc = util.run_command( + command, transcript, use_stdin=True, return_rc=True + ) else: - result, rc = util.run_command(command, param=None, detailed_output=True, return_rc=True) + result, rc = util.run_command( + command, param=None, detailed_output=True, return_rc=True + ) self.current_item.return_code = rc self.log_message(result) elif isinstance(self.current_item, SimulatorRule): condition = self.current_item.get_first_applying_condition() - if condition is not None and condition.logging_active and condition.type != ConditionType.ELSE: - self.log_message("Rule condition " + condition.index() + " (" + condition.condition + ") applied") + if ( + condition is not None + and condition.logging_active + and condition.type != ConditionType.ELSE + ): + self.log_message( + "Rule condition " + + condition.index() + + " (" + + condition.condition + + ") applied" + ) if condition is not None and condition.child_count() > 0: next_item = condition.children[0] @@ -274,7 +304,11 @@ def simulate(self): elif isinstance(self.current_item, SimulatorCounterAction): self.current_item.progress_value() - self.log_message("Increase counter by {} to {}".format(self.current_item.step, self.current_item.value)) + self.log_message( + "Increase counter by {} to {}".format( + self.current_item.step, self.current_item.value + ) + ) next_item = self.current_item.next() elif self.current_item is None: @@ -310,13 +344,20 @@ def process_message(self): for lbl in new_message.message_type: if isinstance(lbl.label, ChecksumLabel): - checksum = lbl.label.calculate_checksum_for_message(new_message, use_decoded_bits=False) - label_range = new_message.get_label_range(lbl=lbl.label, view=0, decode=False) + checksum = lbl.label.calculate_checksum_for_message( + new_message, use_decoded_bits=False + ) + label_range = new_message.get_label_range( + lbl=lbl.label, view=0, decode=False + ) start, end = label_range[0], label_range[1] - new_message.plain_bits[start:end] = checksum + array.array("B", [0] * ( - (end - start) - len(checksum))) + new_message.plain_bits[start:end] = checksum + array.array( + "B", [0] * ((end - start) - len(checksum)) + ) - self.transcript.append(msg.source, msg.destination, new_message, msg.index()) + self.transcript.append( + msg.source, msg.destination, new_message, msg.index() + ) self.send_message(new_message, msg.repeat, sender, msg.modulator_index) self.log_message("Sending message " + msg.index()) self.log_message_labels(new_message) @@ -333,7 +374,11 @@ def process_message(self): retry = 0 max_retries = self.project_manager.simulator_retries - while self.is_simulating and not self.simulation_is_finished() and retry < max_retries: + while ( + self.is_simulating + and not self.simulation_is_finished() + and retry < max_retries + ): received_msg = self.receive_message(sniffer) self.log_message(" Received {} data bits".format(len(received_msg))) @@ -356,14 +401,21 @@ def process_message(self): received_msg.message_type = new_message.message_type self.log_message(" Check whether received data matches") - check_result, error_msg = self.check_message(received_msg, new_message, retry=retry, - msg_index=msg.index()) + check_result, error_msg = self.check_message( + received_msg, new_message, retry=retry, msg_index=msg.index() + ) if check_result: - decoded_msg = Message(received_msg.decoded_bits, 0, - received_msg.message_type, decoder=received_msg.decoder) + decoded_msg = Message( + received_msg.decoded_bits, + 0, + received_msg.message_type, + decoder=received_msg.decoder, + ) msg.send_recv_messages.append(decoded_msg) - self.transcript.append(msg.source, msg.destination, decoded_msg, msg.index()) + self.transcript.append( + msg.source, msg.destination, decoded_msg, msg.index() + ) self.log_message("Received message " + msg.index() + ": ") self.log_message_labels(decoded_msg) return @@ -377,7 +429,9 @@ def process_message(self): self.stop() def log_message(self, message): - timestamp = '{0:%b} {0.day} {0:%H}:{0:%M}:{0:%S}.{0:%f}'.format(datetime.datetime.now()) + timestamp = "{0:%b} {0.day} {0:%H}:{0:%M}:{0:%S}.{0:%f}".format( + datetime.datetime.now() + ) if isinstance(message, list) and len(message) > 0: self.log_messages.append(timestamp + ": " + message[0]) @@ -387,7 +441,9 @@ def log_message(self, message): self.log_messages.append(timestamp + ": " + message) logger.debug(message) - def check_message(self, received_msg, expected_msg, retry: int, msg_index: int) -> (bool, str): + def check_message( + self, received_msg, expected_msg, retry: int, msg_index: int + ) -> (bool, str): if len(received_msg.decoded_bits) == 0: return False, "Failed to decode message {}".format(msg_index) @@ -400,7 +456,9 @@ def check_message(self, received_msg, expected_msg, retry: int, msg_index: int) start_exp, end_exp = expected_msg.get_label_range(lbl.label, 0, False) if isinstance(lbl.label, ChecksumLabel): - expected = lbl.label.calculate_checksum_for_message(received_msg, use_decoded_bits=True) + expected = lbl.label.calculate_checksum_for_message( + received_msg, use_decoded_bits=True + ) start, end = received_msg.get_label_range(lbl.label, 0, True) actual = received_msg.decoded_bits[start:end] else: @@ -409,12 +467,27 @@ def check_message(self, received_msg, expected_msg, retry: int, msg_index: int) if actual != expected: log_msg = [] - log_msg.append("Attempt for message {} [{}/{}]".format(msg_index, retry + 1, - self.project_manager.simulator_retries)) - log_msg.append(HTMLFormatter.indent_string("Mismatch for label: {}".format(lbl.name))) - expected_str = util.convert_bits_to_string(expected, lbl.label.display_format_index) - got_str = util.convert_bits_to_string(actual, lbl.label.display_format_index) - log_msg.append(HTMLFormatter.align_expected_and_got_value(expected_str, got_str, align_depth=2)) + log_msg.append( + "Attempt for message {} [{}/{}]".format( + msg_index, retry + 1, self.project_manager.simulator_retries + ) + ) + log_msg.append( + HTMLFormatter.indent_string( + "Mismatch for label: {}".format(lbl.name) + ) + ) + expected_str = util.convert_bits_to_string( + expected, lbl.label.display_format_index + ) + got_str = util.convert_bits_to_string( + actual, lbl.label.display_format_index + ) + log_msg.append( + HTMLFormatter.align_expected_and_got_value( + expected_str, got_str, align_depth=2 + ) + ) return False, log_msg return True, "" @@ -426,14 +499,16 @@ def log_message_labels(self, message: Message): continue try: - data = message.plain_bits[lbl.start:lbl.end] + data = message.plain_bits[lbl.start : lbl.end] except IndexError: return None lsb = lbl.display_bit_order_index == 1 lsd = lbl.display_bit_order_index == 2 - data = util.convert_bits_to_string(data, lbl.display_format_index, pad_zeros=True, lsb=lsb, lsd=lsd) + data = util.convert_bits_to_string( + data, lbl.display_format_index, pad_zeros=True, lsb=lsb, lsd=lsd + ) if data is None: continue @@ -448,11 +523,17 @@ def resend_last_message(self): return sender = self.sender - self.send_message(lsm.send_recv_messages[-1], lsm.repeat, sender, lsm.modulator_index) + self.send_message( + lsm.send_recv_messages[-1], lsm.repeat, sender, lsm.modulator_index + ) def send_message(self, message, repeat, sender, modulator_index): modulator = self.modulators[modulator_index] - modulated = modulator.modulate(message.encoded_bits, pause=message.pause, dtype=self.sender.device.data_type) + modulated = modulator.modulate( + message.encoded_bits, + pause=message.pause, + dtype=self.sender.device.data_type, + ) curr_repeat = 0 @@ -464,7 +545,9 @@ def receive_message(self, sniffer): if len(sniffer.messages) > 0: return sniffer.messages.pop(0) - if QSignalSpy(sniffer.message_sniffed).wait(self.project_manager.simulator_timeout_ms): + if QSignalSpy(sniffer.message_sniffed).wait( + self.project_manager.simulator_timeout_ms + ): try: return sniffer.messages.pop(0) except IndexError: @@ -479,14 +562,23 @@ def get_full_transcript(self, start=0, use_bit=True): for source, destination, msg, msg_index in self.transcript[start:]: try: data = msg.plain_bits_str if use_bit else msg.plain_hex_str - result.append(self.TRANSCRIPT_FORMAT.format(msg_index, source.shortname, destination.shortname, data)) + result.append( + self.TRANSCRIPT_FORMAT.format( + msg_index, source.shortname, destination.shortname, data + ) + ) except AttributeError: result.append("") return result def generate_message_from_template(self, template_msg: SimulatorMessage): - new_message = Message(template_msg.plain_bits, pause=template_msg.pause, rssi=0, - message_type=template_msg.message_type, decoder=template_msg.decoder) + new_message = Message( + template_msg.plain_bits, + pause=template_msg.pause, + rssi=0, + message_type=template_msg.message_type, + decoder=template_msg.decoder, + ) for lbl in template_msg.children: # type: SimulatorProtocolLabel if lbl.value_type_index == 2: @@ -495,9 +587,11 @@ def generate_message_from_template(self, template_msg: SimulatorMessage): assert valid result = self.expression_parser.evaluate_node(node) elif lbl.value_type_index == 3: - transcript = self.transcript.get_for_participant(template_msg.source - if template_msg.source.simulate - else template_msg.destination) + transcript = self.transcript.get_for_participant( + template_msg.source + if template_msg.source.simulate + else template_msg.destination + ) if template_msg.destination.simulate: direction = "->" if template_msg.source.simulate else "<-" @@ -507,13 +601,19 @@ def generate_message_from_template(self, template_msg: SimulatorMessage): result = util.run_command(cmd, transcript, use_stdin=True) if len(result) != lbl.end - lbl.start: log_msg = "Result value of external program {}: {} ({}) does not match label length {}" - logger.error(log_msg.format(cmd, result, len(result), lbl.end - lbl.start)) + logger.error( + log_msg.format(cmd, result, len(result), lbl.end - lbl.start) + ) continue try: - new_message[lbl.start:lbl.end] = array.array("B", (map(bool, map(int, result)))) + new_message[lbl.start : lbl.end] = array.array( + "B", (map(bool, map(int, result))) + ) except Exception as e: - log_msg = "Could not assign {} to range because {}".format(result, e) + log_msg = "Could not assign {} to range because {}".format( + result, e + ) logger.error(log_msg) continue @@ -534,7 +634,11 @@ def set_label_value(message, label, decimal_value: int): bits = f_string.format(decimal_value) if len(bits) > lbl_len: - logger.warning("Value {0} too big for label {1}, bits truncated".format(decimal_value, label.name)) + logger.warning( + "Value {0} too big for label {1}, bits truncated".format( + decimal_value, label.name + ) + ) for i in range(lbl_len): message[label.start + i] = bool(int(bits[i])) diff --git a/src/urh/simulator/SimulatorConfiguration.py b/src/urh/simulator/SimulatorConfiguration.py index 7de8bf34e6..050efda37b 100644 --- a/src/urh/simulator/SimulatorConfiguration.py +++ b/src/urh/simulator/SimulatorConfiguration.py @@ -15,7 +15,11 @@ from urh.simulator.SimulatorItem import SimulatorItem from urh.simulator.SimulatorMessage import SimulatorMessage from urh.simulator.SimulatorProtocolLabel import SimulatorProtocolLabel -from urh.simulator.SimulatorRule import SimulatorRuleCondition, ConditionType, SimulatorRule +from urh.simulator.SimulatorRule import ( + SimulatorRuleCondition, + ConditionType, + SimulatorRule, +) from urh.simulator.SimulatorSleepAction import SimulatorSleepAction from urh.simulator.SimulatorTriggerCommandAction import SimulatorTriggerCommandAction from urh.util.ProjectManager import ProjectManager @@ -35,8 +39,12 @@ def __init__(self, project_manager: ProjectManager): super().__init__() self.rootItem = SimulatorItem() self.project_manager = project_manager - self.broadcast_part = Participant("Broadcast", "Broadcast", - self.project_manager.broadcast_address_hex, id="broadcast_participant") + self.broadcast_part = Participant( + "Broadcast", + "Broadcast", + self.project_manager.broadcast_address_hex, + id="broadcast_participant", + ) self.__active_participants = None self.item_dict = OrderedDict() @@ -68,11 +76,17 @@ def active_participants(self): @property def rx_needed(self) -> bool: - return any(hasattr(msg.destination, "simulate") and msg.destination.simulate for msg in self.get_all_messages()) + return any( + hasattr(msg.destination, "simulate") and msg.destination.simulate + for msg in self.get_all_messages() + ) @property def tx_needed(self) -> bool: - return any(hasattr(msg.source, "simulate") and msg.source.simulate for msg in self.get_all_messages()) + return any( + hasattr(msg.source, "simulate") and msg.source.simulate + for msg in self.get_all_messages() + ) def update_item_dict(self): self.item_dict.clear() @@ -137,8 +151,10 @@ def add_items(self, items, pos: int, parent_item): def delete_items(self, items): for i, item in enumerate(items): - if (isinstance(item, SimulatorRuleCondition) and - item.type == ConditionType.IF): + if ( + isinstance(item, SimulatorRuleCondition) + and item.type == ConditionType.IF + ): items[i] = item.parent() items[i].delete() @@ -158,13 +174,22 @@ def move_items(self, items, new_pos: int, new_parent: SimulatorItem): self.items_moved.emit(items) - def add_label(self, start: int, end: int, name: str = None, color_index: int = None, - type: FieldType = None, parent_item: SimulatorMessage = None): + def add_label( + self, + start: int, + end: int, + name: str = None, + color_index: int = None, + type: FieldType = None, + parent_item: SimulatorMessage = None, + ): assert isinstance(parent_item, SimulatorMessage) name = "" if not name else name used_colors = [p.color_index for p in parent_item.message_type] - avail_colors = [i for i, _ in enumerate(settings.LABEL_COLORS) if i not in used_colors] + avail_colors = [ + i for i, _ in enumerate(settings.LABEL_COLORS) if i not in used_colors + ] if color_index is None: if len(avail_colors) > 0: @@ -185,7 +210,9 @@ def update_active_participants(self): active_participants = [] for part in self.project_manager.participants: - if any(msg.participant == part or msg.destination == part for msg in messages): + if any( + msg.participant == part or msg.destination == part for msg in messages + ): active_participants.append(part) self.__active_participants = active_participants @@ -202,8 +229,10 @@ def consolidate_messages(self): current_msg = current_item repeat_counter = 0 - while (isinstance(current_msg.next_sibling(), SimulatorMessage) and - current_item.plain_bits == current_msg.next_sibling().plain_bits): + while ( + isinstance(current_msg.next_sibling(), SimulatorMessage) + and current_item.plain_bits == current_msg.next_sibling().plain_bits + ): repeat_counter += 1 current_msg = current_msg.next_sibling() redundant_messages.append(current_msg) @@ -224,7 +253,9 @@ def get_all_messages(self): :rtype: list[SimulatorMessage] """ - return [item for item in self.get_all_items() if isinstance(item, SimulatorMessage)] + return [ + item for item in self.get_all_items() if isinstance(item, SimulatorMessage) + ] def load_from_xml(self, xml_tag: ET.Element, message_types): assert xml_tag.tag == "simulator_config" @@ -232,26 +263,36 @@ def load_from_xml(self, xml_tag: ET.Element, message_types): modulators_tag = xml_tag.find("modulators") if modulators_tag: - self.project_manager.modulators = Modulator.modulators_from_xml_tag(modulators_tag) + self.project_manager.modulators = Modulator.modulators_from_xml_tag( + modulators_tag + ) participants_tag = xml_tag.find("participants") if participants_tag: - for participant in Participant.read_participants_from_xml_tag(participants_tag): + for participant in Participant.read_participants_from_xml_tag( + participants_tag + ): if participant not in self.project_manager.participants: self.project_manager.participants.append(participant) self.participants_changed.emit() decodings_tag = xml_tag.find("decodings") if decodings_tag: - self.project_manager.decodings = Encoding.read_decoders_from_xml_tag(decodings_tag) + self.project_manager.decodings = Encoding.read_decoders_from_xml_tag( + decodings_tag + ) rx_config_tag = xml_tag.find("simulator_rx_conf") if rx_config_tag: - ProjectManager.read_device_conf_dict(rx_config_tag, self.project_manager.simulator_rx_conf) + ProjectManager.read_device_conf_dict( + rx_config_tag, self.project_manager.simulator_rx_conf + ) tx_config_tag = xml_tag.find("simulator_tx_conf") if tx_config_tag: - ProjectManager.read_device_conf_dict(tx_config_tag, self.project_manager.simulator_tx_conf) + ProjectManager.read_device_conf_dict( + tx_config_tag, self.project_manager.simulator_tx_conf + ) for child_tag in xml_tag.find("items"): items.append(self.load_item_from_xml(child_tag, message_types)) @@ -260,10 +301,16 @@ def load_from_xml(self, xml_tag: ET.Element, message_types): def load_item_from_xml(self, xml_tag: ET.Element, message_types) -> SimulatorItem: if xml_tag.tag == "simulator_message": - item = SimulatorMessage.new_from_xml(xml_tag, self.participants, self.project_manager.decodings, - message_types) + item = SimulatorMessage.new_from_xml( + xml_tag, + self.participants, + self.project_manager.decodings, + message_types, + ) elif xml_tag.tag == "simulator_label": - item = SimulatorProtocolLabel.from_xml(xml_tag, self.project_manager.field_types_by_caption) + item = SimulatorProtocolLabel.from_xml( + xml_tag, self.project_manager.field_types_by_caption + ) elif xml_tag.tag == "simulator_trigger_command_action": item = SimulatorTriggerCommandAction.from_xml(xml_tag) elif xml_tag.tag == "simulator_sleep_action": @@ -292,9 +339,13 @@ def save_to_xml(self, standalone=False) -> ET.Element: result = ET.Element("simulator_config") if standalone: - result.append(Modulator.modulators_to_xml_tag(self.project_manager.modulators)) + result.append( + Modulator.modulators_to_xml_tag(self.project_manager.modulators) + ) result.append(Encoding.decodings_to_xml_tag(self.project_manager.decodings)) - result.append(Participant.participants_to_xml_tag(self.project_manager.participants)) + result.append( + Participant.participants_to_xml_tag(self.project_manager.participants) + ) result.append(self.project_manager.simulator_rx_conf_to_xml()) result.append(self.project_manager.simulator_tx_conf_to_xml()) @@ -306,7 +357,11 @@ def save_to_xml(self, standalone=False) -> ET.Element: def __save_item_to_xml(self, tag: ET.Element, item): if isinstance(item, SimulatorMessage): - child_tag = item.to_xml(decoders=self.project_manager.decodings, include_message_type=True, write_bits=True) + child_tag = item.to_xml( + decoders=self.project_manager.decodings, + include_message_type=True, + write_bits=True, + ) else: child_tag = item.to_xml() diff --git a/src/urh/simulator/SimulatorExpressionParser.py b/src/urh/simulator/SimulatorExpressionParser.py index 4f73ea8c53..29ed322d96 100644 --- a/src/urh/simulator/SimulatorExpressionParser.py +++ b/src/urh/simulator/SimulatorExpressionParser.py @@ -26,7 +26,7 @@ class SimulatorExpressionParser(QObject): ast.BitAnd: op.and_, ast.LShift: op.lshift, ast.RShift: op.rshift, - ast.Invert: op.invert + ast.Invert: op.invert, } op_cond = { @@ -38,7 +38,7 @@ class SimulatorExpressionParser(QObject): ast.Lt: op.lt, ast.LtE: op.le, ast.Gt: op.gt, - ast.GtE: op.ge + ast.GtE: op.ge, } operators = {} @@ -55,11 +55,20 @@ def validate_expression(self, expr, is_formula=True): node = None try: - node = ast.parse(expr, mode='eval').body - self.validate_formula_node(node) if is_formula else self.validate_condition_node(node) + node = ast.parse(expr, mode="eval").body + self.validate_formula_node( + node + ) if is_formula else self.validate_condition_node(node) except SyntaxError as err: valid = False - message = "
" + html.escape(expr) + "
" + " " * err.offset + "^
" + str(err) + message = ( + "
"
+                + html.escape(expr)
+                + "
" + + " " * err.offset + + "^
" + + str(err) + ) else: message = self.formula_help if is_formula else self.rule_condition_help @@ -67,15 +76,18 @@ def validate_expression(self, expr, is_formula=True): def evaluate_node(self, node): if isinstance(node, ast.BinOp): - return self.operators[type(node.op)](self.evaluate_node(node.left), - self.evaluate_node(node.right)) + return self.operators[type(node.op)]( + self.evaluate_node(node.left), self.evaluate_node(node.right) + ) elif isinstance(node, ast.UnaryOp): return self.operators[type(node.op)](self.evaluate_node(node.operand)) elif isinstance(node, ast.Compare): to_string = isinstance(node.comparators[0], ast.Str) - return self.operators[type(node.ops[0])](self.evaluate_attribute_node(node.left, to_string), - self.evaluate_node(node.comparators[0])) + return self.operators[type(node.ops[0])]( + self.evaluate_attribute_node(node.left, to_string), + self.evaluate_node(node.comparators[0]), + ) elif isinstance(node, ast.BoolOp): func = all if isinstance(node.op, ast.And) else any return func(self.evaluate_node(value) for value in node.values) @@ -90,15 +102,25 @@ def evaluate_node(self, node): def evaluate_attribute_node(self, node, to_string=False): identifier = node.value.id + "." + node.attr - if isinstance(self.simulator_config.item_dict[identifier], SimulatorProtocolLabel): + if isinstance( + self.simulator_config.item_dict[identifier], SimulatorProtocolLabel + ): label = self.simulator_config.item_dict[identifier] message = label.parent() start, end = message.get_label_range(label, 2 if to_string else 0, False) - return message.plain_ascii_str[start:end] if to_string else int(message.plain_bits_str[start:end], 2) - elif isinstance(self.simulator_config.item_dict[identifier], SimulatorCounterAction): + return ( + message.plain_ascii_str[start:end] + if to_string + else int(message.plain_bits_str[start:end], 2) + ) + elif isinstance( + self.simulator_config.item_dict[identifier], SimulatorCounterAction + ): return self.simulator_config.item_dict[identifier].value - elif isinstance(self.simulator_config.item_dict[identifier], SimulatorTriggerCommandAction): + elif isinstance( + self.simulator_config.item_dict[identifier], SimulatorTriggerCommandAction + ): return self.simulator_config.item_dict[identifier].return_code def validate_formula_node(self, node): @@ -106,13 +128,17 @@ def validate_formula_node(self, node): return elif isinstance(node, ast.BinOp): if type(node.op) not in self.op_formula: - self.raise_syntax_error("unknown operator", node.lineno, node.col_offset) + self.raise_syntax_error( + "unknown operator", node.lineno, node.col_offset + ) self.validate_formula_node(node.left) self.validate_formula_node(node.right) elif isinstance(node, ast.UnaryOp): if type(node.op) not in self.op_formula: - self.raise_syntax_error("unknown operator", node.lineno, node.col_offset) + self.raise_syntax_error( + "unknown operator", node.lineno, node.col_offset + ) self.validate_formula_node(node.operand) elif isinstance(node, ast.Attribute): @@ -123,7 +149,9 @@ def validate_formula_node(self, node): def validate_condition_node(self, node): if isinstance(node, ast.UnaryOp): if type(node.op) not in self.op_cond: - self.raise_syntax_error("unknown operator", node.lineno, node.col_offset) + self.raise_syntax_error( + "unknown operator", node.lineno, node.col_offset + ) self.validate_condition_node(node.operand) elif isinstance(node, ast.Compare): @@ -131,7 +159,9 @@ def validate_condition_node(self, node): self.raise_syntax_error("", node.lineno, node.col_offset) if type(node.ops[0]) not in self.op_cond: - self.raise_syntax_error("unknown operator", node.lineno, node.col_offset) + self.raise_syntax_error( + "unknown operator", node.lineno, node.col_offset + ) self.validate_compare_nodes(node.left, node.comparators[0]) elif isinstance(node, ast.BoolOp): @@ -142,15 +172,20 @@ def validate_condition_node(self, node): def validate_compare_nodes(self, left, right): if not isinstance(left, ast.Attribute): - self.raise_syntax_error("the left-hand side of a comparison must be a label identifier", - left.lineno, left.col_offset) + self.raise_syntax_error( + "the left-hand side of a comparison must be a label identifier", + left.lineno, + left.col_offset, + ) self.validate_attribute_node(left) if not isinstance(right, (ast.Num, ast.Str, ast.Attribute)): self.raise_syntax_error( "the right-hand side of a comparison must be a number, a string or a label identifier", - right.lineno, right.col_offset) + right.lineno, + right.col_offset, + ) if isinstance(right, ast.Attribute): self.validate_attribute_node(right) @@ -162,20 +197,32 @@ def validate_attribute_node(self, node): identifier = node.value.id + "." + node.attr if not self.is_valid_identifier(identifier): - self.raise_syntax_error("'" + identifier + "' is not a valid label identifier", - node.lineno, node.col_offset) + self.raise_syntax_error( + "'" + identifier + "' is not a valid label identifier", + node.lineno, + node.col_offset, + ) def is_valid_identifier(self, identifier): try: item = self.simulator_config.item_dict[identifier] - return isinstance(item, SimulatorProtocolLabel) or\ - isinstance(item, SimulatorCounterAction) or \ - (isinstance(item, SimulatorTriggerCommandAction) and identifier.endswith("rc")) + return ( + isinstance(item, SimulatorProtocolLabel) + or isinstance(item, SimulatorCounterAction) + or ( + isinstance(item, SimulatorTriggerCommandAction) + and identifier.endswith("rc") + ) + ) except KeyError: return False def get_identifiers(self): - return [identifier for identifier in self.simulator_config.item_dict if self.is_valid_identifier(identifier)] + return [ + identifier + for identifier in self.simulator_config.item_dict + if self.is_valid_identifier(identifier) + ] def raise_syntax_error(self, message, lineno, col_offset): if message == "": diff --git a/src/urh/simulator/SimulatorGotoAction.py b/src/urh/simulator/SimulatorGotoAction.py index a225adb90b..a30ea43fd6 100644 --- a/src/urh/simulator/SimulatorGotoAction.py +++ b/src/urh/simulator/SimulatorGotoAction.py @@ -3,7 +3,11 @@ from urh.simulator.SimulatorCounterAction import SimulatorCounterAction from urh.simulator.SimulatorItem import SimulatorItem from urh.simulator.SimulatorProtocolLabel import SimulatorProtocolLabel -from urh.simulator.SimulatorRule import SimulatorRule, SimulatorRuleCondition, ConditionType +from urh.simulator.SimulatorRule import ( + SimulatorRule, + SimulatorRuleCondition, + ConditionType, +) from urh.simulator.SimulatorTriggerCommandAction import SimulatorTriggerCommandAction @@ -20,7 +24,11 @@ def set_parent(self, value): @property def target(self): - return self.simulator_config.item_dict[self.goto_target] if self.validate() else None + return ( + self.simulator_config.item_dict[self.goto_target] + if self.validate() + else None + ) def validate(self): target = self.simulator_config.item_dict.get(self.goto_target, None) diff --git a/src/urh/simulator/SimulatorMessage.py b/src/urh/simulator/SimulatorMessage.py index 3b056492cb..5d233bbb1a 100644 --- a/src/urh/simulator/SimulatorMessage.py +++ b/src/urh/simulator/SimulatorMessage.py @@ -9,9 +9,19 @@ class SimulatorMessage(Message, SimulatorItem): - def __init__(self, destination: Participant, plain_bits, - pause: int, message_type: MessageType, decoder=None, source=None, timestamp=None): - Message.__init__(self, plain_bits, pause, message_type, decoder=decoder, participant=source) + def __init__( + self, + destination: Participant, + plain_bits, + pause: int, + message_type: MessageType, + decoder=None, + source=None, + timestamp=None, + ): + Message.__init__( + self, plain_bits, pause, message_type, decoder=decoder, participant=source + ) SimulatorItem.__init__(self) if timestamp is not None: self.timestamp = timestamp @@ -56,33 +66,62 @@ def plain_ascii_str(self) -> str: @property def plain_bits_str(self) -> str: - return str(self.send_recv_messages[-1]) if len(self.send_recv_messages) > 0 else str(self) + return ( + str(self.send_recv_messages[-1]) + if len(self.send_recv_messages) > 0 + else str(self) + ) def __delitem__(self, index): removed_labels = self._remove_labels_for_range(index, instant_remove=False) self.simulator_config.delete_items(removed_labels) del self.plain_bits[index] - def to_xml(self, decoders=None, include_message_type=False, write_bits=True) -> ET.Element: - result = ET.Element("simulator_message", - attrib={"destination_id": self.destination.id if self.destination else "", - "repeat": str(self.repeat)}) - - result.append(super().to_xml(decoders, include_message_type, write_bits=write_bits)) + def to_xml( + self, decoders=None, include_message_type=False, write_bits=True + ) -> ET.Element: + result = ET.Element( + "simulator_message", + attrib={ + "destination_id": self.destination.id if self.destination else "", + "repeat": str(self.repeat), + }, + ) + + result.append( + super().to_xml(decoders, include_message_type, write_bits=write_bits) + ) return result - def from_xml(self, tag: ET.Element, participants, decoders=None, message_types=None): + def from_xml( + self, tag: ET.Element, participants, decoders=None, message_types=None + ): super().from_xml(tag, participants, decoders, message_types) - self.destination = Participant.find_matching(tag.get("destination_id", ""), participants) + self.destination = Participant.find_matching( + tag.get("destination_id", ""), participants + ) self.repeat = Formatter.str2val(tag.get("repeat", "1"), int, 1) @classmethod - def new_from_xml(cls, tag: ET.Element, participants, decoders=None, message_types=None): - msg = Message.new_from_xml(tag.find("message"), - participants=participants, - decoders=decoders, - message_types=message_types) - destination = Participant.find_matching(tag.get("destination_id", ""), participants) - return SimulatorMessage(destination, msg.plain_bits, msg.pause, msg.message_type, msg.decoder, msg.participant, - timestamp=msg.timestamp) + def new_from_xml( + cls, tag: ET.Element, participants, decoders=None, message_types=None + ): + msg = Message.new_from_xml( + tag.find("message"), + participants=participants, + decoders=decoders, + message_types=message_types, + ) + destination = Participant.find_matching( + tag.get("destination_id", ""), participants + ) + return SimulatorMessage( + destination, + msg.plain_bits, + msg.pause, + msg.message_type, + msg.decoder, + msg.participant, + timestamp=msg.timestamp, + ) diff --git a/src/urh/simulator/SimulatorProtocolLabel.py b/src/urh/simulator/SimulatorProtocolLabel.py index 97ba1c49a4..bd2d592180 100644 --- a/src/urh/simulator/SimulatorProtocolLabel.py +++ b/src/urh/simulator/SimulatorProtocolLabel.py @@ -10,7 +10,13 @@ class SimulatorProtocolLabel(SimulatorItem): - VALUE_TYPES = ["Constant value", "Live input", "Formula", "External program", "Random value"] + VALUE_TYPES = [ + "Constant value", + "Live input", + "Formula", + "External program", + "Random value", + ] def __init__(self, label: ProtocolLabel): super().__init__() @@ -87,11 +93,16 @@ def validate(self): return result def to_xml(self) -> ET.Element: - result = ET.Element("simulator_label", attrib={"value_type_index": str(self.value_type_index), - "external_program": str(self.external_program), - "formula": str(self.formula), - "random_min": str(self.random_min), - "random_max": str(self.random_max)}) + result = ET.Element( + "simulator_label", + attrib={ + "value_type_index": str(self.value_type_index), + "external_program": str(self.external_program), + "formula": str(self.formula), + "random_min": str(self.random_min), + "random_max": str(self.random_max), + }, + ) result.append(self.label.to_xml()) return result @@ -107,11 +118,17 @@ def from_xml(cls, tag: ET.Element, field_types_by_caption=None): if label_tag is not None: label = ProtocolLabel.from_xml(label_tag, field_types_by_caption) else: - label = ChecksumLabel.from_xml(tag.find("checksum_label"), field_types_by_caption) + label = ChecksumLabel.from_xml( + tag.find("checksum_label"), field_types_by_caption + ) result = SimulatorProtocolLabel(label) - result.value_type_index = Formatter.str2val(tag.get("value_type_index", "0"), int) + result.value_type_index = Formatter.str2val( + tag.get("value_type_index", "0"), int + ) result.external_program = tag.get("external_program", "") result.formula = tag.get("formula", "") result.random_min = Formatter.str2val(tag.get("random_min", "0"), int) - result.random_max = Formatter.str2val(tag.get("random_max", str(label.fuzz_maximum-1)), int) + result.random_max = Formatter.str2val( + tag.get("random_max", str(label.fuzz_maximum - 1)), int + ) return result diff --git a/src/urh/simulator/SimulatorRule.py b/src/urh/simulator/SimulatorRule.py index cc30ab3a22..d292efc65c 100644 --- a/src/urh/simulator/SimulatorRule.py +++ b/src/urh/simulator/SimulatorRule.py @@ -22,7 +22,14 @@ def get_first_applying_condition(self): return next((child for child in self.children if child.condition_applies), None) def next_item(self): - return next((c.children[0] for c in self.children if c.condition_applies and c.child_count()), self.next_sibling()) + return next( + ( + c.children[0] + for c in self.children + if c.condition_applies and c.child_count() + ), + self.next_sibling(), + ) def to_xml(self) -> ET.Element: return ET.Element("simulator_rule") @@ -49,7 +56,9 @@ def condition_applies(self) -> bool: if self.type is ConditionType.ELSE: return True - valid, _, node = self.expression_parser.validate_expression(self.condition, is_formula=False) + valid, _, node = self.expression_parser.validate_expression( + self.condition, is_formula=False + ) assert valid == True and node is not None return self.expression_parser.evaluate_node(node) @@ -63,12 +72,16 @@ def validate(self): if self.type is ConditionType.ELSE: return True - result, _, _ = self.expression_parser.validate_expression(self.condition, is_formula=False) + result, _, _ = self.expression_parser.validate_expression( + self.condition, is_formula=False + ) return result def to_xml(self): - return ET.Element("simulator_rule_condition", attrib={"type": self.type.value, - "condition": self.condition}) + return ET.Element( + "simulator_rule_condition", + attrib={"type": self.type.value, "condition": self.condition}, + ) @classmethod def from_xml(cls, tag: ET.Element): diff --git a/src/urh/simulator/Transcript.py b/src/urh/simulator/Transcript.py index 4353d33f29..0ea85ff7eb 100644 --- a/src/urh/simulator/Transcript.py +++ b/src/urh/simulator/Transcript.py @@ -8,7 +8,9 @@ class Transcript(object): def __init__(self): self.__data = [] - def append(self, source: Participant, destination: Participant, msg: Message, index: int): + def append( + self, source: Participant, destination: Participant, msg: Message, index: int + ): if len(self.__data) == 0: self.__data.append([]) @@ -26,12 +28,20 @@ def get_for_all_participants(self, all_rounds: bool, use_bit=True) -> list: if len(self.__data) == 0: return result - rng = range(0, len(self.__data)) if all_rounds else range(len(self.__data)-1, len(self.__data)) + rng = ( + range(0, len(self.__data)) + if all_rounds + else range(len(self.__data) - 1, len(self.__data)) + ) for i in rng: for source, destination, msg, msg_index in self.__data[i]: data = msg.plain_bits_str if use_bit else msg.plain_hex_str - result.append(self.FORMAT.format(msg_index, source.shortname, destination.shortname, data)) + result.append( + self.FORMAT.format( + msg_index, source.shortname, destination.shortname, data + ) + ) if i != len(self.__data) - 1: result.append("") diff --git a/src/urh/simulator/UnlabeledRangeItem.py b/src/urh/simulator/UnlabeledRangeItem.py index 7ab832ae89..45a52e272e 100644 --- a/src/urh/simulator/UnlabeledRangeItem.py +++ b/src/urh/simulator/UnlabeledRangeItem.py @@ -1,6 +1,7 @@ from PyQt5.QtWidgets import QGraphicsTextItem from PyQt5.QtGui import QFontDatabase + class UnlabeledRangeItem(QGraphicsTextItem): def __init__(self, parent): super().__init__(parent) @@ -8,4 +9,4 @@ def __init__(self, parent): font = QFontDatabase.systemFont(QFontDatabase.FixedFont) font.setPointSize(8) self.setFont(font) - self.setPlainText("...") \ No newline at end of file + self.setPlainText("...") diff --git a/src/urh/ui/ExpressionLineEdit.py b/src/urh/ui/ExpressionLineEdit.py index b2604a63be..3f29095c2d 100644 --- a/src/urh/ui/ExpressionLineEdit.py +++ b/src/urh/ui/ExpressionLineEdit.py @@ -6,7 +6,9 @@ class ExpressionLineEdit(QLineEdit): - fld_abbrev_chars = ".0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ_abcdefghijklmnopqrstuvwxyz" + fld_abbrev_chars = ( + ".0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ_abcdefghijklmnopqrstuvwxyz" + ) def __init__(self, parent=None): super().__init__(parent) @@ -25,7 +27,9 @@ def setValidator(self, validator: RuleExpressionValidator): def on_validation_status_changed(self, status, message): if status == QValidator.Intermediate: col = settings.ERROR_BG_COLOR - bg_string = "background-color: rgba({}, {}, {}, {})".format(col.red(), col.green(), col.blue(), col.alpha()) + bg_string = "background-color: rgba({}, {}, {}, {})".format( + col.red(), col.green(), col.blue(), col.alpha() + ) style_sheet = "QLineEdit {" + bg_string + "}" else: style_sheet = "" @@ -41,14 +45,18 @@ def keyPressEvent(self, event): self.e_completer.setCompletionPrefix(token_word) - if (len(token_word) < 1 or (self.e_completer.completionCount() == 1 and - self.e_completer.currentCompletion() == token_word)): + if len(token_word) < 1 or ( + self.e_completer.completionCount() == 1 + and self.e_completer.currentCompletion() == token_word + ): self.e_completer.popup().hide() return cr = self.cursorRect() - cr.setWidth(self.e_completer.popup().sizeHintForColumn(0) + - self.e_completer.popup().verticalScrollBar().sizeHint().width()) + cr.setWidth( + self.e_completer.popup().sizeHintForColumn(0) + + self.e_completer.popup().verticalScrollBar().sizeHint().width() + ) self.e_completer.complete(cr) @@ -71,4 +79,4 @@ def insert_completion(self, completion_text): start, end = self.get_token_under_cursor() new_text = self.text()[:start] + completion_text + self.text()[end:] self.setText(new_text) - self.setCursorPosition(start + len(completion_text)) \ No newline at end of file + self.setCursorPosition(start + len(completion_text)) diff --git a/src/urh/ui/KillerDoubleSpinBox.py b/src/urh/ui/KillerDoubleSpinBox.py index 6eac29ad04..b458625221 100644 --- a/src/urh/ui/KillerDoubleSpinBox.py +++ b/src/urh/ui/KillerDoubleSpinBox.py @@ -11,6 +11,7 @@ class KillerDoubleSpinBox(QDoubleSpinBox): """ Print values with suffix (G,M,K) """ + def __init__(self, parent=None): super().__init__(parent) @@ -41,12 +42,12 @@ def adjust_step(self): self.setSingleStep(10 ** -(self.decimals())) def textFromValue(self, value: float): - if abs(value) >= 10 ** 9: - result, suffix = super().textFromValue(value / 10 ** 9), "G" - elif abs(value) >= 10 ** 6: - result, suffix = super().textFromValue(value / 10 ** 6), "M" - elif abs(value) >= 10 ** 3: - result, suffix = super().textFromValue(value / 10 ** 3), "K" + if abs(value) >= 10**9: + result, suffix = super().textFromValue(value / 10**9), "G" + elif abs(value) >= 10**6: + result, suffix = super().textFromValue(value / 10**6), "M" + elif abs(value) >= 10**3: + result, suffix = super().textFromValue(value / 10**3), "K" else: result, suffix = super().textFromValue(value), "" @@ -61,11 +62,11 @@ def textFromValue(self, value: float): def valueFromText(self, text: str): if text.endswith("G") or text.endswith("g"): - return QLocale().toDouble(text[:-1])[0] * 10 ** 9 + return QLocale().toDouble(text[:-1])[0] * 10**9 elif text.endswith("M") or text.endswith("m"): - return QLocale().toDouble(text[:-1])[0] * 10 ** 6 + return QLocale().toDouble(text[:-1])[0] * 10**6 elif text.endswith("K") or text.endswith("k"): - return QLocale().toDouble(text[:-1])[0] * 10 ** 3 + return QLocale().toDouble(text[:-1])[0] * 10**3 else: return QLocale().toDouble(text.rstrip(self.suffix()))[0] @@ -74,5 +75,9 @@ def validate(self, inpt: str, pos: int): rx = QRegExp("^(-?[0-9]+)[.]?[0-9]*[kKmMgG]?$") else: rx = QRegExp("^(-?[0-9]+)[.]?[0-9]*[{}]?$".format(self.suffix())) - result = QValidator.Acceptable if rx.exactMatch(inpt.replace(",", ".")) else QValidator.Invalid + result = ( + QValidator.Acceptable + if rx.exactMatch(inpt.replace(",", ".")) + else QValidator.Invalid + ) return result, inpt, pos diff --git a/src/urh/ui/ListWidget.py b/src/urh/ui/ListWidget.py index 38e6cba0c6..82b9d964f0 100644 --- a/src/urh/ui/ListWidget.py +++ b/src/urh/ui/ListWidget.py @@ -24,7 +24,7 @@ def dropEvent(self, event: QDropEvent): index = self.indexFromItem(item).row() self.setCurrentRow(index) else: - self.setCurrentRow(self.count()-1) + self.setCurrentRow(self.count() - 1) def dragEnterEvent(self, event: QDragEnterEvent): self.active_element = self.indexAt(event.pos()).row() @@ -34,8 +34,11 @@ def dragEnterEvent(self, event: QDragEnterEvent): def eventFilter(self, sender, event): if event.type() == QEvent.ChildRemoved: self.internalMove.emit() - elif event.type() == QEvent.KeyPress and event.key() in (Qt.Key_Delete, Qt.Key_Backspace)\ - and self.currentItem() is not None: + elif ( + event.type() == QEvent.KeyPress + and event.key() in (Qt.Key_Delete, Qt.Key_Backspace) + and self.currentItem() is not None + ): item = self.currentRow() item_name = self.currentItem().text() self.active_element_text = item_name @@ -86,7 +89,7 @@ def on_disable_function_triggered(self): item = self.indexAt(self.context_menu_pos).row() item_name = self.item(item).text() if settings.DECODING_DISABLED_PREFIX in item_name: - item_name = item_name[len(settings.DECODING_DISABLED_PREFIX):] + item_name = item_name[len(settings.DECODING_DISABLED_PREFIX) :] else: item_name = settings.DECODING_DISABLED_PREFIX + item_name self.takeItem(item) diff --git a/src/urh/ui/RuleExpressionValidator.py b/src/urh/ui/RuleExpressionValidator.py index 1cbfdbf73e..99e54db0e8 100644 --- a/src/urh/ui/RuleExpressionValidator.py +++ b/src/urh/ui/RuleExpressionValidator.py @@ -1,6 +1,7 @@ from PyQt5.QtGui import QValidator from PyQt5.QtCore import pyqtSignal + class RuleExpressionValidator(QValidator): validation_status_changed = pyqtSignal(QValidator.State, str) @@ -14,4 +15,4 @@ def validate(self, text, pos): state = QValidator.Acceptable if valid else QValidator.Intermediate self.validation_status_changed.emit(state, message) - return (state, text, pos) \ No newline at end of file + return (state, text, pos) diff --git a/src/urh/ui/ScrollArea.py b/src/urh/ui/ScrollArea.py index 7adbea0b75..26623c1ada 100644 --- a/src/urh/ui/ScrollArea.py +++ b/src/urh/ui/ScrollArea.py @@ -2,6 +2,7 @@ from PyQt5.QtGui import QDropEvent, QDragEnterEvent, QWheelEvent from PyQt5.QtWidgets import QScrollArea + class ScrollArea(QScrollArea): files_dropped = pyqtSignal(list) diff --git a/src/urh/ui/SimulatorScene.py b/src/urh/ui/SimulatorScene.py index ccae507498..6016b4ed1b 100644 --- a/src/urh/ui/SimulatorScene.py +++ b/src/urh/ui/SimulatorScene.py @@ -2,14 +2,23 @@ from PyQt5.QtCore import pyqtSignal from PyQt5.QtGui import QDropEvent -from PyQt5.QtWidgets import QGraphicsScene, QGraphicsSceneDragDropEvent, QAbstractItemView +from PyQt5.QtWidgets import ( + QGraphicsScene, + QGraphicsSceneDragDropEvent, + QAbstractItemView, +) from urh.signalprocessing.FieldType import FieldType from urh.signalprocessing.Message import Message from urh.signalprocessing.MessageType import MessageType from urh.signalprocessing.Participant import Participant -from urh.simulator.ActionItem import ActionItem, GotoActionItem, TriggerCommandActionItem, SleepActionItem, \ - CounterActionItem +from urh.simulator.ActionItem import ( + ActionItem, + GotoActionItem, + TriggerCommandActionItem, + SleepActionItem, + CounterActionItem, +) from urh.simulator.GraphicsItem import GraphicsItem from urh.simulator.LabelItem import LabelItem from urh.simulator.MessageItem import MessageItem @@ -21,7 +30,11 @@ from urh.simulator.SimulatorItem import SimulatorItem from urh.simulator.SimulatorMessage import SimulatorMessage from urh.simulator.SimulatorProtocolLabel import SimulatorProtocolLabel -from urh.simulator.SimulatorRule import SimulatorRule, SimulatorRuleCondition, ConditionType +from urh.simulator.SimulatorRule import ( + SimulatorRule, + SimulatorRuleCondition, + ConditionType, +) from urh.simulator.SimulatorSleepAction import SimulatorSleepAction from urh.simulator.SimulatorTriggerCommandAction import SimulatorTriggerCommandAction @@ -37,10 +50,12 @@ class SimulatorScene(QGraphicsScene): SimulatorCounterAction: CounterActionItem, SimulatorSleepAction: SleepActionItem, SimulatorMessage: MessageItem, - SimulatorProtocolLabel: LabelItem + SimulatorProtocolLabel: LabelItem, } - def __init__(self, mode: int, simulator_config: SimulatorConfiguration, parent=None): + def __init__( + self, mode: int, simulator_config: SimulatorConfiguration, parent=None + ): super().__init__(parent) self.mode = mode self.simulator_config = simulator_config @@ -49,7 +64,9 @@ def __init__(self, mode: int, simulator_config: SimulatorConfiguration, parent=N self.participants_dict = {} self.participant_items = [] - self.broadcast_part = self.insert_participant(self.simulator_config.broadcast_part) + self.broadcast_part = self.insert_participant( + self.simulator_config.broadcast_part + ) self.not_assigned_part = self.insert_participant(None) self.update_participants(refresh=False) @@ -65,7 +82,11 @@ def visible_participants(self): @property def visible_participants_without_broadcast(self): - return [part for part in self.participant_items if part.isVisible() and part is not self.broadcast_part] + return [ + part + for part in self.participant_items + if part.isVisible() and part is not self.broadcast_part + ] def create_connects(self): self.simulator_config.participants_changed.connect(self.update_participants) @@ -118,7 +139,7 @@ def on_item_added(self, item: SimulatorItem): self.on_item_added(child) def model_to_scene(self, model_item: SimulatorItem): - if (model_item is None or model_item is self.simulator_config.rootItem): + if model_item is None or model_item is self.simulator_config.rootItem: return None try: @@ -152,7 +173,11 @@ def get_parent_scene_item(self, item: GraphicsItem): def min_items_width(self): width = 0 - items = [item for item in self.items() if isinstance(item, (RuleConditionItem, ActionItem))] + items = [ + item + for item in self.items() + if isinstance(item, (RuleConditionItem, ActionItem)) + ] for item in items: if item.labels_width() > width: @@ -182,7 +207,6 @@ def log_selected_items(self, logging_active: bool): self.log_items(items, logging_active) def log_items(self, items, logging_active: bool): - for item in items: item.model_item.logging_active = logging_active @@ -200,8 +224,11 @@ def log_all_items(self, logging_active: bool): self.log_items(self.selectable_items(), logging_active) def selectable_items(self): - return [item for item in self.items() if isinstance(item, GraphicsItem) and - item.is_selectable()] + return [ + item + for item in self.items() + if isinstance(item, GraphicsItem) and item.is_selectable() + ] def move_items(self, items, ref_item, position): new_pos, new_parent = self.insert_at(ref_item, position) @@ -231,7 +258,10 @@ def update_view(self): def update_participants(self, refresh=True): for participant in list(self.participants_dict): - if participant is None or participant == self.simulator_config.broadcast_part: + if ( + participant is None + or participant == self.simulator_config.broadcast_part + ): continue self.removeItem(self.participants_dict[participant]) @@ -272,22 +302,32 @@ def get_selected_messages(self): :rtype: list[SimulatorMessage] """ - return [item.model_item for item in self.selectedItems() if isinstance(item, MessageItem)] - - def select_messages_with_participant(self, participant: ParticipantItem, from_part=True): + return [ + item.model_item + for item in self.selectedItems() + if isinstance(item, MessageItem) + ] + + def select_messages_with_participant( + self, participant: ParticipantItem, from_part=True + ): messages = self.get_all_message_items() self.clearSelection() for msg in messages: - if ((from_part and msg.source is participant) or - (not from_part and msg.destination is participant)): + if (from_part and msg.source is participant) or ( + not from_part and msg.destination is participant + ): msg.select_all() def arrange_participants(self): messages = self.get_all_message_items() for participant in self.participant_items: - if any(msg.source == participant or msg.destination == participant for msg in messages): + if any( + msg.source == participant or msg.destination == participant + for msg in messages + ): participant.setVisible(True) else: participant.setVisible(False) @@ -304,9 +344,20 @@ def arrange_participants(self): curr_participant = vp[i] participants_left = vp[:i] - items = [msg for msg in messages - if ((msg.source == curr_participant and msg.destination in participants_left) - or (msg.source in participants_left and msg.destination == curr_participant))] + items = [ + msg + for msg in messages + if ( + ( + msg.source == curr_participant + and msg.destination in participants_left + ) + or ( + msg.source in participants_left + and msg.destination == curr_participant + ) + ) + ] x_max = vp[i - 1].x_pos() x_max += (vp[i - 1].width() + curr_participant.width()) / 2 @@ -314,7 +365,11 @@ def arrange_participants(self): for msg in items: x = msg.width() + 30 - x += msg.source.x_pos() if msg.source != curr_participant else msg.destination.x_pos() + x += ( + msg.source.x_pos() + if msg.source != curr_participant + else msg.destination.x_pos() + ) if x > x_max: x_max = x @@ -374,7 +429,11 @@ def insert_at(self, ref_item, position, insert_rule=False): return (insert_position, parent_item) def dropEvent(self, event: QDropEvent): - items = [item for item in self.items(event.scenePos()) if isinstance(item, GraphicsItem) and item.acceptDrops()] + items = [ + item + for item in self.items(event.scenePos()) + if isinstance(item, GraphicsItem) and item.acceptDrops() + ] item = None if len(items) == 0 else items[0] if len(event.mimeData().urls()) > 0: self.files_dropped.emit(event.mimeData().urls()) @@ -403,7 +462,9 @@ def dropEvent(self, event: QDropEvent): """:type: list of ProtocolTreeItem """ for group_node in group_nodes: nodes_to_add.extend(group_node.children) - nodes_to_add.extend([file_node for file_node in file_nodes if file_node not in nodes_to_add]) + nodes_to_add.extend( + [file_node for file_node in file_nodes if file_node not in nodes_to_add] + ) protocols_to_add = [node.protocol for node in nodes_to_add] ref_item = item @@ -454,19 +515,38 @@ def add_trigger_command_action(self, ref_item, position): self.simulator_config.add_items([command_action], pos, parent) return command_action - def add_message(self, plain_bits, pause, message_type, ref_item, position, decoder=None, source=None, - destination=None): - message = self.create_message(destination, plain_bits, pause, message_type, decoder, source) + def add_message( + self, + plain_bits, + pause, + message_type, + ref_item, + position, + decoder=None, + source=None, + destination=None, + ): + message = self.create_message( + destination, plain_bits, pause, message_type, decoder, source + ) pos, parent = self.insert_at(ref_item, position, False) self.simulator_config.add_items([message], pos, parent) return message - def create_message(self, destination, plain_bits, pause, message_type, decoder, source): + def create_message( + self, destination, plain_bits, pause, message_type, decoder, source + ): if destination is None: destination = self.simulator_config.broadcast_part - sim_message = SimulatorMessage(destination=destination, plain_bits=plain_bits, pause=pause, - message_type=MessageType(message_type.name), decoder=decoder, source=source) + sim_message = SimulatorMessage( + destination=destination, + plain_bits=plain_bits, + pause=pause, + message_type=MessageType(message_type.name), + decoder=decoder, + source=source, + ) for lbl in message_type: sim_label = SimulatorProtocolLabel(copy.deepcopy(lbl)) @@ -475,7 +555,9 @@ def create_message(self, destination, plain_bits, pause, message_type, decoder, return sim_message def clear_all(self): - self.simulator_config.delete_items([item for item in self.simulator_config.rootItem.children]) + self.simulator_config.delete_items( + [item for item in self.simulator_config.rootItem.children] + ) def add_protocols(self, ref_item, position, protocols_to_add: list): pos, parent = self.insert_at(ref_item, position) @@ -484,12 +566,14 @@ def add_protocols(self, ref_item, position, protocols_to_add: list): for protocol in protocols_to_add: for msg in protocol.messages: source, destination = self.detect_source_destination(msg) - simulator_msg = self.create_message(destination=destination, - plain_bits=copy.copy(msg.decoded_bits), - pause=0, - message_type=msg.message_type, - decoder=msg.decoder, - source=source) + simulator_msg = self.create_message( + destination=destination, + plain_bits=copy.copy(msg.decoded_bits), + pause=0, + message_type=msg.message_type, + decoder=msg.decoder, + source=source, + ) simulator_msg.timestamp = msg.timestamp messages.append(simulator_msg) @@ -517,12 +601,23 @@ def detect_source_destination(self, message: Message): if message.participant: source = message.participant - dst_address_label = next((lbl for lbl in message.message_type if lbl.field_type and - lbl.field_type.function == FieldType.Function.DST_ADDRESS), None) + dst_address_label = next( + ( + lbl + for lbl in message.message_type + if lbl.field_type + and lbl.field_type.function == FieldType.Function.DST_ADDRESS + ), + None, + ) if dst_address_label: - start, end = message.get_label_range(dst_address_label, view=1, decode=True) + start, end = message.get_label_range( + dst_address_label, view=1, decode=True + ) dst_address = message.decoded_hex_str[start:end] - dst = next((p for p in participants if p.address_hex == dst_address), None) + dst = next( + (p for p in participants if p.address_hex == dst_address), None + ) if dst is not None and dst != source: destination = dst diff --git a/src/urh/ui/actions/ChangeSignalParameter.py b/src/urh/ui/actions/ChangeSignalParameter.py index 6223303225..c2361f5d46 100644 --- a/src/urh/ui/actions/ChangeSignalParameter.py +++ b/src/urh/ui/actions/ChangeSignalParameter.py @@ -7,7 +7,13 @@ class ChangeSignalParameter(QUndoCommand): - def __init__(self, signal: Signal, protocol: ProtocolAnalyzer, parameter_name: str, parameter_value): + def __init__( + self, + signal: Signal, + protocol: ProtocolAnalyzer, + parameter_name: str, + parameter_value, + ): super().__init__() if not hasattr(signal, parameter_name): raise ValueError("signal has no attribute {}".format(parameter_name)) @@ -17,20 +23,36 @@ def __init__(self, signal: Signal, protocol: ProtocolAnalyzer, parameter_name: s self.parameter_value = parameter_value self.orig_value = getattr(self.signal, self.parameter_name) - fmt2 = "d" if isinstance(self.orig_value, int) else ".4n" if isinstance(self.orig_value, float) else "s" - fmt3 = "d" if isinstance(parameter_value, int) else ".4n" if isinstance(parameter_value, float) else "s" + fmt2 = ( + "d" + if isinstance(self.orig_value, int) + else ".4n" + if isinstance(self.orig_value, float) + else "s" + ) + fmt3 = ( + "d" + if isinstance(parameter_value, int) + else ".4n" + if isinstance(parameter_value, float) + else "s" + ) signal_name = signal.name[:10] + "..." if len(signal.name) > 10 else signal.name self.setText( - ("change {0} of {1} from {2:" + fmt2 + "} to {3:" + fmt3 + "}") - .format(parameter_name, signal_name, self.orig_value, parameter_value) + ("change {0} of {1} from {2:" + fmt2 + "} to {3:" + fmt3 + "}").format( + parameter_name, signal_name, self.orig_value, parameter_value + ) ) self.protocol = protocol self.orig_messages = copy.deepcopy(self.protocol.messages) def redo(self): - msg_data = [(msg.decoder, msg.participant, msg.message_type) for msg in self.protocol.messages] + msg_data = [ + (msg.decoder, msg.participant, msg.message_type) + for msg in self.protocol.messages + ] setattr(self.signal, self.parameter_name, self.parameter_value) # Restore msg parameters if len(msg_data) == self.protocol.num_messages: diff --git a/src/urh/ui/actions/DeleteBitsAndPauses.py b/src/urh/ui/actions/DeleteBitsAndPauses.py index 4f04fa7e01..ecbe0263c2 100644 --- a/src/urh/ui/actions/DeleteBitsAndPauses.py +++ b/src/urh/ui/actions/DeleteBitsAndPauses.py @@ -6,11 +6,23 @@ class DeleteBitsAndPauses(QUndoCommand): - def __init__(self, proto_analyzer: ProtocolAnalyzer, start_message: int, end_message:int, - start: int, end: int, view: int, decoded: bool, subprotos=None, update_label_ranges=True): + def __init__( + self, + proto_analyzer: ProtocolAnalyzer, + start_message: int, + end_message: int, + start: int, + end: int, + view: int, + decoded: bool, + subprotos=None, + update_label_ranges=True, + ): super().__init__() - self.sub_protocols = [] if subprotos is None else subprotos # type: list[ProtocolAnalyzer] + self.sub_protocols = ( + [] if subprotos is None else subprotos + ) # type: list[ProtocolAnalyzer] self.view = view self.end = end self.start = start @@ -28,20 +40,34 @@ def __init__(self, proto_analyzer: ProtocolAnalyzer, start_message: int, end_mes self.setText("Delete") def redo(self): - self.saved_messages = copy.deepcopy(self.proto_analyzer.messages[self.start_message:self.end_message+1]) - self.removed_message_indices = self.proto_analyzer.delete_messages(self.start_message, self.end_message, - self.start, self.end, - self.view, self.decoded, self.update_label_ranges) + self.saved_messages = copy.deepcopy( + self.proto_analyzer.messages[self.start_message : self.end_message + 1] + ) + self.removed_message_indices = self.proto_analyzer.delete_messages( + self.start_message, + self.end_message, + self.start, + self.end, + self.view, + self.decoded, + self.update_label_ranges, + ) def undo(self): - for i in reversed(range(self.start_message, self.end_message+1)): + for i in reversed(range(self.start_message, self.end_message + 1)): if i in self.removed_message_indices: - self.proto_analyzer.messages.insert(i, self.saved_messages[i-self.start_message]) + self.proto_analyzer.messages.insert( + i, self.saved_messages[i - self.start_message] + ) else: try: - self.proto_analyzer.messages[i] = self.saved_messages[i-self.start_message] + self.proto_analyzer.messages[i] = self.saved_messages[ + i - self.start_message + ] except IndexError: - self.proto_analyzer.messages.append(self.saved_messages[i-self.start_message]) + self.proto_analyzer.messages.append( + self.saved_messages[i - self.start_message] + ) for sub_protocol in self.sub_protocol_history.keys(): sub_protocol.messages = self.sub_protocol_history[sub_protocol] diff --git a/src/urh/ui/actions/EditSignalAction.py b/src/urh/ui/actions/EditSignalAction.py index d161fc8ddf..3e8fe308d0 100644 --- a/src/urh/ui/actions/EditSignalAction.py +++ b/src/urh/ui/actions/EditSignalAction.py @@ -23,10 +23,18 @@ class EditAction(Enum): class EditSignalAction(QUndoCommand): - def __init__(self, signal: Signal, mode: EditAction, - start: int = 0, end: int = 0, position: int = 0, - data_to_insert: np.ndarray=None, dsp_filter: Filter=None, - protocol: ProtocolAnalyzer=None, cache_qad=True): + def __init__( + self, + signal: Signal, + mode: EditAction, + start: int = 0, + end: int = 0, + position: int = 0, + data_to_insert: np.ndarray = None, + dsp_filter: Filter = None, + protocol: ProtocolAnalyzer = None, + cache_qad=True, + ): """ :param signal: Signal to change @@ -55,24 +63,24 @@ def __init__(self, signal: Signal, mode: EditAction, if self.mode == EditAction.crop: self.setText("Crop Signal") - self.pre_crop_data = self.signal.iq_array[0:self.start] - self.post_crop_data = self.signal.iq_array[self.end:] + self.pre_crop_data = self.signal.iq_array[0 : self.start] + self.post_crop_data = self.signal.iq_array[self.end :] if self.cache_qad: - self.pre_crop_qad = self.signal._qad[0:self.start] - self.post_crop_qad = self.signal._qad[self.end:] + self.pre_crop_qad = self.signal._qad[0 : self.start] + self.post_crop_qad = self.signal._qad[self.end :] elif self.mode == EditAction.mute or self.mode == EditAction.filter: if self.mode == EditAction.mute: self.setText("Mute Signal") elif self.mode == EditAction.filter: self.setText("Filter Signal") - self.orig_data_part = copy.copy(self.signal.iq_array[self.start:self.end]) + self.orig_data_part = copy.copy(self.signal.iq_array[self.start : self.end]) if self.cache_qad and self.signal._qad is not None: - self.orig_qad_part = copy.copy(self.signal._qad[self.start:self.end]) + self.orig_qad_part = copy.copy(self.signal._qad[self.start : self.end]) elif self.mode == EditAction.delete: self.setText("Delete Range") - self.orig_data_part = self.signal.iq_array[self.start:self.end] + self.orig_data_part = self.signal.iq_array[self.start : self.end] if self.cache_qad and self.signal._qad is not None: - self.orig_qad_part = self.signal._qad[self.start:self.end] + self.orig_qad_part = self.signal._qad[self.start : self.end] elif self.mode == EditAction.paste: self.setText("Paste") elif self.mode == EditAction.insert: @@ -89,7 +97,9 @@ def redo(self): keep_msg_indices = {} if self.mode in (EditAction.delete, EditAction.mute) and self.protocol: - removed_msg_indices = self.__find_message_indices_in_sample_range(self.start, self.end) + removed_msg_indices = self.__find_message_indices_in_sample_range( + self.start, self.end + ) if removed_msg_indices: for i in range(self.protocol.num_messages): if i < removed_msg_indices[0]: @@ -100,9 +110,13 @@ def redo(self): keep_msg_indices = {i: i for i in range(self.protocol.num_messages)} elif self.mode == EditAction.crop and self.protocol: removed_left = self.__find_message_indices_in_sample_range(0, self.start) - removed_right = self.__find_message_indices_in_sample_range(self.end, self.signal.num_samples) + removed_right = self.__find_message_indices_in_sample_range( + self.end, self.signal.num_samples + ) last_removed_left = removed_left[-1] if removed_left else -1 - first_removed_right = removed_right[0] if removed_right else self.protocol.num_messages + 1 + first_removed_right = ( + removed_right[0] if removed_right else self.protocol.num_messages + 1 + ) for i in range(self.protocol.num_messages): if last_removed_left < i < first_removed_right: @@ -141,33 +155,41 @@ def undo(self): self.signal.iq_array.insert_subarray(self.start, self.orig_data_part) if self.cache_qad and self.orig_qad_part is not None: try: - self.signal._qad = np.insert(self.signal._qad, self.start, self.orig_qad_part) + self.signal._qad = np.insert( + self.signal._qad, self.start, self.orig_qad_part + ) except ValueError: self.signal._qad = None logger.warning("Could not restore cached qad.") elif self.mode == EditAction.mute or self.mode == EditAction.filter: - self.signal.iq_array[self.start:self.end] = self.orig_data_part + self.signal.iq_array[self.start : self.end] = self.orig_data_part if self.cache_qad and self.orig_qad_part is not None: try: - self.signal._qad[self.start:self.end] = self.orig_qad_part + self.signal._qad[self.start : self.end] = self.orig_qad_part except (ValueError, TypeError): self.signal._qad = None logger.warning("Could not restore cached qad.") elif self.mode == EditAction.crop: self.signal.iq_array = IQArray( - np.concatenate((self.pre_crop_data, self.signal.iq_array.data, self.post_crop_data)) + np.concatenate( + (self.pre_crop_data, self.signal.iq_array.data, self.post_crop_data) + ) ) if self.cache_qad: try: - self.signal._qad = np.concatenate((self.pre_crop_qad, self.signal._qad, self.post_crop_qad)) + self.signal._qad = np.concatenate( + (self.pre_crop_qad, self.signal._qad, self.post_crop_qad) + ) except ValueError: self.signal._qad = None logger.warning("Could not restore cached qad.") elif self.mode == EditAction.paste or self.mode == EditAction.insert: - self.signal.delete_range(self.position, self.position+len(self.data_to_insert)) + self.signal.delete_range( + self.position, self.position + len(self.data_to_insert) + ) self.signal.parameter_cache = self.orig_parameter_cache @@ -191,13 +213,16 @@ def __get_keep_msg_indices_for_paste(self): keep_msg_indices = {i: i for i in range(len(self.orig_messages))} try: - paste_start_index = self.__find_message_indices_in_sample_range(self.position, self.signal.num_samples)[0] + paste_start_index = self.__find_message_indices_in_sample_range( + self.position, self.signal.num_samples + )[0] except IndexError: paste_start_index = 0 try: - paste_end_index = self.__find_message_indices_in_sample_range(self.position + len(self.data_to_insert), - self.signal.num_samples)[0] + paste_end_index = self.__find_message_indices_in_sample_range( + self.position + len(self.data_to_insert), self.signal.num_samples + )[0] except IndexError: paste_end_index = 0 diff --git a/src/urh/ui/actions/Fuzz.py b/src/urh/ui/actions/Fuzz.py index d88b402c7c..2127017a08 100644 --- a/src/urh/ui/actions/Fuzz.py +++ b/src/urh/ui/actions/Fuzz.py @@ -5,7 +5,9 @@ class Fuzz(QUndoCommand): - def __init__(self, proto_analyzer_container: ProtocolAnalyzerContainer, fuz_mode: str): + def __init__( + self, proto_analyzer_container: ProtocolAnalyzerContainer, fuz_mode: str + ): super().__init__() self.proto_analyzer_container = proto_analyzer_container self.fuz_mode = fuz_mode @@ -14,17 +16,23 @@ def __init__(self, proto_analyzer_container: ProtocolAnalyzerContainer, fuz_mode self.added_message_indices = [] def redo(self): - if settings.read('use_default_fuzzing_pause', True, bool): + if settings.read("use_default_fuzzing_pause", True, bool): default_pause = settings.read("default_fuzzing_pause", 10**6, int) else: default_pause = None if self.fuz_mode == "Successive": - added_indices = self.proto_analyzer_container.fuzz_successive(default_pause=default_pause) + added_indices = self.proto_analyzer_container.fuzz_successive( + default_pause=default_pause + ) elif self.fuz_mode == "Concurrent": - added_indices = self.proto_analyzer_container.fuzz_concurrent(default_pause=default_pause) + added_indices = self.proto_analyzer_container.fuzz_concurrent( + default_pause=default_pause + ) elif self.fuz_mode == "Exhaustive": - added_indices = self.proto_analyzer_container.fuzz_exhaustive(default_pause=default_pause) + added_indices = self.proto_analyzer_container.fuzz_exhaustive( + default_pause=default_pause + ) else: added_indices = [] diff --git a/src/urh/ui/actions/InsertBitsAndPauses.py b/src/urh/ui/actions/InsertBitsAndPauses.py index bafa06fc64..9001ce5602 100644 --- a/src/urh/ui/actions/InsertBitsAndPauses.py +++ b/src/urh/ui/actions/InsertBitsAndPauses.py @@ -7,7 +7,12 @@ class InsertBitsAndPauses(QUndoCommand): - def __init__(self, proto_analyzer_container: ProtocolAnalyzerContainer, index: int, pa: ProtocolAnalyzer): + def __init__( + self, + proto_analyzer_container: ProtocolAnalyzerContainer, + index: int, + pa: ProtocolAnalyzer, + ): super().__init__() self.proto_analyzer_container = proto_analyzer_container self.proto_analyzer = pa @@ -19,10 +24,12 @@ def __init__(self, proto_analyzer_container: ProtocolAnalyzerContainer, index: i self.num_messages = 0 def redo(self): - self.proto_analyzer_container.insert_protocol_analyzer(self.index, self.proto_analyzer) + self.proto_analyzer_container.insert_protocol_analyzer( + self.index, self.proto_analyzer + ) self.num_messages += len(self.proto_analyzer.messages) def undo(self): - for i in reversed(range(self.index, self.index+self.num_messages)): + for i in reversed(range(self.index, self.index + self.num_messages)): del self.proto_analyzer_container.messages[i] self.num_messages = 0 diff --git a/src/urh/ui/actions/InsertColumn.py b/src/urh/ui/actions/InsertColumn.py index c7865438c0..78b99baf2b 100644 --- a/src/urh/ui/actions/InsertColumn.py +++ b/src/urh/ui/actions/InsertColumn.py @@ -6,10 +6,14 @@ class InsertColumn(QUndoCommand): - def __init__(self, proto_analyzer: ProtocolAnalyzer, index: int, rows: list, view: int): + def __init__( + self, proto_analyzer: ProtocolAnalyzer, index: int, rows: list, view: int + ): super().__init__() self.proto_analyzer = proto_analyzer - self.index = proto_analyzer.convert_index(index, from_view=view, to_view=0, decoded=False)[0] + self.index = proto_analyzer.convert_index( + index, from_view=view, to_view=0, decoded=False + )[0] self.nbits = 1 if view == 0 else 4 if view == 1 else 8 self.rows = rows diff --git a/src/urh/ui/actions/__init__.py b/src/urh/ui/actions/__init__.py index 3fa5af38d8..813939aaf7 100644 --- a/src/urh/ui/actions/__init__.py +++ b/src/urh/ui/actions/__init__.py @@ -1 +1 @@ -__author__ = 'joe' +__author__ = "joe" diff --git a/src/urh/ui/delegates/CheckBoxDelegate.py b/src/urh/ui/delegates/CheckBoxDelegate.py index f6cbfeb7b8..3547a58073 100644 --- a/src/urh/ui/delegates/CheckBoxDelegate.py +++ b/src/urh/ui/delegates/CheckBoxDelegate.py @@ -1,5 +1,10 @@ from PyQt5.QtCore import QModelIndex, QAbstractItemModel, Qt, pyqtSlot -from PyQt5.QtWidgets import QStyledItemDelegate, QWidget, QStyleOptionViewItem, QCheckBox +from PyQt5.QtWidgets import ( + QStyledItemDelegate, + QWidget, + QStyleOptionViewItem, + QCheckBox, +) class CheckBoxDelegate(QStyledItemDelegate): @@ -7,7 +12,9 @@ def __init__(self, parent=None): super().__init__(parent) self.enabled = True - def createEditor(self, parent: QWidget, option: QStyleOptionViewItem, index: QModelIndex): + def createEditor( + self, parent: QWidget, option: QStyleOptionViewItem, index: QModelIndex + ): editor = QCheckBox(parent) editor.stateChanged.connect(self.stateChanged) return editor @@ -18,9 +25,11 @@ def setEditorData(self, editor: QCheckBox, index: QModelIndex): self.enabled = editor.isChecked() editor.blockSignals(False) - def setModelData(self, editor: QCheckBox, model: QAbstractItemModel, index: QModelIndex): + def setModelData( + self, editor: QCheckBox, model: QAbstractItemModel, index: QModelIndex + ): model.setData(index, editor.isChecked(), Qt.EditRole) @pyqtSlot() def stateChanged(self): - self.commitData.emit(self.sender()) \ No newline at end of file + self.commitData.emit(self.sender()) diff --git a/src/urh/ui/delegates/ComboBoxDelegate.py b/src/urh/ui/delegates/ComboBoxDelegate.py index 2f947e65e4..83cf0c2c8a 100644 --- a/src/urh/ui/delegates/ComboBoxDelegate.py +++ b/src/urh/ui/delegates/ComboBoxDelegate.py @@ -2,11 +2,18 @@ from PyQt5.QtCore import QModelIndex, Qt, QAbstractItemModel, pyqtSlot, QRectF from PyQt5.QtGui import QImage, QPainter, QColor, QPixmap -from PyQt5.QtWidgets import QStyledItemDelegate, QWidget, QStyleOptionViewItem, QComboBox +from PyQt5.QtWidgets import ( + QStyledItemDelegate, + QWidget, + QStyleOptionViewItem, + QComboBox, +) class ComboBoxDelegate(QStyledItemDelegate): - def __init__(self, items, colors=None, is_editable=False, return_index=True, parent=None): + def __init__( + self, items, colors=None, is_editable=False, return_index=True, parent=None + ): """ :param items: @@ -25,7 +32,9 @@ def __init__(self, items, colors=None, is_editable=False, return_index=True, par if colors: assert len(items) == len(colors) - def paint(self, painter: QPainter, option: QStyleOptionViewItem, index: QModelIndex): + def paint( + self, painter: QPainter, option: QStyleOptionViewItem, index: QModelIndex + ): if self.colors: try: item = index.model().data(index) @@ -37,13 +46,17 @@ def paint(self, painter: QPainter, option: QStyleOptionViewItem, index: QModelIn rect = QRectF(x + 8, y + h / 2 - 8, 16, 16) painter.fillRect(rect, QColor("black")) rect = rect.adjusted(1, 1, -1, -1) - painter.fillRect(rect, QColor(color.red(), color.green(), color.blue(), 255)) + painter.fillRect( + rect, QColor(color.red(), color.green(), color.blue(), 255) + ) except: super().paint(painter, option, index) else: super().paint(painter, option, index) - def createEditor(self, parent: QWidget, option: QStyleOptionViewItem, index: QModelIndex): + def createEditor( + self, parent: QWidget, option: QStyleOptionViewItem, index: QModelIndex + ): editor = QComboBox(parent) if sys.platform == "win32": # Ensure text entries are visible with windows combo boxes @@ -66,7 +79,9 @@ def createEditor(self, parent: QWidget, option: QStyleOptionViewItem, index: QMo rect = img.rect().adjusted(1, 1, -1, -1) for i, item in enumerate(self.items): color = self.colors[i] - painter.fillRect(rect, QColor(color.red(), color.green(), color.blue(), 255)) + painter.fillRect( + rect, QColor(color.red(), color.green(), color.blue(), 255) + ) editor.setItemData(i, QPixmap.fromImage(img), Qt.DecorationRole) del painter @@ -84,13 +99,17 @@ def setEditorData(self, editor: QWidget, index: QModelIndex): pass editor.blockSignals(False) - def setModelData(self, editor: QWidget, model: QAbstractItemModel, index: QModelIndex): + def setModelData( + self, editor: QWidget, model: QAbstractItemModel, index: QModelIndex + ): if self.return_index: model.setData(index, editor.currentIndex(), Qt.EditRole) else: model.setData(index, editor.currentText(), Qt.EditRole) - def updateEditorGeometry(self, editor: QWidget, option: QStyleOptionViewItem, index: QModelIndex): + def updateEditorGeometry( + self, editor: QWidget, option: QStyleOptionViewItem, index: QModelIndex + ): editor.setGeometry(option.rect) @pyqtSlot() diff --git a/src/urh/ui/delegates/MessageTypeButtonDelegate.py b/src/urh/ui/delegates/MessageTypeButtonDelegate.py index 5eaa3a751a..e5c23c02ff 100644 --- a/src/urh/ui/delegates/MessageTypeButtonDelegate.py +++ b/src/urh/ui/delegates/MessageTypeButtonDelegate.py @@ -17,7 +17,9 @@ def createEditor(self, parent, option, index): button = QPushButton(parent) button.setFlat(True) - num_rules = self.parent().model().get_num_active_rules_of_message_type_at(index.row()) + num_rules = ( + self.parent().model().get_num_active_rules_of_message_type_at(index.row()) + ) if num_rules == 0: icon = QIcon.fromTheme("configure") @@ -51,7 +53,9 @@ def draw_indicator(indicator: int): fw = f.width(indicator_str) fh = f.height() - painter.drawText(math.ceil(w / 2 - fw / 2), math.ceil(h / 2 + fh / 4), indicator_str) + painter.drawText( + math.ceil(w / 2 - fw / 2), math.ceil(h / 2 + fh / 4), indicator_str + ) painter.end() return QIcon(pixmap) diff --git a/src/urh/ui/delegates/ProtocolValueDelegate.py b/src/urh/ui/delegates/ProtocolValueDelegate.py index 00b70cb1b8..e453dc346c 100644 --- a/src/urh/ui/delegates/ProtocolValueDelegate.py +++ b/src/urh/ui/delegates/ProtocolValueDelegate.py @@ -1,6 +1,15 @@ from PyQt5.QtCore import QModelIndex, QAbstractItemModel, Qt -from PyQt5.QtWidgets import QStyledItemDelegate, QWidget, QStyleOptionViewItem, QLineEdit, QHBoxLayout, \ - QCompleter, QLabel, QSpinBox, QDirModel +from PyQt5.QtWidgets import ( + QStyledItemDelegate, + QWidget, + QStyleOptionViewItem, + QLineEdit, + QHBoxLayout, + QCompleter, + QLabel, + QSpinBox, + QDirModel, +) from urh.ui.ExpressionLineEdit import ExpressionLineEdit from urh.ui.RuleExpressionValidator import RuleExpressionValidator @@ -14,7 +23,9 @@ def __init__(self, parent=None): completer.setModel(QDirModel(completer)) self.line_edit_external_program = QLineEdit() self.line_edit_external_program.setCompleter(completer) - self.line_edit_external_program.setPlaceholderText("Type in a path to external program.") + self.line_edit_external_program.setPlaceholderText( + "Type in a path to external program." + ) self.layout = QHBoxLayout() self.layout.setContentsMargins(0, 0, 0, 0) @@ -56,7 +67,9 @@ def __init__(self, controller, parent=None): super().__init__(parent) self.controller = controller - def createEditor(self, parent: QWidget, option: QStyleOptionViewItem, index: QModelIndex): + def createEditor( + self, parent: QWidget, option: QStyleOptionViewItem, index: QModelIndex + ): model = index.model() row = index.row() lbl = model.message_type[row] @@ -64,8 +77,12 @@ def createEditor(self, parent: QWidget, option: QStyleOptionViewItem, index: QMo if lbl.value_type_index == 2: line_edit = ExpressionLineEdit(parent) line_edit.setPlaceholderText("(item1.length + 3) ^ 0x12") - line_edit.setCompleter(QCompleter(self.controller.completer_model, line_edit)) - line_edit.setValidator(RuleExpressionValidator(self.controller.sim_expression_parser)) + line_edit.setCompleter( + QCompleter(self.controller.completer_model, line_edit) + ) + line_edit.setValidator( + RuleExpressionValidator(self.controller.sim_expression_parser) + ) line_edit.setToolTip(self.controller.sim_expression_parser.formula_help) return line_edit elif lbl.value_type_index == 3: @@ -91,10 +108,16 @@ def setEditorData(self, editor: QWidget, index: QModelIndex): else: super().setEditorData(editor, index) - def setModelData(self, editor: QWidget, model: QAbstractItemModel, index: QModelIndex): + def setModelData( + self, editor: QWidget, model: QAbstractItemModel, index: QModelIndex + ): if isinstance(editor, ExternalProgramWidget): model.setData(index, editor.line_edit_external_program.text(), Qt.EditRole) elif isinstance(editor, RandomValueWidget): - model.setData(index, [editor.spinbox_random_min.value(), editor.spinbox_random_max.value()], Qt.EditRole) + model.setData( + index, + [editor.spinbox_random_min.value(), editor.spinbox_random_max.value()], + Qt.EditRole, + ) else: super().setModelData(editor, model, index) diff --git a/src/urh/ui/delegates/SectionComboBoxDelegate.py b/src/urh/ui/delegates/SectionComboBoxDelegate.py index 7e1fe8c8bc..1b658e40c3 100644 --- a/src/urh/ui/delegates/SectionComboBoxDelegate.py +++ b/src/urh/ui/delegates/SectionComboBoxDelegate.py @@ -3,14 +3,23 @@ from PyQt5.QtCore import QModelIndex, pyqtSlot, QAbstractItemModel, Qt from PyQt5.QtGui import QPainter, QStandardItem -from PyQt5.QtWidgets import QItemDelegate, QStyleOptionViewItem, QStyle, QComboBox, QStyledItemDelegate, QWidget +from PyQt5.QtWidgets import ( + QItemDelegate, + QStyleOptionViewItem, + QStyle, + QComboBox, + QStyledItemDelegate, + QWidget, +) class SectionItemDelegate(QItemDelegate): def __init__(self, parent=None): super().__init__(parent) - def paint(self, painter: QPainter, option: QStyleOptionViewItem, index: QModelIndex): + def paint( + self, painter: QPainter, option: QStyleOptionViewItem, index: QModelIndex + ): item_type = index.data(Qt.AccessibleDescriptionRole) if item_type == "parent": parent_option = option @@ -57,7 +66,9 @@ def __init__(self, items: OrderedDict, parent=None): super().__init__(parent) self.items = items - def createEditor(self, parent: QWidget, option: QStyleOptionViewItem, index: QModelIndex): + def createEditor( + self, parent: QWidget, option: QStyleOptionViewItem, index: QModelIndex + ): editor = SectionComboBox(parent) editor.setItemDelegate(SectionItemDelegate(editor.itemDelegate().parent())) if sys.platform == "win32": @@ -77,10 +88,14 @@ def setEditorData(self, editor: SectionComboBox, index: QModelIndex): editor.setCurrentText(item) editor.blockSignals(False) - def setModelData(self, editor: QWidget, model: QAbstractItemModel, index: QModelIndex): + def setModelData( + self, editor: QWidget, model: QAbstractItemModel, index: QModelIndex + ): model.setData(index, editor.currentText(), Qt.EditRole) - def updateEditorGeometry(self, editor: QWidget, option: QStyleOptionViewItem, index: QModelIndex): + def updateEditorGeometry( + self, editor: QWidget, option: QStyleOptionViewItem, index: QModelIndex + ): editor.setGeometry(option.rect) @pyqtSlot() diff --git a/src/urh/ui/delegates/SpinBoxDelegate.py b/src/urh/ui/delegates/SpinBoxDelegate.py index 1bb7437baa..8490cd5062 100644 --- a/src/urh/ui/delegates/SpinBoxDelegate.py +++ b/src/urh/ui/delegates/SpinBoxDelegate.py @@ -12,7 +12,9 @@ def __init__(self, minimum, maximum, parent=None, suffix=""): def _get_editor(self, parent) -> QSpinBox: return QSpinBox(parent) - def createEditor(self, parent: QWidget, option: QStyleOptionViewItem, index: QModelIndex): + def createEditor( + self, parent: QWidget, option: QStyleOptionViewItem, index: QModelIndex + ): editor = self._get_editor(parent) editor.setMinimum(self.minimum) editor.setMaximum(self.maximum) @@ -25,10 +27,12 @@ def setEditorData(self, editor: QWidget, index: QModelIndex): try: editor.setValue(int(index.model().data(index))) except ValueError: - pass # If Label was deleted and UI not updated yet + pass # If Label was deleted and UI not updated yet editor.blockSignals(False) - def setModelData(self, editor: QWidget, model: QAbstractItemModel, index: QModelIndex): + def setModelData( + self, editor: QWidget, model: QAbstractItemModel, index: QModelIndex + ): model.setData(index, editor.value(), Qt.EditRole) @pyqtSlot() diff --git a/src/urh/ui/delegates/__init__.py b/src/urh/ui/delegates/__init__.py index 3fa5af38d8..813939aaf7 100644 --- a/src/urh/ui/delegates/__init__.py +++ b/src/urh/ui/delegates/__init__.py @@ -1 +1 @@ -__author__ = 'joe' +__author__ = "joe" diff --git a/src/urh/ui/painting/FFTSceneManager.py b/src/urh/ui/painting/FFTSceneManager.py index 53831d7864..125c69f518 100644 --- a/src/urh/ui/painting/FFTSceneManager.py +++ b/src/urh/ui/painting/FFTSceneManager.py @@ -16,9 +16,13 @@ def __init__(self, parent, graphic_view=None): self.scene = GridScene(parent=graphic_view) self.scene.setBackgroundBrush(settings.BGCOLOR) - self.peak_item = self.scene.addPath(QPainterPath(), QPen(settings.PEAK_COLOR, 0)) # type: QGraphicsPathItem + self.peak_item = self.scene.addPath( + QPainterPath(), QPen(settings.PEAK_COLOR, 0) + ) # type: QGraphicsPathItem - def show_scene_section(self, x1: float, x2: float, subpath_ranges=None, colors=None): + def show_scene_section( + self, x1: float, x2: float, subpath_ranges=None, colors=None + ): start = int(x1) if x1 > 0 else 0 end = int(x2) if x2 < self.num_samples else self.num_samples paths = path_creator.create_path(np.log10(self.plot_data), start, end) @@ -34,7 +38,11 @@ def show_scene_section(self, x1: float, x2: float, subpath_ranges=None, colors=N def init_scene(self, draw_grid=True): self.scene.draw_grid = draw_grid - self.peak = self.plot_data if len(self.peak) < self.num_samples else np.maximum(self.peak, self.plot_data) + self.peak = ( + self.plot_data + if len(self.peak) < self.num_samples + else np.maximum(self.peak, self.plot_data) + ) self.scene.setSceneRect(0, -5, self.num_samples, 10) def clear_path(self): diff --git a/src/urh/ui/painting/GridScene.py b/src/urh/ui/painting/GridScene.py index 17a8268117..9b4d678b79 100644 --- a/src/urh/ui/painting/GridScene.py +++ b/src/urh/ui/painting/GridScene.py @@ -21,10 +21,18 @@ def __init__(self, parent=None): def drawBackground(self, painter: QPainter, rect: QRectF): if self.draw_grid and len(self.frequencies) > 0: painter.setPen(QPen(painter.pen().color(), 0)) - parent_width = self.parent().width() if hasattr(self.parent(), "width") else 750 - view_rect = self.parent().view_rect() if hasattr(self.parent(), "view_rect") else rect - - font_width = self.font_metrics.width(Formatter.big_value_with_suffix(self.center_freq) + " ") + parent_width = ( + self.parent().width() if hasattr(self.parent(), "width") else 750 + ) + view_rect = ( + self.parent().view_rect() + if hasattr(self.parent(), "view_rect") + else rect + ) + + font_width = self.font_metrics.width( + Formatter.big_value_with_suffix(self.center_freq) + " " + ) x_grid_size = int(view_rect.width() / parent_width * font_width) # x_grid_size = int(0.1 * view_rect.width()) if 0.1 * view_rect.width() > 1 else 1 y_grid_size = 1 @@ -36,14 +44,24 @@ def drawBackground(self, painter: QPainter, rect: QRectF): top = rect.top() - (rect.top() % y_grid_size) bottom = rect.bottom() - (rect.bottom() % y_grid_size) - right_border = int(rect.right()) if rect.right() < len(self.frequencies) else len(self.frequencies) + right_border = ( + int(rect.right()) + if rect.right() < len(self.frequencies) + else len(self.frequencies) + ) scale_x, scale_y = util.calc_x_y_scale(rect, self.parent()) fh = self.font_metrics.height() - x_range = list(range(x_mid, left, -x_grid_size)) + list(range(x_mid, right_border, x_grid_size)) - lines = [QLineF(x, rect.top(), x, bottom-fh*scale_y) for x in x_range] \ - + [QLineF(rect.left(), y, rect.right(), y) for y in np.arange(top, bottom, y_grid_size)] + x_range = list(range(x_mid, left, -x_grid_size)) + list( + range(x_mid, right_border, x_grid_size) + ) + lines = [ + QLineF(x, rect.top(), x, bottom - fh * scale_y) for x in x_range + ] + [ + QLineF(rect.left(), y, rect.right(), y) + for y in np.arange(top, bottom, y_grid_size) + ] pen = painter.pen() pen.setStyle(Qt.DotLine) @@ -63,7 +81,9 @@ def drawBackground(self, painter: QPainter, rect: QRectF): value = Formatter.big_value_with_suffix(self.center_freq + freq, 2) font_width = self.font_metrics.width(value) - painter.drawText(QPointF(x / scale_x - font_width / 2, bottom / scale_y), value) + painter.drawText( + QPointF(x / scale_x - font_width / 2, bottom / scale_y), value + ) def draw_frequency_marker(self, x_pos, frequency): if frequency is None: @@ -86,12 +106,16 @@ def draw_frequency_marker(self, x_pos, frequency): self.frequency_marker[0].setLine(x_pos, y1, x_pos, y2) scale_x, scale_y = util.calc_x_y_scale(self.sceneRect(), self.parent()) - self.frequency_marker[1].setTransform(QTransform.fromScale(scale_x, scale_y), False) - self.frequency_marker[1].setText("Tune to " + Formatter.big_value_with_suffix(frequency, decimals=3)) + self.frequency_marker[1].setTransform( + QTransform.fromScale(scale_x, scale_y), False + ) + self.frequency_marker[1].setText( + "Tune to " + Formatter.big_value_with_suffix(frequency, decimals=3) + ) font_metric = QFontMetrics(self.frequency_marker[1].font()) text_width = font_metric.width("Tune to") * scale_x text_width += (font_metric.width(" ") * scale_x) / 2 - self.frequency_marker[1].setPos(x_pos-text_width, 0.95*y1) + self.frequency_marker[1].setPos(x_pos - text_width, 0.95 * y1) def clear_frequency_marker(self): if self.frequency_marker is not None: @@ -99,7 +123,7 @@ def clear_frequency_marker(self): self.removeItem(self.frequency_marker[1]) self.frequency_marker = None - def get_freq_for_pos(self, x: int) -> float: + def get_freq_for_pos(self, x: int) -> float: try: f = self.frequencies[x] except IndexError: diff --git a/src/urh/ui/painting/LabeledArrow.py b/src/urh/ui/painting/LabeledArrow.py index 79de64160a..68e8b3173c 100644 --- a/src/urh/ui/painting/LabeledArrow.py +++ b/src/urh/ui/painting/LabeledArrow.py @@ -17,11 +17,19 @@ def __init__(self, x1, y1, x2, y2, label): def boundingRect(self): extra = (self.pen().width() + 20) / 2.0 try: - return QRectF(self.line().p1(), QSizeF(self.line().p2().x() - self.line().p1().x(), - self.line().p2().y() - self.line().p1().y())) \ - .normalized().adjusted(-extra, -extra, extra, extra) + return ( + QRectF( + self.line().p1(), + QSizeF( + self.line().p2().x() - self.line().p1().x(), + self.line().p2().y() - self.line().p1().y(), + ), + ) + .normalized() + .adjusted(-extra, -extra, extra, extra) + ) except RuntimeError: - return QRectF(0,0,0,0) + return QRectF(0, 0, 0, 0) def paint(self, painter, QStyleOptionGraphicsItem, QWidget_widget=None): """ @@ -41,12 +49,20 @@ def paint(self, painter, QStyleOptionGraphicsItem, QWidget_widget=None): labelheight = 0.75 * abs(y2 - y1) painter.drawLine(QPointF(x1, y1), QPointF(x1, y1 + labelheight / 2)) - painter.drawLine(QPointF(x1, y1), QPointF(x1 + x_arrowSize / 4, y1 + y_arrowSize / 2)) - painter.drawLine(QPointF(x1, y1), QPointF(x1 - x_arrowSize / 4, y1 + y_arrowSize / 2)) + painter.drawLine( + QPointF(x1, y1), QPointF(x1 + x_arrowSize / 4, y1 + y_arrowSize / 2) + ) + painter.drawLine( + QPointF(x1, y1), QPointF(x1 - x_arrowSize / 4, y1 + y_arrowSize / 2) + ) painter.drawLine(QPointF(x1, y2 - labelheight / 2), QPointF(x1, y2)) - painter.drawLine(QPointF(x1, y2), QPointF(x1 + x_arrowSize / 4, y2 - y_arrowSize / 2)) - painter.drawLine(QPointF(x1, y2), QPointF(x1 - x_arrowSize / 4, y2 - y_arrowSize / 2)) + painter.drawLine( + QPointF(x1, y2), QPointF(x1 + x_arrowSize / 4, y2 - y_arrowSize / 2) + ) + painter.drawLine( + QPointF(x1, y2), QPointF(x1 - x_arrowSize / 4, y2 - y_arrowSize / 2) + ) painter.setRenderHint(QPainter.HighQualityAntialiasing) fm = painter.fontMetrics() @@ -56,11 +72,14 @@ def paint(self, painter, QStyleOptionGraphicsItem, QWidget_widget=None): scale_factor = scale_factor if scale_factor > 0 else 0.0000000000000000001 painter.scale(1, scale_factor) - - # print(y1, y2, pixelsHigh) - painter.drawText(QPointF(x1 - pixelsWide / 2, (1 / scale_factor) * (y1 + y2) / 2 + pixelsHigh / 4), self.label) + painter.drawText( + QPointF( + x1 - pixelsWide / 2, (1 / scale_factor) * (y1 + y2) / 2 + pixelsHigh / 4 + ), + self.label, + ) # painter.drawText(QPointF(x1 - pixelsWide/2, (y1+y2+pixelsHigh)/2), self.label) del painter diff --git a/src/urh/ui/painting/SceneManager.py b/src/urh/ui/painting/SceneManager.py index 2f9c931878..3449574ced 100644 --- a/src/urh/ui/painting/SceneManager.py +++ b/src/urh/ui/painting/SceneManager.py @@ -32,7 +32,9 @@ def num_samples(self): return len(self.plot_data[0]) return len(self.plot_data) - def show_scene_section(self, x1: float, x2: float, subpath_ranges=None, colors=None): + def show_scene_section( + self, x1: float, x2: float, subpath_ranges=None, colors=None + ): """ :param x1: start of section to show :param x2: end of section to show @@ -46,15 +48,28 @@ def show_scene_section(self, x1: float, x2: float, subpath_ranges=None, colors=N if end > start: if isinstance(self.plot_data, list): - paths_i = path_creator.create_path(self.plot_data[0], start=start, end=end, - subpath_ranges=subpath_ranges) - paths_q = path_creator.create_path(self.plot_data[1], start=start, end=end, - subpath_ranges=subpath_ranges) + paths_i = path_creator.create_path( + self.plot_data[0], + start=start, + end=end, + subpath_ranges=subpath_ranges, + ) + paths_q = path_creator.create_path( + self.plot_data[1], + start=start, + end=end, + subpath_ranges=subpath_ranges, + ) self.set_path(paths_i, colors=[settings.LINECOLOR_I] * len(paths_i)) - self.set_path(paths_q, colors=[settings.LINECOLOR_Q] * len(paths_q), run_clear_path=False) + self.set_path( + paths_q, + colors=[settings.LINECOLOR_Q] * len(paths_q), + run_clear_path=False, + ) else: - paths = path_creator.create_path(self.plot_data, start=start, end=end, - subpath_ranges=subpath_ranges) + paths = path_creator.create_path( + self.plot_data, start=start, end=end, subpath_ranges=subpath_ranges + ) self.set_path(paths, colors=colors) def set_path(self, paths: list, colors=None, run_clear_path=True): @@ -63,12 +78,16 @@ def set_path(self, paths: list, colors=None, run_clear_path=True): colors = [settings.LINECOLOR] * len(paths) if colors is None else colors assert len(paths) == len(colors) for path, color in zip(paths, colors): - path_object = self.scene.addPath(path, QPen(color if color else settings.LINECOLOR, 0)) + path_object = self.scene.addPath( + path, QPen(color if color else settings.LINECOLOR, 0) + ) if color: path_object.setZValue(1) def __limit_value(self, val: float) -> int: - return 0 if val < 0 else self.num_samples if val > self.num_samples else int(val) + return ( + 0 if val < 0 else self.num_samples if val > self.num_samples else int(val) + ) def show_full_scene(self): self.show_scene_section(0, self.num_samples) diff --git a/src/urh/ui/painting/Selection.py b/src/urh/ui/painting/Selection.py index de6a92348b..66658d06ee 100644 --- a/src/urh/ui/painting/Selection.py +++ b/src/urh/ui/painting/Selection.py @@ -91,7 +91,9 @@ def end(self): def end(self, value): raise NotImplementedError("Overwrite in subclass") - def _get_selected_edge(self, pos: QPointF, transform: QTransform, horizontal_selection: bool): + def _get_selected_edge( + self, pos: QPointF, transform: QTransform, horizontal_selection: bool + ): x1, x2 = self.x, self.x + self.width y1, y2 = self.y, self.y + self.height x, y = pos.x(), pos.y() diff --git a/src/urh/ui/painting/SignalSceneManager.py b/src/urh/ui/painting/SignalSceneManager.py index d0a312a458..ec9c453144 100644 --- a/src/urh/ui/painting/SignalSceneManager.py +++ b/src/urh/ui/painting/SignalSceneManager.py @@ -8,10 +8,14 @@ class SignalSceneManager(SceneManager): def __init__(self, signal: Signal, parent): super().__init__(parent) self.signal = signal - self.scene_type = 0 # 0 = Analog Signal, 1 = QuadDemodView, 2 = Spectogram, 3 = I/Q view + self.scene_type = ( + 0 # 0 = Analog Signal, 1 = QuadDemodView, 2 = Spectogram, 3 = I/Q view + ) self.mod_type = "ASK" - def show_scene_section(self, x1: float, x2: float, subpath_ranges=None, colors=None): + def show_scene_section( + self, x1: float, x2: float, subpath_ranges=None, colors=None + ): if self.scene_type == 0: self.plot_data = self.signal.real_plot_data elif self.scene_type == 3: @@ -36,7 +40,10 @@ def init_scene(self): self.line_item.setLine(0, 0, 0, 0) # Hide Axis if self.scene_type == 0 or self.scene_type == 3: - self.scene.draw_noise_area(self.signal.noise_min_plot, self.signal.noise_max_plot - self.signal.noise_min_plot) + self.scene.draw_noise_area( + self.signal.noise_min_plot, + self.signal.noise_max_plot - self.signal.noise_min_plot, + ) else: self.scene.draw_sep_area(-self.signal.center_thresholds) diff --git a/src/urh/ui/painting/SniffSceneManager.py b/src/urh/ui/painting/SniffSceneManager.py index 6edee5a853..3bb921c7fd 100644 --- a/src/urh/ui/painting/SniffSceneManager.py +++ b/src/urh/ui/painting/SniffSceneManager.py @@ -12,7 +12,7 @@ def __init__(self, data_array, parent, window_length=5 * 10**6): @property def plot_data(self): - return self.data_array[self.__start:self.end] + return self.data_array[self.__start : self.end] @plot_data.setter def plot_data(self, value): diff --git a/src/urh/ui/painting/SpectrogramScene.py b/src/urh/ui/painting/SpectrogramScene.py index 721b622d52..6692f69523 100644 --- a/src/urh/ui/painting/SpectrogramScene.py +++ b/src/urh/ui/painting/SpectrogramScene.py @@ -8,7 +8,9 @@ def __init__(self, parent=None): super().__init__(parent) self.removeItem(self.selection_area) - self.selection_area = VerticalSelection(0, 0, 0, 0, fillcolor=settings.SELECTION_COLOR, opacity=0.6) + self.selection_area = VerticalSelection( + 0, 0, 0, 0, fillcolor=settings.SELECTION_COLOR, opacity=0.6 + ) self.selection_area.setZValue(1) self.addItem(self.selection_area) diff --git a/src/urh/ui/painting/SpectrogramSceneManager.py b/src/urh/ui/painting/SpectrogramSceneManager.py index ff477d2412..bf6c63ddbf 100644 --- a/src/urh/ui/painting/SpectrogramSceneManager.py +++ b/src/urh/ui/painting/SpectrogramSceneManager.py @@ -21,7 +21,9 @@ def __init__(self, samples, parent): def num_samples(self): return len(self.spectrogram.samples) - def set_parameters(self, samples: np.ndarray, window_size, data_min, data_max) -> bool: + def set_parameters( + self, samples: np.ndarray, window_size, data_min, data_max + ) -> bool: """ Return true if redraw is needed """ @@ -45,11 +47,15 @@ def set_parameters(self, samples: np.ndarray, window_size, data_min, data_max) - return redraw_needed - def show_scene_section(self, x1: float, x2: float, subpath_ranges=None, colors=None): + def show_scene_section( + self, x1: float, x2: float, subpath_ranges=None, colors=None + ): pass def update_scene_rect(self): - self.scene.setSceneRect(0, 0, self.spectrogram.time_bins, self.spectrogram.freq_bins) + self.scene.setSceneRect( + 0, 0, self.spectrogram.time_bins, self.spectrogram.freq_bins + ) def show_full_scene(self): for item in self.scene.items(): diff --git a/src/urh/ui/painting/ZoomableScene.py b/src/urh/ui/painting/ZoomableScene.py index 3dbbe39116..b398f9b3e7 100644 --- a/src/urh/ui/painting/ZoomableScene.py +++ b/src/urh/ui/painting/ZoomableScene.py @@ -3,7 +3,12 @@ import numpy as np from PyQt5.QtCore import QRectF from PyQt5.QtGui import QPen, QFont, QTransform, QFontMetrics -from PyQt5.QtWidgets import QGraphicsScene, QGraphicsRectItem, QGraphicsSceneDragDropEvent, QGraphicsSimpleTextItem +from PyQt5.QtWidgets import ( + QGraphicsScene, + QGraphicsRectItem, + QGraphicsSceneDragDropEvent, + QGraphicsSimpleTextItem, +) from urh import settings from urh.ui.painting.HorizontalSelection import HorizontalSelection @@ -27,8 +32,14 @@ def __init__(self, parent=None): self.ones_arrow = None self.zeros_arrow = None - self.selection_area = HorizontalSelection(0, 0, 0, 0, fillcolor=settings.SELECTION_COLOR, - opacity=settings.SELECTION_OPACITY) + self.selection_area = HorizontalSelection( + 0, + 0, + 0, + 0, + fillcolor=settings.SELECTION_COLOR, + opacity=settings.SELECTION_OPACITY, + ) self.addItem(self.selection_area) @property @@ -43,7 +54,14 @@ def draw_noise_area(self, y, h): area.hide() if self.noise_area is None or self.noise_area.scene() != self: - roi = HorizontalSelection(x, y, w, h, fillcolor=settings.NOISE_COLOR, opacity=settings.NOISE_OPACITY) + roi = HorizontalSelection( + x, + y, + w, + h, + fillcolor=settings.NOISE_COLOR, + opacity=settings.NOISE_OPACITY, + ) self.noise_area = roi self.addItem(self.noise_area) else: @@ -82,13 +100,23 @@ def redraw_legend(self, force_show=False): for i, caption in enumerate(self.captions): caption.show() - scale_x, scale_y = util.calc_x_y_scale(self.separation_areas[i].rect(), self.parent()) + scale_x, scale_y = util.calc_x_y_scale( + self.separation_areas[i].rect(), self.parent() + ) try: - caption.setPos(view_rect.x() + view_rect.width() - fm.width(caption.text()) * scale_x, - self.centers[i] + padding) + caption.setPos( + view_rect.x() + + view_rect.width() + - fm.width(caption.text()) * scale_x, + self.centers[i] + padding, + ) except IndexError: - caption.setPos(view_rect.x() + view_rect.width() - fm.width(caption.text()) * scale_x, - self.centers[i - 1] - padding - fm.height() * scale_y) + caption.setPos( + view_rect.x() + + view_rect.width() + - fm.width(caption.text()) * scale_x, + self.centers[i - 1] - padding - fm.height() * scale_y, + ) caption.setTransform(QTransform.fromScale(scale_x, scale_y), False) @@ -121,7 +149,9 @@ def draw_sep_area(self, centers: np.ndarray, show_symbols=False): for i, area in enumerate(self.separation_areas): area.show() try: - self.separation_areas[i].setRect(x, start, w, abs(start - reversed_centers[i])) + self.separation_areas[i].setRect( + x, start, w, abs(start - reversed_centers[i]) + ) start += abs(start - reversed_centers[i]) except IndexError: self.separation_areas[i].setRect(x, start, w, abs(start - h)) diff --git a/src/urh/ui/ui_advanced_modulation_settings.py b/src/urh/ui/ui_advanced_modulation_settings.py index 33df15565d..388ad581f1 100644 --- a/src/urh/ui/ui_advanced_modulation_settings.py +++ b/src/urh/ui/ui_advanced_modulation_settings.py @@ -43,11 +43,15 @@ def setupUi(self, DialogAdvancedModSettings): self.spinBoxMessageLengthDivisor.setObjectName("spinBoxMessageLengthDivisor") self.verticalLayout_2.addWidget(self.spinBoxMessageLengthDivisor) self.verticalLayout_3.addWidget(self.groupBox_2) - spacerItem = QtWidgets.QSpacerItem(20, 40, QtWidgets.QSizePolicy.Minimum, QtWidgets.QSizePolicy.Expanding) + spacerItem = QtWidgets.QSpacerItem( + 20, 40, QtWidgets.QSizePolicy.Minimum, QtWidgets.QSizePolicy.Expanding + ) self.verticalLayout_3.addItem(spacerItem) self.buttonBox = QtWidgets.QDialogButtonBox(DialogAdvancedModSettings) self.buttonBox.setOrientation(QtCore.Qt.Horizontal) - self.buttonBox.setStandardButtons(QtWidgets.QDialogButtonBox.Cancel|QtWidgets.QDialogButtonBox.Ok) + self.buttonBox.setStandardButtons( + QtWidgets.QDialogButtonBox.Cancel | QtWidgets.QDialogButtonBox.Ok + ) self.buttonBox.setObjectName("buttonBox") self.verticalLayout_3.addWidget(self.buttonBox) @@ -57,9 +61,27 @@ def setupUi(self, DialogAdvancedModSettings): def retranslateUi(self, DialogAdvancedModSettings): _translate = QtCore.QCoreApplication.translate - DialogAdvancedModSettings.setWindowTitle(_translate("DialogAdvancedModSettings", "Advanced Modulation Settings")) - self.groupBox.setTitle(_translate("DialogAdvancedModSettings", "Pause Threshold")) - self.label.setText(_translate("DialogAdvancedModSettings", "

The pause threshold gives you control when to insert a message break.

The pause threshold is the maximum length of consecutive zero bits represented by a pause before a new message begins.

Special value is 0 to disable message breaking completely.

")) - self.spinBoxPauseThreshold.setSpecialValueText(_translate("DialogAdvancedModSettings", "Disable")) - self.groupBox_2.setTitle(_translate("DialogAdvancedModSettings", "Message Length Divisor")) - self.label_2.setText(_translate("DialogAdvancedModSettings", "

With the message divisor length you can control the minimum message length in a flexible way. URH will try to demodulate signals in such a way, that the resulting message has a number of bits that is divisble by the configured divisor.

How does the zero padding work? Remaining zero bits are taken from the pause behind the message if possible.

")) + DialogAdvancedModSettings.setWindowTitle( + _translate("DialogAdvancedModSettings", "Advanced Modulation Settings") + ) + self.groupBox.setTitle( + _translate("DialogAdvancedModSettings", "Pause Threshold") + ) + self.label.setText( + _translate( + "DialogAdvancedModSettings", + '

The pause threshold gives you control when to insert a message break.

The pause threshold is the maximum length of consecutive zero bits represented by a pause before a new message begins.

Special value is 0 to disable message breaking completely.

', + ) + ) + self.spinBoxPauseThreshold.setSpecialValueText( + _translate("DialogAdvancedModSettings", "Disable") + ) + self.groupBox_2.setTitle( + _translate("DialogAdvancedModSettings", "Message Length Divisor") + ) + self.label_2.setText( + _translate( + "DialogAdvancedModSettings", + '

With the message divisor length you can control the minimum message length in a flexible way. URH will try to demodulate signals in such a way, that the resulting message has a number of bits that is divisble by the configured divisor.

How does the zero padding work? Remaining zero bits are taken from the pause behind the message if possible.

', + ) + ) diff --git a/src/urh/ui/ui_analysis.py b/src/urh/ui/ui_analysis.py index 95282290fa..2d1c58347b 100644 --- a/src/urh/ui/ui_analysis.py +++ b/src/urh/ui/ui_analysis.py @@ -12,7 +12,9 @@ class Ui_TabAnalysis(object): def setupUi(self, TabAnalysis): TabAnalysis.setObjectName("TabAnalysis") TabAnalysis.resize(1331, 739) - sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Preferred, QtWidgets.QSizePolicy.Preferred) + sizePolicy = QtWidgets.QSizePolicy( + QtWidgets.QSizePolicy.Preferred, QtWidgets.QSizePolicy.Preferred + ) sizePolicy.setHorizontalStretch(0) sizePolicy.setVerticalStretch(0) sizePolicy.setHeightForWidth(TabAnalysis.sizePolicy().hasHeightForWidth()) @@ -37,26 +39,30 @@ def setupUi(self, TabAnalysis): self.verticalLayout_5 = QtWidgets.QVBoxLayout(self.scrollAreaWidgetContents) self.verticalLayout_5.setObjectName("verticalLayout_5") self.splitter_2 = QtWidgets.QSplitter(self.scrollAreaWidgetContents) - self.splitter_2.setStyleSheet("QSplitter::handle:vertical {\n" -"margin: 4px 0px;\n" -" background-color: qlineargradient(x1:0, y1:0, x2:1, y2:0, \n" -"stop:0 rgba(255, 255, 255, 0), \n" -"stop:0.5 rgba(100, 100, 100, 100), \n" -"stop:1 rgba(255, 255, 255, 0));\n" -"image: url(:/icons/icons/splitter_handle_horizontal.svg);\n" -"}") + self.splitter_2.setStyleSheet( + "QSplitter::handle:vertical {\n" + "margin: 4px 0px;\n" + " background-color: qlineargradient(x1:0, y1:0, x2:1, y2:0, \n" + "stop:0 rgba(255, 255, 255, 0), \n" + "stop:0.5 rgba(100, 100, 100, 100), \n" + "stop:1 rgba(255, 255, 255, 0));\n" + "image: url(:/icons/icons/splitter_handle_horizontal.svg);\n" + "}" + ) self.splitter_2.setOrientation(QtCore.Qt.Vertical) self.splitter_2.setHandleWidth(6) self.splitter_2.setObjectName("splitter_2") self.splitter = QtWidgets.QSplitter(self.splitter_2) - self.splitter.setStyleSheet("QSplitter::handle:horizontal {\n" -"margin: 4px 0px;\n" -" background-color: qlineargradient(x1:0, y1:0, x2:0, y2:1, \n" -"stop:0 rgba(255, 255, 255, 0), \n" -"stop:0.5 rgba(100, 100, 100, 100), \n" -"stop:1 rgba(255, 255, 255, 0));\n" -"image: url(:/icons/icons/splitter_handle_vertical.svg);\n" -"}") + self.splitter.setStyleSheet( + "QSplitter::handle:horizontal {\n" + "margin: 4px 0px;\n" + " background-color: qlineargradient(x1:0, y1:0, x2:0, y2:1, \n" + "stop:0 rgba(255, 255, 255, 0), \n" + "stop:0.5 rgba(100, 100, 100, 100), \n" + "stop:1 rgba(255, 255, 255, 0));\n" + "image: url(:/icons/icons/splitter_handle_vertical.svg);\n" + "}" + ) self.splitter.setOrientation(QtCore.Qt.Horizontal) self.splitter.setHandleWidth(6) self.splitter.setObjectName("splitter") @@ -75,10 +81,14 @@ def setupUi(self, TabAnalysis): self.verticalLayout_3.setSpacing(7) self.verticalLayout_3.setObjectName("verticalLayout_3") self.treeViewProtocols = ProtocolTreeView(self.tab_protocols) - sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Minimum, QtWidgets.QSizePolicy.Expanding) + sizePolicy = QtWidgets.QSizePolicy( + QtWidgets.QSizePolicy.Minimum, QtWidgets.QSizePolicy.Expanding + ) sizePolicy.setHorizontalStretch(0) sizePolicy.setVerticalStretch(0) - sizePolicy.setHeightForWidth(self.treeViewProtocols.sizePolicy().hasHeightForWidth()) + sizePolicy.setHeightForWidth( + self.treeViewProtocols.sizePolicy().hasHeightForWidth() + ) self.treeViewProtocols.setSizePolicy(sizePolicy) self.treeViewProtocols.setAcceptDrops(True) self.treeViewProtocols.setFrameShape(QtWidgets.QFrame.StyledPanel) @@ -88,8 +98,12 @@ def setupUi(self, TabAnalysis): self.treeViewProtocols.setDragDropOverwriteMode(False) self.treeViewProtocols.setDragDropMode(QtWidgets.QAbstractItemView.DragDrop) self.treeViewProtocols.setDefaultDropAction(QtCore.Qt.IgnoreAction) - self.treeViewProtocols.setSelectionMode(QtWidgets.QAbstractItemView.SingleSelection) - self.treeViewProtocols.setSelectionBehavior(QtWidgets.QAbstractItemView.SelectRows) + self.treeViewProtocols.setSelectionMode( + QtWidgets.QAbstractItemView.SingleSelection + ) + self.treeViewProtocols.setSelectionBehavior( + QtWidgets.QAbstractItemView.SelectRows + ) self.treeViewProtocols.setTextElideMode(QtCore.Qt.ElideRight) self.treeViewProtocols.setAnimated(True) self.treeViewProtocols.setObjectName("treeViewProtocols") @@ -104,10 +118,14 @@ def setupUi(self, TabAnalysis): self.verticalLayout_11.setContentsMargins(0, 0, 0, 0) self.verticalLayout_11.setObjectName("verticalLayout_11") self.listViewParticipants = QtWidgets.QListView(self.tab_participants) - sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Preferred, QtWidgets.QSizePolicy.Expanding) + sizePolicy = QtWidgets.QSizePolicy( + QtWidgets.QSizePolicy.Preferred, QtWidgets.QSizePolicy.Expanding + ) sizePolicy.setHorizontalStretch(0) sizePolicy.setVerticalStretch(0) - sizePolicy.setHeightForWidth(self.listViewParticipants.sizePolicy().hasHeightForWidth()) + sizePolicy.setHeightForWidth( + self.listViewParticipants.sizePolicy().hasHeightForWidth() + ) self.listViewParticipants.setSizePolicy(sizePolicy) self.listViewParticipants.setFrameShape(QtWidgets.QFrame.StyledPanel) self.listViewParticipants.setTextElideMode(QtCore.Qt.ElideRight) @@ -124,15 +142,21 @@ def setupUi(self, TabAnalysis): self.label_4.setObjectName("label_4") self.gridLayout_3.addWidget(self.label_4, 0, 0, 1, 1) self.lEncodingErrors = QtWidgets.QLabel(self.layoutWidget) - sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Preferred, QtWidgets.QSizePolicy.Preferred) + sizePolicy = QtWidgets.QSizePolicy( + QtWidgets.QSizePolicy.Preferred, QtWidgets.QSizePolicy.Preferred + ) sizePolicy.setHorizontalStretch(0) sizePolicy.setVerticalStretch(0) - sizePolicy.setHeightForWidth(self.lEncodingErrors.sizePolicy().hasHeightForWidth()) + sizePolicy.setHeightForWidth( + self.lEncodingErrors.sizePolicy().hasHeightForWidth() + ) self.lEncodingErrors.setSizePolicy(sizePolicy) self.lEncodingErrors.setObjectName("lEncodingErrors") self.gridLayout_3.addWidget(self.lEncodingErrors, 2, 0, 1, 1) self.cbDecoding = QtWidgets.QComboBox(self.layoutWidget) - sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Preferred, QtWidgets.QSizePolicy.Fixed) + sizePolicy = QtWidgets.QSizePolicy( + QtWidgets.QSizePolicy.Preferred, QtWidgets.QSizePolicy.Fixed + ) sizePolicy.setHorizontalStretch(0) sizePolicy.setVerticalStretch(0) sizePolicy.setHeightForWidth(self.cbDecoding.sizePolicy().hasHeightForWidth()) @@ -146,15 +170,21 @@ def setupUi(self, TabAnalysis): self.cbDecoding.addItem("") self.gridLayout_3.addWidget(self.cbDecoding, 1, 1, 1, 1) self.chkBoxShowOnlyDiffs = QtWidgets.QCheckBox(self.layoutWidget) - sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Preferred, QtWidgets.QSizePolicy.Fixed) + sizePolicy = QtWidgets.QSizePolicy( + QtWidgets.QSizePolicy.Preferred, QtWidgets.QSizePolicy.Fixed + ) sizePolicy.setHorizontalStretch(0) sizePolicy.setVerticalStretch(0) - sizePolicy.setHeightForWidth(self.chkBoxShowOnlyDiffs.sizePolicy().hasHeightForWidth()) + sizePolicy.setHeightForWidth( + self.chkBoxShowOnlyDiffs.sizePolicy().hasHeightForWidth() + ) self.chkBoxShowOnlyDiffs.setSizePolicy(sizePolicy) self.chkBoxShowOnlyDiffs.setObjectName("chkBoxShowOnlyDiffs") self.gridLayout_3.addWidget(self.chkBoxShowOnlyDiffs, 4, 0, 1, 2) self.cbProtoView = QtWidgets.QComboBox(self.layoutWidget) - sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Preferred, QtWidgets.QSizePolicy.Fixed) + sizePolicy = QtWidgets.QSizePolicy( + QtWidgets.QSizePolicy.Preferred, QtWidgets.QSizePolicy.Fixed + ) sizePolicy.setHorizontalStretch(0) sizePolicy.setVerticalStretch(0) sizePolicy.setHeightForWidth(self.cbProtoView.sizePolicy().hasHeightForWidth()) @@ -165,23 +195,35 @@ def setupUi(self, TabAnalysis): self.cbProtoView.addItem("") self.gridLayout_3.addWidget(self.cbProtoView, 0, 1, 1, 1) self.lDecodingErrorsValue = QtWidgets.QLabel(self.layoutWidget) - sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Preferred, QtWidgets.QSizePolicy.Fixed) + sizePolicy = QtWidgets.QSizePolicy( + QtWidgets.QSizePolicy.Preferred, QtWidgets.QSizePolicy.Fixed + ) sizePolicy.setHorizontalStretch(0) sizePolicy.setVerticalStretch(0) - sizePolicy.setHeightForWidth(self.lDecodingErrorsValue.sizePolicy().hasHeightForWidth()) + sizePolicy.setHeightForWidth( + self.lDecodingErrorsValue.sizePolicy().hasHeightForWidth() + ) self.lDecodingErrorsValue.setSizePolicy(sizePolicy) self.lDecodingErrorsValue.setObjectName("lDecodingErrorsValue") self.gridLayout_3.addWidget(self.lDecodingErrorsValue, 2, 1, 1, 1) self.chkBoxOnlyShowLabelsInProtocol = QtWidgets.QCheckBox(self.layoutWidget) - sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Preferred, QtWidgets.QSizePolicy.Fixed) + sizePolicy = QtWidgets.QSizePolicy( + QtWidgets.QSizePolicy.Preferred, QtWidgets.QSizePolicy.Fixed + ) sizePolicy.setHorizontalStretch(0) sizePolicy.setVerticalStretch(0) - sizePolicy.setHeightForWidth(self.chkBoxOnlyShowLabelsInProtocol.sizePolicy().hasHeightForWidth()) + sizePolicy.setHeightForWidth( + self.chkBoxOnlyShowLabelsInProtocol.sizePolicy().hasHeightForWidth() + ) self.chkBoxOnlyShowLabelsInProtocol.setSizePolicy(sizePolicy) - self.chkBoxOnlyShowLabelsInProtocol.setObjectName("chkBoxOnlyShowLabelsInProtocol") + self.chkBoxOnlyShowLabelsInProtocol.setObjectName( + "chkBoxOnlyShowLabelsInProtocol" + ) self.gridLayout_3.addWidget(self.chkBoxOnlyShowLabelsInProtocol, 5, 0, 1, 2) self.cbShowDiffs = QtWidgets.QCheckBox(self.layoutWidget) - sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Preferred, QtWidgets.QSizePolicy.Fixed) + sizePolicy = QtWidgets.QSizePolicy( + QtWidgets.QSizePolicy.Preferred, QtWidgets.QSizePolicy.Fixed + ) sizePolicy.setHorizontalStretch(0) sizePolicy.setVerticalStretch(0) sizePolicy.setHeightForWidth(self.cbShowDiffs.sizePolicy().hasHeightForWidth()) @@ -189,10 +231,14 @@ def setupUi(self, TabAnalysis): self.cbShowDiffs.setObjectName("cbShowDiffs") self.gridLayout_3.addWidget(self.cbShowDiffs, 3, 0, 1, 2) self.stackedWidgetLogicAnalysis = QtWidgets.QStackedWidget(self.layoutWidget) - sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Preferred, QtWidgets.QSizePolicy.Maximum) + sizePolicy = QtWidgets.QSizePolicy( + QtWidgets.QSizePolicy.Preferred, QtWidgets.QSizePolicy.Maximum + ) sizePolicy.setHorizontalStretch(0) sizePolicy.setVerticalStretch(0) - sizePolicy.setHeightForWidth(self.stackedWidgetLogicAnalysis.sizePolicy().hasHeightForWidth()) + sizePolicy.setHeightForWidth( + self.stackedWidgetLogicAnalysis.sizePolicy().hasHeightForWidth() + ) self.stackedWidgetLogicAnalysis.setSizePolicy(sizePolicy) self.stackedWidgetLogicAnalysis.setObjectName("stackedWidgetLogicAnalysis") self.pageButtonAnalyzer = QtWidgets.QWidget() @@ -202,7 +248,9 @@ def setupUi(self, TabAnalysis): self.verticalLayout_8.setSpacing(0) self.verticalLayout_8.setObjectName("verticalLayout_8") self.btnAnalyze = QtWidgets.QToolButton(self.pageButtonAnalyzer) - sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Preferred, QtWidgets.QSizePolicy.Fixed) + sizePolicy = QtWidgets.QSizePolicy( + QtWidgets.QSizePolicy.Preferred, QtWidgets.QSizePolicy.Fixed + ) sizePolicy.setHorizontalStretch(0) sizePolicy.setVerticalStretch(0) sizePolicy.setHeightForWidth(self.btnAnalyze.sizePolicy().hasHeightForWidth()) @@ -219,10 +267,14 @@ def setupUi(self, TabAnalysis): self.verticalLayout_9.setSpacing(0) self.verticalLayout_9.setObjectName("verticalLayout_9") self.progressBarLogicAnalyzer = QtWidgets.QProgressBar(self.pageProgressBar) - sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Preferred, QtWidgets.QSizePolicy.Fixed) + sizePolicy = QtWidgets.QSizePolicy( + QtWidgets.QSizePolicy.Preferred, QtWidgets.QSizePolicy.Fixed + ) sizePolicy.setHorizontalStretch(0) sizePolicy.setVerticalStretch(0) - sizePolicy.setHeightForWidth(self.progressBarLogicAnalyzer.sizePolicy().hasHeightForWidth()) + sizePolicy.setHeightForWidth( + self.progressBarLogicAnalyzer.sizePolicy().hasHeightForWidth() + ) self.progressBarLogicAnalyzer.setSizePolicy(sizePolicy) self.progressBarLogicAnalyzer.setProperty("value", 24) self.progressBarLogicAnalyzer.setObjectName("progressBarLogicAnalyzer") @@ -238,7 +290,9 @@ def setupUi(self, TabAnalysis): self.gridLayout_2 = QtWidgets.QGridLayout() self.gridLayout_2.setObjectName("gridLayout_2") self.btnSaveProto = QtWidgets.QToolButton(self.layoutWidget1) - sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Fixed, QtWidgets.QSizePolicy.Preferred) + sizePolicy = QtWidgets.QSizePolicy( + QtWidgets.QSizePolicy.Fixed, QtWidgets.QSizePolicy.Preferred + ) sizePolicy.setHorizontalStretch(0) sizePolicy.setVerticalStretch(0) sizePolicy.setHeightForWidth(self.btnSaveProto.sizePolicy().hasHeightForWidth()) @@ -251,7 +305,9 @@ def setupUi(self, TabAnalysis): self.btnSaveProto.setObjectName("btnSaveProto") self.gridLayout_2.addWidget(self.btnSaveProto, 0, 16, 1, 1) self.lSlash = QtWidgets.QLabel(self.layoutWidget1) - sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Preferred, QtWidgets.QSizePolicy.Preferred) + sizePolicy = QtWidgets.QSizePolicy( + QtWidgets.QSizePolicy.Preferred, QtWidgets.QSizePolicy.Preferred + ) sizePolicy.setHorizontalStretch(0) sizePolicy.setVerticalStretch(0) sizePolicy.setHeightForWidth(self.lSlash.sizePolicy().hasHeightForWidth()) @@ -263,29 +319,38 @@ def setupUi(self, TabAnalysis): self.lblShownRows.setObjectName("lblShownRows") self.gridLayout_2.addWidget(self.lblShownRows, 0, 4, 1, 1) self.lTime = QtWidgets.QLabel(self.layoutWidget1) - sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Expanding, QtWidgets.QSizePolicy.Preferred) + sizePolicy = QtWidgets.QSizePolicy( + QtWidgets.QSizePolicy.Expanding, QtWidgets.QSizePolicy.Preferred + ) sizePolicy.setHorizontalStretch(0) sizePolicy.setVerticalStretch(0) sizePolicy.setHeightForWidth(self.lTime.sizePolicy().hasHeightForWidth()) self.lTime.setSizePolicy(sizePolicy) self.lTime.setTextFormat(QtCore.Qt.PlainText) - self.lTime.setAlignment(QtCore.Qt.AlignLeading|QtCore.Qt.AlignLeft|QtCore.Qt.AlignVCenter) + self.lTime.setAlignment( + QtCore.Qt.AlignLeading | QtCore.Qt.AlignLeft | QtCore.Qt.AlignVCenter + ) self.lTime.setObjectName("lTime") self.gridLayout_2.addWidget(self.lTime, 0, 15, 1, 1) self.lSearchCurrent = QtWidgets.QLabel(self.layoutWidget1) - sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Preferred, QtWidgets.QSizePolicy.Preferred) + sizePolicy = QtWidgets.QSizePolicy( + QtWidgets.QSizePolicy.Preferred, QtWidgets.QSizePolicy.Preferred + ) sizePolicy.setHorizontalStretch(0) sizePolicy.setVerticalStretch(0) - sizePolicy.setHeightForWidth(self.lSearchCurrent.sizePolicy().hasHeightForWidth()) + sizePolicy.setHeightForWidth( + self.lSearchCurrent.sizePolicy().hasHeightForWidth() + ) self.lSearchCurrent.setSizePolicy(sizePolicy) - self.lSearchCurrent.setStyleSheet("QLabel\n" -"{\n" -" qproperty-alignment: AlignCenter;\n" -"}") + self.lSearchCurrent.setStyleSheet( + "QLabel\n" "{\n" " qproperty-alignment: AlignCenter;\n" "}" + ) self.lSearchCurrent.setObjectName("lSearchCurrent") self.gridLayout_2.addWidget(self.lSearchCurrent, 0, 6, 1, 1) self.lblRSSI = QtWidgets.QLabel(self.layoutWidget1) - sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Expanding, QtWidgets.QSizePolicy.Preferred) + sizePolicy = QtWidgets.QSizePolicy( + QtWidgets.QSizePolicy.Expanding, QtWidgets.QSizePolicy.Preferred + ) sizePolicy.setHorizontalStretch(0) sizePolicy.setVerticalStretch(0) sizePolicy.setHeightForWidth(self.lblRSSI.sizePolicy().hasHeightForWidth()) @@ -294,10 +359,14 @@ def setupUi(self, TabAnalysis): self.gridLayout_2.addWidget(self.lblRSSI, 0, 12, 1, 1) self.btnNextSearch = QtWidgets.QToolButton(self.layoutWidget1) self.btnNextSearch.setEnabled(False) - sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Preferred, QtWidgets.QSizePolicy.Preferred) + sizePolicy = QtWidgets.QSizePolicy( + QtWidgets.QSizePolicy.Preferred, QtWidgets.QSizePolicy.Preferred + ) sizePolicy.setHorizontalStretch(0) sizePolicy.setVerticalStretch(0) - sizePolicy.setHeightForWidth(self.btnNextSearch.sizePolicy().hasHeightForWidth()) + sizePolicy.setHeightForWidth( + self.btnNextSearch.sizePolicy().hasHeightForWidth() + ) self.btnNextSearch.setSizePolicy(sizePolicy) icon = QtGui.QIcon.fromTheme("go-next") self.btnNextSearch.setIcon(icon) @@ -305,29 +374,36 @@ def setupUi(self, TabAnalysis): self.gridLayout_2.addWidget(self.btnNextSearch, 0, 9, 1, 1) self.btnPrevSearch = QtWidgets.QToolButton(self.layoutWidget1) self.btnPrevSearch.setEnabled(False) - sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Preferred, QtWidgets.QSizePolicy.Preferred) + sizePolicy = QtWidgets.QSizePolicy( + QtWidgets.QSizePolicy.Preferred, QtWidgets.QSizePolicy.Preferred + ) sizePolicy.setHorizontalStretch(0) sizePolicy.setVerticalStretch(0) - sizePolicy.setHeightForWidth(self.btnPrevSearch.sizePolicy().hasHeightForWidth()) + sizePolicy.setHeightForWidth( + self.btnPrevSearch.sizePolicy().hasHeightForWidth() + ) self.btnPrevSearch.setSizePolicy(sizePolicy) icon = QtGui.QIcon.fromTheme("go-previous") self.btnPrevSearch.setIcon(icon) self.btnPrevSearch.setObjectName("btnPrevSearch") self.gridLayout_2.addWidget(self.btnPrevSearch, 0, 5, 1, 1) self.lSearchTotal = QtWidgets.QLabel(self.layoutWidget1) - sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Preferred, QtWidgets.QSizePolicy.Preferred) + sizePolicy = QtWidgets.QSizePolicy( + QtWidgets.QSizePolicy.Preferred, QtWidgets.QSizePolicy.Preferred + ) sizePolicy.setHorizontalStretch(0) sizePolicy.setVerticalStretch(0) sizePolicy.setHeightForWidth(self.lSearchTotal.sizePolicy().hasHeightForWidth()) self.lSearchTotal.setSizePolicy(sizePolicy) - self.lSearchTotal.setStyleSheet("QLabel\n" -"{\n" -" qproperty-alignment: AlignCenter;\n" -"}") + self.lSearchTotal.setStyleSheet( + "QLabel\n" "{\n" " qproperty-alignment: AlignCenter;\n" "}" + ) self.lSearchTotal.setObjectName("lSearchTotal") self.gridLayout_2.addWidget(self.lSearchTotal, 0, 8, 1, 1) self.label_3 = QtWidgets.QLabel(self.layoutWidget1) - self.label_3.setAlignment(QtCore.Qt.AlignRight|QtCore.Qt.AlignTrailing|QtCore.Qt.AlignVCenter) + self.label_3.setAlignment( + QtCore.Qt.AlignRight | QtCore.Qt.AlignTrailing | QtCore.Qt.AlignVCenter + ) self.label_3.setObjectName("label_3") self.gridLayout_2.addWidget(self.label_3, 0, 14, 1, 1) self.line_2 = QtWidgets.QFrame(self.layoutWidget1) @@ -336,20 +412,28 @@ def setupUi(self, TabAnalysis): self.line_2.setObjectName("line_2") self.gridLayout_2.addWidget(self.line_2, 0, 13, 1, 1) self.btnSearchSelectFilter = QtWidgets.QToolButton(self.layoutWidget1) - sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Preferred, QtWidgets.QSizePolicy.Preferred) + sizePolicy = QtWidgets.QSizePolicy( + QtWidgets.QSizePolicy.Preferred, QtWidgets.QSizePolicy.Preferred + ) sizePolicy.setHorizontalStretch(0) sizePolicy.setVerticalStretch(0) - sizePolicy.setHeightForWidth(self.btnSearchSelectFilter.sizePolicy().hasHeightForWidth()) + sizePolicy.setHeightForWidth( + self.btnSearchSelectFilter.sizePolicy().hasHeightForWidth() + ) self.btnSearchSelectFilter.setSizePolicy(sizePolicy) icon = QtGui.QIcon.fromTheme("edit-find") self.btnSearchSelectFilter.setIcon(icon) self.btnSearchSelectFilter.setPopupMode(QtWidgets.QToolButton.MenuButtonPopup) - self.btnSearchSelectFilter.setToolButtonStyle(QtCore.Qt.ToolButtonTextBesideIcon) + self.btnSearchSelectFilter.setToolButtonStyle( + QtCore.Qt.ToolButtonTextBesideIcon + ) self.btnSearchSelectFilter.setAutoRaise(False) self.btnSearchSelectFilter.setArrowType(QtCore.Qt.NoArrow) self.btnSearchSelectFilter.setObjectName("btnSearchSelectFilter") self.gridLayout_2.addWidget(self.btnSearchSelectFilter, 0, 2, 1, 1) - spacerItem = QtWidgets.QSpacerItem(60, 0, QtWidgets.QSizePolicy.Expanding, QtWidgets.QSizePolicy.Minimum) + spacerItem = QtWidgets.QSpacerItem( + 60, 0, QtWidgets.QSizePolicy.Expanding, QtWidgets.QSizePolicy.Minimum + ) self.gridLayout_2.addItem(spacerItem, 0, 10, 1, 1) self.line = QtWidgets.QFrame(self.layoutWidget1) self.line.setFrameShape(QtWidgets.QFrame.VLine) @@ -357,7 +441,9 @@ def setupUi(self, TabAnalysis): self.line.setObjectName("line") self.gridLayout_2.addWidget(self.line, 0, 11, 1, 1) self.btnLoadProto = QtWidgets.QToolButton(self.layoutWidget1) - sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Fixed, QtWidgets.QSizePolicy.Preferred) + sizePolicy = QtWidgets.QSizePolicy( + QtWidgets.QSizePolicy.Fixed, QtWidgets.QSizePolicy.Preferred + ) sizePolicy.setHorizontalStretch(0) sizePolicy.setVerticalStretch(0) sizePolicy.setHeightForWidth(self.btnLoadProto.sizePolicy().hasHeightForWidth()) @@ -370,10 +456,14 @@ def setupUi(self, TabAnalysis): self.lblClearAlignment.setObjectName("lblClearAlignment") self.gridLayout_2.addWidget(self.lblClearAlignment, 0, 3, 1, 1) self.lineEditSearch = QtWidgets.QLineEdit(self.layoutWidget1) - sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Expanding, QtWidgets.QSizePolicy.Preferred) + sizePolicy = QtWidgets.QSizePolicy( + QtWidgets.QSizePolicy.Expanding, QtWidgets.QSizePolicy.Preferred + ) sizePolicy.setHorizontalStretch(0) sizePolicy.setVerticalStretch(0) - sizePolicy.setHeightForWidth(self.lineEditSearch.sizePolicy().hasHeightForWidth()) + sizePolicy.setHeightForWidth( + self.lineEditSearch.sizePolicy().hasHeightForWidth() + ) self.lineEditSearch.setSizePolicy(sizePolicy) self.lineEditSearch.setAcceptDrops(False) self.lineEditSearch.setClearButtonEnabled(True) @@ -381,10 +471,14 @@ def setupUi(self, TabAnalysis): self.gridLayout_2.addWidget(self.lineEditSearch, 0, 1, 1, 1) self.verticalLayout.addLayout(self.gridLayout_2) self.tblViewProtocol = ProtocolTableView(self.layoutWidget1) - sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Expanding, QtWidgets.QSizePolicy.Expanding) + sizePolicy = QtWidgets.QSizePolicy( + QtWidgets.QSizePolicy.Expanding, QtWidgets.QSizePolicy.Expanding + ) sizePolicy.setHorizontalStretch(0) sizePolicy.setVerticalStretch(0) - sizePolicy.setHeightForWidth(self.tblViewProtocol.sizePolicy().hasHeightForWidth()) + sizePolicy.setHeightForWidth( + self.tblViewProtocol.sizePolicy().hasHeightForWidth() + ) self.tblViewProtocol.setSizePolicy(sizePolicy) self.tblViewProtocol.setAcceptDrops(True) self.tblViewProtocol.setAutoFillBackground(True) @@ -394,10 +488,16 @@ def setupUi(self, TabAnalysis): self.tblViewProtocol.setAutoScroll(True) self.tblViewProtocol.setDragDropMode(QtWidgets.QAbstractItemView.DropOnly) self.tblViewProtocol.setAlternatingRowColors(True) - self.tblViewProtocol.setSelectionMode(QtWidgets.QAbstractItemView.ExtendedSelection) + self.tblViewProtocol.setSelectionMode( + QtWidgets.QAbstractItemView.ExtendedSelection + ) self.tblViewProtocol.setTextElideMode(QtCore.Qt.ElideNone) - self.tblViewProtocol.setVerticalScrollMode(QtWidgets.QAbstractItemView.ScrollPerPixel) - self.tblViewProtocol.setHorizontalScrollMode(QtWidgets.QAbstractItemView.ScrollPerPixel) + self.tblViewProtocol.setVerticalScrollMode( + QtWidgets.QAbstractItemView.ScrollPerPixel + ) + self.tblViewProtocol.setHorizontalScrollMode( + QtWidgets.QAbstractItemView.ScrollPerPixel + ) self.tblViewProtocol.setShowGrid(False) self.tblViewProtocol.setGridStyle(QtCore.Qt.NoPen) self.tblViewProtocol.setSortingEnabled(False) @@ -409,7 +509,9 @@ def setupUi(self, TabAnalysis): self.horizontalLayout_3 = QtWidgets.QHBoxLayout() self.horizontalLayout_3.setObjectName("horizontalLayout_3") self.lBits = QtWidgets.QLabel(self.layoutWidget1) - sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Preferred, QtWidgets.QSizePolicy.Preferred) + sizePolicy = QtWidgets.QSizePolicy( + QtWidgets.QSizePolicy.Preferred, QtWidgets.QSizePolicy.Preferred + ) sizePolicy.setHorizontalStretch(0) sizePolicy.setVerticalStretch(0) sizePolicy.setHeightForWidth(self.lBits.sizePolicy().hasHeightForWidth()) @@ -418,10 +520,14 @@ def setupUi(self, TabAnalysis): self.lBits.setObjectName("lBits") self.horizontalLayout_3.addWidget(self.lBits) self.lBitsSelection = QtWidgets.QLineEdit(self.layoutWidget1) - sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Expanding, QtWidgets.QSizePolicy.Preferred) + sizePolicy = QtWidgets.QSizePolicy( + QtWidgets.QSizePolicy.Expanding, QtWidgets.QSizePolicy.Preferred + ) sizePolicy.setHorizontalStretch(0) sizePolicy.setVerticalStretch(0) - sizePolicy.setHeightForWidth(self.lBitsSelection.sizePolicy().hasHeightForWidth()) + sizePolicy.setHeightForWidth( + self.lBitsSelection.sizePolicy().hasHeightForWidth() + ) self.lBitsSelection.setSizePolicy(sizePolicy) self.lBitsSelection.setMaximumSize(QtCore.QSize(16777215, 16777215)) self.lBitsSelection.setAcceptDrops(False) @@ -431,7 +537,9 @@ def setupUi(self, TabAnalysis): self.lBitsSelection.setObjectName("lBitsSelection") self.horizontalLayout_3.addWidget(self.lBitsSelection) self.lHex = QtWidgets.QLabel(self.layoutWidget1) - sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Preferred, QtWidgets.QSizePolicy.Preferred) + sizePolicy = QtWidgets.QSizePolicy( + QtWidgets.QSizePolicy.Preferred, QtWidgets.QSizePolicy.Preferred + ) sizePolicy.setHorizontalStretch(0) sizePolicy.setVerticalStretch(0) sizePolicy.setHeightForWidth(self.lHex.sizePolicy().hasHeightForWidth()) @@ -440,10 +548,14 @@ def setupUi(self, TabAnalysis): self.lHex.setObjectName("lHex") self.horizontalLayout_3.addWidget(self.lHex) self.lHexSelection = QtWidgets.QLineEdit(self.layoutWidget1) - sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Expanding, QtWidgets.QSizePolicy.Preferred) + sizePolicy = QtWidgets.QSizePolicy( + QtWidgets.QSizePolicy.Expanding, QtWidgets.QSizePolicy.Preferred + ) sizePolicy.setHorizontalStretch(0) sizePolicy.setVerticalStretch(0) - sizePolicy.setHeightForWidth(self.lHexSelection.sizePolicy().hasHeightForWidth()) + sizePolicy.setHeightForWidth( + self.lHexSelection.sizePolicy().hasHeightForWidth() + ) self.lHexSelection.setSizePolicy(sizePolicy) self.lHexSelection.setMaximumSize(QtCore.QSize(16777215, 16777215)) self.lHexSelection.setAcceptDrops(False) @@ -453,7 +565,9 @@ def setupUi(self, TabAnalysis): self.lHexSelection.setObjectName("lHexSelection") self.horizontalLayout_3.addWidget(self.lHexSelection) self.lDecimal = QtWidgets.QLabel(self.layoutWidget1) - sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Preferred, QtWidgets.QSizePolicy.Preferred) + sizePolicy = QtWidgets.QSizePolicy( + QtWidgets.QSizePolicy.Preferred, QtWidgets.QSizePolicy.Preferred + ) sizePolicy.setHorizontalStretch(0) sizePolicy.setVerticalStretch(0) sizePolicy.setHeightForWidth(self.lDecimal.sizePolicy().hasHeightForWidth()) @@ -462,25 +576,37 @@ def setupUi(self, TabAnalysis): self.lDecimal.setObjectName("lDecimal") self.horizontalLayout_3.addWidget(self.lDecimal) self.lDecimalSelection = QtWidgets.QLineEdit(self.layoutWidget1) - sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Expanding, QtWidgets.QSizePolicy.Preferred) + sizePolicy = QtWidgets.QSizePolicy( + QtWidgets.QSizePolicy.Expanding, QtWidgets.QSizePolicy.Preferred + ) sizePolicy.setHorizontalStretch(0) sizePolicy.setVerticalStretch(0) - sizePolicy.setHeightForWidth(self.lDecimalSelection.sizePolicy().hasHeightForWidth()) + sizePolicy.setHeightForWidth( + self.lDecimalSelection.sizePolicy().hasHeightForWidth() + ) self.lDecimalSelection.setSizePolicy(sizePolicy) self.lDecimalSelection.setMaximumSize(QtCore.QSize(16777215, 16777215)) self.lDecimalSelection.setAcceptDrops(False) - self.lDecimalSelection.setStyleSheet("background-color: rgba(255, 255, 255, 0);") + self.lDecimalSelection.setStyleSheet( + "background-color: rgba(255, 255, 255, 0);" + ) self.lDecimalSelection.setFrame(False) self.lDecimalSelection.setReadOnly(True) self.lDecimalSelection.setObjectName("lDecimalSelection") self.horizontalLayout_3.addWidget(self.lDecimalSelection) self.lNumSelectedColumns = QtWidgets.QLabel(self.layoutWidget1) - sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Expanding, QtWidgets.QSizePolicy.Preferred) + sizePolicy = QtWidgets.QSizePolicy( + QtWidgets.QSizePolicy.Expanding, QtWidgets.QSizePolicy.Preferred + ) sizePolicy.setHorizontalStretch(0) sizePolicy.setVerticalStretch(0) - sizePolicy.setHeightForWidth(self.lNumSelectedColumns.sizePolicy().hasHeightForWidth()) + sizePolicy.setHeightForWidth( + self.lNumSelectedColumns.sizePolicy().hasHeightForWidth() + ) self.lNumSelectedColumns.setSizePolicy(sizePolicy) - self.lNumSelectedColumns.setAlignment(QtCore.Qt.AlignRight|QtCore.Qt.AlignTrailing|QtCore.Qt.AlignVCenter) + self.lNumSelectedColumns.setAlignment( + QtCore.Qt.AlignRight | QtCore.Qt.AlignTrailing | QtCore.Qt.AlignVCenter + ) self.lNumSelectedColumns.setObjectName("lNumSelectedColumns") self.horizontalLayout_3.addWidget(self.lNumSelectedColumns) self.lColumnsSelectedText = QtWidgets.QLabel(self.layoutWidget1) @@ -495,7 +621,9 @@ def setupUi(self, TabAnalysis): self.gridLayout = QtWidgets.QGridLayout() self.gridLayout.setObjectName("gridLayout") self.label = QtWidgets.QLabel(self.layoutWidget2) - sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Preferred, QtWidgets.QSizePolicy.Fixed) + sizePolicy = QtWidgets.QSizePolicy( + QtWidgets.QSizePolicy.Preferred, QtWidgets.QSizePolicy.Fixed + ) sizePolicy.setHorizontalStretch(0) sizePolicy.setVerticalStretch(0) sizePolicy.setHeightForWidth(self.label.sizePolicy().hasHeightForWidth()) @@ -504,19 +632,27 @@ def setupUi(self, TabAnalysis): self.label.setObjectName("label") self.gridLayout.addWidget(self.label, 0, 0, 1, 1) self.lblLabelValues = QtWidgets.QLabel(self.layoutWidget2) - sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Preferred, QtWidgets.QSizePolicy.Fixed) + sizePolicy = QtWidgets.QSizePolicy( + QtWidgets.QSizePolicy.Preferred, QtWidgets.QSizePolicy.Fixed + ) sizePolicy.setHorizontalStretch(0) sizePolicy.setVerticalStretch(0) - sizePolicy.setHeightForWidth(self.lblLabelValues.sizePolicy().hasHeightForWidth()) + sizePolicy.setHeightForWidth( + self.lblLabelValues.sizePolicy().hasHeightForWidth() + ) self.lblLabelValues.setSizePolicy(sizePolicy) self.lblLabelValues.setAlignment(QtCore.Qt.AlignCenter) self.lblLabelValues.setObjectName("lblLabelValues") self.gridLayout.addWidget(self.lblLabelValues, 0, 1, 1, 1) self.btnAddMessagetype = QtWidgets.QToolButton(self.layoutWidget2) - sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Preferred, QtWidgets.QSizePolicy.Fixed) + sizePolicy = QtWidgets.QSizePolicy( + QtWidgets.QSizePolicy.Preferred, QtWidgets.QSizePolicy.Fixed + ) sizePolicy.setHorizontalStretch(0) sizePolicy.setVerticalStretch(0) - sizePolicy.setHeightForWidth(self.btnAddMessagetype.sizePolicy().hasHeightForWidth()) + sizePolicy.setHeightForWidth( + self.btnAddMessagetype.sizePolicy().hasHeightForWidth() + ) self.btnAddMessagetype.setSizePolicy(sizePolicy) icon = QtGui.QIcon.fromTheme("list-add") self.btnAddMessagetype.setIcon(icon) @@ -524,10 +660,14 @@ def setupUi(self, TabAnalysis): self.btnAddMessagetype.setObjectName("btnAddMessagetype") self.gridLayout.addWidget(self.btnAddMessagetype, 3, 0, 1, 1) self.tblLabelValues = LabelValueTableView(self.layoutWidget2) - sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Expanding, QtWidgets.QSizePolicy.Preferred) + sizePolicy = QtWidgets.QSizePolicy( + QtWidgets.QSizePolicy.Expanding, QtWidgets.QSizePolicy.Preferred + ) sizePolicy.setHorizontalStretch(0) sizePolicy.setVerticalStretch(0) - sizePolicy.setHeightForWidth(self.tblLabelValues.sizePolicy().hasHeightForWidth()) + sizePolicy.setHeightForWidth( + self.tblLabelValues.sizePolicy().hasHeightForWidth() + ) self.tblLabelValues.setSizePolicy(sizePolicy) self.tblLabelValues.setFrameShape(QtWidgets.QFrame.StyledPanel) self.tblLabelValues.setAlternatingRowColors(True) @@ -540,10 +680,14 @@ def setupUi(self, TabAnalysis): self.tblLabelValues.verticalHeader().setVisible(False) self.gridLayout.addWidget(self.tblLabelValues, 1, 1, 3, 1) self.tblViewMessageTypes = MessageTypeTableView(self.layoutWidget2) - sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Preferred, QtWidgets.QSizePolicy.Preferred) + sizePolicy = QtWidgets.QSizePolicy( + QtWidgets.QSizePolicy.Preferred, QtWidgets.QSizePolicy.Preferred + ) sizePolicy.setHorizontalStretch(0) sizePolicy.setVerticalStretch(0) - sizePolicy.setHeightForWidth(self.tblViewMessageTypes.sizePolicy().hasHeightForWidth()) + sizePolicy.setHeightForWidth( + self.tblViewMessageTypes.sizePolicy().hasHeightForWidth() + ) self.tblViewMessageTypes.setSizePolicy(sizePolicy) self.tblViewMessageTypes.setAcceptDrops(False) self.tblViewMessageTypes.setToolTip("") @@ -565,53 +709,107 @@ def setupUi(self, TabAnalysis): def retranslateUi(self, TabAnalysis): _translate = QtCore.QCoreApplication.translate TabAnalysis.setWindowTitle(_translate("TabAnalysis", "Frame")) - self.tabWidget.setTabText(self.tabWidget.indexOf(self.tab_protocols), _translate("TabAnalysis", "Protocols")) - self.tabWidget.setTabText(self.tabWidget.indexOf(self.tab_participants), _translate("TabAnalysis", "Participants")) + self.tabWidget.setTabText( + self.tabWidget.indexOf(self.tab_protocols), + _translate("TabAnalysis", "Protocols"), + ) + self.tabWidget.setTabText( + self.tabWidget.indexOf(self.tab_participants), + _translate("TabAnalysis", "Participants"), + ) self.label_5.setText(_translate("TabAnalysis", "Decoding:")) self.label_4.setText(_translate("TabAnalysis", "View data as:")) self.lEncodingErrors.setText(_translate("TabAnalysis", "Decoding errors:")) self.cbDecoding.setItemText(0, _translate("TabAnalysis", "NRZ")) self.cbDecoding.setItemText(1, _translate("TabAnalysis", "Manchester")) self.cbDecoding.setItemText(2, _translate("TabAnalysis", "Manchester II")) - self.cbDecoding.setItemText(3, _translate("TabAnalysis", "Differential Manchester")) + self.cbDecoding.setItemText( + 3, _translate("TabAnalysis", "Differential Manchester") + ) self.cbDecoding.setItemText(4, _translate("TabAnalysis", "...")) - self.chkBoxShowOnlyDiffs.setText(_translate("TabAnalysis", "Show only diffs in protocol")) - self.cbProtoView.setToolTip(_translate("TabAnalysis", "

Set the desired view here.

")) + self.chkBoxShowOnlyDiffs.setText( + _translate("TabAnalysis", "Show only diffs in protocol") + ) + self.cbProtoView.setToolTip( + _translate( + "TabAnalysis", + "

Set the desired view here.

", + ) + ) self.cbProtoView.setItemText(0, _translate("TabAnalysis", "Bits")) self.cbProtoView.setItemText(1, _translate("TabAnalysis", "Hex")) self.cbProtoView.setItemText(2, _translate("TabAnalysis", "ASCII")) self.lDecodingErrorsValue.setText(_translate("TabAnalysis", "0 (0.00%)")) - self.chkBoxOnlyShowLabelsInProtocol.setText(_translate("TabAnalysis", "Show only labels in protocol")) + self.chkBoxOnlyShowLabelsInProtocol.setText( + _translate("TabAnalysis", "Show only labels in protocol") + ) self.cbShowDiffs.setText(_translate("TabAnalysis", "Mark diffs in protocol")) - self.btnAnalyze.setToolTip(_translate("TabAnalysis", "

Run some automatic analysis on the protocol e.g. assign labels automatically. You can configure which checks to run with the arrow on the right of this button.

")) + self.btnAnalyze.setToolTip( + _translate( + "TabAnalysis", + "

Run some automatic analysis on the protocol e.g. assign labels automatically. You can configure which checks to run with the arrow on the right of this button.

", + ) + ) self.btnAnalyze.setText(_translate("TabAnalysis", "Analyze Protocol")) - self.btnSaveProto.setToolTip(_translate("TabAnalysis", "Save current protocol.")) + self.btnSaveProto.setToolTip( + _translate("TabAnalysis", "Save current protocol.") + ) self.lSlash.setText(_translate("TabAnalysis", "/")) self.lblShownRows.setText(_translate("TabAnalysis", "shown: 42/108")) - self.lTime.setToolTip(_translate("TabAnalysis", "

The MessageStart is the point in time when a protocol message begins. Additionally the relative time (+ ...) from the previous message is shown.

")) + self.lTime.setToolTip( + _translate( + "TabAnalysis", + '

The MessageStart is the point in time when a protocol message begins. Additionally the relative time (+ ...) from the previous message is shown.

', + ) + ) self.lTime.setText(_translate("TabAnalysis", "0 (+0)")) self.lSearchCurrent.setText(_translate("TabAnalysis", "-")) - self.lblRSSI.setToolTip(_translate("TabAnalysis", "

This is the average signal power of the current message. The nearer this value is to zero, the stronger the signal is.

")) + self.lblRSSI.setToolTip( + _translate( + "TabAnalysis", + "

This is the average signal power of the current message. The nearer this value is to zero, the stronger the signal is.

", + ) + ) self.lblRSSI.setText(_translate("TabAnalysis", "-∞ dBm")) self.btnNextSearch.setText(_translate("TabAnalysis", ">")) self.btnPrevSearch.setText(_translate("TabAnalysis", "<")) self.lSearchTotal.setText(_translate("TabAnalysis", "-")) - self.label_3.setToolTip(_translate("TabAnalysis", "

The Message Start is the point in time when a protocol message begins. Additionally the relative time (+ ...) from the previous message is shown.

")) + self.label_3.setToolTip( + _translate( + "TabAnalysis", + '

The Message Start is the point in time when a protocol message begins. Additionally the relative time (+ ...) from the previous message is shown.

', + ) + ) self.label_3.setText(_translate("TabAnalysis", "Timestamp:")) self.btnSearchSelectFilter.setText(_translate("TabAnalysis", "Search")) self.btnLoadProto.setToolTip(_translate("TabAnalysis", "Load a protocol.")) self.btnLoadProto.setText(_translate("TabAnalysis", "...")) - self.lblClearAlignment.setText(_translate("TabAnalysis", "

Reset alignment

")) - self.lineEditSearch.setPlaceholderText(_translate("TabAnalysis", "Enter pattern here")) + self.lblClearAlignment.setText( + _translate( + "TabAnalysis", + '

Reset alignment

', + ) + ) + self.lineEditSearch.setPlaceholderText( + _translate("TabAnalysis", "Enter pattern here") + ) self.lBits.setText(_translate("TabAnalysis", "Bit:")) self.lHex.setText(_translate("TabAnalysis", "Hex:")) self.lDecimal.setText(_translate("TabAnalysis", "Decimal:")) self.lNumSelectedColumns.setText(_translate("TabAnalysis", "0")) - self.lColumnsSelectedText.setText(_translate("TabAnalysis", "column(s) selected")) + self.lColumnsSelectedText.setText( + _translate("TabAnalysis", "column(s) selected") + ) self.label.setText(_translate("TabAnalysis", "Message types")) self.lblLabelValues.setText(_translate("TabAnalysis", "Labels for message")) - self.btnAddMessagetype.setToolTip(_translate("TabAnalysis", "Add a new message type")) - self.btnAddMessagetype.setText(_translate("TabAnalysis", "Add new message type")) + self.btnAddMessagetype.setToolTip( + _translate("TabAnalysis", "Add a new message type") + ) + self.btnAddMessagetype.setText( + _translate("TabAnalysis", "Add new message type") + ) + + from urh.ui.views.LabelValueTableView import LabelValueTableView from urh.ui.views.MessageTypeTableView import MessageTypeTableView from urh.ui.views.ProtocolTableView import ProtocolTableView diff --git a/src/urh/ui/ui_checksum_options_widget.py b/src/urh/ui/ui_checksum_options_widget.py index 281139ec56..582adb59b5 100644 --- a/src/urh/ui/ui_checksum_options_widget.py +++ b/src/urh/ui/ui_checksum_options_widget.py @@ -66,7 +66,9 @@ def setupUi(self, ChecksumOptions): self.btnRemoveRange.setIcon(icon) self.btnRemoveRange.setObjectName("btnRemoveRange") self.verticalLayout.addWidget(self.btnRemoveRange) - spacerItem = QtWidgets.QSpacerItem(20, 40, QtWidgets.QSizePolicy.Minimum, QtWidgets.QSizePolicy.Expanding) + spacerItem = QtWidgets.QSpacerItem( + 20, 40, QtWidgets.QSizePolicy.Minimum, QtWidgets.QSizePolicy.Expanding + ) self.verticalLayout.addItem(spacerItem) self.horizontalLayout.addLayout(self.verticalLayout) self.gridLayout_2.addWidget(self.groupBox, 7, 0, 1, 2) @@ -104,7 +106,7 @@ def setupUi(self, ChecksumOptions): self.verticalLayout_2 = QtWidgets.QVBoxLayout(self.page_wsp) self.verticalLayout_2.setObjectName("verticalLayout_2") self.label_6 = QtWidgets.QLabel(self.page_wsp) - self.label_6.setAlignment(QtCore.Qt.AlignJustify|QtCore.Qt.AlignVCenter) + self.label_6.setAlignment(QtCore.Qt.AlignJustify | QtCore.Qt.AlignVCenter) self.label_6.setWordWrap(True) self.label_6.setObjectName("label_6") self.verticalLayout_2.addWidget(self.label_6) @@ -120,18 +122,24 @@ def setupUi(self, ChecksumOptions): self.radioButtonWSPCRC8 = QtWidgets.QRadioButton(self.page_wsp) self.radioButtonWSPCRC8.setObjectName("radioButtonWSPCRC8") self.verticalLayout_2.addWidget(self.radioButtonWSPCRC8) - spacerItem1 = QtWidgets.QSpacerItem(20, 40, QtWidgets.QSizePolicy.Minimum, QtWidgets.QSizePolicy.Expanding) + spacerItem1 = QtWidgets.QSpacerItem( + 20, 40, QtWidgets.QSizePolicy.Minimum, QtWidgets.QSizePolicy.Expanding + ) self.verticalLayout_2.addItem(spacerItem1) self.stackedWidget.addWidget(self.page_wsp) self.verticalLayout_3.addWidget(self.stackedWidget) - spacerItem2 = QtWidgets.QSpacerItem(20, 107, QtWidgets.QSizePolicy.Minimum, QtWidgets.QSizePolicy.Expanding) + spacerItem2 = QtWidgets.QSpacerItem( + 20, 107, QtWidgets.QSizePolicy.Minimum, QtWidgets.QSizePolicy.Expanding + ) self.verticalLayout_3.addItem(spacerItem2) self.scrollArea.setWidget(self.scrollAreaWidgetContents) self.gridLayout.addWidget(self.scrollArea, 1, 0, 1, 2) self.retranslateUi(ChecksumOptions) self.stackedWidget.setCurrentIndex(0) - ChecksumOptions.setTabOrder(self.comboBoxCRCFunction, self.lineEditCRCPolynomial) + ChecksumOptions.setTabOrder( + self.comboBoxCRCFunction, self.lineEditCRCPolynomial + ) ChecksumOptions.setTabOrder(self.lineEditCRCPolynomial, self.lineEditStartValue) ChecksumOptions.setTabOrder(self.lineEditStartValue, self.lineEditFinalXOR) ChecksumOptions.setTabOrder(self.lineEditFinalXOR, self.tableViewDataRanges) @@ -139,27 +147,57 @@ def setupUi(self, ChecksumOptions): ChecksumOptions.setTabOrder(self.btnAddRange, self.radioButtonWSPAuto) ChecksumOptions.setTabOrder(self.radioButtonWSPAuto, self.btnRemoveRange) ChecksumOptions.setTabOrder(self.btnRemoveRange, self.radioButtonWSPChecksum4) - ChecksumOptions.setTabOrder(self.radioButtonWSPChecksum4, self.radioButtonWSPChecksum8) - ChecksumOptions.setTabOrder(self.radioButtonWSPChecksum8, self.radioButtonWSPCRC8) + ChecksumOptions.setTabOrder( + self.radioButtonWSPChecksum4, self.radioButtonWSPChecksum8 + ) + ChecksumOptions.setTabOrder( + self.radioButtonWSPChecksum8, self.radioButtonWSPCRC8 + ) def retranslateUi(self, ChecksumOptions): _translate = QtCore.QCoreApplication.translate - ChecksumOptions.setWindowTitle(_translate("ChecksumOptions", "Configure Checksum")) + ChecksumOptions.setWindowTitle( + _translate("ChecksumOptions", "Configure Checksum") + ) self.label_4.setText(_translate("ChecksumOptions", "Checksum category:")) self.comboBoxCategory.setItemText(0, _translate("ChecksumOptions", "CRC")) - self.comboBoxCategory.setItemText(1, _translate("ChecksumOptions", "Wireless Short Packet Checksum")) + self.comboBoxCategory.setItemText( + 1, _translate("ChecksumOptions", "Wireless Short Packet Checksum") + ) self.label_5.setText(_translate("ChecksumOptions", "CRC polynomial (hex):")) - self.groupBox.setTitle(_translate("ChecksumOptions", "Configure data ranges for CRC")) + self.groupBox.setTitle( + _translate("ChecksumOptions", "Configure data ranges for CRC") + ) self.btnAddRange.setText(_translate("ChecksumOptions", "...")) self.btnRemoveRange.setText(_translate("ChecksumOptions", "...")) self.label_3.setText(_translate("ChecksumOptions", "CRC function:")) self.label_2.setText(_translate("ChecksumOptions", "Final XOR (hex):")) self.label.setText(_translate("ChecksumOptions", "Start value (hex):")) - self.label_crc_info.setText(_translate("ChecksumOptions", "

Order=17

Length of checksum=16

start value length =16

final XOR length = 16

Polynomial = x1 + 4

")) - self.checkBoxRefIn.setText(_translate("ChecksumOptions", "RefIn (Reflect input)")) - self.checkBoxRefOut.setText(_translate("ChecksumOptions", "RefOut (Reflect output)")) - self.label_6.setText(_translate("ChecksumOptions", "

The Wireless Short Packet (WSP) standard uses three different checksums. URH can automatically detect the used checksum algorithm from the message. However, you can enforce the usage of a certain checksum if you need to.

With Automatic setting, checksums are chosen by these rules:

1) 4 Bit Checksum - For Switch Telegram (RORG=5 or 6 and STATUS = 0x20 or 0x30)

2) 8 Bit Checksum: STATUS bit 27 = 0

3) 8 Bit CRC: STATUS bit 27 = 1

")) - self.radioButtonWSPAuto.setText(_translate("ChecksumOptions", "Automatic (recommended)")) - self.radioButtonWSPChecksum4.setText(_translate("ChecksumOptions", "Force Checksum4")) - self.radioButtonWSPChecksum8.setText(_translate("ChecksumOptions", "Force Checksum8")) + self.label_crc_info.setText( + _translate( + "ChecksumOptions", + '

Order=17

Length of checksum=16

start value length =16

final XOR length = 16

Polynomial = x1 + 4

', + ) + ) + self.checkBoxRefIn.setText( + _translate("ChecksumOptions", "RefIn (Reflect input)") + ) + self.checkBoxRefOut.setText( + _translate("ChecksumOptions", "RefOut (Reflect output)") + ) + self.label_6.setText( + _translate( + "ChecksumOptions", + '

The Wireless Short Packet (WSP) standard uses three different checksums. URH can automatically detect the used checksum algorithm from the message. However, you can enforce the usage of a certain checksum if you need to.

With Automatic setting, checksums are chosen by these rules:

1) 4 Bit Checksum - For Switch Telegram (RORG=5 or 6 and STATUS = 0x20 or 0x30)

2) 8 Bit Checksum: STATUS bit 27 = 0

3) 8 Bit CRC: STATUS bit 27 = 1

', + ) + ) + self.radioButtonWSPAuto.setText( + _translate("ChecksumOptions", "Automatic (recommended)") + ) + self.radioButtonWSPChecksum4.setText( + _translate("ChecksumOptions", "Force Checksum4") + ) + self.radioButtonWSPChecksum8.setText( + _translate("ChecksumOptions", "Force Checksum8") + ) self.radioButtonWSPCRC8.setText(_translate("ChecksumOptions", "Force CRC8")) diff --git a/src/urh/ui/ui_costa.py b/src/urh/ui/ui_costa.py index a5a8a59e18..72e4237e09 100644 --- a/src/urh/ui/ui_costa.py +++ b/src/urh/ui/ui_costa.py @@ -16,7 +16,9 @@ def setupUi(self, DialogCosta): self.verticalLayout = QtWidgets.QVBoxLayout(DialogCosta) self.verticalLayout.setObjectName("verticalLayout") self.label = QtWidgets.QLabel(DialogCosta) - self.label.setAlignment(QtCore.Qt.AlignLeading|QtCore.Qt.AlignLeft|QtCore.Qt.AlignTop) + self.label.setAlignment( + QtCore.Qt.AlignLeading | QtCore.Qt.AlignLeft | QtCore.Qt.AlignTop + ) self.label.setWordWrap(True) self.label.setObjectName("label") self.verticalLayout.addWidget(self.label) @@ -32,10 +34,14 @@ def setupUi(self, DialogCosta): self.verticalLayout.addLayout(self.horizontalLayout) self.buttonBox = QtWidgets.QDialogButtonBox(DialogCosta) self.buttonBox.setOrientation(QtCore.Qt.Horizontal) - self.buttonBox.setStandardButtons(QtWidgets.QDialogButtonBox.Cancel|QtWidgets.QDialogButtonBox.Ok) + self.buttonBox.setStandardButtons( + QtWidgets.QDialogButtonBox.Cancel | QtWidgets.QDialogButtonBox.Ok + ) self.buttonBox.setObjectName("buttonBox") self.verticalLayout.addWidget(self.buttonBox) - spacerItem = QtWidgets.QSpacerItem(20, 40, QtWidgets.QSizePolicy.Minimum, QtWidgets.QSizePolicy.Expanding) + spacerItem = QtWidgets.QSpacerItem( + 20, 40, QtWidgets.QSizePolicy.Minimum, QtWidgets.QSizePolicy.Expanding + ) self.verticalLayout.addItem(spacerItem) self.retranslateUi(DialogCosta) @@ -45,5 +51,10 @@ def setupUi(self, DialogCosta): def retranslateUi(self, DialogCosta): _translate = QtCore.QCoreApplication.translate DialogCosta.setWindowTitle(_translate("DialogCosta", "Configure Costas Loop")) - self.label.setText(_translate("DialogCosta", "URH uses a Costas loop for PSK demodulation. Configure the loop bandwidth below.")) + self.label.setText( + _translate( + "DialogCosta", + "URH uses a Costas loop for PSK demodulation. Configure the loop bandwidth below.", + ) + ) self.labelLoopBandwidth.setText(_translate("DialogCosta", "Loop Bandwidth:")) diff --git a/src/urh/ui/ui_csv_wizard.py b/src/urh/ui/ui_csv_wizard.py index 97b04b119d..1c23beb1af 100644 --- a/src/urh/ui/ui_csv_wizard.py +++ b/src/urh/ui/ui_csv_wizard.py @@ -89,14 +89,18 @@ def setupUi(self, DialogCSVImport): self.gridLayout.addWidget(self.label_4, 3, 0, 1, 2) self.buttonBox = QtWidgets.QDialogButtonBox(DialogCSVImport) self.buttonBox.setOrientation(QtCore.Qt.Horizontal) - self.buttonBox.setStandardButtons(QtWidgets.QDialogButtonBox.Cancel|QtWidgets.QDialogButtonBox.Ok) + self.buttonBox.setStandardButtons( + QtWidgets.QDialogButtonBox.Cancel | QtWidgets.QDialogButtonBox.Ok + ) self.buttonBox.setObjectName("buttonBox") self.gridLayout.addWidget(self.buttonBox, 9, 2, 1, 1) self.groupBoxFilePreview = QtWidgets.QGroupBox(DialogCSVImport) self.groupBoxFilePreview.setObjectName("groupBoxFilePreview") self.verticalLayout = QtWidgets.QVBoxLayout(self.groupBoxFilePreview) self.verticalLayout.setObjectName("verticalLayout") - self.plainTextEditFilePreview = QtWidgets.QPlainTextEdit(self.groupBoxFilePreview) + self.plainTextEditFilePreview = QtWidgets.QPlainTextEdit( + self.groupBoxFilePreview + ) self.plainTextEditFilePreview.setUndoRedoEnabled(False) self.plainTextEditFilePreview.setReadOnly(True) self.plainTextEditFilePreview.setObjectName("plainTextEditFilePreview") @@ -115,26 +119,53 @@ def setupUi(self, DialogCSVImport): self.buttonBox.rejected.connect(DialogCSVImport.reject) DialogCSVImport.setTabOrder(self.lineEditFilename, self.btnChooseFile) DialogCSVImport.setTabOrder(self.btnChooseFile, self.plainTextEditFilePreview) - DialogCSVImport.setTabOrder(self.plainTextEditFilePreview, self.comboBoxCSVSeparator) + DialogCSVImport.setTabOrder( + self.plainTextEditFilePreview, self.comboBoxCSVSeparator + ) DialogCSVImport.setTabOrder(self.comboBoxCSVSeparator, self.btnAddSeparator) DialogCSVImport.setTabOrder(self.btnAddSeparator, self.spinBoxIDataColumn) DialogCSVImport.setTabOrder(self.spinBoxIDataColumn, self.spinBoxQDataColumn) - DialogCSVImport.setTabOrder(self.spinBoxQDataColumn, self.spinBoxTimestampColumn) - DialogCSVImport.setTabOrder(self.spinBoxTimestampColumn, self.tableWidgetPreview) + DialogCSVImport.setTabOrder( + self.spinBoxQDataColumn, self.spinBoxTimestampColumn + ) + DialogCSVImport.setTabOrder( + self.spinBoxTimestampColumn, self.tableWidgetPreview + ) def retranslateUi(self, DialogCSVImport): _translate = QtCore.QCoreApplication.translate DialogCSVImport.setWindowTitle(_translate("DialogCSVImport", "CSV Import")) - self.labelFileNotFound.setText(_translate("DialogCSVImport", "

Could not open the selected file.

")) + self.labelFileNotFound.setText( + _translate( + "DialogCSVImport", + '

Could not open the selected file.

', + ) + ) self.comboBoxCSVSeparator.setItemText(0, _translate("DialogCSVImport", ",")) self.comboBoxCSVSeparator.setItemText(1, _translate("DialogCSVImport", ";")) - self.btnAddSeparator.setToolTip(_translate("DialogCSVImport", "Add a custom separator.")) + self.btnAddSeparator.setToolTip( + _translate("DialogCSVImport", "Add a custom separator.") + ) self.btnAddSeparator.setText(_translate("DialogCSVImport", "...")) - self.spinBoxTimestampColumn.setToolTip(_translate("DialogCSVImport", "

If your dataset contains timestamps URH will calculate the sample rate from them. You can manually edit the sample rate after import in the signal details.

")) - self.spinBoxTimestampColumn.setSpecialValueText(_translate("DialogCSVImport", "Not present")) + self.spinBoxTimestampColumn.setToolTip( + _translate( + "DialogCSVImport", + "

If your dataset contains timestamps URH will calculate the sample rate from them. You can manually edit the sample rate after import in the signal details.

", + ) + ) + self.spinBoxTimestampColumn.setSpecialValueText( + _translate("DialogCSVImport", "Not present") + ) self.label.setText(_translate("DialogCSVImport", "I Data Column:")) - self.spinBoxQDataColumn.setSpecialValueText(_translate("DialogCSVImport", "Not present")) - self.label_3.setToolTip(_translate("DialogCSVImport", "

If your dataset contains timestamps URH will calculate the sample rate from them. You can manually edit the sample rate after import in the signal details.

")) + self.spinBoxQDataColumn.setSpecialValueText( + _translate("DialogCSVImport", "Not present") + ) + self.label_3.setToolTip( + _translate( + "DialogCSVImport", + "

If your dataset contains timestamps URH will calculate the sample rate from them. You can manually edit the sample rate after import in the signal details.

", + ) + ) self.label_3.setText(_translate("DialogCSVImport", "Timestamp Column:")) self.label_2.setText(_translate("DialogCSVImport", "Q Data Column:")) self.groupBox.setTitle(_translate("DialogCSVImport", "Preview")) @@ -146,6 +177,10 @@ def retranslateUi(self, DialogCSVImport): item.setText(_translate("DialogCSVImport", "Q")) self.btnChooseFile.setText(_translate("DialogCSVImport", "...")) self.label_4.setText(_translate("DialogCSVImport", "CSV Separator:")) - self.groupBoxFilePreview.setTitle(_translate("DialogCSVImport", "File Content (at most 100 rows)")) + self.groupBoxFilePreview.setTitle( + _translate("DialogCSVImport", "File Content (at most 100 rows)") + ) self.label_5.setText(_translate("DialogCSVImport", "File to import:")) - self.btnAutoDefault.setText(_translate("DialogCSVImport", "Prevent Dialog From Close with Enter")) + self.btnAutoDefault.setText( + _translate("DialogCSVImport", "Prevent Dialog From Close with Enter") + ) diff --git a/src/urh/ui/ui_decoding.py b/src/urh/ui/ui_decoding.py index ba29dc1dfd..17b273b866 100644 --- a/src/urh/ui/ui_decoding.py +++ b/src/urh/ui/ui_decoding.py @@ -29,7 +29,9 @@ def setupUi(self, Decoder): self.saveas = QtWidgets.QPushButton(Decoder) self.saveas.setObjectName("saveas") self.horizontalLayout_2.addWidget(self.saveas) - spacerItem = QtWidgets.QSpacerItem(40, 20, QtWidgets.QSizePolicy.Expanding, QtWidgets.QSizePolicy.Minimum) + spacerItem = QtWidgets.QSpacerItem( + 40, 20, QtWidgets.QSizePolicy.Expanding, QtWidgets.QSizePolicy.Minimum + ) self.horizontalLayout_2.addItem(spacerItem) self.verticalLayout_4.addLayout(self.horizontalLayout_2) self.horizontalLayout = QtWidgets.QHBoxLayout() @@ -40,10 +42,14 @@ def setupUi(self, Decoder): self.label_8.setObjectName("label_8") self.verticalLayout_2.addWidget(self.label_8) self.basefunctions = QtWidgets.QListWidget(Decoder) - sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Fixed, QtWidgets.QSizePolicy.Expanding) + sizePolicy = QtWidgets.QSizePolicy( + QtWidgets.QSizePolicy.Fixed, QtWidgets.QSizePolicy.Expanding + ) sizePolicy.setHorizontalStretch(0) sizePolicy.setVerticalStretch(0) - sizePolicy.setHeightForWidth(self.basefunctions.sizePolicy().hasHeightForWidth()) + sizePolicy.setHeightForWidth( + self.basefunctions.sizePolicy().hasHeightForWidth() + ) self.basefunctions.setSizePolicy(sizePolicy) self.basefunctions.setDragEnabled(True) self.basefunctions.setDragDropMode(QtWidgets.QAbstractItemView.DragOnly) @@ -53,10 +59,14 @@ def setupUi(self, Decoder): self.label_9.setObjectName("label_9") self.verticalLayout_2.addWidget(self.label_9) self.additionalfunctions = QtWidgets.QListWidget(Decoder) - sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Fixed, QtWidgets.QSizePolicy.Expanding) + sizePolicy = QtWidgets.QSizePolicy( + QtWidgets.QSizePolicy.Fixed, QtWidgets.QSizePolicy.Expanding + ) sizePolicy.setHorizontalStretch(0) sizePolicy.setVerticalStretch(0) - sizePolicy.setHeightForWidth(self.additionalfunctions.sizePolicy().hasHeightForWidth()) + sizePolicy.setHeightForWidth( + self.additionalfunctions.sizePolicy().hasHeightForWidth() + ) self.additionalfunctions.setSizePolicy(sizePolicy) self.additionalfunctions.setDragEnabled(True) self.additionalfunctions.setDragDropMode(QtWidgets.QAbstractItemView.DragOnly) @@ -75,7 +85,9 @@ def setupUi(self, Decoder): self.label.setObjectName("label") self.verticalLayout.addWidget(self.label) self.decoderchain = ListWidget(Decoder) - sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Fixed, QtWidgets.QSizePolicy.Expanding) + sizePolicy = QtWidgets.QSizePolicy( + QtWidgets.QSizePolicy.Fixed, QtWidgets.QSizePolicy.Expanding + ) sizePolicy.setHorizontalStretch(0) sizePolicy.setVerticalStretch(0) sizePolicy.setHeightForWidth(self.decoderchain.sizePolicy().hasHeightForWidth()) @@ -93,16 +105,22 @@ def setupUi(self, Decoder): self.verticalLayout_3 = QtWidgets.QVBoxLayout() self.verticalLayout_3.setObjectName("verticalLayout_3") self.gb_infoandoptions = QtWidgets.QGroupBox(Decoder) - sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Expanding, QtWidgets.QSizePolicy.Expanding) + sizePolicy = QtWidgets.QSizePolicy( + QtWidgets.QSizePolicy.Expanding, QtWidgets.QSizePolicy.Expanding + ) sizePolicy.setHorizontalStretch(0) sizePolicy.setVerticalStretch(0) - sizePolicy.setHeightForWidth(self.gb_infoandoptions.sizePolicy().hasHeightForWidth()) + sizePolicy.setHeightForWidth( + self.gb_infoandoptions.sizePolicy().hasHeightForWidth() + ) self.gb_infoandoptions.setSizePolicy(sizePolicy) self.gb_infoandoptions.setObjectName("gb_infoandoptions") self.verticalLayout_5 = QtWidgets.QVBoxLayout(self.gb_infoandoptions) self.verticalLayout_5.setObjectName("verticalLayout_5") self.info = QtWidgets.QLabel(self.gb_infoandoptions) - sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Expanding, QtWidgets.QSizePolicy.Preferred) + sizePolicy = QtWidgets.QSizePolicy( + QtWidgets.QSizePolicy.Expanding, QtWidgets.QSizePolicy.Preferred + ) sizePolicy.setHorizontalStretch(0) sizePolicy.setVerticalStretch(0) sizePolicy.setHeightForWidth(self.info.sizePolicy().hasHeightForWidth()) @@ -111,12 +129,16 @@ def setupUi(self, Decoder): font.setItalic(True) self.info.setFont(font) self.info.setTextFormat(QtCore.Qt.PlainText) - self.info.setAlignment(QtCore.Qt.AlignLeading|QtCore.Qt.AlignLeft|QtCore.Qt.AlignTop) + self.info.setAlignment( + QtCore.Qt.AlignLeading | QtCore.Qt.AlignLeft | QtCore.Qt.AlignTop + ) self.info.setWordWrap(True) self.info.setObjectName("info") self.verticalLayout_5.addWidget(self.info) self.optionWidget = QtWidgets.QStackedWidget(self.gb_infoandoptions) - sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Expanding, QtWidgets.QSizePolicy.Expanding) + sizePolicy = QtWidgets.QSizePolicy( + QtWidgets.QSizePolicy.Expanding, QtWidgets.QSizePolicy.Expanding + ) sizePolicy.setHorizontalStretch(0) sizePolicy.setVerticalStretch(0) sizePolicy.setHeightForWidth(self.optionWidget.sizePolicy().hasHeightForWidth()) @@ -158,8 +180,12 @@ def setupUi(self, Decoder): self.label_10.setObjectName("label_10") self.gridLayout.addWidget(self.label_10, 0, 1, 1, 1) self.substitution = QtWidgets.QTableWidget(self.page_substitution) - self.substitution.setVerticalScrollMode(QtWidgets.QAbstractItemView.ScrollPerPixel) - self.substitution.setHorizontalScrollMode(QtWidgets.QAbstractItemView.ScrollPerPixel) + self.substitution.setVerticalScrollMode( + QtWidgets.QAbstractItemView.ScrollPerPixel + ) + self.substitution.setHorizontalScrollMode( + QtWidgets.QAbstractItemView.ScrollPerPixel + ) self.substitution.setObjectName("substitution") self.substitution.setColumnCount(0) self.substitution.setRowCount(0) @@ -193,7 +219,9 @@ def setupUi(self, Decoder): self.btnChooseEncoder.setObjectName("btnChooseEncoder") self.horizontalLayout_4.addWidget(self.btnChooseEncoder) self.verticalLayout_6.addLayout(self.horizontalLayout_4) - spacerItem1 = QtWidgets.QSpacerItem(20, 158, QtWidgets.QSizePolicy.Minimum, QtWidgets.QSizePolicy.Expanding) + spacerItem1 = QtWidgets.QSpacerItem( + 20, 158, QtWidgets.QSizePolicy.Minimum, QtWidgets.QSizePolicy.Expanding + ) self.verticalLayout_6.addItem(spacerItem1) self.optionWidget.addWidget(self.page_external) self.page_data_whitening = QtWidgets.QWidget() @@ -281,7 +309,9 @@ def setupUi(self, Decoder): self.verticalLayout_4.addLayout(self.horizontalLayout) self.gridLayout_2 = QtWidgets.QGridLayout() self.gridLayout_2.setObjectName("gridLayout_2") - spacerItem2 = QtWidgets.QSpacerItem(40, 20, QtWidgets.QSizePolicy.Expanding, QtWidgets.QSizePolicy.Minimum) + spacerItem2 = QtWidgets.QSpacerItem( + 40, 20, QtWidgets.QSizePolicy.Expanding, QtWidgets.QSizePolicy.Minimum + ) self.gridLayout_2.addItem(spacerItem2, 0, 1, 1, 1) self.inpt = QtWidgets.QLineEdit(Decoder) self.inpt.setInputMethodHints(QtCore.Qt.ImhDigitsOnly) @@ -309,7 +339,9 @@ def setupUi(self, Decoder): self.gridLayout_2.addWidget(self.label_3, 3, 0, 1, 1) self.verticalLayout_4.addLayout(self.gridLayout_2) self.decoding_errors_label = QtWidgets.QLabel(Decoder) - self.decoding_errors_label.setAlignment(QtCore.Qt.AlignRight|QtCore.Qt.AlignTrailing|QtCore.Qt.AlignVCenter) + self.decoding_errors_label.setAlignment( + QtCore.Qt.AlignRight | QtCore.Qt.AlignTrailing | QtCore.Qt.AlignVCenter + ) self.decoding_errors_label.setObjectName("decoding_errors_label") self.verticalLayout_4.addWidget(self.decoding_errors_label) @@ -319,25 +351,44 @@ def setupUi(self, Decoder): def retranslateUi(self, Decoder): _translate = QtCore.QCoreApplication.translate Decoder.setWindowTitle(_translate("Decoder", "Decoding")) - self.combobox_decodings.setItemText(0, _translate("Decoder", "Non Return to Zero (NRZ)")) + self.combobox_decodings.setItemText( + 0, _translate("Decoder", "Non Return to Zero (NRZ)") + ) self.combobox_decodings.setItemText(1, _translate("Decoder", "Empty")) self.delete_decoding.setText(_translate("Decoder", "Delete")) self.saveas.setText(_translate("Decoder", "Save as...")) self.label_8.setText(_translate("Decoder", "Base Functions")) self.label_9.setText(_translate("Decoder", "Additional Functions")) self.label.setText(_translate("Decoder", "Your Decoding")) - self.gb_infoandoptions.setTitle(_translate("Decoder", "Information and Options")) - self.info.setText(_translate("Decoder", "Please drag functions from the categories base and additional to the decoding process (Decoder). You can reorder functions by drag and drop and remove functions by dropping them outside the Decoder box. Click on every function for detailed information.")) + self.gb_infoandoptions.setTitle( + _translate("Decoder", "Information and Options") + ) + self.info.setText( + _translate( + "Decoder", + "Please drag functions from the categories base and additional to the decoding process (Decoder). You can reorder functions by drag and drop and remove functions by dropping them outside the Decoder box. Click on every function for detailed information.", + ) + ) self.label_5.setText(_translate("Decoder", "Number of redundant bits")) - self.label_6.setText(_translate("Decoder", "Carrier (\'1_\' -> 1_1_1_...)")) + self.label_6.setText(_translate("Decoder", "Carrier ('1_' -> 1_1_1_...)")) self.label_10.setText(_translate("Decoder", "Rows")) self.label_11.setText(_translate("Decoder", "Decoder")) self.btnChooseDecoder.setText(_translate("Decoder", "...")) self.label_12.setText(_translate("Decoder", "Encoder")) self.btnChooseEncoder.setText(_translate("Decoder", "...")) - self.label_13.setText(_translate("Decoder", "Synchronization bytes (hex coded)")) - self.label_14.setText(_translate("Decoder", "Data whitening polynomial (LFSR, hex, w/o first bit)")) - self.datawhitening_overwrite_crc.setText(_translate("Decoder", "Overwrite CRC16 field with correct value when encoding")) + self.label_13.setText( + _translate("Decoder", "Synchronization bytes (hex coded)") + ) + self.label_14.setText( + _translate( + "Decoder", "Data whitening polynomial (LFSR, hex, w/o first bit)" + ) + ) + self.datawhitening_overwrite_crc.setText( + _translate( + "Decoder", "Overwrite CRC16 field with correct value when encoding" + ) + ) self.cutmark.setText(_translate("Decoder", "1010")) self.label_15.setText(_translate("Decoder", "Sequence")) self.rB_delbefore.setText(_translate("Decoder", "&Cut before")) @@ -345,13 +396,25 @@ def retranslateUi(self, Decoder): self.rB_delbeforepos.setText(_translate("Decoder", "Cut before")) self.rB_delafterpos.setText(_translate("Decoder", "Cut after")) self.label_16.setText(_translate("Decoder", "Position (in bit)")) - self.label_17.setText(_translate("Decoder", "Maximum (<=) length of 1-sequence for: Low (0)")) - self.label_18.setText(_translate("Decoder", "Minimum (>=) length of 1-sequence for: High (1)")) - self.label_19.setText(_translate("Decoder", "Number of 0s between 1-sequences (just for encoding)")) + self.label_17.setText( + _translate("Decoder", "Maximum (<=) length of 1-sequence for: Low (0)") + ) + self.label_18.setText( + _translate("Decoder", "Minimum (>=) length of 1-sequence for: High (1)") + ) + self.label_19.setText( + _translate( + "Decoder", "Number of 0s between 1-sequences (just for encoding)" + ) + ) self.btnAddtoYourDecoding.setText(_translate("Decoder", "Add to Your Decoding")) self.combobox_signals.setItemText(0, _translate("Decoder", "Test")) self.label_2.setText(_translate("Decoder", "Signal {0,1}:")) self.label_3.setText(_translate("Decoder", "Decoded Bits:")) - self.decoding_errors_label.setText(_translate("Decoder", "[Decoding Errors = 0]")) + self.decoding_errors_label.setText( + _translate("Decoder", "[Decoding Errors = 0]") + ) + + from urh.ui.ListWidget import ListWidget from urh.ui.views.ZoomableGraphicView import ZoomableGraphicView diff --git a/src/urh/ui/ui_filter_bandwidth_dialog.py b/src/urh/ui/ui_filter_bandwidth_dialog.py index 6e5e3d059c..8052e41d8f 100644 --- a/src/urh/ui/ui_filter_bandwidth_dialog.py +++ b/src/urh/ui/ui_filter_bandwidth_dialog.py @@ -16,22 +16,32 @@ def setupUi(self, DialogFilterBandwidth): self.verticalLayout.setSpacing(7) self.verticalLayout.setObjectName("verticalLayout") self.labelExplanation = QtWidgets.QLabel(DialogFilterBandwidth) - sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Preferred, QtWidgets.QSizePolicy.Preferred) + sizePolicy = QtWidgets.QSizePolicy( + QtWidgets.QSizePolicy.Preferred, QtWidgets.QSizePolicy.Preferred + ) sizePolicy.setHorizontalStretch(0) sizePolicy.setVerticalStretch(0) - sizePolicy.setHeightForWidth(self.labelExplanation.sizePolicy().hasHeightForWidth()) + sizePolicy.setHeightForWidth( + self.labelExplanation.sizePolicy().hasHeightForWidth() + ) self.labelExplanation.setSizePolicy(sizePolicy) - self.labelExplanation.setAlignment(QtCore.Qt.AlignJustify|QtCore.Qt.AlignTop) + self.labelExplanation.setAlignment(QtCore.Qt.AlignJustify | QtCore.Qt.AlignTop) self.labelExplanation.setWordWrap(True) self.labelExplanation.setObjectName("labelExplanation") self.verticalLayout.addWidget(self.labelExplanation) self.gridLayout = QtWidgets.QGridLayout() self.gridLayout.setObjectName("gridLayout") - self.doubleSpinBoxCustomBandwidth = QtWidgets.QDoubleSpinBox(DialogFilterBandwidth) - sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Minimum, QtWidgets.QSizePolicy.Fixed) + self.doubleSpinBoxCustomBandwidth = QtWidgets.QDoubleSpinBox( + DialogFilterBandwidth + ) + sizePolicy = QtWidgets.QSizePolicy( + QtWidgets.QSizePolicy.Minimum, QtWidgets.QSizePolicy.Fixed + ) sizePolicy.setHorizontalStretch(0) sizePolicy.setVerticalStretch(0) - sizePolicy.setHeightForWidth(self.doubleSpinBoxCustomBandwidth.sizePolicy().hasHeightForWidth()) + sizePolicy.setHeightForWidth( + self.doubleSpinBoxCustomBandwidth.sizePolicy().hasHeightForWidth() + ) self.doubleSpinBoxCustomBandwidth.setSizePolicy(sizePolicy) self.doubleSpinBoxCustomBandwidth.setDecimals(4) self.doubleSpinBoxCustomBandwidth.setMinimum(0.0001) @@ -89,7 +99,9 @@ def setupUi(self, DialogFilterBandwidth): self.radioButtonVery_Narrow.setObjectName("radioButtonVery_Narrow") self.gridLayout.addWidget(self.radioButtonVery_Narrow, 2, 0, 1, 1) self.label = QtWidgets.QLabel(DialogFilterBandwidth) - sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Preferred, QtWidgets.QSizePolicy.Maximum) + sizePolicy = QtWidgets.QSizePolicy( + QtWidgets.QSizePolicy.Preferred, QtWidgets.QSizePolicy.Maximum + ) sizePolicy.setHorizontalStretch(0) sizePolicy.setVerticalStretch(0) sizePolicy.setHeightForWidth(self.label.sizePolicy().hasHeightForWidth()) @@ -113,7 +125,9 @@ def setupUi(self, DialogFilterBandwidth): self.verticalLayout.addLayout(self.gridLayout) self.buttonBox = QtWidgets.QDialogButtonBox(DialogFilterBandwidth) self.buttonBox.setOrientation(QtCore.Qt.Horizontal) - self.buttonBox.setStandardButtons(QtWidgets.QDialogButtonBox.Cancel|QtWidgets.QDialogButtonBox.Ok) + self.buttonBox.setStandardButtons( + QtWidgets.QDialogButtonBox.Cancel | QtWidgets.QDialogButtonBox.Ok + ) self.buttonBox.setCenterButtons(True) self.buttonBox.setObjectName("buttonBox") self.verticalLayout.addWidget(self.buttonBox) @@ -127,24 +141,59 @@ def setupUi(self, DialogFilterBandwidth): def retranslateUi(self, DialogFilterBandwidth): _translate = QtCore.QCoreApplication.translate - DialogFilterBandwidth.setWindowTitle(_translate("DialogFilterBandwidth", "Configure Filter Bandwidth")) - self.labelExplanation.setText(_translate("DialogFilterBandwidth", "To separate the frequency bands from each other a bandpass filter is used. You can configure the bandwidth of this filter here. The bandwidth determines the length N of the filter kernel. Decreasing the bandwidth will increase the accuracy of the filter, at cost of higher computation time.")) + DialogFilterBandwidth.setWindowTitle( + _translate("DialogFilterBandwidth", "Configure Filter Bandwidth") + ) + self.labelExplanation.setText( + _translate( + "DialogFilterBandwidth", + "To separate the frequency bands from each other a bandpass filter is used. You can configure the bandwidth of this filter here. The bandwidth determines the length N of the filter kernel. Decreasing the bandwidth will increase the accuracy of the filter, at cost of higher computation time.", + ) + ) self.radioButtonCustom.setText(_translate("DialogFilterBandwidth", "Custom")) - self.labelMediumKernelLength.setText(_translate("DialogFilterBandwidth", "TextLabel")) + self.labelMediumKernelLength.setText( + _translate("DialogFilterBandwidth", "TextLabel") + ) self.radioButtonWide.setText(_translate("DialogFilterBandwidth", "Wide")) - self.labelVeryWideKernelLength.setText(_translate("DialogFilterBandwidth", "TextLabel")) + self.labelVeryWideKernelLength.setText( + _translate("DialogFilterBandwidth", "TextLabel") + ) self.radioButtonNarrow.setText(_translate("DialogFilterBandwidth", "Narrow")) - self.labelWideBandwidth.setText(_translate("DialogFilterBandwidth", "TextLabel")) - self.labelVeryNarrowKernelLength.setText(_translate("DialogFilterBandwidth", "TextLabel")) - self.labelBandwidthCaption.setText(_translate("DialogFilterBandwidth", "Bandwidth (Hz)")) - self.labelNarrowBandwidth.setText(_translate("DialogFilterBandwidth", "TextLabel")) - self.labelNarrowKernelLength.setText(_translate("DialogFilterBandwidth", "TextLabel")) - self.labelVeryNarrowBandwidth.setText(_translate("DialogFilterBandwidth", "TextLabel")) - self.labelKernelLengthCaption.setText(_translate("DialogFilterBandwidth", "Kernel Length N")) - self.labelWideKernelLength.setText(_translate("DialogFilterBandwidth", "TextLabel")) - self.radioButtonVery_Wide.setText(_translate("DialogFilterBandwidth", "Very Wide")) - self.radioButtonVery_Narrow.setText(_translate("DialogFilterBandwidth", "Very Narrow")) + self.labelWideBandwidth.setText( + _translate("DialogFilterBandwidth", "TextLabel") + ) + self.labelVeryNarrowKernelLength.setText( + _translate("DialogFilterBandwidth", "TextLabel") + ) + self.labelBandwidthCaption.setText( + _translate("DialogFilterBandwidth", "Bandwidth (Hz)") + ) + self.labelNarrowBandwidth.setText( + _translate("DialogFilterBandwidth", "TextLabel") + ) + self.labelNarrowKernelLength.setText( + _translate("DialogFilterBandwidth", "TextLabel") + ) + self.labelVeryNarrowBandwidth.setText( + _translate("DialogFilterBandwidth", "TextLabel") + ) + self.labelKernelLengthCaption.setText( + _translate("DialogFilterBandwidth", "Kernel Length N") + ) + self.labelWideKernelLength.setText( + _translate("DialogFilterBandwidth", "TextLabel") + ) + self.radioButtonVery_Wide.setText( + _translate("DialogFilterBandwidth", "Very Wide") + ) + self.radioButtonVery_Narrow.setText( + _translate("DialogFilterBandwidth", "Very Narrow") + ) self.label.setText(_translate("DialogFilterBandwidth", "Choose ")) - self.labelVeryWideBandwidth.setText(_translate("DialogFilterBandwidth", "TextLabel")) + self.labelVeryWideBandwidth.setText( + _translate("DialogFilterBandwidth", "TextLabel") + ) self.radioButtonMedium.setText(_translate("DialogFilterBandwidth", "Medium")) - self.labelMediumBandwidth.setText(_translate("DialogFilterBandwidth", "TextLabel")) + self.labelMediumBandwidth.setText( + _translate("DialogFilterBandwidth", "TextLabel") + ) diff --git a/src/urh/ui/ui_filter_dialog.py b/src/urh/ui/ui_filter_dialog.py index 67579252c8..ce5ab27cd6 100644 --- a/src/urh/ui/ui_filter_dialog.py +++ b/src/urh/ui/ui_filter_dialog.py @@ -25,11 +25,15 @@ def setupUi(self, FilterDialog): self.gridLayout.addWidget(self.radioButtonCustomTaps, 9, 0, 1, 1) self.buttonBox = QtWidgets.QDialogButtonBox(FilterDialog) self.buttonBox.setOrientation(QtCore.Qt.Horizontal) - self.buttonBox.setStandardButtons(QtWidgets.QDialogButtonBox.Cancel|QtWidgets.QDialogButtonBox.Ok) + self.buttonBox.setStandardButtons( + QtWidgets.QDialogButtonBox.Cancel | QtWidgets.QDialogButtonBox.Ok + ) self.buttonBox.setCenterButtons(True) self.buttonBox.setObjectName("buttonBox") self.gridLayout.addWidget(self.buttonBox, 15, 0, 1, 2) - spacerItem = QtWidgets.QSpacerItem(20, 40, QtWidgets.QSizePolicy.Minimum, QtWidgets.QSizePolicy.Expanding) + spacerItem = QtWidgets.QSpacerItem( + 20, 40, QtWidgets.QSizePolicy.Minimum, QtWidgets.QSizePolicy.Expanding + ) self.gridLayout.addItem(spacerItem, 16, 0, 1, 1) self.line = QtWidgets.QFrame(FilterDialog) self.line.setFrameShape(QtWidgets.QFrame.HLine) @@ -91,11 +95,35 @@ def retranslateUi(self, FilterDialog): _translate = QtCore.QCoreApplication.translate FilterDialog.setWindowTitle(_translate("FilterDialog", "Configure filter")) self.radioButtonCustomTaps.setText(_translate("FilterDialog", "Custom taps:")) - self.radioButtonMovingAverage.setText(_translate("FilterDialog", "Moving average")) - self.label_4.setText(_translate("FilterDialog", "A DC correction filter will remove the DC component (mean value) of the signal and center it around zero.")) - self.lineEditCustomTaps.setToolTip(_translate("FilterDialog", "

You can configure custom filter taps here either explicit using [0.1, 0.2, 0.3] or with python programming shortcuts like [0.1] * 3 + [0.2] * 4 will result in [0.1, 0.1, 0.1, 0.2, 0.2, 0.2, 0.2]

")) + self.radioButtonMovingAverage.setText( + _translate("FilterDialog", "Moving average") + ) + self.label_4.setText( + _translate( + "FilterDialog", + "A DC correction filter will remove the DC component (mean value) of the signal and center it around zero.", + ) + ) + self.lineEditCustomTaps.setToolTip( + _translate( + "FilterDialog", + '

You can configure custom filter taps here either explicit using [0.1, 0.2, 0.3] or with python programming shortcuts like [0.1] * 3 + [0.2] * 4 will result in [0.1, 0.1, 0.1, 0.2, 0.2, 0.2, 0.2]

', + ) + ) self.lineEditCustomTaps.setText(_translate("FilterDialog", "[0.1]*10")) self.label.setText(_translate("FilterDialog", "Number of taps:")) - self.label_3.setText(_translate("FilterDialog", "You can imagine taps as weighting factors applied to n samples of the signal whereby n is the number of taps. By default we use 10 taps with each tap set to 0.1 producing a moving average filter.")) - self.label_2.setText(_translate("FilterDialog", "These n weighted samples get summed up to produce the output of the filter. In DSP terms you configure the impulse response of the filter here.")) - self.radioButtonDCcorrection.setText(_translate("FilterDialog", "DC correction")) + self.label_3.setText( + _translate( + "FilterDialog", + "You can imagine taps as weighting factors applied to n samples of the signal whereby n is the number of taps. By default we use 10 taps with each tap set to 0.1 producing a moving average filter.", + ) + ) + self.label_2.setText( + _translate( + "FilterDialog", + "These n weighted samples get summed up to produce the output of the filter. In DSP terms you configure the impulse response of the filter here.", + ) + ) + self.radioButtonDCcorrection.setText( + _translate("FilterDialog", "DC correction") + ) diff --git a/src/urh/ui/ui_fuzzing.py b/src/urh/ui/ui_fuzzing.py index bab9a49cd5..2fe82559ab 100644 --- a/src/urh/ui/ui_fuzzing.py +++ b/src/urh/ui/ui_fuzzing.py @@ -15,10 +15,14 @@ def setupUi(self, FuzzingDialog): self.gridLayout_5 = QtWidgets.QGridLayout(FuzzingDialog) self.gridLayout_5.setObjectName("gridLayout_5") self.spinBoxFuzzMessage = QtWidgets.QSpinBox(FuzzingDialog) - sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Preferred, QtWidgets.QSizePolicy.Fixed) + sizePolicy = QtWidgets.QSizePolicy( + QtWidgets.QSizePolicy.Preferred, QtWidgets.QSizePolicy.Fixed + ) sizePolicy.setHorizontalStretch(0) sizePolicy.setVerticalStretch(0) - sizePolicy.setHeightForWidth(self.spinBoxFuzzMessage.sizePolicy().hasHeightForWidth()) + sizePolicy.setHeightForWidth( + self.spinBoxFuzzMessage.sizePolicy().hasHeightForWidth() + ) self.spinBoxFuzzMessage.setSizePolicy(sizePolicy) self.spinBoxFuzzMessage.setMaximum(999999999) self.spinBoxFuzzMessage.setObjectName("spinBoxFuzzMessage") @@ -34,10 +38,14 @@ def setupUi(self, FuzzingDialog): self.btnAddFuzzingValues.setObjectName("btnAddFuzzingValues") self.gridLayout_5.addWidget(self.btnAddFuzzingValues, 9, 1, 1, 1) self.stackedWidgetLabels = QtWidgets.QStackedWidget(FuzzingDialog) - sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Maximum, QtWidgets.QSizePolicy.Preferred) + sizePolicy = QtWidgets.QSizePolicy( + QtWidgets.QSizePolicy.Maximum, QtWidgets.QSizePolicy.Preferred + ) sizePolicy.setHorizontalStretch(0) sizePolicy.setVerticalStretch(0) - sizePolicy.setHeightForWidth(self.stackedWidgetLabels.sizePolicy().hasHeightForWidth()) + sizePolicy.setHeightForWidth( + self.stackedWidgetLabels.sizePolicy().hasHeightForWidth() + ) self.stackedWidgetLabels.setSizePolicy(sizePolicy) self.stackedWidgetLabels.setObjectName("stackedWidgetLabels") self.pageAddRangeLabel = QtWidgets.QWidget() @@ -47,7 +55,9 @@ def setupUi(self, FuzzingDialog): self.verticalLayout_3.setSpacing(6) self.verticalLayout_3.setObjectName("verticalLayout_3") self.lStart = QtWidgets.QLabel(self.pageAddRangeLabel) - sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Maximum, QtWidgets.QSizePolicy.Preferred) + sizePolicy = QtWidgets.QSizePolicy( + QtWidgets.QSizePolicy.Maximum, QtWidgets.QSizePolicy.Preferred + ) sizePolicy.setHorizontalStretch(0) sizePolicy.setVerticalStretch(0) sizePolicy.setHeightForWidth(self.lStart.sizePolicy().hasHeightForWidth()) @@ -55,7 +65,9 @@ def setupUi(self, FuzzingDialog): self.lStart.setObjectName("lStart") self.verticalLayout_3.addWidget(self.lStart) self.lEnd = QtWidgets.QLabel(self.pageAddRangeLabel) - sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Maximum, QtWidgets.QSizePolicy.Preferred) + sizePolicy = QtWidgets.QSizePolicy( + QtWidgets.QSizePolicy.Maximum, QtWidgets.QSizePolicy.Preferred + ) sizePolicy.setHorizontalStretch(0) sizePolicy.setVerticalStretch(0) sizePolicy.setHeightForWidth(self.lEnd.sizePolicy().hasHeightForWidth()) @@ -63,7 +75,9 @@ def setupUi(self, FuzzingDialog): self.lEnd.setObjectName("lEnd") self.verticalLayout_3.addWidget(self.lEnd) self.lStep = QtWidgets.QLabel(self.pageAddRangeLabel) - sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Maximum, QtWidgets.QSizePolicy.Preferred) + sizePolicy = QtWidgets.QSizePolicy( + QtWidgets.QSizePolicy.Maximum, QtWidgets.QSizePolicy.Preferred + ) sizePolicy.setHorizontalStretch(0) sizePolicy.setVerticalStretch(0) sizePolicy.setHeightForWidth(self.lStep.sizePolicy().hasHeightForWidth()) @@ -86,10 +100,14 @@ def setupUi(self, FuzzingDialog): self.checkBoxUpperBound.setObjectName("checkBoxUpperBound") self.verticalLayout_4.addWidget(self.checkBoxUpperBound) self.lNumberBoundaries = QtWidgets.QLabel(self.pageAddBoundariesLabel) - sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Preferred, QtWidgets.QSizePolicy.Fixed) + sizePolicy = QtWidgets.QSizePolicy( + QtWidgets.QSizePolicy.Preferred, QtWidgets.QSizePolicy.Fixed + ) sizePolicy.setHorizontalStretch(0) sizePolicy.setVerticalStretch(0) - sizePolicy.setHeightForWidth(self.lNumberBoundaries.sizePolicy().hasHeightForWidth()) + sizePolicy.setHeightForWidth( + self.lNumberBoundaries.sizePolicy().hasHeightForWidth() + ) self.lNumberBoundaries.setSizePolicy(sizePolicy) self.lNumberBoundaries.setObjectName("lNumberBoundaries") self.verticalLayout_4.addWidget(self.lNumberBoundaries) @@ -117,7 +135,9 @@ def setupUi(self, FuzzingDialog): self.lPreBits.setObjectName("lPreBits") self.horizontalLayout_2.addWidget(self.lPreBits) self.lFuzzedBits = QtWidgets.QLabel(FuzzingDialog) - sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Preferred, QtWidgets.QSizePolicy.Preferred) + sizePolicy = QtWidgets.QSizePolicy( + QtWidgets.QSizePolicy.Preferred, QtWidgets.QSizePolicy.Preferred + ) sizePolicy.setHorizontalStretch(0) sizePolicy.setVerticalStretch(0) sizePolicy.setHeightForWidth(self.lFuzzedBits.sizePolicy().hasHeightForWidth()) @@ -130,19 +150,27 @@ def setupUi(self, FuzzingDialog): self.lFuzzedBits.setObjectName("lFuzzedBits") self.horizontalLayout_2.addWidget(self.lFuzzedBits) self.lPostBits = QtWidgets.QLabel(FuzzingDialog) - self.lPostBits.setAlignment(QtCore.Qt.AlignRight|QtCore.Qt.AlignTrailing|QtCore.Qt.AlignVCenter) + self.lPostBits.setAlignment( + QtCore.Qt.AlignRight | QtCore.Qt.AlignTrailing | QtCore.Qt.AlignVCenter + ) self.lPostBits.setObjectName("lPostBits") self.horizontalLayout_2.addWidget(self.lPostBits) - spacerItem = QtWidgets.QSpacerItem(40, 20, QtWidgets.QSizePolicy.Expanding, QtWidgets.QSizePolicy.Minimum) + spacerItem = QtWidgets.QSpacerItem( + 40, 20, QtWidgets.QSizePolicy.Expanding, QtWidgets.QSizePolicy.Minimum + ) self.horizontalLayout_2.addItem(spacerItem) self.gridLayout_5.addLayout(self.horizontalLayout_2, 1, 1, 1, 1) self.verticalLayout = QtWidgets.QVBoxLayout() self.verticalLayout.setObjectName("verticalLayout") self.lFuzzedValues = QtWidgets.QLabel(FuzzingDialog) - sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Preferred, QtWidgets.QSizePolicy.Fixed) + sizePolicy = QtWidgets.QSizePolicy( + QtWidgets.QSizePolicy.Preferred, QtWidgets.QSizePolicy.Fixed + ) sizePolicy.setHorizontalStretch(0) sizePolicy.setVerticalStretch(0) - sizePolicy.setHeightForWidth(self.lFuzzedValues.sizePolicy().hasHeightForWidth()) + sizePolicy.setHeightForWidth( + self.lFuzzedValues.sizePolicy().hasHeightForWidth() + ) self.lFuzzedValues.setSizePolicy(sizePolicy) font = QtGui.QFont() font.setBold(True) @@ -162,20 +190,30 @@ def setupUi(self, FuzzingDialog): self.btnDelRow.setObjectName("btnDelRow") self.gridLayout_4.addWidget(self.btnDelRow, 1, 1, 1, 1) self.tblFuzzingValues = FuzzingTableView(FuzzingDialog) - sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Expanding, QtWidgets.QSizePolicy.Expanding) + sizePolicy = QtWidgets.QSizePolicy( + QtWidgets.QSizePolicy.Expanding, QtWidgets.QSizePolicy.Expanding + ) sizePolicy.setHorizontalStretch(0) sizePolicy.setVerticalStretch(0) - sizePolicy.setHeightForWidth(self.tblFuzzingValues.sizePolicy().hasHeightForWidth()) + sizePolicy.setHeightForWidth( + self.tblFuzzingValues.sizePolicy().hasHeightForWidth() + ) self.tblFuzzingValues.setSizePolicy(sizePolicy) self.tblFuzzingValues.setAlternatingRowColors(True) - self.tblFuzzingValues.setVerticalScrollMode(QtWidgets.QAbstractItemView.ScrollPerPixel) - self.tblFuzzingValues.setHorizontalScrollMode(QtWidgets.QAbstractItemView.ScrollPerPixel) + self.tblFuzzingValues.setVerticalScrollMode( + QtWidgets.QAbstractItemView.ScrollPerPixel + ) + self.tblFuzzingValues.setHorizontalScrollMode( + QtWidgets.QAbstractItemView.ScrollPerPixel + ) self.tblFuzzingValues.setShowGrid(False) self.tblFuzzingValues.setObjectName("tblFuzzingValues") self.tblFuzzingValues.horizontalHeader().setHighlightSections(False) self.tblFuzzingValues.verticalHeader().setHighlightSections(False) self.gridLayout_4.addWidget(self.tblFuzzingValues, 0, 0, 4, 1) - spacerItem1 = QtWidgets.QSpacerItem(20, 40, QtWidgets.QSizePolicy.Minimum, QtWidgets.QSizePolicy.Expanding) + spacerItem1 = QtWidgets.QSpacerItem( + 20, 40, QtWidgets.QSizePolicy.Minimum, QtWidgets.QSizePolicy.Expanding + ) self.gridLayout_4.addItem(spacerItem1, 3, 1, 1, 1) self.btnAddRow = QtWidgets.QToolButton(FuzzingDialog) icon = QtGui.QIcon.fromTheme("list-add") @@ -247,7 +285,9 @@ def setupUi(self, FuzzingDialog): self.stackedWidgetSpinboxes.addWidget(self.pageAddRandom) self.gridLayout_5.addWidget(self.stackedWidgetSpinboxes, 7, 1, 2, 1) self.lSourceBlock = QtWidgets.QLabel(FuzzingDialog) - sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Maximum, QtWidgets.QSizePolicy.Maximum) + sizePolicy = QtWidgets.QSizePolicy( + QtWidgets.QSizePolicy.Maximum, QtWidgets.QSizePolicy.Maximum + ) sizePolicy.setHorizontalStretch(0) sizePolicy.setVerticalStretch(0) sizePolicy.setHeightForWidth(self.lSourceBlock.sizePolicy().hasHeightForWidth()) @@ -255,15 +295,21 @@ def setupUi(self, FuzzingDialog): self.lSourceBlock.setObjectName("lSourceBlock") self.gridLayout_5.addWidget(self.lSourceBlock, 1, 0, 1, 1) self.lFuzzingReferenceBlock = QtWidgets.QLabel(FuzzingDialog) - sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Maximum, QtWidgets.QSizePolicy.Preferred) + sizePolicy = QtWidgets.QSizePolicy( + QtWidgets.QSizePolicy.Maximum, QtWidgets.QSizePolicy.Preferred + ) sizePolicy.setHorizontalStretch(0) sizePolicy.setVerticalStretch(0) - sizePolicy.setHeightForWidth(self.lFuzzingReferenceBlock.sizePolicy().hasHeightForWidth()) + sizePolicy.setHeightForWidth( + self.lFuzzingReferenceBlock.sizePolicy().hasHeightForWidth() + ) self.lFuzzingReferenceBlock.setSizePolicy(sizePolicy) self.lFuzzingReferenceBlock.setObjectName("lFuzzingReferenceBlock") self.gridLayout_5.addWidget(self.lFuzzingReferenceBlock, 2, 0, 1, 1) self.lFuzzingEnd = QtWidgets.QLabel(FuzzingDialog) - sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Maximum, QtWidgets.QSizePolicy.Maximum) + sizePolicy = QtWidgets.QSizePolicy( + QtWidgets.QSizePolicy.Maximum, QtWidgets.QSizePolicy.Maximum + ) sizePolicy.setHorizontalStretch(0) sizePolicy.setVerticalStretch(0) sizePolicy.setHeightForWidth(self.lFuzzingEnd.sizePolicy().hasHeightForWidth()) @@ -274,48 +320,68 @@ def setupUi(self, FuzzingDialog): self.lStrategy.setObjectName("lStrategy") self.gridLayout_5.addWidget(self.lStrategy, 6, 0, 1, 1) self.comboBoxFuzzingLabel = QtWidgets.QComboBox(FuzzingDialog) - sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Preferred, QtWidgets.QSizePolicy.Fixed) + sizePolicy = QtWidgets.QSizePolicy( + QtWidgets.QSizePolicy.Preferred, QtWidgets.QSizePolicy.Fixed + ) sizePolicy.setHorizontalStretch(0) sizePolicy.setVerticalStretch(0) - sizePolicy.setHeightForWidth(self.comboBoxFuzzingLabel.sizePolicy().hasHeightForWidth()) + sizePolicy.setHeightForWidth( + self.comboBoxFuzzingLabel.sizePolicy().hasHeightForWidth() + ) self.comboBoxFuzzingLabel.setSizePolicy(sizePolicy) self.comboBoxFuzzingLabel.setMaximumSize(QtCore.QSize(16777215, 16777215)) self.comboBoxFuzzingLabel.setEditable(True) self.comboBoxFuzzingLabel.setObjectName("comboBoxFuzzingLabel") self.gridLayout_5.addWidget(self.comboBoxFuzzingLabel, 0, 1, 1, 1) self.spinBoxFuzzingEnd = QtWidgets.QSpinBox(FuzzingDialog) - sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Preferred, QtWidgets.QSizePolicy.Fixed) + sizePolicy = QtWidgets.QSizePolicy( + QtWidgets.QSizePolicy.Preferred, QtWidgets.QSizePolicy.Fixed + ) sizePolicy.setHorizontalStretch(0) sizePolicy.setVerticalStretch(0) - sizePolicy.setHeightForWidth(self.spinBoxFuzzingEnd.sizePolicy().hasHeightForWidth()) + sizePolicy.setHeightForWidth( + self.spinBoxFuzzingEnd.sizePolicy().hasHeightForWidth() + ) self.spinBoxFuzzingEnd.setSizePolicy(sizePolicy) self.spinBoxFuzzingEnd.setMinimum(1) self.spinBoxFuzzingEnd.setMaximum(999999999) self.spinBoxFuzzingEnd.setObjectName("spinBoxFuzzingEnd") self.gridLayout_5.addWidget(self.spinBoxFuzzingEnd, 4, 1, 1, 1) self.spinBoxFuzzingStart = QtWidgets.QSpinBox(FuzzingDialog) - sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Preferred, QtWidgets.QSizePolicy.Fixed) + sizePolicy = QtWidgets.QSizePolicy( + QtWidgets.QSizePolicy.Preferred, QtWidgets.QSizePolicy.Fixed + ) sizePolicy.setHorizontalStretch(0) sizePolicy.setVerticalStretch(0) - sizePolicy.setHeightForWidth(self.spinBoxFuzzingStart.sizePolicy().hasHeightForWidth()) + sizePolicy.setHeightForWidth( + self.spinBoxFuzzingStart.sizePolicy().hasHeightForWidth() + ) self.spinBoxFuzzingStart.setSizePolicy(sizePolicy) self.spinBoxFuzzingStart.setMinimum(1) self.spinBoxFuzzingStart.setMaximum(999999999) self.spinBoxFuzzingStart.setObjectName("spinBoxFuzzingStart") self.gridLayout_5.addWidget(self.spinBoxFuzzingStart, 3, 1, 1, 1) self.lFuzzingStart = QtWidgets.QLabel(FuzzingDialog) - sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Maximum, QtWidgets.QSizePolicy.Maximum) + sizePolicy = QtWidgets.QSizePolicy( + QtWidgets.QSizePolicy.Maximum, QtWidgets.QSizePolicy.Maximum + ) sizePolicy.setHorizontalStretch(0) sizePolicy.setVerticalStretch(0) - sizePolicy.setHeightForWidth(self.lFuzzingStart.sizePolicy().hasHeightForWidth()) + sizePolicy.setHeightForWidth( + self.lFuzzingStart.sizePolicy().hasHeightForWidth() + ) self.lFuzzingStart.setSizePolicy(sizePolicy) self.lFuzzingStart.setObjectName("lFuzzingStart") self.gridLayout_5.addWidget(self.lFuzzingStart, 3, 0, 1, 1) self.lFuzzingLabel = QtWidgets.QLabel(FuzzingDialog) - sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Maximum, QtWidgets.QSizePolicy.Preferred) + sizePolicy = QtWidgets.QSizePolicy( + QtWidgets.QSizePolicy.Maximum, QtWidgets.QSizePolicy.Preferred + ) sizePolicy.setHorizontalStretch(0) sizePolicy.setVerticalStretch(0) - sizePolicy.setHeightForWidth(self.lFuzzingLabel.sizePolicy().hasHeightForWidth()) + sizePolicy.setHeightForWidth( + self.lFuzzingLabel.sizePolicy().hasHeightForWidth() + ) self.lFuzzingLabel.setSizePolicy(sizePolicy) self.lFuzzingLabel.setObjectName("lFuzzingLabel") self.gridLayout_5.addWidget(self.lFuzzingLabel, 0, 0, 1, 1) @@ -323,23 +389,39 @@ def setupUi(self, FuzzingDialog): self.retranslateUi(FuzzingDialog) self.stackedWidgetLabels.setCurrentIndex(0) self.stackedWidgetSpinboxes.setCurrentIndex(0) - self.comboBoxStrategy.currentIndexChanged['int'].connect(self.stackedWidgetLabels.setCurrentIndex) - self.comboBoxStrategy.currentIndexChanged['int'].connect(self.stackedWidgetSpinboxes.setCurrentIndex) + self.comboBoxStrategy.currentIndexChanged["int"].connect( + self.stackedWidgetLabels.setCurrentIndex + ) + self.comboBoxStrategy.currentIndexChanged["int"].connect( + self.stackedWidgetSpinboxes.setCurrentIndex + ) def retranslateUi(self, FuzzingDialog): _translate = QtCore.QCoreApplication.translate FuzzingDialog.setWindowTitle(_translate("FuzzingDialog", "Fuzzing")) - self.comboBoxStrategy.setItemText(0, _translate("FuzzingDialog", "Add Range of Values")) - self.comboBoxStrategy.setItemText(1, _translate("FuzzingDialog", "Add Boundaries")) - self.comboBoxStrategy.setItemText(2, _translate("FuzzingDialog", "Add Random Values from Range")) - self.comboBoxStrategy.setItemText(3, _translate("FuzzingDialog", "Add De Bruijn Sequence")) - self.btnAddFuzzingValues.setText(_translate("FuzzingDialog", "Add to Fuzzed Values")) + self.comboBoxStrategy.setItemText( + 0, _translate("FuzzingDialog", "Add Range of Values") + ) + self.comboBoxStrategy.setItemText( + 1, _translate("FuzzingDialog", "Add Boundaries") + ) + self.comboBoxStrategy.setItemText( + 2, _translate("FuzzingDialog", "Add Random Values from Range") + ) + self.comboBoxStrategy.setItemText( + 3, _translate("FuzzingDialog", "Add De Bruijn Sequence") + ) + self.btnAddFuzzingValues.setText( + _translate("FuzzingDialog", "Add to Fuzzed Values") + ) self.lStart.setText(_translate("FuzzingDialog", "Start (Decimal):")) self.lEnd.setText(_translate("FuzzingDialog", "End (Decimal):")) self.lStep.setText(_translate("FuzzingDialog", "Step (Decimal):")) self.checkBoxLowerBound.setText(_translate("FuzzingDialog", "Lower Bound")) self.checkBoxUpperBound.setText(_translate("FuzzingDialog", "Upper Bound")) - self.lNumberBoundaries.setText(_translate("FuzzingDialog", "Values per Boundary:")) + self.lNumberBoundaries.setText( + _translate("FuzzingDialog", "Values per Boundary:") + ) self.lRandomMin.setText(_translate("FuzzingDialog", "Range Minimum:")) self.lRandomMax.setText(_translate("FuzzingDialog", "Range Maximum:")) self.lNumRandom.setText(_translate("FuzzingDialog", "Number Values:")) @@ -347,17 +429,37 @@ def retranslateUi(self, FuzzingDialog): self.lFuzzedBits.setText(_translate("FuzzingDialog", "1010")) self.lPostBits.setText(_translate("FuzzingDialog", "010101")) self.lFuzzedValues.setText(_translate("FuzzingDialog", "Fuzzed Values")) - self.chkBRemoveDuplicates.setText(_translate("FuzzingDialog", "Remove Duplicates")) - self.btnDelRow.setToolTip(_translate("FuzzingDialog", "Remove selected values or last value if nothing is selected.")) + self.chkBRemoveDuplicates.setText( + _translate("FuzzingDialog", "Remove Duplicates") + ) + self.btnDelRow.setToolTip( + _translate( + "FuzzingDialog", + "Remove selected values or last value if nothing is selected.", + ) + ) self.btnDelRow.setText(_translate("FuzzingDialog", "...")) self.btnAddRow.setToolTip(_translate("FuzzingDialog", "Add a new value.")) self.btnAddRow.setText(_translate("FuzzingDialog", "...")) - self.btnRepeatValues.setToolTip(_translate("FuzzingDialog", "Repeat selected values or all values if nothing is selected.")) + self.btnRepeatValues.setToolTip( + _translate( + "FuzzingDialog", + "Repeat selected values or all values if nothing is selected.", + ) + ) self.btnRepeatValues.setText(_translate("FuzzingDialog", "...")) self.lSourceBlock.setText(_translate("FuzzingDialog", "Source Message:")) - self.lFuzzingReferenceBlock.setText(_translate("FuzzingDialog", "Message to fuzz:")) - self.lFuzzingEnd.setText(_translate("FuzzingDialog", "Fuzzing Label End Index:")) + self.lFuzzingReferenceBlock.setText( + _translate("FuzzingDialog", "Message to fuzz:") + ) + self.lFuzzingEnd.setText( + _translate("FuzzingDialog", "Fuzzing Label End Index:") + ) self.lStrategy.setText(_translate("FuzzingDialog", "Strategy:")) - self.lFuzzingStart.setText(_translate("FuzzingDialog", "Fuzzing Label Start Index:")) + self.lFuzzingStart.setText( + _translate("FuzzingDialog", "Fuzzing Label Start Index:") + ) self.lFuzzingLabel.setText(_translate("FuzzingDialog", "Fuzzing Label:")) + + from urh.ui.views.FuzzingTableView import FuzzingTableView diff --git a/src/urh/ui/ui_generator.py b/src/urh/ui/ui_generator.py index ed40fd8a6e..825c8935f9 100644 --- a/src/urh/ui/ui_generator.py +++ b/src/urh/ui/ui_generator.py @@ -27,14 +27,16 @@ def setupUi(self, GeneratorTab): self.verticalLayout_2 = QtWidgets.QVBoxLayout(self.scrollAreaWidgetContents) self.verticalLayout_2.setObjectName("verticalLayout_2") self.splitter = QtWidgets.QSplitter(self.scrollAreaWidgetContents) - self.splitter.setStyleSheet("QSplitter::handle:horizontal {\n" -"margin: 4px 0px;\n" -" background-color: qlineargradient(x1:0, y1:0, x2:0, y2:1, \n" -"stop:0 rgba(255, 255, 255, 0), \n" -"stop:0.5 rgba(100, 100, 100, 100), \n" -"stop:1 rgba(255, 255, 255, 0));\n" -"image: url(:/icons/icons/splitter_handle_vertical.svg);\n" -"}") + self.splitter.setStyleSheet( + "QSplitter::handle:horizontal {\n" + "margin: 4px 0px;\n" + " background-color: qlineargradient(x1:0, y1:0, x2:0, y2:1, \n" + "stop:0 rgba(255, 255, 255, 0), \n" + "stop:0.5 rgba(100, 100, 100, 100), \n" + "stop:1 rgba(255, 255, 255, 0));\n" + "image: url(:/icons/icons/splitter_handle_vertical.svg);\n" + "}" + ) self.splitter.setOrientation(QtCore.Qt.Horizontal) self.splitter.setHandleWidth(6) self.splitter.setObjectName("splitter") @@ -44,7 +46,9 @@ def setupUi(self, GeneratorTab): self.verticalLayout.setContentsMargins(11, 11, 11, 11) self.verticalLayout.setObjectName("verticalLayout") self.tabWidget = QtWidgets.QTabWidget(self.layoutWidget_2) - sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Expanding, QtWidgets.QSizePolicy.Expanding) + sizePolicy = QtWidgets.QSizePolicy( + QtWidgets.QSizePolicy.Expanding, QtWidgets.QSizePolicy.Expanding + ) sizePolicy.setHorizontalStretch(0) sizePolicy.setVerticalStretch(0) sizePolicy.setHeightForWidth(self.tabWidget.sizePolicy().hasHeightForWidth()) @@ -59,10 +63,14 @@ def setupUi(self, GeneratorTab): self.verticalLayout_4.setContentsMargins(0, 0, 0, 0) self.verticalLayout_4.setObjectName("verticalLayout_4") self.treeProtocols = GeneratorTreeView(self.tab_proto) - sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Preferred, QtWidgets.QSizePolicy.Expanding) + sizePolicy = QtWidgets.QSizePolicy( + QtWidgets.QSizePolicy.Preferred, QtWidgets.QSizePolicy.Expanding + ) sizePolicy.setHorizontalStretch(0) sizePolicy.setVerticalStretch(0) - sizePolicy.setHeightForWidth(self.treeProtocols.sizePolicy().hasHeightForWidth()) + sizePolicy.setHeightForWidth( + self.treeProtocols.sizePolicy().hasHeightForWidth() + ) self.treeProtocols.setSizePolicy(sizePolicy) self.treeProtocols.setObjectName("treeProtocols") self.treeProtocols.header().setDefaultSectionSize(57) @@ -74,12 +82,17 @@ def setupUi(self, GeneratorTab): self.gridLayout_5.setContentsMargins(0, 0, 0, 0) self.gridLayout_5.setObjectName("gridLayout_5") self.lWPauses = GeneratorListWidget(self.tab_pauses) - sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Expanding, QtWidgets.QSizePolicy.Expanding) + sizePolicy = QtWidgets.QSizePolicy( + QtWidgets.QSizePolicy.Expanding, QtWidgets.QSizePolicy.Expanding + ) sizePolicy.setHorizontalStretch(0) sizePolicy.setVerticalStretch(0) sizePolicy.setHeightForWidth(self.lWPauses.sizePolicy().hasHeightForWidth()) self.lWPauses.setSizePolicy(sizePolicy) - self.lWPauses.setEditTriggers(QtWidgets.QAbstractItemView.DoubleClicked|QtWidgets.QAbstractItemView.EditKeyPressed) + self.lWPauses.setEditTriggers( + QtWidgets.QAbstractItemView.DoubleClicked + | QtWidgets.QAbstractItemView.EditKeyPressed + ) self.lWPauses.setProperty("showDropIndicator", False) self.lWPauses.setDragDropMode(QtWidgets.QAbstractItemView.NoDragDrop) self.lWPauses.setObjectName("lWPauses") @@ -92,12 +105,18 @@ def setupUi(self, GeneratorTab): self.verticalLayout_9.setSpacing(6) self.verticalLayout_9.setObjectName("verticalLayout_9") self.listViewProtoLabels = GeneratorListView(self.tab_fuzzing) - sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Expanding, QtWidgets.QSizePolicy.Expanding) + sizePolicy = QtWidgets.QSizePolicy( + QtWidgets.QSizePolicy.Expanding, QtWidgets.QSizePolicy.Expanding + ) sizePolicy.setHorizontalStretch(0) sizePolicy.setVerticalStretch(0) - sizePolicy.setHeightForWidth(self.listViewProtoLabels.sizePolicy().hasHeightForWidth()) + sizePolicy.setHeightForWidth( + self.listViewProtoLabels.sizePolicy().hasHeightForWidth() + ) self.listViewProtoLabels.setSizePolicy(sizePolicy) - self.listViewProtoLabels.setEditTriggers(QtWidgets.QAbstractItemView.EditKeyPressed) + self.listViewProtoLabels.setEditTriggers( + QtWidgets.QAbstractItemView.EditKeyPressed + ) self.listViewProtoLabels.setObjectName("listViewProtoLabels") self.verticalLayout_9.addWidget(self.listViewProtoLabels) self.groupBox = QtWidgets.QGroupBox(self.tab_fuzzing) @@ -105,10 +124,14 @@ def setupUi(self, GeneratorTab): self.horizontalLayout_6 = QtWidgets.QHBoxLayout(self.groupBox) self.horizontalLayout_6.setObjectName("horizontalLayout_6") self.stackedWidgetFuzzing = QtWidgets.QStackedWidget(self.groupBox) - sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Preferred, QtWidgets.QSizePolicy.Maximum) + sizePolicy = QtWidgets.QSizePolicy( + QtWidgets.QSizePolicy.Preferred, QtWidgets.QSizePolicy.Maximum + ) sizePolicy.setHorizontalStretch(0) sizePolicy.setVerticalStretch(0) - sizePolicy.setHeightForWidth(self.stackedWidgetFuzzing.sizePolicy().hasHeightForWidth()) + sizePolicy.setHeightForWidth( + self.stackedWidgetFuzzing.sizePolicy().hasHeightForWidth() + ) self.stackedWidgetFuzzing.setSizePolicy(sizePolicy) self.stackedWidgetFuzzing.setObjectName("stackedWidgetFuzzing") self.pageFuzzingUI = QtWidgets.QWidget() @@ -177,10 +200,14 @@ def setupUi(self, GeneratorTab): self.lEncoding.setObjectName("lEncoding") self.modulationLayout_2.addWidget(self.lEncoding, 0, 0, 1, 1) self.lEncodingValue = QtWidgets.QLabel(self.layoutWidget_2) - sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Preferred, QtWidgets.QSizePolicy.Preferred) + sizePolicy = QtWidgets.QSizePolicy( + QtWidgets.QSizePolicy.Preferred, QtWidgets.QSizePolicy.Preferred + ) sizePolicy.setHorizontalStretch(0) sizePolicy.setVerticalStretch(0) - sizePolicy.setHeightForWidth(self.lEncodingValue.sizePolicy().hasHeightForWidth()) + sizePolicy.setHeightForWidth( + self.lEncodingValue.sizePolicy().hasHeightForWidth() + ) self.lEncodingValue.setSizePolicy(sizePolicy) self.lEncodingValue.setObjectName("lEncodingValue") self.modulationLayout_2.addWidget(self.lEncodingValue, 0, 1, 1, 1) @@ -216,10 +243,14 @@ def setupUi(self, GeneratorTab): self.cBoxModulations.addItem("") self.gridLayout_6.addWidget(self.cBoxModulations, 2, 1, 1, 1) self.prBarGeneration = QtWidgets.QProgressBar(self.layoutWidget_2) - sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Minimum, QtWidgets.QSizePolicy.Fixed) + sizePolicy = QtWidgets.QSizePolicy( + QtWidgets.QSizePolicy.Minimum, QtWidgets.QSizePolicy.Fixed + ) sizePolicy.setHorizontalStretch(0) sizePolicy.setVerticalStretch(0) - sizePolicy.setHeightForWidth(self.prBarGeneration.sizePolicy().hasHeightForWidth()) + sizePolicy.setHeightForWidth( + self.prBarGeneration.sizePolicy().hasHeightForWidth() + ) self.prBarGeneration.setSizePolicy(sizePolicy) self.prBarGeneration.setProperty("value", 0) self.prBarGeneration.setObjectName("prBarGeneration") @@ -257,8 +288,12 @@ def setupUi(self, GeneratorTab): self.tableMessages.setDefaultDropAction(QtCore.Qt.CopyAction) self.tableMessages.setAlternatingRowColors(True) self.tableMessages.setSelectionBehavior(QtWidgets.QAbstractItemView.SelectItems) - self.tableMessages.setVerticalScrollMode(QtWidgets.QAbstractItemView.ScrollPerPixel) - self.tableMessages.setHorizontalScrollMode(QtWidgets.QAbstractItemView.ScrollPerPixel) + self.tableMessages.setVerticalScrollMode( + QtWidgets.QAbstractItemView.ScrollPerPixel + ) + self.tableMessages.setHorizontalScrollMode( + QtWidgets.QAbstractItemView.ScrollPerPixel + ) self.tableMessages.setShowGrid(False) self.tableMessages.setObjectName("tableMessages") self.tableMessages.horizontalHeader().setHighlightSections(False) @@ -270,7 +305,9 @@ def setupUi(self, GeneratorTab): self.btnNetworkSDRSend.setCheckable(True) self.btnNetworkSDRSend.setObjectName("btnNetworkSDRSend") self.gridLayout_2.addWidget(self.btnNetworkSDRSend, 2, 0, 1, 1) - spacerItem = QtWidgets.QSpacerItem(38, 22, QtWidgets.QSizePolicy.Expanding, QtWidgets.QSizePolicy.Minimum) + spacerItem = QtWidgets.QSpacerItem( + 38, 22, QtWidgets.QSizePolicy.Expanding, QtWidgets.QSizePolicy.Minimum + ) self.gridLayout_2.addItem(spacerItem, 2, 4, 1, 2) self.cbViewType = QtWidgets.QComboBox(self.layoutWidget) self.cbViewType.setObjectName("cbViewType") @@ -279,7 +316,9 @@ def setupUi(self, GeneratorTab): self.cbViewType.addItem("") self.gridLayout_2.addWidget(self.cbViewType, 2, 7, 1, 1) self.lViewType = QtWidgets.QLabel(self.layoutWidget) - sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Fixed, QtWidgets.QSizePolicy.Preferred) + sizePolicy = QtWidgets.QSizePolicy( + QtWidgets.QSizePolicy.Fixed, QtWidgets.QSizePolicy.Preferred + ) sizePolicy.setHorizontalStretch(0) sizePolicy.setVerticalStretch(0) sizePolicy.setHeightForWidth(self.lViewType.sizePolicy().hasHeightForWidth()) @@ -295,10 +334,14 @@ def setupUi(self, GeneratorTab): self.horizontalLayout.setContentsMargins(-1, 0, -1, 0) self.horizontalLayout.setObjectName("horizontalLayout") self.labelGeneratedData = QtWidgets.QLabel(self.layoutWidget) - sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Preferred, QtWidgets.QSizePolicy.Preferred) + sizePolicy = QtWidgets.QSizePolicy( + QtWidgets.QSizePolicy.Preferred, QtWidgets.QSizePolicy.Preferred + ) sizePolicy.setHorizontalStretch(0) sizePolicy.setVerticalStretch(0) - sizePolicy.setHeightForWidth(self.labelGeneratedData.sizePolicy().hasHeightForWidth()) + sizePolicy.setHeightForWidth( + self.labelGeneratedData.sizePolicy().hasHeightForWidth() + ) self.labelGeneratedData.setSizePolicy(sizePolicy) font = QtGui.QFont() font.setBold(True) @@ -308,7 +351,9 @@ def setupUi(self, GeneratorTab): self.labelGeneratedData.setObjectName("labelGeneratedData") self.horizontalLayout.addWidget(self.labelGeneratedData) self.btnSave = QtWidgets.QToolButton(self.layoutWidget) - sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Fixed, QtWidgets.QSizePolicy.Preferred) + sizePolicy = QtWidgets.QSizePolicy( + QtWidgets.QSizePolicy.Fixed, QtWidgets.QSizePolicy.Preferred + ) sizePolicy.setHorizontalStretch(0) sizePolicy.setVerticalStretch(0) sizePolicy.setHeightForWidth(self.btnSave.sizePolicy().hasHeightForWidth()) @@ -318,7 +363,9 @@ def setupUi(self, GeneratorTab): self.btnSave.setObjectName("btnSave") self.horizontalLayout.addWidget(self.btnSave) self.btnOpen = QtWidgets.QToolButton(self.layoutWidget) - sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Fixed, QtWidgets.QSizePolicy.Preferred) + sizePolicy = QtWidgets.QSizePolicy( + QtWidgets.QSizePolicy.Fixed, QtWidgets.QSizePolicy.Preferred + ) sizePolicy.setHorizontalStretch(0) sizePolicy.setVerticalStretch(0) sizePolicy.setHeightForWidth(self.btnOpen.sizePolicy().hasHeightForWidth()) @@ -347,20 +394,56 @@ def setupUi(self, GeneratorTab): def retranslateUi(self, GeneratorTab): _translate = QtCore.QCoreApplication.translate GeneratorTab.setWindowTitle(_translate("GeneratorTab", "Form")) - self.treeProtocols.setToolTip(_translate("GeneratorTab", "

Drag&Drop Protocols to the table on the right to fill the generation table.

")) - self.tabWidget.setTabText(self.tabWidget.indexOf(self.tab_proto), _translate("GeneratorTab", "Protocols")) - self.lWPauses.setToolTip(_translate("GeneratorTab", "

The pauses will be added automatically when you drag a protocol from the tree above to the table on the right.

You can see the position of each pause by selecting it. There will be drawn a line in the table indicating the position of the pause.

Use context menu or double click to edit a pauses\' length.

")) - self.tabWidget.setTabText(self.tabWidget.indexOf(self.tab_pauses), _translate("GeneratorTab", "Pauses")) - self.groupBox.setTitle(_translate("GeneratorTab", "Add fuzzing values to generated data")) + self.treeProtocols.setToolTip( + _translate( + "GeneratorTab", + "

Drag&Drop Protocols to the table on the right to fill the generation table.

", + ) + ) + self.tabWidget.setTabText( + self.tabWidget.indexOf(self.tab_proto), + _translate("GeneratorTab", "Protocols"), + ) + self.lWPauses.setToolTip( + _translate( + "GeneratorTab", + '

The pauses will be added automatically when you drag a protocol from the tree above to the table on the right.

You can see the position of each pause by selecting it. There will be drawn a line in the table indicating the position of the pause.

Use context menu or double click to edit a pauses\' length.

', + ) + ) + self.tabWidget.setTabText( + self.tabWidget.indexOf(self.tab_pauses), + _translate("GeneratorTab", "Pauses"), + ) + self.groupBox.setTitle( + _translate("GeneratorTab", "Add fuzzing values to generated data") + ) self.btnFuzz.setText(_translate("GeneratorTab", "Fuzz")) - self.rBSuccessive.setToolTip(_translate("GeneratorTab", "

For multiple labels per message the fuzzed values are inserted one-by-one.

")) + self.rBSuccessive.setToolTip( + _translate( + "GeneratorTab", + '

For multiple labels per message the fuzzed values are inserted one-by-one.

', + ) + ) self.rBSuccessive.setText(_translate("GeneratorTab", "S&uccessive")) - self.rbConcurrent.setToolTip(_translate("GeneratorTab", "

For multiple labels per message the labels are fuzzed at the same time.

")) + self.rbConcurrent.setToolTip( + _translate( + "GeneratorTab", + '

For multiple labels per message the labels are fuzzed at the same time.

', + ) + ) self.rbConcurrent.setText(_translate("GeneratorTab", "&Concurrent")) - self.rBExhaustive.setToolTip(_translate("GeneratorTab", "

For multiple labels per message the fuzzed values are inserted in all possible combinations.

")) + self.rBExhaustive.setToolTip( + _translate( + "GeneratorTab", + '

For multiple labels per message the fuzzed values are inserted in all possible combinations.

', + ) + ) self.rBExhaustive.setText(_translate("GeneratorTab", "E&xhaustive")) self.progressBarFuzzing.setFormat(_translate("GeneratorTab", "%v/%m")) - self.tabWidget.setTabText(self.tabWidget.indexOf(self.tab_fuzzing), _translate("GeneratorTab", "Fuzzing")) + self.tabWidget.setTabText( + self.tabWidget.indexOf(self.tab_fuzzing), + _translate("GeneratorTab", "Fuzzing"), + ) self.lCarrierFreqValue.setText(_translate("GeneratorTab", "TextLabel")) self.lModType.setText(_translate("GeneratorTab", "Modulation Type:")) self.lModTypeValue.setText(_translate("GeneratorTab", "TextLabel")) @@ -382,24 +465,48 @@ def retranslateUi(self, GeneratorTab): self.btnSend.setText(_translate("GeneratorTab", "Send data...")) self.btnEditModulation.setText(_translate("GeneratorTab", "Edit ...")) self.lModulation.setText(_translate("GeneratorTab", "Modulation:")) - self.btnGenerate.setToolTip(_translate("GeneratorTab", "Generate the complex file of the modulated signal, after tuning all parameters above.")) + self.btnGenerate.setToolTip( + _translate( + "GeneratorTab", + "Generate the complex file of the modulated signal, after tuning all parameters above.", + ) + ) self.btnGenerate.setText(_translate("GeneratorTab", "Generate file...")) - self.btnNetworkSDRSend.setToolTip(_translate("GeneratorTab", "

Send encoded data to your external application via TCP.

")) + self.btnNetworkSDRSend.setToolTip( + _translate( + "GeneratorTab", + '

Send encoded data to your external application via TCP.

', + ) + ) self.btnNetworkSDRSend.setText(_translate("GeneratorTab", "Send via Network")) self.cbViewType.setItemText(0, _translate("GeneratorTab", "Bit")) self.cbViewType.setItemText(1, _translate("GeneratorTab", "Hex")) self.cbViewType.setItemText(2, _translate("GeneratorTab", "ASCII")) self.lViewType.setText(_translate("GeneratorTab", "Viewtype:")) - self.btnRfCatSend.setToolTip(_translate("GeneratorTab", "

Send encoded data via RfCat.

Hit again for stopping the sending process. Note that you can set the number of repetitions (from 1 to infinite) in:

Edit->Options->Device->\'Device sending repetitions\'

")) + self.btnRfCatSend.setToolTip( + _translate( + "GeneratorTab", + '

Send encoded data via RfCat.

Hit again for stopping the sending process. Note that you can set the number of repetitions (from 1 to infinite) in:

Edit->Options->Device->\'Device sending repetitions\'

', + ) + ) self.btnRfCatSend.setText(_translate("GeneratorTab", "Send via RfCat")) self.labelGeneratedData.setText(_translate("GeneratorTab", "Generated Data")) - self.btnSave.setToolTip(_translate("GeneratorTab", "Save current fuzz profile.")) + self.btnSave.setToolTip( + _translate("GeneratorTab", "Save current fuzz profile.") + ) self.btnSave.setText(_translate("GeneratorTab", "...")) self.btnOpen.setToolTip(_translate("GeneratorTab", "Load a fuzz profile.")) self.btnOpen.setText(_translate("GeneratorTab", "...")) - self.lEstimatedTime.setToolTip(_translate("GeneratorTab", "

The estimated average time is based on the average number of bits per message and average sample rate, you set for the modulations.

")) + self.lEstimatedTime.setToolTip( + _translate( + "GeneratorTab", + "

The estimated average time is based on the average number of bits per message and average sample rate, you set for the modulations.

", + ) + ) self.lEstimatedTime.setText(_translate("GeneratorTab", "Estimated Time: ")) self.btnFZSave.setText(_translate("GeneratorTab", "Save as FlipperZero SubGHz")) + + from urh.ui.ElidedLabel import ElidedLabel from urh.ui.GeneratorListWidget import GeneratorListWidget from urh.ui.views.GeneratorListView import GeneratorListView diff --git a/src/urh/ui/ui_main.py b/src/urh/ui/ui_main.py index 3defb740b8..4634c24e3e 100644 --- a/src/urh/ui/ui_main.py +++ b/src/urh/ui/ui_main.py @@ -14,7 +14,11 @@ def setupUi(self, MainWindow): MainWindow.setObjectName("MainWindow") MainWindow.resize(798, 469) icon = QtGui.QIcon() - icon.addPixmap(QtGui.QPixmap(":/icons/icons/appicon.png"), QtGui.QIcon.Normal, QtGui.QIcon.Off) + icon.addPixmap( + QtGui.QPixmap(":/icons/icons/appicon.png"), + QtGui.QIcon.Normal, + QtGui.QIcon.Off, + ) MainWindow.setWindowIcon(icon) MainWindow.setTabShape(QtWidgets.QTabWidget.Rounded) MainWindow.setDockNestingEnabled(False) @@ -23,14 +27,16 @@ def setupUi(self, MainWindow): self.verticalLayout_4 = QtWidgets.QVBoxLayout(self.centralwidget) self.verticalLayout_4.setObjectName("verticalLayout_4") self.splitter = QtWidgets.QSplitter(self.centralwidget) - self.splitter.setStyleSheet("QSplitter::handle:horizontal {\n" -"margin: 4px 0px;\n" -" background-color: qlineargradient(x1:0, y1:0, x2:0, y2:1, \n" -"stop:0 rgba(255, 255, 255, 0), \n" -"stop:0.5 rgba(100, 100, 100, 100), \n" -"stop:1 rgba(255, 255, 255, 0));\n" -"image: url(:/icons/icons/splitter_handle_vertical.svg);\n" -"}") + self.splitter.setStyleSheet( + "QSplitter::handle:horizontal {\n" + "margin: 4px 0px;\n" + " background-color: qlineargradient(x1:0, y1:0, x2:0, y2:1, \n" + "stop:0 rgba(255, 255, 255, 0), \n" + "stop:0.5 rgba(100, 100, 100, 100), \n" + "stop:1 rgba(255, 255, 255, 0));\n" + "image: url(:/icons/icons/splitter_handle_vertical.svg);\n" + "}" + ) self.splitter.setOrientation(QtCore.Qt.Horizontal) self.splitter.setHandleWidth(6) self.splitter.setObjectName("splitter") @@ -43,17 +49,23 @@ def setupUi(self, MainWindow): self.horizontalLayout_3 = QtWidgets.QHBoxLayout() self.horizontalLayout_3.setObjectName("horizontalLayout_3") self.lnEdtTreeFilter = QtWidgets.QLineEdit(self.layoutWidget) - sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Fixed, QtWidgets.QSizePolicy.Fixed) + sizePolicy = QtWidgets.QSizePolicy( + QtWidgets.QSizePolicy.Fixed, QtWidgets.QSizePolicy.Fixed + ) sizePolicy.setHorizontalStretch(0) sizePolicy.setVerticalStretch(0) - sizePolicy.setHeightForWidth(self.lnEdtTreeFilter.sizePolicy().hasHeightForWidth()) + sizePolicy.setHeightForWidth( + self.lnEdtTreeFilter.sizePolicy().hasHeightForWidth() + ) self.lnEdtTreeFilter.setSizePolicy(sizePolicy) self.lnEdtTreeFilter.setAcceptDrops(False) self.lnEdtTreeFilter.setInputMethodHints(QtCore.Qt.ImhDialableCharactersOnly) self.lnEdtTreeFilter.setClearButtonEnabled(True) self.lnEdtTreeFilter.setObjectName("lnEdtTreeFilter") self.horizontalLayout_3.addWidget(self.lnEdtTreeFilter) - spacerItem = QtWidgets.QSpacerItem(40, 20, QtWidgets.QSizePolicy.Expanding, QtWidgets.QSizePolicy.Minimum) + spacerItem = QtWidgets.QSpacerItem( + 40, 20, QtWidgets.QSizePolicy.Expanding, QtWidgets.QSizePolicy.Minimum + ) self.horizontalLayout_3.addItem(spacerItem) self.btnFileTreeGoUp = QtWidgets.QToolButton(self.layoutWidget) icon = QtGui.QIcon.fromTheme("go-up") @@ -62,7 +74,9 @@ def setupUi(self, MainWindow): self.horizontalLayout_3.addWidget(self.btnFileTreeGoUp) self.verticalLayout_3.addLayout(self.horizontalLayout_3) self.fileTree = DirectoryTreeView(self.layoutWidget) - sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Minimum, QtWidgets.QSizePolicy.Expanding) + sizePolicy = QtWidgets.QSizePolicy( + QtWidgets.QSizePolicy.Minimum, QtWidgets.QSizePolicy.Expanding + ) sizePolicy.setHorizontalStretch(10) sizePolicy.setVerticalStretch(0) sizePolicy.setHeightForWidth(self.fileTree.sizePolicy().hasHeightForWidth()) @@ -79,10 +93,14 @@ def setupUi(self, MainWindow): self.fileTree.header().setStretchLastSection(False) self.verticalLayout_3.addWidget(self.fileTree) self.tabWidget_Project = QtWidgets.QTabWidget(self.layoutWidget) - sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Expanding, QtWidgets.QSizePolicy.Preferred) + sizePolicy = QtWidgets.QSizePolicy( + QtWidgets.QSizePolicy.Expanding, QtWidgets.QSizePolicy.Preferred + ) sizePolicy.setHorizontalStretch(0) sizePolicy.setVerticalStretch(0) - sizePolicy.setHeightForWidth(self.tabWidget_Project.sizePolicy().hasHeightForWidth()) + sizePolicy.setHeightForWidth( + self.tabWidget_Project.sizePolicy().hasHeightForWidth() + ) self.tabWidget_Project.setSizePolicy(sizePolicy) self.tabWidget_Project.setStyleSheet("QTabWidget::pane { border: 0; }") self.tabWidget_Project.setObjectName("tabWidget_Project") @@ -107,7 +125,9 @@ def setupUi(self, MainWindow): self.tabWidget_Project.addTab(self.tabDescription, "") self.verticalLayout_3.addWidget(self.tabWidget_Project) self.tabWidget = QtWidgets.QTabWidget(self.splitter) - sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Expanding, QtWidgets.QSizePolicy.Expanding) + sizePolicy = QtWidgets.QSizePolicy( + QtWidgets.QSizePolicy.Expanding, QtWidgets.QSizePolicy.Expanding + ) sizePolicy.setHorizontalStretch(1) sizePolicy.setVerticalStretch(0) sizePolicy.setHeightForWidth(self.tabWidget.sizePolicy().hasHeightForWidth()) @@ -194,7 +214,9 @@ def setupUi(self, MainWindow): self.actionShow_Confirm_Close_Dialog = QtWidgets.QAction(MainWindow) self.actionShow_Confirm_Close_Dialog.setCheckable(True) self.actionShow_Confirm_Close_Dialog.setChecked(False) - self.actionShow_Confirm_Close_Dialog.setObjectName("actionShow_Confirm_Close_Dialog") + self.actionShow_Confirm_Close_Dialog.setObjectName( + "actionShow_Confirm_Close_Dialog" + ) self.actionTest = QtWidgets.QAction(MainWindow) self.actionTest.setObjectName("actionTest") self.actionHold_Shift_to_Drag = QtWidgets.QAction(MainWindow) @@ -232,7 +254,9 @@ def setupUi(self, MainWindow): self.actionSeperate_Protocols_in_Compare_Frame = QtWidgets.QAction(MainWindow) self.actionSeperate_Protocols_in_Compare_Frame.setCheckable(True) self.actionSeperate_Protocols_in_Compare_Frame.setChecked(True) - self.actionSeperate_Protocols_in_Compare_Frame.setObjectName("actionSeperate_Protocols_in_Compare_Frame") + self.actionSeperate_Protocols_in_Compare_Frame.setObjectName( + "actionSeperate_Protocols_in_Compare_Frame" + ) self.actionOpenArchive = QtWidgets.QAction(MainWindow) self.actionOpenArchive.setObjectName("actionOpenArchive") self.actionOpen = QtWidgets.QAction(MainWindow) @@ -247,7 +271,9 @@ def setupUi(self, MainWindow): self.actionShow_only_Compare_Frame = QtWidgets.QAction(MainWindow) self.actionShow_only_Compare_Frame.setCheckable(True) self.actionShow_only_Compare_Frame.setChecked(True) - self.actionShow_only_Compare_Frame.setObjectName("actionShow_only_Compare_Frame") + self.actionShow_only_Compare_Frame.setObjectName( + "actionShow_only_Compare_Frame" + ) self.actionConfigurePlugins = QtWidgets.QAction(MainWindow) self.actionConfigurePlugins.setIconVisibleInMenu(True) self.actionConfigurePlugins.setObjectName("actionConfigurePlugins") @@ -255,10 +281,16 @@ def setupUi(self, MainWindow): self.actionSort_Frames_by_Name.setObjectName("actionSort_Frames_by_Name") self.actionConvert_Folder_to_Project = QtWidgets.QAction(MainWindow) self.actionConvert_Folder_to_Project.setIconVisibleInMenu(True) - self.actionConvert_Folder_to_Project.setObjectName("actionConvert_Folder_to_Project") + self.actionConvert_Folder_to_Project.setObjectName( + "actionConvert_Folder_to_Project" + ) self.actionDecoding = QtWidgets.QAction(MainWindow) icon1 = QtGui.QIcon() - icon1.addPixmap(QtGui.QPixmap(":/icons/icons/decoding.svg"), QtGui.QIcon.Normal, QtGui.QIcon.Off) + icon1.addPixmap( + QtGui.QPixmap(":/icons/icons/decoding.svg"), + QtGui.QIcon.Normal, + QtGui.QIcon.Off, + ) self.actionDecoding.setIcon(icon1) self.actionDecoding.setObjectName("actionDecoding") self.actionRecord = QtWidgets.QAction(MainWindow) @@ -268,7 +300,11 @@ def setupUi(self, MainWindow): self.actionRecord.setObjectName("actionRecord") self.actionSpectrum_Analyzer = QtWidgets.QAction(MainWindow) icon2 = QtGui.QIcon() - icon2.addPixmap(QtGui.QPixmap(":/icons/icons/spectrum.svg"), QtGui.QIcon.Normal, QtGui.QIcon.Off) + icon2.addPixmap( + QtGui.QPixmap(":/icons/icons/spectrum.svg"), + QtGui.QIcon.Normal, + QtGui.QIcon.Off, + ) self.actionSpectrum_Analyzer.setIcon(icon2) self.actionSpectrum_Analyzer.setIconVisibleInMenu(True) self.actionSpectrum_Analyzer.setObjectName("actionSpectrum_Analyzer") @@ -283,7 +319,11 @@ def setupUi(self, MainWindow): self.actionNew_Project.setObjectName("actionNew_Project") self.actionSniff_protocol = QtWidgets.QAction(MainWindow) icon3 = QtGui.QIcon() - icon3.addPixmap(QtGui.QPixmap(":/icons/icons/sniffer.svg"), QtGui.QIcon.Normal, QtGui.QIcon.Off) + icon3.addPixmap( + QtGui.QPixmap(":/icons/icons/sniffer.svg"), + QtGui.QIcon.Normal, + QtGui.QIcon.Off, + ) self.actionSniff_protocol.setIcon(icon3) self.actionSniff_protocol.setObjectName("actionSniff_protocol") self.actionProject_settings = QtWidgets.QAction(MainWindow) @@ -317,11 +357,15 @@ def setupUi(self, MainWindow): self.actionAuto_detect_new_signals = QtWidgets.QAction(MainWindow) self.actionAuto_detect_new_signals.setCheckable(True) self.actionAuto_detect_new_signals.setChecked(True) - self.actionAuto_detect_new_signals.setObjectName("actionAuto_detect_new_signals") + self.actionAuto_detect_new_signals.setObjectName( + "actionAuto_detect_new_signals" + ) self.actionAutomaticNoiseThreshold = QtWidgets.QAction(MainWindow) self.actionAutomaticNoiseThreshold.setCheckable(True) self.actionAutomaticNoiseThreshold.setChecked(True) - self.actionAutomaticNoiseThreshold.setObjectName("actionAutomaticNoiseThreshold") + self.actionAutomaticNoiseThreshold.setObjectName( + "actionAutomaticNoiseThreshold" + ) self.action1NoiseThreshold = QtWidgets.QAction(MainWindow) self.action1NoiseThreshold.setCheckable(True) self.action1NoiseThreshold.setObjectName("action1NoiseThreshold") @@ -380,17 +424,42 @@ def retranslateUi(self, MainWindow): MainWindow.setWindowTitle(_translate("MainWindow", "Universal Radio Hacker")) self.lnEdtTreeFilter.setPlaceholderText(_translate("MainWindow", "Filter")) self.btnFileTreeGoUp.setText(_translate("MainWindow", "...")) - self.tabWidget_Project.setTabText(self.tabWidget_Project.indexOf(self.tabParticipants), _translate("MainWindow", "Participants")) - self.tabWidget_Project.setTabText(self.tabWidget_Project.indexOf(self.tabDescription), _translate("MainWindow", "Description")) - self.tabWidget.setTabText(self.tabWidget.indexOf(self.tab_interpretation), _translate("MainWindow", "Interpretation")) - self.tabWidget.setTabText(self.tabWidget.indexOf(self.tab_protocol), _translate("MainWindow", "Analysis")) - self.tabWidget.setTabText(self.tabWidget.indexOf(self.tab_generator), _translate("MainWindow", "Generator")) - self.tabWidget.setTabText(self.tabWidget.indexOf(self.tab_simulator), _translate("MainWindow", "Simulator")) - self.labelNonProjectMode.setText(_translate("MainWindow", "

Warning: You are running URH in non project mode. All your settings will be lost after closing the program. If you want to keep your settings create a project via File -> New Project. Don\'t show this hint

")) + self.tabWidget_Project.setTabText( + self.tabWidget_Project.indexOf(self.tabParticipants), + _translate("MainWindow", "Participants"), + ) + self.tabWidget_Project.setTabText( + self.tabWidget_Project.indexOf(self.tabDescription), + _translate("MainWindow", "Description"), + ) + self.tabWidget.setTabText( + self.tabWidget.indexOf(self.tab_interpretation), + _translate("MainWindow", "Interpretation"), + ) + self.tabWidget.setTabText( + self.tabWidget.indexOf(self.tab_protocol), + _translate("MainWindow", "Analysis"), + ) + self.tabWidget.setTabText( + self.tabWidget.indexOf(self.tab_generator), + _translate("MainWindow", "Generator"), + ) + self.tabWidget.setTabText( + self.tabWidget.indexOf(self.tab_simulator), + _translate("MainWindow", "Simulator"), + ) + self.labelNonProjectMode.setText( + _translate( + "MainWindow", + '

Warning: You are running URH in non project mode. All your settings will be lost after closing the program. If you want to keep your settings create a project via File -> New Project. Don\'t show this hint

', + ) + ) self.menuFile.setTitle(_translate("MainWindow", "Fi&le")) self.menuImport.setTitle(_translate("MainWindow", "Import")) self.menuEdit.setTitle(_translate("MainWindow", "Edi&t")) - self.menuDefault_noise_threshold.setTitle(_translate("MainWindow", "Default noise threshold")) + self.menuDefault_noise_threshold.setTitle( + _translate("MainWindow", "Default noise threshold") + ) self.menuHelp.setTitle(_translate("MainWindow", "Hel&p")) self.actionFSK.setText(_translate("MainWindow", "Undo")) self.actionOOK.setText(_translate("MainWindow", "Redo")) @@ -399,43 +468,75 @@ def retranslateUi(self, MainWindow): self.actionAuto_Fit_Y.setText(_translate("MainWindow", "&Auto Fit Y")) self.actionUndo.setText(_translate("MainWindow", "&Undo")) self.actionRedo.setText(_translate("MainWindow", "&Redo")) - self.actionShow_Confirm_Close_Dialog.setText(_translate("MainWindow", "&Show Confirm Close Dialog")) + self.actionShow_Confirm_Close_Dialog.setText( + _translate("MainWindow", "&Show Confirm Close Dialog") + ) self.actionTest.setText(_translate("MainWindow", "test")) - self.actionHold_Shift_to_Drag.setText(_translate("MainWindow", "&Hold Shift to Drag")) + self.actionHold_Shift_to_Drag.setText( + _translate("MainWindow", "&Hold Shift to Drag") + ) self.actionDocumentation.setText(_translate("MainWindow", "&Documentation")) - self.actionAbout_AutomaticHacker.setText(_translate("MainWindow", "&About Universal Radio Hacker...")) + self.actionAbout_AutomaticHacker.setText( + _translate("MainWindow", "&About Universal Radio Hacker...") + ) self.actionOpenSignal.setText(_translate("MainWindow", "&Signal")) self.actionOpenProtocol.setText(_translate("MainWindow", "&Protocol")) - self.actionShow_Compare_Frame.setText(_translate("MainWindow", "Show &Compare Frame")) + self.actionShow_Compare_Frame.setText( + _translate("MainWindow", "Show &Compare Frame") + ) self.actionCloseAllFiles.setText(_translate("MainWindow", "&Close all files")) self.actionSaveAllSignals.setText(_translate("MainWindow", "&Save all signals")) - self.actionSeperate_Protocols_in_Compare_Frame.setText(_translate("MainWindow", "Separate &Protocols in Compare Frame")) + self.actionSeperate_Protocols_in_Compare_Frame.setText( + _translate("MainWindow", "Separate &Protocols in Compare Frame") + ) self.actionOpenArchive.setText(_translate("MainWindow", "&Archive")) self.actionOpen.setText(_translate("MainWindow", "&Open...")) self.actionOpen_Folder.setText(_translate("MainWindow", "Open &Folder..")) - self.actionShow_only_Compare_Frame.setText(_translate("MainWindow", "Show Compare Frame only")) + self.actionShow_only_Compare_Frame.setText( + _translate("MainWindow", "Show Compare Frame only") + ) self.actionConfigurePlugins.setText(_translate("MainWindow", "Configure...")) - self.actionSort_Frames_by_Name.setText(_translate("MainWindow", "Sort &Frames by Name")) - self.actionConvert_Folder_to_Project.setText(_translate("MainWindow", "Conv&ert Folder to Project")) + self.actionSort_Frames_by_Name.setText( + _translate("MainWindow", "Sort &Frames by Name") + ) + self.actionConvert_Folder_to_Project.setText( + _translate("MainWindow", "Conv&ert Folder to Project") + ) self.actionDecoding.setText(_translate("MainWindow", "&Decoding...")) self.actionRecord.setText(_translate("MainWindow", "&Record signal...")) - self.actionSpectrum_Analyzer.setText(_translate("MainWindow", "Spectrum &Analyzer...")) + self.actionSpectrum_Analyzer.setText( + _translate("MainWindow", "Spectrum &Analyzer...") + ) self.actionOptions.setText(_translate("MainWindow", "&Options...")) self.actionNew_Project.setText(_translate("MainWindow", "&New Project..")) - self.actionSniff_protocol.setText(_translate("MainWindow", "Sn&iff protocol...")) - self.actionProject_settings.setText(_translate("MainWindow", "&Project settings...")) + self.actionSniff_protocol.setText( + _translate("MainWindow", "Sn&iff protocol...") + ) + self.actionProject_settings.setText( + _translate("MainWindow", "&Project settings...") + ) self.actionSave_project.setText(_translate("MainWindow", "Sa&ve project")) self.actionFullscreen_mode.setText(_translate("MainWindow", "&Fullscreen mode")) self.actionOpen_directory.setText(_translate("MainWindow", "Open &folder...")) self.actionAbout_Qt.setText(_translate("MainWindow", "About &Qt")) self.actionShowFileTree.setText(_translate("MainWindow", "&Show file tree")) - self.actionSamples_from_csv.setText(_translate("MainWindow", "IQ samples from csv")) + self.actionSamples_from_csv.setText( + _translate("MainWindow", "IQ samples from csv") + ) self.actionClose_project.setText(_translate("MainWindow", "Close project")) - self.actionAuto_detect_new_signals.setText(_translate("MainWindow", "Auto detect signals on loading")) - self.actionAutomaticNoiseThreshold.setText(_translate("MainWindow", "Automatic")) + self.actionAuto_detect_new_signals.setText( + _translate("MainWindow", "Auto detect signals on loading") + ) + self.actionAutomaticNoiseThreshold.setText( + _translate("MainWindow", "Automatic") + ) self.action1NoiseThreshold.setText(_translate("MainWindow", "1%")) self.action5NoiseThreshold.setText(_translate("MainWindow", "5%")) self.action10NoiseThreshold.setText(_translate("MainWindow", "10%")) - self.action100NoiseThreshold.setText(_translate("MainWindow", "100% (disables demodulation)")) + self.action100NoiseThreshold.setText( + _translate("MainWindow", "100% (disables demodulation)") + ) + + from urh.ui.views.DirectoryTreeView import DirectoryTreeView from . import urh_rc diff --git a/src/urh/ui/ui_messagetype_options.py b/src/urh/ui/ui_messagetype_options.py index 47ea4b71d6..c35f880073 100644 --- a/src/urh/ui/ui_messagetype_options.py +++ b/src/urh/ui/ui_messagetype_options.py @@ -35,7 +35,9 @@ def setupUi(self, DialogMessageType): self.rbAssignAutomatically = QtWidgets.QRadioButton(DialogMessageType) self.rbAssignAutomatically.setObjectName("rbAssignAutomatically") self.gridLayout.addWidget(self.rbAssignAutomatically, 0, 1, 1, 1) - spacerItem = QtWidgets.QSpacerItem(20, 145, QtWidgets.QSizePolicy.Minimum, QtWidgets.QSizePolicy.Expanding) + spacerItem = QtWidgets.QSpacerItem( + 20, 145, QtWidgets.QSizePolicy.Minimum, QtWidgets.QSizePolicy.Expanding + ) self.gridLayout.addItem(spacerItem, 4, 2, 1, 1) self.btnAddRule = QtWidgets.QToolButton(DialogMessageType) icon = QtGui.QIcon.fromTheme("list-add") @@ -43,7 +45,9 @@ def setupUi(self, DialogMessageType): self.btnAddRule.setObjectName("btnAddRule") self.gridLayout.addWidget(self.btnAddRule, 2, 2, 1, 1) self.buttonBox = QtWidgets.QDialogButtonBox(DialogMessageType) - self.buttonBox.setStandardButtons(QtWidgets.QDialogButtonBox.Cancel|QtWidgets.QDialogButtonBox.Ok) + self.buttonBox.setStandardButtons( + QtWidgets.QDialogButtonBox.Cancel | QtWidgets.QDialogButtonBox.Ok + ) self.buttonBox.setObjectName("buttonBox") self.gridLayout.addWidget(self.buttonBox, 5, 0, 1, 2) @@ -52,12 +56,22 @@ def setupUi(self, DialogMessageType): def retranslateUi(self, DialogMessageType): _translate = QtCore.QCoreApplication.translate DialogMessageType.setWindowTitle(_translate("DialogMessageType", "Dialog")) - self.cbRulesetMode.setItemText(0, _translate("DialogMessageType", "All rules must apply (AND)")) - self.cbRulesetMode.setItemText(1, _translate("DialogMessageType", "At least one rule must apply (OR)")) - self.cbRulesetMode.setItemText(2, _translate("DialogMessageType", "No rule must apply (NOR)")) + self.cbRulesetMode.setItemText( + 0, _translate("DialogMessageType", "All rules must apply (AND)") + ) + self.cbRulesetMode.setItemText( + 1, _translate("DialogMessageType", "At least one rule must apply (OR)") + ) + self.cbRulesetMode.setItemText( + 2, _translate("DialogMessageType", "No rule must apply (NOR)") + ) self.btnRemoveRule.setToolTip(_translate("DialogMessageType", "Remove ruleset")) self.btnRemoveRule.setText(_translate("DialogMessageType", "...")) - self.rbAssignManually.setText(_translate("DialogMessageType", "Assi&gn manually")) - self.rbAssignAutomatically.setText(_translate("DialogMessageType", "Assign a&utomatically")) + self.rbAssignManually.setText( + _translate("DialogMessageType", "Assi&gn manually") + ) + self.rbAssignAutomatically.setText( + _translate("DialogMessageType", "Assign a&utomatically") + ) self.btnAddRule.setToolTip(_translate("DialogMessageType", "Add ruleset")) self.btnAddRule.setText(_translate("DialogMessageType", "...")) diff --git a/src/urh/ui/ui_modulation.py b/src/urh/ui/ui_modulation.py index d2ed49469f..eb9f329fc3 100644 --- a/src/urh/ui/ui_modulation.py +++ b/src/urh/ui/ui_modulation.py @@ -13,7 +13,11 @@ def setupUi(self, DialogModulation): DialogModulation.setObjectName("DialogModulation") DialogModulation.resize(977, 1041) icon = QtGui.QIcon() - icon.addPixmap(QtGui.QPixmap(":/icons/icons/modulation.svg"), QtGui.QIcon.Normal, QtGui.QIcon.Off) + icon.addPixmap( + QtGui.QPixmap(":/icons/icons/modulation.svg"), + QtGui.QIcon.Normal, + QtGui.QIcon.Off, + ) DialogModulation.setWindowIcon(icon) self.verticalLayout = QtWidgets.QVBoxLayout(DialogModulation) self.verticalLayout.setObjectName("verticalLayout") @@ -21,8 +25,12 @@ def setupUi(self, DialogModulation): self.gridLayout_5.setObjectName("gridLayout_5") self.comboBoxCustomModulations = QtWidgets.QComboBox(DialogModulation) self.comboBoxCustomModulations.setEditable(True) - self.comboBoxCustomModulations.setInsertPolicy(QtWidgets.QComboBox.InsertAtCurrent) - self.comboBoxCustomModulations.setSizeAdjustPolicy(QtWidgets.QComboBox.AdjustToContents) + self.comboBoxCustomModulations.setInsertPolicy( + QtWidgets.QComboBox.InsertAtCurrent + ) + self.comboBoxCustomModulations.setSizeAdjustPolicy( + QtWidgets.QComboBox.AdjustToContents + ) self.comboBoxCustomModulations.setObjectName("comboBoxCustomModulations") self.comboBoxCustomModulations.addItem("") self.gridLayout_5.addWidget(self.comboBoxCustomModulations, 0, 0, 1, 1) @@ -54,7 +62,9 @@ def setupUi(self, DialogModulation): self.label_5.setObjectName("label_5") self.gridLayout_7.addWidget(self.label_5, 2, 0, 1, 1) self.lEqual = QtWidgets.QLabel(self.scrollAreaWidgetContents_2) - sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Fixed, QtWidgets.QSizePolicy.Fixed) + sizePolicy = QtWidgets.QSizePolicy( + QtWidgets.QSizePolicy.Fixed, QtWidgets.QSizePolicy.Fixed + ) sizePolicy.setHorizontalStretch(0) sizePolicy.setVerticalStretch(0) sizePolicy.setHeightForWidth(self.lEqual.sizePolicy().hasHeightForWidth()) @@ -73,7 +83,9 @@ def setupUi(self, DialogModulation): self.label_6.setFont(font) self.label_6.setObjectName("label_6") self.gridLayout_7.addWidget(self.label_6, 4, 0, 1, 1) - spacerItem = QtWidgets.QSpacerItem(40, 20, QtWidgets.QSizePolicy.Expanding, QtWidgets.QSizePolicy.Minimum) + spacerItem = QtWidgets.QSpacerItem( + 40, 20, QtWidgets.QSizePolicy.Expanding, QtWidgets.QSizePolicy.Minimum + ) self.gridLayout_7.addItem(spacerItem, 8, 1, 1, 1) self.label_7 = QtWidgets.QLabel(self.scrollAreaWidgetContents_2) font = QtGui.QFont() @@ -82,9 +94,13 @@ def setupUi(self, DialogModulation): self.label_7.setFont(font) self.label_7.setObjectName("label_7") self.gridLayout_7.addWidget(self.label_7, 8, 0, 1, 1) - spacerItem1 = QtWidgets.QSpacerItem(40, 20, QtWidgets.QSizePolicy.Expanding, QtWidgets.QSizePolicy.Minimum) + spacerItem1 = QtWidgets.QSpacerItem( + 40, 20, QtWidgets.QSizePolicy.Expanding, QtWidgets.QSizePolicy.Minimum + ) self.gridLayout_7.addItem(spacerItem1, 2, 3, 1, 1) - spacerItem2 = QtWidgets.QSpacerItem(40, 20, QtWidgets.QSizePolicy.Expanding, QtWidgets.QSizePolicy.Minimum) + spacerItem2 = QtWidgets.QSpacerItem( + 40, 20, QtWidgets.QSizePolicy.Expanding, QtWidgets.QSizePolicy.Minimum + ) self.gridLayout_7.addItem(spacerItem2, 4, 1, 1, 1) self.label_4 = QtWidgets.QLabel(self.scrollAreaWidgetContents_2) font = QtGui.QFont() @@ -93,10 +109,14 @@ def setupUi(self, DialogModulation): self.label_4.setFont(font) self.label_4.setObjectName("label_4") self.gridLayout_7.addWidget(self.label_4, 0, 0, 1, 1) - self.gVOriginalSignal = ZoomAndDropableGraphicView(self.scrollAreaWidgetContents_2) + self.gVOriginalSignal = ZoomAndDropableGraphicView( + self.scrollAreaWidgetContents_2 + ) self.gVOriginalSignal.setVerticalScrollBarPolicy(QtCore.Qt.ScrollBarAlwaysOff) self.gVOriginalSignal.setHorizontalScrollBarPolicy(QtCore.Qt.ScrollBarAlwaysOn) - self.gVOriginalSignal.setRenderHints(QtGui.QPainter.Antialiasing|QtGui.QPainter.HighQualityAntialiasing) + self.gVOriginalSignal.setRenderHints( + QtGui.QPainter.Antialiasing | QtGui.QPainter.HighQualityAntialiasing + ) self.gVOriginalSignal.setDragMode(QtWidgets.QGraphicsView.NoDrag) self.gVOriginalSignal.setObjectName("gVOriginalSignal") self.gridLayout_7.addWidget(self.gVOriginalSignal, 9, 1, 1, 3) @@ -110,10 +130,14 @@ def setupUi(self, DialogModulation): self.gridLayout_4 = QtWidgets.QGridLayout(self.scrollAreaWidgetContents_5) self.gridLayout_4.setObjectName("gridLayout_4") self.lCurrentSearchResult = QtWidgets.QLabel(self.scrollAreaWidgetContents_5) - sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Preferred, QtWidgets.QSizePolicy.Preferred) + sizePolicy = QtWidgets.QSizePolicy( + QtWidgets.QSizePolicy.Preferred, QtWidgets.QSizePolicy.Preferred + ) sizePolicy.setHorizontalStretch(0) sizePolicy.setVerticalStretch(0) - sizePolicy.setHeightForWidth(self.lCurrentSearchResult.sizePolicy().hasHeightForWidth()) + sizePolicy.setHeightForWidth( + self.lCurrentSearchResult.sizePolicy().hasHeightForWidth() + ) self.lCurrentSearchResult.setSizePolicy(sizePolicy) self.lCurrentSearchResult.setMinimumSize(QtCore.QSize(0, 0)) self.lCurrentSearchResult.setMaximumSize(QtCore.QSize(16777215, 16777215)) @@ -121,20 +145,28 @@ def setupUi(self, DialogModulation): self.lCurrentSearchResult.setObjectName("lCurrentSearchResult") self.gridLayout_4.addWidget(self.lCurrentSearchResult, 3, 1, 1, 2) self.cbShowDataBitsOnly = QtWidgets.QCheckBox(self.scrollAreaWidgetContents_5) - sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Maximum, QtWidgets.QSizePolicy.Fixed) + sizePolicy = QtWidgets.QSizePolicy( + QtWidgets.QSizePolicy.Maximum, QtWidgets.QSizePolicy.Fixed + ) sizePolicy.setHorizontalStretch(0) sizePolicy.setVerticalStretch(0) - sizePolicy.setHeightForWidth(self.cbShowDataBitsOnly.sizePolicy().hasHeightForWidth()) + sizePolicy.setHeightForWidth( + self.cbShowDataBitsOnly.sizePolicy().hasHeightForWidth() + ) self.cbShowDataBitsOnly.setSizePolicy(sizePolicy) self.cbShowDataBitsOnly.setMinimumSize(QtCore.QSize(0, 0)) self.cbShowDataBitsOnly.setMaximumSize(QtCore.QSize(16777215, 16777215)) self.cbShowDataBitsOnly.setObjectName("cbShowDataBitsOnly") self.gridLayout_4.addWidget(self.cbShowDataBitsOnly, 2, 0, 1, 5) self.btnSearchPrev = QtWidgets.QPushButton(self.scrollAreaWidgetContents_5) - sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Fixed, QtWidgets.QSizePolicy.Fixed) + sizePolicy = QtWidgets.QSizePolicy( + QtWidgets.QSizePolicy.Fixed, QtWidgets.QSizePolicy.Fixed + ) sizePolicy.setHorizontalStretch(0) sizePolicy.setVerticalStretch(0) - sizePolicy.setHeightForWidth(self.btnSearchPrev.sizePolicy().hasHeightForWidth()) + sizePolicy.setHeightForWidth( + self.btnSearchPrev.sizePolicy().hasHeightForWidth() + ) self.btnSearchPrev.setSizePolicy(sizePolicy) self.btnSearchPrev.setMaximumSize(QtCore.QSize(16777215, 16777215)) self.btnSearchPrev.setText("") @@ -143,20 +175,28 @@ def setupUi(self, DialogModulation): self.btnSearchPrev.setObjectName("btnSearchPrev") self.gridLayout_4.addWidget(self.btnSearchPrev, 3, 0, 1, 1) self.lTotalSearchresults = QtWidgets.QLabel(self.scrollAreaWidgetContents_5) - sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Preferred, QtWidgets.QSizePolicy.Preferred) + sizePolicy = QtWidgets.QSizePolicy( + QtWidgets.QSizePolicy.Preferred, QtWidgets.QSizePolicy.Preferred + ) sizePolicy.setHorizontalStretch(0) sizePolicy.setVerticalStretch(0) - sizePolicy.setHeightForWidth(self.lTotalSearchresults.sizePolicy().hasHeightForWidth()) + sizePolicy.setHeightForWidth( + self.lTotalSearchresults.sizePolicy().hasHeightForWidth() + ) self.lTotalSearchresults.setSizePolicy(sizePolicy) self.lTotalSearchresults.setMaximumSize(QtCore.QSize(16777215, 16777215)) self.lTotalSearchresults.setAlignment(QtCore.Qt.AlignCenter) self.lTotalSearchresults.setObjectName("lTotalSearchresults") self.gridLayout_4.addWidget(self.lTotalSearchresults, 3, 4, 1, 1) self.treeViewSignals = ModulatorTreeView(self.scrollAreaWidgetContents_5) - sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Preferred, QtWidgets.QSizePolicy.Preferred) + sizePolicy = QtWidgets.QSizePolicy( + QtWidgets.QSizePolicy.Preferred, QtWidgets.QSizePolicy.Preferred + ) sizePolicy.setHorizontalStretch(0) sizePolicy.setVerticalStretch(0) - sizePolicy.setHeightForWidth(self.treeViewSignals.sizePolicy().hasHeightForWidth()) + sizePolicy.setHeightForWidth( + self.treeViewSignals.sizePolicy().hasHeightForWidth() + ) self.treeViewSignals.setSizePolicy(sizePolicy) self.treeViewSignals.setProperty("showDropIndicator", True) self.treeViewSignals.setDragEnabled(True) @@ -165,7 +205,9 @@ def setupUi(self, DialogModulation): self.treeViewSignals.setObjectName("treeViewSignals") self.gridLayout_4.addWidget(self.treeViewSignals, 0, 0, 1, 6) self.lSlash = QtWidgets.QLabel(self.scrollAreaWidgetContents_5) - sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Fixed, QtWidgets.QSizePolicy.Preferred) + sizePolicy = QtWidgets.QSizePolicy( + QtWidgets.QSizePolicy.Fixed, QtWidgets.QSizePolicy.Preferred + ) sizePolicy.setHorizontalStretch(0) sizePolicy.setVerticalStretch(0) sizePolicy.setHeightForWidth(self.lSlash.sizePolicy().hasHeightForWidth()) @@ -174,10 +216,14 @@ def setupUi(self, DialogModulation): self.lSlash.setObjectName("lSlash") self.gridLayout_4.addWidget(self.lSlash, 3, 3, 1, 1) self.btnSearchNext = QtWidgets.QPushButton(self.scrollAreaWidgetContents_5) - sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Fixed, QtWidgets.QSizePolicy.Fixed) + sizePolicy = QtWidgets.QSizePolicy( + QtWidgets.QSizePolicy.Fixed, QtWidgets.QSizePolicy.Fixed + ) sizePolicy.setHorizontalStretch(0) sizePolicy.setVerticalStretch(0) - sizePolicy.setHeightForWidth(self.btnSearchNext.sizePolicy().hasHeightForWidth()) + sizePolicy.setHeightForWidth( + self.btnSearchNext.sizePolicy().hasHeightForWidth() + ) self.btnSearchNext.setSizePolicy(sizePolicy) self.btnSearchNext.setMaximumSize(QtCore.QSize(16777215, 16777215)) self.btnSearchNext.setText("") @@ -186,10 +232,14 @@ def setupUi(self, DialogModulation): self.btnSearchNext.setObjectName("btnSearchNext") self.gridLayout_4.addWidget(self.btnSearchNext, 3, 5, 1, 1) self.chkBoxLockSIV = QtWidgets.QCheckBox(self.scrollAreaWidgetContents_5) - sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Maximum, QtWidgets.QSizePolicy.Fixed) + sizePolicy = QtWidgets.QSizePolicy( + QtWidgets.QSizePolicy.Maximum, QtWidgets.QSizePolicy.Fixed + ) sizePolicy.setHorizontalStretch(0) sizePolicy.setVerticalStretch(0) - sizePolicy.setHeightForWidth(self.chkBoxLockSIV.sizePolicy().hasHeightForWidth()) + sizePolicy.setHeightForWidth( + self.chkBoxLockSIV.sizePolicy().hasHeightForWidth() + ) self.chkBoxLockSIV.setSizePolicy(sizePolicy) self.chkBoxLockSIV.setObjectName("chkBoxLockSIV") self.gridLayout_4.addWidget(self.chkBoxLockSIV, 1, 0, 1, 5) @@ -197,26 +247,38 @@ def setupUi(self, DialogModulation): self.gridLayout_7.addWidget(self.scrollArea_5, 9, 0, 1, 1) self.horizontalLayout = QtWidgets.QHBoxLayout() self.horizontalLayout.setObjectName("horizontalLayout") - self.lSamplesInViewModulatedText = QtWidgets.QLabel(self.scrollAreaWidgetContents_2) - sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Maximum, QtWidgets.QSizePolicy.Preferred) + self.lSamplesInViewModulatedText = QtWidgets.QLabel( + self.scrollAreaWidgetContents_2 + ) + sizePolicy = QtWidgets.QSizePolicy( + QtWidgets.QSizePolicy.Maximum, QtWidgets.QSizePolicy.Preferred + ) sizePolicy.setHorizontalStretch(0) sizePolicy.setVerticalStretch(0) - sizePolicy.setHeightForWidth(self.lSamplesInViewModulatedText.sizePolicy().hasHeightForWidth()) + sizePolicy.setHeightForWidth( + self.lSamplesInViewModulatedText.sizePolicy().hasHeightForWidth() + ) self.lSamplesInViewModulatedText.setSizePolicy(sizePolicy) self.lSamplesInViewModulatedText.setObjectName("lSamplesInViewModulatedText") self.horizontalLayout.addWidget(self.lSamplesInViewModulatedText) self.lSamplesInViewModulated = QtWidgets.QLabel(self.scrollAreaWidgetContents_2) - sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Preferred, QtWidgets.QSizePolicy.Maximum) + sizePolicy = QtWidgets.QSizePolicy( + QtWidgets.QSizePolicy.Preferred, QtWidgets.QSizePolicy.Maximum + ) sizePolicy.setHorizontalStretch(0) sizePolicy.setVerticalStretch(0) - sizePolicy.setHeightForWidth(self.lSamplesInViewModulated.sizePolicy().hasHeightForWidth()) + sizePolicy.setHeightForWidth( + self.lSamplesInViewModulated.sizePolicy().hasHeightForWidth() + ) self.lSamplesInViewModulated.setSizePolicy(sizePolicy) self.lSamplesInViewModulated.setObjectName("lSamplesInViewModulated") self.horizontalLayout.addWidget(self.lSamplesInViewModulated) self.label_9 = QtWidgets.QLabel(self.scrollAreaWidgetContents_2) self.label_9.setObjectName("label_9") self.horizontalLayout.addWidget(self.label_9) - self.lModulatedSelectedSamples = QtWidgets.QLabel(self.scrollAreaWidgetContents_2) + self.lModulatedSelectedSamples = QtWidgets.QLabel( + self.scrollAreaWidgetContents_2 + ) self.lModulatedSelectedSamples.setObjectName("lModulatedSelectedSamples") self.horizontalLayout.addWidget(self.lModulatedSelectedSamples) self.gridLayout_7.addLayout(self.horizontalLayout, 6, 1, 1, 1) @@ -230,20 +292,28 @@ def setupUi(self, DialogModulation): self.gridLayout_2 = QtWidgets.QGridLayout(self.scrollAreaWidgetContents_3) self.gridLayout_2.setObjectName("gridLayout_2") self.spinBoxSampleRate = KillerDoubleSpinBox(self.scrollAreaWidgetContents_3) - sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Preferred, QtWidgets.QSizePolicy.Fixed) + sizePolicy = QtWidgets.QSizePolicy( + QtWidgets.QSizePolicy.Preferred, QtWidgets.QSizePolicy.Fixed + ) sizePolicy.setHorizontalStretch(0) sizePolicy.setVerticalStretch(0) - sizePolicy.setHeightForWidth(self.spinBoxSampleRate.sizePolicy().hasHeightForWidth()) + sizePolicy.setHeightForWidth( + self.spinBoxSampleRate.sizePolicy().hasHeightForWidth() + ) self.spinBoxSampleRate.setSizePolicy(sizePolicy) self.spinBoxSampleRate.setDecimals(10) self.spinBoxSampleRate.setMinimum(0.001) self.spinBoxSampleRate.setMaximum(999999999.0) self.spinBoxSampleRate.setObjectName("spinBoxSampleRate") self.gridLayout_2.addWidget(self.spinBoxSampleRate, 2, 1, 1, 1) - spacerItem3 = QtWidgets.QSpacerItem(20, 40, QtWidgets.QSizePolicy.Minimum, QtWidgets.QSizePolicy.Expanding) + spacerItem3 = QtWidgets.QSpacerItem( + 20, 40, QtWidgets.QSizePolicy.Minimum, QtWidgets.QSizePolicy.Expanding + ) self.gridLayout_2.addItem(spacerItem3, 3, 0, 1, 1) self.label_3 = QtWidgets.QLabel(self.scrollAreaWidgetContents_3) - sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Maximum, QtWidgets.QSizePolicy.Preferred) + sizePolicy = QtWidgets.QSizePolicy( + QtWidgets.QSizePolicy.Maximum, QtWidgets.QSizePolicy.Preferred + ) sizePolicy.setHorizontalStretch(0) sizePolicy.setVerticalStretch(0) sizePolicy.setHeightForWidth(self.label_3.sizePolicy().hasHeightForWidth()) @@ -251,28 +321,40 @@ def setupUi(self, DialogModulation): self.label_3.setObjectName("label_3") self.gridLayout_2.addWidget(self.label_3, 2, 0, 1, 1) self.label = QtWidgets.QLabel(self.scrollAreaWidgetContents_3) - sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Maximum, QtWidgets.QSizePolicy.Preferred) + sizePolicy = QtWidgets.QSizePolicy( + QtWidgets.QSizePolicy.Maximum, QtWidgets.QSizePolicy.Preferred + ) sizePolicy.setHorizontalStretch(0) sizePolicy.setVerticalStretch(0) sizePolicy.setHeightForWidth(self.label.sizePolicy().hasHeightForWidth()) self.label.setSizePolicy(sizePolicy) self.label.setObjectName("label") self.gridLayout_2.addWidget(self.label, 1, 0, 1, 1) - self.spinBoxSamplesPerSymbol = QtWidgets.QSpinBox(self.scrollAreaWidgetContents_3) - sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Preferred, QtWidgets.QSizePolicy.Fixed) + self.spinBoxSamplesPerSymbol = QtWidgets.QSpinBox( + self.scrollAreaWidgetContents_3 + ) + sizePolicy = QtWidgets.QSizePolicy( + QtWidgets.QSizePolicy.Preferred, QtWidgets.QSizePolicy.Fixed + ) sizePolicy.setHorizontalStretch(0) sizePolicy.setVerticalStretch(0) - sizePolicy.setHeightForWidth(self.spinBoxSamplesPerSymbol.sizePolicy().hasHeightForWidth()) + sizePolicy.setHeightForWidth( + self.spinBoxSamplesPerSymbol.sizePolicy().hasHeightForWidth() + ) self.spinBoxSamplesPerSymbol.setSizePolicy(sizePolicy) self.spinBoxSamplesPerSymbol.setMinimum(1) self.spinBoxSamplesPerSymbol.setMaximum(999999) self.spinBoxSamplesPerSymbol.setObjectName("spinBoxSamplesPerSymbol") self.gridLayout_2.addWidget(self.spinBoxSamplesPerSymbol, 1, 1, 1, 1) self.linEdDataBits = QtWidgets.QLineEdit(self.scrollAreaWidgetContents_3) - sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Preferred, QtWidgets.QSizePolicy.Preferred) + sizePolicy = QtWidgets.QSizePolicy( + QtWidgets.QSizePolicy.Preferred, QtWidgets.QSizePolicy.Preferred + ) sizePolicy.setHorizontalStretch(0) sizePolicy.setVerticalStretch(0) - sizePolicy.setHeightForWidth(self.linEdDataBits.sizePolicy().hasHeightForWidth()) + sizePolicy.setHeightForWidth( + self.linEdDataBits.sizePolicy().hasHeightForWidth() + ) self.linEdDataBits.setSizePolicy(sizePolicy) self.linEdDataBits.setObjectName("linEdDataBits") self.gridLayout_2.addWidget(self.linEdDataBits, 0, 0, 1, 2) @@ -288,18 +370,26 @@ def setupUi(self, DialogModulation): self.gridLayout = QtWidgets.QGridLayout(self.scrollAreaWidgetContents) self.gridLayout.setObjectName("gridLayout") self.lCarrierFreq = QtWidgets.QLabel(self.scrollAreaWidgetContents) - sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Maximum, QtWidgets.QSizePolicy.Preferred) + sizePolicy = QtWidgets.QSizePolicy( + QtWidgets.QSizePolicy.Maximum, QtWidgets.QSizePolicy.Preferred + ) sizePolicy.setHorizontalStretch(0) sizePolicy.setVerticalStretch(0) sizePolicy.setHeightForWidth(self.lCarrierFreq.sizePolicy().hasHeightForWidth()) self.lCarrierFreq.setSizePolicy(sizePolicy) self.lCarrierFreq.setObjectName("lCarrierFreq") self.gridLayout.addWidget(self.lCarrierFreq, 0, 0, 1, 1) - self.doubleSpinBoxCarrierFreq = KillerDoubleSpinBox(self.scrollAreaWidgetContents) - sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Preferred, QtWidgets.QSizePolicy.Fixed) + self.doubleSpinBoxCarrierFreq = KillerDoubleSpinBox( + self.scrollAreaWidgetContents + ) + sizePolicy = QtWidgets.QSizePolicy( + QtWidgets.QSizePolicy.Preferred, QtWidgets.QSizePolicy.Fixed + ) sizePolicy.setHorizontalStretch(0) sizePolicy.setVerticalStretch(0) - sizePolicy.setHeightForWidth(self.doubleSpinBoxCarrierFreq.sizePolicy().hasHeightForWidth()) + sizePolicy.setHeightForWidth( + self.doubleSpinBoxCarrierFreq.sizePolicy().hasHeightForWidth() + ) self.doubleSpinBoxCarrierFreq.setSizePolicy(sizePolicy) self.doubleSpinBoxCarrierFreq.setSuffix("") self.doubleSpinBoxCarrierFreq.setDecimals(10) @@ -308,18 +398,26 @@ def setupUi(self, DialogModulation): self.doubleSpinBoxCarrierFreq.setObjectName("doubleSpinBoxCarrierFreq") self.gridLayout.addWidget(self.doubleSpinBoxCarrierFreq, 0, 1, 1, 1) self.label_2 = QtWidgets.QLabel(self.scrollAreaWidgetContents) - sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Maximum, QtWidgets.QSizePolicy.Preferred) + sizePolicy = QtWidgets.QSizePolicy( + QtWidgets.QSizePolicy.Maximum, QtWidgets.QSizePolicy.Preferred + ) sizePolicy.setHorizontalStretch(0) sizePolicy.setVerticalStretch(0) sizePolicy.setHeightForWidth(self.label_2.sizePolicy().hasHeightForWidth()) self.label_2.setSizePolicy(sizePolicy) self.label_2.setObjectName("label_2") self.gridLayout.addWidget(self.label_2, 1, 0, 1, 1) - self.doubleSpinBoxCarrierPhase = QtWidgets.QDoubleSpinBox(self.scrollAreaWidgetContents) - sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Preferred, QtWidgets.QSizePolicy.Fixed) + self.doubleSpinBoxCarrierPhase = QtWidgets.QDoubleSpinBox( + self.scrollAreaWidgetContents + ) + sizePolicy = QtWidgets.QSizePolicy( + QtWidgets.QSizePolicy.Preferred, QtWidgets.QSizePolicy.Fixed + ) sizePolicy.setHorizontalStretch(0) sizePolicy.setVerticalStretch(0) - sizePolicy.setHeightForWidth(self.doubleSpinBoxCarrierPhase.sizePolicy().hasHeightForWidth()) + sizePolicy.setHeightForWidth( + self.doubleSpinBoxCarrierPhase.sizePolicy().hasHeightForWidth() + ) self.doubleSpinBoxCarrierPhase.setSizePolicy(sizePolicy) self.doubleSpinBoxCarrierPhase.setDecimals(3) self.doubleSpinBoxCarrierPhase.setMaximum(360.0) @@ -327,19 +425,27 @@ def setupUi(self, DialogModulation): self.gridLayout.addWidget(self.doubleSpinBoxCarrierPhase, 1, 1, 1, 1) self.btnAutoDetect = QtWidgets.QPushButton(self.scrollAreaWidgetContents) self.btnAutoDetect.setEnabled(False) - sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Preferred, QtWidgets.QSizePolicy.Fixed) + sizePolicy = QtWidgets.QSizePolicy( + QtWidgets.QSizePolicy.Preferred, QtWidgets.QSizePolicy.Fixed + ) sizePolicy.setHorizontalStretch(0) sizePolicy.setVerticalStretch(0) - sizePolicy.setHeightForWidth(self.btnAutoDetect.sizePolicy().hasHeightForWidth()) + sizePolicy.setHeightForWidth( + self.btnAutoDetect.sizePolicy().hasHeightForWidth() + ) self.btnAutoDetect.setSizePolicy(sizePolicy) self.btnAutoDetect.setObjectName("btnAutoDetect") self.gridLayout.addWidget(self.btnAutoDetect, 2, 0, 1, 2) - spacerItem4 = QtWidgets.QSpacerItem(20, 40, QtWidgets.QSizePolicy.Minimum, QtWidgets.QSizePolicy.Expanding) + spacerItem4 = QtWidgets.QSpacerItem( + 20, 40, QtWidgets.QSizePolicy.Minimum, QtWidgets.QSizePolicy.Expanding + ) self.gridLayout.addItem(spacerItem4, 3, 0, 1, 1) self.scrollArea_2.setWidget(self.scrollAreaWidgetContents) self.gridLayout_7.addWidget(self.scrollArea_2, 1, 0, 1, 1) self.lPlus = QtWidgets.QLabel(self.scrollAreaWidgetContents_2) - sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Maximum, QtWidgets.QSizePolicy.Fixed) + sizePolicy = QtWidgets.QSizePolicy( + QtWidgets.QSizePolicy.Maximum, QtWidgets.QSizePolicy.Fixed + ) sizePolicy.setHorizontalStretch(0) sizePolicy.setVerticalStretch(0) sizePolicy.setHeightForWidth(self.lPlus.sizePolicy().hasHeightForWidth()) @@ -352,7 +458,9 @@ def setupUi(self, DialogModulation): self.lPlus.setObjectName("lPlus") self.gridLayout_7.addWidget(self.lPlus, 2, 2, 1, 1) self.gVCarrier = ZoomableGraphicView(self.scrollAreaWidgetContents_2) - sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Expanding, QtWidgets.QSizePolicy.Expanding) + sizePolicy = QtWidgets.QSizePolicy( + QtWidgets.QSizePolicy.Expanding, QtWidgets.QSizePolicy.Expanding + ) sizePolicy.setHorizontalStretch(0) sizePolicy.setVerticalStretch(0) sizePolicy.setHeightForWidth(self.gVCarrier.sizePolicy().hasHeightForWidth()) @@ -360,14 +468,20 @@ def setupUi(self, DialogModulation): self.gVCarrier.setAcceptDrops(False) self.gVCarrier.setVerticalScrollBarPolicy(QtCore.Qt.ScrollBarAlwaysOff) self.gVCarrier.setHorizontalScrollBarPolicy(QtCore.Qt.ScrollBarAlwaysOn) - self.gVCarrier.setRenderHints(QtGui.QPainter.Antialiasing|QtGui.QPainter.HighQualityAntialiasing) + self.gVCarrier.setRenderHints( + QtGui.QPainter.Antialiasing | QtGui.QPainter.HighQualityAntialiasing + ) self.gVCarrier.setDragMode(QtWidgets.QGraphicsView.NoDrag) self.gVCarrier.setObjectName("gVCarrier") self.gridLayout_7.addWidget(self.gVCarrier, 1, 1, 1, 3) - spacerItem5 = QtWidgets.QSpacerItem(40, 20, QtWidgets.QSizePolicy.Expanding, QtWidgets.QSizePolicy.Minimum) + spacerItem5 = QtWidgets.QSpacerItem( + 40, 20, QtWidgets.QSizePolicy.Expanding, QtWidgets.QSizePolicy.Minimum + ) self.gridLayout_7.addItem(spacerItem5, 2, 1, 1, 1) self.gVModulated = ZoomableGraphicView(self.scrollAreaWidgetContents_2) - sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Expanding, QtWidgets.QSizePolicy.Expanding) + sizePolicy = QtWidgets.QSizePolicy( + QtWidgets.QSizePolicy.Expanding, QtWidgets.QSizePolicy.Expanding + ) sizePolicy.setHorizontalStretch(0) sizePolicy.setVerticalStretch(0) sizePolicy.setHeightForWidth(self.gVModulated.sizePolicy().hasHeightForWidth()) @@ -375,12 +489,16 @@ def setupUi(self, DialogModulation): self.gVModulated.setAcceptDrops(False) self.gVModulated.setVerticalScrollBarPolicy(QtCore.Qt.ScrollBarAlwaysOff) self.gVModulated.setHorizontalScrollBarPolicy(QtCore.Qt.ScrollBarAlwaysOn) - self.gVModulated.setRenderHints(QtGui.QPainter.Antialiasing|QtGui.QPainter.HighQualityAntialiasing) + self.gVModulated.setRenderHints( + QtGui.QPainter.Antialiasing | QtGui.QPainter.HighQualityAntialiasing + ) self.gVModulated.setDragMode(QtWidgets.QGraphicsView.NoDrag) self.gVModulated.setObjectName("gVModulated") self.gridLayout_7.addWidget(self.gVModulated, 5, 1, 1, 3) self.gVData = ZoomableGraphicView(self.scrollAreaWidgetContents_2) - sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Expanding, QtWidgets.QSizePolicy.Expanding) + sizePolicy = QtWidgets.QSizePolicy( + QtWidgets.QSizePolicy.Expanding, QtWidgets.QSizePolicy.Expanding + ) sizePolicy.setHorizontalStretch(0) sizePolicy.setVerticalStretch(0) sizePolicy.setHeightForWidth(self.gVData.sizePolicy().hasHeightForWidth()) @@ -388,7 +506,9 @@ def setupUi(self, DialogModulation): self.gVData.setAcceptDrops(False) self.gVData.setVerticalScrollBarPolicy(QtCore.Qt.ScrollBarAlwaysOff) self.gVData.setHorizontalScrollBarPolicy(QtCore.Qt.ScrollBarAlwaysOn) - self.gVData.setRenderHints(QtGui.QPainter.Antialiasing|QtGui.QPainter.HighQualityAntialiasing) + self.gVData.setRenderHints( + QtGui.QPainter.Antialiasing | QtGui.QPainter.HighQualityAntialiasing + ) self.gVData.setDragMode(QtWidgets.QGraphicsView.NoDrag) self.gVData.setObjectName("gVData") self.gridLayout_7.addWidget(self.gVData, 3, 1, 1, 3) @@ -418,7 +538,9 @@ def setupUi(self, DialogModulation): self.lGaussBT = QtWidgets.QLabel(self.scrollAreaWidgetContents_4) self.lGaussBT.setObjectName("lGaussBT") self.gridLayout_3.addWidget(self.lGaussBT, 3, 0, 1, 1) - self.spinBoxGaussFilterWidth = QtWidgets.QDoubleSpinBox(self.scrollAreaWidgetContents_4) + self.spinBoxGaussFilterWidth = QtWidgets.QDoubleSpinBox( + self.scrollAreaWidgetContents_4 + ) self.spinBoxGaussFilterWidth.setMinimum(0.01) self.spinBoxGaussFilterWidth.setMaximum(100.0) self.spinBoxGaussFilterWidth.setSingleStep(0.01) @@ -428,19 +550,29 @@ def setupUi(self, DialogModulation): self.labelBitsPerSymbol = QtWidgets.QLabel(self.scrollAreaWidgetContents_4) self.labelBitsPerSymbol.setObjectName("labelBitsPerSymbol") self.gridLayout_3.addWidget(self.labelBitsPerSymbol, 1, 0, 1, 1) - spacerItem6 = QtWidgets.QSpacerItem(20, 40, QtWidgets.QSizePolicy.Minimum, QtWidgets.QSizePolicy.Expanding) + spacerItem6 = QtWidgets.QSpacerItem( + 20, 40, QtWidgets.QSizePolicy.Minimum, QtWidgets.QSizePolicy.Expanding + ) self.gridLayout_3.addItem(spacerItem6, 5, 0, 1, 1) - spacerItem7 = QtWidgets.QSpacerItem(20, 40, QtWidgets.QSizePolicy.Minimum, QtWidgets.QSizePolicy.Expanding) + spacerItem7 = QtWidgets.QSpacerItem( + 20, 40, QtWidgets.QSizePolicy.Minimum, QtWidgets.QSizePolicy.Expanding + ) self.gridLayout_3.addItem(spacerItem7, 5, 1, 1, 1) self.lineEditParameters = QtWidgets.QLineEdit(self.scrollAreaWidgetContents_4) self.lineEditParameters.setClearButtonEnabled(False) self.lineEditParameters.setObjectName("lineEditParameters") self.gridLayout_3.addWidget(self.lineEditParameters, 2, 1, 1, 1) - self.comboBoxModulationType = QtWidgets.QComboBox(self.scrollAreaWidgetContents_4) - sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Preferred, QtWidgets.QSizePolicy.Preferred) + self.comboBoxModulationType = QtWidgets.QComboBox( + self.scrollAreaWidgetContents_4 + ) + sizePolicy = QtWidgets.QSizePolicy( + QtWidgets.QSizePolicy.Preferred, QtWidgets.QSizePolicy.Preferred + ) sizePolicy.setHorizontalStretch(0) sizePolicy.setVerticalStretch(0) - sizePolicy.setHeightForWidth(self.comboBoxModulationType.sizePolicy().hasHeightForWidth()) + sizePolicy.setHeightForWidth( + self.comboBoxModulationType.sizePolicy().hasHeightForWidth() + ) self.comboBoxModulationType.setSizePolicy(sizePolicy) self.comboBoxModulationType.setMaximumSize(QtCore.QSize(16777215, 16777215)) self.comboBoxModulationType.setObjectName("comboBoxModulationType") @@ -454,12 +586,18 @@ def setupUi(self, DialogModulation): self.gridLayout_3.addWidget(self.labelParameters, 2, 0, 1, 1) self.scrollArea_4.setWidget(self.scrollAreaWidgetContents_4) self.gridLayout_7.addWidget(self.scrollArea_4, 5, 0, 1, 1) - spacerItem8 = QtWidgets.QSpacerItem(40, 20, QtWidgets.QSizePolicy.Expanding, QtWidgets.QSizePolicy.Minimum) + spacerItem8 = QtWidgets.QSpacerItem( + 40, 20, QtWidgets.QSizePolicy.Expanding, QtWidgets.QSizePolicy.Minimum + ) self.gridLayout_7.addItem(spacerItem8, 4, 3, 1, 1) - spacerItem9 = QtWidgets.QSpacerItem(40, 20, QtWidgets.QSizePolicy.Expanding, QtWidgets.QSizePolicy.Minimum) + spacerItem9 = QtWidgets.QSpacerItem( + 40, 20, QtWidgets.QSizePolicy.Expanding, QtWidgets.QSizePolicy.Minimum + ) self.gridLayout_7.addItem(spacerItem9, 8, 3, 1, 1) self.lEqual_qm = QtWidgets.QLabel(self.scrollAreaWidgetContents_2) - sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Fixed, QtWidgets.QSizePolicy.Fixed) + sizePolicy = QtWidgets.QSizePolicy( + QtWidgets.QSizePolicy.Fixed, QtWidgets.QSizePolicy.Fixed + ) sizePolicy.setHorizontalStretch(0) sizePolicy.setVerticalStretch(0) sizePolicy.setHeightForWidth(self.lEqual_qm.sizePolicy().hasHeightForWidth()) @@ -473,27 +611,43 @@ def setupUi(self, DialogModulation): self.gridLayout_7.addWidget(self.lEqual_qm, 8, 2, 1, 1) self.horizontalLayout_2 = QtWidgets.QHBoxLayout() self.horizontalLayout_2.setObjectName("horizontalLayout_2") - self.lSamplesInViewOrigSignalText = QtWidgets.QLabel(self.scrollAreaWidgetContents_2) - sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Maximum, QtWidgets.QSizePolicy.Preferred) + self.lSamplesInViewOrigSignalText = QtWidgets.QLabel( + self.scrollAreaWidgetContents_2 + ) + sizePolicy = QtWidgets.QSizePolicy( + QtWidgets.QSizePolicy.Maximum, QtWidgets.QSizePolicy.Preferred + ) sizePolicy.setHorizontalStretch(0) sizePolicy.setVerticalStretch(0) - sizePolicy.setHeightForWidth(self.lSamplesInViewOrigSignalText.sizePolicy().hasHeightForWidth()) + sizePolicy.setHeightForWidth( + self.lSamplesInViewOrigSignalText.sizePolicy().hasHeightForWidth() + ) self.lSamplesInViewOrigSignalText.setSizePolicy(sizePolicy) self.lSamplesInViewOrigSignalText.setObjectName("lSamplesInViewOrigSignalText") self.horizontalLayout_2.addWidget(self.lSamplesInViewOrigSignalText) - self.lSamplesInViewOrigSignal = QtWidgets.QLabel(self.scrollAreaWidgetContents_2) - sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Preferred, QtWidgets.QSizePolicy.Preferred) + self.lSamplesInViewOrigSignal = QtWidgets.QLabel( + self.scrollAreaWidgetContents_2 + ) + sizePolicy = QtWidgets.QSizePolicy( + QtWidgets.QSizePolicy.Preferred, QtWidgets.QSizePolicy.Preferred + ) sizePolicy.setHorizontalStretch(0) sizePolicy.setVerticalStretch(0) - sizePolicy.setHeightForWidth(self.lSamplesInViewOrigSignal.sizePolicy().hasHeightForWidth()) + sizePolicy.setHeightForWidth( + self.lSamplesInViewOrigSignal.sizePolicy().hasHeightForWidth() + ) self.lSamplesInViewOrigSignal.setSizePolicy(sizePolicy) self.lSamplesInViewOrigSignal.setObjectName("lSamplesInViewOrigSignal") self.horizontalLayout_2.addWidget(self.lSamplesInViewOrigSignal) self.label_10 = QtWidgets.QLabel(self.scrollAreaWidgetContents_2) self.label_10.setObjectName("label_10") self.horizontalLayout_2.addWidget(self.label_10) - self.lOriginalSignalSamplesSelected = QtWidgets.QLabel(self.scrollAreaWidgetContents_2) - self.lOriginalSignalSamplesSelected.setObjectName("lOriginalSignalSamplesSelected") + self.lOriginalSignalSamplesSelected = QtWidgets.QLabel( + self.scrollAreaWidgetContents_2 + ) + self.lOriginalSignalSamplesSelected.setObjectName( + "lOriginalSignalSamplesSelected" + ) self.horizontalLayout_2.addWidget(self.lOriginalSignalSamplesSelected) self.gridLayout_7.addLayout(self.horizontalLayout_2, 10, 1, 1, 1) self.gridLayout_7.setRowStretch(1, 1) @@ -506,15 +660,21 @@ def setupUi(self, DialogModulation): self.retranslateUi(DialogModulation) DialogModulation.setTabOrder(self.btnAddModulation, self.scrollArea_2) DialogModulation.setTabOrder(self.scrollArea_2, self.doubleSpinBoxCarrierFreq) - DialogModulation.setTabOrder(self.doubleSpinBoxCarrierFreq, self.doubleSpinBoxCarrierPhase) + DialogModulation.setTabOrder( + self.doubleSpinBoxCarrierFreq, self.doubleSpinBoxCarrierPhase + ) DialogModulation.setTabOrder(self.doubleSpinBoxCarrierPhase, self.btnAutoDetect) DialogModulation.setTabOrder(self.btnAutoDetect, self.scrollArea_3) DialogModulation.setTabOrder(self.scrollArea_3, self.linEdDataBits) DialogModulation.setTabOrder(self.linEdDataBits, self.spinBoxSamplesPerSymbol) - DialogModulation.setTabOrder(self.spinBoxSamplesPerSymbol, self.spinBoxSampleRate) + DialogModulation.setTabOrder( + self.spinBoxSamplesPerSymbol, self.spinBoxSampleRate + ) DialogModulation.setTabOrder(self.spinBoxSampleRate, self.scrollArea_4) DialogModulation.setTabOrder(self.scrollArea_4, self.comboBoxModulationType) - DialogModulation.setTabOrder(self.comboBoxModulationType, self.spinBoxBitsPerSymbol) + DialogModulation.setTabOrder( + self.comboBoxModulationType, self.spinBoxBitsPerSymbol + ) DialogModulation.setTabOrder(self.spinBoxBitsPerSymbol, self.lineEditParameters) DialogModulation.setTabOrder(self.lineEditParameters, self.spinBoxGaussBT) DialogModulation.setTabOrder(self.spinBoxGaussBT, self.spinBoxGaussFilterWidth) @@ -529,51 +689,97 @@ def setupUi(self, DialogModulation): DialogModulation.setTabOrder(self.cbShowDataBitsOnly, self.btnSearchPrev) DialogModulation.setTabOrder(self.btnSearchPrev, self.btnSearchNext) DialogModulation.setTabOrder(self.btnSearchNext, self.btnRemoveModulation) - DialogModulation.setTabOrder(self.btnRemoveModulation, self.comboBoxCustomModulations) + DialogModulation.setTabOrder( + self.btnRemoveModulation, self.comboBoxCustomModulations + ) DialogModulation.setTabOrder(self.comboBoxCustomModulations, self.scrollArea) def retranslateUi(self, DialogModulation): _translate = QtCore.QCoreApplication.translate DialogModulation.setWindowTitle(_translate("DialogModulation", "Modulation")) - self.comboBoxCustomModulations.setItemText(0, _translate("DialogModulation", "My Modulation")) + self.comboBoxCustomModulations.setItemText( + 0, _translate("DialogModulation", "My Modulation") + ) self.btnAddModulation.setText(_translate("DialogModulation", "...")) self.btnRemoveModulation.setText(_translate("DialogModulation", "...")) self.label_5.setText(_translate("DialogModulation", "Data (raw bits)")) self.label_6.setText(_translate("DialogModulation", "Modulation")) - self.label_7.setText(_translate("DialogModulation", "Original Signal (drag&drop)")) + self.label_7.setText( + _translate("DialogModulation", "Original Signal (drag&drop)") + ) self.label_4.setText(_translate("DialogModulation", "Carrier")) self.lCurrentSearchResult.setText(_translate("DialogModulation", "-")) - self.cbShowDataBitsOnly.setText(_translate("DialogModulation", "Show Only Data Sequence\n" -"(10)")) + self.cbShowDataBitsOnly.setText( + _translate("DialogModulation", "Show Only Data Sequence\n" "(10)") + ) self.lTotalSearchresults.setText(_translate("DialogModulation", "-")) self.lSlash.setText(_translate("DialogModulation", "/")) - self.chkBoxLockSIV.setText(_translate("DialogModulation", "Lock view to original signal")) - self.lSamplesInViewModulatedText.setText(_translate("DialogModulation", "Samples in View:")) - self.lSamplesInViewModulated.setToolTip(_translate("DialogModulation", "

Shown Samples in View:

Red - if samples in view differ from original signal

Normal - if samples in view are equal to the original signal

")) - self.lSamplesInViewModulated.setText(_translate("DialogModulation", "101010121")) + self.chkBoxLockSIV.setText( + _translate("DialogModulation", "Lock view to original signal") + ) + self.lSamplesInViewModulatedText.setText( + _translate("DialogModulation", "Samples in View:") + ) + self.lSamplesInViewModulated.setToolTip( + _translate( + "DialogModulation", + '

Shown Samples in View:

Red - if samples in view differ from original signal

Normal - if samples in view are equal to the original signal

', + ) + ) + self.lSamplesInViewModulated.setText( + _translate("DialogModulation", "101010121") + ) self.label_9.setText(_translate("DialogModulation", "Samples selected:")) self.lModulatedSelectedSamples.setText(_translate("DialogModulation", "0")) self.label_3.setText(_translate("DialogModulation", "Sample Rate (Sps):")) self.label.setText(_translate("DialogModulation", "Samples per Symbol:")) - self.linEdDataBits.setPlaceholderText(_translate("DialogModulation", "Enter Data Bits here")) + self.linEdDataBits.setPlaceholderText( + _translate("DialogModulation", "Enter Data Bits here") + ) self.lCarrierFreq.setText(_translate("DialogModulation", "Frequency:")) self.label_2.setText(_translate("DialogModulation", "Phase:")) self.doubleSpinBoxCarrierPhase.setSuffix(_translate("DialogModulation", "°")) - self.btnAutoDetect.setToolTip(_translate("DialogModulation", "

Auto detect the frequency based on the original signal. You have to select a signal (bottom of this window) to use this feature.


Select a signal by dragging it from the tree and dropping it on the graphics pane to the right.

")) - self.btnAutoDetect.setText(_translate("DialogModulation", "Auto detect from original signal")) + self.btnAutoDetect.setToolTip( + _translate( + "DialogModulation", + '

Auto detect the frequency based on the original signal. You have to select a signal (bottom of this window) to use this feature.


Select a signal by dragging it from the tree and dropping it on the graphics pane to the right.

', + ) + ) + self.btnAutoDetect.setText( + _translate("DialogModulation", "Auto detect from original signal") + ) self.lGaussWidth.setText(_translate("DialogModulation", "Gauss filter width:")) self.lGaussBT.setText(_translate("DialogModulation", "Gauss BT:")) - self.labelBitsPerSymbol.setText(_translate("DialogModulation", "Bits per Symbol:")) - self.comboBoxModulationType.setItemText(0, _translate("DialogModulation", "Amplitude Shift Keying (ASK)")) - self.comboBoxModulationType.setItemText(1, _translate("DialogModulation", "Frequency Shift Keying (FSK)")) - self.comboBoxModulationType.setItemText(2, _translate("DialogModulation", "Gaussian Frequency Shift Keying (GFSK)")) - self.comboBoxModulationType.setItemText(3, _translate("DialogModulation", "Phase Shift Keying (PSK)")) + self.labelBitsPerSymbol.setText( + _translate("DialogModulation", "Bits per Symbol:") + ) + self.comboBoxModulationType.setItemText( + 0, _translate("DialogModulation", "Amplitude Shift Keying (ASK)") + ) + self.comboBoxModulationType.setItemText( + 1, _translate("DialogModulation", "Frequency Shift Keying (FSK)") + ) + self.comboBoxModulationType.setItemText( + 2, _translate("DialogModulation", "Gaussian Frequency Shift Keying (GFSK)") + ) + self.comboBoxModulationType.setItemText( + 3, _translate("DialogModulation", "Phase Shift Keying (PSK)") + ) self.labelParameters.setText(_translate("DialogModulation", "Parameters:")) - self.lSamplesInViewOrigSignalText.setText(_translate("DialogModulation", "Samples in View:")) - self.lSamplesInViewOrigSignal.setToolTip(_translate("DialogModulation", "

Shown Samples in View:

Red - if samples in view differ from original signal

Normal - if samples in view are equal to the original signal

")) + self.lSamplesInViewOrigSignalText.setText( + _translate("DialogModulation", "Samples in View:") + ) + self.lSamplesInViewOrigSignal.setToolTip( + _translate( + "DialogModulation", + '

Shown Samples in View:

Red - if samples in view differ from original signal

Normal - if samples in view are equal to the original signal

', + ) + ) self.lSamplesInViewOrigSignal.setText(_translate("DialogModulation", "0")) self.label_10.setText(_translate("DialogModulation", "Samples selected:")) self.lOriginalSignalSamplesSelected.setText(_translate("DialogModulation", "0")) + + from urh.ui.KillerDoubleSpinBox import KillerDoubleSpinBox from urh.ui.views.ModulatorTreeView import ModulatorTreeView from urh.ui.views.ZoomAndDropableGraphicView import ZoomAndDropableGraphicView diff --git a/src/urh/ui/ui_modulation_parameters_dialog.py b/src/urh/ui/ui_modulation_parameters_dialog.py index 62d1f9b6e2..61a6e79f6d 100644 --- a/src/urh/ui/ui_modulation_parameters_dialog.py +++ b/src/urh/ui/ui_modulation_parameters_dialog.py @@ -28,7 +28,9 @@ def setupUi(self, DialogModulationParameters): self.tblSymbolParameters.verticalHeader().setVisible(False) self.verticalLayout.addWidget(self.tblSymbolParameters) self.buttonBox = QtWidgets.QDialogButtonBox(DialogModulationParameters) - self.buttonBox.setStandardButtons(QtWidgets.QDialogButtonBox.Cancel|QtWidgets.QDialogButtonBox.Ok) + self.buttonBox.setStandardButtons( + QtWidgets.QDialogButtonBox.Cancel | QtWidgets.QDialogButtonBox.Ok + ) self.buttonBox.setObjectName("buttonBox") self.verticalLayout.addWidget(self.buttonBox) @@ -36,7 +38,9 @@ def setupUi(self, DialogModulationParameters): def retranslateUi(self, DialogModulationParameters): _translate = QtCore.QCoreApplication.translate - DialogModulationParameters.setWindowTitle(_translate("DialogModulationParameters", "Modulation Parameters")) + DialogModulationParameters.setWindowTitle( + _translate("DialogModulationParameters", "Modulation Parameters") + ) item = self.tblSymbolParameters.horizontalHeaderItem(0) item.setText(_translate("DialogModulationParameters", "Symbol")) item = self.tblSymbolParameters.horizontalHeaderItem(1) diff --git a/src/urh/ui/ui_modulation_settings_widget.py b/src/urh/ui/ui_modulation_settings_widget.py index 2d9256a99a..f2b4d0714d 100644 --- a/src/urh/ui/ui_modulation_settings_widget.py +++ b/src/urh/ui/ui_modulation_settings_widget.py @@ -20,20 +20,22 @@ def setupUi(self, ModulationSettings): font.setBold(True) font.setWeight(75) self.groupBoxSniffSettings.setFont(font) - self.groupBoxSniffSettings.setStyleSheet("QGroupBox\n" -"{\n" -"border: none;\n" -"}\n" -"\n" -"QGroupBox::title {\n" -" subcontrol-origin: margin;\n" -"}\n" -"QGroupBox::indicator:unchecked {\n" -" image: url(:/icons/icons/collapse.svg)\n" -"}\n" -"QGroupBox::indicator:checked {\n" -" image: url(:/icons/icons/uncollapse.svg)\n" -"}") + self.groupBoxSniffSettings.setStyleSheet( + "QGroupBox\n" + "{\n" + "border: none;\n" + "}\n" + "\n" + "QGroupBox::title {\n" + " subcontrol-origin: margin;\n" + "}\n" + "QGroupBox::indicator:unchecked {\n" + " image: url(:/icons/icons/collapse.svg)\n" + "}\n" + "QGroupBox::indicator:checked {\n" + " image: url(:/icons/icons/uncollapse.svg)\n" + "}" + ) self.groupBoxSniffSettings.setFlat(True) self.groupBoxSniffSettings.setCheckable(True) self.groupBoxSniffSettings.setObjectName("groupBoxSniffSettings") @@ -56,10 +58,14 @@ def setupUi(self, ModulationSettings): self.gridLayout = QtWidgets.QGridLayout() self.gridLayout.setObjectName("gridLayout") self.labelCarrierFrequencyValue = QtWidgets.QLabel(self.frame) - sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Preferred, QtWidgets.QSizePolicy.Preferred) + sizePolicy = QtWidgets.QSizePolicy( + QtWidgets.QSizePolicy.Preferred, QtWidgets.QSizePolicy.Preferred + ) sizePolicy.setHorizontalStretch(0) sizePolicy.setVerticalStretch(0) - sizePolicy.setHeightForWidth(self.labelCarrierFrequencyValue.sizePolicy().hasHeightForWidth()) + sizePolicy.setHeightForWidth( + self.labelCarrierFrequencyValue.sizePolicy().hasHeightForWidth() + ) self.labelCarrierFrequencyValue.setSizePolicy(sizePolicy) self.labelCarrierFrequencyValue.setObjectName("labelCarrierFrequencyValue") self.gridLayout.addWidget(self.labelCarrierFrequencyValue, 0, 1, 1, 1) @@ -112,33 +118,61 @@ def setupUi(self, ModulationSettings): self.btnConfigurationDialog.setIcon(icon) self.btnConfigurationDialog.setObjectName("btnConfigurationDialog") self.verticalLayout_2.addWidget(self.btnConfigurationDialog) - spacerItem = QtWidgets.QSpacerItem(20, 40, QtWidgets.QSizePolicy.Minimum, QtWidgets.QSizePolicy.Expanding) + spacerItem = QtWidgets.QSpacerItem( + 20, 40, QtWidgets.QSizePolicy.Minimum, QtWidgets.QSizePolicy.Expanding + ) self.verticalLayout_2.addItem(spacerItem) self.gridLayout_3.addWidget(self.frame, 0, 0, 1, 1) self.verticalLayout.addWidget(self.groupBoxSniffSettings) self.retranslateUi(ModulationSettings) - self.groupBoxSniffSettings.toggled['bool'].connect(self.frame.setVisible) - ModulationSettings.setTabOrder(self.groupBoxSniffSettings, self.comboBoxModulationProfiles) - ModulationSettings.setTabOrder(self.comboBoxModulationProfiles, self.btnConfigurationDialog) + self.groupBoxSniffSettings.toggled["bool"].connect(self.frame.setVisible) + ModulationSettings.setTabOrder( + self.groupBoxSniffSettings, self.comboBoxModulationProfiles + ) + ModulationSettings.setTabOrder( + self.comboBoxModulationProfiles, self.btnConfigurationDialog + ) def retranslateUi(self, ModulationSettings): _translate = QtCore.QCoreApplication.translate ModulationSettings.setWindowTitle(_translate("ModulationSettings", "Form")) - self.groupBoxSniffSettings.setTitle(_translate("ModulationSettings", "Modulation settings")) - self.labelModulationProfile.setText(_translate("ModulationSettings", "Choose profile:")) - self.labelCarrierFrequencyValue.setText(_translate("ModulationSettings", "TextLabel")) + self.groupBoxSniffSettings.setTitle( + _translate("ModulationSettings", "Modulation settings") + ) + self.labelModulationProfile.setText( + _translate("ModulationSettings", "Choose profile:") + ) + self.labelCarrierFrequencyValue.setText( + _translate("ModulationSettings", "TextLabel") + ) self.labelSampleRate.setText(_translate("ModulationSettings", "Sample Rate:")) - self.labelCarrierFrequency.setText(_translate("ModulationSettings", "Carrier Frequency:")) - self.labelSamplesPerSymbol.setText(_translate("ModulationSettings", "Samples per Symbol:")) + self.labelCarrierFrequency.setText( + _translate("ModulationSettings", "Carrier Frequency:") + ) + self.labelSamplesPerSymbol.setText( + _translate("ModulationSettings", "Samples per Symbol:") + ) self.labelSampleRateValue.setText(_translate("ModulationSettings", "TextLabel")) - self.labelModulationType.setText(_translate("ModulationSettings", "Modulation type:")) - self.labelSamplesPerSymbolValue.setText(_translate("ModulationSettings", "TextLabel")) - self.labelModulationTypeValue.setText(_translate("ModulationSettings", "TextLabel")) - self.labelParameters.setText(_translate("ModulationSettings", "Amplitudes in %:")) + self.labelModulationType.setText( + _translate("ModulationSettings", "Modulation type:") + ) + self.labelSamplesPerSymbolValue.setText( + _translate("ModulationSettings", "TextLabel") + ) + self.labelModulationTypeValue.setText( + _translate("ModulationSettings", "TextLabel") + ) + self.labelParameters.setText( + _translate("ModulationSettings", "Amplitudes in %:") + ) self.labelParameterValues.setText(_translate("ModulationSettings", "0/100")) self.label.setText(_translate("ModulationSettings", "Bits per Symbol:")) self.labelBitsPerSymbol.setText(_translate("ModulationSettings", "1")) - self.btnConfigurationDialog.setText(_translate("ModulationSettings", "Open modulation configuration dialog...")) + self.btnConfigurationDialog.setText( + _translate("ModulationSettings", "Open modulation configuration dialog...") + ) + + from urh.ui.ElidedLabel import ElidedLabel from . import urh_rc diff --git a/src/urh/ui/ui_options.py b/src/urh/ui/ui_options.py index 99052ed25a..94d77335ee 100644 --- a/src/urh/ui/ui_options.py +++ b/src/urh/ui/ui_options.py @@ -44,17 +44,31 @@ def setupUi(self, DialogOptions): self.groupBoxModulationAccuracy.setObjectName("groupBoxModulationAccuracy") self.verticalLayout_7 = QtWidgets.QVBoxLayout(self.groupBoxModulationAccuracy) self.verticalLayout_7.setObjectName("verticalLayout_7") - self.radioButtonLowModulationAccuracy = QtWidgets.QRadioButton(self.groupBoxModulationAccuracy) - self.radioButtonLowModulationAccuracy.setObjectName("radioButtonLowModulationAccuracy") + self.radioButtonLowModulationAccuracy = QtWidgets.QRadioButton( + self.groupBoxModulationAccuracy + ) + self.radioButtonLowModulationAccuracy.setObjectName( + "radioButtonLowModulationAccuracy" + ) self.verticalLayout_7.addWidget(self.radioButtonLowModulationAccuracy) - self.radioButtonMediumModulationAccuracy = QtWidgets.QRadioButton(self.groupBoxModulationAccuracy) - self.radioButtonMediumModulationAccuracy.setObjectName("radioButtonMediumModulationAccuracy") + self.radioButtonMediumModulationAccuracy = QtWidgets.QRadioButton( + self.groupBoxModulationAccuracy + ) + self.radioButtonMediumModulationAccuracy.setObjectName( + "radioButtonMediumModulationAccuracy" + ) self.verticalLayout_7.addWidget(self.radioButtonMediumModulationAccuracy) - self.radioButtonHighModulationAccuracy = QtWidgets.QRadioButton(self.groupBoxModulationAccuracy) - self.radioButtonHighModulationAccuracy.setObjectName("radioButtonHighModulationAccuracy") + self.radioButtonHighModulationAccuracy = QtWidgets.QRadioButton( + self.groupBoxModulationAccuracy + ) + self.radioButtonHighModulationAccuracy.setObjectName( + "radioButtonHighModulationAccuracy" + ) self.verticalLayout_7.addWidget(self.radioButtonHighModulationAccuracy) self.verticalLayout_9.addWidget(self.groupBoxModulationAccuracy) - spacerItem = QtWidgets.QSpacerItem(20, 500, QtWidgets.QSizePolicy.Minimum, QtWidgets.QSizePolicy.Expanding) + spacerItem = QtWidgets.QSpacerItem( + 20, 500, QtWidgets.QSizePolicy.Minimum, QtWidgets.QSizePolicy.Expanding + ) self.verticalLayout_9.addItem(spacerItem) self.tabWidget.addTab(self.tabGeneration, "") self.tabView = QtWidgets.QWidget() @@ -67,10 +81,14 @@ def setupUi(self, DialogOptions): self.label_7.setObjectName("label_7") self.horizontalLayout_2.addWidget(self.label_7) self.comboBoxDefaultView = QtWidgets.QComboBox(self.tabView) - sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Preferred, QtWidgets.QSizePolicy.Preferred) + sizePolicy = QtWidgets.QSizePolicy( + QtWidgets.QSizePolicy.Preferred, QtWidgets.QSizePolicy.Preferred + ) sizePolicy.setHorizontalStretch(0) sizePolicy.setVerticalStretch(0) - sizePolicy.setHeightForWidth(self.comboBoxDefaultView.sizePolicy().hasHeightForWidth()) + sizePolicy.setHeightForWidth( + self.comboBoxDefaultView.sizePolicy().hasHeightForWidth() + ) self.comboBoxDefaultView.setSizePolicy(sizePolicy) self.comboBoxDefaultView.setObjectName("comboBoxDefaultView") self.comboBoxDefaultView.addItem("") @@ -79,7 +97,9 @@ def setupUi(self, DialogOptions): self.horizontalLayout_2.addWidget(self.comboBoxDefaultView) self.verticalLayout.addLayout(self.horizontalLayout_2) self.checkBoxShowConfirmCloseDialog = QtWidgets.QCheckBox(self.tabView) - self.checkBoxShowConfirmCloseDialog.setObjectName("checkBoxShowConfirmCloseDialog") + self.checkBoxShowConfirmCloseDialog.setObjectName( + "checkBoxShowConfirmCloseDialog" + ) self.verticalLayout.addWidget(self.checkBoxShowConfirmCloseDialog) self.checkBoxHoldShiftToDrag = QtWidgets.QCheckBox(self.tabView) self.checkBoxHoldShiftToDrag.setObjectName("checkBoxHoldShiftToDrag") @@ -127,15 +147,27 @@ def setupUi(self, DialogOptions): self.groupBoxSpectrogramColormap.setObjectName("groupBoxSpectrogramColormap") self.verticalLayout_2 = QtWidgets.QVBoxLayout(self.groupBoxSpectrogramColormap) self.verticalLayout_2.setObjectName("verticalLayout_2") - self.scrollAreaSpectrogramColormap = QtWidgets.QScrollArea(self.groupBoxSpectrogramColormap) + self.scrollAreaSpectrogramColormap = QtWidgets.QScrollArea( + self.groupBoxSpectrogramColormap + ) self.scrollAreaSpectrogramColormap.setWidgetResizable(True) - self.scrollAreaSpectrogramColormap.setObjectName("scrollAreaSpectrogramColormap") + self.scrollAreaSpectrogramColormap.setObjectName( + "scrollAreaSpectrogramColormap" + ) self.scrollAreaWidgetSpectrogramColormapContents = QtWidgets.QWidget() - self.scrollAreaWidgetSpectrogramColormapContents.setGeometry(QtCore.QRect(0, 0, 762, 466)) - self.scrollAreaWidgetSpectrogramColormapContents.setObjectName("scrollAreaWidgetSpectrogramColormapContents") - self.verticalLayout_4 = QtWidgets.QVBoxLayout(self.scrollAreaWidgetSpectrogramColormapContents) + self.scrollAreaWidgetSpectrogramColormapContents.setGeometry( + QtCore.QRect(0, 0, 762, 466) + ) + self.scrollAreaWidgetSpectrogramColormapContents.setObjectName( + "scrollAreaWidgetSpectrogramColormapContents" + ) + self.verticalLayout_4 = QtWidgets.QVBoxLayout( + self.scrollAreaWidgetSpectrogramColormapContents + ) self.verticalLayout_4.setObjectName("verticalLayout_4") - self.scrollAreaSpectrogramColormap.setWidget(self.scrollAreaWidgetSpectrogramColormapContents) + self.scrollAreaSpectrogramColormap.setWidget( + self.scrollAreaWidgetSpectrogramColormapContents + ) self.verticalLayout_2.addWidget(self.scrollAreaSpectrogramColormap) self.verticalLayout.addWidget(self.groupBoxSpectrogramColormap) self.tabWidget.addTab(self.tabView, "") @@ -161,11 +193,15 @@ def setupUi(self, DialogOptions): self.btnRemoveLabeltype.setIcon(icon) self.btnRemoveLabeltype.setObjectName("btnRemoveLabeltype") self.verticalLayout_3.addWidget(self.btnRemoveLabeltype) - spacerItem1 = QtWidgets.QSpacerItem(20, 40, QtWidgets.QSizePolicy.Minimum, QtWidgets.QSizePolicy.Expanding) + spacerItem1 = QtWidgets.QSpacerItem( + 20, 40, QtWidgets.QSizePolicy.Minimum, QtWidgets.QSizePolicy.Expanding + ) self.verticalLayout_3.addItem(spacerItem1) self.horizontalLayout_3.addLayout(self.verticalLayout_3) self.verticalLayout_5.addLayout(self.horizontalLayout_3) - spacerItem2 = QtWidgets.QSpacerItem(20, 203, QtWidgets.QSizePolicy.Minimum, QtWidgets.QSizePolicy.Expanding) + spacerItem2 = QtWidgets.QSpacerItem( + 20, 203, QtWidgets.QSizePolicy.Minimum, QtWidgets.QSizePolicy.Expanding + ) self.verticalLayout_5.addItem(spacerItem2) self.tabWidget.addTab(self.tabFieldtypes, "") self.tab_plugins = QtWidgets.QWidget() @@ -234,7 +270,9 @@ def setupUi(self, DialogOptions): self.btnRebuildNative.setObjectName("btnRebuildNative") self.gridLayout_5.addWidget(self.btnRebuildNative, 4, 0, 1, 1) self.labelRebuildNativeStatus = QtWidgets.QLabel(self.groupBoxNativeOptions) - self.labelRebuildNativeStatus.setAlignment(QtCore.Qt.AlignLeading|QtCore.Qt.AlignLeft|QtCore.Qt.AlignVCenter) + self.labelRebuildNativeStatus.setAlignment( + QtCore.Qt.AlignLeading | QtCore.Qt.AlignLeft | QtCore.Qt.AlignVCenter + ) self.labelRebuildNativeStatus.setObjectName("labelRebuildNativeStatus") self.gridLayout_5.addWidget(self.labelRebuildNativeStatus, 4, 2, 1, 1) self.verticalLayout_8.addWidget(self.groupBoxNativeOptions) @@ -292,59 +330,194 @@ def retranslateUi(self, DialogOptions): _translate = QtCore.QCoreApplication.translate DialogOptions.setWindowTitle(_translate("DialogOptions", "Options")) self.labelFuzzingSamples.setText(_translate("DialogOptions", "Samples")) - self.checkBoxDefaultFuzzingPause.setToolTip(_translate("DialogOptions", "

If you disable the default pause, the pause of the fuzzed message will be used.

")) - self.checkBoxDefaultFuzzingPause.setText(_translate("DialogOptions", "Use a default pause for fuzzed messages")) - self.checkBoxMultipleModulations.setText(_translate("DialogOptions", "Enable modulation profiles")) - self.groupBoxModulationAccuracy.setTitle(_translate("DialogOptions", "Modulation Accuracy")) - self.radioButtonLowModulationAccuracy.setText(_translate("DialogOptions", "Low (2x8 bit) - Recommended for HackRF and RTL-SDR")) - self.radioButtonMediumModulationAccuracy.setText(_translate("DialogOptions", "Medium (2x16 bit) - Recommended for BladeRF, PlutoSDR and SDRPlay")) - self.radioButtonHighModulationAccuracy.setText(_translate("DialogOptions", "High (2x32 bit) - Recommended if you are not sure what to choose")) - self.tabWidget.setTabText(self.tabWidget.indexOf(self.tabGeneration), _translate("DialogOptions", "Generation")) + self.checkBoxDefaultFuzzingPause.setToolTip( + _translate( + "DialogOptions", + "

If you disable the default pause, the pause of the fuzzed message will be used.

", + ) + ) + self.checkBoxDefaultFuzzingPause.setText( + _translate("DialogOptions", "Use a default pause for fuzzed messages") + ) + self.checkBoxMultipleModulations.setText( + _translate("DialogOptions", "Enable modulation profiles") + ) + self.groupBoxModulationAccuracy.setTitle( + _translate("DialogOptions", "Modulation Accuracy") + ) + self.radioButtonLowModulationAccuracy.setText( + _translate( + "DialogOptions", "Low (2x8 bit) - Recommended for HackRF and RTL-SDR" + ) + ) + self.radioButtonMediumModulationAccuracy.setText( + _translate( + "DialogOptions", + "Medium (2x16 bit) - Recommended for BladeRF, PlutoSDR and SDRPlay", + ) + ) + self.radioButtonHighModulationAccuracy.setText( + _translate( + "DialogOptions", + "High (2x32 bit) - Recommended if you are not sure what to choose", + ) + ) + self.tabWidget.setTabText( + self.tabWidget.indexOf(self.tabGeneration), + _translate("DialogOptions", "Generation"), + ) self.label_7.setText(_translate("DialogOptions", "Default View:")) self.comboBoxDefaultView.setItemText(0, _translate("DialogOptions", "Bit")) self.comboBoxDefaultView.setItemText(1, _translate("DialogOptions", "Hex")) self.comboBoxDefaultView.setItemText(2, _translate("DialogOptions", "ASCII")) - self.checkBoxShowConfirmCloseDialog.setText(_translate("DialogOptions", "Show \"confirm close\" dialog")) - self.checkBoxHoldShiftToDrag.setToolTip(_translate("DialogOptions", "

If checked, you need to hold the Shift key to drag with the mouse inside graphic views like the drawn signal in Interpretation tab, while making a selection with the mouse does not require holding any buttons.

If unchecked, this is inverted: Hold shift to make a selection, and drag by default.

")) - self.checkBoxHoldShiftToDrag.setText(_translate("DialogOptions", "Hold shift to drag")) - self.checkBoxPauseTime.setText(_translate("DialogOptions", "Show pauses as time")) + self.checkBoxShowConfirmCloseDialog.setText( + _translate("DialogOptions", 'Show "confirm close" dialog') + ) + self.checkBoxHoldShiftToDrag.setToolTip( + _translate( + "DialogOptions", + '

If checked, you need to hold the Shift key to drag with the mouse inside graphic views like the drawn signal in Interpretation tab, while making a selection with the mouse does not require holding any buttons.

If unchecked, this is inverted: Hold shift to make a selection, and drag by default.

', + ) + ) + self.checkBoxHoldShiftToDrag.setText( + _translate("DialogOptions", "Hold shift to drag") + ) + self.checkBoxPauseTime.setText( + _translate("DialogOptions", "Show pauses as time") + ) self.checkBoxAlignLabels.setText(_translate("DialogOptions", "Align on labels")) - self.labelFontSize.setText(_translate("DialogOptions", "

Application font size (restart for full effect):

")) + self.labelFontSize.setText( + _translate( + "DialogOptions", + '

Application font size (restart for full effect):

', + ) + ) self.doubleSpinBoxFontSize.setSuffix(_translate("DialogOptions", "pt")) - self.label_9.setText(_translate("DialogOptions", "Choose application theme (requires restart):")) - self.comboBoxTheme.setItemText(0, _translate("DialogOptions", "native look (default)")) + self.label_9.setText( + _translate("DialogOptions", "Choose application theme (requires restart):") + ) + self.comboBoxTheme.setItemText( + 0, _translate("DialogOptions", "native look (default)") + ) self.comboBoxTheme.setItemText(1, _translate("DialogOptions", "fallback theme")) - self.comboBoxTheme.setItemText(2, _translate("DialogOptions", "fallback theme (dark)")) - self.labelIconTheme.setText(_translate("DialogOptions", "Choose icon theme (requires restart):")) - self.comboBoxIconTheme.setItemText(0, _translate("DialogOptions", "bundled icons (default)")) - self.comboBoxIconTheme.setItemText(1, _translate("DialogOptions", "native icon theme")) - self.groupBoxSpectrogramColormap.setTitle(_translate("DialogOptions", "Spectrogram Colormap")) - self.tabWidget.setTabText(self.tabWidget.indexOf(self.tabView), _translate("DialogOptions", "View")) + self.comboBoxTheme.setItemText( + 2, _translate("DialogOptions", "fallback theme (dark)") + ) + self.labelIconTheme.setText( + _translate("DialogOptions", "Choose icon theme (requires restart):") + ) + self.comboBoxIconTheme.setItemText( + 0, _translate("DialogOptions", "bundled icons (default)") + ) + self.comboBoxIconTheme.setItemText( + 1, _translate("DialogOptions", "native icon theme") + ) + self.groupBoxSpectrogramColormap.setTitle( + _translate("DialogOptions", "Spectrogram Colormap") + ) + self.tabWidget.setTabText( + self.tabWidget.indexOf(self.tabView), _translate("DialogOptions", "View") + ) self.btnAddLabelType.setText(_translate("DialogOptions", "...")) self.btnRemoveLabeltype.setText(_translate("DialogOptions", "...")) - self.tabWidget.setTabText(self.tabWidget.indexOf(self.tabFieldtypes), _translate("DialogOptions", "Fieldtypes")) - self.tabWidget.setTabText(self.tabWidget.indexOf(self.tab_plugins), _translate("DialogOptions", "Plugins")) - self.labelInfoDeviceTable.setText(_translate("DialogOptions", "

Use the checkboxes in the table below to choose device backends and enable or disable devices. Disabled devices will not show up in device related dialogs such as send or receive.

")) - self.labelDeviceMissingInfo.setText(_translate("DialogOptions", "

Missing a native backend? Perform a health check! If GNU Radio backend is not available double check the GNU Radio settings below.

")) - self.groupBoxNativeOptions.setTitle(_translate("DialogOptions", "Native options")) + self.tabWidget.setTabText( + self.tabWidget.indexOf(self.tabFieldtypes), + _translate("DialogOptions", "Fieldtypes"), + ) + self.tabWidget.setTabText( + self.tabWidget.indexOf(self.tab_plugins), + _translate("DialogOptions", "Plugins"), + ) + self.labelInfoDeviceTable.setText( + _translate( + "DialogOptions", + "

Use the checkboxes in the table below to choose device backends and enable or disable devices. Disabled devices will not show up in device related dialogs such as send or receive.

", + ) + ) + self.labelDeviceMissingInfo.setText( + _translate( + "DialogOptions", + '

Missing a native backend? Perform a health check! If GNU Radio backend is not available double check the GNU Radio settings below.

', + ) + ) + self.groupBoxNativeOptions.setTitle( + _translate("DialogOptions", "Native options") + ) self.labelLibDirs.setText(_translate("DialogOptions", "Library directories:")) - self.lineEditIncludeDirs.setPlaceholderText(_translate("DialogOptions", "Comma separated list of additional include directories")) - self.labelNativeRebuildInfo.setText(_translate("DialogOptions", "You can rebuild the native device extensions here. This is useful, when you installed a device driver afterwards or your drivers are stored in an unusual location.")) - self.lineEditLibDirs.setPlaceholderText(_translate("DialogOptions", "Comma separated list of additional library directories")) - self.labelIncludeDirs.setText(_translate("DialogOptions", "Include directories:")) + self.lineEditIncludeDirs.setPlaceholderText( + _translate( + "DialogOptions", + "Comma separated list of additional include directories", + ) + ) + self.labelNativeRebuildInfo.setText( + _translate( + "DialogOptions", + "You can rebuild the native device extensions here. This is useful, when you installed a device driver afterwards or your drivers are stored in an unusual location.", + ) + ) + self.lineEditLibDirs.setPlaceholderText( + _translate( + "DialogOptions", + "Comma separated list of additional library directories", + ) + ) + self.labelIncludeDirs.setText( + _translate("DialogOptions", "Include directories:") + ) self.btnViewBuildLog.setText(_translate("DialogOptions", "View log")) - self.btnRebuildNative.setToolTip(_translate("DialogOptions", "

Rebuild the native device extensions. You need to restart URH after this, to use new extensions.

")) + self.btnRebuildNative.setToolTip( + _translate( + "DialogOptions", + "

Rebuild the native device extensions. You need to restart URH after this, to use new extensions.

", + ) + ) self.btnRebuildNative.setText(_translate("DialogOptions", "Rebuild")) - self.labelRebuildNativeStatus.setText(_translate("DialogOptions", "Rebuild new device extensions. Please restart URH to use them.")) - self.groupBox_3.setTitle(_translate("DialogOptions", "GNU Radio options (optional)")) - self.label.setToolTip(_translate("DialogOptions", "

Choose a python interpreter which has access to your GNU Radio installation, that is, you can do python -c "import gnuradio" with it on the command line.

")) + self.labelRebuildNativeStatus.setText( + _translate( + "DialogOptions", + "Rebuild new device extensions. Please restart URH to use them.", + ) + ) + self.groupBox_3.setTitle( + _translate("DialogOptions", "GNU Radio options (optional)") + ) + self.label.setToolTip( + _translate( + "DialogOptions", + '

Choose a python interpreter which has access to your GNU Radio installation, that is, you can do python -c "import gnuradio" with it on the command line.

', + ) + ) self.label.setText(_translate("DialogOptions", "Python Interpreter:")) - self.lineEditGRPythonInterpreter.setToolTip(_translate("DialogOptions", "

Choose a python interpreter which has access to your GNU Radio installation, that is, you can do python -c "import gnuradio" with it on the command line.

")) - self.lineEditGRPythonInterpreter.setPlaceholderText(_translate("DialogOptions", "Enter python interpreter path e.g. /usr/bin/python")) + self.lineEditGRPythonInterpreter.setToolTip( + _translate( + "DialogOptions", + '

Choose a python interpreter which has access to your GNU Radio installation, that is, you can do python -c "import gnuradio" with it on the command line.

', + ) + ) + self.lineEditGRPythonInterpreter.setPlaceholderText( + _translate( + "DialogOptions", "Enter python interpreter path e.g. /usr/bin/python" + ) + ) self.btnChooseGRPythonInterpreter.setText(_translate("DialogOptions", "...")) - self.label_8.setText(_translate("DialogOptions", "Default sending repititions:")) - self.spinBoxNumSendingRepeats.setSpecialValueText(_translate("DialogOptions", "Infinite")) - self.label_5.setText(_translate("DialogOptions", "Use this percentage of available RAM for buffer allocation:")) + self.label_8.setText( + _translate("DialogOptions", "Default sending repititions:") + ) + self.spinBoxNumSendingRepeats.setSpecialValueText( + _translate("DialogOptions", "Infinite") + ) + self.label_5.setText( + _translate( + "DialogOptions", + "Use this percentage of available RAM for buffer allocation:", + ) + ) self.doubleSpinBoxRAMThreshold.setSuffix(_translate("DialogOptions", "%")) - self.tabWidget.setTabText(self.tabWidget.indexOf(self.tabDevices), _translate("DialogOptions", "Device")) + self.tabWidget.setTabText( + self.tabWidget.indexOf(self.tabDevices), + _translate("DialogOptions", "Device"), + ) + + from urh.ui.KillerDoubleSpinBox import KillerDoubleSpinBox diff --git a/src/urh/ui/ui_plugins.py b/src/urh/ui/ui_plugins.py index ddc4040651..6efa1878f3 100644 --- a/src/urh/ui/ui_plugins.py +++ b/src/urh/ui/ui_plugins.py @@ -22,10 +22,14 @@ def setupUi(self, FramePlugins): self.label.setObjectName("label") self.verticalLayout_2.addWidget(self.label) self.listViewPlugins = QtWidgets.QListView(FramePlugins) - sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Expanding, QtWidgets.QSizePolicy.MinimumExpanding) + sizePolicy = QtWidgets.QSizePolicy( + QtWidgets.QSizePolicy.Expanding, QtWidgets.QSizePolicy.MinimumExpanding + ) sizePolicy.setHorizontalStretch(0) sizePolicy.setVerticalStretch(0) - sizePolicy.setHeightForWidth(self.listViewPlugins.sizePolicy().hasHeightForWidth()) + sizePolicy.setHeightForWidth( + self.listViewPlugins.sizePolicy().hasHeightForWidth() + ) self.listViewPlugins.setSizePolicy(sizePolicy) self.listViewPlugins.setObjectName("listViewPlugins") self.verticalLayout_2.addWidget(self.listViewPlugins) @@ -33,7 +37,9 @@ def setupUi(self, FramePlugins): self.verticalLayout = QtWidgets.QVBoxLayout() self.verticalLayout.setObjectName("verticalLayout") self.label_2 = QtWidgets.QLabel(FramePlugins) - sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Preferred, QtWidgets.QSizePolicy.Preferred) + sizePolicy = QtWidgets.QSizePolicy( + QtWidgets.QSizePolicy.Preferred, QtWidgets.QSizePolicy.Preferred + ) sizePolicy.setHorizontalStretch(0) sizePolicy.setVerticalStretch(0) sizePolicy.setHeightForWidth(self.label_2.sizePolicy().hasHeightForWidth()) @@ -41,10 +47,14 @@ def setupUi(self, FramePlugins): self.label_2.setObjectName("label_2") self.verticalLayout.addWidget(self.label_2) self.txtEditPluginDescription = QtWidgets.QTextEdit(FramePlugins) - sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Expanding, QtWidgets.QSizePolicy.Expanding) + sizePolicy = QtWidgets.QSizePolicy( + QtWidgets.QSizePolicy.Expanding, QtWidgets.QSizePolicy.Expanding + ) sizePolicy.setHorizontalStretch(0) sizePolicy.setVerticalStretch(0) - sizePolicy.setHeightForWidth(self.txtEditPluginDescription.sizePolicy().hasHeightForWidth()) + sizePolicy.setHeightForWidth( + self.txtEditPluginDescription.sizePolicy().hasHeightForWidth() + ) self.txtEditPluginDescription.setSizePolicy(sizePolicy) self.txtEditPluginDescription.setReadOnly(True) self.txtEditPluginDescription.setPlaceholderText("") @@ -53,10 +63,14 @@ def setupUi(self, FramePlugins): self.horizontalLayout.addLayout(self.verticalLayout) self.verticalLayout_3.addLayout(self.horizontalLayout) self.groupBoxSettings = QtWidgets.QGroupBox(FramePlugins) - sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Preferred, QtWidgets.QSizePolicy.Expanding) + sizePolicy = QtWidgets.QSizePolicy( + QtWidgets.QSizePolicy.Preferred, QtWidgets.QSizePolicy.Expanding + ) sizePolicy.setHorizontalStretch(0) sizePolicy.setVerticalStretch(0) - sizePolicy.setHeightForWidth(self.groupBoxSettings.sizePolicy().hasHeightForWidth()) + sizePolicy.setHeightForWidth( + self.groupBoxSettings.sizePolicy().hasHeightForWidth() + ) self.groupBoxSettings.setSizePolicy(sizePolicy) self.groupBoxSettings.setMaximumSize(QtCore.QSize(16777215, 16777215)) self.groupBoxSettings.setObjectName("groupBoxSettings") diff --git a/src/urh/ui/ui_project.py b/src/urh/ui/ui_project.py index 75377c8c98..f47597a5b8 100644 --- a/src/urh/ui/ui_project.py +++ b/src/urh/ui/ui_project.py @@ -25,7 +25,9 @@ def setupUi(self, ProjectDialog): self.lblName = QtWidgets.QLabel(ProjectDialog) self.lblName.setObjectName("lblName") self.verticalLayout.addWidget(self.lblName) - spacerItem = QtWidgets.QSpacerItem(17, 10, QtWidgets.QSizePolicy.Minimum, QtWidgets.QSizePolicy.Fixed) + spacerItem = QtWidgets.QSpacerItem( + 17, 10, QtWidgets.QSizePolicy.Minimum, QtWidgets.QSizePolicy.Fixed + ) self.verticalLayout.addItem(spacerItem) self.gridLayout = QtWidgets.QGridLayout() self.gridLayout.setObjectName("gridLayout") @@ -43,14 +45,18 @@ def setupUi(self, ProjectDialog): self.lblNewPath = QtWidgets.QLabel(ProjectDialog) self.lblNewPath.setObjectName("lblNewPath") self.gridLayout.addWidget(self.lblNewPath, 1, 3, 1, 1) - spacerItem1 = QtWidgets.QSpacerItem(20, 57, QtWidgets.QSizePolicy.Minimum, QtWidgets.QSizePolicy.Expanding) + spacerItem1 = QtWidgets.QSpacerItem( + 20, 57, QtWidgets.QSizePolicy.Minimum, QtWidgets.QSizePolicy.Expanding + ) self.gridLayout.addItem(spacerItem1, 15, 4, 1, 2) self.txtEdDescription = QtWidgets.QPlainTextEdit(ProjectDialog) self.txtEdDescription.setObjectName("txtEdDescription") self.gridLayout.addWidget(self.txtEdDescription, 10, 3, 1, 1) self.tblParticipants = ParticipantTableView(ProjectDialog) self.tblParticipants.setAlternatingRowColors(True) - self.tblParticipants.setSelectionMode(QtWidgets.QAbstractItemView.ExtendedSelection) + self.tblParticipants.setSelectionMode( + QtWidgets.QAbstractItemView.ExtendedSelection + ) self.tblParticipants.setObjectName("tblParticipants") self.tblParticipants.horizontalHeader().setCascadingSectionResizes(False) self.tblParticipants.horizontalHeader().setDefaultSectionSize(100) @@ -117,7 +123,9 @@ def setupUi(self, ProjectDialog): self.label_2.setObjectName("label_2") self.gridLayout.addWidget(self.label_2, 3, 0, 1, 2) self.label = QtWidgets.QLabel(ProjectDialog) - sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Maximum, QtWidgets.QSizePolicy.Fixed) + sizePolicy = QtWidgets.QSizePolicy( + QtWidgets.QSizePolicy.Maximum, QtWidgets.QSizePolicy.Fixed + ) sizePolicy.setHorizontalStretch(0) sizePolicy.setVerticalStretch(0) sizePolicy.setHeightForWidth(self.label.sizePolicy().hasHeightForWidth()) @@ -138,7 +146,9 @@ def setupUi(self, ProjectDialog): self.label_4.setObjectName("label_4") self.gridLayout.addWidget(self.label_4, 16, 0, 1, 2) self.label_8 = QtWidgets.QLabel(ProjectDialog) - self.label_8.setAlignment(QtCore.Qt.AlignLeading|QtCore.Qt.AlignLeft|QtCore.Qt.AlignVCenter) + self.label_8.setAlignment( + QtCore.Qt.AlignLeading | QtCore.Qt.AlignLeft | QtCore.Qt.AlignVCenter + ) self.label_8.setObjectName("label_8") self.gridLayout.addWidget(self.label_8, 10, 0, 1, 2) self.label_12 = QtWidgets.QLabel(ProjectDialog) @@ -166,7 +176,9 @@ def setupUi(self, ProjectDialog): self.btnDown.setObjectName("btnDown") self.gridLayout.addWidget(self.btnDown, 14, 4, 1, 1) self.buttonBox = QtWidgets.QDialogButtonBox(ProjectDialog) - self.buttonBox.setStandardButtons(QtWidgets.QDialogButtonBox.Cancel|QtWidgets.QDialogButtonBox.Ok) + self.buttonBox.setStandardButtons( + QtWidgets.QDialogButtonBox.Cancel | QtWidgets.QDialogButtonBox.Ok + ) self.buttonBox.setObjectName("buttonBox") self.gridLayout.addWidget(self.buttonBox, 17, 3, 1, 1) self.verticalLayout.addLayout(self.gridLayout) @@ -181,36 +193,65 @@ def setupUi(self, ProjectDialog): ProjectDialog.setTabOrder(self.txtEdDescription, self.tblParticipants) ProjectDialog.setTabOrder(self.tblParticipants, self.btnAddParticipant) ProjectDialog.setTabOrder(self.btnAddParticipant, self.btnRemoveParticipant) - ProjectDialog.setTabOrder(self.btnRemoveParticipant, self.lineEditBroadcastAddress) + ProjectDialog.setTabOrder( + self.btnRemoveParticipant, self.lineEditBroadcastAddress + ) def retranslateUi(self, ProjectDialog): _translate = QtCore.QCoreApplication.translate - ProjectDialog.setWindowTitle(_translate("ProjectDialog", "Create a new project")) + ProjectDialog.setWindowTitle( + _translate("ProjectDialog", "Create a new project") + ) self.lNewProject.setText(_translate("ProjectDialog", "New Project")) self.lblName.setText(_translate("ProjectDialog", "")) self.label_5.setText(_translate("ProjectDialog", "Sps")) - self.lblNewPath.setText(_translate("ProjectDialog", "

Note: A new directory will be created.

")) + self.lblNewPath.setText( + _translate( + "ProjectDialog", + '

Note: A new directory will be created.

', + ) + ) self.label_3.setText(_translate("ProjectDialog", "Default frequency:")) - self.lineEditBroadcastAddress.setToolTip(_translate("ProjectDialog", "

Enter the broadcast address of your protocol in hex. If you do not know what to enter here, just leave the default.

")) + self.lineEditBroadcastAddress.setToolTip( + _translate( + "ProjectDialog", + '

Enter the broadcast address of your protocol in hex. If you do not know what to enter here, just leave the default.

', + ) + ) self.lineEditBroadcastAddress.setText(_translate("ProjectDialog", "ffff")) self.label_10.setText(_translate("ProjectDialog", "Default bandwidth:")) - self.btnAddParticipant.setToolTip(_translate("ProjectDialog", "Add participant")) + self.btnAddParticipant.setToolTip( + _translate("ProjectDialog", "Add participant") + ) self.btnAddParticipant.setText(_translate("ProjectDialog", "...")) self.btnSelectPath.setText(_translate("ProjectDialog", "...")) self.label_6.setText(_translate("ProjectDialog", "Hz")) self.label_2.setText(_translate("ProjectDialog", "Default sample rate:")) self.label.setText(_translate("ProjectDialog", "Choose a path:")) - self.btnRemoveParticipant.setToolTip(_translate("ProjectDialog", "Remove participant")) + self.btnRemoveParticipant.setToolTip( + _translate("ProjectDialog", "Remove participant") + ) self.btnRemoveParticipant.setText(_translate("ProjectDialog", "...")) self.label_4.setText(_translate("ProjectDialog", "Broadcast address (hex):")) self.label_8.setText(_translate("ProjectDialog", "Description:")) self.label_12.setText(_translate("ProjectDialog", "Hz")) self.label_11.setText(_translate("ProjectDialog", "Default gain:")) - self.btnUp.setToolTip(_translate("ProjectDialog", "Move selected participants up")) + self.btnUp.setToolTip( + _translate("ProjectDialog", "Move selected participants up") + ) self.btnUp.setText(_translate("ProjectDialog", "...")) - self.lOpenSpectrumAnalyzer.setText(_translate("ProjectDialog", "

Tip: Open spectrum analyzer to find these values.

")) + self.lOpenSpectrumAnalyzer.setText( + _translate( + "ProjectDialog", + '

Tip: Open spectrum analyzer to find these values.

', + ) + ) self.label_9.setText(_translate("ProjectDialog", "Participants:")) - self.btnDown.setToolTip(_translate("ProjectDialog", "Move selected participants down")) + self.btnDown.setToolTip( + _translate("ProjectDialog", "Move selected participants down") + ) self.btnDown.setText(_translate("ProjectDialog", "...")) + + from urh.ui.KillerDoubleSpinBox import KillerDoubleSpinBox from urh.ui.views.ParticipantTableView import ParticipantTableView diff --git a/src/urh/ui/ui_properties_dialog.py b/src/urh/ui/ui_properties_dialog.py index f01e4dbc3e..89d3bddb87 100644 --- a/src/urh/ui/ui_properties_dialog.py +++ b/src/urh/ui/ui_properties_dialog.py @@ -15,14 +15,16 @@ def setupUi(self, DialogLabels): self.verticalLayout_3 = QtWidgets.QVBoxLayout(DialogLabels) self.verticalLayout_3.setObjectName("verticalLayout_3") self.splitter = QtWidgets.QSplitter(DialogLabels) - self.splitter.setStyleSheet("QSplitter::handle:vertical {\n" -"margin: 4px 0px;\n" -" background-color: qlineargradient(x1:0, y1:0, x2:1, y2:0, \n" -"stop:0 rgba(255, 255, 255, 0), \n" -"stop:0.5 rgba(100, 100, 100, 100), \n" -"stop:1 rgba(255, 255, 255, 0));\n" -" image: url(:/icons/icons/splitter_handle_horizontal.svg);\n" -"}") + self.splitter.setStyleSheet( + "QSplitter::handle:vertical {\n" + "margin: 4px 0px;\n" + " background-color: qlineargradient(x1:0, y1:0, x2:1, y2:0, \n" + "stop:0 rgba(255, 255, 255, 0), \n" + "stop:0.5 rgba(100, 100, 100, 100), \n" + "stop:1 rgba(255, 255, 255, 0));\n" + " image: url(:/icons/icons/splitter_handle_horizontal.svg);\n" + "}" + ) self.splitter.setOrientation(QtCore.Qt.Vertical) self.splitter.setHandleWidth(6) self.splitter.setChildrenCollapsible(False) @@ -32,10 +34,18 @@ def setupUi(self, DialogLabels): self.verticalLayout = QtWidgets.QVBoxLayout(self.groupBoxSettings) self.verticalLayout.setObjectName("verticalLayout") self.tblViewProtoLabels = ProtocolLabelTableView(self.groupBoxSettings) - self.tblViewProtoLabels.setSelectionMode(QtWidgets.QAbstractItemView.ExtendedSelection) - self.tblViewProtoLabels.setSelectionBehavior(QtWidgets.QAbstractItemView.SelectItems) - self.tblViewProtoLabels.setVerticalScrollMode(QtWidgets.QAbstractItemView.ScrollPerPixel) - self.tblViewProtoLabels.setHorizontalScrollMode(QtWidgets.QAbstractItemView.ScrollPerPixel) + self.tblViewProtoLabels.setSelectionMode( + QtWidgets.QAbstractItemView.ExtendedSelection + ) + self.tblViewProtoLabels.setSelectionBehavior( + QtWidgets.QAbstractItemView.SelectItems + ) + self.tblViewProtoLabels.setVerticalScrollMode( + QtWidgets.QAbstractItemView.ScrollPerPixel + ) + self.tblViewProtoLabels.setHorizontalScrollMode( + QtWidgets.QAbstractItemView.ScrollPerPixel + ) self.tblViewProtoLabels.setShowGrid(False) self.tblViewProtoLabels.setObjectName("tblViewProtoLabels") self.verticalLayout.addWidget(self.tblViewProtoLabels) @@ -53,14 +63,18 @@ def setupUi(self, DialogLabels): self.cbProtoView.addItem("") self.cbProtoView.addItem("") self.horizontalLayout_2.addWidget(self.cbProtoView) - spacerItem = QtWidgets.QSpacerItem(40, 20, QtWidgets.QSizePolicy.Expanding, QtWidgets.QSizePolicy.Minimum) + spacerItem = QtWidgets.QSpacerItem( + 40, 20, QtWidgets.QSizePolicy.Expanding, QtWidgets.QSizePolicy.Minimum + ) self.horizontalLayout_2.addItem(spacerItem) self.verticalLayout.addLayout(self.horizontalLayout_2) self.groupBoxAdvancedSettings = QtWidgets.QGroupBox(self.splitter) self.groupBoxAdvancedSettings.setObjectName("groupBoxAdvancedSettings") self.verticalLayout_2 = QtWidgets.QVBoxLayout(self.groupBoxAdvancedSettings) self.verticalLayout_2.setObjectName("verticalLayout_2") - self.tabWidgetAdvancedSettings = QtWidgets.QTabWidget(self.groupBoxAdvancedSettings) + self.tabWidgetAdvancedSettings = QtWidgets.QTabWidget( + self.groupBoxAdvancedSettings + ) self.tabWidgetAdvancedSettings.setObjectName("tabWidgetAdvancedSettings") self.verticalLayout_2.addWidget(self.tabWidgetAdvancedSettings) self.verticalLayout_3.addWidget(self.splitter) @@ -72,13 +86,23 @@ def setupUi(self, DialogLabels): def retranslateUi(self, DialogLabels): _translate = QtCore.QCoreApplication.translate - DialogLabels.setWindowTitle(_translate("DialogLabels", "Manage Protocol Labels")) - self.groupBoxSettings.setTitle(_translate("DialogLabels", "Protocol Label Settings")) - self.label.setText(_translate("DialogLabels", "Start/End values refer to view type:")) + DialogLabels.setWindowTitle( + _translate("DialogLabels", "Manage Protocol Labels") + ) + self.groupBoxSettings.setTitle( + _translate("DialogLabels", "Protocol Label Settings") + ) + self.label.setText( + _translate("DialogLabels", "Start/End values refer to view type:") + ) self.cbProtoView.setItemText(0, _translate("DialogLabels", "Bits")) self.cbProtoView.setItemText(1, _translate("DialogLabels", "Hex")) self.cbProtoView.setItemText(2, _translate("DialogLabels", "ASCII")) - self.groupBoxAdvancedSettings.setTitle(_translate("DialogLabels", "Advanced Settings")) + self.groupBoxAdvancedSettings.setTitle( + _translate("DialogLabels", "Advanced Settings") + ) self.btnConfirm.setText(_translate("DialogLabels", "Confirm")) + + from urh.ui.views.ProtocolLabelTableView import ProtocolLabelTableView from . import urh_rc diff --git a/src/urh/ui/ui_send_recv.py b/src/urh/ui/ui_send_recv.py index 40a04c52ec..fd48345b3e 100644 --- a/src/urh/ui/ui_send_recv.py +++ b/src/urh/ui/ui_send_recv.py @@ -17,14 +17,16 @@ def setupUi(self, SendRecvDialog): self.verticalLayout = QtWidgets.QVBoxLayout(SendRecvDialog) self.verticalLayout.setObjectName("verticalLayout") self.splitter = QtWidgets.QSplitter(SendRecvDialog) - self.splitter.setStyleSheet("QSplitter::handle:horizontal {\n" -"margin: 4px 0px;\n" -" background-color: qlineargradient(x1:0, y1:0, x2:0, y2:1, \n" -"stop:0 rgba(255, 255, 255, 0), \n" -"stop:0.5 rgba(100, 100, 100, 100), \n" -"stop:1 rgba(255, 255, 255, 0));\n" -"image: url(:/icons/icons/splitter_handle_vertical.svg);\n" -"}") + self.splitter.setStyleSheet( + "QSplitter::handle:horizontal {\n" + "margin: 4px 0px;\n" + " background-color: qlineargradient(x1:0, y1:0, x2:0, y2:1, \n" + "stop:0 rgba(255, 255, 255, 0), \n" + "stop:0.5 rgba(100, 100, 100, 100), \n" + "stop:1 rgba(255, 255, 255, 0));\n" + "image: url(:/icons/icons/splitter_handle_vertical.svg);\n" + "}" + ) self.splitter.setOrientation(QtCore.Qt.Horizontal) self.splitter.setObjectName("splitter") self.scrollArea = QtWidgets.QScrollArea(self.splitter) @@ -37,10 +39,7 @@ def setupUi(self, SendRecvDialog): self.verticalLayout_8 = QtWidgets.QVBoxLayout(self.scrollAreaWidgetContents_2) self.verticalLayout_8.setObjectName("verticalLayout_8") self.groupBox = QtWidgets.QGroupBox(self.scrollAreaWidgetContents_2) - self.groupBox.setStyleSheet("QGroupBox\n" -"{\n" -" border: none;\n" -"}") + self.groupBox.setStyleSheet("QGroupBox\n" "{\n" " border: none;\n" "}") self.groupBox.setTitle("") self.groupBox.setObjectName("groupBox") self.gridLayout_2 = QtWidgets.QGridLayout(self.groupBox) @@ -67,26 +66,38 @@ def setupUi(self, SendRecvDialog): self.lTimeText.setObjectName("lTimeText") self.gridLayout_2.addWidget(self.lTimeText, 12, 0, 1, 1) self.lSamplesCapturedText = QtWidgets.QLabel(self.groupBox) - sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Fixed, QtWidgets.QSizePolicy.Preferred) + sizePolicy = QtWidgets.QSizePolicy( + QtWidgets.QSizePolicy.Fixed, QtWidgets.QSizePolicy.Preferred + ) sizePolicy.setHorizontalStretch(0) sizePolicy.setVerticalStretch(0) - sizePolicy.setHeightForWidth(self.lSamplesCapturedText.sizePolicy().hasHeightForWidth()) + sizePolicy.setHeightForWidth( + self.lSamplesCapturedText.sizePolicy().hasHeightForWidth() + ) self.lSamplesCapturedText.setSizePolicy(sizePolicy) self.lSamplesCapturedText.setObjectName("lSamplesCapturedText") self.gridLayout_2.addWidget(self.lSamplesCapturedText, 5, 0, 1, 1) self.lSignalSizeText = QtWidgets.QLabel(self.groupBox) - sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Fixed, QtWidgets.QSizePolicy.Preferred) + sizePolicy = QtWidgets.QSizePolicy( + QtWidgets.QSizePolicy.Fixed, QtWidgets.QSizePolicy.Preferred + ) sizePolicy.setHorizontalStretch(0) sizePolicy.setVerticalStretch(0) - sizePolicy.setHeightForWidth(self.lSignalSizeText.sizePolicy().hasHeightForWidth()) + sizePolicy.setHeightForWidth( + self.lSignalSizeText.sizePolicy().hasHeightForWidth() + ) self.lSignalSizeText.setSizePolicy(sizePolicy) self.lSignalSizeText.setObjectName("lSignalSizeText") self.gridLayout_2.addWidget(self.lSignalSizeText, 9, 0, 1, 1) self.lSamplesCaptured = QtWidgets.QLabel(self.groupBox) - sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Expanding, QtWidgets.QSizePolicy.Preferred) + sizePolicy = QtWidgets.QSizePolicy( + QtWidgets.QSizePolicy.Expanding, QtWidgets.QSizePolicy.Preferred + ) sizePolicy.setHorizontalStretch(0) sizePolicy.setVerticalStretch(0) - sizePolicy.setHeightForWidth(self.lSamplesCaptured.sizePolicy().hasHeightForWidth()) + sizePolicy.setHeightForWidth( + self.lSamplesCaptured.sizePolicy().hasHeightForWidth() + ) self.lSamplesCaptured.setSizePolicy(sizePolicy) font = QtGui.QFont() font.setBold(True) @@ -104,7 +115,9 @@ def setupUi(self, SendRecvDialog): self.lTime.setObjectName("lTime") self.gridLayout_2.addWidget(self.lTime, 15, 0, 1, 2) self.lSignalSize = QtWidgets.QLabel(self.groupBox) - sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Expanding, QtWidgets.QSizePolicy.Preferred) + sizePolicy = QtWidgets.QSizePolicy( + QtWidgets.QSizePolicy.Expanding, QtWidgets.QSizePolicy.Preferred + ) sizePolicy.setHorizontalStretch(0) sizePolicy.setVerticalStretch(0) sizePolicy.setHeightForWidth(self.lSignalSize.sizePolicy().hasHeightForWidth()) @@ -128,10 +141,14 @@ def setupUi(self, SendRecvDialog): self.lblCurrentRepeatValue.setObjectName("lblCurrentRepeatValue") self.gridLayout_2.addWidget(self.lblCurrentRepeatValue, 17, 0, 1, 1) self.labelReceiveBufferFull = QtWidgets.QLabel(self.groupBox) - sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Expanding, QtWidgets.QSizePolicy.Preferred) + sizePolicy = QtWidgets.QSizePolicy( + QtWidgets.QSizePolicy.Expanding, QtWidgets.QSizePolicy.Preferred + ) sizePolicy.setHorizontalStretch(0) sizePolicy.setVerticalStretch(0) - sizePolicy.setHeightForWidth(self.labelReceiveBufferFull.sizePolicy().hasHeightForWidth()) + sizePolicy.setHeightForWidth( + self.labelReceiveBufferFull.sizePolicy().hasHeightForWidth() + ) self.labelReceiveBufferFull.setSizePolicy(sizePolicy) font = QtGui.QFont() font.setBold(True) @@ -142,7 +159,9 @@ def setupUi(self, SendRecvDialog): self.gridLayout_2.addWidget(self.labelReceiveBufferFull, 8, 0, 1, 1) self.horizontalLayout = QtWidgets.QHBoxLayout() self.horizontalLayout.setObjectName("horizontalLayout") - spacerItem = QtWidgets.QSpacerItem(40, 20, QtWidgets.QSizePolicy.Expanding, QtWidgets.QSizePolicy.Minimum) + spacerItem = QtWidgets.QSpacerItem( + 40, 20, QtWidgets.QSizePolicy.Expanding, QtWidgets.QSizePolicy.Minimum + ) self.horizontalLayout.addItem(spacerItem) self.btnStart = QtWidgets.QToolButton(self.groupBox) self.btnStart.setMinimumSize(QtCore.QSize(64, 64)) @@ -176,10 +195,14 @@ def setupUi(self, SendRecvDialog): self.btnClear.setToolButtonStyle(QtCore.Qt.ToolButtonTextUnderIcon) self.btnClear.setObjectName("btnClear") self.horizontalLayout.addWidget(self.btnClear) - spacerItem1 = QtWidgets.QSpacerItem(40, 20, QtWidgets.QSizePolicy.Expanding, QtWidgets.QSizePolicy.Minimum) + spacerItem1 = QtWidgets.QSpacerItem( + 40, 20, QtWidgets.QSizePolicy.Expanding, QtWidgets.QSizePolicy.Minimum + ) self.horizontalLayout.addItem(spacerItem1) self.gridLayout_2.addLayout(self.horizontalLayout, 1, 0, 1, 2) - spacerItem2 = QtWidgets.QSpacerItem(20, 10, QtWidgets.QSizePolicy.Minimum, QtWidgets.QSizePolicy.Fixed) + spacerItem2 = QtWidgets.QSpacerItem( + 20, 10, QtWidgets.QSizePolicy.Minimum, QtWidgets.QSizePolicy.Fixed + ) self.gridLayout_2.addItem(spacerItem2, 2, 0, 1, 1) self.verticalLayout_8.addWidget(self.groupBox) self.txtEditErrors = QtWidgets.QTextEdit(self.scrollAreaWidgetContents_2) @@ -199,8 +222,12 @@ def setupUi(self, SendRecvDialog): self.verticalLayout_2 = QtWidgets.QVBoxLayout(self.page_receive) self.verticalLayout_2.setObjectName("verticalLayout_2") self.graphicsViewReceive = LiveGraphicView(self.page_receive) - self.graphicsViewReceive.setVerticalScrollBarPolicy(QtCore.Qt.ScrollBarAlwaysOff) - self.graphicsViewReceive.setHorizontalScrollBarPolicy(QtCore.Qt.ScrollBarAsNeeded) + self.graphicsViewReceive.setVerticalScrollBarPolicy( + QtCore.Qt.ScrollBarAlwaysOff + ) + self.graphicsViewReceive.setHorizontalScrollBarPolicy( + QtCore.Qt.ScrollBarAsNeeded + ) self.graphicsViewReceive.setObjectName("graphicsViewReceive") self.verticalLayout_2.addWidget(self.graphicsViewReceive) self.stackedWidget.addWidget(self.page_receive) @@ -210,7 +237,9 @@ def setupUi(self, SendRecvDialog): self.verticalLayout_3.setObjectName("verticalLayout_3") self.graphicsViewSend = EditableGraphicView(self.page_send) self.graphicsViewSend.setMouseTracking(True) - self.graphicsViewSend.setRenderHints(QtGui.QPainter.Antialiasing|QtGui.QPainter.TextAntialiasing) + self.graphicsViewSend.setRenderHints( + QtGui.QPainter.Antialiasing | QtGui.QPainter.TextAntialiasing + ) self.graphicsViewSend.setTransformationAnchor(QtWidgets.QGraphicsView.NoAnchor) self.graphicsViewSend.setResizeAnchor(QtWidgets.QGraphicsView.NoAnchor) self.graphicsViewSend.setObjectName("graphicsViewSend") @@ -227,7 +256,9 @@ def setupUi(self, SendRecvDialog): self.verticalLayout_6 = QtWidgets.QVBoxLayout(self.page_continuous_send) self.verticalLayout_6.setObjectName("verticalLayout_6") self.graphicsViewContinuousSend = LiveGraphicView(self.page_continuous_send) - self.graphicsViewContinuousSend.setRenderHints(QtGui.QPainter.Antialiasing|QtGui.QPainter.TextAntialiasing) + self.graphicsViewContinuousSend.setRenderHints( + QtGui.QPainter.Antialiasing | QtGui.QPainter.TextAntialiasing + ) self.graphicsViewContinuousSend.setObjectName("graphicsViewContinuousSend") self.verticalLayout_6.addWidget(self.graphicsViewContinuousSend) self.stackedWidget.addWidget(self.page_continuous_send) @@ -239,11 +270,19 @@ def setupUi(self, SendRecvDialog): self.graphicsViewFFT.setObjectName("graphicsViewFFT") self.verticalLayout_7.addWidget(self.graphicsViewFFT) self.graphicsViewSpectrogram = QtWidgets.QGraphicsView(self.page_spectrum) - self.graphicsViewSpectrogram.setVerticalScrollBarPolicy(QtCore.Qt.ScrollBarAsNeeded) - self.graphicsViewSpectrogram.setHorizontalScrollBarPolicy(QtCore.Qt.ScrollBarAlwaysOff) - self.graphicsViewSpectrogram.setRenderHints(QtGui.QPainter.SmoothPixmapTransform|QtGui.QPainter.TextAntialiasing) + self.graphicsViewSpectrogram.setVerticalScrollBarPolicy( + QtCore.Qt.ScrollBarAsNeeded + ) + self.graphicsViewSpectrogram.setHorizontalScrollBarPolicy( + QtCore.Qt.ScrollBarAlwaysOff + ) + self.graphicsViewSpectrogram.setRenderHints( + QtGui.QPainter.SmoothPixmapTransform | QtGui.QPainter.TextAntialiasing + ) self.graphicsViewSpectrogram.setCacheMode(QtWidgets.QGraphicsView.CacheNone) - self.graphicsViewSpectrogram.setViewportUpdateMode(QtWidgets.QGraphicsView.MinimalViewportUpdate) + self.graphicsViewSpectrogram.setViewportUpdateMode( + QtWidgets.QGraphicsView.MinimalViewportUpdate + ) self.graphicsViewSpectrogram.setObjectName("graphicsViewSpectrogram") self.verticalLayout_7.addWidget(self.graphicsViewSpectrogram) self.verticalLayout_7.setStretch(0, 1) @@ -300,13 +339,21 @@ def retranslateUi(self, SendRecvDialog): _translate = QtCore.QCoreApplication.translate SendRecvDialog.setWindowTitle(_translate("SendRecvDialog", "Record Signal")) self.progressBarMessage.setFormat(_translate("SendRecvDialog", "%v/%m")) - self.labelCurrentMessage.setText(_translate("SendRecvDialog", "Current message:")) - self.lReceiveBufferFullText.setText(_translate("SendRecvDialog", "Receive buffer full:")) + self.labelCurrentMessage.setText( + _translate("SendRecvDialog", "Current message:") + ) + self.lReceiveBufferFullText.setText( + _translate("SendRecvDialog", "Receive buffer full:") + ) self.progressBarSample.setFormat(_translate("SendRecvDialog", "%v/%m")) self.lSamplesSentText.setText(_translate("SendRecvDialog", "Current sample:")) self.lTimeText.setText(_translate("SendRecvDialog", "Time (in seconds):")) - self.lSamplesCapturedText.setText(_translate("SendRecvDialog", "Samples captured:")) - self.lSignalSizeText.setText(_translate("SendRecvDialog", "Signal size (in MiB):")) + self.lSamplesCapturedText.setText( + _translate("SendRecvDialog", "Samples captured:") + ) + self.lSignalSizeText.setText( + _translate("SendRecvDialog", "Signal size (in MiB):") + ) self.lSamplesCaptured.setText(_translate("SendRecvDialog", "0")) self.lTime.setText(_translate("SendRecvDialog", "0")) self.lSignalSize.setText(_translate("SendRecvDialog", "0")) @@ -320,10 +367,23 @@ def retranslateUi(self, SendRecvDialog): self.btnSave.setText(_translate("SendRecvDialog", "Save...")) self.btnClear.setToolTip(_translate("SendRecvDialog", "Clear")) self.btnClear.setText(_translate("SendRecvDialog", "Clear")) - self.label_7.setText(_translate("SendRecvDialog", "Hint: You can edit the raw signal before sending.")) - self.btnAccept.setToolTip(_translate("SendRecvDialog", "

Accept the sniffed data and load it into Analysis tab.

")) - self.btnAccept.setText(_translate("SendRecvDialog", "Accept data (Open in Analysis)")) + self.label_7.setText( + _translate( + "SendRecvDialog", "Hint: You can edit the raw signal before sending." + ) + ) + self.btnAccept.setToolTip( + _translate( + "SendRecvDialog", + '

Accept the sniffed data and load it into Analysis tab.

', + ) + ) + self.btnAccept.setText( + _translate("SendRecvDialog", "Accept data (Open in Analysis)") + ) self.label_y_scale.setText(_translate("SendRecvDialog", "Y-Scale")) + + from urh.ui.views.EditableGraphicView import EditableGraphicView from urh.ui.views.LiveGraphicView import LiveGraphicView from . import urh_rc diff --git a/src/urh/ui/ui_send_recv_device_settings.py b/src/urh/ui/ui_send_recv_device_settings.py index 7188ffd99b..622bdb6497 100644 --- a/src/urh/ui/ui_send_recv_device_settings.py +++ b/src/urh/ui/ui_send_recv_device_settings.py @@ -21,20 +21,22 @@ def setupUi(self, FormDeviceSettings): font.setBold(True) font.setWeight(75) self.groupBoxDeviceSettings.setFont(font) - self.groupBoxDeviceSettings.setStyleSheet("QGroupBox\n" -"{\n" -"border: none;\n" -"}\n" -"\n" -"QGroupBox::title {\n" -" subcontrol-origin: margin;\n" -"}\n" -"QGroupBox::indicator:unchecked {\n" -" image: url(:/icons/icons/collapse.svg)\n" -"}\n" -"QGroupBox::indicator:checked {\n" -" image: url(:/icons/icons/uncollapse.svg)\n" -"}") + self.groupBoxDeviceSettings.setStyleSheet( + "QGroupBox\n" + "{\n" + "border: none;\n" + "}\n" + "\n" + "QGroupBox::title {\n" + " subcontrol-origin: margin;\n" + "}\n" + "QGroupBox::indicator:unchecked {\n" + " image: url(:/icons/icons/collapse.svg)\n" + "}\n" + "QGroupBox::indicator:checked {\n" + " image: url(:/icons/icons/uncollapse.svg)\n" + "}" + ) self.groupBoxDeviceSettings.setFlat(True) self.groupBoxDeviceSettings.setCheckable(True) self.groupBoxDeviceSettings.setObjectName("groupBoxDeviceSettings") @@ -101,7 +103,9 @@ def setupUi(self, FormDeviceSettings): self.sliderGain.setObjectName("sliderGain") self.gridLayout_5.addWidget(self.sliderGain, 0, 0, 1, 1) self.spinBoxGain = QtWidgets.QSpinBox(self.frame_2) - sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.MinimumExpanding, QtWidgets.QSizePolicy.Fixed) + sizePolicy = QtWidgets.QSizePolicy( + QtWidgets.QSizePolicy.MinimumExpanding, QtWidgets.QSizePolicy.Fixed + ) sizePolicy.setHorizontalStretch(0) sizePolicy.setVerticalStretch(0) sizePolicy.setHeightForWidth(self.spinBoxGain.sizePolicy().hasHeightForWidth()) @@ -122,10 +126,14 @@ def setupUi(self, FormDeviceSettings): self.sliderIFGain.setObjectName("sliderIFGain") self.gridLayout_7.addWidget(self.sliderIFGain, 0, 0, 1, 1) self.spinBoxIFGain = QtWidgets.QSpinBox(self.frame_2) - sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.MinimumExpanding, QtWidgets.QSizePolicy.Fixed) + sizePolicy = QtWidgets.QSizePolicy( + QtWidgets.QSizePolicy.MinimumExpanding, QtWidgets.QSizePolicy.Fixed + ) sizePolicy.setHorizontalStretch(0) sizePolicy.setVerticalStretch(0) - sizePolicy.setHeightForWidth(self.spinBoxIFGain.sizePolicy().hasHeightForWidth()) + sizePolicy.setHeightForWidth( + self.spinBoxIFGain.sizePolicy().hasHeightForWidth() + ) self.spinBoxIFGain.setSizePolicy(sizePolicy) self.spinBoxIFGain.setObjectName("spinBoxIFGain") self.gridLayout_7.addWidget(self.spinBoxIFGain, 0, 1, 1, 1) @@ -139,7 +147,9 @@ def setupUi(self, FormDeviceSettings): self.comboBoxDeviceIdentifier.setObjectName("comboBoxDeviceIdentifier") self.gridLayout.addWidget(self.comboBoxDeviceIdentifier, 1, 1, 1, 1) self.cbDevice = QtWidgets.QComboBox(self.frame_2) - sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Expanding, QtWidgets.QSizePolicy.Fixed) + sizePolicy = QtWidgets.QSizePolicy( + QtWidgets.QSizePolicy.Expanding, QtWidgets.QSizePolicy.Fixed + ) sizePolicy.setHorizontalStretch(0) sizePolicy.setVerticalStretch(0) sizePolicy.setHeightForWidth(self.cbDevice.sizePolicy().hasHeightForWidth()) @@ -164,10 +174,14 @@ def setupUi(self, FormDeviceSettings): self.sliderBasebandGain.setObjectName("sliderBasebandGain") self.gridLayout_8.addWidget(self.sliderBasebandGain, 0, 0, 1, 1) self.spinBoxBasebandGain = QtWidgets.QSpinBox(self.frame_2) - sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.MinimumExpanding, QtWidgets.QSizePolicy.Fixed) + sizePolicy = QtWidgets.QSizePolicy( + QtWidgets.QSizePolicy.MinimumExpanding, QtWidgets.QSizePolicy.Fixed + ) sizePolicy.setHorizontalStretch(0) sizePolicy.setVerticalStretch(0) - sizePolicy.setHeightForWidth(self.spinBoxBasebandGain.sizePolicy().hasHeightForWidth()) + sizePolicy.setHeightForWidth( + self.spinBoxBasebandGain.sizePolicy().hasHeightForWidth() + ) self.spinBoxBasebandGain.setSizePolicy(sizePolicy) self.spinBoxBasebandGain.setObjectName("spinBoxBasebandGain") self.gridLayout_8.addWidget(self.spinBoxBasebandGain, 0, 1, 1, 1) @@ -231,13 +245,17 @@ def setupUi(self, FormDeviceSettings): self.labelChannel.setObjectName("labelChannel") self.gridLayout.addWidget(self.labelChannel, 3, 0, 1, 1) self.btnLockBWSR = QtWidgets.QToolButton(self.frame_2) - sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Fixed, QtWidgets.QSizePolicy.Fixed) + sizePolicy = QtWidgets.QSizePolicy( + QtWidgets.QSizePolicy.Fixed, QtWidgets.QSizePolicy.Fixed + ) sizePolicy.setHorizontalStretch(0) sizePolicy.setVerticalStretch(0) sizePolicy.setHeightForWidth(self.btnLockBWSR.sizePolicy().hasHeightForWidth()) self.btnLockBWSR.setSizePolicy(sizePolicy) icon = QtGui.QIcon() - icon.addPixmap(QtGui.QPixmap(":/icons/icons/lock.svg"), QtGui.QIcon.Normal, QtGui.QIcon.Off) + icon.addPixmap( + QtGui.QPixmap(":/icons/icons/lock.svg"), QtGui.QIcon.Normal, QtGui.QIcon.Off + ) self.btnLockBWSR.setIcon(icon) self.btnLockBWSR.setIconSize(QtCore.QSize(16, 16)) self.btnLockBWSR.setCheckable(True) @@ -257,11 +275,15 @@ def setupUi(self, FormDeviceSettings): self.verticalLayout.addWidget(self.groupBoxDeviceSettings) self.retranslateUi(FormDeviceSettings) - self.groupBoxDeviceSettings.toggled['bool'].connect(self.frame_2.setVisible) + self.groupBoxDeviceSettings.toggled["bool"].connect(self.frame_2.setVisible) FormDeviceSettings.setTabOrder(self.groupBoxDeviceSettings, self.cbDevice) FormDeviceSettings.setTabOrder(self.cbDevice, self.comboBoxDeviceIdentifier) - FormDeviceSettings.setTabOrder(self.comboBoxDeviceIdentifier, self.btnRefreshDeviceIdentifier) - FormDeviceSettings.setTabOrder(self.btnRefreshDeviceIdentifier, self.lineEditSubdevice) + FormDeviceSettings.setTabOrder( + self.comboBoxDeviceIdentifier, self.btnRefreshDeviceIdentifier + ) + FormDeviceSettings.setTabOrder( + self.btnRefreshDeviceIdentifier, self.lineEditSubdevice + ) FormDeviceSettings.setTabOrder(self.lineEditSubdevice, self.comboBoxChannel) FormDeviceSettings.setTabOrder(self.comboBoxChannel, self.comboBoxAntenna) FormDeviceSettings.setTabOrder(self.comboBoxAntenna, self.lineEditIP) @@ -275,63 +297,206 @@ def setupUi(self, FormDeviceSettings): FormDeviceSettings.setTabOrder(self.spinBoxGain, self.sliderIFGain) FormDeviceSettings.setTabOrder(self.sliderIFGain, self.spinBoxIFGain) FormDeviceSettings.setTabOrder(self.spinBoxIFGain, self.sliderBasebandGain) - FormDeviceSettings.setTabOrder(self.sliderBasebandGain, self.spinBoxBasebandGain) - FormDeviceSettings.setTabOrder(self.spinBoxBasebandGain, self.spinBoxFreqCorrection) - FormDeviceSettings.setTabOrder(self.spinBoxFreqCorrection, self.comboBoxDirectSampling) + FormDeviceSettings.setTabOrder( + self.sliderBasebandGain, self.spinBoxBasebandGain + ) + FormDeviceSettings.setTabOrder( + self.spinBoxBasebandGain, self.spinBoxFreqCorrection + ) + FormDeviceSettings.setTabOrder( + self.spinBoxFreqCorrection, self.comboBoxDirectSampling + ) FormDeviceSettings.setTabOrder(self.comboBoxDirectSampling, self.spinBoxNRepeat) FormDeviceSettings.setTabOrder(self.spinBoxNRepeat, self.checkBoxDCCorrection) def retranslateUi(self, FormDeviceSettings): _translate = QtCore.QCoreApplication.translate FormDeviceSettings.setWindowTitle(_translate("FormDeviceSettings", "Form")) - self.groupBoxDeviceSettings.setTitle(_translate("FormDeviceSettings", "Device settings")) + self.groupBoxDeviceSettings.setTitle( + _translate("FormDeviceSettings", "Device settings") + ) self.labelAntenna.setText(_translate("FormDeviceSettings", "Antenna:")) - self.labelBasebandGain.setToolTip(_translate("FormDeviceSettings", "

The baseband gain is applied to the baseband signal in your software defined radio. The baseband signal is at low frequency and gathered from the RF signal by complex downsampling.

")) - self.labelBasebandGain.setText(_translate("FormDeviceSettings", "Baseband gain:")) - self.lineEditSubdevice.setToolTip(_translate("FormDeviceSettings", "

Configure the subdevice of your USRP. For example, B:0 to select a WBX on slot B. You can learn more at http://files.ettus.com/manual/page_configuration.html#config_subdev.

")) - self.labelSubdevice.setToolTip(_translate("FormDeviceSettings", "

Configure the subdevice of your USRP. For example, B:0 to select a WBX on slot B. You can learn more at http://files.ettus.com/manual/page_configuration.html#config_subdev.

")) - self.labelSubdevice.setText(_translate("FormDeviceSettings", "

Subdevice:

")) + self.labelBasebandGain.setToolTip( + _translate( + "FormDeviceSettings", + '

The baseband gain is applied to the baseband signal in your software defined radio. The baseband signal is at low frequency and gathered from the RF signal by complex downsampling.

', + ) + ) + self.labelBasebandGain.setText( + _translate("FormDeviceSettings", "Baseband gain:") + ) + self.lineEditSubdevice.setToolTip( + _translate( + "FormDeviceSettings", + '

Configure the subdevice of your USRP. For example, B:0 to select a WBX on slot B. You can learn more at http://files.ettus.com/manual/page_configuration.html#config_subdev.

', + ) + ) + self.labelSubdevice.setToolTip( + _translate( + "FormDeviceSettings", + '

Configure the subdevice of your USRP. For example, B:0 to select a WBX on slot B. You can learn more at http://files.ettus.com/manual/page_configuration.html#config_subdev.

', + ) + ) + self.labelSubdevice.setText( + _translate( + "FormDeviceSettings", + "

Subdevice:

", + ) + ) self.lineEditIP.setText(_translate("FormDeviceSettings", "127.0.0.1")) - self.btnRefreshDeviceIdentifier.setToolTip(_translate("FormDeviceSettings", "

Automatically detect connected SDRs of the above configured type. There is no need to press this button if you have only one SDR of a certain type attached.

")) + self.btnRefreshDeviceIdentifier.setToolTip( + _translate( + "FormDeviceSettings", + '

Automatically detect connected SDRs of the above configured type. There is no need to press this button if you have only one SDR of a certain type attached.

', + ) + ) self.btnRefreshDeviceIdentifier.setText(_translate("FormDeviceSettings", "...")) - self.labelDirectSampling.setToolTip(_translate("FormDeviceSettings", "

Set the direct sampling mode. If you do not know what to choose here, just set it to disabled. The native backend is recommended, when using this setting.

")) - self.labelDirectSampling.setText(_translate("FormDeviceSettings", "Direct sampling:")) + self.labelDirectSampling.setToolTip( + _translate( + "FormDeviceSettings", + '

Set the direct sampling mode. If you do not know what to choose here, just set it to disabled. The native backend is recommended, when using this setting.

', + ) + ) + self.labelDirectSampling.setText( + _translate("FormDeviceSettings", "Direct sampling:") + ) self.labelBandwidth.setText(_translate("FormDeviceSettings", "Bandwidth (Hz):")) - self.sliderGain.setToolTip(_translate("FormDeviceSettings", "

The gain (more exactly RF gain) is the gain applied to the RF signal. This amplifies the high frequent signal arriving at the antenna of your Software Defined Radio.

")) - self.spinBoxGain.setToolTip(_translate("FormDeviceSettings", "

The gain (more exactly RF gain) is the gain applied to the RF signal. This amplifies the high frequent signal arriving at the antenna of your Software Defined Radio.

")) - self.labelSampleRate.setText(_translate("FormDeviceSettings", "Sample rate (Sps):")) - self.sliderIFGain.setToolTip(_translate("FormDeviceSettings", "

The IF Gain is applied to the Intermediate Frequency signal in your Software Defined Radio. An IF signal has a lower frequency than the high frequent RF signal, so signal processing can be applied more efficiently.

")) - self.spinBoxIFGain.setToolTip(_translate("FormDeviceSettings", "

The IF Gain is applied to the Intermediate Frequency signal in your Software Defined Radio. An IF signal has a lower frequency than the high frequent RF signal, so signal processing can be applied more efficiently.

")) - self.labelFreqCorrection.setToolTip(_translate("FormDeviceSettings", "

Set the frequency correction in ppm. If you do not know what to enter here, just leave it to one.

")) - self.labelFreqCorrection.setText(_translate("FormDeviceSettings", "Frequency correction:")) - self.comboBoxDeviceIdentifier.setToolTip(_translate("FormDeviceSettings", "

You can enter a device identifier here if you have multiple SDRs of the same type attached to separate them. There is no need to configure this value otherwise. URH will automatically select an attached SDR of the configured type if you leave this value empty.

")) + self.sliderGain.setToolTip( + _translate( + "FormDeviceSettings", + "

The gain (more exactly RF gain) is the gain applied to the RF signal. This amplifies the high frequent signal arriving at the antenna of your Software Defined Radio.

", + ) + ) + self.spinBoxGain.setToolTip( + _translate( + "FormDeviceSettings", + "

The gain (more exactly RF gain) is the gain applied to the RF signal. This amplifies the high frequent signal arriving at the antenna of your Software Defined Radio.

", + ) + ) + self.labelSampleRate.setText( + _translate("FormDeviceSettings", "Sample rate (Sps):") + ) + self.sliderIFGain.setToolTip( + _translate( + "FormDeviceSettings", + "

The IF Gain is applied to the Intermediate Frequency signal in your Software Defined Radio. An IF signal has a lower frequency than the high frequent RF signal, so signal processing can be applied more efficiently.

", + ) + ) + self.spinBoxIFGain.setToolTip( + _translate( + "FormDeviceSettings", + "

The IF Gain is applied to the Intermediate Frequency signal in your Software Defined Radio. An IF signal has a lower frequency than the high frequent RF signal, so signal processing can be applied more efficiently.

", + ) + ) + self.labelFreqCorrection.setToolTip( + _translate( + "FormDeviceSettings", + '

Set the frequency correction in ppm. If you do not know what to enter here, just leave it to one.

', + ) + ) + self.labelFreqCorrection.setText( + _translate("FormDeviceSettings", "Frequency correction:") + ) + self.comboBoxDeviceIdentifier.setToolTip( + _translate( + "FormDeviceSettings", + '

You can enter a device identifier here if you have multiple SDRs of the same type attached to separate them. There is no need to configure this value otherwise. URH will automatically select an attached SDR of the configured type if you leave this value empty.

', + ) + ) self.cbDevice.setItemText(0, _translate("FormDeviceSettings", "USRP")) self.cbDevice.setItemText(1, _translate("FormDeviceSettings", "HackRF")) - self.spinBoxNRepeat.setSpecialValueText(_translate("FormDeviceSettings", "Infinite")) - self.sliderBasebandGain.setToolTip(_translate("FormDeviceSettings", "

The baseband gain is applied to the baseband signal in your software defined radio. The baseband signal is at low frequency and gathered from the RF signal by complex downsampling.

")) - self.spinBoxBasebandGain.setToolTip(_translate("FormDeviceSettings", "

The baseband gain is applied to the baseband signal in your software defined radio. The baseband signal is at low frequency and gathered from the RF signal by complex downsampling.

")) + self.spinBoxNRepeat.setSpecialValueText( + _translate("FormDeviceSettings", "Infinite") + ) + self.sliderBasebandGain.setToolTip( + _translate( + "FormDeviceSettings", + '

The baseband gain is applied to the baseband signal in your software defined radio. The baseband signal is at low frequency and gathered from the RF signal by complex downsampling.

', + ) + ) + self.spinBoxBasebandGain.setToolTip( + _translate( + "FormDeviceSettings", + '

The baseband gain is applied to the baseband signal in your software defined radio. The baseband signal is at low frequency and gathered from the RF signal by complex downsampling.

', + ) + ) self.labelPort.setText(_translate("FormDeviceSettings", "Port number:")) - self.labelGain.setToolTip(_translate("FormDeviceSettings", "

The gain (more exactly RF gain) is the gain applied to the RF signal. This amplifies the high frequent signal arriving at the antenna of your Software Defined Radio.

")) + self.labelGain.setToolTip( + _translate( + "FormDeviceSettings", + "

The gain (more exactly RF gain) is the gain applied to the RF signal. This amplifies the high frequent signal arriving at the antenna of your Software Defined Radio.

", + ) + ) self.labelGain.setText(_translate("FormDeviceSettings", "Gain:")) - self.checkBoxDCCorrection.setToolTip(_translate("FormDeviceSettings", "Apply DC correction during recording, that is, ensure the captured signal has a mean value of zero.")) - self.checkBoxDCCorrection.setText(_translate("FormDeviceSettings", "Apply DC correction")) - self.labelDeviceIdentifier.setToolTip(_translate("FormDeviceSettings", "

You can enter a device identifier here if you have multiple SDRs of the same type attached to separate them. There is no need to configure this value otherwise. URH will automatically select an attached SDR of the configured type if you leave this value empty.

")) - self.labelDeviceIdentifier.setText(_translate("FormDeviceSettings", "Device Identifier:")) + self.checkBoxDCCorrection.setToolTip( + _translate( + "FormDeviceSettings", + "Apply DC correction during recording, that is, ensure the captured signal has a mean value of zero.", + ) + ) + self.checkBoxDCCorrection.setText( + _translate("FormDeviceSettings", "Apply DC correction") + ) + self.labelDeviceIdentifier.setToolTip( + _translate( + "FormDeviceSettings", + '

You can enter a device identifier here if you have multiple SDRs of the same type attached to separate them. There is no need to configure this value otherwise. URH will automatically select an attached SDR of the configured type if you leave this value empty.

', + ) + ) + self.labelDeviceIdentifier.setText( + _translate("FormDeviceSettings", "Device Identifier:") + ) self.labelFreq.setText(_translate("FormDeviceSettings", "Frequency (Hz):")) self.labelIP.setText(_translate("FormDeviceSettings", "IP address:")) - self.spinBoxFreqCorrection.setToolTip(_translate("FormDeviceSettings", "

Set the frequency correction in ppm. If you do not know what to enter here, just leave it to one.

")) + self.spinBoxFreqCorrection.setToolTip( + _translate( + "FormDeviceSettings", + '

Set the frequency correction in ppm. If you do not know what to enter here, just leave it to one.

', + ) + ) self.labelNRepeat.setText(_translate("FormDeviceSettings", "Repeat:")) - self.comboBoxDirectSampling.setToolTip(_translate("FormDeviceSettings", "

Set the direct sampling mode. If you do not know what to choose here, just set it to disabled. The native backend is recommended, when using this setting.

")) - self.labelDCCorrection.setToolTip(_translate("FormDeviceSettings", "Apply DC correction during recording, that is, ensure the captured signal has a mean value of zero.")) - self.labelDCCorrection.setText(_translate("FormDeviceSettings", "DC correction:")) - self.labelIFGain.setToolTip(_translate("FormDeviceSettings", "

The IF Gain is applied to the Intermediate Frequency signal in your Software Defined Radio. An IF signal has a lower frequency than the high frequent RF signal, so signal processing can be applied more efficiently.

")) + self.comboBoxDirectSampling.setToolTip( + _translate( + "FormDeviceSettings", + '

Set the direct sampling mode. If you do not know what to choose here, just set it to disabled. The native backend is recommended, when using this setting.

', + ) + ) + self.labelDCCorrection.setToolTip( + _translate( + "FormDeviceSettings", + "Apply DC correction during recording, that is, ensure the captured signal has a mean value of zero.", + ) + ) + self.labelDCCorrection.setText( + _translate("FormDeviceSettings", "DC correction:") + ) + self.labelIFGain.setToolTip( + _translate( + "FormDeviceSettings", + "

The IF Gain is applied to the Intermediate Frequency signal in your Software Defined Radio. An IF signal has a lower frequency than the high frequent RF signal, so signal processing can be applied more efficiently.

", + ) + ) self.labelIFGain.setText(_translate("FormDeviceSettings", "IF Gain:")) self.labelChannel.setText(_translate("FormDeviceSettings", "Channel:")) self.btnLockBWSR.setText(_translate("FormDeviceSettings", "...")) self.label_3.setText(_translate("FormDeviceSettings", "Device:")) - self.labelBiasTee.setToolTip(_translate("FormDeviceSettings", "

Enable the bias tee of your SDR, if you have an external LNA connected. Leave this disabled if you have no external LNA attached.

")) + self.labelBiasTee.setToolTip( + _translate( + "FormDeviceSettings", + "

Enable the bias tee of your SDR, if you have an external LNA connected. Leave this disabled if you have no external LNA attached.

", + ) + ) self.labelBiasTee.setText(_translate("FormDeviceSettings", "Bias Tee:")) - self.checkBoxBiasTee.setToolTip(_translate("FormDeviceSettings", "

Enable the bias tee of your SDR, if you have an external LNA connected. Leave this disabled if you have no external LNA attached.

")) - self.checkBoxBiasTee.setText(_translate("FormDeviceSettings", "Enable Bias Tee")) + self.checkBoxBiasTee.setToolTip( + _translate( + "FormDeviceSettings", + "

Enable the bias tee of your SDR, if you have an external LNA connected. Leave this disabled if you have no external LNA attached.

", + ) + ) + self.checkBoxBiasTee.setText( + _translate("FormDeviceSettings", "Enable Bias Tee") + ) + + from urh.ui.KillerDoubleSpinBox import KillerDoubleSpinBox from . import urh_rc diff --git a/src/urh/ui/ui_send_recv_sniff_settings.py b/src/urh/ui/ui_send_recv_sniff_settings.py index 843e885899..62b3f47392 100644 --- a/src/urh/ui/ui_send_recv_sniff_settings.py +++ b/src/urh/ui/ui_send_recv_sniff_settings.py @@ -20,20 +20,22 @@ def setupUi(self, SniffSettings): font.setBold(True) font.setWeight(75) self.groupBoxSniffSettings.setFont(font) - self.groupBoxSniffSettings.setStyleSheet("QGroupBox\n" -"{\n" -"border: none;\n" -"}\n" -"\n" -"QGroupBox::title {\n" -" subcontrol-origin: margin;\n" -"}\n" -"QGroupBox::indicator:unchecked {\n" -" image: url(:/icons/icons/collapse.svg)\n" -"}\n" -"QGroupBox::indicator:checked {\n" -" image: url(:/icons/icons/uncollapse.svg)\n" -"}") + self.groupBoxSniffSettings.setStyleSheet( + "QGroupBox\n" + "{\n" + "border: none;\n" + "}\n" + "\n" + "QGroupBox::title {\n" + " subcontrol-origin: margin;\n" + "}\n" + "QGroupBox::indicator:unchecked {\n" + " image: url(:/icons/icons/collapse.svg)\n" + "}\n" + "QGroupBox::indicator:checked {\n" + " image: url(:/icons/icons/uncollapse.svg)\n" + "}" + ) self.groupBoxSniffSettings.setFlat(True) self.groupBoxSniffSettings.setCheckable(True) self.groupBoxSniffSettings.setObjectName("groupBoxSniffSettings") @@ -53,10 +55,14 @@ def setupUi(self, SniffSettings): self.horizontalLayout_3 = QtWidgets.QHBoxLayout() self.horizontalLayout_3.setObjectName("horizontalLayout_3") self.spinbox_sniff_Noise = QtWidgets.QDoubleSpinBox(self.frame) - sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Expanding, QtWidgets.QSizePolicy.Fixed) + sizePolicy = QtWidgets.QSizePolicy( + QtWidgets.QSizePolicy.Expanding, QtWidgets.QSizePolicy.Fixed + ) sizePolicy.setHorizontalStretch(0) sizePolicy.setVerticalStretch(0) - sizePolicy.setHeightForWidth(self.spinbox_sniff_Noise.sizePolicy().hasHeightForWidth()) + sizePolicy.setHeightForWidth( + self.spinbox_sniff_Noise.sizePolicy().hasHeightForWidth() + ) self.spinbox_sniff_Noise.setSizePolicy(sizePolicy) self.spinbox_sniff_Noise.setDecimals(4) self.spinbox_sniff_Noise.setMaximum(1.0) @@ -89,16 +95,22 @@ def setupUi(self, SniffSettings): self.spinbox_sniff_SamplesPerSymbol = QtWidgets.QSpinBox(self.frame) self.spinbox_sniff_SamplesPerSymbol.setMinimum(1) self.spinbox_sniff_SamplesPerSymbol.setMaximum(999999999) - self.spinbox_sniff_SamplesPerSymbol.setObjectName("spinbox_sniff_SamplesPerSymbol") + self.spinbox_sniff_SamplesPerSymbol.setObjectName( + "spinbox_sniff_SamplesPerSymbol" + ) self.gridLayout.addWidget(self.spinbox_sniff_SamplesPerSymbol, 4, 1, 1, 1) self.label_sniff_viewtype = QtWidgets.QLabel(self.frame) self.label_sniff_viewtype.setObjectName("label_sniff_viewtype") self.gridLayout.addWidget(self.label_sniff_viewtype, 9, 0, 1, 1) self.lineEdit_sniff_OutputFile = QtWidgets.QLineEdit(self.frame) - sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Expanding, QtWidgets.QSizePolicy.Fixed) + sizePolicy = QtWidgets.QSizePolicy( + QtWidgets.QSizePolicy.Expanding, QtWidgets.QSizePolicy.Fixed + ) sizePolicy.setHorizontalStretch(0) sizePolicy.setVerticalStretch(0) - sizePolicy.setHeightForWidth(self.lineEdit_sniff_OutputFile.sizePolicy().hasHeightForWidth()) + sizePolicy.setHeightForWidth( + self.lineEdit_sniff_OutputFile.sizePolicy().hasHeightForWidth() + ) self.lineEdit_sniff_OutputFile.setSizePolicy(sizePolicy) self.lineEdit_sniff_OutputFile.setReadOnly(False) self.lineEdit_sniff_OutputFile.setClearButtonEnabled(True) @@ -115,10 +127,14 @@ def setupUi(self, SniffSettings): self.horizontalLayout_2 = QtWidgets.QHBoxLayout() self.horizontalLayout_2.setObjectName("horizontalLayout_2") self.comboBox_sniff_signal = QtWidgets.QComboBox(self.frame) - sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Expanding, QtWidgets.QSizePolicy.Fixed) + sizePolicy = QtWidgets.QSizePolicy( + QtWidgets.QSizePolicy.Expanding, QtWidgets.QSizePolicy.Fixed + ) sizePolicy.setHorizontalStretch(0) sizePolicy.setVerticalStretch(0) - sizePolicy.setHeightForWidth(self.comboBox_sniff_signal.sizePolicy().hasHeightForWidth()) + sizePolicy.setHeightForWidth( + self.comboBox_sniff_signal.sizePolicy().hasHeightForWidth() + ) self.comboBox_sniff_signal.setSizePolicy(sizePolicy) self.comboBox_sniff_signal.setObjectName("comboBox_sniff_signal") self.horizontalLayout_2.addWidget(self.comboBox_sniff_signal) @@ -132,10 +148,14 @@ def setupUi(self, SniffSettings): self.horizontalLayout_4 = QtWidgets.QHBoxLayout() self.horizontalLayout_4.setObjectName("horizontalLayout_4") self.spinbox_sniff_Center = QtWidgets.QDoubleSpinBox(self.frame) - sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Expanding, QtWidgets.QSizePolicy.Fixed) + sizePolicy = QtWidgets.QSizePolicy( + QtWidgets.QSizePolicy.Expanding, QtWidgets.QSizePolicy.Fixed + ) sizePolicy.setHorizontalStretch(0) sizePolicy.setVerticalStretch(0) - sizePolicy.setHeightForWidth(self.spinbox_sniff_Center.sizePolicy().hasHeightForWidth()) + sizePolicy.setHeightForWidth( + self.spinbox_sniff_Center.sizePolicy().hasHeightForWidth() + ) self.spinbox_sniff_Center.setSizePolicy(sizePolicy) self.spinbox_sniff_Center.setDecimals(4) self.spinbox_sniff_Center.setMinimum(-3.14) @@ -166,10 +186,14 @@ def setupUi(self, SniffSettings): self.label_sniff_Noise.setObjectName("label_sniff_Noise") self.gridLayout.addWidget(self.label_sniff_Noise, 1, 0, 1, 1) self.comboBox_sniff_encoding = QtWidgets.QComboBox(self.frame) - sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Expanding, QtWidgets.QSizePolicy.Fixed) + sizePolicy = QtWidgets.QSizePolicy( + QtWidgets.QSizePolicy.Expanding, QtWidgets.QSizePolicy.Fixed + ) sizePolicy.setHorizontalStretch(0) sizePolicy.setVerticalStretch(0) - sizePolicy.setHeightForWidth(self.comboBox_sniff_encoding.sizePolicy().hasHeightForWidth()) + sizePolicy.setHeightForWidth( + self.comboBox_sniff_encoding.sizePolicy().hasHeightForWidth() + ) self.comboBox_sniff_encoding.setSizePolicy(sizePolicy) self.comboBox_sniff_encoding.setObjectName("comboBox_sniff_encoding") self.gridLayout.addWidget(self.comboBox_sniff_encoding, 8, 1, 1, 1) @@ -188,41 +212,76 @@ def setupUi(self, SniffSettings): self.verticalLayout.addWidget(self.groupBoxSniffSettings) self.retranslateUi(SniffSettings) - self.groupBoxSniffSettings.toggled['bool'].connect(self.frame.setVisible) + self.groupBoxSniffSettings.toggled["bool"].connect(self.frame.setVisible) SniffSettings.setTabOrder(self.groupBoxSniffSettings, self.spinbox_sniff_Noise) - SniffSettings.setTabOrder(self.spinbox_sniff_Noise, self.spinbox_sniff_SamplesPerSymbol) - SniffSettings.setTabOrder(self.spinbox_sniff_SamplesPerSymbol, self.spinbox_sniff_ErrorTolerance) - SniffSettings.setTabOrder(self.spinbox_sniff_ErrorTolerance, self.combox_sniff_Modulation) - SniffSettings.setTabOrder(self.combox_sniff_Modulation, self.comboBox_sniff_encoding) - SniffSettings.setTabOrder(self.comboBox_sniff_encoding, self.comboBox_sniff_viewtype) - SniffSettings.setTabOrder(self.comboBox_sniff_viewtype, self.checkBox_sniff_Timestamp) - SniffSettings.setTabOrder(self.checkBox_sniff_Timestamp, self.lineEdit_sniff_OutputFile) + SniffSettings.setTabOrder( + self.spinbox_sniff_Noise, self.spinbox_sniff_SamplesPerSymbol + ) + SniffSettings.setTabOrder( + self.spinbox_sniff_SamplesPerSymbol, self.spinbox_sniff_ErrorTolerance + ) + SniffSettings.setTabOrder( + self.spinbox_sniff_ErrorTolerance, self.combox_sniff_Modulation + ) + SniffSettings.setTabOrder( + self.combox_sniff_Modulation, self.comboBox_sniff_encoding + ) + SniffSettings.setTabOrder( + self.comboBox_sniff_encoding, self.comboBox_sniff_viewtype + ) + SniffSettings.setTabOrder( + self.comboBox_sniff_viewtype, self.checkBox_sniff_Timestamp + ) + SniffSettings.setTabOrder( + self.checkBox_sniff_Timestamp, self.lineEdit_sniff_OutputFile + ) def retranslateUi(self, SniffSettings): _translate = QtCore.QCoreApplication.translate SniffSettings.setWindowTitle(_translate("SniffSettings", "Form")) - self.groupBoxSniffSettings.setTitle(_translate("SniffSettings", "Sniff settings")) + self.groupBoxSniffSettings.setTitle( + _translate("SniffSettings", "Sniff settings") + ) self.label_sniff_Center.setText(_translate("SniffSettings", "Center:")) - self.checkBoxAdaptiveNoise.setToolTip(_translate("SniffSettings", "

With adaptive noise URH will update the noise level automatically during RX. This is helpful in a dynamic environment where noise differs in time.

")) + self.checkBoxAdaptiveNoise.setToolTip( + _translate( + "SniffSettings", + "

With adaptive noise URH will update the noise level automatically during RX. This is helpful in a dynamic environment where noise differs in time.

", + ) + ) self.checkBoxAdaptiveNoise.setText(_translate("SniffSettings", "Adaptive")) self.label_sniff_Modulation.setText(_translate("SniffSettings", "Modulation:")) self.label_sniff_Signal.setText(_translate("SniffSettings", "Use values from:")) self.combox_sniff_Modulation.setItemText(0, _translate("SniffSettings", "ASK")) self.combox_sniff_Modulation.setItemText(1, _translate("SniffSettings", "FSK")) self.combox_sniff_Modulation.setItemText(2, _translate("SniffSettings", "PSK")) - self.label_sniff_Tolerance.setText(_translate("SniffSettings", "Error Tolerance:")) + self.label_sniff_Tolerance.setText( + _translate("SniffSettings", "Error Tolerance:") + ) self.label_sniff_viewtype.setText(_translate("SniffSettings", "View:")) - self.lineEdit_sniff_OutputFile.setPlaceholderText(_translate("SniffSettings", "None")) - self.label_sniff_BitLength.setText(_translate("SniffSettings", "Samples per Symbol:")) + self.lineEdit_sniff_OutputFile.setPlaceholderText( + _translate("SniffSettings", "None") + ) + self.label_sniff_BitLength.setText( + _translate("SniffSettings", "Samples per Symbol:") + ) self.btn_sniff_use_signal.setText(_translate("SniffSettings", "Use")) - self.label_sniff_OutputFile.setText(_translate("SniffSettings", "Write bitstream to file:")) + self.label_sniff_OutputFile.setText( + _translate("SniffSettings", "Write bitstream to file:") + ) self.checkBoxAutoCenter.setText(_translate("SniffSettings", "Automatic")) self.label_sniff_encoding.setText(_translate("SniffSettings", "Encoding:")) self.comboBox_sniff_viewtype.setItemText(0, _translate("SniffSettings", "Bit")) self.comboBox_sniff_viewtype.setItemText(1, _translate("SniffSettings", "Hex")) - self.comboBox_sniff_viewtype.setItemText(2, _translate("SniffSettings", "ASCII")) - self.checkBox_sniff_Timestamp.setText(_translate("SniffSettings", "Show Timestamp")) + self.comboBox_sniff_viewtype.setItemText( + 2, _translate("SniffSettings", "ASCII") + ) + self.checkBox_sniff_Timestamp.setText( + _translate("SniffSettings", "Show Timestamp") + ) self.label_sniff_Noise.setText(_translate("SniffSettings", "Noise:")) self.labelCenterSpacing.setText(_translate("SniffSettings", "Center Spacing:")) self.labelBitsPerSymbol.setText(_translate("SniffSettings", "Bits per Symbol:")) + + from . import urh_rc diff --git a/src/urh/ui/ui_signal_details.py b/src/urh/ui/ui_signal_details.py index 885bdb6004..2595d369f7 100644 --- a/src/urh/ui/ui_signal_details.py +++ b/src/urh/ui/ui_signal_details.py @@ -16,13 +16,15 @@ def setupUi(self, SignalDetails): self.verticalLayout.setObjectName("verticalLayout") self.gridLayout = QtWidgets.QGridLayout() self.gridLayout.setObjectName("gridLayout") - spacerItem = QtWidgets.QSpacerItem(40, 20, QtWidgets.QSizePolicy.Expanding, QtWidgets.QSizePolicy.Minimum) + spacerItem = QtWidgets.QSpacerItem( + 40, 20, QtWidgets.QSizePolicy.Expanding, QtWidgets.QSizePolicy.Minimum + ) self.gridLayout.addItem(spacerItem, 2, 2, 1, 1) self.dsb_sample_rate = KillerDoubleSpinBox(SignalDetails) self.dsb_sample_rate.setWrapping(False) self.dsb_sample_rate.setProperty("showGroupSeparator", False) self.dsb_sample_rate.setMinimum(0.01) - self.dsb_sample_rate.setMaximum(1e+33) + self.dsb_sample_rate.setMaximum(1e33) self.dsb_sample_rate.setProperty("value", 1000000.0) self.dsb_sample_rate.setObjectName("dsb_sample_rate") self.gridLayout.addWidget(self.dsb_sample_rate, 5, 1, 1, 1) @@ -30,12 +32,18 @@ def setupUi(self, SignalDetails): self.label.setObjectName("label") self.gridLayout.addWidget(self.label, 0, 0, 1, 1) self.lblFile = QtWidgets.QLabel(SignalDetails) - sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Expanding, QtWidgets.QSizePolicy.Preferred) + sizePolicy = QtWidgets.QSizePolicy( + QtWidgets.QSizePolicy.Expanding, QtWidgets.QSizePolicy.Preferred + ) sizePolicy.setHorizontalStretch(0) sizePolicy.setVerticalStretch(0) sizePolicy.setHeightForWidth(self.lblFile.sizePolicy().hasHeightForWidth()) self.lblFile.setSizePolicy(sizePolicy) - self.lblFile.setTextInteractionFlags(QtCore.Qt.LinksAccessibleByMouse|QtCore.Qt.TextSelectableByKeyboard|QtCore.Qt.TextSelectableByMouse) + self.lblFile.setTextInteractionFlags( + QtCore.Qt.LinksAccessibleByMouse + | QtCore.Qt.TextSelectableByKeyboard + | QtCore.Qt.TextSelectableByMouse + ) self.lblFile.setObjectName("lblFile") self.gridLayout.addWidget(self.lblFile, 1, 1, 1, 1) self.label_2 = QtWidgets.QLabel(SignalDetails) @@ -54,12 +62,18 @@ def setupUi(self, SignalDetails): self.label_3.setObjectName("label_3") self.gridLayout.addWidget(self.label_3, 2, 0, 1, 1) self.lblName = QtWidgets.QLabel(SignalDetails) - sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Expanding, QtWidgets.QSizePolicy.Preferred) + sizePolicy = QtWidgets.QSizePolicy( + QtWidgets.QSizePolicy.Expanding, QtWidgets.QSizePolicy.Preferred + ) sizePolicy.setHorizontalStretch(0) sizePolicy.setVerticalStretch(0) sizePolicy.setHeightForWidth(self.lblName.sizePolicy().hasHeightForWidth()) self.lblName.setSizePolicy(sizePolicy) - self.lblName.setTextInteractionFlags(QtCore.Qt.LinksAccessibleByMouse|QtCore.Qt.TextSelectableByKeyboard|QtCore.Qt.TextSelectableByMouse) + self.lblName.setTextInteractionFlags( + QtCore.Qt.LinksAccessibleByMouse + | QtCore.Qt.TextSelectableByKeyboard + | QtCore.Qt.TextSelectableByMouse + ) self.lblName.setObjectName("lblName") self.gridLayout.addWidget(self.lblName, 0, 1, 1, 1) self.lblFileSize = QtWidgets.QLabel(SignalDetails) @@ -78,7 +92,9 @@ def setupUi(self, SignalDetails): self.lDuration.setObjectName("lDuration") self.gridLayout.addWidget(self.lDuration, 6, 1, 1, 1) self.verticalLayout.addLayout(self.gridLayout) - spacerItem1 = QtWidgets.QSpacerItem(20, 135, QtWidgets.QSizePolicy.Minimum, QtWidgets.QSizePolicy.Expanding) + spacerItem1 = QtWidgets.QSpacerItem( + 20, 135, QtWidgets.QSizePolicy.Minimum, QtWidgets.QSizePolicy.Expanding + ) self.verticalLayout.addItem(spacerItem1) self.retranslateUi(SignalDetails) @@ -99,4 +115,6 @@ def retranslateUi(self, SignalDetails): self.lFileCreated.setText(_translate("SignalDetails", "TextLabel")) self.label_7.setText(_translate("SignalDetails", "Duration:")) self.lDuration.setText(_translate("SignalDetails", "42s")) + + from urh.ui.KillerDoubleSpinBox import KillerDoubleSpinBox diff --git a/src/urh/ui/ui_signal_frame.py b/src/urh/ui/ui_signal_frame.py index 6f172b4b72..55a70adeba 100644 --- a/src/urh/ui/ui_signal_frame.py +++ b/src/urh/ui/ui_signal_frame.py @@ -13,7 +13,9 @@ class Ui_SignalFrame(object): def setupUi(self, SignalFrame): SignalFrame.setObjectName("SignalFrame") SignalFrame.resize(1057, 652) - sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Preferred, QtWidgets.QSizePolicy.Maximum) + sizePolicy = QtWidgets.QSizePolicy( + QtWidgets.QSizePolicy.Preferred, QtWidgets.QSizePolicy.Maximum + ) sizePolicy.setHorizontalStretch(0) sizePolicy.setVerticalStretch(0) sizePolicy.setHeightForWidth(SignalFrame.sizePolicy().hasHeightForWidth()) @@ -35,10 +37,14 @@ def setupUi(self, SignalFrame): self.gridLayout_2.setSizeConstraint(QtWidgets.QLayout.SetFixedSize) self.gridLayout_2.setObjectName("gridLayout_2") self.lSignalViewText = QtWidgets.QLabel(SignalFrame) - sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Minimum, QtWidgets.QSizePolicy.Preferred) + sizePolicy = QtWidgets.QSizePolicy( + QtWidgets.QSizePolicy.Minimum, QtWidgets.QSizePolicy.Preferred + ) sizePolicy.setHorizontalStretch(0) sizePolicy.setVerticalStretch(0) - sizePolicy.setHeightForWidth(self.lSignalViewText.sizePolicy().hasHeightForWidth()) + sizePolicy.setHeightForWidth( + self.lSignalViewText.sizePolicy().hasHeightForWidth() + ) self.lSignalViewText.setSizePolicy(sizePolicy) font = QtGui.QFont() font.setUnderline(False) @@ -59,13 +65,19 @@ def setupUi(self, SignalFrame): self.btnSaveSignal.setIcon(icon) self.btnSaveSignal.setObjectName("btnSaveSignal") self.gridLayout.addWidget(self.btnSaveSignal, 0, 3, 1, 1) - spacerItem = QtWidgets.QSpacerItem(10, 20, QtWidgets.QSizePolicy.Expanding, QtWidgets.QSizePolicy.Minimum) + spacerItem = QtWidgets.QSpacerItem( + 10, 20, QtWidgets.QSizePolicy.Expanding, QtWidgets.QSizePolicy.Minimum + ) self.gridLayout.addItem(spacerItem, 0, 2, 1, 1) self.btnCloseSignal = QtWidgets.QToolButton(SignalFrame) - sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Fixed, QtWidgets.QSizePolicy.Fixed) + sizePolicy = QtWidgets.QSizePolicy( + QtWidgets.QSizePolicy.Fixed, QtWidgets.QSizePolicy.Fixed + ) sizePolicy.setHorizontalStretch(0) sizePolicy.setVerticalStretch(0) - sizePolicy.setHeightForWidth(self.btnCloseSignal.sizePolicy().hasHeightForWidth()) + sizePolicy.setHeightForWidth( + self.btnCloseSignal.sizePolicy().hasHeightForWidth() + ) self.btnCloseSignal.setSizePolicy(sizePolicy) self.btnCloseSignal.setMinimumSize(QtCore.QSize(24, 24)) self.btnCloseSignal.setMaximumSize(QtCore.QSize(24, 24)) @@ -75,7 +87,9 @@ def setupUi(self, SignalFrame): self.btnCloseSignal.setObjectName("btnCloseSignal") self.gridLayout.addWidget(self.btnCloseSignal, 0, 9, 1, 1) self.lSignalTyp = QtWidgets.QLabel(SignalFrame) - sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Fixed, QtWidgets.QSizePolicy.Preferred) + sizePolicy = QtWidgets.QSizePolicy( + QtWidgets.QSizePolicy.Fixed, QtWidgets.QSizePolicy.Preferred + ) sizePolicy.setHorizontalStretch(0) sizePolicy.setVerticalStretch(0) sizePolicy.setHeightForWidth(self.lSignalTyp.sizePolicy().hasHeightForWidth()) @@ -83,7 +97,9 @@ def setupUi(self, SignalFrame): self.lSignalTyp.setObjectName("lSignalTyp") self.gridLayout.addWidget(self.lSignalTyp, 0, 1, 1, 1) self.lSignalNr = QtWidgets.QLabel(SignalFrame) - sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Maximum, QtWidgets.QSizePolicy.Fixed) + sizePolicy = QtWidgets.QSizePolicy( + QtWidgets.QSizePolicy.Maximum, QtWidgets.QSizePolicy.Fixed + ) sizePolicy.setHorizontalStretch(0) sizePolicy.setVerticalStretch(0) sizePolicy.setHeightForWidth(self.lSignalNr.sizePolicy().hasHeightForWidth()) @@ -124,29 +140,41 @@ def setupUi(self, SignalFrame): self.spinBoxTolerance.setObjectName("spinBoxTolerance") self.gridLayout_2.addWidget(self.spinBoxTolerance, 8, 1, 1, 1) self.lSamplesPerSymbol = QtWidgets.QLabel(SignalFrame) - sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Minimum, QtWidgets.QSizePolicy.Preferred) + sizePolicy = QtWidgets.QSizePolicy( + QtWidgets.QSizePolicy.Minimum, QtWidgets.QSizePolicy.Preferred + ) sizePolicy.setHorizontalStretch(0) sizePolicy.setVerticalStretch(0) - sizePolicy.setHeightForWidth(self.lSamplesPerSymbol.sizePolicy().hasHeightForWidth()) + sizePolicy.setHeightForWidth( + self.lSamplesPerSymbol.sizePolicy().hasHeightForWidth() + ) self.lSamplesPerSymbol.setSizePolicy(sizePolicy) self.lSamplesPerSymbol.setTextInteractionFlags(QtCore.Qt.LinksAccessibleByMouse) self.lSamplesPerSymbol.setObjectName("lSamplesPerSymbol") self.gridLayout_2.addWidget(self.lSamplesPerSymbol, 5, 0, 1, 1) self.lErrorTolerance = QtWidgets.QLabel(SignalFrame) - sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Minimum, QtWidgets.QSizePolicy.Preferred) + sizePolicy = QtWidgets.QSizePolicy( + QtWidgets.QSizePolicy.Minimum, QtWidgets.QSizePolicy.Preferred + ) sizePolicy.setHorizontalStretch(0) sizePolicy.setVerticalStretch(0) - sizePolicy.setHeightForWidth(self.lErrorTolerance.sizePolicy().hasHeightForWidth()) + sizePolicy.setHeightForWidth( + self.lErrorTolerance.sizePolicy().hasHeightForWidth() + ) self.lErrorTolerance.setSizePolicy(sizePolicy) self.lErrorTolerance.setMinimumSize(QtCore.QSize(0, 0)) self.lErrorTolerance.setMaximumSize(QtCore.QSize(16777215, 16777215)) self.lErrorTolerance.setObjectName("lErrorTolerance") self.gridLayout_2.addWidget(self.lErrorTolerance, 8, 0, 1, 1) self.lCenterOffset = QtWidgets.QLabel(SignalFrame) - sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Minimum, QtWidgets.QSizePolicy.Preferred) + sizePolicy = QtWidgets.QSizePolicy( + QtWidgets.QSizePolicy.Minimum, QtWidgets.QSizePolicy.Preferred + ) sizePolicy.setHorizontalStretch(0) sizePolicy.setVerticalStretch(0) - sizePolicy.setHeightForWidth(self.lCenterOffset.sizePolicy().hasHeightForWidth()) + sizePolicy.setHeightForWidth( + self.lCenterOffset.sizePolicy().hasHeightForWidth() + ) self.lCenterOffset.setSizePolicy(sizePolicy) self.lCenterOffset.setMinimumSize(QtCore.QSize(0, 0)) self.lCenterOffset.setMaximumSize(QtCore.QSize(16777215, 16777215)) @@ -157,7 +185,9 @@ def setupUi(self, SignalFrame): self.labelModulation.setObjectName("labelModulation") self.gridLayout_2.addWidget(self.labelModulation, 10, 0, 1, 1) self.cbSignalView = QtWidgets.QComboBox(SignalFrame) - sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Minimum, QtWidgets.QSizePolicy.Fixed) + sizePolicy = QtWidgets.QSizePolicy( + QtWidgets.QSizePolicy.Minimum, QtWidgets.QSizePolicy.Fixed + ) sizePolicy.setHorizontalStretch(0) sizePolicy.setVerticalStretch(0) sizePolicy.setHeightForWidth(self.cbSignalView.sizePolicy().hasHeightForWidth()) @@ -184,10 +214,14 @@ def setupUi(self, SignalFrame): self.spinBoxCenterSpacing.setObjectName("spinBoxCenterSpacing") self.gridLayout_2.addWidget(self.spinBoxCenterSpacing, 4, 1, 1, 1) self.lineEditSignalName = QtWidgets.QLineEdit(SignalFrame) - sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Preferred, QtWidgets.QSizePolicy.Fixed) + sizePolicy = QtWidgets.QSizePolicy( + QtWidgets.QSizePolicy.Preferred, QtWidgets.QSizePolicy.Fixed + ) sizePolicy.setHorizontalStretch(0) sizePolicy.setVerticalStretch(0) - sizePolicy.setHeightForWidth(self.lineEditSignalName.sizePolicy().hasHeightForWidth()) + sizePolicy.setHeightForWidth( + self.lineEditSignalName.sizePolicy().hasHeightForWidth() + ) self.lineEditSignalName.setSizePolicy(sizePolicy) self.lineEditSignalName.setMinimumSize(QtCore.QSize(214, 0)) self.lineEditSignalName.setMaximumSize(QtCore.QSize(16777215, 16777215)) @@ -207,7 +241,9 @@ def setupUi(self, SignalFrame): icon = QtGui.QIcon.fromTheme("configure") self.btnAdvancedModulationSettings.setIcon(icon) self.btnAdvancedModulationSettings.setIconSize(QtCore.QSize(16, 16)) - self.btnAdvancedModulationSettings.setObjectName("btnAdvancedModulationSettings") + self.btnAdvancedModulationSettings.setObjectName( + "btnAdvancedModulationSettings" + ) self.horizontalLayout_5.addWidget(self.btnAdvancedModulationSettings) self.gridLayout_2.addLayout(self.horizontalLayout_5, 10, 1, 1, 1) self.chkBoxSyncSelection = QtWidgets.QCheckBox(SignalFrame) @@ -230,10 +266,14 @@ def setupUi(self, SignalFrame): self.spinBoxSamplesPerSymbol.setObjectName("spinBoxSamplesPerSymbol") self.gridLayout_2.addWidget(self.spinBoxSamplesPerSymbol, 5, 1, 1, 1) self.btnAutoDetect = QtWidgets.QToolButton(SignalFrame) - sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Preferred, QtWidgets.QSizePolicy.Fixed) + sizePolicy = QtWidgets.QSizePolicy( + QtWidgets.QSizePolicy.Preferred, QtWidgets.QSizePolicy.Fixed + ) sizePolicy.setHorizontalStretch(0) sizePolicy.setVerticalStretch(0) - sizePolicy.setHeightForWidth(self.btnAutoDetect.sizePolicy().hasHeightForWidth()) + sizePolicy.setHeightForWidth( + self.btnAutoDetect.sizePolicy().hasHeightForWidth() + ) self.btnAutoDetect.setSizePolicy(sizePolicy) self.btnAutoDetect.setIconSize(QtCore.QSize(16, 16)) self.btnAutoDetect.setCheckable(False) @@ -248,10 +288,14 @@ def setupUi(self, SignalFrame): self.line.setObjectName("line") self.gridLayout_2.addWidget(self.line, 15, 0, 1, 2) self.sliderSpectrogramMin = QtWidgets.QSlider(SignalFrame) - sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Preferred, QtWidgets.QSizePolicy.Fixed) + sizePolicy = QtWidgets.QSizePolicy( + QtWidgets.QSizePolicy.Preferred, QtWidgets.QSizePolicy.Fixed + ) sizePolicy.setHorizontalStretch(0) sizePolicy.setVerticalStretch(0) - sizePolicy.setHeightForWidth(self.sliderSpectrogramMin.sizePolicy().hasHeightForWidth()) + sizePolicy.setHeightForWidth( + self.sliderSpectrogramMin.sizePolicy().hasHeightForWidth() + ) self.sliderSpectrogramMin.setSizePolicy(sizePolicy) self.sliderSpectrogramMin.setMinimum(-150) self.sliderSpectrogramMin.setMaximum(10) @@ -262,10 +306,14 @@ def setupUi(self, SignalFrame): self.labelFFTWindowSize.setObjectName("labelFFTWindowSize") self.gridLayout_2.addWidget(self.labelFFTWindowSize, 20, 0, 1, 1) self.sliderSpectrogramMax = QtWidgets.QSlider(SignalFrame) - sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Preferred, QtWidgets.QSizePolicy.Fixed) + sizePolicy = QtWidgets.QSizePolicy( + QtWidgets.QSizePolicy.Preferred, QtWidgets.QSizePolicy.Fixed + ) sizePolicy.setHorizontalStretch(0) sizePolicy.setVerticalStretch(0) - sizePolicy.setHeightForWidth(self.sliderSpectrogramMax.sizePolicy().hasHeightForWidth()) + sizePolicy.setHeightForWidth( + self.sliderSpectrogramMax.sizePolicy().hasHeightForWidth() + ) self.sliderSpectrogramMax.setSizePolicy(sizePolicy) self.sliderSpectrogramMax.setMinimum(-150) self.sliderSpectrogramMax.setMaximum(10) @@ -284,13 +332,19 @@ def setupUi(self, SignalFrame): self.labelNoise = QtWidgets.QLabel(SignalFrame) self.labelNoise.setObjectName("labelNoise") self.gridLayout_2.addWidget(self.labelNoise, 2, 0, 1, 1) - spacerItem1 = QtWidgets.QSpacerItem(20, 40, QtWidgets.QSizePolicy.Minimum, QtWidgets.QSizePolicy.Expanding) + spacerItem1 = QtWidgets.QSpacerItem( + 20, 40, QtWidgets.QSizePolicy.Minimum, QtWidgets.QSizePolicy.Expanding + ) self.gridLayout_2.addItem(spacerItem1, 14, 0, 1, 1) self.sliderFFTWindowSize = QtWidgets.QSlider(SignalFrame) - sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Preferred, QtWidgets.QSizePolicy.Fixed) + sizePolicy = QtWidgets.QSizePolicy( + QtWidgets.QSizePolicy.Preferred, QtWidgets.QSizePolicy.Fixed + ) sizePolicy.setHorizontalStretch(0) sizePolicy.setVerticalStretch(0) - sizePolicy.setHeightForWidth(self.sliderFFTWindowSize.sizePolicy().hasHeightForWidth()) + sizePolicy.setHeightForWidth( + self.sliderFFTWindowSize.sizePolicy().hasHeightForWidth() + ) self.sliderFFTWindowSize.setSizePolicy(sizePolicy) self.sliderFFTWindowSize.setMinimum(6) self.sliderFFTWindowSize.setMaximum(15) @@ -302,19 +356,23 @@ def setupUi(self, SignalFrame): self.gridLayout_2.addWidget(self.lBitsPerSymbol, 11, 0, 1, 1) self.horizontalLayout.addLayout(self.gridLayout_2) self.splitter = QtWidgets.QSplitter(SignalFrame) - sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Expanding, QtWidgets.QSizePolicy.Expanding) + sizePolicy = QtWidgets.QSizePolicy( + QtWidgets.QSizePolicy.Expanding, QtWidgets.QSizePolicy.Expanding + ) sizePolicy.setHorizontalStretch(0) sizePolicy.setVerticalStretch(0) sizePolicy.setHeightForWidth(self.splitter.sizePolicy().hasHeightForWidth()) self.splitter.setSizePolicy(sizePolicy) - self.splitter.setStyleSheet("QSplitter::handle:vertical {\n" -"margin: 4px 0px;\n" -" background-color: qlineargradient(x1:0, y1:0, x2:1, y2:0, \n" -"stop:0 rgba(255, 255, 255, 0), \n" -"stop:0.5 rgba(100, 100, 100, 100), \n" -"stop:1 rgba(255, 255, 255, 0));\n" -" image: url(:/icons/icons/splitter_handle_horizontal.svg);\n" -"}") + self.splitter.setStyleSheet( + "QSplitter::handle:vertical {\n" + "margin: 4px 0px;\n" + " background-color: qlineargradient(x1:0, y1:0, x2:1, y2:0, \n" + "stop:0 rgba(255, 255, 255, 0), \n" + "stop:0.5 rgba(100, 100, 100, 100), \n" + "stop:1 rgba(255, 255, 255, 0));\n" + " image: url(:/icons/icons/splitter_handle_horizontal.svg);\n" + "}" + ) self.splitter.setFrameShape(QtWidgets.QFrame.NoFrame) self.splitter.setLineWidth(1) self.splitter.setOrientation(QtCore.Qt.Vertical) @@ -340,7 +398,9 @@ def setupUi(self, SignalFrame): self.horizontalLayout_6.setObjectName("horizontalLayout_6") self.gvSignal = EpicGraphicView(self.pageSignal) self.gvSignal.setEnabled(True) - sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Expanding, QtWidgets.QSizePolicy.Expanding) + sizePolicy = QtWidgets.QSizePolicy( + QtWidgets.QSizePolicy.Expanding, QtWidgets.QSizePolicy.Expanding + ) sizePolicy.setHorizontalStretch(0) sizePolicy.setVerticalStretch(0) sizePolicy.setHeightForWidth(self.gvSignal.sizePolicy().hasHeightForWidth()) @@ -357,14 +417,21 @@ def setupUi(self, SignalFrame): self.gvSignal.setVerticalScrollBarPolicy(QtCore.Qt.ScrollBarAlwaysOn) self.gvSignal.setHorizontalScrollBarPolicy(QtCore.Qt.ScrollBarAlwaysOn) self.gvSignal.setInteractive(False) - self.gvSignal.setRenderHints(QtGui.QPainter.Antialiasing|QtGui.QPainter.TextAntialiasing) + self.gvSignal.setRenderHints( + QtGui.QPainter.Antialiasing | QtGui.QPainter.TextAntialiasing + ) self.gvSignal.setDragMode(QtWidgets.QGraphicsView.NoDrag) self.gvSignal.setCacheMode(QtWidgets.QGraphicsView.CacheNone) self.gvSignal.setTransformationAnchor(QtWidgets.QGraphicsView.NoAnchor) self.gvSignal.setResizeAnchor(QtWidgets.QGraphicsView.NoAnchor) - self.gvSignal.setViewportUpdateMode(QtWidgets.QGraphicsView.MinimalViewportUpdate) + self.gvSignal.setViewportUpdateMode( + QtWidgets.QGraphicsView.MinimalViewportUpdate + ) self.gvSignal.setRubberBandSelectionMode(QtCore.Qt.ContainsItemShape) - self.gvSignal.setOptimizationFlags(QtWidgets.QGraphicsView.DontClipPainter|QtWidgets.QGraphicsView.DontSavePainterState) + self.gvSignal.setOptimizationFlags( + QtWidgets.QGraphicsView.DontClipPainter + | QtWidgets.QGraphicsView.DontSavePainterState + ) self.gvSignal.setObjectName("gvSignal") self.horizontalLayout_6.addWidget(self.gvSignal) self.stackedWidget.addWidget(self.pageSignal) @@ -381,8 +448,13 @@ def setupUi(self, SignalFrame): self.gvSpectrogram.setRenderHints(QtGui.QPainter.TextAntialiasing) self.gvSpectrogram.setCacheMode(QtWidgets.QGraphicsView.CacheNone) self.gvSpectrogram.setTransformationAnchor(QtWidgets.QGraphicsView.NoAnchor) - self.gvSpectrogram.setViewportUpdateMode(QtWidgets.QGraphicsView.MinimalViewportUpdate) - self.gvSpectrogram.setOptimizationFlags(QtWidgets.QGraphicsView.DontClipPainter|QtWidgets.QGraphicsView.DontSavePainterState) + self.gvSpectrogram.setViewportUpdateMode( + QtWidgets.QGraphicsView.MinimalViewportUpdate + ) + self.gvSpectrogram.setOptimizationFlags( + QtWidgets.QGraphicsView.DontClipPainter + | QtWidgets.QGraphicsView.DontSavePainterState + ) self.gvSpectrogram.setObjectName("gvSpectrogram") self.horizontalLayout_4.addWidget(self.gvSpectrogram) self.stackedWidget.addWidget(self.pageSpectrogram) @@ -395,14 +467,18 @@ def setupUi(self, SignalFrame): font.setPointSize(12) self.labelLoadingAutoInterpretation.setFont(font) self.labelLoadingAutoInterpretation.setWordWrap(True) - self.labelLoadingAutoInterpretation.setObjectName("labelLoadingAutoInterpretation") + self.labelLoadingAutoInterpretation.setObjectName( + "labelLoadingAutoInterpretation" + ) self.verticalLayout_2.addWidget(self.labelLoadingAutoInterpretation) self.stackedWidget.addWidget(self.pageLoading) self.horizontalLayout_2.addWidget(self.stackedWidget) self.verticalLayout_5 = QtWidgets.QVBoxLayout() self.verticalLayout_5.setObjectName("verticalLayout_5") self.lYScale = QtWidgets.QLabel(self.layoutWidget) - self.lYScale.setLocale(QtCore.QLocale(QtCore.QLocale.English, QtCore.QLocale.UnitedStates)) + self.lYScale.setLocale( + QtCore.QLocale(QtCore.QLocale.English, QtCore.QLocale.UnitedStates) + ) self.lYScale.setObjectName("lYScale") self.verticalLayout_5.addWidget(self.lYScale) self.sliderYScale = QtWidgets.QSlider(self.layoutWidget) @@ -417,10 +493,14 @@ def setupUi(self, SignalFrame): self.horizontalLayout_3 = QtWidgets.QHBoxLayout() self.horizontalLayout_3.setObjectName("horizontalLayout_3") self.btnShowHideStartEnd = QtWidgets.QToolButton(self.layoutWidget) - sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Minimum, QtWidgets.QSizePolicy.Preferred) + sizePolicy = QtWidgets.QSizePolicy( + QtWidgets.QSizePolicy.Minimum, QtWidgets.QSizePolicy.Preferred + ) sizePolicy.setHorizontalStretch(0) sizePolicy.setVerticalStretch(0) - sizePolicy.setHeightForWidth(self.btnShowHideStartEnd.sizePolicy().hasHeightForWidth()) + sizePolicy.setHeightForWidth( + self.btnShowHideStartEnd.sizePolicy().hasHeightForWidth() + ) self.btnShowHideStartEnd.setSizePolicy(sizePolicy) self.btnShowHideStartEnd.setAutoFillBackground(False) self.btnShowHideStartEnd.setStyleSheet("") @@ -452,7 +532,9 @@ def setupUi(self, SignalFrame): self.labelRSSI = QtWidgets.QLabel(self.layoutWidget) self.labelRSSI.setObjectName("labelRSSI") self.horizontalLayout_3.addWidget(self.labelRSSI) - spacerItem2 = QtWidgets.QSpacerItem(40, 20, QtWidgets.QSizePolicy.Expanding, QtWidgets.QSizePolicy.Minimum) + spacerItem2 = QtWidgets.QSpacerItem( + 40, 20, QtWidgets.QSizePolicy.Expanding, QtWidgets.QSizePolicy.Minimum + ) self.horizontalLayout_3.addItem(spacerItem2) self.btnFilter = QtWidgets.QToolButton(self.layoutWidget) icon = QtGui.QIcon.fromTheme("view-filter") @@ -481,10 +563,14 @@ def setupUi(self, SignalFrame): self.spinBoxSelectionEnd.setMaximum(99999999) self.spinBoxSelectionEnd.setObjectName("spinBoxSelectionEnd") self.additionalInfos.addWidget(self.spinBoxSelectionEnd) - spacerItem3 = QtWidgets.QSpacerItem(40, 20, QtWidgets.QSizePolicy.Expanding, QtWidgets.QSizePolicy.Minimum) + spacerItem3 = QtWidgets.QSpacerItem( + 40, 20, QtWidgets.QSizePolicy.Expanding, QtWidgets.QSizePolicy.Minimum + ) self.additionalInfos.addItem(spacerItem3) self.lZoomText = QtWidgets.QLabel(self.layoutWidget) - sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Minimum, QtWidgets.QSizePolicy.Minimum) + sizePolicy = QtWidgets.QSizePolicy( + QtWidgets.QSizePolicy.Minimum, QtWidgets.QSizePolicy.Minimum + ) sizePolicy.setHorizontalStretch(0) sizePolicy.setVerticalStretch(0) sizePolicy.setHeightForWidth(self.lZoomText.sizePolicy().hasHeightForWidth()) @@ -496,7 +582,9 @@ def setupUi(self, SignalFrame): font.setUnderline(False) self.lZoomText.setFont(font) self.lZoomText.setTextFormat(QtCore.Qt.PlainText) - self.lZoomText.setAlignment(QtCore.Qt.AlignLeading|QtCore.Qt.AlignLeft|QtCore.Qt.AlignVCenter) + self.lZoomText.setAlignment( + QtCore.Qt.AlignLeading | QtCore.Qt.AlignLeft | QtCore.Qt.AlignVCenter + ) self.lZoomText.setObjectName("lZoomText") self.additionalInfos.addWidget(self.lZoomText) self.spinBoxXZoom = QtWidgets.QSpinBox(self.layoutWidget) @@ -504,7 +592,9 @@ def setupUi(self, SignalFrame): self.spinBoxXZoom.setMaximum(999999999) self.spinBoxXZoom.setObjectName("spinBoxXZoom") self.additionalInfos.addWidget(self.spinBoxXZoom) - spacerItem4 = QtWidgets.QSpacerItem(40, 20, QtWidgets.QSizePolicy.Expanding, QtWidgets.QSizePolicy.Minimum) + spacerItem4 = QtWidgets.QSpacerItem( + 40, 20, QtWidgets.QSizePolicy.Expanding, QtWidgets.QSizePolicy.Minimum + ) self.additionalInfos.addItem(spacerItem4) self.lSamplesInView = QtWidgets.QLabel(self.layoutWidget) self.lSamplesInView.setObjectName("lSamplesInView") @@ -520,7 +610,9 @@ def setupUi(self, SignalFrame): self.additionalInfos.addWidget(self.lSamplesViewText) self.verticalLayout.addLayout(self.additionalInfos) self.txtEdProto = TextEditProtocolView(self.splitter) - sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Expanding, QtWidgets.QSizePolicy.MinimumExpanding) + sizePolicy = QtWidgets.QSizePolicy( + QtWidgets.QSizePolicy.Expanding, QtWidgets.QSizePolicy.MinimumExpanding + ) sizePolicy.setHorizontalStretch(0) sizePolicy.setVerticalStretch(0) sizePolicy.setHeightForWidth(self.txtEdProto.sizePolicy().hasHeightForWidth()) @@ -547,8 +639,12 @@ def setupUi(self, SignalFrame): SignalFrame.setTabOrder(self.spinBoxSamplesPerSymbol, self.spinBoxTolerance) SignalFrame.setTabOrder(self.spinBoxTolerance, self.cbModulationType) SignalFrame.setTabOrder(self.cbModulationType, self.spinBoxBitsPerSymbol) - SignalFrame.setTabOrder(self.spinBoxBitsPerSymbol, self.btnAdvancedModulationSettings) - SignalFrame.setTabOrder(self.btnAdvancedModulationSettings, self.btnShowHideStartEnd) + SignalFrame.setTabOrder( + self.spinBoxBitsPerSymbol, self.btnAdvancedModulationSettings + ) + SignalFrame.setTabOrder( + self.btnAdvancedModulationSettings, self.btnShowHideStartEnd + ) SignalFrame.setTabOrder(self.btnShowHideStartEnd, self.btnAutoDetect) SignalFrame.setTabOrder(self.btnAutoDetect, self.txtEdProto) SignalFrame.setTabOrder(self.txtEdProto, self.cbSignalView) @@ -569,7 +665,12 @@ def retranslateUi(self, SignalFrame): _translate = QtCore.QCoreApplication.translate SignalFrame.setWindowTitle(_translate("SignalFrame", "Frame")) self.lSignalViewText.setText(_translate("SignalFrame", "Signal view:")) - self.spinBoxBitsPerSymbol.setToolTip(_translate("SignalFrame", "

Higher order modulations can carry multiple bits with each symbol. Configure how many bits are represented by a symbol. (Default = Binary modulation with one bit per symbol)

")) + self.spinBoxBitsPerSymbol.setToolTip( + _translate( + "SignalFrame", + '

Higher order modulations can carry multiple bits with each symbol. Configure how many bits are represented by a symbol. (Default = Binary modulation with one bit per symbol)

', + ) + ) self.btnSaveSignal.setText(_translate("SignalFrame", "...")) self.btnCloseSignal.setText(_translate("SignalFrame", "X")) self.lSignalTyp.setText(_translate("SignalFrame", "")) @@ -579,68 +680,183 @@ def retranslateUi(self, SignalFrame): self.cbProtoView.setItemText(0, _translate("SignalFrame", "Bits")) self.cbProtoView.setItemText(1, _translate("SignalFrame", "Hex")) self.cbProtoView.setItemText(2, _translate("SignalFrame", "ASCII")) - self.lCenterSpacing.setToolTip(_translate("SignalFrame", "

For higher order modulations (> 1 Bits/Symbol), there are multiple centers. We assume that the spacing between all possible symbols is constant. Therefore you configure the spacing between centers.

")) + self.lCenterSpacing.setToolTip( + _translate( + "SignalFrame", + '

For higher order modulations (> 1 Bits/Symbol), there are multiple centers. We assume that the spacing between all possible symbols is constant. Therefore you configure the spacing between centers.

', + ) + ) self.lCenterSpacing.setText(_translate("SignalFrame", "Center spacing:")) - self.spinBoxTolerance.setToolTip(_translate("SignalFrame", "

This is the error tolerance for determining the pulse lengths in the demodulated signal.

Example: Say, we are reading a ones pulse and the tolerance value was set to 5. Then 5 errors (which must follow sequentially) are accepted.

Tune this value if you have spiky data after demodulation.

")) - self.lSamplesPerSymbol.setToolTip(_translate("SignalFrame", "

This is the length of one symbol in samples. For binary modulations (default) this is the bit length.

")) + self.spinBoxTolerance.setToolTip( + _translate( + "SignalFrame", + '

This is the error tolerance for determining the pulse lengths in the demodulated signal.

Example: Say, we are reading a ones pulse and the tolerance value was set to 5. Then 5 errors (which must follow sequentially) are accepted.

Tune this value if you have spiky data after demodulation.

', + ) + ) + self.lSamplesPerSymbol.setToolTip( + _translate( + "SignalFrame", + '

This is the length of one symbol in samples. For binary modulations (default) this is the bit length.

', + ) + ) self.lSamplesPerSymbol.setText(_translate("SignalFrame", "Samples/Symbol:")) - self.lErrorTolerance.setToolTip(_translate("SignalFrame", "

This is the error tolerance for determining the pulse lengths in the demodulated signal.

Example: Say, we are reading a ones pulse and the tolerance value was set to 5. Then 5 errors (which must follow sequentially) are accepted.

Tune this value if you have spiky data after demodulation.

")) + self.lErrorTolerance.setToolTip( + _translate( + "SignalFrame", + '

This is the error tolerance for determining the pulse lengths in the demodulated signal.

Example: Say, we are reading a ones pulse and the tolerance value was set to 5. Then 5 errors (which must follow sequentially) are accepted.

Tune this value if you have spiky data after demodulation.

', + ) + ) self.lErrorTolerance.setText(_translate("SignalFrame", "Error tolerance:")) - self.lCenterOffset.setToolTip(_translate("SignalFrame", "

This is the threshold used for determining if a bit is one or zero. You can set it here or grab the middle of the area in Quadrature Demod View.

")) + self.lCenterOffset.setToolTip( + _translate( + "SignalFrame", + '

This is the threshold used for determining if a bit is one or zero. You can set it here or grab the middle of the area in Quadrature Demod View.

', + ) + ) self.lCenterOffset.setText(_translate("SignalFrame", "Center:")) - self.labelModulation.setToolTip(_translate("SignalFrame", "

Choose signals modulation:

  • Amplitude Shift Keying (ASK)
  • Frequency Shift Keying (FSK)
  • Phase Shift Keying (PSK)
")) + self.labelModulation.setToolTip( + _translate( + "SignalFrame", + "

Choose signals modulation:

  • Amplitude Shift Keying (ASK)
  • Frequency Shift Keying (FSK)
  • Phase Shift Keying (PSK)
", + ) + ) self.labelModulation.setText(_translate("SignalFrame", "Modulation:")) - self.cbSignalView.setToolTip(_translate("SignalFrame", "

Choose the view of your signal. Analog, Demodulated, Spectrogram or I/Q view.

The quadrature demodulation uses a threshold of magnitudes, to suppress noise. All samples with a magnitude lower than this threshold will be eliminated after demodulation.

Tune this value by selecting a noisy area and mark it as noise using context menu.

Signal colors:
I => blue
Q => black

")) + self.cbSignalView.setToolTip( + _translate( + "SignalFrame", + '

Choose the view of your signal. Analog, Demodulated, Spectrogram or I/Q view.

The quadrature demodulation uses a threshold of magnitudes, to suppress noise. All samples with a magnitude lower than this threshold will be eliminated after demodulation.

Tune this value by selecting a noisy area and mark it as noise using context menu.

Signal colors:
I => blue
Q => black

', + ) + ) self.cbSignalView.setItemText(0, _translate("SignalFrame", "Analog")) self.cbSignalView.setItemText(1, _translate("SignalFrame", "Demodulated")) self.cbSignalView.setItemText(2, _translate("SignalFrame", "Spectrogram")) self.cbSignalView.setItemText(3, _translate("SignalFrame", "I/Q view")) - self.spinBoxNoiseTreshold.setToolTip(_translate("SignalFrame", "

Set the noise magnitude of your signal. You can tune this value to mute noise in your signal and reveal the true data.

")) - self.spinBoxCenterSpacing.setToolTip(_translate("SignalFrame", "

For higher order modulations (> 1 Bits/Symbol), there are multiple centers. We assume that the spacing between all possible symbols is constant. Therefore you configure the spacing between centers.

")) + self.spinBoxNoiseTreshold.setToolTip( + _translate( + "SignalFrame", + '

Set the noise magnitude of your signal. You can tune this value to mute noise in your signal and reveal the true data.

', + ) + ) + self.spinBoxCenterSpacing.setToolTip( + _translate( + "SignalFrame", + '

For higher order modulations (> 1 Bits/Symbol), there are multiple centers. We assume that the spacing between all possible symbols is constant. Therefore you configure the spacing between centers.

', + ) + ) self.lineEditSignalName.setText(_translate("SignalFrame", "SignalName")) - self.cbModulationType.setToolTip(_translate("SignalFrame", "

Choose signals modulation:

  • Amplitude Shift Keying (ASK)
  • Frequency Shift Keying (FSK)
  • Phase Shift Keying (PSK)
")) + self.cbModulationType.setToolTip( + _translate( + "SignalFrame", + "

Choose signals modulation:

  • Amplitude Shift Keying (ASK)
  • Frequency Shift Keying (FSK)
  • Phase Shift Keying (PSK)
", + ) + ) self.cbModulationType.setItemText(0, _translate("SignalFrame", "ASK")) self.cbModulationType.setItemText(1, _translate("SignalFrame", "FSK")) self.cbModulationType.setItemText(2, _translate("SignalFrame", "PSK")) self.btnAdvancedModulationSettings.setText(_translate("SignalFrame", "...")) - self.chkBoxSyncSelection.setToolTip(_translate("SignalFrame", "If this is set to true, your selected protocol bits will show up in the signal view, and vice versa.")) + self.chkBoxSyncSelection.setToolTip( + _translate( + "SignalFrame", + "If this is set to true, your selected protocol bits will show up in the signal view, and vice versa.", + ) + ) self.chkBoxSyncSelection.setText(_translate("SignalFrame", "Sync selection")) - self.labelSpectrogramMin.setText(_translate("SignalFrame", "Datamin:")) - self.labelSpectrogramMax.setText(_translate("SignalFrame", "Datamax:")) - self.chkBoxShowProtocol.setToolTip(_translate("SignalFrame", "Show the extracted protocol based on the parameters InfoLen, PauseLen and ZeroTreshold (in QuadratureDemod-View).\n" -"\n" -"If you want your protocol to be better separated, edit the PauseLen using right-click menu from a selection in SignalView or ProtocolView.")) + self.labelSpectrogramMin.setText( + _translate("SignalFrame", "Datamin:") + ) + self.labelSpectrogramMax.setText( + _translate("SignalFrame", "Datamax:") + ) + self.chkBoxShowProtocol.setToolTip( + _translate( + "SignalFrame", + "Show the extracted protocol based on the parameters InfoLen, PauseLen and ZeroTreshold (in QuadratureDemod-View).\n" + "\n" + "If you want your protocol to be better separated, edit the PauseLen using right-click menu from a selection in SignalView or ProtocolView.", + ) + ) self.chkBoxShowProtocol.setText(_translate("SignalFrame", "Show data as")) - self.spinBoxSamplesPerSymbol.setToolTip(_translate("SignalFrame", "

This is the length of one symbol in samples. For binary modulations (default) this is the bit length.

")) - self.btnAutoDetect.setToolTip(_translate("SignalFrame", "

Automatically detect center, bit length and tolerance. You can also choose to additionally detect the noise and modulation when clicking this button.

")) + self.spinBoxSamplesPerSymbol.setToolTip( + _translate( + "SignalFrame", + '

This is the length of one symbol in samples. For binary modulations (default) this is the bit length.

', + ) + ) + self.btnAutoDetect.setToolTip( + _translate( + "SignalFrame", + '

Automatically detect center, bit length and tolerance. You can also choose to additionally detect the noise and modulation when clicking this button.

', + ) + ) self.btnAutoDetect.setText(_translate("SignalFrame", "Autodetect parameters")) self.labelFFTWindowSize.setText(_translate("SignalFrame", "FFT window size:")) - self.spinBoxCenterOffset.setToolTip(_translate("SignalFrame", "

This is the threshold used for determining if a bit is one or zero. You can set it here or grab the middle of the area in Quadrature Demod View.

")) - self.labelNoise.setToolTip(_translate("SignalFrame", "

Set the noise magnitude of your signal. You can tune this value to mute noise in your signal and reveal the true data.

")) + self.spinBoxCenterOffset.setToolTip( + _translate( + "SignalFrame", + '

This is the threshold used for determining if a bit is one or zero. You can set it here or grab the middle of the area in Quadrature Demod View.

', + ) + ) + self.labelNoise.setToolTip( + _translate( + "SignalFrame", + '

Set the noise magnitude of your signal. You can tune this value to mute noise in your signal and reveal the true data.

', + ) + ) self.labelNoise.setText(_translate("SignalFrame", "Noise:")) - self.lBitsPerSymbol.setToolTip(_translate("SignalFrame", "

Higher order modulations can carry multiple bits with each symbol. Configure how many bits are represented by a symbol. (Default = Binary modulation with one bit per symbol)

")) + self.lBitsPerSymbol.setToolTip( + _translate( + "SignalFrame", + '

Higher order modulations can carry multiple bits with each symbol. Configure how many bits are represented by a symbol. (Default = Binary modulation with one bit per symbol)

', + ) + ) self.lBitsPerSymbol.setText(_translate("SignalFrame", "Bits/Symbol:")) - self.labelLoadingAutoInterpretation.setText(_translate("SignalFrame", "

Running automatic detecting of demodulation parameters.

You can disable this behaviour for newly loaded signals by unchecking Edit -> Auto detect signals on loading.

")) + self.labelLoadingAutoInterpretation.setText( + _translate( + "SignalFrame", + '

Running automatic detecting of demodulation parameters.

You can disable this behaviour for newly loaded signals by unchecking Edit -> Auto detect signals on loading.

', + ) + ) self.lYScale.setText(_translate("SignalFrame", "Y-Scale")) self.btnShowHideStartEnd.setText(_translate("SignalFrame", "-")) - self.lNumSelectedSamples.setToolTip(_translate("SignalFrame", "Number of currently selected samples.")) + self.lNumSelectedSamples.setToolTip( + _translate("SignalFrame", "Number of currently selected samples.") + ) self.lNumSelectedSamples.setText(_translate("SignalFrame", "0")) - self.lTextSelectedSamples.setToolTip(_translate("SignalFrame", "Number of currently selected samples.")) + self.lTextSelectedSamples.setToolTip( + _translate("SignalFrame", "Number of currently selected samples.") + ) self.lTextSelectedSamples.setText(_translate("SignalFrame", "selected")) self.lDuration.setText(_translate("SignalFrame", "42 µs")) - self.labelRSSI.setToolTip(_translate("SignalFrame", "

This is the average signal power of the selection. The closer this value is to zero, the stronger the selected signal is.

")) + self.labelRSSI.setToolTip( + _translate( + "SignalFrame", + "

This is the average signal power of the selection. The closer this value is to zero, the stronger the selected signal is.

", + ) + ) self.labelRSSI.setText(_translate("SignalFrame", "0,434 dBm")) self.btnFilter.setText(_translate("SignalFrame", "Filter (moving average)")) self.lStart.setText(_translate("SignalFrame", "Start:")) self.lEnd.setText(_translate("SignalFrame", "End:")) - self.lZoomText.setToolTip(_translate("SignalFrame", "

Current (relative) Zoom. Standard is 100%, if you zoom in, this factor increases. You can directly set a value in the spinbox or use the mousewheel to zoom.

")) + self.lZoomText.setToolTip( + _translate( + "SignalFrame", + '

Current (relative) Zoom. Standard is 100%, if you zoom in, this factor increases. You can directly set a value in the spinbox or use the mousewheel to zoom.

', + ) + ) self.lZoomText.setText(_translate("SignalFrame", "X-Zoom:")) - self.spinBoxXZoom.setToolTip(_translate("SignalFrame", "

Current (relative) Zoom. Standard is 100%, if you zoom in, this factor increases. You can directly set a value in the spinbox or use the mousewheel to zoom.

")) + self.spinBoxXZoom.setToolTip( + _translate( + "SignalFrame", + '

Current (relative) Zoom. Standard is 100%, if you zoom in, this factor increases. You can directly set a value in the spinbox or use the mousewheel to zoom.

', + ) + ) self.spinBoxXZoom.setSuffix(_translate("SignalFrame", "%")) self.lSamplesInView.setText(_translate("SignalFrame", "0")) self.lStrich.setText(_translate("SignalFrame", "/")) self.lSamplesTotal.setText(_translate("SignalFrame", "0")) self.lSamplesViewText.setText(_translate("SignalFrame", "Samples in view")) + + from urh.ui.views.EpicGraphicView import EpicGraphicView from urh.ui.views.SpectrogramGraphicView import SpectrogramGraphicView from urh.ui.views.TextEditProtocolView import TextEditProtocolView diff --git a/src/urh/ui/ui_simulator.py b/src/urh/ui/ui_simulator.py index 8159c3953b..7c7c69f998 100644 --- a/src/urh/ui/ui_simulator.py +++ b/src/urh/ui/ui_simulator.py @@ -26,14 +26,16 @@ def setupUi(self, SimulatorTab): self.verticalLayout_5 = QtWidgets.QVBoxLayout(self.scrollAreaWidgetContents) self.verticalLayout_5.setObjectName("verticalLayout_5") self.splitterLeftRight = QtWidgets.QSplitter(self.scrollAreaWidgetContents) - self.splitterLeftRight.setStyleSheet("QSplitter::handle:horizontal {\n" -"margin: 4px 0px;\n" -" background-color: qlineargradient(x1:0, y1:0, x2:0, y2:1, \n" -"stop:0 rgba(255, 255, 255, 0), \n" -"stop:0.5 rgba(100, 100, 100, 100), \n" -"stop:1 rgba(255, 255, 255, 0));\n" -"image: url(:/icons/icons/splitter_handle_vertical.svg);\n" -"}") + self.splitterLeftRight.setStyleSheet( + "QSplitter::handle:horizontal {\n" + "margin: 4px 0px;\n" + " background-color: qlineargradient(x1:0, y1:0, x2:0, y2:1, \n" + "stop:0 rgba(255, 255, 255, 0), \n" + "stop:0.5 rgba(100, 100, 100, 100), \n" + "stop:1 rgba(255, 255, 255, 0));\n" + "image: url(:/icons/icons/splitter_handle_vertical.svg);\n" + "}" + ) self.splitterLeftRight.setOrientation(QtCore.Qt.Horizontal) self.splitterLeftRight.setHandleWidth(6) self.splitterLeftRight.setObjectName("splitterLeftRight") @@ -61,10 +63,14 @@ def setupUi(self, SimulatorTab): self.label_4.setObjectName("label_4") self.gridLayout.addWidget(self.label_4, 0, 0, 1, 1) self.spinBoxNRepeat = QtWidgets.QSpinBox(self.layoutWidget) - sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Expanding, QtWidgets.QSizePolicy.Fixed) + sizePolicy = QtWidgets.QSizePolicy( + QtWidgets.QSizePolicy.Expanding, QtWidgets.QSizePolicy.Fixed + ) sizePolicy.setHorizontalStretch(0) sizePolicy.setVerticalStretch(0) - sizePolicy.setHeightForWidth(self.spinBoxNRepeat.sizePolicy().hasHeightForWidth()) + sizePolicy.setHeightForWidth( + self.spinBoxNRepeat.sizePolicy().hasHeightForWidth() + ) self.spinBoxNRepeat.setSizePolicy(sizePolicy) self.spinBoxNRepeat.setMaximum(9999999) self.spinBoxNRepeat.setObjectName("spinBoxNRepeat") @@ -73,10 +79,14 @@ def setupUi(self, SimulatorTab): self.label_3.setObjectName("label_3") self.gridLayout.addWidget(self.label_3, 1, 0, 1, 1) self.spinBoxTimeout = QtWidgets.QSpinBox(self.layoutWidget) - sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Expanding, QtWidgets.QSizePolicy.Fixed) + sizePolicy = QtWidgets.QSizePolicy( + QtWidgets.QSizePolicy.Expanding, QtWidgets.QSizePolicy.Fixed + ) sizePolicy.setHorizontalStretch(0) sizePolicy.setVerticalStretch(0) - sizePolicy.setHeightForWidth(self.spinBoxTimeout.sizePolicy().hasHeightForWidth()) + sizePolicy.setHeightForWidth( + self.spinBoxTimeout.sizePolicy().hasHeightForWidth() + ) self.spinBoxTimeout.setSizePolicy(sizePolicy) self.spinBoxTimeout.setMinimum(1) self.spinBoxTimeout.setMaximum(9999999) @@ -86,10 +96,14 @@ def setupUi(self, SimulatorTab): self.label_7.setObjectName("label_7") self.gridLayout.addWidget(self.label_7, 2, 0, 1, 1) self.comboBoxError = QtWidgets.QComboBox(self.layoutWidget) - sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Expanding, QtWidgets.QSizePolicy.Fixed) + sizePolicy = QtWidgets.QSizePolicy( + QtWidgets.QSizePolicy.Expanding, QtWidgets.QSizePolicy.Fixed + ) sizePolicy.setHorizontalStretch(0) sizePolicy.setVerticalStretch(0) - sizePolicy.setHeightForWidth(self.comboBoxError.sizePolicy().hasHeightForWidth()) + sizePolicy.setHeightForWidth( + self.comboBoxError.sizePolicy().hasHeightForWidth() + ) self.comboBoxError.setSizePolicy(sizePolicy) self.comboBoxError.setObjectName("comboBoxError") self.comboBoxError.addItem("") @@ -112,14 +126,16 @@ def setupUi(self, SimulatorTab): self.btnStartSim.setObjectName("btnStartSim") self.verticalLayout_3.addWidget(self.btnStartSim) self.splitter = QtWidgets.QSplitter(self.splitterLeftRight) - self.splitter.setStyleSheet("QSplitter::handle:vertical {\n" -"margin: 4px 0px;\n" -" background-color: qlineargradient(x1:0, y1:0, x2:1, y2:0, \n" -"stop:0 rgba(255, 255, 255, 0), \n" -"stop:0.5 rgba(100, 100, 100, 100), \n" -"stop:1 rgba(255, 255, 255, 0));\n" -"image: url(:/icons/icons/splitter_handle_horizontal.svg);\n" -"}") + self.splitter.setStyleSheet( + "QSplitter::handle:vertical {\n" + "margin: 4px 0px;\n" + " background-color: qlineargradient(x1:0, y1:0, x2:1, y2:0, \n" + "stop:0 rgba(255, 255, 255, 0), \n" + "stop:0.5 rgba(100, 100, 100, 100), \n" + "stop:1 rgba(255, 255, 255, 0));\n" + "image: url(:/icons/icons/splitter_handle_horizontal.svg);\n" + "}" + ) self.splitter.setOrientation(QtCore.Qt.Vertical) self.splitter.setHandleWidth(6) self.splitter.setObjectName("splitter") @@ -129,7 +145,9 @@ def setupUi(self, SimulatorTab): self.verticalLayout_2.setContentsMargins(11, 11, 11, 11) self.verticalLayout_2.setObjectName("verticalLayout_2") self.tabWidget = QtWidgets.QTabWidget(self.layoutWidget_2) - sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Expanding, QtWidgets.QSizePolicy.Expanding) + sizePolicy = QtWidgets.QSizePolicy( + QtWidgets.QSizePolicy.Expanding, QtWidgets.QSizePolicy.Expanding + ) sizePolicy.setHorizontalStretch(0) sizePolicy.setVerticalStretch(0) sizePolicy.setHeightForWidth(self.tabWidget.sizePolicy().hasHeightForWidth()) @@ -145,7 +163,9 @@ def setupUi(self, SimulatorTab): self.verticalLayout.setSpacing(7) self.verticalLayout.setObjectName("verticalLayout") self.gvSimulator = SimulatorGraphicsView(self.tab) - sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Preferred, QtWidgets.QSizePolicy.Expanding) + sizePolicy = QtWidgets.QSizePolicy( + QtWidgets.QSizePolicy.Preferred, QtWidgets.QSizePolicy.Expanding + ) sizePolicy.setHorizontalStretch(0) sizePolicy.setVerticalStretch(0) sizePolicy.setHeightForWidth(self.gvSimulator.sizePolicy().hasHeightForWidth()) @@ -159,14 +179,22 @@ def setupUi(self, SimulatorTab): self.verticalLayout_6.setContentsMargins(0, 0, 0, 0) self.verticalLayout_6.setObjectName("verticalLayout_6") self.tblViewMessage = SimulatorMessageTableView(self.tab_2) - sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Preferred, QtWidgets.QSizePolicy.Expanding) + sizePolicy = QtWidgets.QSizePolicy( + QtWidgets.QSizePolicy.Preferred, QtWidgets.QSizePolicy.Expanding + ) sizePolicy.setHorizontalStretch(0) sizePolicy.setVerticalStretch(0) - sizePolicy.setHeightForWidth(self.tblViewMessage.sizePolicy().hasHeightForWidth()) + sizePolicy.setHeightForWidth( + self.tblViewMessage.sizePolicy().hasHeightForWidth() + ) self.tblViewMessage.setSizePolicy(sizePolicy) self.tblViewMessage.setAlternatingRowColors(True) - self.tblViewMessage.setVerticalScrollMode(QtWidgets.QAbstractItemView.ScrollPerPixel) - self.tblViewMessage.setHorizontalScrollMode(QtWidgets.QAbstractItemView.ScrollPerPixel) + self.tblViewMessage.setVerticalScrollMode( + QtWidgets.QAbstractItemView.ScrollPerPixel + ) + self.tblViewMessage.setHorizontalScrollMode( + QtWidgets.QAbstractItemView.ScrollPerPixel + ) self.tblViewMessage.setShowGrid(False) self.tblViewMessage.setObjectName("tblViewMessage") self.tblViewMessage.horizontalHeader().setHighlightSections(False) @@ -175,13 +203,17 @@ def setupUi(self, SimulatorTab): self.horizontalLayout_3 = QtWidgets.QHBoxLayout() self.horizontalLayout_3.setObjectName("horizontalLayout_3") self.lNumSelectedColumns = QtWidgets.QLabel(self.tab_2) - self.lNumSelectedColumns.setAlignment(QtCore.Qt.AlignLeading|QtCore.Qt.AlignLeft|QtCore.Qt.AlignVCenter) + self.lNumSelectedColumns.setAlignment( + QtCore.Qt.AlignLeading | QtCore.Qt.AlignLeft | QtCore.Qt.AlignVCenter + ) self.lNumSelectedColumns.setObjectName("lNumSelectedColumns") self.horizontalLayout_3.addWidget(self.lNumSelectedColumns) self.lColumnsSelectedText = QtWidgets.QLabel(self.tab_2) self.lColumnsSelectedText.setObjectName("lColumnsSelectedText") self.horizontalLayout_3.addWidget(self.lColumnsSelectedText) - spacerItem = QtWidgets.QSpacerItem(138, 33, QtWidgets.QSizePolicy.Expanding, QtWidgets.QSizePolicy.Minimum) + spacerItem = QtWidgets.QSpacerItem( + 138, 33, QtWidgets.QSizePolicy.Expanding, QtWidgets.QSizePolicy.Minimum + ) self.horizontalLayout_3.addItem(spacerItem) self.label_5 = QtWidgets.QLabel(self.tab_2) self.label_5.setObjectName("label_5") @@ -224,7 +256,9 @@ def setupUi(self, SimulatorTab): self.btnDown.setIcon(icon) self.btnDown.setObjectName("btnDown") self.verticalLayout_9.addWidget(self.btnDown) - spacerItem1 = QtWidgets.QSpacerItem(20, 40, QtWidgets.QSizePolicy.Minimum, QtWidgets.QSizePolicy.Expanding) + spacerItem1 = QtWidgets.QSpacerItem( + 20, 40, QtWidgets.QSizePolicy.Minimum, QtWidgets.QSizePolicy.Expanding + ) self.verticalLayout_9.addItem(spacerItem1) self.horizontalLayout.addLayout(self.verticalLayout_9) self.tabWidget.addTab(self.tabParticipants, "") @@ -235,10 +269,14 @@ def setupUi(self, SimulatorTab): self.verticalLayout_4.setContentsMargins(11, 11, 11, 11) self.verticalLayout_4.setObjectName("verticalLayout_4") self.lblMsgFieldsValues = QtWidgets.QLabel(self.layoutWidget_3) - sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Preferred, QtWidgets.QSizePolicy.Fixed) + sizePolicy = QtWidgets.QSizePolicy( + QtWidgets.QSizePolicy.Preferred, QtWidgets.QSizePolicy.Fixed + ) sizePolicy.setHorizontalStretch(0) sizePolicy.setVerticalStretch(0) - sizePolicy.setHeightForWidth(self.lblMsgFieldsValues.sizePolicy().hasHeightForWidth()) + sizePolicy.setHeightForWidth( + self.lblMsgFieldsValues.sizePolicy().hasHeightForWidth() + ) self.lblMsgFieldsValues.setSizePolicy(sizePolicy) font = QtGui.QFont() font.setBold(True) @@ -262,9 +300,13 @@ def setupUi(self, SimulatorTab): self.goto_combobox = QtWidgets.QComboBox(self.page_goto_action) self.goto_combobox.setObjectName("goto_combobox") self.verticalLayout_7.addWidget(self.goto_combobox, 0, 1, 1, 1) - spacerItem2 = QtWidgets.QSpacerItem(40, 20, QtWidgets.QSizePolicy.Expanding, QtWidgets.QSizePolicy.Minimum) + spacerItem2 = QtWidgets.QSpacerItem( + 40, 20, QtWidgets.QSizePolicy.Expanding, QtWidgets.QSizePolicy.Minimum + ) self.verticalLayout_7.addItem(spacerItem2, 0, 2, 1, 1) - spacerItem3 = QtWidgets.QSpacerItem(20, 40, QtWidgets.QSizePolicy.Minimum, QtWidgets.QSizePolicy.Expanding) + spacerItem3 = QtWidgets.QSpacerItem( + 20, 40, QtWidgets.QSizePolicy.Minimum, QtWidgets.QSizePolicy.Expanding + ) self.verticalLayout_7.addItem(spacerItem3, 1, 0, 1, 3) self.detail_view_widget.addWidget(self.page_goto_action) self.page_message = QtWidgets.QWidget() @@ -272,7 +314,9 @@ def setupUi(self, SimulatorTab): self.gridLayout_6 = QtWidgets.QGridLayout(self.page_message) self.gridLayout_6.setObjectName("gridLayout_6") self.label_10 = QtWidgets.QLabel(self.page_message) - sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Preferred, QtWidgets.QSizePolicy.Preferred) + sizePolicy = QtWidgets.QSizePolicy( + QtWidgets.QSizePolicy.Preferred, QtWidgets.QSizePolicy.Preferred + ) sizePolicy.setHorizontalStretch(0) sizePolicy.setVerticalStretch(0) sizePolicy.setHeightForWidth(self.label_10.sizePolicy().hasHeightForWidth()) @@ -288,12 +332,16 @@ def setupUi(self, SimulatorTab): self.tblViewFieldValues.verticalHeader().setVisible(False) self.gridLayout_6.addWidget(self.tblViewFieldValues, 2, 2, 1, 1) self.label_11 = QtWidgets.QLabel(self.page_message) - sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Preferred, QtWidgets.QSizePolicy.Preferred) + sizePolicy = QtWidgets.QSizePolicy( + QtWidgets.QSizePolicy.Preferred, QtWidgets.QSizePolicy.Preferred + ) sizePolicy.setHorizontalStretch(0) sizePolicy.setVerticalStretch(0) sizePolicy.setHeightForWidth(self.label_11.sizePolicy().hasHeightForWidth()) self.label_11.setSizePolicy(sizePolicy) - self.label_11.setAlignment(QtCore.Qt.AlignLeading|QtCore.Qt.AlignLeft|QtCore.Qt.AlignTop) + self.label_11.setAlignment( + QtCore.Qt.AlignLeading | QtCore.Qt.AlignLeft | QtCore.Qt.AlignTop + ) self.label_11.setObjectName("label_11") self.gridLayout_6.addWidget(self.label_11, 2, 0, 1, 1) self.spinBoxRepeat = QtWidgets.QSpinBox(self.page_message) @@ -314,7 +362,9 @@ def setupUi(self, SimulatorTab): self.label_12 = QtWidgets.QLabel(self.page_rule) self.label_12.setObjectName("label_12") self.gridLayout_3.addWidget(self.label_12, 0, 0, 1, 1) - spacerItem4 = QtWidgets.QSpacerItem(20, 40, QtWidgets.QSizePolicy.Minimum, QtWidgets.QSizePolicy.Expanding) + spacerItem4 = QtWidgets.QSpacerItem( + 20, 40, QtWidgets.QSizePolicy.Minimum, QtWidgets.QSizePolicy.Expanding + ) self.gridLayout_3.addItem(spacerItem4, 1, 0, 1, 2) self.ruleCondLineEdit = ExpressionLineEdit(self.page_rule) self.ruleCondLineEdit.setObjectName("ruleCondLineEdit") @@ -324,7 +374,9 @@ def setupUi(self, SimulatorTab): self.page_ext_prog_action.setObjectName("page_ext_prog_action") self.gridLayout_9 = QtWidgets.QGridLayout(self.page_ext_prog_action) self.gridLayout_9.setObjectName("gridLayout_9") - self.checkBoxPassTranscriptSTDIN = QtWidgets.QCheckBox(self.page_ext_prog_action) + self.checkBoxPassTranscriptSTDIN = QtWidgets.QCheckBox( + self.page_ext_prog_action + ) self.checkBoxPassTranscriptSTDIN.setObjectName("checkBoxPassTranscriptSTDIN") self.gridLayout_9.addWidget(self.checkBoxPassTranscriptSTDIN, 2, 0, 1, 4) self.label_14 = QtWidgets.QLabel(self.page_ext_prog_action) @@ -337,7 +389,9 @@ def setupUi(self, SimulatorTab): self.btnChooseCommand = QtWidgets.QToolButton(self.page_ext_prog_action) self.btnChooseCommand.setObjectName("btnChooseCommand") self.gridLayout_9.addWidget(self.btnChooseCommand, 1, 2, 1, 2) - spacerItem5 = QtWidgets.QSpacerItem(20, 40, QtWidgets.QSizePolicy.Minimum, QtWidgets.QSizePolicy.Expanding) + spacerItem5 = QtWidgets.QSpacerItem( + 20, 40, QtWidgets.QSizePolicy.Minimum, QtWidgets.QSizePolicy.Expanding + ) self.gridLayout_9.addItem(spacerItem5, 4, 0, 1, 4) self.label_18 = QtWidgets.QLabel(self.page_ext_prog_action) self.label_18.setWordWrap(True) @@ -360,7 +414,9 @@ def setupUi(self, SimulatorTab): self.doubleSpinBoxSleep.setObjectName("doubleSpinBoxSleep") self.horizontalLayout_2.addWidget(self.doubleSpinBoxSleep) self.verticalLayout_10.addLayout(self.horizontalLayout_2) - spacerItem6 = QtWidgets.QSpacerItem(20, 231, QtWidgets.QSizePolicy.Minimum, QtWidgets.QSizePolicy.Expanding) + spacerItem6 = QtWidgets.QSpacerItem( + 20, 231, QtWidgets.QSizePolicy.Minimum, QtWidgets.QSizePolicy.Expanding + ) self.verticalLayout_10.addItem(spacerItem6) self.detail_view_widget.addWidget(self.page_sleep) self.page = QtWidgets.QWidget() @@ -389,7 +445,9 @@ def setupUi(self, SimulatorTab): self.label_17.setWordWrap(True) self.label_17.setObjectName("label_17") self.verticalLayout_11.addWidget(self.label_17) - spacerItem7 = QtWidgets.QSpacerItem(20, 36, QtWidgets.QSizePolicy.Minimum, QtWidgets.QSizePolicy.Expanding) + spacerItem7 = QtWidgets.QSpacerItem( + 20, 36, QtWidgets.QSizePolicy.Minimum, QtWidgets.QSizePolicy.Expanding + ) self.verticalLayout_11.addItem(spacerItem7) self.detail_view_widget.addWidget(self.page) self.verticalLayout_4.addWidget(self.detail_view_widget) @@ -404,53 +462,101 @@ def setupUi(self, SimulatorTab): def retranslateUi(self, SimulatorTab): _translate = QtCore.QCoreApplication.translate SimulatorTab.setWindowTitle(_translate("SimulatorTab", "Form")) - self.label.setText(_translate("SimulatorTab", "Protocols (Drag&Drop to Flow Graph):")) + self.label.setText( + _translate("SimulatorTab", "Protocols (Drag&Drop to Flow Graph):") + ) self.label_6.setText(_translate("SimulatorTab", "Simulate these participants:")) - self.label_4.setText(_translate("SimulatorTab", "Repeat simulation this often:")) + self.label_4.setText( + _translate("SimulatorTab", "Repeat simulation this often:") + ) self.spinBoxNRepeat.setSpecialValueText(_translate("SimulatorTab", "Infinite")) self.label_3.setText(_translate("SimulatorTab", "Timeout:")) self.spinBoxTimeout.setSuffix(_translate("SimulatorTab", "ms")) - self.label_7.setText(_translate("SimulatorTab", "In case of an overdue response:")) - self.comboBoxError.setItemText(0, _translate("SimulatorTab", "Resend last message")) + self.label_7.setText( + _translate("SimulatorTab", "In case of an overdue response:") + ) + self.comboBoxError.setItemText( + 0, _translate("SimulatorTab", "Resend last message") + ) self.comboBoxError.setItemText(1, _translate("SimulatorTab", "Stop simulation")) - self.comboBoxError.setItemText(2, _translate("SimulatorTab", "Restart simulation")) + self.comboBoxError.setItemText( + 2, _translate("SimulatorTab", "Restart simulation") + ) self.label_8.setText(_translate("SimulatorTab", "Maximum retries:")) self.btnStartSim.setText(_translate("SimulatorTab", "Simulate...")) - self.tabWidget.setTabText(self.tabWidget.indexOf(self.tab), _translate("SimulatorTab", "Flow Graph")) + self.tabWidget.setTabText( + self.tabWidget.indexOf(self.tab), _translate("SimulatorTab", "Flow Graph") + ) self.lNumSelectedColumns.setText(_translate("SimulatorTab", "0")) - self.lColumnsSelectedText.setText(_translate("SimulatorTab", "column(s) selected")) + self.lColumnsSelectedText.setText( + _translate("SimulatorTab", "column(s) selected") + ) self.label_5.setText(_translate("SimulatorTab", "Viewtype:")) self.cbViewType.setItemText(0, _translate("SimulatorTab", "Bit")) self.cbViewType.setItemText(1, _translate("SimulatorTab", "Hex")) self.cbViewType.setItemText(2, _translate("SimulatorTab", "ASCII")) - self.tabWidget.setTabText(self.tabWidget.indexOf(self.tab_2), _translate("SimulatorTab", "Messages")) + self.tabWidget.setTabText( + self.tabWidget.indexOf(self.tab_2), _translate("SimulatorTab", "Messages") + ) self.btnAddParticipant.setToolTip(_translate("SimulatorTab", "Add participant")) self.btnAddParticipant.setText(_translate("SimulatorTab", "Add")) - self.btnRemoveParticipant.setToolTip(_translate("SimulatorTab", "Remove participant")) + self.btnRemoveParticipant.setToolTip( + _translate("SimulatorTab", "Remove participant") + ) self.btnRemoveParticipant.setText(_translate("SimulatorTab", "Remove")) - self.btnUp.setToolTip(_translate("SimulatorTab", "Move selected participants up")) + self.btnUp.setToolTip( + _translate("SimulatorTab", "Move selected participants up") + ) self.btnUp.setText(_translate("SimulatorTab", "...")) - self.btnDown.setToolTip(_translate("SimulatorTab", "Move selected participants down")) + self.btnDown.setToolTip( + _translate("SimulatorTab", "Move selected participants down") + ) self.btnDown.setText(_translate("SimulatorTab", "...")) - self.tabWidget.setTabText(self.tabWidget.indexOf(self.tabParticipants), _translate("SimulatorTab", "Participants")) - self.lblMsgFieldsValues.setText(_translate("SimulatorTab", "Detail view for item")) + self.tabWidget.setTabText( + self.tabWidget.indexOf(self.tabParticipants), + _translate("SimulatorTab", "Participants"), + ) + self.lblMsgFieldsValues.setText( + _translate("SimulatorTab", "Detail view for item") + ) self.label_9.setText(_translate("SimulatorTab", "Goto:")) self.label_10.setText(_translate("SimulatorTab", "Copies:")) self.label_11.setText(_translate("SimulatorTab", "Labels:")) self.label_2.setText(_translate("SimulatorTab", "Coding:")) self.lblEncodingDecoding.setText(_translate("SimulatorTab", "-")) self.label_12.setText(_translate("SimulatorTab", "Condition:")) - self.ruleCondLineEdit.setPlaceholderText(_translate("SimulatorTab", "not (item1.crc == 0b1010 and item2.length >=3)")) - self.checkBoxPassTranscriptSTDIN.setText(_translate("SimulatorTab", "Pass transcript to STDIN")) + self.ruleCondLineEdit.setPlaceholderText( + _translate("SimulatorTab", "not (item1.crc == 0b1010 and item2.length >=3)") + ) + self.checkBoxPassTranscriptSTDIN.setText( + _translate("SimulatorTab", "Pass transcript to STDIN") + ) self.label_14.setText(_translate("SimulatorTab", "Command:")) - self.lineEditTriggerCommand.setPlaceholderText(_translate("SimulatorTab", "Path [+arguments] to external command e.g. mail or sendsms")) + self.lineEditTriggerCommand.setPlaceholderText( + _translate( + "SimulatorTab", + "Path [+arguments] to external command e.g. mail or sendsms", + ) + ) self.btnChooseCommand.setText(_translate("SimulatorTab", "...")) - self.label_18.setText(_translate("SimulatorTab", "

You can access the return code of this item in formulas and rules using the item identifier followed by .rc e.g. item5.rc.

")) + self.label_18.setText( + _translate( + "SimulatorTab", + '

You can access the return code of this item in formulas and rules using the item identifier followed by .rc e.g. item5.rc.

', + ) + ) self.label_13.setText(_translate("SimulatorTab", "Sleep for:")) self.doubleSpinBoxSleep.setSuffix(_translate("SimulatorTab", "s")) self.label_15.setText(_translate("SimulatorTab", "Start:")) self.label_16.setText(_translate("SimulatorTab", "Step:")) - self.label_17.setText(_translate("SimulatorTab", "

This counter will increase by step each time it gets hit during simulation. It will preserve it\'s value during simulation repeats and retries. To reset all counters stop the simulation and start it again.

Access the value of this counter using item<Number>.counter_value in Formulas or as parameter in external programs e.g. external_py -c item5.counter_value. The value of this counter will be inserted during simulation time.

")) + self.label_17.setText( + _translate( + "SimulatorTab", + '

This counter will increase by step each time it gets hit during simulation. It will preserve it\'s value during simulation repeats and retries. To reset all counters stop the simulation and start it again.

Access the value of this counter using item<Number>.counter_value in Formulas or as parameter in external programs e.g. external_py -c item5.counter_value. The value of this counter will be inserted during simulation time.

', + ) + ) + + from urh.ui.ExpressionLineEdit import ExpressionLineEdit from urh.ui.views.GeneratorTreeView import GeneratorTreeView from urh.ui.views.ParticipantTableView import ParticipantTableView diff --git a/src/urh/ui/ui_simulator_dialog.py b/src/urh/ui/ui_simulator_dialog.py index fa0124373e..0fb285826c 100644 --- a/src/urh/ui/ui_simulator_dialog.py +++ b/src/urh/ui/ui_simulator_dialog.py @@ -56,14 +56,22 @@ def setupUi(self, DialogSimulator): self.scrollAreaWidgetContentsRX.setObjectName("scrollAreaWidgetContentsRX") self.verticalLayout_6 = QtWidgets.QVBoxLayout(self.scrollAreaWidgetContentsRX) self.verticalLayout_6.setObjectName("verticalLayout_6") - self.btnTestSniffSettings = QtWidgets.QPushButton(self.scrollAreaWidgetContentsRX) + self.btnTestSniffSettings = QtWidgets.QPushButton( + self.scrollAreaWidgetContentsRX + ) icon = QtGui.QIcon() - icon.addPixmap(QtGui.QPixmap(":/icons/icons/sniffer.svg"), QtGui.QIcon.Normal, QtGui.QIcon.Off) + icon.addPixmap( + QtGui.QPixmap(":/icons/icons/sniffer.svg"), + QtGui.QIcon.Normal, + QtGui.QIcon.Off, + ) self.btnTestSniffSettings.setIcon(icon) self.btnTestSniffSettings.setAutoDefault(False) self.btnTestSniffSettings.setObjectName("btnTestSniffSettings") self.verticalLayout_6.addWidget(self.btnTestSniffSettings) - spacerItem = QtWidgets.QSpacerItem(20, 40, QtWidgets.QSizePolicy.Minimum, QtWidgets.QSizePolicy.Expanding) + spacerItem = QtWidgets.QSpacerItem( + 20, 40, QtWidgets.QSizePolicy.Minimum, QtWidgets.QSizePolicy.Expanding + ) self.verticalLayout_6.addItem(spacerItem) self.scrollAreaRX.setWidget(self.scrollAreaWidgetContentsRX) self.verticalLayout_5.addWidget(self.scrollAreaRX) @@ -82,7 +90,9 @@ def setupUi(self, DialogSimulator): self.scrollAreaWidgetContentsTX.setObjectName("scrollAreaWidgetContentsTX") self.verticalLayout_8 = QtWidgets.QVBoxLayout(self.scrollAreaWidgetContentsTX) self.verticalLayout_8.setObjectName("verticalLayout_8") - spacerItem1 = QtWidgets.QSpacerItem(20, 40, QtWidgets.QSizePolicy.Minimum, QtWidgets.QSizePolicy.Expanding) + spacerItem1 = QtWidgets.QSpacerItem( + 20, 40, QtWidgets.QSizePolicy.Minimum, QtWidgets.QSizePolicy.Expanding + ) self.verticalLayout_8.addItem(spacerItem1) self.scrollAreaTX.setWidget(self.scrollAreaWidgetContentsTX) self.verticalLayout_7.addWidget(self.scrollAreaTX) @@ -102,20 +112,22 @@ def setupUi(self, DialogSimulator): self.verticalLayout_15 = QtWidgets.QVBoxLayout(self.tab_simulation) self.verticalLayout_15.setObjectName("verticalLayout_15") self.groupBoxSimulationStatus = QtWidgets.QGroupBox(self.tab_simulation) - self.groupBoxSimulationStatus.setStyleSheet("QGroupBox\n" -"{\n" -"border: none;\n" -"}\n" -"\n" -"QGroupBox::title {\n" -" subcontrol-origin: margin;\n" -"}\n" -"QGroupBox::indicator:unchecked {\n" -" image: url(:/icons/icons/collapse.svg)\n" -"}\n" -"QGroupBox::indicator:checked {\n" -" image: url(:/icons/icons/uncollapse.svg)\n" -"}") + self.groupBoxSimulationStatus.setStyleSheet( + "QGroupBox\n" + "{\n" + "border: none;\n" + "}\n" + "\n" + "QGroupBox::title {\n" + " subcontrol-origin: margin;\n" + "}\n" + "QGroupBox::indicator:unchecked {\n" + " image: url(:/icons/icons/collapse.svg)\n" + "}\n" + "QGroupBox::indicator:checked {\n" + " image: url(:/icons/icons/uncollapse.svg)\n" + "}" + ) self.groupBoxSimulationStatus.setCheckable(True) self.groupBoxSimulationStatus.setObjectName("groupBoxSimulationStatus") self.verticalLayout_12 = QtWidgets.QVBoxLayout(self.groupBoxSimulationStatus) @@ -165,20 +177,22 @@ def setupUi(self, DialogSimulator): self.verticalLayout_12.addWidget(self.frame) self.verticalLayout_15.addWidget(self.groupBoxSimulationStatus) self.groupBoxRXStatus = QtWidgets.QGroupBox(self.tab_simulation) - self.groupBoxRXStatus.setStyleSheet("QGroupBox\n" -"{\n" -"border: none;\n" -"}\n" -"\n" -"QGroupBox::title {\n" -" subcontrol-origin: margin;\n" -"}\n" -"QGroupBox::indicator:unchecked {\n" -" image: url(:/icons/icons/collapse.svg)\n" -"}\n" -"QGroupBox::indicator:checked {\n" -" image: url(:/icons/icons/uncollapse.svg)\n" -"}") + self.groupBoxRXStatus.setStyleSheet( + "QGroupBox\n" + "{\n" + "border: none;\n" + "}\n" + "\n" + "QGroupBox::title {\n" + " subcontrol-origin: margin;\n" + "}\n" + "QGroupBox::indicator:unchecked {\n" + " image: url(:/icons/icons/collapse.svg)\n" + "}\n" + "QGroupBox::indicator:checked {\n" + " image: url(:/icons/icons/uncollapse.svg)\n" + "}" + ) self.groupBoxRXStatus.setCheckable(True) self.groupBoxRXStatus.setObjectName("groupBoxRXStatus") self.verticalLayout_14 = QtWidgets.QVBoxLayout(self.groupBoxRXStatus) @@ -196,7 +210,9 @@ def setupUi(self, DialogSimulator): self.checkBoxCaptureFullRX = QtWidgets.QCheckBox(self.frame_2) self.checkBoxCaptureFullRX.setObjectName("checkBoxCaptureFullRX") self.horizontalLayout_5.addWidget(self.checkBoxCaptureFullRX) - spacerItem2 = QtWidgets.QSpacerItem(40, 20, QtWidgets.QSizePolicy.Expanding, QtWidgets.QSizePolicy.Minimum) + spacerItem2 = QtWidgets.QSpacerItem( + 40, 20, QtWidgets.QSizePolicy.Expanding, QtWidgets.QSizePolicy.Minimum + ) self.horizontalLayout_5.addItem(spacerItem2) self.btnSaveRX = QtWidgets.QToolButton(self.frame_2) icon = QtGui.QIcon.fromTheme("document-save") @@ -227,7 +243,9 @@ def setupUi(self, DialogSimulator): self.radioButtonTranscriptHex = QtWidgets.QRadioButton(self.tab) self.radioButtonTranscriptHex.setObjectName("radioButtonTranscriptHex") self.horizontalLayout_3.addWidget(self.radioButtonTranscriptHex) - spacerItem3 = QtWidgets.QSpacerItem(40, 20, QtWidgets.QSizePolicy.Expanding, QtWidgets.QSizePolicy.Minimum) + spacerItem3 = QtWidgets.QSpacerItem( + 40, 20, QtWidgets.QSizePolicy.Expanding, QtWidgets.QSizePolicy.Minimum + ) self.horizontalLayout_3.addItem(spacerItem3) self.btnOpenInAnalysis = QtWidgets.QPushButton(self.tab) self.btnOpenInAnalysis.setObjectName("btnOpenInAnalysis") @@ -261,8 +279,8 @@ def setupUi(self, DialogSimulator): self.retranslateUi(DialogSimulator) self.tabWidgetSimulatorSettings.setCurrentIndex(3) self.tabWidget.setCurrentIndex(0) - self.groupBoxSimulationStatus.toggled['bool'].connect(self.frame.setVisible) - self.groupBoxRXStatus.toggled['bool'].connect(self.frame_2.setVisible) + self.groupBoxSimulationStatus.toggled["bool"].connect(self.frame.setVisible) + self.groupBoxRXStatus.toggled["bool"].connect(self.frame_2.setVisible) def retranslateUi(self, DialogSimulator): _translate = QtCore.QCoreApplication.translate @@ -270,31 +288,73 @@ def retranslateUi(self, DialogSimulator): self.btnLogAll.setText(_translate("DialogSimulator", "Log all")) self.btnLogNone.setText(_translate("DialogSimulator", "Log none")) self.btnToggleLog.setText(_translate("DialogSimulator", "Toggle selected")) - self.tabWidgetSimulatorSettings.setTabText(self.tabWidgetSimulatorSettings.indexOf(self.tabLog), _translate("DialogSimulator", "Log settings")) - self.btnTestSniffSettings.setText(_translate("DialogSimulator", "Test sniffer settings")) - self.tabWidgetSimulatorSettings.setTabText(self.tabWidgetSimulatorSettings.indexOf(self.tabRX), _translate("DialogSimulator", "RX settings")) - self.tabWidgetSimulatorSettings.setTabText(self.tabWidgetSimulatorSettings.indexOf(self.tabTX), _translate("DialogSimulator", "TX settings")) - self.groupBoxSimulationStatus.setTitle(_translate("DialogSimulator", "Simulation Status")) + self.tabWidgetSimulatorSettings.setTabText( + self.tabWidgetSimulatorSettings.indexOf(self.tabLog), + _translate("DialogSimulator", "Log settings"), + ) + self.btnTestSniffSettings.setText( + _translate("DialogSimulator", "Test sniffer settings") + ) + self.tabWidgetSimulatorSettings.setTabText( + self.tabWidgetSimulatorSettings.indexOf(self.tabRX), + _translate("DialogSimulator", "RX settings"), + ) + self.tabWidgetSimulatorSettings.setTabText( + self.tabWidgetSimulatorSettings.indexOf(self.tabTX), + _translate("DialogSimulator", "TX settings"), + ) + self.groupBoxSimulationStatus.setTitle( + _translate("DialogSimulator", "Simulation Status") + ) self.label.setText(_translate("DialogSimulator", "Current iteration:")) self.lblCurrentRepeatValue.setText(_translate("DialogSimulator", "0")) self.label_2.setText(_translate("DialogSimulator", "Current item:")) self.lblCurrentItemValue.setText(_translate("DialogSimulator", "0")) self.btnSaveLog.setText(_translate("DialogSimulator", "...")) self.groupBoxRXStatus.setTitle(_translate("DialogSimulator", "RX Status")) - self.checkBoxCaptureFullRX.setText(_translate("DialogSimulator", "Capture complete RX")) + self.checkBoxCaptureFullRX.setText( + _translate("DialogSimulator", "Capture complete RX") + ) self.btnSaveRX.setToolTip(_translate("DialogSimulator", "Save current capture")) self.btnSaveRX.setText(_translate("DialogSimulator", "Save")) - self.tabWidget.setTabText(self.tabWidget.indexOf(self.tab_simulation), _translate("DialogSimulator", "Status")) - self.textEditTranscript.setPlaceholderText(_translate("DialogSimulator", "Here you will find all messages that were sent and received during simulation.")) - self.radioButtonTranscriptBit.setText(_translate("DialogSimulator", "Bit &view")) + self.tabWidget.setTabText( + self.tabWidget.indexOf(self.tab_simulation), + _translate("DialogSimulator", "Status"), + ) + self.textEditTranscript.setPlaceholderText( + _translate( + "DialogSimulator", + "Here you will find all messages that were sent and received during simulation.", + ) + ) + self.radioButtonTranscriptBit.setText( + _translate("DialogSimulator", "Bit &view") + ) self.radioButtonTranscriptHex.setText(_translate("DialogSimulator", "Hex view")) - self.btnOpenInAnalysis.setText(_translate("DialogSimulator", "Open in Analysis")) + self.btnOpenInAnalysis.setText( + _translate("DialogSimulator", "Open in Analysis") + ) self.btnSaveTranscript.setText(_translate("DialogSimulator", "...")) - self.tabWidget.setTabText(self.tabWidget.indexOf(self.tab), _translate("DialogSimulator", "Messages")) - self.textEditDevices.setPlaceholderText(_translate("DialogSimulator", "After simulation start you will see the log messages of your configured SDRs here.")) - self.tabWidget.setTabText(self.tabWidget.indexOf(self.tab_device), _translate("DialogSimulator", "Devices")) + self.tabWidget.setTabText( + self.tabWidget.indexOf(self.tab), _translate("DialogSimulator", "Messages") + ) + self.textEditDevices.setPlaceholderText( + _translate( + "DialogSimulator", + "After simulation start you will see the log messages of your configured SDRs here.", + ) + ) + self.tabWidget.setTabText( + self.tabWidget.indexOf(self.tab_device), + _translate("DialogSimulator", "Devices"), + ) self.btnStartStop.setText(_translate("DialogSimulator", "Start")) - self.tabWidgetSimulatorSettings.setTabText(self.tabWidgetSimulatorSettings.indexOf(self.tabSimulation), _translate("DialogSimulator", "Simulation")) + self.tabWidgetSimulatorSettings.setTabText( + self.tabWidgetSimulatorSettings.indexOf(self.tabSimulation), + _translate("DialogSimulator", "Simulation"), + ) + + from urh.ui.views.LiveGraphicView import LiveGraphicView from urh.ui.views.LoggingGraphicsView import LoggingGraphicsView from . import urh_rc diff --git a/src/urh/ui/ui_tab_interpretation.py b/src/urh/ui/ui_tab_interpretation.py index fc596b81c0..905660da0b 100644 --- a/src/urh/ui/ui_tab_interpretation.py +++ b/src/urh/ui/ui_tab_interpretation.py @@ -17,7 +17,9 @@ def setupUi(self, Interpretation): self.horizontalLayout.setSpacing(0) self.horizontalLayout.setObjectName("horizontalLayout") self.scrollArea = ScrollArea(Interpretation) - sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Preferred, QtWidgets.QSizePolicy.Expanding) + sizePolicy = QtWidgets.QSizePolicy( + QtWidgets.QSizePolicy.Preferred, QtWidgets.QSizePolicy.Expanding + ) sizePolicy.setHorizontalStretch(0) sizePolicy.setVerticalStretch(0) sizePolicy.setHeightForWidth(self.scrollArea.sizePolicy().hasHeightForWidth()) @@ -31,10 +33,14 @@ def setupUi(self, Interpretation): self.scrollArea.setObjectName("scrollArea") self.scrlAreaSignals = QtWidgets.QWidget() self.scrlAreaSignals.setGeometry(QtCore.QRect(0, 0, 631, 561)) - sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Preferred, QtWidgets.QSizePolicy.Expanding) + sizePolicy = QtWidgets.QSizePolicy( + QtWidgets.QSizePolicy.Preferred, QtWidgets.QSizePolicy.Expanding + ) sizePolicy.setHorizontalStretch(0) sizePolicy.setVerticalStretch(0) - sizePolicy.setHeightForWidth(self.scrlAreaSignals.sizePolicy().hasHeightForWidth()) + sizePolicy.setHeightForWidth( + self.scrlAreaSignals.sizePolicy().hasHeightForWidth() + ) self.scrlAreaSignals.setSizePolicy(sizePolicy) self.scrlAreaSignals.setAutoFillBackground(True) self.scrlAreaSignals.setStyleSheet("") @@ -43,14 +49,16 @@ def setupUi(self, Interpretation): self.verticalLayout.setContentsMargins(0, 0, 0, 0) self.verticalLayout.setObjectName("verticalLayout") self.splitter = QtWidgets.QSplitter(self.scrlAreaSignals) - self.splitter.setStyleSheet("QSplitter::handle:vertical {\n" -"margin: 4px 0px;\n" -" background-color: qlineargradient(x1:0, y1:0, x2:1, y2:0, \n" -"stop:0 rgba(255, 255, 255, 0), \n" -"stop:0.5 rgba(100, 100, 100, 100), \n" -"stop:1 rgba(255, 255, 255, 0));\n" -" image: url(:/icons/icons/splitter_handle_horizontal.svg);\n" -"}") + self.splitter.setStyleSheet( + "QSplitter::handle:vertical {\n" + "margin: 4px 0px;\n" + " background-color: qlineargradient(x1:0, y1:0, x2:1, y2:0, \n" + "stop:0 rgba(255, 255, 255, 0), \n" + "stop:0.5 rgba(100, 100, 100, 100), \n" + "stop:1 rgba(255, 255, 255, 0));\n" + " image: url(:/icons/icons/splitter_handle_horizontal.svg);\n" + "}" + ) self.splitter.setOrientation(QtCore.Qt.Vertical) self.splitter.setHandleWidth(6) self.splitter.setObjectName("splitter") @@ -75,6 +83,13 @@ def setupUi(self, Interpretation): def retranslateUi(self, Interpretation): _translate = QtCore.QCoreApplication.translate Interpretation.setWindowTitle(_translate("Interpretation", "Form")) - self.labelGettingStarted.setText(_translate("Interpretation", "

Open a file or record a new signal using the File menu to get started.

")) + self.labelGettingStarted.setText( + _translate( + "Interpretation", + "

Open a file or record a new signal using the File menu to get started.

", + ) + ) + + from urh.ui.ScrollArea import ScrollArea from . import urh_rc diff --git a/src/urh/ui/urh_rc.py b/src/urh/ui/urh_rc.py index d7cadd4166..82874cfbb7 100644 --- a/src/urh/ui/urh_rc.py +++ b/src/urh/ui/urh_rc.py @@ -13158,7 +13158,7 @@ \x00\x00\x01\x71\x40\xc9\x02\x46\ " -qt_version = [int(v) for v in QtCore.qVersion().split('.')] +qt_version = [int(v) for v in QtCore.qVersion().split(".")] if qt_version < [5, 8, 0]: rcc_version = 1 qt_resource_struct = qt_resource_struct_v1 @@ -13166,10 +13166,17 @@ rcc_version = 2 qt_resource_struct = qt_resource_struct_v2 + def qInitResources(): - QtCore.qRegisterResourceData(rcc_version, qt_resource_struct, qt_resource_name, qt_resource_data) + QtCore.qRegisterResourceData( + rcc_version, qt_resource_struct, qt_resource_name, qt_resource_data + ) + def qCleanupResources(): - QtCore.qUnregisterResourceData(rcc_version, qt_resource_struct, qt_resource_name, qt_resource_data) + QtCore.qUnregisterResourceData( + rcc_version, qt_resource_struct, qt_resource_name, qt_resource_data + ) + qInitResources() diff --git a/src/urh/ui/views/DirectoryTreeView.py b/src/urh/ui/views/DirectoryTreeView.py index d4ca336e3d..24829a3800 100644 --- a/src/urh/ui/views/DirectoryTreeView.py +++ b/src/urh/ui/views/DirectoryTreeView.py @@ -23,11 +23,17 @@ def create_directory(self): return model = self.model().sourceModel() - dir_name, ok = QInputDialog.getText(self, self.tr("Create Directory"), self.tr("Directory name")) + dir_name, ok = QInputDialog.getText( + self, self.tr("Create Directory"), self.tr("Directory name") + ) if ok and len(dir_name) > 0: if not model.mkdir(index, dir_name).isValid(): - QMessageBox.information(self, self.tr("Create Directory"), self.tr("Failed to create the directory")) + QMessageBox.information( + self, + self.tr("Create Directory"), + self.tr("Failed to create the directory"), + ) def remove(self): index = self.model().mapToSource(self.currentIndex()) # type: QModelIndex @@ -41,16 +47,23 @@ def remove(self): ok = model.remove(index) if not ok: - QMessageBox.information(self, self.tr("Remove"), - self.tr("Failed to remove {0}".format(model.fileName(index)))) + QMessageBox.information( + self, + self.tr("Remove"), + self.tr("Failed to remove {0}".format(model.fileName(index))), + ) def create_context_menu(self) -> QMenu: menu = QMenu(self) index = self.model().mapToSource(self.currentIndex()) # type: QModelIndex if index.isValid(): - current_index_info = self.model().sourceModel().fileInfo(index) # type: QFileInfo + current_index_info = ( + self.model().sourceModel().fileInfo(index) + ) # type: QFileInfo if current_index_info.isDir(): - if os.path.isfile(os.path.join(current_index_info.filePath(), settings.PROJECT_FILE)): + if os.path.isfile( + os.path.join(current_index_info.filePath(), settings.PROJECT_FILE) + ): open_action = menu.addAction("Open project") open_action.setIcon(QIcon(":/icons/icons/appicon.png")) else: @@ -68,7 +81,9 @@ def create_context_menu(self) -> QMenu: menu.addSeparator() open_in_explorer_action = menu.addAction("Open in file manager...") - open_in_explorer_action.triggered.connect(self.on_open_explorer_action_triggered) + open_in_explorer_action.triggered.connect( + self.on_open_explorer_action_triggered + ) return menu diff --git a/src/urh/ui/views/EditableGraphicView.py b/src/urh/ui/views/EditableGraphicView.py index 51024f1dc7..653f0350a2 100644 --- a/src/urh/ui/views/EditableGraphicView.py +++ b/src/urh/ui/views/EditableGraphicView.py @@ -62,7 +62,9 @@ def __init__(self, parent=None): self.delete_action.setIcon(QIcon.fromTheme("edit-delete")) self.addAction(self.delete_action) - self.save_as_action = QAction(self.tr("Save Signal as..."), self) # type: QAction + self.save_as_action = QAction( + self.tr("Save Signal as..."), self + ) # type: QAction self.save_as_action.setIcon(QIcon.fromTheme("document-save-as")) self.save_as_action.setShortcut(QKeySequence.SaveAs) self.save_as_action.triggered.connect(self.save_as_clicked.emit) @@ -84,7 +86,9 @@ def __init__(self, parent=None): self.insert_sine_action.triggered.connect(self.on_insert_sine_action_triggered) self.insert_sine_plugin = InsertSinePlugin() - self.insert_sine_plugin.insert_sine_wave_clicked.connect(self.on_insert_sine_wave_clicked) + self.insert_sine_plugin.insert_sine_wave_clicked.connect( + self.on_insert_sine_wave_clicked + ) def init_undo_stack(self, undo_stack): self.undo_stack = undo_stack @@ -183,13 +187,17 @@ def create_context_menu(self): none_participant_action = participant_menu.addAction("None") none_participant_action.setCheckable(True) none_participant_action.setActionGroup(participant_group) - none_participant_action.triggered.connect(self.on_none_participant_action_triggered) + none_participant_action.triggered.connect( + self.on_none_participant_action_triggered + ) if selected_msg and selected_msg.participant is None: none_participant_action.setChecked(True) for participant in self.participants: - pa = participant_menu.addAction(participant.name + " (" + participant.shortname + ")") + pa = participant_menu.addAction( + participant.name + " (" + participant.shortname + ")" + ) pa.setCheckable(True) pa.setActionGroup(participant_group) if selected_msg and selected_msg.participant == participant: @@ -227,7 +235,9 @@ def clear_horizontal_selection(self): def toggle_symbol_legend(self): if self.scene_type == 1 and self.signal is not None: - self.scene().always_show_symbols_legend = self.show_symbol_legend_action.isChecked() + self.scene().always_show_symbols_legend = ( + self.show_symbol_legend_action.isChecked() + ) self.scene().draw_sep_area(-self.signal.center_thresholds) @pyqtSlot() @@ -242,10 +252,12 @@ def on_insert_sine_action_triggered(self): logger.critical("No data to insert a sine wave to") return - dialog = self.insert_sine_plugin.get_insert_sine_dialog(original_data=original_data, - position=self.paste_position, - sample_rate=self.sample_rate, - num_samples=num_samples) + dialog = self.insert_sine_plugin.get_insert_sine_dialog( + original_data=original_data, + position=self.paste_position, + sample_rate=self.sample_rate, + num_samples=num_samples, + ) dialog.show() @pyqtSlot() @@ -253,26 +265,38 @@ def on_insert_sine_wave_clicked(self): if self.insert_sine_plugin.complex_wave is not None and self.signal is not None: self.clear_horizontal_selection() - insert_action = EditSignalAction(signal=self.signal, protocol=self.protocol, - data_to_insert=self.insert_sine_plugin.complex_wave, - position=self.paste_position, - mode=EditAction.insert, cache_qad=self.cache_qad) + insert_action = EditSignalAction( + signal=self.signal, + protocol=self.protocol, + data_to_insert=self.insert_sine_plugin.complex_wave, + position=self.paste_position, + mode=EditAction.insert, + cache_qad=self.cache_qad, + ) self.undo_stack.push(insert_action) @pyqtSlot() def on_copy_action_triggered(self): if self.something_is_selected: - self.stored_item = self.signal.iq_array[int(self.selection_area.start):int(self.selection_area.end)] + self.stored_item = self.signal.iq_array[ + int(self.selection_area.start) : int(self.selection_area.end) + ] @pyqtSlot() def on_paste_action_triggered(self): if self.stored_item is not None: # paste_position is set in ContextMenuEvent self.clear_horizontal_selection() - paste_action = EditSignalAction(signal=self.signal, protocol=self.protocol, - start=self.selection_area.start, end=self.selection_area.end, - data_to_insert=self.stored_item, position=self.paste_position, - mode=EditAction.paste, cache_qad=self.cache_qad) + paste_action = EditSignalAction( + signal=self.signal, + protocol=self.protocol, + start=self.selection_area.start, + end=self.selection_area.end, + data_to_insert=self.stored_item, + position=self.paste_position, + mode=EditAction.paste, + cache_qad=self.cache_qad, + ) self.undo_stack.push(paste_action) @pyqtSlot() @@ -280,9 +304,14 @@ def on_delete_action_triggered(self): if self.something_is_selected: start, end = self.selection_area.start, self.selection_area.end self.clear_horizontal_selection() - del_action = EditSignalAction(signal=self.signal, protocol=self.protocol, - start=start, end=end, - mode=EditAction.delete, cache_qad=self.cache_qad) + del_action = EditSignalAction( + signal=self.signal, + protocol=self.protocol, + start=start, + end=end, + mode=EditAction.delete, + cache_qad=self.cache_qad, + ) self.undo_stack.push(del_action) @pyqtSlot() @@ -290,21 +319,33 @@ def on_crop_action_triggered(self): if self.something_is_selected: start, end = self.selection_area.start, self.selection_area.end self.clear_horizontal_selection() - crop_action = EditSignalAction(signal=self.signal, protocol=self.protocol, - start=start, end=end, - mode=EditAction.crop, cache_qad=self.cache_qad) + crop_action = EditSignalAction( + signal=self.signal, + protocol=self.protocol, + start=start, + end=end, + mode=EditAction.crop, + cache_qad=self.cache_qad, + ) self.undo_stack.push(crop_action) @pyqtSlot() def on_mute_action_triggered(self): - mute_action = EditSignalAction(signal=self.signal, protocol=self.protocol, - start=self.selection_area.start, end=self.selection_area.end, - mode=EditAction.mute, cache_qad=self.cache_qad) + mute_action = EditSignalAction( + signal=self.signal, + protocol=self.protocol, + start=self.selection_area.start, + end=self.selection_area.end, + mode=EditAction.mute, + cache_qad=self.cache_qad, + ) self.undo_stack.push(mute_action) @pyqtSlot() def on_create_action_triggered(self): - self.create_clicked.emit(int(self.selection_area.start), int(self.selection_area.end)) + self.create_clicked.emit( + int(self.selection_area.start), int(self.selection_area.end) + ) @pyqtSlot() def on_none_participant_action_triggered(self): diff --git a/src/urh/ui/views/EpicGraphicView.py b/src/urh/ui/views/EpicGraphicView.py index 3d71fcbc94..e348cfab9c 100644 --- a/src/urh/ui/views/EpicGraphicView.py +++ b/src/urh/ui/views/EpicGraphicView.py @@ -12,6 +12,7 @@ class EpicGraphicView(EditableGraphicView): """ Tied to Signal Frame (Interpretation) """ + save_clicked = pyqtSignal() def __init__(self, parent=None): @@ -44,8 +45,10 @@ def sample_rate(self, value): @property def selected_messages(self): if self.something_is_selected and self.protocol: - sb, _, eb, _ = self.protocol.get_bitseq_from_selection(self.selection_area.start, abs(self.selection_area.width)) - return self.protocol.messages[sb:eb + 1] + sb, _, eb, _ = self.protocol.get_bitseq_from_selection( + self.selection_area.start, abs(self.selection_area.width) + ) + return self.protocol.messages[sb : eb + 1] else: return [] @@ -68,8 +71,11 @@ def _get_sub_path_ranges_and_colors(self, start: float, end: float): if message.bit_sample_pos[-2] < start: continue - color = None if message.participant is None else settings.PARTICIPANT_COLORS[ - message.participant.color_index] + color = ( + None + if message.participant is None + else settings.PARTICIPANT_COLORS[message.participant.color_index] + ) if color is None: continue @@ -87,7 +93,9 @@ def _get_sub_path_ranges_and_colors(self, start: float, end: float): break # Data part of the message - sub_path_ranges.append((message.bit_sample_pos[0], message.bit_sample_pos[-2] + 1)) + sub_path_ranges.append( + (message.bit_sample_pos[0], message.bit_sample_pos[-2] + 1) + ) colors.append(color) start = message.bit_sample_pos[-2] + 1 @@ -103,4 +111,3 @@ def _get_sub_path_ranges_and_colors(self, start: float, end: float): @pyqtSlot() def on_save_action_triggered(self): self.save_clicked.emit() - diff --git a/src/urh/ui/views/GeneratorTableView.py b/src/urh/ui/views/GeneratorTableView.py index 133260b5d4..eb06389714 100644 --- a/src/urh/ui/views/GeneratorTableView.py +++ b/src/urh/ui/views/GeneratorTableView.py @@ -1,6 +1,16 @@ from PyQt5.QtCore import Qt, QRect, pyqtSignal, pyqtSlot -from PyQt5.QtGui import QDragMoveEvent, QDragEnterEvent, QPainter, QBrush, QColor, QPen, QDropEvent, QDragLeaveEvent, \ - QContextMenuEvent, QIcon +from PyQt5.QtGui import ( + QDragMoveEvent, + QDragEnterEvent, + QPainter, + QBrush, + QColor, + QPen, + QDropEvent, + QDragLeaveEvent, + QContextMenuEvent, + QIcon, +) from PyQt5.QtWidgets import QActionGroup, QInputDialog from PyQt5.QtWidgets import QHeaderView, QAbstractItemView, QStyleOption, QMenu @@ -34,26 +44,44 @@ def dragMoveEvent(self, event: QDragMoveEvent): pos = event.pos() row = self.rowAt(pos.y()) - index = self.model().createIndex(row, 0) # this always get the default 0 column index + index = self.model().createIndex( + row, 0 + ) # this always get the default 0 column index rect = self.visualRect(index) rect_left = self.visualRect(index.sibling(index.row(), 0)) - rect_right = self.visualRect(index.sibling(index.row(), - self.horizontalHeader().logicalIndex( - self.model().columnCount() - 1))) # in case section has been moved + rect_right = self.visualRect( + index.sibling( + index.row(), + self.horizontalHeader().logicalIndex(self.model().columnCount() - 1), + ) + ) # in case section has been moved self.drop_indicator_position = self.position(event.pos(), rect) if self.drop_indicator_position == self.AboveItem: - self.drop_indicator_rect = QRect(rect_left.left(), rect_left.top(), rect_right.right() - rect_left.left(), 0) + self.drop_indicator_rect = QRect( + rect_left.left(), + rect_left.top(), + rect_right.right() - rect_left.left(), + 0, + ) event.accept() elif self.drop_indicator_position == self.BelowItem: - self.drop_indicator_rect = QRect(rect_left.left(), rect_left.bottom(), rect_right.right() - rect_left.left(), - 0) + self.drop_indicator_rect = QRect( + rect_left.left(), + rect_left.bottom(), + rect_right.right() - rect_left.left(), + 0, + ) event.accept() elif self.drop_indicator_position == self.OnItem: - self.drop_indicator_rect = QRect(rect_left.left(), rect_left.bottom(), rect_right.right() - rect_left.left(), - 0) + self.drop_indicator_rect = QRect( + rect_left.left(), + rect_left.bottom(), + rect_right.right() - rect_left.left(), + 0, + ) event.accept() else: self.drop_indicator_rect = QRect() @@ -62,23 +90,38 @@ def dragMoveEvent(self, event: QDragMoveEvent): self.viewport().update() def __rect_for_row(self, row): - index = self.model().createIndex(row, 0) # this always get the default 0 column index + index = self.model().createIndex( + row, 0 + ) # this always get the default 0 column index # rect = self.visualRect(index) rect_left = self.visualRect(index.sibling(index.row(), 0)) - rect_right = self.visualRect(index.sibling(index.row(), - self.horizontalHeader().logicalIndex( - self.model().columnCount() - 1))) # in case section has been moved - return QRect(rect_left.left(), rect_left.bottom(), rect_right.right() - rect_left.left(), 0) + rect_right = self.visualRect( + index.sibling( + index.row(), + self.horizontalHeader().logicalIndex(self.model().columnCount() - 1), + ) + ) # in case section has been moved + return QRect( + rect_left.left(), + rect_left.bottom(), + rect_right.right() - rect_left.left(), + 0, + ) def dropEvent(self, event: QDropEvent): self.drag_active = False row = self.rowAt(event.pos().y()) - index = self.model().createIndex(row, 0) # this always get the default 0 column index + index = self.model().createIndex( + row, 0 + ) # this always get the default 0 column index rect = self.visualRect(index) drop_indicator_position = self.position(event.pos(), rect) if row == -1: row = self.model().row_count - 1 - elif drop_indicator_position == self.BelowItem or drop_indicator_position == self.OnItem: + elif ( + drop_indicator_position == self.BelowItem + or drop_indicator_position == self.OnItem + ): row += 1 self.model().dropped_row = row @@ -164,7 +207,9 @@ def create_context_menu(self) -> QMenu: self.encoding_actions = {} if not self.selection_is_empty: - selected_encoding = self.model().protocol.messages[self.selected_rows[0]].decoder + selected_encoding = ( + self.model().protocol.messages[self.selected_rows[0]].decoder + ) for i in self.selected_rows: if self.model().protocol.messages[i].decoder != selected_encoding: selected_encoding = None @@ -185,7 +230,9 @@ def create_context_menu(self) -> QMenu: ea.triggered.connect(self.on_encoding_action_triggered) menu.addSeparator() - de_bruijn_action = menu.addAction("Generate De Bruijn Sequence from Selection") + de_bruijn_action = menu.addAction( + "Generate De Bruijn Sequence from Selection" + ) de_bruijn_action.triggered.connect(self.on_de_bruijn_action_triggered) return menu @@ -201,7 +248,9 @@ def on_clear_action_triggered(self): @pyqtSlot() def on_encoding_action_triggered(self): for row in self.selected_rows: - self.model().protocol.messages[row].decoder = self.encoding_actions[self.sender()] + self.model().protocol.messages[row].decoder = self.encoding_actions[ + self.sender() + ] self.encodings_updated.emit() @pyqtSlot() @@ -217,7 +266,12 @@ def on_de_bruijn_action_triggered(self): @pyqtSlot() def on_add_message_action_triggered(self): row = self.rowAt(self.context_menu_pos.y()) - num_bits, ok = QInputDialog.getInt(self, self.tr("How many bits shall the new message have?"), - self.tr("Number of bits:"), 42, 1) + num_bits, ok = QInputDialog.getInt( + self, + self.tr("How many bits shall the new message have?"), + self.tr("Number of bits:"), + 42, + 1, + ) if ok: self.model().add_empty_row_behind(row, num_bits) diff --git a/src/urh/ui/views/GeneratorTreeView.py b/src/urh/ui/views/GeneratorTreeView.py index 7c56715b81..6742736116 100644 --- a/src/urh/ui/views/GeneratorTreeView.py +++ b/src/urh/ui/views/GeneratorTreeView.py @@ -16,4 +16,4 @@ def model(self) -> GeneratorTreeModel: return super().model() def selectionModel(self) -> QItemSelectionModel: - return super().selectionModel() \ No newline at end of file + return super().selectionModel() diff --git a/src/urh/ui/views/LabelValueTableView.py b/src/urh/ui/views/LabelValueTableView.py index f46b8a8bd9..b6d235ae19 100644 --- a/src/urh/ui/views/LabelValueTableView.py +++ b/src/urh/ui/views/LabelValueTableView.py @@ -17,13 +17,30 @@ class LabelValueTableView(QTableView): def __init__(self, parent=None): super().__init__(parent) - self.setItemDelegateForColumn(1, ComboBoxDelegate([""] * len(settings.LABEL_COLORS), - colors=settings.LABEL_COLORS, - parent=self)) - self.setItemDelegateForColumn(2, ComboBoxDelegate(ProtocolLabel.DISPLAY_FORMATS, parent=self)) - - orders = OrderedDict([("Big Endian (BE)", [bo + "/BE" for bo in ProtocolLabel.DISPLAY_BIT_ORDERS]), - ("Little Endian (LE)", [bo + "/LE" for bo in ProtocolLabel.DISPLAY_BIT_ORDERS])]) + self.setItemDelegateForColumn( + 1, + ComboBoxDelegate( + [""] * len(settings.LABEL_COLORS), + colors=settings.LABEL_COLORS, + parent=self, + ), + ) + self.setItemDelegateForColumn( + 2, ComboBoxDelegate(ProtocolLabel.DISPLAY_FORMATS, parent=self) + ) + + orders = OrderedDict( + [ + ( + "Big Endian (BE)", + [bo + "/BE" for bo in ProtocolLabel.DISPLAY_BIT_ORDERS], + ), + ( + "Little Endian (LE)", + [bo + "/LE" for bo in ProtocolLabel.DISPLAY_BIT_ORDERS], + ), + ] + ) self.setItemDelegateForColumn(3, SectionComboBoxDelegate(orders, parent=self)) @@ -54,16 +71,22 @@ def create_context_menu(self): if len(self.model().controller.proto_analyzer.message_types) > 1: msg_type_menu = menu.addMenu("Copy to message type") - for i, message_type in enumerate(self.model().controller.proto_analyzer.message_types): + for i, message_type in enumerate( + self.model().controller.proto_analyzer.message_types + ): if message_type != self.model().controller.active_message_type: msg_type_action = msg_type_menu.addAction(message_type.name) msg_type_action.setData(i) - msg_type_action.triggered.connect(self.on_copy_to_msg_type_action_triggered) + msg_type_action.triggered.connect( + self.on_copy_to_msg_type_action_triggered + ) menu.addAction(self.del_rows_action) menu.addSeparator() configure_field_types_action = menu.addAction("Configure field types...") - configure_field_types_action.triggered.connect(self.configure_field_types_action_triggered.emit) + configure_field_types_action.triggered.connect( + self.configure_field_types_action_triggered.emit + ) return menu @@ -86,4 +109,6 @@ def on_edit_label_action_triggered(self): @pyqtSlot() def on_copy_to_msg_type_action_triggered(self): min_row, max_row = self.selected_min_max_row - self.model().add_labels_to_message_type(min_row, max_row, int(self.sender().data())) + self.model().add_labels_to_message_type( + min_row, max_row, int(self.sender().data()) + ) diff --git a/src/urh/ui/views/LoggingGraphicsView.py b/src/urh/ui/views/LoggingGraphicsView.py index d6e7b2d88c..d980ce70b1 100644 --- a/src/urh/ui/views/LoggingGraphicsView.py +++ b/src/urh/ui/views/LoggingGraphicsView.py @@ -5,7 +5,6 @@ class LoggingGraphicsView(QGraphicsView): - def __init__(self, parent=None): super().__init__(parent) @@ -13,11 +12,17 @@ def __init__(self, parent=None): self.log_selected_action = QAction(self.tr("Log selected items"), self) self.log_selected_action.setShortcut(QKeySequence("L")) - self.log_selected_action.triggered.connect(self.on_log_selected_action_triggered) + self.log_selected_action.triggered.connect( + self.on_log_selected_action_triggered + ) - self.do_not_log_selected_action = QAction(self.tr("Do not log selected items"), self) + self.do_not_log_selected_action = QAction( + self.tr("Do not log selected items"), self + ) self.do_not_log_selected_action.setShortcut(QKeySequence("N")) - self.do_not_log_selected_action.triggered.connect(self.on_do_not_log_selected_action_triggered) + self.do_not_log_selected_action.triggered.connect( + self.on_do_not_log_selected_action_triggered + ) self.select_all_action = QAction(self.tr("Select all"), self) self.select_all_action.setShortcut(QKeySequence.SelectAll) @@ -38,9 +43,12 @@ def create_context_menu(self): menu.addAction(self.log_selected_action) menu.addAction(self.do_not_log_selected_action) - SimulatorGraphicsView.add_select_actions_to_menu(menu, self.scene(), - select_to_trigger=self.on_select_to_action_triggered, - select_from_trigger=self.on_select_from_action_triggered) + SimulatorGraphicsView.add_select_actions_to_menu( + menu, + self.scene(), + select_to_trigger=self.on_select_to_action_triggered, + select_from_trigger=self.on_select_from_action_triggered, + ) return menu @@ -48,7 +56,9 @@ def on_select_from_action_triggered(self): self.scene().select_messages_with_participant(self.sender().data()) def on_select_to_action_triggered(self): - self.scene().select_messages_with_participant(self.sender().data(), from_part=False) + self.scene().select_messages_with_participant( + self.sender().data(), from_part=False + ) def on_log_selected_action_triggered(self): self.scene().log_selected_items(True) diff --git a/src/urh/ui/views/MessageTypeTableView.py b/src/urh/ui/views/MessageTypeTableView.py index 0cb1805393..b7843312e3 100644 --- a/src/urh/ui/views/MessageTypeTableView.py +++ b/src/urh/ui/views/MessageTypeTableView.py @@ -52,9 +52,13 @@ def create_context_menu(self): menu.addAction(self.del_rows_action) menu.addSeparator() - update_message_types_action = menu.addAction("Update automatically assigned message types") + update_message_types_action = menu.addAction( + "Update automatically assigned message types" + ) update_message_types_action.setIcon(QIcon.fromTheme("view-refresh")) - update_message_types_action.triggered.connect(self.auto_message_type_update_triggered.emit) + update_message_types_action.triggered.connect( + self.auto_message_type_update_triggered.emit + ) menu.addSeparator() show_all_action = menu.addAction("Show all message types") @@ -77,9 +81,13 @@ def delete_rows(self): @pyqtSlot() def on_show_all_action_triggered(self): for i in range(self.model().rowCount()): - self.model().setData(self.model().index(i, 0), Qt.Checked, role=Qt.CheckStateRole) + self.model().setData( + self.model().index(i, 0), Qt.Checked, role=Qt.CheckStateRole + ) @pyqtSlot() def on_hide_all_action_triggered(self): for i in range(self.model().rowCount()): - self.model().setData(self.model().index(i, 0), Qt.Unchecked, role=Qt.CheckStateRole) + self.model().setData( + self.model().index(i, 0), Qt.Unchecked, role=Qt.CheckStateRole + ) diff --git a/src/urh/ui/views/ModulatorTreeView.py b/src/urh/ui/views/ModulatorTreeView.py index 7d73c48f38..ca5cea6051 100644 --- a/src/urh/ui/views/ModulatorTreeView.py +++ b/src/urh/ui/views/ModulatorTreeView.py @@ -18,4 +18,4 @@ def selectionModel(self) -> QItemSelectionModel: def selectionChanged(self, QItemSelection, QItemSelection_1): self.selection_changed.emit() - super().selectionChanged(QItemSelection, QItemSelection_1) \ No newline at end of file + super().selectionChanged(QItemSelection, QItemSelection_1) diff --git a/src/urh/ui/views/ParticipantTableView.py b/src/urh/ui/views/ParticipantTableView.py index 96047aa089..d2230dcc97 100644 --- a/src/urh/ui/views/ParticipantTableView.py +++ b/src/urh/ui/views/ParticipantTableView.py @@ -24,7 +24,9 @@ def selected_columns(self) -> (int, int): if selection.isEmpty(): return 0, self.model().columnCount() - 1 - return min([rng.left() for rng in selection]), max([rng.right() for rng in selection]) + return min([rng.left() for rng in selection]), max( + [rng.right() for rng in selection] + ) def select(self, row_1, col_1, row_2, col_2): selection = QItemSelection() @@ -52,9 +54,13 @@ def create_context_menu(self): menu.addAction(self.remove_action) menu.addSeparator() - move_up = menu.addAction(QIcon.fromTheme("go-up"), "Move selected participants up") + move_up = menu.addAction( + QIcon.fromTheme("go-up"), "Move selected participants up" + ) move_up.triggered.connect(self.on_move_up_action_triggered) - move_down = menu.addAction(QIcon.fromTheme("go-down"), "Move selected participants down") + move_down = menu.addAction( + QIcon.fromTheme("go-down"), "Move selected participants down" + ) move_down.triggered.connect(self.on_move_down_action_triggered) return menu @@ -72,9 +78,14 @@ def refresh_participant_table(self): for row in range(n): self.closePersistentEditor(self.model().index(row, 3)) - self.setItemDelegateForColumn(2, ComboBoxDelegate([""] * len(settings.PARTICIPANT_COLORS), - colors=settings.PARTICIPANT_COLORS, - parent=self)) + self.setItemDelegateForColumn( + 2, + ComboBoxDelegate( + [""] * len(settings.PARTICIPANT_COLORS), + colors=settings.PARTICIPANT_COLORS, + parent=self, + ), + ) self.setItemDelegateForColumn(3, ComboBoxDelegate(items, parent=self)) for row in range(n): @@ -94,7 +105,7 @@ def on_move_up_action_triggered(self): col_start, col_end = self.selected_columns start, end = self.model().move_up(self.selectionModel().selection()) if start is not None and end is not None: - self.select(start-1, col_start, end-1, col_end) + self.select(start - 1, col_start, end - 1, col_end) @pyqtSlot() def on_move_down_action_triggered(self): diff --git a/src/urh/ui/views/ProtocolLabelTableView.py b/src/urh/ui/views/ProtocolLabelTableView.py index 6a680660d2..2834789d48 100644 --- a/src/urh/ui/views/ProtocolLabelTableView.py +++ b/src/urh/ui/views/ProtocolLabelTableView.py @@ -33,8 +33,11 @@ def create_context_menu(self): if isinstance(self.model(), SimulatorMessageFieldModel): value_type_group = QActionGroup(self) value_type_menu = menu.addMenu("Set value type") - labels = [self.model().message_type[i] for i in self.selected_rows - if not self.model().message_type[i].is_checksum_label] + labels = [ + self.model().message_type[i] + for i in self.selected_rows + if not self.model().message_type[i].is_checksum_label + ] for i, value_type in enumerate(SimulatorProtocolLabel.VALUE_TYPES): va = value_type_menu.addAction(value_type) @@ -61,4 +64,3 @@ def on_set_value_type_action_triggered(self): assert isinstance(self.model(), SimulatorMessageFieldModel) value_type_index = self.sender().data() self.model().set_value_type_index(self.selected_rows, value_type_index) - diff --git a/src/urh/ui/views/ProtocolTableView.py b/src/urh/ui/views/ProtocolTableView.py index 33c3040c85..528a880ae4 100644 --- a/src/urh/ui/views/ProtocolTableView.py +++ b/src/urh/ui/views/ProtocolTableView.py @@ -53,7 +53,9 @@ def selected_messages(self): rows = set(i.row() for i in self.selectionModel().selectedIndexes()) return [messages[i] for i in rows] - def selectionChanged(self, selection_1: QItemSelection, selection_2: QItemSelection): + def selectionChanged( + self, selection_1: QItemSelection, selection_2: QItemSelection + ): self.selection_changed.emit() super().selectionChanged(selection_1, selection_2) @@ -70,7 +72,11 @@ def dropEvent(self, event: QDropEvent): def create_context_menu(self): menu = super().create_context_menu() row = self.rowAt(self.context_menu_pos.y()) - cols = [index.column() for index in self.selectionModel().selectedIndexes() if index.row() == row] + cols = [ + index.column() + for index in self.selectionModel().selectedIndexes() + if index.row() == row + ] cols.sort() pos = self.context_menu_pos @@ -113,10 +119,15 @@ def create_context_menu(self): new_message_type_action = message_type_menu.addAction("Create new") new_message_type_action.setIcon(QIcon.fromTheme("list-add")) - new_message_type_action.triggered.connect(self.on_new_message_type_action_triggered) - - if self.model().participants and self.model().protocol and not self.selection_is_empty: - + new_message_type_action.triggered.connect( + self.on_new_message_type_action_triggered + ) + + if ( + self.model().participants + and self.model().protocol + and not self.selection_is_empty + ): participant_group = QActionGroup(self) participant_menu_str = self.tr("Participant") if selected_participant is None: @@ -129,13 +140,17 @@ def create_context_menu(self): none_participant_action = participant_menu.addAction("None") none_participant_action.setCheckable(True) none_participant_action.setActionGroup(participant_group) - none_participant_action.triggered.connect(self.on_none_participant_action_triggered) + none_participant_action.triggered.connect( + self.on_none_participant_action_triggered + ) if selected_participant is None: none_participant_action.setChecked(True) for participant in self.model().participants: - pa = participant_menu.addAction(participant.name + " (" + participant.shortname + ")") + pa = participant_menu.addAction( + participant.name + " (" + participant.shortname + ")" + ) pa.setCheckable(True) pa.setActionGroup(participant_group) if selected_participant == participant: @@ -152,23 +167,31 @@ def create_context_menu(self): menu.addAction(self.hide_row_action) hidden_rows = self.model().hidden_rows if len(hidden_rows) > 0: - show_row_action = menu.addAction(self.tr("Show all rows (reset {0:d} hidden)".format(len(hidden_rows)))) + show_row_action = menu.addAction( + self.tr("Show all rows (reset {0:d} hidden)".format(len(hidden_rows))) + ) show_row_action.triggered.connect(self.on_show_row_action_triggered) if self.model().refindex != -1: menu.addAction(self.ref_message_action) if not self.model().is_writeable: - show_interpretation_action = menu.addAction(self.tr("Show selection in Interpretation")) + show_interpretation_action = menu.addAction( + self.tr("Show selection in Interpretation") + ) show_interpretation_action.setIcon(QIcon.fromTheme("zoom-select")) - show_interpretation_action.triggered.connect(self.on_show_in_interpretation_action_triggered) + show_interpretation_action.triggered.connect( + self.on_show_in_interpretation_action_triggered + ) if self.model().is_writeable: writeable_action = menu.addAction(self.tr("Writeable")) writeable_action.setCheckable(True) writeable_action.setChecked(True) else: - writeable_action = menu.addAction(self.tr("Writeable (decouples from signal)")) + writeable_action = menu.addAction( + self.tr("Writeable (decouples from signal)") + ) writeable_action.setCheckable(True) writeable_action.setChecked(False) @@ -180,8 +203,13 @@ def create_context_menu(self): for plugin in self.controller.plugin_manager.protocol_plugins: if plugin.enabled: - act = plugin.get_action(self, undo_stack, self.selection_range(), - self.controller.proto_analyzer, view) + act = plugin.get_action( + self, + undo_stack, + self.selection_range(), + self.controller.proto_analyzer, + view, + ) if act is not None: menu.addAction(act) @@ -257,7 +285,9 @@ def on_participant_action_triggered(self): @pyqtSlot() def on_message_type_action_triggered(self): - self.messagetype_selected.emit(self.message_type_actions[self.sender()], self.selected_messages) + self.messagetype_selected.emit( + self.message_type_actions[self.sender()], self.selected_messages + ) @pyqtSlot() def on_new_message_type_action_triggered(self): diff --git a/src/urh/ui/views/ProtocolTreeView.py b/src/urh/ui/views/ProtocolTreeView.py index b72ad5bd30..38e7e2ef1d 100644 --- a/src/urh/ui/views/ProtocolTreeView.py +++ b/src/urh/ui/views/ProtocolTreeView.py @@ -1,7 +1,7 @@ from PyQt5.QtCore import QItemSelection, pyqtSlot from PyQt5.QtCore import pyqtSignal, QItemSelectionModel, Qt from PyQt5.QtGui import QContextMenuEvent, QDropEvent, QIcon -from PyQt5.QtWidgets import QTreeView, QAbstractItemView, QMenu +from PyQt5.QtWidgets import QTreeView, QAbstractItemView, QMenu from urh.models.ProtocolTreeModel import ProtocolTreeModel @@ -35,8 +35,13 @@ def create_context_menu(self): new_group_action.triggered.connect(self.on_new_group_action_triggered) item = self.model().getItem(self.indexAt(self.context_menu_pos)) - selected_items = [self.model().getItem(index) for index in self.selectionModel().selectedIndexes()] - selected_protocols = [item.protocol for item in selected_items if not item.is_group] + selected_items = [ + self.model().getItem(index) + for index in self.selectionModel().selectedIndexes() + ] + selected_protocols = [ + item.protocol for item in selected_items if not item.is_group + ] self.move_to_group_actions.clear() if item.is_group: @@ -58,14 +63,18 @@ def create_context_menu(self): for i in other_groups: group_name = self.model().rootItem.child(i).data() move_to_group_action = move_to_group_menu.addAction(group_name) - move_to_group_action.triggered.connect(self.on_move_to_group_action_triggered) + move_to_group_action.triggered.connect( + self.on_move_to_group_action_triggered + ) self.move_to_group_actions[move_to_group_action] = i if item != self.model().rootItem: menu.addSeparator() sort_group_elements_action = menu.addAction("Sort Group Elements") sort_group_elements_action.setIcon(QIcon.fromTheme("view-sort-ascending")) - sort_group_elements_action.triggered.connect(self.on_sort_group_elements_action_triggered) + sort_group_elements_action.triggered.connect( + self.on_sort_group_elements_action_triggered + ) return menu @@ -93,14 +102,22 @@ def on_new_group_action_triggered(self): @pyqtSlot() def on_move_to_group_action_triggered(self): - selected_items = [self.model().getItem(index) for index in self.selectionModel().selectedIndexes()] + selected_items = [ + self.model().getItem(index) + for index in self.selectionModel().selectedIndexes() + ] i = self.move_to_group_actions[self.sender()] self.model().move_to_group(selected_items, i) @pyqtSlot() def on_close_action_triggered(self): - selected_items = [self.model().getItem(index) for index in self.selectionModel().selectedIndexes()] - selected_protocols = [item.protocol for item in selected_items if not item.is_group] + selected_items = [ + self.model().getItem(index) + for index in self.selectionModel().selectedIndexes() + ] + selected_protocols = [ + item.protocol for item in selected_items if not item.is_group + ] self.close_wanted.emit(selected_protocols) @pyqtSlot() diff --git a/src/urh/ui/views/SelectableGraphicView.py b/src/urh/ui/views/SelectableGraphicView.py index bead32d6fb..f808c064f4 100644 --- a/src/urh/ui/views/SelectableGraphicView.py +++ b/src/urh/ui/views/SelectableGraphicView.py @@ -59,11 +59,15 @@ def has_horizontal_selection(self) -> bool: @property def hold_shift_to_drag(self) -> bool: - return settings.read('hold_shift_to_drag', True, type=bool) + return settings.read("hold_shift_to_drag", True, type=bool) @property def something_is_selected(self) -> bool: - return hasattr(self, "selection_area") and self.selection_area is not None and not self.selection_area.is_empty + return ( + hasattr(self, "selection_area") + and self.selection_area is not None + and not self.selection_area.is_empty + ) def is_pos_in_separea(self, pos: QPoint): """ @@ -106,9 +110,12 @@ def mousePressEvent(self, event: QMouseEvent): cursor = self.cursor().shape() has_shift_modifier = event.modifiers() == Qt.ShiftModifier - is_in_shift_mode = (has_shift_modifier and self.hold_shift_to_drag) \ - or (not has_shift_modifier and not self.hold_shift_to_drag) \ - and cursor != Qt.SplitHCursor and cursor != Qt.SplitVCursor + is_in_shift_mode = ( + (has_shift_modifier and self.hold_shift_to_drag) + or (not has_shift_modifier and not self.hold_shift_to_drag) + and cursor != Qt.SplitHCursor + and cursor != Qt.SplitVCursor + ) if event.buttons() == Qt.LeftButton and is_in_shift_mode: self.setCursor(Qt.ClosedHandCursor) @@ -118,7 +125,10 @@ def mousePressEvent(self, event: QMouseEvent): self.separation_area_moving = True self.setCursor(Qt.SplitVCursor) - elif self.selection_area.is_empty or self.selection_area.selected_edge is None: + elif ( + self.selection_area.is_empty + or self.selection_area.selected_edge is None + ): # Create new selection self.mouse_press_pos = event.pos() self.mouse_pos = event.pos() @@ -137,11 +147,15 @@ def mouseMoveEvent(self, event: QMouseEvent): if self.grab_start is not None: move_x = self.grab_start.x() - event.pos().x() - self.horizontalScrollBar().setValue(self.horizontalScrollBar().value() + move_x) + self.horizontalScrollBar().setValue( + self.horizontalScrollBar().value() + move_x + ) if self.move_y_with_drag: move_y = self.grab_start.y() - event.pos().y() - self.verticalScrollBar().setValue(self.verticalScrollBar().value() + move_y) + self.verticalScrollBar().setValue( + self.verticalScrollBar().value() + move_y + ) self.grab_start = event.pos() return @@ -150,8 +164,14 @@ def mouseMoveEvent(self, event: QMouseEvent): y_sep = self.mapToScene(event.pos()).y() y = self.sceneRect().y() h = self.sceneRect().height() - if y < y_sep < y + h and hasattr(self, "signal") and self.signal is not None: - self.scene().draw_sep_area(-self.signal.get_thresholds_for_center(-y_sep), show_symbols=True) + if ( + y < y_sep < y + h + and hasattr(self, "signal") + and self.signal is not None + ): + self.scene().draw_sep_area( + -self.signal.get_thresholds_for_center(-y_sep), show_symbols=True + ) elif self.is_pos_in_separea(self.mapToScene(event.pos())): self.setCursor(Qt.SplitVCursor) elif cursor == Qt.SplitVCursor and self.has_horizontal_selection: @@ -161,8 +181,9 @@ def mouseMoveEvent(self, event: QMouseEvent): pos = self.mapToScene(event.pos()) roi_edge = self.selection_area.get_selected_edge(pos, self.transform()) if roi_edge is None: - if (cursor == Qt.SplitHCursor and self.has_horizontal_selection) \ - or (cursor == Qt.SplitVCursor and not self.has_horizontal_selection): + if (cursor == Qt.SplitHCursor and self.has_horizontal_selection) or ( + cursor == Qt.SplitVCursor and not self.has_horizontal_selection + ): self.unsetCursor() return elif roi_edge == 0 or roi_edge == 1: @@ -172,7 +193,6 @@ def mouseMoveEvent(self, event: QMouseEvent): self.setCursor(Qt.SplitVCursor) if event.buttons() == Qt.LeftButton and self.selection_area.resizing: - if self.selection_area.selected_edge == 0: start = self.mapToScene(event.pos()) self.__set_selection_area(x=start.x(), y=start.y()) @@ -226,7 +246,11 @@ def mouseReleaseEvent(self, event: QMouseEvent): self.grab_start = None self.setCursor(Qt.OpenHandCursor) - elif self.separation_area_moving and hasattr(self, "signal") and self.signal is not None: + elif ( + self.separation_area_moving + and hasattr(self, "signal") + and self.signal is not None + ): y_sep = self.mapToScene(event.pos()).y() y = self.sceneRect().y() h = self.sceneRect().height() @@ -252,15 +276,23 @@ def refresh_selection_area(self): This happens e.g. when switching from Signal View to Quad Demod view :return: """ - self.__set_selection_area(x=self.selection_area.x, y=self.selection_area.y, - w=self.selection_area.width, h=self.selection_area.height) + self.__set_selection_area( + x=self.selection_area.x, + y=self.selection_area.y, + w=self.selection_area.width, + h=self.selection_area.height, + ) def set_vertical_selection(self, y=None, h=None): self.selection_area.setX(self.sceneRect().x()) self.selection_area.width = self.sceneRect().width() if y is not None: - y = util.clip(y, self.sceneRect().y(), self.sceneRect().y() + self.sceneRect().height()) + y = util.clip( + y, + self.sceneRect().y(), + self.sceneRect().y() + self.sceneRect().height(), + ) self.selection_area.setY(y) if h is not None: @@ -279,7 +311,9 @@ def set_horizontal_selection(self, x=None, w=None): self.selection_area.height = self.view_rect().height() if x is not None: - x = util.clip(x, self.sceneRect().x(), self.sceneRect().x() + self.sceneRect().width()) + x = util.clip( + x, self.sceneRect().x(), self.sceneRect().x() + self.sceneRect().width() + ) self.selection_area.setX(x) if w is not None: @@ -309,14 +343,18 @@ def emit_selection_size_changed(self): self.selection_height_changed.emit(int(self.selection_area.height)) def emit_selection_start_end_changed(self): - self.sel_area_start_end_changed.emit(self.selection_area.start, self.selection_area.end) + self.sel_area_start_end_changed.emit( + self.selection_area.start, self.selection_area.end + ) def view_rect(self) -> QRectF: """ Return the boundaries of the view in scene coordinates """ top_left = self.mapToScene(0, 0) - bottom_right = self.mapToScene(self.viewport().width() - 1, self.viewport().height() - 1) + bottom_right = self.mapToScene( + self.viewport().width() - 1, self.viewport().height() - 1 + ) return QRectF(top_left, bottom_right) def eliminate(self): diff --git a/src/urh/ui/views/SimulatorGraphicsView.py b/src/urh/ui/views/SimulatorGraphicsView.py index 5106a68531..49ba227898 100644 --- a/src/urh/ui/views/SimulatorGraphicsView.py +++ b/src/urh/ui/views/SimulatorGraphicsView.py @@ -2,7 +2,14 @@ from PyQt5.QtCore import Qt, pyqtSlot, pyqtSignal from PyQt5.QtGui import QKeySequence, QIcon -from PyQt5.QtWidgets import QGraphicsView, QAction, QActionGroup, QMenu, QAbstractItemView, QInputDialog +from PyQt5.QtWidgets import ( + QGraphicsView, + QAction, + QActionGroup, + QMenu, + QAbstractItemView, + QInputDialog, +) from urh.signalprocessing.MessageType import MessageType from urh.simulator.GraphicsItem import GraphicsItem @@ -40,7 +47,9 @@ def __init__(self, parent=None): self.delete_action.setShortcutContext(Qt.WidgetWithChildrenShortcut) self.addAction(self.select_all_action) - self.copy_action = QAction(self.tr("Copy selected items"), self) # type: QAction + self.copy_action = QAction( + self.tr("Copy selected items"), self + ) # type: QAction self.copy_action.setShortcut(QKeySequence.Copy) self.copy_action.triggered.connect(self.on_copy_action_triggered) self.copy_action.setShortcutContext(Qt.WidgetWithChildrenShortcut) @@ -59,9 +68,13 @@ def scene(self) -> SimulatorScene: @pyqtSlot() def on_add_message_action_triggered(self): - num_bits, ok = QInputDialog.getInt(self, - self.tr("How many bits shall the new message have?"), - self.tr("Number of bits:"), 42, 1) + num_bits, ok = QInputDialog.getInt( + self, + self.tr("How many bits shall the new message have?"), + self.tr("Number of bits:"), + 42, + 1, + ) if ok: self.add_empty_message(num_bits) @@ -77,44 +90,64 @@ def add_empty_message(self, num_bits): else: position = QAbstractItemView.BelowItem - message = self.scene().add_message(plain_bits=[0] * num_bits, - pause=0, - message_type=message_type, - ref_item=ref_item, - position=position) + message = self.scene().add_message( + plain_bits=[0] * num_bits, + pause=0, + message_type=message_type, + ref_item=ref_item, + position=position, + ) self.jump_to_item(message) @pyqtSlot() def on_add_rule_action_triggered(self): - rule = self.scene().add_rule(self.context_menu_item, QAbstractItemView.BelowItem) + rule = self.scene().add_rule( + self.context_menu_item, QAbstractItemView.BelowItem + ) if_cond = rule.children[0] self.jump_to_item(if_cond) @pyqtSlot() def on_add_goto_action_triggered(self): ref_item = self.context_menu_item - position = QAbstractItemView.OnItem if isinstance(ref_item, RuleConditionItem) else QAbstractItemView.BelowItem + position = ( + QAbstractItemView.OnItem + if isinstance(ref_item, RuleConditionItem) + else QAbstractItemView.BelowItem + ) ga = self.scene().add_goto_action(ref_item, position) self.jump_to_item(ga) @pyqtSlot() def on_add_sleep_action_triggered(self): ref_item = self.context_menu_item - position = QAbstractItemView.OnItem if isinstance(ref_item, RuleConditionItem) else QAbstractItemView.BelowItem + position = ( + QAbstractItemView.OnItem + if isinstance(ref_item, RuleConditionItem) + else QAbstractItemView.BelowItem + ) sa = self.scene().add_sleep_action(ref_item, position) self.jump_to_item(sa) @pyqtSlot() def on_add_counter_action_triggered(self): ref_item = self.context_menu_item - position = QAbstractItemView.OnItem if isinstance(ref_item, RuleConditionItem) else QAbstractItemView.BelowItem + position = ( + QAbstractItemView.OnItem + if isinstance(ref_item, RuleConditionItem) + else QAbstractItemView.BelowItem + ) ca = self.scene().add_counter_action(ref_item, position) self.jump_to_item(ca) @pyqtSlot() def on_trigger_command_action_triggered(self): ref_item = self.context_menu_item - position = QAbstractItemView.OnItem if isinstance(ref_item, RuleConditionItem) else QAbstractItemView.BelowItem + position = ( + QAbstractItemView.OnItem + if isinstance(ref_item, RuleConditionItem) + else QAbstractItemView.BelowItem + ) pa = self.scene().add_trigger_command_action(ref_item, position) self.jump_to_item(pa) @@ -180,7 +213,9 @@ def on_select_from_action_triggered(self): self.scene().select_messages_with_participant(self.sender().data()) def on_select_to_action_triggered(self): - self.scene().select_messages_with_participant(self.sender().data(), from_part=False) + self.scene().select_messages_with_participant( + self.sender().data(), from_part=False + ) def create_context_menu(self): menu = QMenu() @@ -206,17 +241,23 @@ def create_context_menu(self): add_counter_action = action_menu.addAction("Counter") add_counter_action.triggered.connect(self.on_add_counter_action_triggered) trigger_command_action = action_menu.addAction("Trigger command") - trigger_command_action.triggered.connect(self.on_trigger_command_action_triggered) + trigger_command_action.triggered.connect( + self.on_trigger_command_action_triggered + ) if isinstance(self.context_menu_item, RuleConditionItem): menu.addSeparator() add_else_if_cond_action = menu.addAction("Add else if block") - add_else_if_cond_action.triggered.connect(self.on_add_else_if_cond_action_triggered) + add_else_if_cond_action.triggered.connect( + self.on_add_else_if_cond_action_triggered + ) if not self.context_menu_item.parentItem().has_else_condition: add_else_cond_action = menu.addAction("Add else block") - add_else_cond_action.triggered.connect(self.on_add_else_cond_action_triggered) + add_else_cond_action.triggered.connect( + self.on_add_else_cond_action_triggered + ) menu.addSeparator() menu.addAction(self.copy_action) @@ -237,8 +278,12 @@ def create_context_menu(self): va.setActionGroup(value_type_group) va.setData(i) - if all(lbl.value_type_index == i for msg in messages for lbl in msg.message_type - if not lbl.is_checksum_label): + if all( + lbl.value_type_index == i + for msg in messages + for lbl in msg.message_type + if not lbl.is_checksum_label + ): va.setChecked(True) va.triggered.connect(self.on_set_value_type_action_triggered) @@ -285,24 +330,35 @@ def create_context_menu(self): swap_part_action.triggered.connect(self.on_swap_part_action_triggered) swap_part_action.setIcon(QIcon.fromTheme("object-flip-horizontal")) - pause_action = menu.addAction("Set subsequent pause ({} samples)".format(self.context_menu_item.model_item.pause)) + pause_action = menu.addAction( + "Set subsequent pause ({} samples)".format( + self.context_menu_item.model_item.pause + ) + ) pause_action.triggered.connect(self.on_pause_action_triggered) menu.addSeparator() if len(self.scene().get_all_message_items()) > 1: consolidate_messages_action = menu.addAction("Consolidate messages") - consolidate_messages_action.triggered.connect(self.on_consolidate_messages_action_triggered) + consolidate_messages_action.triggered.connect( + self.on_consolidate_messages_action_triggered + ) - if len([item for item in self.scene().items() if isinstance(item, GraphicsItem)]): + if len( + [item for item in self.scene().items() if isinstance(item, GraphicsItem)] + ): # menu.addAction(self.select_all_action) clear_all_action = menu.addAction("Clear all") clear_all_action.triggered.connect(self.on_clear_all_action_triggered) clear_all_action.setIcon(QIcon.fromTheme("edit-clear")) - self.add_select_actions_to_menu(menu, self.scene(), - select_to_trigger=self.on_select_to_action_triggered, - select_from_trigger=self.on_select_from_action_triggered) + self.add_select_actions_to_menu( + menu, + self.scene(), + select_to_trigger=self.on_select_to_action_triggered, + select_from_trigger=self.on_select_from_action_triggered, + ) return menu @@ -332,7 +388,11 @@ def jump_to_scene_item(self, item): item.setSelected(True) def contextMenuEvent(self, event): - items = [item for item in self.items(event.pos()) if isinstance(item, GraphicsItem) and item.is_selectable()] + items = [ + item + for item in self.items(event.pos()) + if isinstance(item, GraphicsItem) and item.is_selectable() + ] self.context_menu_item = None if len(items) == 0 else items[0] menu = self.create_context_menu() menu.exec_(event.globalPos()) @@ -349,15 +409,22 @@ def keyPressEvent(self, event): @pyqtSlot() def on_pause_action_triggered(self): - p = self.context_menu_item.model_item.pause if isinstance(self.context_menu_item, MessageItem) else 0 - pause, ok = QInputDialog.getInt(self, self.tr("Enter new pause"), - self.tr("Pause in samples:"), p, 0) + p = ( + self.context_menu_item.model_item.pause + if isinstance(self.context_menu_item, MessageItem) + else 0 + ) + pause, ok = QInputDialog.getInt( + self, self.tr("Enter new pause"), self.tr("Pause in samples:"), p, 0 + ) if ok: for msg in self.scene().get_selected_messages(): msg.pause = pause @classmethod - def add_select_actions_to_menu(cls, menu, scene: SimulatorScene, select_to_trigger, select_from_trigger): + def add_select_actions_to_menu( + cls, menu, scene: SimulatorScene, select_to_trigger, select_from_trigger + ): if len(scene.visible_participants) == 0: return @@ -387,5 +454,6 @@ def on_paste_action_triggered(self): assert isinstance(item, GraphicsItem) parent = item.model_item.parent() pos = parent.child_count() if parent is not None else 0 - self.scene().simulator_config.add_items([copy.deepcopy(item.model_item)], pos, parent) - + self.scene().simulator_config.add_items( + [copy.deepcopy(item.model_item)], pos, parent + ) diff --git a/src/urh/ui/views/SimulatorLabelTableView.py b/src/urh/ui/views/SimulatorLabelTableView.py index f49f08f428..bdf6d173d3 100644 --- a/src/urh/ui/views/SimulatorLabelTableView.py +++ b/src/urh/ui/views/SimulatorLabelTableView.py @@ -13,7 +13,6 @@ def __init__(self, parent=None): self.setMouseTracking(True) self.clicked.connect(self.on_clicked) - def model(self) -> SimulatorMessageFieldModel: return super().model() diff --git a/src/urh/ui/views/SimulatorMessageTableView.py b/src/urh/ui/views/SimulatorMessageTableView.py index bc2b8ab1fd..d389f65d6c 100644 --- a/src/urh/ui/views/SimulatorMessageTableView.py +++ b/src/urh/ui/views/SimulatorMessageTableView.py @@ -21,7 +21,9 @@ def __init__(self, parent=None): def _insert_column(self, pos): view_type = self.model().proto_view - index = self.model().protocol.convert_index(pos, from_view=view_type, to_view=0, decoded=False)[0] + index = self.model().protocol.convert_index( + pos, from_view=view_type, to_view=0, decoded=False + )[0] nbits = 1 if view_type == 0 else 4 if view_type == 1 else 8 for row in self.selected_rows: msg = self.model().protocol.messages[row] @@ -53,8 +55,10 @@ def create_context_menu(self) -> QMenu: selected_encoding = self.selected_message.decoder - if not all(self.model().protocol.messages[i].decoder is selected_encoding - for i in self.selected_rows): + if not all( + self.model().protocol.messages[i].decoder is selected_encoding + for i in self.selected_rows + ): selected_encoding = None encoding_group = QActionGroup(self) @@ -72,10 +76,14 @@ def create_context_menu(self) -> QMenu: ea.triggered.connect(self.on_encoding_action_triggered) if settings.read("multiple_modulations", False, bool): - selected_modulation = self.model().protocol.messages[self.selected_rows[0]].modulator_index - - if not all(self.model().protocol.messages[i].modulator_index == selected_modulation - for i in self.selected_rows): + selected_modulation = ( + self.model().protocol.messages[self.selected_rows[0]].modulator_index + ) + + if not all( + self.model().protocol.messages[i].modulator_index == selected_modulation + for i in self.selected_rows + ): selected_modulation = -1 modulation_group = QActionGroup(self) @@ -93,7 +101,9 @@ def create_context_menu(self) -> QMenu: ma.triggered.connect(self.on_modulation_action_triggered) open_modulator_dialog_action = modulation_menu.addAction(self.tr("...")) - open_modulator_dialog_action.triggered.connect(self.on_open_modulator_dialog_action_triggered) + open_modulator_dialog_action.triggered.connect( + self.on_open_modulator_dialog_action_triggered + ) return menu diff --git a/src/urh/ui/views/SpectrogramGraphicView.py b/src/urh/ui/views/SpectrogramGraphicView.py index 387a197dcb..e10746ca0b 100644 --- a/src/urh/ui/views/SpectrogramGraphicView.py +++ b/src/urh/ui/views/SpectrogramGraphicView.py @@ -21,7 +21,9 @@ def __init__(self, parent=None): super().__init__(parent) self.move_y_with_drag = True - self.scene_manager = SpectrogramSceneManager(np.zeros(1, dtype=np.complex64), parent=self) + self.scene_manager = SpectrogramSceneManager( + np.zeros(1, dtype=np.complex64), parent=self + ) self.setScene(self.scene_manager.scene) @property @@ -54,16 +56,22 @@ def create_context_menu(self): filter_bw = Filter.read_configured_filter_bw() text = self.tr("Apply bandpass filter (filter bw={0:n})".format(filter_bw)) create_from_frequency_selection = menu.addAction(text) - create_from_frequency_selection.triggered.connect(self.on_create_from_frequency_selection_triggered) + create_from_frequency_selection.triggered.connect( + self.on_create_from_frequency_selection_triggered + ) create_from_frequency_selection.setIcon(QIcon.fromTheme("view-filter")) try: - cancel_button = " or ".join(k.toString() for k in QKeySequence.keyBindings(QKeySequence.Cancel)) + cancel_button = " or ".join( + k.toString() for k in QKeySequence.keyBindings(QKeySequence.Cancel) + ) except Exception as e: logger.debug("Error reading cancel button: " + str(e)) cancel_button = "Esc" - create_from_frequency_selection.setToolTip("You can abort filtering with {}.".format(cancel_button)) + create_from_frequency_selection.setToolTip( + "You can abort filtering with {}.".format(cancel_button) + ) configure_filter_bw = menu.addAction(self.tr("Configure filter bandwidth...")) configure_filter_bw.triggered.connect(self.on_configure_filter_bw_triggered) @@ -91,7 +99,9 @@ def auto_fit_view(self): def emit_selection_start_end_changed(self): h = self.sceneRect().height() - self.sel_area_start_end_changed.emit(h - self.selection_area.end, h - self.selection_area.start) + self.sel_area_start_end_changed.emit( + h - self.selection_area.end, h - self.selection_area.start + ) @pyqtSlot() def on_create_from_frequency_selection_triggered(self): @@ -110,7 +120,7 @@ def on_configure_filter_bw_triggered(self): @pyqtSlot() def on_export_fta_action_triggered(self): - if not(self.scene_manager and self.scene_manager.spectrogram): + if not (self.scene_manager and self.scene_manager.spectrogram): return self.export_fta_wanted.emit() diff --git a/src/urh/ui/views/TableView.py b/src/urh/ui/views/TableView.py index 00e8b44eea..acc99d95ff 100644 --- a/src/urh/ui/views/TableView.py +++ b/src/urh/ui/views/TableView.py @@ -21,8 +21,10 @@ def __init__(self, parent=None): self.use_header_colors = False self.original_font_size = self.font().pointSize() - self.original_header_font_sizes = {"vertical": self.verticalHeader().font().pointSize(), - "horizontal": self.horizontalHeader().font().pointSize()} + self.original_header_font_sizes = { + "vertical": self.verticalHeader().font().pointSize(), + "horizontal": self.horizontalHeader().font().pointSize(), + } self.zoom_in_action = QAction(self.tr("Zoom in"), self) self.zoom_in_action.setShortcut(QKeySequence.ZoomIn) @@ -40,7 +42,9 @@ def __init__(self, parent=None): self.zoom_original_action = QAction(self.tr("Zoom original"), self) self.zoom_original_action.setShortcut(QKeySequence(Qt.CTRL + Qt.Key_0)) - self.zoom_original_action.triggered.connect(self.on_zoom_original_action_triggered) + self.zoom_original_action.triggered.connect( + self.on_zoom_original_action_triggered + ) self.zoom_original_action.setShortcutContext(Qt.WidgetWithChildrenShortcut) self.zoom_original_action.setIcon(QIcon.fromTheme("zoom-original")) self.addAction(self.zoom_original_action) @@ -51,11 +55,19 @@ def _add_insert_column_menu(self, menu): column_menu = menu.addMenu("Insert column") insert_column_left_action = column_menu.addAction("on the left") - insert_column_left_action.triggered.connect(self.on_insert_column_left_action_triggered) - insert_column_left_action.setIcon(QIcon.fromTheme("edit-table-insert-column-left")) + insert_column_left_action.triggered.connect( + self.on_insert_column_left_action_triggered + ) + insert_column_left_action.setIcon( + QIcon.fromTheme("edit-table-insert-column-left") + ) insert_column_right_action = column_menu.addAction("on the right") - insert_column_right_action.setIcon(QIcon.fromTheme("edit-table-insert-column-right")) - insert_column_right_action.triggered.connect(self.on_insert_column_right_action_triggered) + insert_column_right_action.setIcon( + QIcon.fromTheme("edit-table-insert-column-right") + ) + insert_column_right_action.triggered.connect( + self.on_insert_column_right_action_triggered + ) def selectionModel(self) -> QItemSelectionModel: return super().selectionModel() @@ -126,8 +138,10 @@ def create_context_menu(self) -> QMenu: if self.context_menu_pos is None: return menu - selected_label_index = self.model().get_selected_label_index(row=self.rowAt(self.context_menu_pos.y()), - column=self.columnAt(self.context_menu_pos.x())) + selected_label_index = self.model().get_selected_label_index( + row=self.rowAt(self.context_menu_pos.y()), + column=self.columnAt(self.context_menu_pos.x()), + ) if self.model().row_count > 0: if selected_label_index == -1: @@ -137,7 +151,9 @@ def create_context_menu(self) -> QMenu: label_action = menu.addAction("Edit label...") label_action.setIcon(QIcon.fromTheme("configure")) - label_action.triggered.connect(self.on_create_or_edit_label_action_triggered) + label_action.triggered.connect( + self.on_create_or_edit_label_action_triggered + ) menu.addSeparator() zoom_menu = menu.addMenu("Zoom font size") @@ -180,7 +196,9 @@ def resize_vertical_header(self): num_rows = self.model().rowCount() if self.isVisible() and num_rows > 0: hd = self.model().headerData - max_len = np.max([len(str(hd(i, Qt.Vertical, Qt.DisplayRole))) for i in range(num_rows)]) + max_len = np.max( + [len(str(hd(i, Qt.Vertical, Qt.DisplayRole))) for i in range(num_rows)] + ) w = (self.font().pointSize() + 2) * max_len # https://github.com/jopohl/urh/issues/182 @@ -216,8 +234,10 @@ def keyPressEvent(self, event: QKeyEvent): self.model().insert_column(start, list(range(min_row, max_row + 1))) - if event.key() not in (Qt.Key_Right, Qt.Key_Left, Qt.Key_Up, Qt.Key_Down) \ - or event.modifiers() == Qt.ShiftModifier: + if ( + event.key() not in (Qt.Key_Right, Qt.Key_Left, Qt.Key_Up, Qt.Key_Down) + or event.modifiers() == Qt.ShiftModifier + ): super().keyPressEvent(event) return @@ -314,8 +334,10 @@ def on_insert_column_right_action_triggered(self): @pyqtSlot() def on_create_or_edit_label_action_triggered(self): - selected_label_index = self.model().get_selected_label_index(row=self.rowAt(self.context_menu_pos.y()), - column=self.columnAt(self.context_menu_pos.x())) + selected_label_index = self.model().get_selected_label_index( + row=self.rowAt(self.context_menu_pos.y()), + column=self.columnAt(self.context_menu_pos.x()), + ) if selected_label_index == -1: min_row, max_row, start, end = self.selection_range() self.create_label_triggered.emit(min_row, start, end) diff --git a/src/urh/ui/views/TextEditProtocolView.py b/src/urh/ui/views/TextEditProtocolView.py index 0afb55d909..4d92b9f1eb 100644 --- a/src/urh/ui/views/TextEditProtocolView.py +++ b/src/urh/ui/views/TextEditProtocolView.py @@ -17,7 +17,7 @@ def __init__(self, parent=None): @property def selected_text(self): - return self.textCursor().selectedText().replace('\u2028', '\n') + return self.textCursor().selectedText().replace("\u2028", "\n") def keyPressEvent(self, event: QKeyEvent): if event.key() == Qt.Key_Delete: @@ -98,8 +98,8 @@ def create_context_menu(self) -> QMenu: cursor = self.textCursor() if self.participants and self.messages and not cursor.selection().isEmpty(): self.selected_messages = [] - start_msg = self.toPlainText()[0:cursor.selectionStart()].count("\n") - end_msg = self.toPlainText()[0:cursor.selectionEnd()].count("\n") + 1 + start_msg = self.toPlainText()[0 : cursor.selectionStart()].count("\n") + end_msg = self.toPlainText()[0 : cursor.selectionEnd()].count("\n") + 1 for i in range(start_msg, end_msg): self.selected_messages.append(self.messages[i]) @@ -113,13 +113,17 @@ def create_context_menu(self) -> QMenu: none_participant_action = participant_menu.addAction("None") none_participant_action.setCheckable(True) none_participant_action.setActionGroup(participant_group) - none_participant_action.triggered.connect(self.on_none_participant_action_triggered) + none_participant_action.triggered.connect( + self.on_none_participant_action_triggered + ) if selected_msg and selected_msg.participant is None: none_participant_action.setChecked(True) for participant in self.participants: - pa = participant_menu.addAction(participant.name + " (" + participant.shortname + ")") + pa = participant_menu.addAction( + participant.name + " (" + participant.shortname + ")" + ) pa.setCheckable(True) pa.setActionGroup(participant_group) if selected_msg and selected_msg.participant == participant: @@ -134,7 +138,9 @@ def create_context_menu(self) -> QMenu: menu.addSeparator() - line_wrap_action = menu.addAction("Linewrap (may take a while for long protocols)") + line_wrap_action = menu.addAction( + "Linewrap (may take a while for long protocols)" + ) line_wrap_action.setCheckable(True) line_wrap = self.lineWrapMode() == QTextEdit.WidgetWidth line_wrap_action.setChecked(line_wrap) diff --git a/src/urh/ui/views/ZoomAndDropableGraphicView.py b/src/urh/ui/views/ZoomAndDropableGraphicView.py index 49aede97df..c6ae1ba072 100644 --- a/src/urh/ui/views/ZoomAndDropableGraphicView.py +++ b/src/urh/ui/views/ZoomAndDropableGraphicView.py @@ -65,9 +65,11 @@ def auto_fit_view(self): plot_min, plot_max = util.minmax(self.signal.real_plot_data) data_min, data_max = IQArray.min_max_for_dtype(self.signal.real_plot_data.dtype) - self.scale(1, (data_max - data_min) / (plot_max-plot_min)) + self.scale(1, (data_max - data_min) / (plot_max - plot_min)) - self.centerOn(self.view_rect().x() + self.view_rect().width() / 2, self.y_center) + self.centerOn( + self.view_rect().x() + self.view_rect().width() / 2, self.y_center + ) def eliminate(self): # Do _not_ call eliminate() for self.signal and self.proto_analyzer diff --git a/src/urh/ui/views/ZoomableGraphicView.py b/src/urh/ui/views/ZoomableGraphicView.py index 600819e715..d18a2ac4c6 100644 --- a/src/urh/ui/views/ZoomableGraphicView.py +++ b/src/urh/ui/views/ZoomableGraphicView.py @@ -38,7 +38,9 @@ def __init__(self, parent=None): self.zoom_original_action = QAction(self.tr("Zoom original"), self) self.zoom_original_action.setShortcut(QKeySequence(Qt.CTRL + Qt.Key_0)) - self.zoom_original_action.triggered.connect(self.on_zoom_original_action_triggered) + self.zoom_original_action.triggered.connect( + self.on_zoom_original_action_triggered + ) self.zoom_original_action.setShortcutContext(Qt.WidgetWithChildrenShortcut) self.zoom_original_action.setIcon(QIcon.fromTheme("zoom-original")) self.addAction(self.zoom_original_action) @@ -60,7 +62,9 @@ def y_center(self): else: return -self.signal.center except Exception as e: - logger.error("Could not access y_center property: {0}. Falling back to 0".format(e)) + logger.error( + "Could not access y_center property: {0}. Falling back to 0".format(e) + ) return 0 def create_context_menu(self): @@ -97,7 +101,9 @@ def zoom(self, factor, zoom_to_mouse_cursor=True, cursor_pos=None): factor = self.view_rect().width() / self.MINIMUM_VIEW_WIDTH if zoom_to_mouse_cursor: - pos = self.mapFromGlobal(QCursor.pos()) if cursor_pos is None else cursor_pos + pos = ( + self.mapFromGlobal(QCursor.pos()) if cursor_pos is None else cursor_pos + ) else: pos = None old_pos = self.mapToScene(pos) if pos is not None else None @@ -134,14 +140,19 @@ def auto_fit_view(self): if abs(h_tar) > 0: self.scale(1, h_view / h_tar) - self.centerOn(self.view_rect().x() + self.view_rect().width() / 2, self.y_center) + self.centerOn( + self.view_rect().x() + self.view_rect().width() / 2, self.y_center + ) def show_full_scene(self, reinitialize=False): y_factor = self.transform().m22() self.resetTransform() # Use full self.width() here to enable show_full_scene when view_rect not yet set e.g. in Record Signal Dialog - x_factor = self.width() / ( - self.sceneRect().width() * self.scene_x_zoom_stretch) if self.sceneRect().width() else 1 + x_factor = ( + self.width() / (self.sceneRect().width() * self.scene_x_zoom_stretch) + if self.sceneRect().width() + else 1 + ) self.scale(x_factor, y_factor) self.centerOn(0, self.y_center) @@ -172,7 +183,9 @@ def redraw_view(self, reinitialize=False): vr = self.view_rect() start, end = vr.x(), vr.x() + vr.width() - self.scene_manager.show_scene_section(start, end, *self._get_sub_path_ranges_and_colors(start, end)) + self.scene_manager.show_scene_section( + start, end, *self._get_sub_path_ranges_and_colors(start, end) + ) if self.scene_type == 1: self.scene().redraw_legend() diff --git a/src/urh/ui/views/__init__.py b/src/urh/ui/views/__init__.py index 3fa5af38d8..813939aaf7 100644 --- a/src/urh/ui/views/__init__.py +++ b/src/urh/ui/views/__init__.py @@ -1 +1 @@ -__author__ = 'joe' +__author__ = "joe" diff --git a/src/urh/ui/xtra_icons_rc.py b/src/urh/ui/xtra_icons_rc.py index 1d893be3c9..d13b052843 100644 --- a/src/urh/ui/xtra_icons_rc.py +++ b/src/urh/ui/xtra_icons_rc.py @@ -60374,18 +60374,25 @@ \x00\x00\x01\x63\xee\xee\x7d\xe3\ " -qt_version = QtCore.qVersion().split('.') -if qt_version < ['5', '8', '0']: +qt_version = QtCore.qVersion().split(".") +if qt_version < ["5", "8", "0"]: rcc_version = 1 qt_resource_struct = qt_resource_struct_v1 else: rcc_version = 2 qt_resource_struct = qt_resource_struct_v2 + def qInitResources(): - QtCore.qRegisterResourceData(rcc_version, qt_resource_struct, qt_resource_name, qt_resource_data) + QtCore.qRegisterResourceData( + rcc_version, qt_resource_struct, qt_resource_name, qt_resource_data + ) + def qCleanupResources(): - QtCore.qUnregisterResourceData(rcc_version, qt_resource_struct, qt_resource_name, qt_resource_data) + QtCore.qUnregisterResourceData( + rcc_version, qt_resource_struct, qt_resource_name, qt_resource_data + ) + qInitResources() diff --git a/src/urh/util/Errors.py b/src/urh/util/Errors.py index d0bab9dc89..34d82a4c88 100644 --- a/src/urh/util/Errors.py +++ b/src/urh/util/Errors.py @@ -12,9 +12,13 @@ class Errors: def generic_error(title: str, msg: str, detailed_msg: str = None): w = QWidget() if detailed_msg: - msg = "Error: " + msg.replace("\n", - "
") + "
" + "

----------

" + detailed_msg.replace( - "\n", "
") + msg = ( + "Error: " + + msg.replace("\n", "
") + + "
" + + "

----------

" + + detailed_msg.replace("\n", "
") + ) QMessageBox.critical(w, title, msg) @staticmethod @@ -28,93 +32,124 @@ def exception(exception: Exception): @staticmethod def no_device(): w = QWidget() - QMessageBox.critical(w, w.tr("No devices"), - w.tr("You have to choose at least one available " - "device in Edit->Options->Device.")) + QMessageBox.critical( + w, + w.tr("No devices"), + w.tr( + "You have to choose at least one available " + "device in Edit->Options->Device." + ), + ) @staticmethod def empty_selection(): w = QWidget() - QMessageBox.critical(w, w.tr("No selection"), - w.tr("Your selection is empty!")) + QMessageBox.critical(w, w.tr("No selection"), w.tr("Your selection is empty!")) @staticmethod def write_error(msg): w = QWidget() - QMessageBox.critical(w, w.tr("Write error"), - w.tr("There was a error writing this file! {0}".format(msg))) + QMessageBox.critical( + w, + w.tr("Write error"), + w.tr("There was a error writing this file! {0}".format(msg)), + ) @staticmethod def usrp_found(): w = QWidget() - QMessageBox.critical(w, w.tr("USRP not found"), - w.tr("USRP could not be found . Is the IP " - "correct?")) + QMessageBox.critical( + w, + w.tr("USRP not found"), + w.tr("USRP could not be found . Is the IP " "correct?"), + ) @staticmethod def hackrf_not_found(): w = QWidget() if sys.platform == "win32": - msg = "Could not connect to HackRF. Try these solutions:" \ - "

1. Ensure HackRF is plugged in." \ - "
2. Install HackRF USB driver with Zadig." + msg = ( + "Could not connect to HackRF. Try these solutions:" + "

1. Ensure HackRF is plugged in." + "
2. Install HackRF USB driver with Zadig." + ) else: - msg = "Could not connect to HackRF. Try these solutions:" \ - "

1. Ensure HackRF is plugged in." \ - "
2. Run the command hackrf_info in terminal as root." \ - "
3. If 2. works for you, follow the instructions " \ - "here." + msg = ( + "Could not connect to HackRF. Try these solutions:" + "

1. Ensure HackRF is plugged in." + "
2. Run the command hackrf_info in terminal as root." + "
3. If 2. works for you, follow the instructions " + "here." + ) - QMessageBox.critical(w, w.tr("HackRF not found"), - w.tr(msg)) + QMessageBox.critical(w, w.tr("HackRF not found"), w.tr(msg)) @staticmethod def gnuradio_not_installed(): w = QWidget() - QMessageBox.critical(w, w.tr("GNU Radio not found"), - w.tr("You need to install GNU Radio for this " - "feature.")) + QMessageBox.critical( + w, + w.tr("GNU Radio not found"), + w.tr("You need to install GNU Radio for this " "feature."), + ) @staticmethod def rtlsdr_sdr_driver(): if sys.platform == "win32": w = QWidget() - QMessageBox.critical(w, w.tr("Could not access RTL-SDR device"), - w.tr("You may need to reinstall the driver with Zadig for 'Composite' device.
" - "See here " - "for more information.")) + QMessageBox.critical( + w, + w.tr("Could not access RTL-SDR device"), + w.tr( + "You may need to reinstall the driver with Zadig for 'Composite' device.
" + "See here " + "for more information." + ), + ) @staticmethod def empty_group(): w = QWidget() - QMessageBox.critical(w, w.tr("Empty group"), - w.tr("The group may not be empty.")) + QMessageBox.critical( + w, w.tr("Empty group"), w.tr("The group may not be empty.") + ) @staticmethod def invalid_path(path: str): w = QWidget() - QMessageBox.critical(w, w.tr("Invalid Path"), - w.tr("The path {0} is invalid.".format(path))) + QMessageBox.critical( + w, w.tr("Invalid Path"), w.tr("The path {0} is invalid.".format(path)) + ) @staticmethod def network_sdr_send_is_elsewhere(): w = QWidget() - QMessageBox.information(w, "This feature is elsewhere", "You can send your data with the network SDR by " - "using the button below the generator table.") + QMessageBox.information( + w, + "This feature is elsewhere", + "You can send your data with the network SDR by " + "using the button below the generator table.", + ) @staticmethod def not_enough_ram_for_sending_precache(memory_size_bytes): w = QWidget() if memory_size_bytes: - msg = "Precaching all your modulated data would take {0}B of memory, " \ - "which does not fit into your RAM.
".format(Formatter.big_value_with_suffix(memory_size_bytes)) + msg = ( + "Precaching all your modulated data would take {0}B of memory, " + "which does not fit into your RAM.
".format( + Formatter.big_value_with_suffix(memory_size_bytes) + ) + ) else: msg = "" - msg += "Sending will be done in continuous mode.

" \ - "This means, modulation will be performed live during sending.

" \ - "If you experience problems, " \ - "consider sending less messages or upgrade your RAM." + msg += ( + "Sending will be done in continuous mode.

" + "This means, modulation will be performed live during sending.

" + "If you experience problems, " + "consider sending less messages or upgrade your RAM." + ) QMessageBox.information(w, w.tr("Entering continuous send mode"), w.tr(msg)) diff --git a/src/urh/util/FileOperator.py b/src/urh/util/FileOperator.py index f82694d3d0..b9fc14f39f 100644 --- a/src/urh/util/FileOperator.py +++ b/src/urh/util/FileOperator.py @@ -22,7 +22,7 @@ np.int16: ".complex32s", np.uint16: ".complex32u", np.float32: ".complex", - np.complex64: ".complex" + np.complex64: ".complex", } SIGNAL_NAME_FILTERS_BY_TYPE = { @@ -31,7 +31,7 @@ np.uint16: "Complex32 unsigned (*.complex32u *.cu16)", np.int16: "Complex32 signed (*.complex32s *.cs16)", np.float32: "Complex (*.complex)", - np.complex64: "Complex (*.complex)" + np.complex64: "Complex (*.complex)", } EVERYTHING_FILE_FILTER = "All Files (*)" @@ -50,11 +50,18 @@ ZIP_FILE_FILTER = "Zip Archive (*.zip)" SUB_FILE_FILTER = "Flipper Zero SubGHz RAW (*.sub)" + def __get__name_filter_for_signals() -> str: - return ";;".join([EVERYTHING_FILE_FILTER] + SIGNAL_NAME_FILTERS + [COMPRESSED_COMPLEX_FILE_FILTER, WAV_FILE_FILTER, SUB_FILE_FILTER]) + return ";;".join( + [EVERYTHING_FILE_FILTER] + + SIGNAL_NAME_FILTERS + + [COMPRESSED_COMPLEX_FILE_FILTER, WAV_FILE_FILTER, SUB_FILE_FILTER] + ) -def get_open_dialog(directory_mode=False, parent=None, name_filter="full") -> QFileDialog: +def get_open_dialog( + directory_mode=False, parent=None, name_filter="full" +) -> QFileDialog: dialog = QFileDialog(parent=parent, directory=RECENT_PATH) if directory_mode: @@ -64,9 +71,21 @@ def get_open_dialog(directory_mode=False, parent=None, name_filter="full") -> QF dialog.setFileMode(QFileDialog.ExistingFiles) dialog.setWindowTitle("Open Files") if name_filter == "full": - name_filter = __get__name_filter_for_signals() + ";;" \ - + ";;".join([PROTOCOL_FILE_FILTER, BINARY_PROTOCOL_FILE_FILTER, PLAIN_BITS_FILE_FILTER, - FUZZING_FILE_FILTER, SIMULATOR_FILE_FILTER, TAR_FILE_FILTER, ZIP_FILE_FILTER]) + name_filter = ( + __get__name_filter_for_signals() + + ";;" + + ";;".join( + [ + PROTOCOL_FILE_FILTER, + BINARY_PROTOCOL_FILE_FILTER, + PLAIN_BITS_FILE_FILTER, + FUZZING_FILE_FILTER, + SIMULATOR_FILE_FILTER, + TAR_FILE_FILTER, + ZIP_FILE_FILTER, + ] + ) + ) elif name_filter == "signals_only": name_filter = __get__name_filter_for_signals() elif name_filter == "proto": @@ -81,7 +100,9 @@ def get_open_dialog(directory_mode=False, parent=None, name_filter="full") -> QF return dialog -def ask_save_file_name(initial_name: str, caption="Save signal", selected_name_filter=None): +def ask_save_file_name( + initial_name: str, caption="Save signal", selected_name_filter=None +): global RECENT_PATH if caption == "Save signal": name_filter = __get__name_filter_for_signals() @@ -94,7 +115,9 @@ def ask_save_file_name(initial_name: str, caption="Save signal", selected_name_f elif caption == "Export spectrogram": name_filter = "Frequency Time (*.ft);;Frequency Time Amplitude (*.fta)" elif caption == "Save protocol": - name_filter = ";;".join([PROTOCOL_FILE_FILTER, BINARY_PROTOCOL_FILE_FILTER, WIRESHARK_FILE_FILTER]) + name_filter = ";;".join( + [PROTOCOL_FILE_FILTER, BINARY_PROTOCOL_FILE_FILTER, WIRESHARK_FILE_FILTER] + ) elif caption == "Export demodulated": name_filter = ";;".join([WAV_FILE_FILTER, SUB_FILE_FILTER]) else: @@ -120,15 +143,21 @@ def ask_save_file_name(initial_name: str, caption="Save signal", selected_name_f return filename -def ask_signal_file_name_and_save(signal_name: str, data, sample_rate=1e6, wav_only=False, parent=None) -> str: +def ask_signal_file_name_and_save( + signal_name: str, data, sample_rate=1e6, wav_only=False, parent=None +) -> str: if wav_only: if not signal_name.endswith(".wav") and not signal_name.endswith(".wave"): signal_name += ".wav" selected_name_filter = WAV_FILE_FILTER else: - if not any(signal_name.endswith(e) for e in SIGNAL_NAME_FILTERS_BY_TYPE.values()): + if not any( + signal_name.endswith(e) for e in SIGNAL_NAME_FILTERS_BY_TYPE.values() + ): try: - dtype = next(d for d in SIGNAL_FILE_EXTENSIONS_BY_TYPE.keys() if d == data.dtype) + dtype = next( + d for d in SIGNAL_FILE_EXTENSIONS_BY_TYPE.keys() if d == data.dtype + ) signal_name += SIGNAL_FILE_EXTENSIONS_BY_TYPE[dtype] selected_name_filter = SIGNAL_NAME_FILTERS_BY_TYPE[dtype] except StopIteration: @@ -136,7 +165,9 @@ def ask_signal_file_name_and_save(signal_name: str, data, sample_rate=1e6, wav_o else: selected_name_filter = None - filename = ask_save_file_name(signal_name, selected_name_filter=selected_name_filter) + filename = ask_save_file_name( + signal_name, selected_name_filter=selected_name_filter + ) if filename: try: @@ -167,7 +198,9 @@ def save_data(data, filename: str, sample_rate=1e6, num_channels=2): archive = archives[filename] if archive.endswith("zip"): rewrite_zip(archive) - elif archive.endswith("tar") or archive.endswith("bz2") or archive.endswith("gz"): + elif ( + archive.endswith("tar") or archive.endswith("bz2") or archive.endswith("gz") + ): rewrite_tar(archive) @@ -178,9 +211,9 @@ def save_signal(signal): def rewrite_zip(zip_name): tempdir = tempfile.mkdtemp() try: - temp_name = os.path.join(tempdir, 'new.zip') + temp_name = os.path.join(tempdir, "new.zip") files_in_archive = [f for f in archives.keys() if archives[f] == zip_name] - with zipfile.ZipFile(temp_name, 'w') as zip_write: + with zipfile.ZipFile(temp_name, "w") as zip_write: for filename in files_in_archive: zip_write.write(filename) shutil.move(temp_name, zip_name) @@ -197,9 +230,9 @@ def rewrite_tar(tar_name: str): compression = "bz2" try: ext = "" if len(compression) == 0 else "." + compression - temp_name = os.path.join(tempdir, 'new.tar' + ext) + temp_name = os.path.join(tempdir, "new.tar" + ext) files_in_archive = [f for f in archives.keys() if archives[f] == tar_name] - with tarfile.open(temp_name, 'w:' + compression) as tar_write: + with tarfile.open(temp_name, "w:" + compression) as tar_write: for file in files_in_archive: tar_write.add(file) shutil.move(temp_name, tar_name) @@ -218,7 +251,11 @@ def uncompress_archives(file_names, temp_dir): """ result = [] for filename in file_names: - if filename.endswith(".tar") or filename.endswith(".tar.gz") or filename.endswith(".tar.bz2"): + if ( + filename.endswith(".tar") + or filename.endswith(".tar.gz") + or filename.endswith(".tar.bz2") + ): obj = tarfile.open(filename, "r") extracted_file_names = [] for j, member in enumerate(obj.getmembers()): @@ -243,6 +280,10 @@ def uncompress_archives(file_names, temp_dir): def get_directory(): - directory = QFileDialog.getExistingDirectory(None, "Choose Directory", QDir.homePath(), - QFileDialog.ShowDirsOnly | QFileDialog.DontResolveSymlinks) + directory = QFileDialog.getExistingDirectory( + None, + "Choose Directory", + QDir.homePath(), + QFileDialog.ShowDirsOnly | QFileDialog.DontResolveSymlinks, + ) return directory diff --git a/src/urh/util/Formatter.py b/src/urh/util/Formatter.py index 9265f25d71..b3dd734746 100644 --- a/src/urh/util/Formatter.py +++ b/src/urh/util/Formatter.py @@ -8,7 +8,9 @@ def local_decimal_seperator(): return locale.localeconv()["decimal_point"] @staticmethod - def science_time(time_in_seconds: float, decimals=2, append_seconds=True, remove_spaces=False) -> str: + def science_time( + time_in_seconds: float, decimals=2, append_seconds=True, remove_spaces=False + ) -> str: if time_in_seconds < 1e-6: suffix = "n" value = time_in_seconds * 1e9 @@ -51,11 +53,14 @@ def big_value_with_suffix(value: float, decimals=3, strip_zeros=True) -> str: return result + suffix - @staticmethod def str2val(str_val, dtype, default=0): try: return dtype(str_val) except (ValueError, TypeError): - logger.warning("The {0} is not a valid {1}, assuming {2}".format(str_val, str(dtype), str(default))) + logger.warning( + "The {0} is not a valid {1}, assuming {2}".format( + str_val, str(dtype), str(default) + ) + ) return default diff --git a/src/urh/util/GenericCRC.py b/src/urh/util/GenericCRC.py index b39621b7a4..88a38c3a91 100755 --- a/src/urh/util/GenericCRC.py +++ b/src/urh/util/GenericCRC.py @@ -9,49 +9,73 @@ class GenericCRC(object): # https://en.wikipedia.org/wiki/Polynomial_representations_of_cyclic_redundancy_checks - DEFAULT_POLYNOMIALS = OrderedDict([ - # x^8 + x^7 + x^6 + x^4 + x^2 + 1 - ("8_standard", array.array("B", [1, - 1, 1, 0, 1, 0, 1, 0, 1])), - - # x^16+x^15+x^2+x^0 - ("16_standard", array.array("B", [1, - 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1])), - - # x^16+x^12+x^5+x^0 - ("16_ccitt", array.array("B", [1, - 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1])), - - # x^16+x^13+x^12+x^11+x^10+x^8+x^6+x^5+x^2+x^0 - ("16_dnp", array.array("B", [1, - 0, 0, 1, 1, 1, 1, 0, 1, 0, 1, 1, 0, 0, 1, 0, 1])), - - # x^8 + x^2 + x + 1 - ("8_ccitt", array.array("B", [1, - 0, 0, 0, 0, 0, 1, 1, 1])) - ]) - - STANDARD_CHECKSUMS = OrderedDict([ - # see method guess_standard_parameters_and_datarange for default parameters - # Links: - # - https://en.wikipedia.org/wiki/Cyclic_redundancy_check - # - http://reveng.sourceforge.net/crc-catalogue/1-15.htm - # - https://crccalc.com/ - ("CRC8 (default)", dict(polynomial="0xD5")), - ("CRC8 CCITT", dict(polynomial="0x07")), - ("CRC8 Bluetooth", dict(polynomial="0xA7", ref_in=True, ref_out=True)), - ("CRC8 DARC", dict(polynomial="0x39", ref_in=True, ref_out=True)), - ("CRC8 NRSC-5", dict(polynomial="0x31", start_value=1)), - ("CRC16 (default)", dict(polynomial="0x8005", ref_in=True, ref_out=True)), - ("CRC16 CCITT", dict(polynomial="0x1021", ref_in=True, ref_out=True)), - ("CRC16 NRSC-5", dict(polynomial="0x080B", start_value=1, ref_in=True, ref_out=True)), - ("CRC16 CC1101", dict(polynomial="0x8005", start_value=1)), - ("CRC16 CDMA2000", dict(polynomial="0xC867", start_value=1)), - ("CRC32 (default)", dict(polynomial="0x04C11DB7", start_value=1, final_xor=1, ref_in=True, ref_out=True)), - ]) - - def __init__(self, polynomial="16_standard", start_value=False, final_xor=False, reverse_polynomial=False, - reverse_all=False, little_endian=False, lsb_first=False): + DEFAULT_POLYNOMIALS = OrderedDict( + [ + # x^8 + x^7 + x^6 + x^4 + x^2 + 1 + ("8_standard", array.array("B", [1, 1, 1, 0, 1, 0, 1, 0, 1])), + # x^16+x^15+x^2+x^0 + ( + "16_standard", + array.array("B", [1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1]), + ), + # x^16+x^12+x^5+x^0 + ( + "16_ccitt", + array.array("B", [1, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1]), + ), + # x^16+x^13+x^12+x^11+x^10+x^8+x^6+x^5+x^2+x^0 + ( + "16_dnp", + array.array("B", [1, 0, 0, 1, 1, 1, 1, 0, 1, 0, 1, 1, 0, 0, 1, 0, 1]), + ), + # x^8 + x^2 + x + 1 + ("8_ccitt", array.array("B", [1, 0, 0, 0, 0, 0, 1, 1, 1])), + ] + ) + + STANDARD_CHECKSUMS = OrderedDict( + [ + # see method guess_standard_parameters_and_datarange for default parameters + # Links: + # - https://en.wikipedia.org/wiki/Cyclic_redundancy_check + # - http://reveng.sourceforge.net/crc-catalogue/1-15.htm + # - https://crccalc.com/ + ("CRC8 (default)", dict(polynomial="0xD5")), + ("CRC8 CCITT", dict(polynomial="0x07")), + ("CRC8 Bluetooth", dict(polynomial="0xA7", ref_in=True, ref_out=True)), + ("CRC8 DARC", dict(polynomial="0x39", ref_in=True, ref_out=True)), + ("CRC8 NRSC-5", dict(polynomial="0x31", start_value=1)), + ("CRC16 (default)", dict(polynomial="0x8005", ref_in=True, ref_out=True)), + ("CRC16 CCITT", dict(polynomial="0x1021", ref_in=True, ref_out=True)), + ( + "CRC16 NRSC-5", + dict(polynomial="0x080B", start_value=1, ref_in=True, ref_out=True), + ), + ("CRC16 CC1101", dict(polynomial="0x8005", start_value=1)), + ("CRC16 CDMA2000", dict(polynomial="0xC867", start_value=1)), + ( + "CRC32 (default)", + dict( + polynomial="0x04C11DB7", + start_value=1, + final_xor=1, + ref_in=True, + ref_out=True, + ), + ), + ] + ) + + def __init__( + self, + polynomial="16_standard", + start_value=False, + final_xor=False, + reverse_polynomial=False, + reverse_all=False, + little_endian=False, + lsb_first=False, + ): if isinstance(polynomial, str): self.caption = polynomial else: @@ -70,24 +94,42 @@ def __init__(self, polynomial="16_standard", start_value=False, final_xor=False, def __read_parameter(self, value): if isinstance(value, bool) or isinstance(value, int): - return array.array('B', [value] * (self.poly_order - 1)) + return array.array("B", [value] * (self.poly_order - 1)) else: if len(value) == self.poly_order - 1: return value else: - return array.array('B', value[0] * (self.poly_order - 1)) + return array.array("B", value[0] * (self.poly_order - 1)) def __eq__(self, other): if not isinstance(other, GenericCRC): return False - return all(getattr(self, attrib) == getattr(other, attrib) for attrib in ( - "polynomial", "reverse_polynomial", "reverse_all", "little_endian", "lsb_first", "start_value", - "final_xor")) + return all( + getattr(self, attrib) == getattr(other, attrib) + for attrib in ( + "polynomial", + "reverse_polynomial", + "reverse_all", + "little_endian", + "lsb_first", + "start_value", + "final_xor", + ) + ) def __hash__(self): - return hash((self.polynomial.tobytes(), self.reverse_polynomial, self.reverse_all, self.little_endian, - self.lsb_first, self.start_value.tobytes(), self.final_xor.tobytes())) + return hash( + ( + self.polynomial.tobytes(), + self.reverse_polynomial, + self.reverse_all, + self.little_endian, + self.lsb_first, + self.start_value.tobytes(), + self.final_xor.tobytes(), + ) + ) @property def poly_order(self): @@ -133,27 +175,44 @@ def choose_polynomial(self, polynomial): return polynomial def get_parameters(self): - return self.polynomial, self.start_value, self.final_xor, \ - self.lsb_first, self.reverse_polynomial, self.reverse_all, self.little_endian + return ( + self.polynomial, + self.start_value, + self.final_xor, + self.lsb_first, + self.reverse_polynomial, + self.reverse_all, + self.little_endian, + ) def crc(self, inpt): - result = c_util.crc(array.array("B", inpt), - array.array("B", self.polynomial), - array.array("B", self.start_value), - array.array("B", self.final_xor), - self.lsb_first, self.reverse_polynomial, self.reverse_all, self.little_endian) + result = c_util.crc( + array.array("B", inpt), + array.array("B", self.polynomial), + array.array("B", self.start_value), + array.array("B", self.final_xor), + self.lsb_first, + self.reverse_polynomial, + self.reverse_all, + self.little_endian, + ) return util.number_to_bits(result, self.poly_order - 1) def cached_crc(self, inpt, bits=8): if len(self.cache) == 0: self.calculate_cache(bits) - result = c_util.cached_crc(self.cache, - self.__cache_bits, - array.array("B", inpt), - array.array("B", self.polynomial), - array.array("B", self.start_value), - array.array("B", self.final_xor), - self.lsb_first, self.reverse_polynomial, self.reverse_all, self.little_endian) + result = c_util.cached_crc( + self.cache, + self.__cache_bits, + array.array("B", inpt), + array.array("B", self.polynomial), + array.array("B", self.start_value), + array.array("B", self.final_xor), + self.lsb_first, + self.reverse_polynomial, + self.reverse_all, + self.little_endian, + ) return util.number_to_bits(result, self.poly_order - 1) def calculate_cache(self, bits=8): @@ -161,26 +220,33 @@ def calculate_cache(self, bits=8): self.__cache_bits = bits else: self.__cache_bits = 8 if self.poly_order > 8 else self.poly_order - 1 - self.cache = c_util.calculate_cache(array.array("B", self.polynomial), self.reverse_polynomial, - self.__cache_bits) + self.cache = c_util.calculate_cache( + array.array("B", self.polynomial), + self.reverse_polynomial, + self.__cache_bits, + ) def get_crc_datarange(self, inpt, vrfy_crc_start): - return c_util.get_crc_datarange(array.array("B", inpt), - array.array("B", self.polynomial), - vrfy_crc_start, - array.array("B", self.start_value), - array.array("B", self.final_xor), - self.lsb_first, self.reverse_polynomial, self.reverse_all, self.little_endian) + return c_util.get_crc_datarange( + array.array("B", inpt), + array.array("B", self.polynomial), + vrfy_crc_start, + array.array("B", self.start_value), + array.array("B", self.final_xor), + self.lsb_first, + self.reverse_polynomial, + self.reverse_all, + self.little_endian, + ) def reference_crc(self, inpt): len_inpt = len(inpt) if len(self.start_value) < self.poly_order - 1: return False - crc = copy.copy(self.start_value[0:(self.poly_order - 1)]) + crc = copy.copy(self.start_value[0 : (self.poly_order - 1)]) for i in range(0, len_inpt + 7, 8): for j in range(0, 8): - if self.lsb_first: idx = i + (7 - j) else: @@ -190,7 +256,9 @@ def reference_crc(self, inpt): break if crc[0] != inpt[idx]: - crc[0:self.poly_order - 2] = crc[1:self.poly_order - 1] # crc = crc << 1 + crc[0 : self.poly_order - 2] = crc[ + 1 : self.poly_order - 1 + ] # crc = crc << 1 crc[self.poly_order - 2] = False for x in range(0, self.poly_order - 1): if self.reverse_polynomial: @@ -198,7 +266,9 @@ def reference_crc(self, inpt): else: crc[x] ^= self.polynomial[x + 1] else: - crc[0:self.poly_order - 2] = crc[1:self.poly_order - 1] # crc = crc << 1 + crc[0 : self.poly_order - 2] = crc[ + 1 : self.poly_order - 1 + ] # crc = crc << 1 crc[self.poly_order - 2] = False for i in range(0, self.poly_order - 1): @@ -227,8 +297,10 @@ def calculate(self, bits: array.array): @staticmethod def __swap_bytes(array, pos1: int, pos2: int): - array[pos1 * 8:pos1 * 8 + 8], array[pos2 * 8:pos2 * 8 + 8] = \ - array[pos2 * 8: pos2 * 8 + 8], array[pos1 * 8:pos1 * 8 + 8] + array[pos1 * 8 : pos1 * 8 + 8], array[pos2 * 8 : pos2 * 8 + 8] = ( + array[pos2 * 8 : pos2 * 8 + 8], + array[pos1 * 8 : pos1 * 8 + 8], + ) @staticmethod def from_standard_checksum(name: str): @@ -237,8 +309,16 @@ def from_standard_checksum(name: str): result.caption = name return result - def set_individual_parameters(self, polynomial, start_value=0, final_xor=0, ref_in=False, ref_out=False, - little_endian=False, reverse_polynomial=False): + def set_individual_parameters( + self, + polynomial, + start_value=0, + final_xor=0, + ref_in=False, + ref_out=False, + little_endian=False, + reverse_polynomial=False, + ): # Set polynomial from hex or bit array old = self.polynomial if isinstance(polynomial, str): @@ -253,7 +333,10 @@ def set_individual_parameters(self, polynomial, start_value=0, final_xor=0, ref_ # Set start value completely or 0000/FFFF if isinstance(start_value, int): self.start_value = array.array("B", [start_value] * (self.poly_order - 1)) - elif isinstance(start_value, array.array) and len(start_value) == self.poly_order - 1: + elif ( + isinstance(start_value, array.array) + and len(start_value) == self.poly_order - 1 + ): self.start_value = start_value else: raise ValueError("Invalid start value length") @@ -261,7 +344,9 @@ def set_individual_parameters(self, polynomial, start_value=0, final_xor=0, ref_ # Set final xor completely or 0000/FFFF if isinstance(final_xor, int): self.final_xor = array.array("B", [final_xor] * (self.poly_order - 1)) - elif isinstance(final_xor, array.array) and len(final_xor) == self.poly_order - 1: + elif ( + isinstance(final_xor, array.array) and len(final_xor) == self.poly_order - 1 + ): self.final_xor = final_xor else: raise ValueError("Invalid final xor length") @@ -283,7 +368,7 @@ def set_crc_parameters(self, i): old = self.polynomial self.polynomial = self.choose_polynomial(val) poly_order = len(self.polynomial) - if (self.polynomial != old): + if self.polynomial != old: self.cache = [] self.__cache_bits = 8 @@ -302,7 +387,7 @@ def set_crc_parameters(self, i): self.reverse_polynomial = False else: self.reverse_polynomial = True - if (self.reverse_polynomial != old_reverse): + if self.reverse_polynomial != old_reverse: self.cache = [] self.__cache_bits = 8 @@ -342,7 +427,9 @@ def __initialize_standard_checksums(cls): start_val = 0 if isinstance(start_val, int): - cls.STANDARD_CHECKSUMS[name]["start_value"] = array.array("B", [start_val] * n) + cls.STANDARD_CHECKSUMS[name]["start_value"] = array.array( + "B", [start_val] * n + ) try: final_xor = cls.STANDARD_CHECKSUMS[name]["final_xor"] @@ -350,7 +437,9 @@ def __initialize_standard_checksums(cls): final_xor = 0 if isinstance(final_xor, int): - cls.STANDARD_CHECKSUMS[name]["final_xor"] = array.array("B", [final_xor] * n) + cls.STANDARD_CHECKSUMS[name]["final_xor"] = array.array( + "B", [final_xor] * n + ) def guess_all(self, bits, trash_max=7, ignore_positions: set = None): """ @@ -386,7 +475,7 @@ def bruteforce_all(self, inpt, trash_max=7): def guess_standard_parameters(self, inpt, vrfy_crc): # Tests all standard parameters and return parameter_value (else False), if a valid CRC could be computed. # Note: vfry_crc is included inpt! - for i in range(0, 2 ** 8): + for i in range(0, 2**8): self.set_crc_parameters(i) if len(vrfy_crc) == self.poly_order and self.crc(inpt) == vrfy_crc: return i @@ -399,20 +488,23 @@ def guess_standard_parameters_and_datarange(self, inpt, trash): Note: vfry_crc is included inpt! """ # Test longer polynomials first, because smaller polynomials have higher risk of false positive - for name, parameters in sorted(self.STANDARD_CHECKSUMS.items(), - key=lambda x: len(x[1]["polynomial"]), - reverse=True): + for name, parameters in sorted( + self.STANDARD_CHECKSUMS.items(), + key=lambda x: len(x[1]["polynomial"]), + reverse=True, + ): self.caption = name - data_begin, data_end = c_util.get_crc_datarange(inpt, - parameters["polynomial"], - max(0, - len(inpt) - trash - len(parameters["polynomial"])) + 1, - parameters["start_value"], - parameters["final_xor"], - parameters.get("ref_in", False), - parameters.get("reverse_polynomial", False), - parameters.get("ref_out", False), - parameters.get("little_endian", False)) + data_begin, data_end = c_util.get_crc_datarange( + inpt, + parameters["polynomial"], + max(0, len(inpt) - trash - len(parameters["polynomial"])) + 1, + parameters["start_value"], + parameters["final_xor"], + parameters.get("ref_in", False), + parameters.get("reverse_polynomial", False), + parameters.get("ref_out", False), + parameters.get("little_endian", False), + ) if (data_begin, data_end) != (0, 0): self.set_individual_parameters(**parameters) return self, data_begin, data_end @@ -422,7 +514,7 @@ def bruteforce_parameters_and_data_range(self, inpt, vrfy_crc_start): # Tests all standard parameters and return parameter_value (else False), if a valid CRC could be computed # and determines start and end of crc datarange (end is set before crc) # Note: vfry_crc is included inpt! - for i in range(0, 2 ** 8): + for i in range(0, 2**8): self.set_crc_parameters(i) data_begin, data_end = self.get_crc_datarange(inpt, vrfy_crc_start) if (data_begin, data_end) != (0, 0): @@ -440,7 +532,9 @@ def reverse_engineer_polynomial(self, dataset, crcset): one_bitter_crc = [] for i in range(0, setlen): for j in range(i + 1, setlen): - if len(dataset[i]) == len(dataset[j]) and len(crcset[i]) == len(crcset[j]): + if len(dataset[i]) == len(dataset[j]) and len(crcset[i]) == len( + crcset[j] + ): count = 0 tmp = -1 for x in range(0, len(dataset[i])): @@ -460,7 +554,11 @@ def reverse_engineer_polynomial(self, dataset, crcset): setlen = len(one_bitter) for i in range(0, setlen): for j in range(0, setlen): - if i != j and one_bitter[i] + 1 == one_bitter[j] and one_bitter_crc[j][0] == True: + if ( + i != j + and one_bitter[i] + 1 == one_bitter[j] + and one_bitter_crc[j][0] == True + ): # Compute Polynomial polynomial = one_bitter_crc[i].copy() for x in range(0, len(one_bitter_crc[i]) - 1): @@ -484,9 +582,13 @@ def from_xml(cls, tag: ET.Element): final_xor = tag.get("final_xor", "0000") ref_in = bool(int(tag.get("ref_in", "0"))) ref_out = bool(int(tag.get("ref_out", "0"))) - return GenericCRC(polynomial=util.string2bits(polynomial), - start_value=util.string2bits(start_value), final_xor=util.string2bits(final_xor), - lsb_first=ref_in, reverse_all=ref_out) + return GenericCRC( + polynomial=util.string2bits(polynomial), + start_value=util.string2bits(start_value), + final_xor=util.string2bits(final_xor), + lsb_first=ref_in, + reverse_all=ref_out, + ) @staticmethod def bit2str(inpt): @@ -498,7 +600,7 @@ def str2bit(inpt): @staticmethod def int2bit(inpt): - return [True if x == "1" else False for x in '{0:08b}'.format(inpt)] + return [True if x == "1" else False for x in "{0:08b}".format(inpt)] @staticmethod def str2arr(inpt): @@ -511,4 +613,4 @@ def bit2int(inpt): @staticmethod def hex2str(inpt): bitstring = bin(int(inpt, base=16))[2:] - return "0" * (4 * len(inpt.lstrip('0x')) - len(bitstring)) + bitstring + return "0" * (4 * len(inpt.lstrip("0x")) - len(bitstring)) + bitstring diff --git a/src/urh/util/HTMLFormatter.py b/src/urh/util/HTMLFormatter.py index 2268577589..3207276d86 100644 --- a/src/urh/util/HTMLFormatter.py +++ b/src/urh/util/HTMLFormatter.py @@ -7,7 +7,9 @@ def monospace(string): def indent_string(string, depth=1): width = depth * INDENT_WIDTH_PX - return '
{1}
'.format(width, string) + return '
{1}
'.format( + width, string + ) def mark_differences(value: str, compare_against: str): @@ -27,6 +29,8 @@ def mark_differences(value: str, compare_against: str): def align_expected_and_got_value(expected: str, got: str, align_depth=1): width = align_depth * INDENT_WIDTH_PX got_marked = mark_differences(got, expected) - return '' \ - '' \ - '
Expected: {1}
Got: {2}
'.format(width, monospace(expected), monospace(got_marked)) + return ( + '' + "" + "
Expected: {1}
Got: {2}
".format(width, monospace(expected), monospace(got_marked)) + ) diff --git a/src/urh/util/Logger.py b/src/urh/util/Logger.py index 99d7df5e23..efcc367473 100644 --- a/src/urh/util/Logger.py +++ b/src/urh/util/Logger.py @@ -5,16 +5,16 @@ class Color: - PURPLE = '\033[95m' - CYAN = '\033[96m' - DARKCYAN = '\033[36m' - BLUE = '\033[94m' - GREEN = '\033[92m' - YELLOW = '\033[93m' - RED = '\033[91m' - BOLD = '\033[1m' - UNDERLINE = '\033[4m' - END = '\033[0m' + PURPLE = "\033[95m" + CYAN = "\033[96m" + DARKCYAN = "\033[36m" + BLUE = "\033[94m" + GREEN = "\033[92m" + YELLOW = "\033[93m" + RED = "\033[91m" + BOLD = "\033[1m" + UNDERLINE = "\033[4m" + END = "\033[0m" TMP = "/tmp" if sys.platform == "darwin" else tempfile.gettempdir() @@ -40,7 +40,7 @@ def save_log_level(): logger_conf = { "level": read_log_level(default=logging.DEBUG), - "format": '[%(levelname)s::%(filename)s::%(funcName)s] %(message)s' + "format": "[%(levelname)s::%(filename)s::%(funcName)s] %(message)s", } log_file_handler = None @@ -53,19 +53,24 @@ def save_log_level(): # Add the log message handler to the logger import logging.handlers - log_file_handler = logging.handlers.RotatingFileHandler(logfile_name, maxBytes=2e6, backupCount=5) + log_file_handler = logging.handlers.RotatingFileHandler( + logfile_name, maxBytes=2e6, backupCount=5 + ) logging.basicConfig(**logger_conf) logging_colors_per_level = { logging.WARNING: Color.YELLOW, logging.ERROR: Color.RED, - logging.CRITICAL: Color.RED + logging.CRITICAL: Color.RED, } for level, level_color in logging_colors_per_level.items(): if sys.platform != "win32": - logging.addLevelName(level, "{0}{1}{2}".format(level_color, logging.getLevelName(level), Color.END)) + logging.addLevelName( + level, + "{0}{1}{2}".format(level_color, logging.getLevelName(level), Color.END), + ) logger = logging.getLogger("urh") diff --git a/src/urh/util/ProjectManager.py b/src/urh/util/ProjectManager.py index d9d42f5bb9..53f1a0bc9f 100644 --- a/src/urh/util/ProjectManager.py +++ b/src/urh/util/ProjectManager.py @@ -27,10 +27,12 @@ class ProjectManager(QObject): def __init__(self, main_controller): super().__init__() self.main_controller = main_controller - self.device_conf = dict(frequency=config.DEFAULT_FREQUENCY, - sample_rate=config.DEFAULT_SAMPLE_RATE, - bandwidth=config.DEFAULT_BANDWIDTH, - name="USRP") + self.device_conf = dict( + frequency=config.DEFAULT_FREQUENCY, + sample_rate=config.DEFAULT_SAMPLE_RATE, + bandwidth=config.DEFAULT_BANDWIDTH, + name="USRP", + ) self.simulator_rx_conf = dict() self.simulator_tx_conf = dict() @@ -95,7 +97,9 @@ def project_file(self, value): def reload_field_types(self): self.field_types = FieldType.load_from_xml() - self.field_types_by_caption = {field_type.caption: field_type for field_type in self.field_types} + self.field_types_by_caption = { + field_type.caption: field_type for field_type in self.field_types + } def set_device_parameters(self, kwargs: dict): for key, value in kwargs.items(): @@ -118,24 +122,25 @@ def load_decodings(self): if self.project_file: return else: - prefix = os.path.realpath(os.path.join(settings.get_qt_settings_filename(), "..")) - - fallback = [Encoding(["Non Return To Zero (NRZ)"]), - - Encoding(["Non Return To Zero + Invert", - settings.DECODING_INVERT]), - - Encoding(["Manchester I", - settings.DECODING_EDGE]), - - Encoding(["Manchester II", - settings.DECODING_EDGE, - settings.DECODING_INVERT]), - - Encoding(["Differential Manchester", - settings.DECODING_EDGE, - settings.DECODING_DIFFERENTIAL]) - ] + prefix = os.path.realpath( + os.path.join(settings.get_qt_settings_filename(), "..") + ) + + fallback = [ + Encoding(["Non Return To Zero (NRZ)"]), + Encoding(["Non Return To Zero + Invert", settings.DECODING_INVERT]), + Encoding(["Manchester I", settings.DECODING_EDGE]), + Encoding( + ["Manchester II", settings.DECODING_EDGE, settings.DECODING_INVERT] + ), + Encoding( + [ + "Differential Manchester", + settings.DECODING_EDGE, + settings.DECODING_DIFFERENTIAL, + ] + ), + ] try: f = open(os.path.join(prefix, settings.DECODINGS_FILE), "r") @@ -171,7 +176,7 @@ def read_device_conf_dict(tag: ET.Element, target_dict): value = dev_tag.text if dev_tag.tag == "bit_len": - target_dict["samples_per_symbol"] = value # legacy + target_dict["samples_per_symbol"] = value # legacy else: target_dict[dev_tag.tag] = value @@ -184,15 +189,25 @@ def __device_conf_dict_to_xml(key_name: str, device_conf: dict): return result def simulator_rx_conf_to_xml(self) -> ET.Element: - return self.__device_conf_dict_to_xml("simulator_rx_conf", self.simulator_rx_conf) + return self.__device_conf_dict_to_xml( + "simulator_rx_conf", self.simulator_rx_conf + ) def simulator_tx_conf_to_xml(self) -> ET.Element: - return self.__device_conf_dict_to_xml("simulator_tx_conf", self.simulator_tx_conf) + return self.__device_conf_dict_to_xml( + "simulator_tx_conf", self.simulator_tx_conf + ) def read_parameters(self, root): - self.read_device_conf_dict(root.find("device_conf"), target_dict=self.device_conf) - self.read_device_conf_dict(root.find("simulator_rx_conf"), target_dict=self.simulator_rx_conf) - self.read_device_conf_dict(root.find("simulator_tx_conf"), target_dict=self.simulator_tx_conf) + self.read_device_conf_dict( + root.find("device_conf"), target_dict=self.device_conf + ) + self.read_device_conf_dict( + root.find("simulator_rx_conf"), target_dict=self.simulator_rx_conf + ) + self.read_device_conf_dict( + root.find("simulator_tx_conf"), target_dict=self.simulator_tx_conf + ) self.description = root.get("description", "").replace(self.NEWLINE_CODE, "\n") self.broadcast_address_hex = root.get("broadcast_address_hex", "ffff") @@ -204,7 +219,9 @@ def read_message_types(self): tree = ET.parse(self.project_file) root = tree.getroot() result = [] - for msg_type_tag in root.find("protocol").find("message_types").findall("message_type"): + for msg_type_tag in ( + root.find("protocol").find("message_types").findall("message_type") + ): result.append(MessageType.from_xml(msg_type_tag)) return result @@ -220,10 +237,13 @@ def set_project_folder(self, path, ask_for_new_project=True, close_all=True): collapse_project_tabs = False if not os.path.isfile(self.project_file): if ask_for_new_project: - reply = QMessageBox.question(self.main_controller, "Project File", - "Do you want to create a Project File for this folder?\n" - "If you chose No, you can do it later via File->Convert Folder to Project.", - QMessageBox.Yes | QMessageBox.No) + reply = QMessageBox.question( + self.main_controller, + "Project File", + "Do you want to create a Project File for this folder?\n" + "If you chose No, you can do it later via File->Convert Folder to Project.", + QMessageBox.Yes | QMessageBox.No, + ) if reply == QMessageBox.Yes: self.main_controller.show_project_settings() @@ -243,15 +263,20 @@ def set_project_folder(self, path, ask_for_new_project=True, close_all=True): self.modulation_was_edited = bool(int(root.get("modulation_was_edited", 0))) cfc = self.main_controller.compare_frame_controller self.read_parameters(root) - self.participants[:] = Participant.read_participants_from_xml_tag(xml_tag=root.find("protocol")) + self.participants[:] = Participant.read_participants_from_xml_tag( + xml_tag=root.find("protocol") + ) self.main_controller.add_files(self.read_opened_filenames()) self.read_compare_frame_groups(root) self.decodings = Encoding.read_decoders_from_xml_tag(root.find("protocol")) cfc.proto_analyzer.message_types[:] = self.read_message_types() cfc.message_type_table_model.update() - cfc.proto_analyzer.from_xml_tag(root=root.find("protocol"), participants=self.participants, - decodings=cfc.decodings) + cfc.proto_analyzer.from_xml_tag( + root=root.find("protocol"), + participants=self.participants, + decodings=cfc.decodings, + ) cfc.updateUI() @@ -263,7 +288,9 @@ def set_project_folder(self, path, ask_for_new_project=True, close_all=True): logger.exception(e) self.modulators = self.read_modulators_from_project_file() - self.main_controller.simulator_tab_controller.load_config_from_xml_tag(root.find("simulator_config")) + self.main_controller.simulator_tab_controller.load_config_from_xml_tag( + root.find("simulator_config") + ) if len(self.project_path) > 0 and self.project_file is None: self.main_controller.ui.actionConvert_Folder_to_Project.setEnabled(True) @@ -273,7 +300,10 @@ def set_project_folder(self, path, ask_for_new_project=True, close_all=True): self.main_controller.adjust_for_current_file(path) self.main_controller.filemodel.setRootPath(path) self.main_controller.ui.fileTree.setRootIndex( - self.main_controller.file_proxy_model.mapFromSource(self.main_controller.filemodel.index(path))) + self.main_controller.file_proxy_model.mapFromSource( + self.main_controller.filemodel.index(path) + ) + ) self.main_controller.ui.fileTree.setToolTip(path) self.main_controller.ui.splitter.setSizes([1, 1]) if collapse_project_tabs: @@ -375,7 +405,7 @@ def save_project(self, simulator_config=None): return # Recreate file - open(self.project_file, 'w').close() + open(self.project_file, "w").close() root = ET.Element("UniversalRadioHackerProject") tree = ET.ElementTree(root) tree.write(self.project_file) @@ -389,12 +419,17 @@ def save_project(self, simulator_config=None): root.append(self.simulator_rx_conf_to_xml()) root.append(self.simulator_tx_conf_to_xml()) root.set("description", str(self.description).replace("\n", self.NEWLINE_CODE)) - root.set("collapse_project_tabs", str(int(not self.main_controller.ui.tabParticipants.isVisible()))) + root.set( + "collapse_project_tabs", + str(int(not self.main_controller.ui.tabParticipants.isVisible())), + ) root.set("modulation_was_edited", str(int(self.modulation_was_edited))) root.set("broadcast_address_hex", str(self.broadcast_address_hex)) open_files = [] - for i, sf in enumerate(self.main_controller.signal_tab_controller.signal_frames): + for i, sf in enumerate( + self.main_controller.signal_tab_controller.signal_frames + ): self.write_signal_information_to_project_file(sf.signal, tree=tree) try: pf = self.main_controller.signal_protocol_dict[sf] @@ -434,15 +469,23 @@ def save_project(self, simulator_config=None): if proto_frame.filename: proto_tag = ET.SubElement(group_tag, "cf_protocol") try: - rel_file_name = os.path.relpath(proto_frame.filename, self.project_path) + rel_file_name = os.path.relpath( + proto_frame.filename, self.project_path + ) except ValueError: rel_file_name = proto_frame.filename proto_tag.set("filename", rel_file_name) - root.append(cfc.proto_analyzer.to_xml_tag(decodings=cfc.decodings, participants=self.participants, - messages=[msg for proto in cfc.full_protocol_list for msg in - proto.messages])) + root.append( + cfc.proto_analyzer.to_xml_tag( + decodings=cfc.decodings, + participants=self.participants, + messages=[ + msg for proto in cfc.full_protocol_list for msg in proto.messages + ], + ) + ) if simulator_config is not None: root.append(simulator_config.save_to_xml()) @@ -492,25 +535,37 @@ def read_project_file_for_signal(self, signal: Signal): if sig_tag.attrib["filename"] == signal_filename: signal.name = sig_tag.attrib["name"] center = sig_tag.get("qad_center", None) # legacy support - signal.center = float(sig_tag.get("center", 0)) if center is None else float(center) + signal.center = ( + float(sig_tag.get("center", 0)) if center is None else float(center) + ) signal.center_spacing = float(sig_tag.get("center_spacing", 0.1)) signal.tolerance = int(sig_tag.get("tolerance", 5)) signal.bits_per_symbol = int(sig_tag.get("bits_per_symbol", 1)) - signal.costas_loop_bandwidth = float(sig_tag.get("costas_loop_bandwidth", 0.1)) + signal.costas_loop_bandwidth = float( + sig_tag.get("costas_loop_bandwidth", 0.1) + ) signal.noise_threshold = float(sig_tag.get("noise_threshold", 0.1)) signal.sample_rate = float(sig_tag.get("sample_rate", 1e6)) - signal.samples_per_symbol = int(sig_tag.get("bit_length", 0)) # Legacy for old project files + signal.samples_per_symbol = int( + sig_tag.get("bit_length", 0) + ) # Legacy for old project files if signal.samples_per_symbol == 0: - signal.samples_per_symbol = int(sig_tag.get("samples_per_symbol", 100)) + signal.samples_per_symbol = int( + sig_tag.get("samples_per_symbol", 100) + ) try: # Legacy support when modulation type was integer - signal.modulation_type = Signal.MODULATION_TYPES[int(sig_tag.get("modulation_type", 0))] + signal.modulation_type = Signal.MODULATION_TYPES[ + int(sig_tag.get("modulation_type", 0)) + ] except (ValueError, IndexError): signal.modulation_type = sig_tag.get("modulation_type", "ASK") signal.pause_threshold = int(sig_tag.get("pause_threshold", 8)) - signal.message_length_divisor = int(sig_tag.get("message_length_divisor", 1)) + signal.message_length_divisor = int( + sig_tag.get("message_length_divisor", 1) + ) break return True @@ -525,7 +580,9 @@ def read_opened_filenames(self): pos = int(file_tag.attrib["position"]) filename = file_tag.attrib["name"] if not os.path.isfile(filename): - filename = os.path.normpath(os.path.join(self.project_path, filename)) + filename = os.path.normpath( + os.path.join(self.project_path, filename) + ) file_names.insert(pos, filename) QApplication.setOverrideCursor(Qt.WaitCursor) @@ -535,7 +592,9 @@ def read_opened_filenames(self): return [] def read_compare_frame_groups(self, root): - proto_tree_model = self.main_controller.compare_frame_controller.proto_tree_model + proto_tree_model = ( + self.main_controller.compare_frame_controller.proto_tree_model + ) tree_root = proto_tree_model.rootItem pfi = proto_tree_model.protocol_tree_items proto_frame_items = [item for item in pfi[0]] # type: list[ProtocolTreeItem] @@ -554,9 +613,17 @@ def read_compare_frame_groups(self, root): for proto_tag in group_tag.iter("cf_protocol"): filename = proto_tag.attrib["filename"] if not os.path.isfile(filename): - filename = os.path.normpath(os.path.join(self.project_path, filename)) + filename = os.path.normpath( + os.path.join(self.project_path, filename) + ) try: - proto_frame_item = next((p for p in proto_frame_items if p.protocol.filename == filename)) + proto_frame_item = next( + ( + p + for p in proto_frame_items + if p.protocol.filename == filename + ) + ) except StopIteration: proto_frame_item = None @@ -569,14 +636,20 @@ def read_compare_frame_groups(self, root): def from_dialog(self, dialog): if dialog.committed: - if dialog.new_project or not os.path.isfile(os.path.join(dialog.path, settings.PROJECT_FILE)): - self.set_project_folder(dialog.path, ask_for_new_project=False, close_all=False) + if dialog.new_project or not os.path.isfile( + os.path.join(dialog.path, settings.PROJECT_FILE) + ): + self.set_project_folder( + dialog.path, ask_for_new_project=False, close_all=False + ) self.device_conf["frequency"] = dialog.freq self.device_conf["sample_rate"] = dialog.sample_rate self.device_conf["gain"] = dialog.gain self.device_conf["bandwidth"] = dialog.bandwidth self.description = dialog.description - self.broadcast_address_hex = dialog.broadcast_address_hex.lower().replace(" ", "") + self.broadcast_address_hex = dialog.broadcast_address_hex.lower().replace( + " ", "" + ) if dialog.new_project: self.participants[:] = dialog.participants self.project_updated.emit() diff --git a/src/urh/util/RingBuffer.py b/src/urh/util/RingBuffer.py index 17634bdc9d..a0b9df30aa 100644 --- a/src/urh/util/RingBuffer.py +++ b/src/urh/util/RingBuffer.py @@ -8,11 +8,19 @@ class RingBuffer(object): """ A RingBuffer containing complex values. """ + def __init__(self, size: int, dtype=np.float32): self.dtype = dtype - types = {np.uint8: "B", np.int8: "b", np.int16: "h", np.uint16: "H", np.float32: "f", np.float64: "d"} - self.__data = Array(types[self.dtype], 2*size) + types = { + np.uint8: "B", + np.int8: "b", + np.int16: "h", + np.uint16: "H", + np.float32: "f", + np.float64: "d", + } + self.__data = Array(types[self.dtype], 2 * size) self.size = size self.__left_index = Value("L", 0) @@ -48,7 +56,9 @@ def space_left(self): @property def data(self): - return np.frombuffer(self.__data.get_obj(), dtype=self.dtype).reshape(len(self.__data) // 2, 2) + return np.frombuffer(self.__data.get_obj(), dtype=self.dtype).reshape( + len(self.__data) // 2, 2 + ) @property def view_data(self): @@ -78,12 +88,14 @@ def push(self, values: IQArray): if len(self) + n > self.size: raise ValueError("Too much data to push to RingBuffer") - slide_1 = np.s_[self.right_index:min(self.right_index + n, self.size)] - slide_2 = np.s_[:max(self.right_index + n - self.size, 0)] + slide_1 = np.s_[self.right_index : min(self.right_index + n, self.size)] + slide_2 = np.s_[: max(self.right_index + n - self.size, 0)] with self.__data.get_lock(): - data = np.frombuffer(self.__data.get_obj(), dtype=self.dtype).reshape(len(self.__data) // 2, 2) - data[slide_1] = values[:slide_1.stop - slide_1.start] - data[slide_2] = values[slide_1.stop - slide_1.start:] + data = np.frombuffer(self.__data.get_obj(), dtype=self.dtype).reshape( + len(self.__data) // 2, 2 + ) + data[slide_1] = values[: slide_1.stop - slide_1.start] + data[slide_2] = values[slide_1.stop - slide_1.start :] self.right_index += n self.__length.value += n @@ -108,17 +120,19 @@ def pop(self, number: int, ensure_even_length=False) -> np.ndarray: number = min(number, len(self)) with self.__data.get_lock(): - result = np.ones(2*number, dtype=self.dtype).reshape(number, 2) - data = np.frombuffer(self.__data.get_obj(), dtype=self.dtype).reshape(len(self.__data) // 2, 2) + result = np.ones(2 * number, dtype=self.dtype).reshape(number, 2) + data = np.frombuffer(self.__data.get_obj(), dtype=self.dtype).reshape( + len(self.__data) // 2, 2 + ) if self.left_index + number > len(data): end = len(data) - self.left_index else: end = number - result[:end] = data[self.left_index:self.left_index + end] + result[:end] = data[self.left_index : self.left_index + end] if end < number: - result[end:] = data[:number-end] + result[end:] = data[: number - end] self.left_index += number self.__length.value -= number diff --git a/src/urh/util/WSPChecksum.py b/src/urh/util/WSPChecksum.py index e4dc7efed2..ade07df8b4 100644 --- a/src/urh/util/WSPChecksum.py +++ b/src/urh/util/WSPChecksum.py @@ -19,8 +19,7 @@ class ChecksumMode(Enum): checksum8 = 2 crc8 = 3 - CRC_8_POLYNOMIAL = array.array("B", [1, - 0, 0, 0, 0, 0, 1, 1, 1]) # x^8+x^2+x+1 + CRC_8_POLYNOMIAL = array.array("B", [1, 0, 0, 0, 0, 0, 1, 1, 1]) # x^8+x^2+x+1 def __init__(self, mode=ChecksumMode.auto): self.mode = mode @@ -74,9 +73,15 @@ def search_for_wsp_checksum(cls, bits_behind_sync): return 0, 0, 0, 0 # Check for EOF rorg = bits_behind_sync[0:4].tobytes() - if rorg == array.array("B", [0, 1, 0, 1]).tobytes() or rorg == array.array("B", [0, 1, 1, 0]).tobytes(): + if ( + rorg == array.array("B", [0, 1, 0, 1]).tobytes() + or rorg == array.array("B", [0, 1, 1, 0]).tobytes() + ): # Switch telegram - if cls.checksum4(bits_behind_sync[-8:]).tobytes() == bits_behind_sync[-8:-4].tobytes(): + if ( + cls.checksum4(bits_behind_sync[-8:]).tobytes() + == bits_behind_sync[-8:-4].tobytes() + ): crc_start = len(bits_behind_sync) - 8 crc_stop = len(bits_behind_sync) - 4 data_stop = crc_start @@ -92,15 +97,15 @@ def checksum4(cls, bits: array.array) -> array.array: val = copy.copy(bits) val[-4:] = array.array("B", [False, False, False, False]) for i in range(0, len(val), 8): - hash += int("".join(map(str, map(int, val[i:i + 8]))), 2) - hash = (((hash & 0xf0) >> 4) + (hash & 0x0f)) & 0x0f + hash += int("".join(map(str, map(int, val[i : i + 8]))), 2) + hash = (((hash & 0xF0) >> 4) + (hash & 0x0F)) & 0x0F return array.array("B", list(map(bool, map(int, "{0:04b}".format(hash))))) @classmethod def checksum8(cls, bits: array.array) -> array.array: hash = 0 for i in range(0, len(bits) - 8, 8): - hash += int("".join(map(str, map(int, bits[i:i + 8]))), 2) + hash += int("".join(map(str, map(int, bits[i : i + 8]))), 2) return array.array("B", list(map(bool, map(int, "{0:08b}".format(hash % 256))))) @classmethod diff --git a/src/urh/util/__init__.py b/src/urh/util/__init__.py index 3fa5af38d8..813939aaf7 100644 --- a/src/urh/util/__init__.py +++ b/src/urh/util/__init__.py @@ -1 +1 @@ -__author__ = 'joe' +__author__ = "joe" diff --git a/src/urh/util/util.py b/src/urh/util/util.py index 97aa578cff..b7a55e1cda 100644 --- a/src/urh/util/util.py +++ b/src/urh/util/util.py @@ -21,7 +21,9 @@ PROJECT_PATH = None # for referencing in external program calls BCD_ERROR_SYMBOL = "?" -BCD_LUT = {"{0:04b}".format(i): str(i) if i < 10 else BCD_ERROR_SYMBOL for i in range(16)} +BCD_LUT = { + "{0:04b}".format(i): str(i) if i < 10 else BCD_ERROR_SYMBOL for i in range(16) +} BCD_REVERSE_LUT = {str(i): "{0:04b}".format(i) for i in range(10)} BCD_REVERSE_LUT[BCD_ERROR_SYMBOL] = "0000" @@ -42,6 +44,7 @@ def set_icon_theme(): if sys.platform != "linux" or settings.read("icon_theme_index", 0, int) == 0: # noinspection PyUnresolvedReferences import urh.ui.xtra_icons_rc + QIcon.setThemeName("oxy") else: QIcon.setThemeName("") @@ -49,6 +52,7 @@ def set_icon_theme(): def get_free_port(): import socket + s = socket.socket() s.bind(("", 0)) port = s.getsockname()[1] @@ -60,9 +64,8 @@ def set_shared_library_path(): shared_lib_dir = get_shared_library_path() if shared_lib_dir: - if sys.platform == "win32": - current_path = os.environ.get("PATH", '') + current_path = os.environ.get("PATH", "") if not current_path.startswith(shared_lib_dir): os.environ["PATH"] = shared_lib_dir + os.pathsep + current_path os.add_dll_directory(shared_lib_dir) @@ -70,6 +73,7 @@ def set_shared_library_path(): # LD_LIBRARY_PATH will not be considered at runtime so we explicitly load the .so's we need exts = [".so"] if sys.platform == "linux" else [".so", ".dylib"] import ctypes + libs = sorted(os.listdir(shared_lib_dir)) libusb = next((lib for lib in libs if "libusb" in lib), None) if libusb: @@ -90,19 +94,26 @@ def get_shared_library_path(): if hasattr(sys, "frozen"): return os.path.dirname(sys.executable) - util_dir = os.path.dirname(os.path.realpath(__file__)) if not os.path.islink(__file__) \ + util_dir = ( + os.path.dirname(os.path.realpath(__file__)) + if not os.path.islink(__file__) else os.path.dirname(os.path.realpath(os.readlink(__file__))) + ) urh_dir = os.path.realpath(os.path.join(util_dir, "..")) assert os.path.isdir(urh_dir) - shared_lib_dir = os.path.realpath(os.path.join(urh_dir, "dev", "native", "lib", "shared")) + shared_lib_dir = os.path.realpath( + os.path.join(urh_dir, "dev", "native", "lib", "shared") + ) if os.path.isdir(shared_lib_dir): return shared_lib_dir else: return "" -def convert_bits_to_string(bits, output_view_type: int, pad_zeros=False, lsb=False, lsd=False, endianness="big"): +def convert_bits_to_string( + bits, output_view_type: int, pad_zeros=False, lsb=False, lsd=False, endianness="big" +): """ Convert bit array to string :param endianness: Endianness little or big @@ -130,17 +141,31 @@ def convert_bits_to_string(bits, output_view_type: int, pad_zeros=False, lsb=Fal if endianness == "little": # reverse byte wise - bits_str = "".join(bits_str[max(i - 8, 0):i] for i in range(len(bits_str), 0, -8)) + bits_str = "".join( + bits_str[max(i - 8, 0) : i] for i in range(len(bits_str), 0, -8) + ) if output_view_type == 0: # bit result = bits_str elif output_view_type == 1: # hex - result = "".join(["{0:x}".format(int(bits_str[i:i + 4], 2)) for i in range(0, len(bits_str), 4)]) + result = "".join( + [ + "{0:x}".format(int(bits_str[i : i + 4], 2)) + for i in range(0, len(bits_str), 4) + ] + ) elif output_view_type == 2: # ascii - result = "".join(map(chr, - [int("".join(bits_str[i:i + 8]), 2) for i in range(0, len(bits_str), 8)])) + result = "".join( + map( + chr, + [ + int("".join(bits_str[i : i + 8]), 2) + for i in range(0, len(bits_str), 8) + ], + ) + ) elif output_view_type == 3: # decimal try: @@ -148,7 +173,9 @@ def convert_bits_to_string(bits, output_view_type: int, pad_zeros=False, lsb=Fal except ValueError: return None elif output_view_type == 4: # bcd - result = "".join([BCD_LUT[bits_str[i:i + 4]] for i in range(0, len(bits_str), 4)]) + result = "".join( + [BCD_LUT[bits_str[i : i + 4]] for i in range(0, len(bits_str), 4)] + ) else: raise ValueError("Unknown view type") @@ -209,7 +236,9 @@ def bcd2bit(value: str) -> array.array: return array.array("B", []) -def convert_string_to_bits(value: str, display_format: int, target_num_bits: int) -> array.array: +def convert_string_to_bits( + value: str, display_format: int, target_num_bits: int +) -> array.array: if display_format == 0: result = string2bits(value) elif display_format == 1: @@ -341,9 +370,20 @@ def get_default_windows_program_for_extension(extension: str): return DEFAULT_PROGRAMS_WINDOWS[extension] try: - assoc = subprocess.check_output("assoc " + extension, shell=True, stderr=subprocess.PIPE).decode().split("=")[1] - ftype = subprocess.check_output("ftype " + assoc, shell=True).decode().split("=")[1].split(" ")[0] - ftype = ftype.replace('"', '') + assoc = ( + subprocess.check_output( + "assoc " + extension, shell=True, stderr=subprocess.PIPE + ) + .decode() + .split("=")[1] + ) + ftype = ( + subprocess.check_output("ftype " + assoc, shell=True) + .decode() + .split("=")[1] + .split(" ")[0] + ) + ftype = ftype.replace('"', "") assert shutil.which(ftype) is not None except Exception: return None @@ -358,7 +398,7 @@ def parse_command(command: str): splitted = shlex.split(command, posix=posix) # strip quotations if not posix: - splitted = [s.replace('"', '').replace("'", "") for s in splitted] + splitted = [s.replace('"', "").replace("'", "") for s in splitted] except ValueError: splitted = [] # e.g. when missing matching " @@ -366,7 +406,11 @@ def parse_command(command: str): return "", [] cmd = splitted.pop(0) - if PROJECT_PATH is not None and not os.path.isabs(cmd) and shutil.which(cmd) is None: + if ( + PROJECT_PATH is not None + and not os.path.isabs(cmd) + and shutil.which(cmd) is None + ): # Path relative to project path cmd = os.path.normpath(os.path.join(PROJECT_PATH, cmd)) cmd = [cmd] @@ -378,14 +422,16 @@ def parse_command(command: str): return " ".join(cmd), splitted -def run_command(command, param: str = None, use_stdin=False, detailed_output=False, return_rc=False): +def run_command( + command, param: str = None, use_stdin=False, detailed_output=False, return_rc=False +): cmd, arg = parse_command(command) if shutil.which(cmd) is None: logger.error("Could not find {}".format(cmd)) return "" startupinfo = None - if os.name == 'nt': + if os.name == "nt": startupinfo = subprocess.STARTUPINFO() startupinfo.dwFlags |= subprocess.STARTF_USESHOWWINDOW if "." in cmd: @@ -400,7 +446,12 @@ def run_command(command, param: str = None, use_stdin=False, detailed_output=Fal if param is not None: call_list.append(param) - p = subprocess.Popen(call_list, stdout=subprocess.PIPE, stderr=subprocess.PIPE, startupinfo=startupinfo) + p = subprocess.Popen( + call_list, + stdout=subprocess.PIPE, + stderr=subprocess.PIPE, + startupinfo=startupinfo, + ) out, err = p.communicate() result = "{} exited with {}".format(" ".join(call_list), p.returncode) if out.decode(): @@ -413,8 +464,13 @@ def run_command(command, param: str = None, use_stdin=False, detailed_output=Fal else: return result elif use_stdin: - p = subprocess.Popen(call_list, stdout=subprocess.PIPE, stdin=subprocess.PIPE, stderr=subprocess.PIPE, - startupinfo=startupinfo) + p = subprocess.Popen( + call_list, + stdout=subprocess.PIPE, + stdin=subprocess.PIPE, + stderr=subprocess.PIPE, + startupinfo=startupinfo, + ) param = param.encode() if param is not None else None out, _ = p.communicate(param) if return_rc: @@ -428,7 +484,9 @@ def run_command(command, param: str = None, use_stdin=False, detailed_output=Fal if return_rc: raise ValueError("Return Code not supported for this configuration") - return subprocess.check_output(call_list, stderr=subprocess.PIPE, startupinfo=startupinfo).decode() + return subprocess.check_output( + call_list, stderr=subprocess.PIPE, startupinfo=startupinfo + ).decode() except Exception as e: msg = "Could not run {} ({})".format(cmd, e) logger.error(msg) @@ -450,18 +508,20 @@ def set_splitter_stylesheet(splitter: QSplitter): splitter.setHandleWidth(4) bgcolor = settings.BGCOLOR.lighter(150) r, g, b, a = bgcolor.red(), bgcolor.green(), bgcolor.blue(), bgcolor.alpha() - splitter.setStyleSheet("QSplitter::handle:vertical {{margin: 4px 0px; " - "background-color: qlineargradient(x1:0, y1:0, x2:1, y2:0, " - "stop:0.2 rgba(255, 255, 255, 0)," - "stop:0.5 rgba({0}, {1}, {2}, {3})," - "stop:0.8 rgba(255, 255, 255, 0));" - "image: url(:/icons/icons/splitter_handle_horizontal.svg);}}" - "QSplitter::handle:horizontal {{margin: 4px 0px; " - "background-color: qlineargradient(x1:0, y1:0, x2:0, y2:1, " - "stop:0.2 rgba(255, 255, 255, 0)," - "stop:0.5 rgba({0}, {1}, {2}, {3})," - "stop:0.8 rgba(255, 255, 255, 0));" - "image: url(:/icons/icons/splitter_handle_vertical.svg);}}".format(r, g, b, a)) + splitter.setStyleSheet( + "QSplitter::handle:vertical {{margin: 4px 0px; " + "background-color: qlineargradient(x1:0, y1:0, x2:1, y2:0, " + "stop:0.2 rgba(255, 255, 255, 0)," + "stop:0.5 rgba({0}, {1}, {2}, {3})," + "stop:0.8 rgba(255, 255, 255, 0));" + "image: url(:/icons/icons/splitter_handle_horizontal.svg);}}" + "QSplitter::handle:horizontal {{margin: 4px 0px; " + "background-color: qlineargradient(x1:0, y1:0, x2:0, y2:1, " + "stop:0.2 rgba(255, 255, 255, 0)," + "stop:0.5 rgba({0}, {1}, {2}, {3})," + "stop:0.8 rgba(255, 255, 255, 0));" + "image: url(:/icons/icons/splitter_handle_vertical.svg);}}".format(r, g, b, a) + ) def calc_x_y_scale(rect, parent): diff --git a/src/urh/version.py b/src/urh/version.py index f7928a7a23..7a1891c1be 100644 --- a/src/urh/version.py +++ b/src/urh/version.py @@ -1,5 +1,5 @@ -VERSION = "2.9.5" +VERSION = "2.9.5" -if __name__ == '__main__': +if __name__ == "__main__": # To read out version easy on command line for InnoSetup print(VERSION) diff --git a/tests/PlotTests.py b/tests/PlotTests.py index ffce688141..e17bcf3b7d 100644 --- a/tests/PlotTests.py +++ b/tests/PlotTests.py @@ -24,12 +24,14 @@ def test_plot(self): modulated_samples = modulator.modulate([True, False, True, False, False], 77) data = copy.deepcopy(modulated_samples) - modulated_samples = modulator.modulate([False, True, True, True, True, False, True], 100, start=len(data)) + modulated_samples = modulator.modulate( + [False, True, True, True, True, False, True], 100, start=len(data) + ) data = np.concatenate((data, modulated_samples)) plt.subplot(2, 1, 1) axes = plt.gca() - axes.set_ylim([-2,2]) + axes.set_ylim([-2, 2]) plt.plot(data.real) plt.title("Modulated Wave") @@ -48,7 +50,11 @@ def test_carrier_auto_detect(self): signal.samples_per_symbol = 25 pa = ProtocolAnalyzer(signal) pa.get_protocol_from_signal() - start, num_samples = pa.get_samplepos_of_bitseq(0, 0, 0, 999999, include_pause=False) + start, num_samples = pa.get_samplepos_of_bitseq( + 0, 0, 0, 999999, include_pause=False + ) print("-----------") - print(signal.estimate_frequency(start, end=start+num_samples, sample_rate=2e6)) + print( + signal.estimate_frequency(start, end=start + num_samples, sample_rate=2e6) + ) diff --git a/tests/QtTestCase.py b/tests/QtTestCase.py index f1f65ebe48..0dc8e443bd 100644 --- a/tests/QtTestCase.py +++ b/tests/QtTestCase.py @@ -16,11 +16,14 @@ class QtTestCase(unittest.TestCase): - SHOW = os.path.exists(os.path.join(os.path.dirname(os.path.realpath(__file__)), "show_gui")) + SHOW = os.path.exists( + os.path.join(os.path.dirname(os.path.realpath(__file__)), "show_gui") + ) @classmethod def setUpClass(cls): import multiprocessing as mp + try: mp.set_start_method("spawn") except RuntimeError: @@ -65,18 +68,29 @@ def add_signal_to_generator(self, signal_index: int): item = gframe.tree_model.rootItem.children[0].children[signal_index] index = gframe.tree_model.createIndex(signal_index, 0, item) rect = gframe.ui.treeProtocols.visualRect(index) - QTest.mousePress(gframe.ui.treeProtocols.viewport(), Qt.LeftButton, pos=rect.center()) + QTest.mousePress( + gframe.ui.treeProtocols.viewport(), Qt.LeftButton, pos=rect.center() + ) self.assertEqual(gframe.ui.treeProtocols.selectedIndexes()[0], index) mimedata = gframe.tree_model.mimeData(gframe.ui.treeProtocols.selectedIndexes()) - gframe.table_model.dropMimeData(mimedata, 1, -1, -1, gframe.table_model.createIndex(0, 0)) + gframe.table_model.dropMimeData( + mimedata, 1, -1, -1, gframe.table_model.createIndex(0, 0) + ) def add_all_signals_to_simulator(self): assert isinstance(self.form, MainController) sim_frame = self.form.simulator_tab_controller sim_frame.ui.treeProtocols.selectAll() self.assertGreater(len(sim_frame.ui.treeProtocols.selectedIndexes()), 0) - mimedata = sim_frame.tree_model.mimeData(sim_frame.ui.treeProtocols.selectedIndexes()) - drop_event = QDropEvent(sim_frame.ui.gvSimulator.rect().center(), Qt.CopyAction | Qt.MoveAction, - mimedata, Qt.LeftButton, Qt.NoModifier) + mimedata = sim_frame.tree_model.mimeData( + sim_frame.ui.treeProtocols.selectedIndexes() + ) + drop_event = QDropEvent( + sim_frame.ui.gvSimulator.rect().center(), + Qt.CopyAction | Qt.MoveAction, + mimedata, + Qt.LeftButton, + Qt.NoModifier, + ) drop_event.acceptProposedAction() sim_frame.ui.gvSimulator.dropEvent(drop_event) diff --git a/tests/SpectrogramTest.py b/tests/SpectrogramTest.py index d6538cc427..cddee77d61 100644 --- a/tests/SpectrogramTest.py +++ b/tests/SpectrogramTest.py @@ -12,9 +12,11 @@ class SpectrogramTest(unittest.TestCase): - """ short time fourier transform of audio signal """ + """short time fourier transform of audio signal""" - def stft(self, samples, window_size, overlap_factor=0.5, window_function=np.hanning): + def stft( + self, samples, window_size, overlap_factor=0.5, window_function=np.hanning + ): """ Perform Short-time Fourier transform to get the spectrogram for the given samples @@ -30,19 +32,33 @@ def stft(self, samples, window_size, overlap_factor=0.5, window_function=np.hann hop_size = window_size - int(overlap_factor * window_size) # pad with zeros to ensure last window fits signal - padded_samples = np.append(samples, np.zeros((len(samples) - window_size) % hop_size)) + padded_samples = np.append( + samples, np.zeros((len(samples) - window_size) % hop_size) + ) num_frames = ((len(padded_samples) - window_size) // hop_size) + 1 - frames = [padded_samples[i*hop_size:i*hop_size+window_size] * window for i in range(num_frames)] + frames = [ + padded_samples[i * hop_size : i * hop_size + window_size] * window + for i in range(num_frames) + ] return np.fft.fft(frames) def setUp(self): - self.signal = Signal(get_path_for_data_file("two_participants.complex16s"), "test") + self.signal = Signal( + get_path_for_data_file("two_participants.complex16s"), "test" + ) def test_numpy_impl(self): sample_rate = 1e6 - spectrogram = np.fft.fftshift(self.stft(self.signal.iq_array.data, 2**10, overlap_factor=0.5)) / 1024 - - ims = 10 * np.log10(spectrogram.real ** 2 + spectrogram.imag ** 2) # convert amplitudes to decibel + spectrogram = ( + np.fft.fftshift( + self.stft(self.signal.iq_array.data, 2**10, overlap_factor=0.5) + ) + / 1024 + ) + + ims = 10 * np.log10( + spectrogram.real**2 + spectrogram.imag**2 + ) # convert amplitudes to decibel num_time_bins, num_freq_bins = np.shape(ims) plt.imshow(np.transpose(ims), aspect="auto", cmap="magma") @@ -53,9 +69,16 @@ def test_numpy_impl(self): plt.ylim(ymin=0, ymax=num_freq_bins) x_tick_pos = np.linspace(0, num_time_bins - 1, 5, dtype=np.float32) - plt.xticks(x_tick_pos, ["%.02f" % l for l in (x_tick_pos * len(self.signal.iq_array.data) / num_time_bins) / sample_rate]) + plt.xticks( + x_tick_pos, + [ + "%.02f" % l + for l in (x_tick_pos * len(self.signal.iq_array.data) / num_time_bins) + / sample_rate + ], + ) y_tick_pos = np.linspace(0, num_freq_bins - 1, 10, dtype=np.int16) - frequencies = np.fft.fftshift(np.fft.fftfreq(num_freq_bins, 1/sample_rate)) + frequencies = np.fft.fftshift(np.fft.fftfreq(num_freq_bins, 1 / sample_rate)) plt.yticks(y_tick_pos, ["%.02f" % frequencies[i] for i in y_tick_pos]) plt.show() @@ -65,10 +88,12 @@ def narrowband_iir(self, fc, bw, fs): bw /= fs R = 1 - 3 * bw - K = (1 - 2 * R * np.cos(2 * np.pi * fc) + R ** 2) / (2 - 2*np.cos(2 * np.pi * fc)) + K = (1 - 2 * R * np.cos(2 * np.pi * fc) + R**2) / ( + 2 - 2 * np.cos(2 * np.pi * fc) + ) - a = np.array([K, -2*K*np.cos(2 * np.pi * fc), K], dtype=np.float64) - b = np.array([2 * R * np.cos(2 * np.pi * fc), -R**2], dtype=np.float64) + a = np.array([K, -2 * K * np.cos(2 * np.pi * fc), K], dtype=np.float64) + b = np.array([2 * R * np.cos(2 * np.pi * fc), -(R**2)], dtype=np.float64) return a, b @@ -80,10 +105,10 @@ def test_bandpass(self): t = np.linspace(0, T, nsamples, endpoint=False) a = 0.02 f0 = 600 - x = 0.25 * np.sin(2 * np.pi * 0.25*f0 * t) + x = 0.25 * np.sin(2 * np.pi * 0.25 * f0 * t) x += 0.25 * np.sin(2 * np.pi * f0 * t) - x += 0.25 * np.sin(2 * np.pi * 2*f0 * t) - x += 0.25 * np.sin(2 * np.pi * 3*f0 * t) + x += 0.25 * np.sin(2 * np.pi * 2 * f0 * t) + x += 0.25 * np.sin(2 * np.pi * 3 * f0 * t) import time @@ -97,9 +122,9 @@ def test_bandpass(self): y = Filter.apply_bandpass_filter(data, lowcut / fs, highcut / fs, filter_bw=b) - plt.plot(y, label='Filtered signal (%g Hz)' % f0) - plt.plot(data, label='Noisy signal') - plt.legend(loc='upper left') + plt.plot(y, label="Filtered signal (%g Hz)" % f0) + plt.plot(data, label="Noisy signal") + plt.legend(loc="upper left") plt.show() def test_iir_bandpass(self): @@ -114,31 +139,29 @@ def test_iir_bandpass(self): x += 0.25 * np.sin(2 * np.pi * 2 * f0 * t) x += 0.25 * np.sin(2 * np.pi * 3 * f0 * t) - #data = x.astype(np.complex64) + # data = x.astype(np.complex64) data = np.sin(2 * np.pi * f0 * t).astype(np.complex64) print("Len data", len(data)) a, b = self.narrowband_iir(f0, 100, fs) s = a.sum() + b.sum() - #a /= s - #b /= s - print(a, b) + # a /= s + # b /= s + print(a, b) filtered_data = signal_functions.iir_filter(a, b, data) - #plt.plot(data, label='Noisy signal') - plt.plot(np.fft.fft(filtered_data), label='Filtered signal (%g Hz)' % f0) - + # plt.plot(data, label='Noisy signal') + plt.plot(np.fft.fft(filtered_data), label="Filtered signal (%g Hz)" % f0) - - plt.legend(loc='upper left') + plt.legend(loc="upper left") plt.show() def test_channels(self): - sample_rate = 10 ** 6 + sample_rate = 10**6 - channel1_freq = 40 * 10 ** 3 - channel2_freq = 240 * 10 ** 3 + channel1_freq = 40 * 10**3 + channel2_freq = 240 * 10**3 channel1_data = array.array("B", [1, 0, 1, 0, 1, 0, 0, 1]) channel2_data = array.array("B", [1, 1, 0, 0, 1, 1, 0, 1]) @@ -148,14 +171,20 @@ def test_channels(self): filter_freq1_high = 1.5 * channel1_freq filter_freq1_low = 0.5 * channel1_freq - filter_freq2_high = 1.5*channel2_freq + filter_freq2_high = 1.5 * channel2_freq filter_freq2_low = 0.5 * channel2_freq - modulator1, modulator2, modulator3 = Modulator("test"), Modulator("test2"), Modulator("test3") + modulator1, modulator2, modulator3 = ( + Modulator("test"), + Modulator("test2"), + Modulator("test3"), + ) modulator1.carrier_freq_hz = channel1_freq modulator2.carrier_freq_hz = channel2_freq modulator3.carrier_freq_hz = -channel2_freq - modulator1.sample_rate = modulator2.sample_rate = modulator3.sample_rate = sample_rate + modulator1.sample_rate = ( + modulator2.sample_rate + ) = modulator3.sample_rate = sample_rate data1 = modulator1.modulate(channel1_data) data2 = modulator2.modulate(channel2_data) data3 = modulator3.modulate(channel3_data) @@ -174,19 +203,28 @@ def test_channels(self): plt.imshow(np.transpose(spectrogram.data), aspect="auto", cmap="magma") plt.ylim(0, spectrogram.freq_bins) - chann1_filtered = Filter.apply_bandpass_filter(mixed_signal, filter_freq1_low / sample_rate, filter_freq1_high / sample_rate, filter_bw) + chann1_filtered = Filter.apply_bandpass_filter( + mixed_signal, + filter_freq1_low / sample_rate, + filter_freq1_high / sample_rate, + filter_bw, + ) plt.subplot("223") plt.title("Channel 1 Filtered ({})".format("".join(map(str, channel1_data)))) plt.plot(chann1_filtered) - chann2_filtered = Filter.apply_bandpass_filter(mixed_signal, filter_freq2_low / sample_rate, filter_freq2_high / sample_rate, filter_bw) + chann2_filtered = Filter.apply_bandpass_filter( + mixed_signal, + filter_freq2_low / sample_rate, + filter_freq2_high / sample_rate, + filter_bw, + ) plt.subplot("224") plt.title("Channel 2 Filtered ({})".format("".join(map(str, channel2_data)))) plt.plot(chann2_filtered) plt.show() - def test_bandpass_h(self): f_low = -0.4 f_high = -0.3 @@ -197,10 +235,12 @@ def test_bandpass_h(self): N = Filter.get_filter_length_from_bandwidth(bw) - h = Filter.design_windowed_sinc_lpf(f_c, bw=bw) * np.exp(np.complex(0,1) * np.pi * 2 * f_shift * np.arange(0, N, dtype=complex)) + h = Filter.design_windowed_sinc_lpf(f_c, bw=bw) * np.exp( + np.complex(0, 1) * np.pi * 2 * f_shift * np.arange(0, N, dtype=complex) + ) - #h = Filter.design_windowed_sinc_bandpass(f_low=f_low, f_high=f_high, bw=bw) - #h = Filter.design_windowed_sinc_lpf(0.42, bw=0.08) + # h = Filter.design_windowed_sinc_bandpass(f_low=f_low, f_high=f_high, bw=bw) + # h = Filter.design_windowed_sinc_lpf(0.42, bw=0.08) impulse = np.exp(1j * np.linspace(0, 1, 50)) @@ -213,6 +253,4 @@ def test_bandpass_h(self): plt.show() - - # h = cls.design_windowed_sinc_bandpass(f_low, f_high, filter_bw) diff --git a/tests/TestExternalDecodings.py b/tests/TestExternalDecodings.py index 196aceeb94..1b24cf0f26 100644 --- a/tests/TestExternalDecodings.py +++ b/tests/TestExternalDecodings.py @@ -12,33 +12,604 @@ def test_external_homematic(self): path = os.path.realpath(os.path.join(f, "..", "..")) code = os.path.join(path, "data", "decodings", "homematic_complete") - e = Encoding(["test external homematic", settings.DECODING_EXTERNAL, - code + " d" + ";" + code + " e"]) + e = Encoding( + [ + "test external homematic", + settings.DECODING_EXTERNAL, + code + " d" + ";" + code + " e", + ] + ) - data = array.array("B", - [1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, - 0, 1, 1, 1, 0, 1, 0, 0, 1, 1, 1, 0, 0, 1, 0, 1, 0, 1, 1, 1, 0, 1, 0, 0, 1, 1, 1, 0, 0, 1, 0, - 1, 0, 1, 1, 1, 0, 0, 1, 1, 0, 1, 0, 1, 1, 0, 0, 1, 1, 1, 0, 0, 1, 0, 0, 1, 1, 1, 1, 1, 1, 0, - 0, 1, 1, 1, 0, 0, 1, 0, 0, 0, 1, 1, 1, 1, 1, 1, 0, 1, 0, 1, 0, 1, 0, 0, 1, 0, 0, 0, 1, 1, 0, - 0, 1, 1, 0, 1, 1, 1, 1, 0, 1, 0, 1, 0, 1, 0, 0, 1, 1, 0, 1, 0, 1, 1, 1, 0, 0, 0, 1, 1, 0, 0, - 0, 0, 0, 1, 1, 1, 1, 0, 1, 1, 1, 0, 0, 1, 1, 1, 0, 1, 1, 0, 1, 0, 0, 1, 1, 0, 0, 0, 0, 1, 1, - 1, 1, 0, 0, 1, 1, 1, 1, 0, 1, 1, 1, 0, 0, 1, 1, 1, 0, 0, 1, 0, 1, 0, 0, 0, 0, 0, 0, 1, 0, 1, - 0, 0, 0, 0, 1, 1, 1, 0, 1, 0, 0, 1, 0, 1, 0, 0, 0, 1, 0, 1, 1, 1, 0, 0, 1, 1, 1, 0, 0, 0, 0, - 1, 1, 1, 1, 0, 1, 1, 0, 1, 1, 1, 1, 0, 0, 1, 0, 1, 1, 1, 0, 1, 0, 1, 1, 0, 1, 0, 1, 1, 1, 1, - 0, 0, 1, 0, 1, 0, 1, 1, 1, 1]) + data = array.array( + "B", + [ + 1, + 0, + 1, + 0, + 1, + 0, + 1, + 0, + 1, + 0, + 1, + 0, + 1, + 0, + 1, + 0, + 1, + 0, + 1, + 0, + 1, + 0, + 1, + 0, + 1, + 0, + 1, + 0, + 1, + 0, + 1, + 0, + 1, + 1, + 1, + 0, + 1, + 0, + 0, + 1, + 1, + 1, + 0, + 0, + 1, + 0, + 1, + 0, + 1, + 1, + 1, + 0, + 1, + 0, + 0, + 1, + 1, + 1, + 0, + 0, + 1, + 0, + 1, + 0, + 1, + 1, + 1, + 0, + 0, + 1, + 1, + 0, + 1, + 0, + 1, + 1, + 0, + 0, + 1, + 1, + 1, + 0, + 0, + 1, + 0, + 0, + 1, + 1, + 1, + 1, + 1, + 1, + 0, + 0, + 1, + 1, + 1, + 0, + 0, + 1, + 0, + 0, + 0, + 1, + 1, + 1, + 1, + 1, + 1, + 0, + 1, + 0, + 1, + 0, + 1, + 0, + 0, + 1, + 0, + 0, + 0, + 1, + 1, + 0, + 0, + 1, + 1, + 0, + 1, + 1, + 1, + 1, + 0, + 1, + 0, + 1, + 0, + 1, + 0, + 0, + 1, + 1, + 0, + 1, + 0, + 1, + 1, + 1, + 0, + 0, + 0, + 1, + 1, + 0, + 0, + 0, + 0, + 0, + 1, + 1, + 1, + 1, + 0, + 1, + 1, + 1, + 0, + 0, + 1, + 1, + 1, + 0, + 1, + 1, + 0, + 1, + 0, + 0, + 1, + 1, + 0, + 0, + 0, + 0, + 1, + 1, + 1, + 1, + 0, + 0, + 1, + 1, + 1, + 1, + 0, + 1, + 1, + 1, + 0, + 0, + 1, + 1, + 1, + 0, + 0, + 1, + 0, + 1, + 0, + 0, + 0, + 0, + 0, + 0, + 1, + 0, + 1, + 0, + 0, + 0, + 0, + 1, + 1, + 1, + 0, + 1, + 0, + 0, + 1, + 0, + 1, + 0, + 0, + 0, + 1, + 0, + 1, + 1, + 1, + 0, + 0, + 1, + 1, + 1, + 0, + 0, + 0, + 0, + 1, + 1, + 1, + 1, + 0, + 1, + 1, + 0, + 1, + 1, + 1, + 1, + 0, + 0, + 1, + 0, + 1, + 1, + 1, + 0, + 1, + 0, + 1, + 1, + 0, + 1, + 0, + 1, + 1, + 1, + 1, + 0, + 0, + 1, + 0, + 1, + 0, + 1, + 1, + 1, + 1, + ], + ) decoded = e.decode(data) - self.assertEqual(decoded, array.array("B", - [1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, - 1, 0, 1, 0, 1, 0, 1, 0, 1, 1, 1, 0, 1, 0, 0, 1, 1, 1, 0, 0, 1, 0, 1, 0, - 1, 1, 1, 0, 1, 0, 0, 1, 1, 1, 0, 0, 1, 0, 1, 0, 0, 0, 0, 1, 1, 0, 0, 1, - 0, 0, 1, 0, 0, 1, 0, 0, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, - 0, 0, 1, 1, 1, 0, 0, 1, 0, 0, 1, 0, 0, 1, 1, 1, 1, 1, 0, 0, 1, 1, 0, 0, - 0, 0, 1, 1, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 0, 0, 1, 1, 0, 0, - 1, 0, 1, 1, 0, 0, 0, 0, 1, 1, 0, 0, 0, 1, 0, 1, 0, 0, 1, 1, 1, 0, 1, 0, - 1, 1, 1, 1, 0, 0, 1, 0, 0, 0, 1, 1, 0, 0, 0, 1, 1, 0, 1, 1, 1, 0, 1, 0, - 0, 1, 0, 1, 1, 1, 0, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 1, 0, 1, 1, 0, 1, 1, - 0, 1, 0, 1, 0, 1, 0, 0, 0, 0, 0, 1, 1, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, - 0, 0, 1, 1, 0, 1, 0, 1, 1, 1, 0, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, - 1, 1, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 1, 1, 0, 0, 1, 1, 0, 0, 1, 0, 0])) + self.assertEqual( + decoded, + array.array( + "B", + [ + 1, + 0, + 1, + 0, + 1, + 0, + 1, + 0, + 1, + 0, + 1, + 0, + 1, + 0, + 1, + 0, + 1, + 0, + 1, + 0, + 1, + 0, + 1, + 0, + 1, + 0, + 1, + 0, + 1, + 0, + 1, + 0, + 1, + 1, + 1, + 0, + 1, + 0, + 0, + 1, + 1, + 1, + 0, + 0, + 1, + 0, + 1, + 0, + 1, + 1, + 1, + 0, + 1, + 0, + 0, + 1, + 1, + 1, + 0, + 0, + 1, + 0, + 1, + 0, + 0, + 0, + 0, + 1, + 1, + 0, + 0, + 1, + 0, + 0, + 1, + 0, + 0, + 1, + 0, + 0, + 1, + 0, + 1, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 1, + 1, + 0, + 0, + 1, + 1, + 1, + 0, + 0, + 1, + 0, + 0, + 1, + 0, + 0, + 1, + 1, + 1, + 1, + 1, + 0, + 0, + 1, + 1, + 0, + 0, + 0, + 0, + 1, + 1, + 0, + 0, + 0, + 1, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 1, + 1, + 1, + 0, + 0, + 1, + 1, + 0, + 0, + 1, + 0, + 1, + 1, + 0, + 0, + 0, + 0, + 1, + 1, + 0, + 0, + 0, + 1, + 0, + 1, + 0, + 0, + 1, + 1, + 1, + 0, + 1, + 0, + 1, + 1, + 1, + 1, + 0, + 0, + 1, + 0, + 0, + 0, + 1, + 1, + 0, + 0, + 0, + 1, + 1, + 0, + 1, + 1, + 1, + 0, + 1, + 0, + 0, + 1, + 0, + 1, + 1, + 1, + 0, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 0, + 0, + 0, + 1, + 0, + 1, + 1, + 0, + 1, + 1, + 0, + 1, + 0, + 1, + 0, + 1, + 0, + 0, + 0, + 0, + 0, + 1, + 1, + 1, + 0, + 0, + 0, + 0, + 1, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 1, + 1, + 0, + 1, + 0, + 1, + 1, + 1, + 0, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 0, + 0, + 0, + 0, + 0, + 0, + 1, + 1, + 0, + 0, + 0, + 0, + 1, + 1, + 1, + 1, + 0, + 0, + 0, + 1, + 1, + 0, + 0, + 1, + 1, + 0, + 0, + 1, + 0, + 0, + ], + ), + ) encoded = e.encode(decoded) self.assertEqual(encoded, data) diff --git a/tests/TestGeneratorTablePerformance.py b/tests/TestGeneratorTablePerformance.py index 2c067d96e6..4f17b54a98 100644 --- a/tests/TestGeneratorTablePerformance.py +++ b/tests/TestGeneratorTablePerformance.py @@ -31,24 +31,40 @@ def test_performance(self): item = self.gframe.tree_model.rootItem.children[0].children[0] index = self.gframe.tree_model.createIndex(0, 0, item) rect = self.gframe.ui.treeProtocols.visualRect(index) - QTest.mousePress(self.gframe.ui.treeProtocols.viewport(), Qt.LeftButton, pos = rect.center()) + QTest.mousePress( + self.gframe.ui.treeProtocols.viewport(), Qt.LeftButton, pos=rect.center() + ) self.assertEqual(self.gframe.ui.treeProtocols.selectedIndexes()[0], index) - mimedata = self.gframe.tree_model.mimeData(self.gframe.ui.treeProtocols.selectedIndexes()) - t = time.time() - self.gframe.table_model.dropMimeData(mimedata, 1, -1, -1, self.gframe.table_model.createIndex(0, 0)) + mimedata = self.gframe.tree_model.mimeData( + self.gframe.ui.treeProtocols.selectedIndexes() + ) + t = time.time() + self.gframe.table_model.dropMimeData( + mimedata, 1, -1, -1, self.gframe.table_model.createIndex(0, 0) + ) print("{0}: {1} s".format("Time for dropping mimedata", (time.time() - t))) self.assertEqual(self.gframe.table_model.row_count, self.NUM_MESSAGES) print("==============================00") - indx = self.gframe.table_model.createIndex(int(self.NUM_MESSAGES / 2), int(self.BITS_PER_MESSAGE / 2)) - roles = (Qt.DisplayRole, Qt.BackgroundColorRole, Qt.TextAlignmentRole, Qt.TextColorRole, Qt.FontRole) + indx = self.gframe.table_model.createIndex( + int(self.NUM_MESSAGES / 2), int(self.BITS_PER_MESSAGE / 2) + ) + roles = ( + Qt.DisplayRole, + Qt.BackgroundColorRole, + Qt.TextAlignmentRole, + Qt.TextColorRole, + Qt.FontRole, + ) time_for_display = 100 for role in roles: t = time.time() - self.gframe.table_model.data(indx, role = role) - microseconds = (time.time() - t) * 10 ** 6 - self.assertLessEqual(microseconds, 2 * time_for_display, msg=self.__role_to_str(role)) + self.gframe.table_model.data(indx, role=role) + microseconds = (time.time() - t) * 10**6 + self.assertLessEqual( + microseconds, 2 * time_for_display, msg=self.__role_to_str(role) + ) if role == Qt.DisplayRole: time_for_display = microseconds print("{0}: {1} µs".format(self.__role_to_str(role), microseconds)) @@ -56,7 +72,11 @@ def test_performance(self): def __build_protocol(self): result = ProtocolAnalyzer(signal=None) for _ in range(self.NUM_MESSAGES): - b = Message([True] * self.BITS_PER_MESSAGE, pause = 1000, message_type=result.default_message_type) + b = Message( + [True] * self.BITS_PER_MESSAGE, + pause=1000, + message_type=result.default_message_type, + ) result.messages.append(b) return result @@ -64,7 +84,13 @@ def __add_labels(self): start = 0 label_len = 3 for i in range(self.NUM_LABELS): - self.cframe.add_protocol_label(start=start, end=start + label_len, messagenr=0, proto_view=0, edit_label_name = False) + self.cframe.add_protocol_label( + start=start, + end=start + label_len, + messagenr=0, + proto_view=0, + edit_label_name=False, + ) start += label_len + 1 def __role_to_str(self, role): diff --git a/tests/TestInstallation.py b/tests/TestInstallation.py index 7f2c9cf3a0..cffc0f265e 100644 --- a/tests/TestInstallation.py +++ b/tests/TestInstallation.py @@ -7,9 +7,15 @@ class VMHelper(object): - def __init__(self, vm_name: str, shell: str = "", ssh_username: str = None, ssh_port: str = None): + def __init__( + self, + vm_name: str, + shell: str = "", + ssh_username: str = None, + ssh_port: str = None, + ): self.vm_name = vm_name - self.shell = shell # like cmd.exe /c + self.shell = shell # like cmd.exe /c self.ssh_username = ssh_username self.ssh_port = ssh_port @@ -21,12 +27,17 @@ def start_vm(self): def stop_vm(self, save=True): if save: - call('VBoxManage controlvm "{0}" savestate'.format(self.vm_name), shell=True) + call( + 'VBoxManage controlvm "{0}" savestate'.format(self.vm_name), shell=True + ) return if self.use_ssh: self.send_command("sudo shutdown -h now") else: - call('VBoxManage controlvm "{0}" acpipowerbutton'.format(self.vm_name), shell=True) + call( + 'VBoxManage controlvm "{0}" acpipowerbutton'.format(self.vm_name), + shell=True, + ) def wait_for_vm_up(self): if not self.__vm_is_up: @@ -34,7 +45,9 @@ def wait_for_vm_up(self): command = "ping -c 1" if self.use_ssh else "ping -n 1" command += " github.com" - while self.__send_command(command, hide_output=True, print_command=False) != 0: + while ( + self.__send_command(command, hide_output=True, print_command=False) != 0 + ): time.sleep(1) self.__vm_is_up = True @@ -43,13 +56,23 @@ def send_command(self, command: str) -> int: self.wait_for_vm_up() return self.__send_command(command) - def __send_command(self, command: str, hide_output=False, print_command=True) -> int: + def __send_command( + self, command: str, hide_output=False, print_command=True + ) -> int: if self.use_ssh: - fullcmd = ["ssh", "-p", str(self.ssh_port), "{0}@127.0.0.1".format(self.ssh_username), '"{0}"'.format(command)] + fullcmd = [ + "ssh", + "-p", + str(self.ssh_port), + "{0}@127.0.0.1".format(self.ssh_username), + '"{0}"'.format(command), + ] else: - fullcmd = ["VBoxManage", "guestcontrol", '"{0}"'.format(self.vm_name), "run"] \ - + self.shell.split(" ") \ - + ['"{0}"'.format(command)] + fullcmd = ( + ["VBoxManage", "guestcontrol", '"{0}"'.format(self.vm_name), "run"] + + self.shell.split(" ") + + ['"{0}"'.format(command)] + ) kwargs = {"stdout": DEVNULL, "stderr": DEVNULL} if hide_output else {} @@ -62,19 +85,20 @@ def __send_command(self, command: str, hide_output=False, print_command=True) -> class TestInstallation(unittest.TestCase): - def test_linux(self): distributions = [ - #"archlinux", + # "archlinux", "debian8", - #"ubuntu1404", + # "ubuntu1404", "ubuntu1604", - #"kali", + # "kali", # "gentoo" # can't test gentoo till this bug is fixed: https://github.com/docker/docker/issues/1916#issuecomment-184356102 ] for distribution in distributions: - self.assertTrue(docker_util.run_image(distribution, rebuild=False), msg=distribution) + self.assertTrue( + docker_util.run_image(distribution, rebuild=False), msg=distribution + ) def test_windows(self): r""" @@ -136,14 +160,22 @@ def test_osx(self): vm_helper.send_command("git clone https://github.com/jopohl/urh " + target_dir) # Build extensions - rc = vm_helper.send_command("{0}python3 {1}/src/urh/cythonext/build.py".format(python_bin_dir, target_dir)) + rc = vm_helper.send_command( + "{0}python3 {1}/src/urh/cythonext/build.py".format( + python_bin_dir, target_dir + ) + ) self.assertEqual(rc, 0) # Run Unit tests - rc = vm_helper.send_command("{1}py.test {0}/tests".format(target_dir, python_bin_dir)) + rc = vm_helper.send_command( + "{1}py.test {0}/tests".format(target_dir, python_bin_dir) + ) self.assertEqual(rc, 0) - vm_helper.send_command("{0}pip3 --no-cache-dir install urh".format(python_bin_dir)) + vm_helper.send_command( + "{0}pip3 --no-cache-dir install urh".format(python_bin_dir) + ) rc = vm_helper.send_command("{0}urh autoclose".format(python_bin_dir)) self.assertEqual(rc, 0) vm_helper.send_command("{0}pip3 uninstall --yes urh".format(python_bin_dir)) diff --git a/tests/__init__.py b/tests/__init__.py index 979a7f7b98..306e7f9fae 100644 --- a/tests/__init__.py +++ b/tests/__init__.py @@ -1,5 +1,6 @@ import os import sys + f = os.readlink(__file__) if os.path.islink(__file__) else __file__ path = os.path.realpath(os.path.join(f, "..", "..", "src")) diff --git a/tests/auto_interpretation/__init__.py b/tests/auto_interpretation/__init__.py index 87f58ad866..9cbaeafcfd 100644 --- a/tests/auto_interpretation/__init__.py +++ b/tests/auto_interpretation/__init__.py @@ -1,7 +1,8 @@ import os import sys + f = os.readlink(__file__) if os.path.islink(__file__) else __file__ path = os.path.realpath(os.path.join(f, "..", "..", "..", "src")) if path not in sys.path: - sys.path.insert(0, path) \ No newline at end of file + sys.path.insert(0, path) diff --git a/tests/auto_interpretation/auto_interpretation_test_util.py b/tests/auto_interpretation/auto_interpretation_test_util.py index e67e10e6bd..49761c34c8 100644 --- a/tests/auto_interpretation/auto_interpretation_test_util.py +++ b/tests/auto_interpretation/auto_interpretation_test_util.py @@ -9,7 +9,16 @@ from urh.signalprocessing.Signal import Signal -def demodulate(signal_data, mod_type: str, bit_length, center, noise, tolerance, decoding=None, pause_threshold=8): +def demodulate( + signal_data, + mod_type: str, + bit_length, + center, + noise, + tolerance, + decoding=None, + pause_threshold=8, +): signal = Signal("", "") if isinstance(signal_data, IQArray): signal.iq_array = signal_data @@ -43,7 +52,9 @@ def generate_signal(messages: list, modulator: Modulator, snr_db: int, add_noise modulated = modulator.modulate(msg.encoded_bits, msg.pause) if add_noise: - message_powers.append(np.mean(np.abs(modulated[:len(modulated) - msg.pause]))) + message_powers.append( + np.mean(np.abs(modulated[: len(modulated) - msg.pause])) + ) result.append(modulated) @@ -51,7 +62,11 @@ def generate_signal(messages: list, modulator: Modulator, snr_db: int, add_noise if not add_noise: return result - noise = np.random.normal(loc=0, scale=1, size=2 * len(result)).astype(np.float32).view(np.complex64) + noise = ( + np.random.normal(loc=0, scale=1, size=2 * len(result)) + .astype(np.float32) + .view(np.complex64) + ) # https://stackoverflow.com/questions/23690766/proper-way-to-add-noise-to-signal snr_ratio = np.power(10, snr_db / 10) @@ -67,19 +82,31 @@ def generate_message_bits(num_bits=80, preamble="", sync="", eof=""): bits_to_generate = num_bits - (len(preamble) + len(sync) + len(eof)) if bits_to_generate < 0: - raise ValueError("Preamble and Sync and EOF are together larger than requested num bits") + raise ValueError( + "Preamble and Sync and EOF are together larger than requested num bits" + ) bytes_to_generate = bits_to_generate // 8 leftover_bits = bits_to_generate % 8 - return "".join([preamble, sync] - + ["{0:08b}".format(random.choice(range(0, 256))) for _ in range(bytes_to_generate)] - + [random.choice(["0", "1"]) for _ in range(leftover_bits)] - + [eof] - ) - - -def generate_random_messages(num_messages: int, num_bits: int, - preamble: str, sync: str, eof: str, message_pause: int): + return "".join( + [preamble, sync] + + [ + "{0:08b}".format(random.choice(range(0, 256))) + for _ in range(bytes_to_generate) + ] + + [random.choice(["0", "1"]) for _ in range(leftover_bits)] + + [eof] + ) + + +def generate_random_messages( + num_messages: int, + num_bits: int, + preamble: str, + sync: str, + eof: str, + message_pause: int, +): return [ Message.from_plain_bits_str( generate_message_bits(num_bits, preamble, sync, eof), pause=message_pause diff --git a/tests/auto_interpretation/test_additional_signals.py b/tests/auto_interpretation/test_additional_signals.py index 6836615ead..25dcf8ca87 100644 --- a/tests/auto_interpretation/test_additional_signals.py +++ b/tests/auto_interpretation/test_additional_signals.py @@ -29,13 +29,26 @@ def test_action(self): result = AutoInterpretation.estimate(data) mod_type, bit_length = result["modulation_type"], result["bit_length"] - center, noise, tolerance = result["center"], result["noise"], result["tolerance"] + center, noise, tolerance = ( + result["center"], + result["noise"], + result["tolerance"], + ) self.assertEqual(mod_type, "ASK") self.assertGreaterEqual(bit_length, 400) self.assertLessEqual(bit_length, 600) - print("noise", noise, "center", center, "bit length", bit_length, "tolerance", tolerance) + print( + "noise", + noise, + "center", + center, + "bit length", + bit_length, + "tolerance", + tolerance, + ) demodulated = demodulate(data, mod_type, bit_length, center, noise, tolerance) print(demodulated) self.assertEqual(len(demodulated), 19) @@ -51,7 +64,11 @@ def test_audi(self): result = AutoInterpretation.estimate(data) mod_type, bit_length = result["modulation_type"], result["bit_length"] - center, noise, tolerance = result["center"], result["noise"], result["tolerance"] + center, noise, tolerance = ( + result["center"], + result["noise"], + result["tolerance"], + ) self.assertEqual(mod_type, "ASK") self.assertGreaterEqual(bit_length, 2400) @@ -59,11 +76,24 @@ def test_audi(self): self.assertGreaterEqual(center, 0.005) self.assertLessEqual(center, 0.32) - print("noise", noise, "center", center, "bit length", bit_length, "tolerance", tolerance) + print( + "noise", + noise, + "center", + center, + "bit length", + bit_length, + "tolerance", + tolerance, + ) demodulated = demodulate(data, mod_type, bit_length, center, noise, tolerance) print(demodulated) self.assertEqual(len(demodulated), 1) - self.assertTrue(demodulated[0].startswith("aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa")) + self.assertTrue( + demodulated[0].startswith( + "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa" + ) + ) self.assertTrue(demodulated[0].endswith("cad4c")) def test_brennenstuhl(self): @@ -75,13 +105,28 @@ def test_brennenstuhl(self): result = AutoInterpretation.estimate(data) mod_type, bit_length = result["modulation_type"], result["bit_length"] - center, noise, tolerance = result["center"], result["noise"], result["tolerance"] + center, noise, tolerance = ( + result["center"], + result["noise"], + result["tolerance"], + ) self.assertEqual(mod_type, "ASK") self.assertEqual(bit_length, 300) - print("noise", noise, "center", center, "bit length", bit_length, "tolerance", tolerance) - demodulated = demodulate(data, mod_type, bit_length, center, noise, tolerance, pause_threshold=8) + print( + "noise", + noise, + "center", + center, + "bit length", + bit_length, + "tolerance", + tolerance, + ) + demodulated = demodulate( + data, mod_type, bit_length, center, noise, tolerance, pause_threshold=8 + ) print(demodulated) self.assertEqual(len(demodulated), 64) for i in range(64): @@ -97,13 +142,26 @@ def test_esaver(self): result = AutoInterpretation.estimate(data) mod_type, bit_length = result["modulation_type"], result["bit_length"] - center, noise, tolerance = result["center"], result["noise"], result["tolerance"] + center, noise, tolerance = ( + result["center"], + result["noise"], + result["tolerance"], + ) print(center, noise) self.assertEqual(mod_type, "FSK") self.assertEqual(bit_length, 100) - print("noise", noise, "center", center, "bit length", bit_length, "tolerance", tolerance) + print( + "noise", + noise, + "center", + center, + "bit length", + bit_length, + "tolerance", + tolerance, + ) demodulated = demodulate(data, mod_type, bit_length, center, noise, tolerance) print(demodulated) self.assertEqual(len(demodulated), 12) @@ -119,13 +177,26 @@ def test_scislo(self): result = AutoInterpretation.estimate(data) mod_type, bit_length = result["modulation_type"], result["bit_length"] - center, noise, tolerance = result["center"], result["noise"], result["tolerance"] + center, noise, tolerance = ( + result["center"], + result["noise"], + result["tolerance"], + ) self.assertEqual(mod_type, "FSK") self.assertEqual(bit_length, 200) self.assertGreaterEqual(noise, 0.0120) - print("noise", noise, "center", center, "bit length", bit_length, "tolerance", tolerance) + print( + "noise", + noise, + "center", + center, + "bit length", + bit_length, + "tolerance", + tolerance, + ) demodulated = demodulate(data, mod_type, bit_length, center, noise, tolerance) print(demodulated) self.assertEqual(len(demodulated), 8) @@ -141,7 +212,11 @@ def test_vw(self): result = AutoInterpretation.estimate(data) mod_type, bit_length = result["modulation_type"], result["bit_length"] - center, noise, tolerance = result["center"], result["noise"], result["tolerance"] + center, noise, tolerance = ( + result["center"], + result["noise"], + result["tolerance"], + ) self.assertEqual(mod_type, "ASK") self.assertGreaterEqual(bit_length, 2000) @@ -150,4 +225,8 @@ def test_vw(self): demodulated = demodulate(data, mod_type, bit_length, center, noise, tolerance) print(demodulated) self.assertEqual(len(demodulated), 1) - self.assertTrue(demodulated[0].startswith("aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa")) \ No newline at end of file + self.assertTrue( + demodulated[0].startswith( + "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa" + ) + ) diff --git a/tests/auto_interpretation/test_auto_interpretation_integration.py b/tests/auto_interpretation/test_auto_interpretation_integration.py index 5a309d7314..d5cd83b617 100644 --- a/tests/auto_interpretation/test_auto_interpretation_integration.py +++ b/tests/auto_interpretation/test_auto_interpretation_integration.py @@ -12,29 +12,46 @@ class TestAutoInterpretationIntegration(unittest.TestCase): def test_auto_interpretation_fsk(self): - fsk_signal = np.fromfile(get_path_for_data_file("fsk.complex"), dtype=np.float32) + fsk_signal = np.fromfile( + get_path_for_data_file("fsk.complex"), dtype=np.float32 + ) result = AutoInterpretation.estimate(fsk_signal) mod_type, bit_length = result["modulation_type"], result["bit_length"] - center, noise, tolerance = result["center"], result["noise"], result["tolerance"] + center, noise, tolerance = ( + result["center"], + result["noise"], + result["tolerance"], + ) self.assertEqual(mod_type, "FSK") self.assertEqual(bit_length, 100) self.assertGreater(tolerance, 0) self.assertLessEqual(tolerance, 5) - self.assertEqual(demodulate(fsk_signal, mod_type, bit_length, center, noise, tolerance)[0], - "aaaaaaaac626c626f4dc1d98eef7a427999cd239d3f18") + self.assertEqual( + demodulate(fsk_signal, mod_type, bit_length, center, noise, tolerance)[0], + "aaaaaaaac626c626f4dc1d98eef7a427999cd239d3f18", + ) def test_auto_interpretation_ask(self): - ask_signal = np.fromfile(get_path_for_data_file("ask.complex"), dtype=np.float32) + ask_signal = np.fromfile( + get_path_for_data_file("ask.complex"), dtype=np.float32 + ) result = AutoInterpretation.estimate(ask_signal) mod_type, bit_length = result["modulation_type"], result["bit_length"] - center, noise, tolerance = result["center"], result["noise"], result["tolerance"] + center, noise, tolerance = ( + result["center"], + result["noise"], + result["tolerance"], + ) self.assertEqual(mod_type, "ASK") self.assertEqual(bit_length, 300) self.assertGreater(tolerance, 0) self.assertLessEqual(tolerance, 6) - self.assertEqual(demodulate(ask_signal, mod_type, bit_length, center, noise, tolerance)[0], "b25b6db6c80") + self.assertEqual( + demodulate(ask_signal, mod_type, bit_length, center, noise, tolerance)[0], + "b25b6db6c80", + ) def test_auto_interpretation_overshoot_ook(self): data = Signal(get_path_for_data_file("ook_overshoot.complex16s"), "").iq_array @@ -43,18 +60,31 @@ def test_auto_interpretation_overshoot_ook(self): self.assertEqual(result["bit_length"], 500) def test_auto_interpretation_enocean(self): - enocean_signal = np.fromfile(get_path_for_data_file("enocean.complex"), dtype=np.float32) + enocean_signal = np.fromfile( + get_path_for_data_file("enocean.complex"), dtype=np.float32 + ) result = AutoInterpretation.estimate(enocean_signal) mod_type, bit_length = result["modulation_type"], result["bit_length"] - center, noise, tolerance = result["center"], result["noise"], result["tolerance"] + center, noise, tolerance = ( + result["center"], + result["noise"], + result["tolerance"], + ) self.assertEqual(mod_type, "ASK") self.assertGreaterEqual(center, 0.0077) self.assertLessEqual(center, 0.0465) self.assertLessEqual(tolerance, 5) self.assertEqual(bit_length, 40) - demod = demodulate(enocean_signal, mod_type, bit_length, center, noise, tolerance, - decoding=Encoding(["WSP", settings.DECODING_ENOCEAN])) + demod = demodulate( + enocean_signal, + mod_type, + bit_length, + center, + noise, + tolerance, + decoding=Encoding(["WSP", settings.DECODING_ENOCEAN]), + ) self.assertEqual(len(demod), 3) self.assertEqual(demod[0], demod[2]) self.assertEqual(demod[0], "aa9610002c1c024b") @@ -63,11 +93,17 @@ def test_auto_interpretation_xavax(self): signal = Signal(get_path_for_data_file("xavax.coco"), "") result = AutoInterpretation.estimate(signal.iq_array.data) mod_type, bit_length = result["modulation_type"], result["bit_length"] - center, noise, tolerance = result["center"], result["noise"], result["tolerance"] + center, noise, tolerance = ( + result["center"], + result["noise"], + result["tolerance"], + ) self.assertEqual(mod_type, "FSK") self.assertEqual(bit_length, 100) - demod = demodulate(signal.iq_array.data, mod_type, bit_length, center, noise, tolerance) + demod = demodulate( + signal.iq_array.data, mod_type, bit_length, center, noise, tolerance + ) self.assertGreaterEqual(len(demod), 5) for i in range(1, len(demod)): @@ -78,12 +114,18 @@ def test_auto_interpretation_elektromaten(self): result = AutoInterpretation.estimate(data) mod_type, bit_length = result["modulation_type"], result["bit_length"] - center, noise, tolerance = result["center"], result["noise"], result["tolerance"] + center, noise, tolerance = ( + result["center"], + result["noise"], + result["tolerance"], + ) self.assertEqual(mod_type, "ASK") self.assertEqual(bit_length, 600) - demodulated = demodulate(data, mod_type, bit_length, center, noise, tolerance, pause_threshold=8) + demodulated = demodulate( + data, mod_type, bit_length, center, noise, tolerance, pause_threshold=8 + ) self.assertEqual(len(demodulated), 11) for i in range(11): self.assertTrue(demodulated[i].startswith("8")) @@ -93,7 +135,11 @@ def test_auto_interpretation_homematic(self): result = AutoInterpretation.estimate(data) mod_type, bit_length = result["modulation_type"], result["bit_length"] - center, noise, tolerance = result["center"], result["noise"], result["tolerance"] + center, noise, tolerance = ( + result["center"], + result["noise"], + result["tolerance"], + ) self.assertEqual(mod_type, "FSK") self.assertEqual(bit_length, 100) diff --git a/tests/auto_interpretation/test_bit_length_detection.py b/tests/auto_interpretation/test_bit_length_detection.py index d814e24518..a90e00d784 100644 --- a/tests/auto_interpretation/test_bit_length_detection.py +++ b/tests/auto_interpretation/test_bit_length_detection.py @@ -3,52 +3,219 @@ from urh.ainterpretation import AutoInterpretation + class TestAutoInterpretation(unittest.TestCase): def __run_merge(self, data): - return list(AutoInterpretation.merge_plateau_lengths(np.array(data, dtype=np.uint64))) + return list( + AutoInterpretation.merge_plateau_lengths(np.array(data, dtype=np.uint64)) + ) def test_merge_plateau_lengths(self): self.assertEqual(AutoInterpretation.merge_plateau_lengths([]), []) self.assertEqual(AutoInterpretation.merge_plateau_lengths([42]), [42]) - self.assertEqual(AutoInterpretation.merge_plateau_lengths([100, 100, 100]), [100, 100, 100]) + self.assertEqual( + AutoInterpretation.merge_plateau_lengths([100, 100, 100]), [100, 100, 100] + ) self.assertEqual(self.__run_merge([100, 49, 1, 50, 100]), [100, 100, 100]) self.assertEqual(self.__run_merge([100, 48, 2, 50, 100]), [100, 100, 100]) - self.assertEqual(self.__run_merge([100, 100, 67, 1, 10, 1, 21]), [100, 100, 100]) - self.assertEqual(self.__run_merge([100, 100, 67, 1, 10, 1, 21, 100, 50, 1, 49]), [100, 100, 100, 100, 100]) + self.assertEqual( + self.__run_merge([100, 100, 67, 1, 10, 1, 21]), [100, 100, 100] + ) + self.assertEqual( + self.__run_merge([100, 100, 67, 1, 10, 1, 21, 100, 50, 1, 49]), + [100, 100, 100, 100, 100], + ) def test_estimate_tolerance_from_plateau_lengths(self): - self.assertEqual(AutoInterpretation.estimate_tolerance_from_plateau_lengths([]), None) - self.assertEqual(AutoInterpretation.estimate_tolerance_from_plateau_lengths([10]), None) - self.assertEqual(AutoInterpretation.estimate_tolerance_from_plateau_lengths([100, 49, 1, 50, 100]), 1) - self.assertEqual(AutoInterpretation.estimate_tolerance_from_plateau_lengths([100, 49, 2, 50, 100]), 2) - self.assertEqual(AutoInterpretation.estimate_tolerance_from_plateau_lengths([100, 49, 2, 50, 100, 1]), 2) - self.assertEqual(AutoInterpretation.estimate_tolerance_from_plateau_lengths([8, 8, 6, 1, 1]), 1) + self.assertEqual( + AutoInterpretation.estimate_tolerance_from_plateau_lengths([]), None + ) + self.assertEqual( + AutoInterpretation.estimate_tolerance_from_plateau_lengths([10]), None + ) + self.assertEqual( + AutoInterpretation.estimate_tolerance_from_plateau_lengths( + [100, 49, 1, 50, 100] + ), + 1, + ) + self.assertEqual( + AutoInterpretation.estimate_tolerance_from_plateau_lengths( + [100, 49, 2, 50, 100] + ), + 2, + ) + self.assertEqual( + AutoInterpretation.estimate_tolerance_from_plateau_lengths( + [100, 49, 2, 50, 100, 1] + ), + 2, + ) + self.assertEqual( + AutoInterpretation.estimate_tolerance_from_plateau_lengths([8, 8, 6, 1, 1]), + 1, + ) def test_tolerant_greatest_common_divisor(self): self.assertEqual(AutoInterpretation.get_tolerant_greatest_common_divisor([]), 1) - self.assertEqual(AutoInterpretation.get_tolerant_greatest_common_divisor([22]), 1) - self.assertEqual(AutoInterpretation.get_tolerant_greatest_common_divisor([10, 5, 5]), 5) - self.assertEqual(AutoInterpretation.get_tolerant_greatest_common_divisor([100, 100, 100]), 100) - self.assertEqual(AutoInterpretation.get_tolerant_greatest_common_divisor([100, 100, 200, 300, 100, 400]), 100) - self.assertEqual(AutoInterpretation.get_tolerant_greatest_common_divisor([100, 101, 100, 100]), 100) - self.assertEqual(AutoInterpretation.get_tolerant_greatest_common_divisor([100, 101, 202, 301, 100, 500]), 100) + self.assertEqual( + AutoInterpretation.get_tolerant_greatest_common_divisor([22]), 1 + ) + self.assertEqual( + AutoInterpretation.get_tolerant_greatest_common_divisor([10, 5, 5]), 5 + ) + self.assertEqual( + AutoInterpretation.get_tolerant_greatest_common_divisor([100, 100, 100]), + 100, + ) + self.assertEqual( + AutoInterpretation.get_tolerant_greatest_common_divisor( + [100, 100, 200, 300, 100, 400] + ), + 100, + ) + self.assertEqual( + AutoInterpretation.get_tolerant_greatest_common_divisor( + [100, 101, 100, 100] + ), + 100, + ) + self.assertEqual( + AutoInterpretation.get_tolerant_greatest_common_divisor( + [100, 101, 202, 301, 100, 500] + ), + 100, + ) def test_get_bit_length_from_plateau_length(self): self.assertEqual(AutoInterpretation.get_bit_length_from_plateau_lengths([]), 0) - self.assertEqual(AutoInterpretation.get_bit_length_from_plateau_lengths([42]), 42) - plateau_lengths = np.array([2, 1, 2, 73, 1, 26, 100, 40, 1, 59, 100, 47, 1, 52, 67, 1, 10, 1, 21, 33, 1, 66, 100, 5, 1, 3, 1, 48, 1, 27, 1, 8], dtype=np.uint64) + self.assertEqual( + AutoInterpretation.get_bit_length_from_plateau_lengths([42]), 42 + ) + plateau_lengths = np.array( + [ + 2, + 1, + 2, + 73, + 1, + 26, + 100, + 40, + 1, + 59, + 100, + 47, + 1, + 52, + 67, + 1, + 10, + 1, + 21, + 33, + 1, + 66, + 100, + 5, + 1, + 3, + 1, + 48, + 1, + 27, + 1, + 8, + ], + dtype=np.uint64, + ) merged_lengths = AutoInterpretation.merge_plateau_lengths(plateau_lengths) - self.assertEqual(AutoInterpretation.get_bit_length_from_plateau_lengths(merged_lengths), 100) - + self.assertEqual( + AutoInterpretation.get_bit_length_from_plateau_lengths(merged_lengths), 100 + ) - plateau_lengths = np.array([1, 292, 331, 606, 647, 286, 645, 291, 334, 601, 339, 601, 338, 602, 337, 603, 338, 604, 336, 605, 337, 600, 338, 605, 646], dtype=np.uint64) + plateau_lengths = np.array( + [ + 1, + 292, + 331, + 606, + 647, + 286, + 645, + 291, + 334, + 601, + 339, + 601, + 338, + 602, + 337, + 603, + 338, + 604, + 336, + 605, + 337, + 600, + 338, + 605, + 646, + ], + dtype=np.uint64, + ) merged_lengths = AutoInterpretation.merge_plateau_lengths(plateau_lengths) - self.assertEqual(AutoInterpretation.get_bit_length_from_plateau_lengths(merged_lengths), 300) + self.assertEqual( + AutoInterpretation.get_bit_length_from_plateau_lengths(merged_lengths), 300 + ) - plateau_lengths = np.array([3, 8, 8, 8, 8, 8, 8, 8, 8, 16, 8, 8, 16, 32, 8, 8, 8, 8, 8, 24, 8, 24, 8, 24, 8, 24, 8, 24, 16, 16, 24, 8], dtype=np.uint64) + plateau_lengths = np.array( + [ + 3, + 8, + 8, + 8, + 8, + 8, + 8, + 8, + 8, + 16, + 8, + 8, + 16, + 32, + 8, + 8, + 8, + 8, + 8, + 24, + 8, + 24, + 8, + 24, + 8, + 24, + 8, + 24, + 16, + 16, + 24, + 8, + ], + dtype=np.uint64, + ) merged_lengths = AutoInterpretation.merge_plateau_lengths(plateau_lengths) - self.assertEqual(AutoInterpretation.get_bit_length_from_plateau_lengths(merged_lengths), 8) + self.assertEqual( + AutoInterpretation.get_bit_length_from_plateau_lengths(merged_lengths), 8 + ) def test_get_bit_length_from_merged_plateau_lengths(self): - merged_lengths = np.array([40, 40, 40, 40, 40, 30, 50, 30, 90, 40, 40, 80, 160, 30, 50, 30], dtype=np.uint64) - self.assertEqual(AutoInterpretation.get_bit_length_from_plateau_lengths(merged_lengths), 40) + merged_lengths = np.array( + [40, 40, 40, 40, 40, 30, 50, 30, 90, 40, 40, 80, 160, 30, 50, 30], + dtype=np.uint64, + ) + self.assertEqual( + AutoInterpretation.get_bit_length_from_plateau_lengths(merged_lengths), 40 + ) diff --git a/tests/auto_interpretation/test_center_detection.py b/tests/auto_interpretation/test_center_detection.py index 35cbcdbd98..e042153325 100644 --- a/tests/auto_interpretation/test_center_detection.py +++ b/tests/auto_interpretation/test_center_detection.py @@ -16,7 +16,9 @@ def generate_rectangular_signal(bits: str, bit_len: int): result = np.zeros(len(bits) * bit_len, dtype=np.float32) for i, bit in enumerate(bits): if int(bit) != 0: - result[i * bit_len:(i + 1) * bit_len] = np.ones(bit_len, dtype=np.int8) + result[i * bit_len : (i + 1) * bit_len] = np.ones( + bit_len, dtype=np.int8 + ) return result rect = generate_rectangular_signal("101010111100011", bit_len=10) @@ -51,7 +53,13 @@ def test_enocean_center_detection(self): self.assertLessEqual(center, 0.072, msg=str(i)) def test_ask_50_center_detection(self): - message_indices = [(0, 8000), (18000, 26000), (36000, 44000), (54000, 62000), (72000, 80000)] + message_indices = [ + (0, 8000), + (18000, 26000), + (36000, 44000), + (54000, 62000), + (72000, 80000), + ] data = Signal(get_path_for_data_file("ask50.complex")).iq_array.data rect = afp_demod(data, 0.0509, "ASK", 2) @@ -77,8 +85,10 @@ def test_homematic_center_detection(self): self.assertLessEqual(center2, -0.0367) def test_noised_homematic_center_detection(self): - data = Signal(get_path_for_data_file("noised_homematic.complex"), "").iq_array.data - rect = afp_demod(data, 0.0, "FSK", 2) + data = Signal( + get_path_for_data_file("noised_homematic.complex"), "" + ).iq_array.data + rect = afp_demod(data, 0.0, "FSK", 2) center = detect_center(rect) @@ -103,9 +113,13 @@ def test_fsk_live_capture(self): data = Signal(get_path_for_data_file("fsk_live.coco"), "").iq_array.data n = 10 - moving_average_filter = Filter([1/n for _ in range(n)], filter_type=FilterType.moving_average) - filtered_data = moving_average_filter.apply_fir_filter(data.flatten()).view(np.float32) - filtered_data = filtered_data.reshape((len(filtered_data)//2, 2)) + moving_average_filter = Filter( + [1 / n for _ in range(n)], filter_type=FilterType.moving_average + ) + filtered_data = moving_average_filter.apply_fir_filter(data.flatten()).view( + np.float32 + ) + filtered_data = filtered_data.reshape((len(filtered_data) // 2, 2)) rect = afp_demod(filtered_data, 0.0175, "FSK", 2) center = detect_center(rect) diff --git a/tests/auto_interpretation/test_estimate_tolerance.py b/tests/auto_interpretation/test_estimate_tolerance.py index 3d3578cc85..bb781d4078 100644 --- a/tests/auto_interpretation/test_estimate_tolerance.py +++ b/tests/auto_interpretation/test_estimate_tolerance.py @@ -7,34 +7,6074 @@ class TestEstimateTolerance(unittest.TestCase): def test_tolerance_estimation(self): - data = [[40, 4, 3, 8, 12, 3, 4, 3, 2, 9, 10, 4, 7, 12, 7, 5, 11, 4, 8, 10, 1, 1, 1, 1, 4, 4, 10, 7, 7, 1, 17, 1, 1, 5, 3, 2, 1, 3, 17, 1, 1, 1, 1, 3, 3, 7, 18, 1, 3, 1, 1, 8, 7, 6, 6, 14, 6, 5, 8, 14, 2, 6, 10, 16, 1, 1, 16, 7, 2, 6, 18, 3, 1, 4, 1, 5, 15, 1, 3, 1, 2, 1, 1, 9, 18, 15, 6, 3, 9, 13, 1, 1, 4, 4, 10, 15, 2, 1, 1, 1, 13, 5, 7, 3, 17, 1, 1, 1, 1, 2, 3, 2, 1, 4, 22, 2, 2, 7, 18, 15, 6, 4, 8, 15, 4, 3, 11, 15, 2, 4, 12, 8, 2, 2, 1, 2, 18, 3, 1, 3, 2, 6, 15, 1, 3, 1, 2, 4, 1, 6, 19, 2, 2, 10, 10, 2, 6, 15, 18, 15, 18, 15, 1, 3, 14, 4, 7, 4, 16, 1, 8, 8, 12, 1, 8, 1, 3, 8, 8, 5, 5, 15, 6, 5, 7, 15, 4, 4, 10, 15, 1, 5, 12, 7, 1, 7, 18, 3, 1, 3, 2, 6, 14, 1, 3, 3, 1, 11, 9, 2, 7, 15, 6, 6, 6, 15, 4, 6, 8, 15, 1, 7, 8, 7, 3, 1, 2, 4, 1, 2, 15, 3, 6, 6, 11, 1, 3, 1, 8, 8, 12, 1, 9, 1, 1, 10, 5, 7, 6, 15, 1, 1, 1, 7, 8, 15, 1, 6, 9, 22, 3, 1, 3, 4, 1, 1, 13, 1, 3, 3, 2, 3, 1, 5, 24, 9, 10, 3, 6, 1, 1, 12, 3, 8, 7, 15, 2, 14, 2, 7, 8, 10, 1, 10, 10, 1, 1, 1, 1, 3, 7, 4, 15, 1, 1, 1, 1, 3, 3, 2, 1, 5, 3, 1, 1, 12, 9, 1, 8, 2, 1, 9, 7, 8, 6, 15, 2, 7, 7, 17, 1, 21, 8, 11, 1, 8, 12, 3, 1, 1, 1, 1, 1, 12, 3, 1, 3, 10, 10, 2, 11, 9, 7, 5, 7, 15, 1, 23, 7, 24, 5, 22, 1, 7, 1, 8, 12, 3, 1, 1, 1, 1, 1, 12, 12, 3, 4, 1, 1, 12, 8, 4, 7, 15, 1, 24, 8, 22, 6, 31, 1, 8, 11, 4, 1, 3, 1, 3, 2, 6, 9, 6, 3, 2, 2, 10, 2, 15, 7, 4, 3, 19, 1, 32, 1, 23, 3, 26, 8, 3, 2, 1, 1, 14, 2, 2, 3, 11, 8, 3, 1, 2, 4, 1, 2, 11, 2, 11, 1, 2, 7, 26, 2, 55, 6, 20, 1, 1, 9, 3, 1, 3, 1, 13, 3, 1, 2, 12, 8, 5, 5, 1, 2, 11, 2, 10, 2, 2, 4, 11, 2, 16, 2, 32, 1, 22, 7, 19, 2, 2, 3, 2, 1, 7, 8, 7, 3, 1, 3, 11, 7, 5, 6, 2, 1, 9, 1, 1, 2, 15, 2, 11, 4, 16, 1, 24, 6, 24, 6, 21, 3, 1, 2, 3, 1, 7, 8, 7, 4, 1, 2, 11, 2, 13, 7, 4, 1, 2, 4, 16, 2, 12, 1, 41, 7, 37, 8, 1, 2, 4, 1, 1, 1, 1, 2, 12, 3, 1, 3, 6, 5, 1, 2, 11, 3, 10, 1, 1, 7, 8, 3, 17, 1, 23, 7, 24, 5, 30, 2, 7, 7, 3, 1, 4, 2, 1, 3, 12, 2, 13, 7, 7, 2, 1, 1, 1, 1, 12, 4, 1, 2, 51, 6, 57, 2, 2, 2, 7, 2, 15, 6, 1, 2, 7, 2, 12, 1, 1, 3, 1, 1, 9, 1, 2, 3, 7, 7, 26, 1, 88, 10, 6, 3, 13, 3, 1, 2, 11, 3, 2, 2, 7, 3, 1, 1, 1, 1, 12, 2, 8, 7, 181, 1, 16, 1, 9, 2, 1, 4, 7, 1, 2, 3, 2, 1, 8, 3, 12, 1, 9, 1, 3, 7, 13, 1, 8, 2, 1, 1, 1, 2, 3, 1, 54, 1, 16, 1, 15, 3], - [1, 1, 2, 3660, 1, 634, 1, 465, 1, 50, 1, 66, 1, 16, 1, 815, 1, 522, 1, 97, 1, 14, 1, 78, 1, 21, 1, 142, 1, 28, 1, 57, 1, 129, 1, 129, 1, 7, 1, 14, 1, 28, 1, 34, 1, 196, 1, 14, 1, 22, 1, 159, 1, 68, 1, 88, 1, 51, 1, 25, 1, 119, 1, 370], - [4, 2, 2, 1, 8, 1, 1, 1, 6, 2, 6, 2, 2, 1, 1, 1, 6, 1, 1, 2, 1, 1, 2, 2, 1, 1, 3, 2, 3, 1, 6, 1, 4, 2, 2, 1, 4, 2, 3, 2, 1, 2], - [1, 66, 1, 13, 1, 2, 1, 2, 104, 104, 104, 105, 104, 104, 104, 105, 104, 104, 104, 104, 104, 104, 104, 105, 104, 104, 104, 104, 105, 104, 104, 104, 104, 104, 104, 105, 104, 104, 104, 104, 105, 104, 104, 104, 104, 104, 104, 104, 209, 104, 105, 208, 104, 312, 105, 104, 104, 104, 521, 416, 105, 104, 208, 104, 313, 208, 209, 104, 104, 104, 417], - [1, 73, 1, 2, 1, 6, 1, 1, 105, 104, 104, 105, 104, 104, 104, 105, 104, 104, 104, 104, 104, 104, 104, 105, 104, 104, 104, 105, 104, 104, 104, 104, 104, 104, 104, 105, 104, 104, 104, 104, 105, 104, 104, 104, 105, 103, 104, 105, 208, 104, 104, 209, 104, 312, 105, 104, 104, 104, 521, 417, 104, 104, 208, 104, 313, 208, 209, 104, 104, 104, 416], - [1, 76, 1, 2, 1, 3, 1, 1, 105, 104, 104, 104, 105, 104, 104, 104, 105, 103, 104, 105, 104, 104, 104, 105, 104, 104, 104, 104, 105, 103, 104, 105, 104, 104, 104, 104, 105, 104, 104, 104, 105, 103, 104, 105, 104, 104, 104, 105, 208, 104, 104, 209, 103, 313, 105, 103, 104, 105, 521, 416, 104, 105, 208, 104, 313, 208, 209, 103, 104, 105, 416], - [1, 11, 1, 10, 1, 10, 1, 10, 1, 5, 1, 4, 1, 5, 1, 4, 2, 4, 1, 3, 3, 3, 3, 2, 104, 105, 104, 104, 105, 104, 103, 104, 105, 104, 104, 104, 105, 104, 104, 104, 104, 105, 104, 104, 104, 104, 104, 104, 105, 104, 104, 104, 104, 105, 104, 104, 103, 105, 104, 104, 105, 104, 104, 104, 208, 104, 105], - [1, 12, 1, 22, 1, 10, 1, 3, 1, 1, 1, 4, 1, 5, 1, 3, 2, 4, 2, 4, 2, 3, 2, 3, 104, 104, 105, 104, 104, 104, 105, 104, 104, 104, 104, 104, 105, 104, 104, 104, 104, 104, 105, 104, 105, 103, 104, 104, 104, 105, 104, 104, 104, 105, 104, 103, 105, 104, 104, 104, 105, 104, 104, 104, 209, 103, 105], - [1, 12, 1, 22, 1, 10, 1, 5, 1, 3, 2, 5, 1, 3, 2, 4, 2, 3, 3, 3, 2, 3, 104, 105, 104, 104, 105, 103, 104, 105, 104, 104, 104, 104, 105, 104, 104, 104, 104, 105, 104, 103, 105, 104, 104, 104, 104, 105, 104, 104, 104, 104, 105, 103, 105, 104, 104, 104, 104, 105, 104, 104, 208, 104, 104], - [1, 66, 1, 2, 1, 6, 1, 6, 1, 1, 105, 104, 104, 104, 105, 104, 104, 104, 105, 103, 105, 104, 104, 104, 104, 105, 104, 104, 104, 104, 105, 103, 105, 104, 104, 104, 104, 104, 105, 104, 104, 104, 105, 103, 104, 105, 104, 104, 104, 105, 208, 104, 104, 209, 104, 312, 105, 104, 104, 104, 521, 417, 103, 104, 209, 104, 313, 208, 209, 103, 104, 105, 416], - [1, 66, 1, 13, 1, 2, 1, 2, 105, 103, 104, 105, 104, 104, 104, 105, 104, 104, 104, 104, 105, 103, 104, 105, 104, 104, 104, 104, 105, 104, 104, 104, 105, 104, 103, 105, 104, 104, 104, 105, 104, 104, 104, 105, 104, 104, 104, 104, 208, 105, 104, 208, 104, 312, 105, 104, 104, 104, 521, 417, 104, 104, 208, 105, 312, 208, 209, 104, 104, 105, 416], - [1, 66, 1, 6, 1, 6, 1, 2, 1, 2, 105, 104, 104, 104, 105, 103, 104, 105, 104, 104, 104, 104, 105, 104, 104, 105, 104, 103, 104, 105, 104, 104, 104, 104, 105, 104, 104, 104, 104, 104, 105, 104, 104, 104, 104, 104, 105, 104, 104, 104, 208, 105, 104, 208, 104, 312, 105, 104, 104, 104, 521, 417, 104, 105, 207, 104, 314, 208, 208, 104, 104, 105, 416], - [2, 3, 13, 1, 5, 1, 1, 1, 26, 1, 2, 1, 2, 1, 6, 1, 5, 1, 2, 1, 5, 1, 3, 1, 6, 1, 3, 1, 3, 1, 7, 1, 1, 1, 3, 1, 19, 1, 7, 1, 26, 1, 26, 1, 2, 1, 5, 1, 2, 1, 3, 1, 7, 1, 12, 1, 6, 1, 24, 1, 4, 1, 6, 1, 6, 1, 4, 1, 1, 1, 27, 1, 6, 1, 7, 1, 13, 1, 6, 1, 7, 1, 6, 1, 16, 1, 1, 1, 11, 1, 6, 1, 1, 1, 3, 1, 2, 1, 1, 1, 4, 1, 6, 1, 3, 1, 2, 1, 3, 1, 2, 1, 6, 1, 3, 1, 2, 1, 1, 1, 2, 1, 3, 1, 2, 1, 3, 1, 6, 1, 2, 1, 3, 1, 4, 1, 112, 1, 2, 1, 5, 1, 1, 1, 4, 1, 1, 1, 4, 1, 1, 1, 4, 1, 1, 2, 3, 1, 1, 1, 2, 1, 1, 1, 1, 3, 4, 2, 1, 1, 2, 1, 1, 1, 1, 1, 2, 1, 3, 2, 1, 1, 1, 1, 4, 1, 4, 1, 1, 1, 4, 1, 6, 1, 28, 1, 83, 1, 1, 1, 5, 1, 6, 1, 6, 1, 4, 1, 2, 1, 3, 1, 2, 1, 6, 1, 3, 1, 2, 1, 3, 1, 2, 1, 3, 1, 4, 1, 1, 1, 4, 1, 2, 1, 3, 1, 4, 1, 1, 1, 4, 1, 1, 1, 5, 1, 9, 1, 6, 1, 4, 1, 11, 1, 13, 1, 7, 1, 6, 1, 40, 1, 3, 1, 1, 1, 2, 1, 6, 1, 3, 1, 2, 1, 3, 1, 13, 1, 6, 1, 6, 1, 25, 1, 6, 1, 4, 1, 6, 1, 45, 1, 14, 1, 6, 1, 6, 1, 14, 1, 16, 1, 1, 1, 3, 2, 1, 1, 1, 1, 1, 1, 1, 2, 1, 1, 1, 1, 4, 1, 6, 1, 1, 1, 1, 1, 2, 1, 4, 1, 1, 1, 3, 1, 2, 1, 4, 1, 1, 1, 4, 1, 6, 1, 3, 1, 2, 1, 4, 1, 6, 1, 10, 1, 112, 1, 1, 1, 1, 1, 4, 1, 1, 1, 4, 1, 2, 1, 3, 1, 1, 1, 4, 1, 1, 1, 4, 1, 1, 2, 3, 1, 1, 2, 1, 1, 1, 1, 1, 4, 1, 1, 1, 2, 1, 1, 2, 1, 1, 1, 2, 1, 1, 1, 4, 1, 1, 1, 4, 1, 4, 1, 1, 1, 4, 1, 3, 1, 24, 1, 78, 1, 7, 1, 20, 1, 7, 1, 6, 1, 3, 1, 2, 1, 3, 1, 2, 1, 3, 1, 4, 1, 2, 1, 3, 1, 2, 1, 3, 1, 6, 1, 4, 1, 1, 1, 11, 1, 7, 1, 7, 1, 25, 1, 11, 1, 7, 1, 27, 1, 9, 1, 1, 1, 2, 1, 1, 1, 3, 1, 2, 1, 3, 1, 2, 1, 3, 1, 2, 1, 3, 1, 2, 1, 3, 1, 6, 1, 25, 1, 13, 1, 11, 1, 65, 1, 13, 1, 7, 1, 6, 1, 6, 1, 3, 1, 4, 1, 1, 1, 2, 1, 1, 1, 1, 1, 1, 1, 2, 1, 1, 1, 1, 2, 1, 1, 1, 1, 2, 1, 1, 1, 4, 1, 1, 1, 4, 1, 1, 1, 4, 1, 1, 1, 4, 1, 6, 1, 3, 1, 2, 1, 4, 1, 1, 1, 1, 1, 2, 1, 6, 1, 3, 1, 2, 1, 3, 1, 108, 1, 3, 1, 1, 1, 2, 1, 3, 1, 2, 1, 3, 1, 1, 1, 4, 1, 1, 1, 4, 1, 2, 1, 3, 1, 2, 1, 3, 1, 4, 1, 1, 1, 1, 2, 1, 1, 1, 1, 4, 1, 1, 1, 2, 1, 1, 1, 2, 1, 1, 1, 1, 1, 2, 1, 1, 1, 2, 1, 1, 1, 2, 1, 1, 1, 4, 1, 10, 1, 7, 1, 6, 1, 14, 1, 66, 1, 8, 1, 6, 1, 6, 1, 6, 1, 10, 1, 6, 1, 6, 1, 6, 1, 7, 1, 3, 1, 6, 1, 4, 1, 1, 1, 4, 1, 2, 1, 3, 1, 19, 1, 7, 1, 14, 1, 18, 1, 10, 1, 7, 1, 6, 1, 13, 1, 7, 1, 1, 1, 6, 1, 1, 1, 4, 1, 5, 1, 2, 1, 3, 1, 7, 1, 6, 1, 6, 1, 3, 1, 6, 1, 6, 1, 18, 1, 11, 1, 57, 1, 14, 1, 13, 1, 6, 1, 11, 1, 1, 1, 1, 1, 4, 1, 1, 1, 1, 2, 1, 1, 1, 1, 2, 1, 1, 1, 1, 2, 1, 1, 1, 1, 1, 2, 1, 1, 4, 1, 1, 1, 4, 1, 1, 1, 4, 1, 1, 1, 4, 1, 3, 1, 2, 1, 4, 1, 1, 1, 4, 1, 3, 1, 2, 1, 3, 1, 2, 1, 4, 1, 13, 1, 97, 1, 1, 1, 2, 1, 3, 1, 2, 1, 3, 1, 1, 1, 4, 1, 2, 1, 3, 1, 2, 1, 3, 1, 4, 1, 1, 1, 4, 1, 1, 1, 4, 1, 1, 1, 4, 1, 6, 1, 1, 2, 1, 1, 1, 1, 1, 2, 1, 1, 1, 2, 1, 1, 1, 1, 2, 4, 1, 1, 1, 2, 12, 1, 6, 1, 7, 1, 21, 1, 14, 1, 13, 1, 26, 1, 8, 1, 5, 1, 6, 1, 13, 1, 10, 1, 6, 1, 7, 1, 6, 1, 3, 1, 6, 1, 4, 1, 2, 1, 3, 1, 2, 1, 3, 1, 31, 1, 7, 1, 14, 1, 3, 1, 25, 1, 7, 1, 16, 1, 8, 1, 1, 1, 4, 1, 1, 1, 4, 1, 1, 1, 4, 1, 6, 1, 1, 1, 4, 1, 6, 1, 3, 1, 2, 1, 3, 1, 6, 1, 7, 1, 3, 1, 13, 1, 52, 1, 21, 1, 21, 1, 6, 1, 5, 1, 2, 1, 6, 1, 1, 1, 1, 2, 3, 1, 1, 2, 1, 1, 1, 1, 1, 2, 1, 1, 1, 1, 2, 1, 1, 1, 1, 2, 1, 1, 1, 2, 1, 1, 1, 1, 4, 1, 1, 1, 4, 1, 4, 1, 1, 1, 4, 1, 1, 1, 4, 1, 3, 1, 2, 1, 3, 1, 2, 1, 4, 1, 3, 1, 108, 1, 1, 1, 5, 1, 6, 1, 2, 1, 3, 1, 6, 1, 4, 1, 1, 1, 6, 1, 4, 1, 2, 1, 3, 1, 2, 1, 3, 1, 1, 2, 3, 1, 4, 1, 1, 1, 4, 1, 1, 2, 1, 1, 1, 1, 1, 2, 1, 1, 1, 1, 1, 1, 15, 1, 3, 1, 6, 1, 7, 1, 29, 1, 46, 1, 2, 1, 8, 1, 12, 1, 25, 1, 13, 1, 11, 1, 3, 1, 6, 1, 6, 1, 21, 1, 7, 1, 14, 1, 6, 1, 7, 1, 6, 1, 5, 1, 4, 1, 11, 1, 6, 1, 7, 1, 6, 1, 20, 1, 6, 1, 6, 1, 13, 1, 57, 1, 1, 1, 6, 1, 6, 1, 6, 1, 6, 1, 6, 1, 6, 1, 3, 1, 2, 1, 3, 1, 2, 1, 3, 1, 6, 1, 4, 1, 2, 1, 3, 1, 6, 1, 4, 1, 2, 1, 1, 1, 6, 1, 15, 1, 5, 1, 7, 1, 7, 1, 3, 1, 4, 1, 7, 1, 5, 1, 21, 1, 6, 1, 9, 1, 3, 1, 1, 1, 2, 1, 3, 1, 2, 1, 6, 1, 6, 1, 6, 1, 3, 1, 2, 1, 3, 1, 2, 1, 3, 1, 11, 1, 6, 1, 6, 1, 11, 1, 6, 1, 6, 1, 11, 1, 3, 1, 6, 1, 4, 1, 2, 1, 3, 1, 6, 1, 4, 1, 2, 1, 3, 1, 2, 1, 1, 1, 1, 1, 4, 1, 2, 1, 3, 1, 2, 1, 1, 1, 1, 1, 4, 1, 4, 1, 1, 1, 1, 2, 1, 1, 9, 1, 25, 1, 7, 1, 6, 1, 14, 1, 6, 1, 28, 1, 6, 1, 2, 1, 1, 1, 6, 1, 6, 1, 6, 1, 10, 1, 13, 1, 6, 1, 10, 1, 7, 1, 6, 1, 3, 1, 7, 1, 6, 1, 3, 1, 6, 1, 4, 1, 2, 1, 3, 1, 2, 1, 4, 1, 3, 1, 2, 1, 3, 1, 2, 1, 1, 1, 1, 1, 4, 1, 2, 1, 3, 1, 1, 2, 1, 1, 1, 1, 4, 1, 1, 2, 1, 1, 1, 1, 1, 2, 1, 1, 2, 1, 1, 1, 1, 1, 2, 1, 1, 2, 1, 1, 1, 1, 2, 1, 1, 1, 3, 2, 1, 1, 4, 1, 1, 1, 4, 1, 4, 1, 1, 1, 4, 1, 1, 1, 4, 1, 4, 1, 6, 1, 3, 1, 2, 1, 4, 1, 3, 1, 2, 1, 3, 1, 7, 1, 3, 1, 2, 1, 3, 1, 4, 1, 82, 1, 21, 1, 3, 1, 5, 1, 1, 1, 4, 1, 1, 1, 6, 1, 4, 1, 1, 1, 4, 1, 1, 1, 4, 1, 1, 1, 2, 1, 1, 1, 1, 1, 4, 1, 1, 2, 1, 1, 1, 2, 1, 1, 1, 1, 1, 2, 1, 1, 1, 2, 1, 1, 1, 1, 2, 1, 1, 1, 4, 1, 1, 1, 1, 2, 1, 1, 3, 1, 4, 1, 8, 1, 22, 1, 71, 1, 8, 1, 6, 1, 5, 1, 7, 1, 6, 1, 3, 1, 2, 1, 3, 1, 6, 1, 2, 1, 3, 1, 4, 1, 1, 1, 4, 1, 2, 1, 3, 1, 4, 1, 1, 1, 4, 1, 1, 1, 4, 1, 5, 1, 7, 1, 6, 1, 8, 1, 7, 1, 8, 1, 5, 1, 6, 1, 14, 1, 6, 1, 28, 1, 103, 1, 42, 1, 6, 1, 6, 1, 6, 1, 20, 1, 5, 1, 8, 1, 2, 1, 4, 1, 7, 1, 6, 1, 12, 1, 6, 1, 28, 1, 6, 1, 153, 1, 6, 1, 6, 1, 20, 1, 5, 1, 7, 1, 2, 1, 13, 1, 5, 1, 8, 1, 5, 1, 2, 1, 6, 1, 1, 1, 1, 1, 2, 1, 3, 1, 2, 1, 6, 1, 3, 1, 2, 1, 6, 1, 4, 1, 6, 1, 6, 1, 3, 1, 6, 1, 7, 1, 10, 1, 18, 1, 6, 1, 11, 1, 3, 1, 2, 1, 6, 1, 3, 1, 7, 1, 3, 1, 2, 1, 4, 1, 3, 1, 2, 1, 3, 1, 4, 1, 2, 1, 3, 1, 2, 1, 1, 1, 3, 1, 8, 1, 7, 1, 14, 1, 22, 1, 14, 1, 6, 1, 21, 1, 6, 1, 6, 1, 96, 1, 1, 1, 5, 1, 7, 1, 6, 1, 5, 1, 6, 1, 4, 1, 2, 1, 3, 1, 2, 1, 3, 1, 6, 1, 4, 1, 1, 1, 4, 1, 2, 1, 3, 1, 1, 2, 3, 1, 1, 2, 1, 1, 1, 1, 4, 1, 6, 1, 8, 1, 2, 1, 14, 1, 6, 1, 13, 1, 7, 1, 6, 1, 28, 1, 6, 1, 104, 1, 2, 1, 5, 1, 2, 1, 6, 1, 5, 1, 4, 1, 2, 1, 3, 1, 2, 1, 3, 1, 2, 1, 3, 1, 1, 2, 1, 1, 1, 1, 1, 2, 1, 1, 1, 1, 4, 1, 1, 1, 4, 1, 1, 2, 1, 1, 1, 1, 2, 1, 1, 1, 1, 2, 1, 4, 1, 1, 2, 1, 22, 1, 6, 1, 162, 1, 6, 1, 35, 1, 6, 1, 6, 1, 5, 1, 7, 1, 3, 1, 3, 1, 8, 1, 5, 1, 20, 1, 4, 1, 4, 1, 1, 1, 1, 1, 4, 1, 1, 1, 3, 1, 2, 1, 3, 1, 2, 1, 4, 1, 6, 1, 6, 1, 6, 1, 10, 1, 18, 1, 6, 1, 6, 1, 11, 1, 11, 1, 5, 1, 7, 1, 3, 1, 6, 1, 4, 1, 2, 1, 3, 1, 4, 1, 1, 1, 4, 1, 2, 1, 4, 1, 3, 1, 6, 1, 4, 1, 1, 1, 4, 1, 22, 1, 17, 1, 6, 1, 7, 1, 6, 1, 21, 1, 6, 1, 28, 1, 98, 1, 2, 1, 3, 1, 2, 1, 3, 1, 2, 1, 3, 1, 2, 1, 3, 1, 2, 1, 3, 1, 6, 1, 4, 1, 1, 1, 4, 1, 2, 1, 3, 1, 1, 1, 4, 1, 1, 2, 1, 1, 1, 1, 4, 1, 1, 1, 4, 1, 1, 2, 1, 1, 1, 1, 4, 1, 10, 1, 5, 1, 14, 1, 14, 1, 35, 1, 21, 1, 1, 1, 5, 1, 7, 1, 5, 1, 6, 1, 6, 1, 24, 1, 7, 1, 3, 1, 2, 1, 3, 1, 7, 1, 3, 1, 2, 1, 33, 1, 14, 1, 6, 1, 6, 1, 14, 1, 2, 1, 1, 1, 11, 1, 5, 1, 6, 1, 6, 1, 28, 1, 146, 1, 6, 1, 6, 1, 34, 1, 6, 1, 7, 1, 5, 1, 2, 1, 8, 1, 4, 1, 5, 1, 6, 1, 6, 1, 7, 1, 17, 1, 1, 1, 5, 1, 2, 1, 3, 1, 2, 1, 6, 1, 6, 1, 6, 1, 3, 1, 2, 1, 3, 1, 13, 1, 11, 1, 6, 1, 48, 1, 36, 1, 13, 1, 6, 1, 7, 1, 6, 1, 2, 1, 1, 1, 1, 2, 3, 1, 2, 1, 1, 1, 1, 1, 2, 1, 1, 1, 1, 2, 1, 1, 1, 1, 1, 2, 1, 1, 1, 1, 4, 1, 1, 1, 4, 1, 3, 2, 1, 1, 4, 1, 1, 1, 4, 1, 1, 1, 4, 1, 3, 1, 2, 1, 3, 1, 2, 1, 4, 1, 3, 1, 2, 1, 3, 1, 2, 1, 4, 1, 10, 1, 6, 1, 11, 1, 11, 1, 13, 1, 11, 1, 3, 1, 6, 1, 7, 1, 3, 1, 37, 1, 6, 1, 22, 1, 6, 1, 6, 1, 11, 1, 3, 1, 7, 1, 3, 1, 6, 1, 1, 1, 1, 1, 4, 1, 1, 1, 4, 1, 1, 1, 4, 1, 1, 1, 4, 1, 1, 1, 4, 1, 6, 1, 4, 1, 1, 1, 3, 1, 7, 1, 3, 1, 2, 1, 3, 1, 2, 1, 3, 1, 7, 1, 3, 1, 82, 1, 6, 1, 20, 1, 14, 1, 6, 1, 6, 1, 6, 1, 29, 1, 6, 1, 6, 1, 6, 1, 6, 1, 8, 1, 6, 1, 1, 1, 3, 1, 2, 1, 3, 1, 2, 1, 3, 1, 2, 1, 6, 1, 3, 1, 2, 1, 3, 1, 6, 1, 6, 1, 7, 1, 10, 1, 18, 1, 41, 1, 57, 1, 7, 1, 16, 1, 18, 1, 6, 1, 7, 1, 6, 1, 20, 1, 6, 1, 6, 1, 153, 1, 6, 1, 20, 1, 21, 1, 13, 1, 1, 1, 1, 1, 1, 1, 1, 1, 2, 1, 1, 1, 2, 1, 1, 1, 6, 1, 1, 1, 1, 1, 2, 1, 4, 1, 1, 1, 3, 1, 2, 1, 4, 1, 1, 1, 3, 1, 7, 1, 3, 1, 2, 1, 3, 1, 2, 1, 3, 1, 7, 1, 3, 1, 107, 1, 4, 1, 2, 1, 5, 1, 2, 1, 3, 1, 1, 1, 4, 1, 1, 1, 4, 1, 1, 1, 4, 1, 1, 2, 3, 1, 1, 1, 4, 1, 1, 2, 3, 1, 1, 2, 1, 1, 1, 1, 2, 1, 1, 1, 2, 1, 1, 1, 2, 1, 1, 1, 4, 1, 1, 1, 4, 1, 3, 2, 1, 1, 43, 1, 21, 1, 111, 1, 6, 1, 21, 1, 6, 1, 6, 1, 6, 1, 6, 1, 6, 1, 10, 1, 1, 1, 2, 1, 7, 1, 5, 1, 6, 1, 6, 1, 6, 1, 13, 1, 6, 1, 6, 1, 8, 1, 3, 1, 2, 1, 5, 1, 7, 1, 6, 1, 6, 1, 5, 1, 4, 1, 6, 1, 11, 1, 13, 1, 48, 1, 14, 1, 6, 1, 21, 1, 6, 1, 6, 1, 7, 1, 6, 1, 15, 1, 5, 1, 6, 1, 6, 1, 28, 1, 167, 1, 6, 1, 13, 1, 6, 1, 6, 1, 30, 1, 5, 1, 6, 1, 6, 1, 6, 1, 28, 1, 6, 1, 13, 1, 110, 1, 27, 1, 28, 1, 6, 1, 30, 1, 19, 1, 6, 1, 6, 1, 49, 1, 103, 1, 6, 1, 6, 1, 13, 1, 27, 1, 5, 1, 1, 1, 1, 1, 1, 2, 1, 1, 1, 1, 2, 1, 1, 1, 1, 1, 2, 1, 1, 1, 2, 1, 1, 1, 3, 2, 1, 1, 4, 1, 1, 1, 4, 1, 1, 1, 4, 1, 1, 1, 4, 1, 3, 1, 2, 1, 4, 1, 1, 1, 4, 1, 1, 1, 4, 1, 3, 1, 2, 1, 4, 1, 148, 1, 6, 1, 6, 1, 6, 1, 6, 1, 19, 1, 16, 1, 6, 1, 6, 1, 7, 1, 20, 1, 27, 1, 110, 1, 56, 1, 6, 1, 6, 1, 6, 1, 4, 1, 16, 1, 6, 1, 7, 1, 6, 1, 20, 1, 6, 1, 89, 1, 6, 1, 6, 1, 6, 1, 6, 1, 3, 1, 2, 1, 3, 1, 6, 1, 6, 1, 4, 1, 2, 1, 3, 1, 2, 1, 3, 1, 6, 1, 4, 1, 2, 1, 3, 1, 2, 1, 14, 1, 6, 1, 6, 1, 8, 1, 3, 1, 3, 1, 7, 1, 6, 1, 6, 1, 6, 1, 14, 1, 6, 1, 6, 1, 14, 1, 131, 1, 28, 1, 6, 1, 6, 1, 6, 1, 5, 1, 6, 1, 6, 1, 2, 1, 5, 1, 7, 1, 6, 1, 20, 1, 6, 1, 167, 1, 6, 1, 6, 1, 6, 1, 6, 1, 20, 1, 6, 1, 6, 1, 2, 1, 5, 1, 7, 1, 5, 1, 6, 1, 6, 1, 14, 1, 20, 1, 159, 1, 1, 1, 1, 1, 6, 1, 2, 1, 3, 1, 1, 1, 4, 1, 1, 2, 3, 1, 1, 1, 2, 1, 1, 1, 1, 3, 2, 1, 1, 2, 1, 1, 1, 2, 1, 1, 1, 1, 2, 1, 3, 2, 1, 1, 1, 1, 2, 1, 1, 1, 4, 1, 6, 1, 3, 1, 2, 1, 4, 1, 2, 1, 8, 1, 156, 1, 6, 1, 6, 1, 6, 1, 20, 1, 6, 1, 7, 1, 5, 1, 2, 1, 8, 1, 3, 1, 13, 1, 7, 1, 27, 1, 6, 1, 131, 1, 35, 1, 6, 1, 6, 1, 6, 1, 6, 1, 13, 1, 2, 1, 7, 1, 4, 1, 20, 1, 6, 1, 6, 1, 28, 1, 13, 1, 117, 1, 13, 1, 34, 1, 7, 1, 6, 1, 5, 1, 2, 1, 7, 1, 5, 1, 20, 1, 6, 1, 13, 1, 6, 1, 167, 1, 6, 1, 20, 1, 6, 1, 7, 1, 5, 1, 2, 1, 7, 1, 5, 1, 5, 1, 6, 1, 6, 1, 28, 1, 6, 1, 181, 1, 6, 1, 6, 1, 12, 1, 2, 1, 7, 1, 5, 1, 20, 1, 6, 1, 6, 1, 6, 1, 41, 1, 2, 1, 8, 1, 6, 1, 3, 1, 20, 1, 13, 1, 6, 1, 3, 1, 6, 1, 7, 1, 6, 1, 3, 1, 4, 1, 2, 1, 3, 1, 6, 1, 4, 1, 1, 1, 4, 1, 2, 1, 3, 1, 4, 1, 2, 1, 3, 1, 1, 2, 1, 1, 1, 1, 4, 1, 1, 1, 2, 1, 1, 1, 1, 2, 1, 1, 1, 1, 1, 2, 1, 1, 1, 3, 2, 1, 2, 1, 2, 3, 1, 1, 1, 2, 1, 1, 4, 1, 1, 1, 4, 1, 1, 1, 2, 1, 1, 1, 4, 1, 1, 1, 3, 1, 4, 1, 2, 1, 4, 1, 6, 1, 3, 1, 2, 1, 3, 1, 2, 1, 4, 1, 3, 1, 2, 1, 4, 1, 6, 1, 3, 1, 6, 1, 4, 1, 109, 1, 2, 1, 1, 1, 2, 1, 3, 1, 1, 1, 4, 1, 1, 1, 4, 1, 1, 1, 4, 1, 1, 1, 2, 1, 1, 1, 1, 2, 3, 1, 4, 1, 1, 1, 2, 1, 1, 2, 1, 1, 1, 1, 1, 2, 1, 1, 1, 1, 4, 1, 4, 1, 1, 1, 4, 1, 1, 1, 4, 1, 3, 1, 2, 1, 37, 1, 7, 1, 65, 1, 2, 1, 5, 1, 6, 1, 6, 1, 7, 1, 3, 1, 2, 1, 3, 1, 2, 1, 3, 1, 6, 1, 4, 1, 1, 1, 7, 1, 3, 1, 4, 1, 1, 1, 2, 1, 1, 1, 1, 1, 4, 1, 1, 1, 2, 1, 4, 1, 7, 1, 16, 1, 14, 1, 7, 1, 59, 1, 6, 1, 2, 1, 6, 1, 3, 1, 13, 1, 6, 1, 25, 1, 6, 1, 10, 1, 6, 1, 2, 1, 22, 1, 14, 1, 14, 1, 6, 1, 20, 1, 6, 1, 6, 1, 2, 1, 5, 1, 7, 1, 6, 1, 6, 1, 6, 1, 6, 1, 28, 1, 6, 1, 131, 1, 35, 1, 6, 1, 6, 1, 5, 1, 6, 1, 6, 1, 2, 1, 13, 1, 6, 1, 6, 1, 13, 1, 6, 1, 6, 1, 160, 1, 13, 1, 13, 1, 14, 1, 5, 1, 5, 1, 7, 1, 2, 1, 5, 1, 7, 1, 5, 1, 6, 1, 39, 1, 3, 1, 1, 1, 2, 1, 3, 1, 2, 1, 3, 1, 2, 1, 3, 1, 2, 1, 6, 1, 3, 1, 6, 1, 32, 1, 10, 1, 7, 1, 68, 1, 20, 1, 6, 1, 7, 1, 5, 1, 2, 1, 7, 1, 5, 1, 20, 1, 6, 1, 13, 1, 6, 1, 167, 1, 6, 1, 20, 1, 6, 1, 7, 1, 5, 1, 2, 1, 6, 1, 1, 1, 3, 1, 6, 1, 6, 1, 7, 1, 27, 1, 6, 1, 78, 1, 6, 1, 6, 1, 5, 1, 6, 1, 7, 1, 3, 1, 6, 1, 4, 1, 1, 1, 4, 1, 2, 1, 3, 1, 2, 1, 3, 1, 4, 1, 2, 1, 41, 1, 16, 1, 11, 1, 7, 1, 29, 1, 5, 1, 2, 1, 3, 1, 2, 1, 1, 1, 3, 1, 2, 1, 4, 1, 5, 1, 7, 1, 3, 1, 2, 1, 3, 1, 6, 1, 6, 1, 4, 1, 13, 1, 6, 1, 4, 1, 6, 1, 6, 1, 3, 1, 7, 1, 3, 1, 2, 1, 3, 1, 4, 1, 2, 1, 3, 1, 6, 1, 4, 1, 2, 1, 3, 1, 6, 1, 4, 1, 2, 1, 3, 1, 4, 1, 1, 1, 4, 1, 1, 1, 2, 1, 3, 1, 9, 1, 5, 1, 2, 1, 7, 1, 6, 1, 6, 1, 6, 1, 7, 1, 6, 1, 6, 1, 14, 1, 123, 1, 2, 1, 1, 1, 3, 1, 2, 1, 3, 1, 2, 1, 3, 1, 2, 1, 3, 1, 6, 1, 1, 1, 4, 1, 6, 1, 4, 1, 1, 1, 4, 1, 1, 1, 4, 1, 1, 2, 3, 1, 2, 1, 1, 1, 1, 1, 2, 1, 1, 1, 2, 1, 1, 2, 1, 1, 1, 1, 11, 1, 7, 1, 7, 1, 212, 1, 6, 1, 6, 1, 13, 1, 15, 1, 27, 1, 6, 1, 6, 1, 153, 1, 6, 1, 6, 1, 6, 1, 6, 1, 20, 1, 7, 1, 13, 1, 3, 1, 11, 1, 5, 1, 6, 1, 7, 1, 27, 1, 80, 1, 20, 1, 2775, 3, 20, 1, 16, 1, 2, 1, 17], - [1, 53, 1, 9, 1, 3, 1, 6, 1, 5, 2, 2, 1, 1, 105, 104, 104, 104, 105, 103, 104, 105, 104, 104, 104, 104, 105, 104, 104, 104, 105, 103, 105, 104, 104, 104, 104, 104, 105, 104, 104, 104, 105, 103, 104, 105, 104, 104, 104, 105, 104, 104, 104, 104, 208, 105, 104, 208, 104, 313, 104, 104, 104, 104, 521, 417, 104, 104, 208, 104, 313, 209, 208, 104, 104, 104, 417], - [1, 69, 1, 6, 1, 6, 1, 1, 105, 104, 104, 105, 104, 104, 104, 105, 104, 104, 104, 104, 104, 104, 104, 105, 104, 104, 104, 105, 104, 104, 104, 105, 104, 103, 104, 105, 104, 104, 104, 104, 105, 104, 104, 104, 105, 103, 104, 105, 208, 104, 105, 208, 104, 312, 105, 104, 104, 104, 521, 417, 104, 104, 208, 105, 312, 208, 209, 104, 104, 104, 417], - [1, 66, 1, 9, 1, 3, 1, 4, 105, 104, 105, 104, 104, 104, 104, 105, 104, 104, 104, 104, 105, 103, 105, 104, 104, 104, 104, 105, 104, 104, 104, 104, 104, 104, 104, 105, 104, 104, 104, 105, 104, 104, 104, 104, 105, 103, 104, 105, 208, 105, 104, 208, 104, 312, 105, 104, 104, 104, 521, 417, 104, 104, 208, 104, 313, 208, 209, 104, 104, 105, 416], - [1, 51, 1, 13, 1, 3, 3, 6, 106, 105, 103, 105, 104, 105, 104, 103, 105, 104, 104, 104, 105, 104, 104, 104, 104, 104, 104, 105, 104, 104, 104, 104, 104, 105, 103, 105, 105, 104, 104, 103, 104, 105, 104, 104, 105, 104, 104, 103, 209, 105, 104], - [2, 72, 1, 5, 1, 2, 106, 105, 103, 105, 104, 105, 103, 104, 104, 104, 105, 104, 105, 103, 105, 104, 104, 104, 104, 105, 103, 105, 104, 104, 104, 105, 103, 105, 103, 105, 104, 104, 104, 104, 105, 104, 104, 104, 105, 103, 209, 104, 105], - [1, 78, 3, 1, 106, 104, 104, 104, 104, 105, 104, 104, 104, 104, 104, 105, 104, 104, 105, 103, 104, 104, 104, 105, 104, 105, 104, 103, 105, 104, 104, 105, 104, 104, 104, 104, 104, 104, 104, 105, 104, 104, 105, 103, 208, 105, 103], - [1, 83, 1, 1, 105, 104, 104, 104, 105, 104, 104, 104, 105, 104, 104, 104, 105, 103, 104, 104, 105, 104, 104, 104, 105, 103, 105, 103, 105, 104, 104, 104, 105, 104, 104, 104, 105, 104, 104, 104, 104, 104, 104, 105, 208, 104, 104, 208, 104, 313, 105, 104, 104, 103, 522, 416, 104, 104, 209, 104, 313, 208, 209, 104, 103, 105, 416], - [1, 80, 1, 2, 1, 1, 105, 104, 104, 104, 105, 104, 104, 104, 104, 105, 104, 104, 104, 104, 104, 105, 104, 104, 104, 104, 104, 104, 104, 105, 104, 104, 104, 104, 105, 104, 104, 104, 104, 105, 103, 105, 104, 104, 104, 104, 208, 105, 104, 208, 104, 313, 105, 104, 103, 104, 522, 416, 104, 104, 209, 104, 313, 208, 208, 104, 104, 105, 416], - [1, 73, 1, 2, 1, 9, 105, 104, 104, 104, 105, 103, 104, 105, 104, 104, 104, 105, 104, 104, 104, 104, 105, 103, 105, 104, 104, 104, 104, 105, 104, 104, 104, 104, 104, 104, 104, 105, 104, 104, 104, 105, 104, 104, 104, 104, 208, 105, 104, 208, 104, 313, 104, 104, 104, 104, 522, 416, 104, 104, 208, 105, 312, 209, 208, 104, 104, 105, 416], - [1, 13, 2, 4, 1, 9, 1, 4, 2, 9, 1, 4, 2, 3, 3, 4, 1, 9, 1, 3, 3, 4, 2, 2, 105, 105, 104, 103, 105, 104, 104, 104, 105, 104, 104, 104, 104, 104, 104, 105, 104, 104, 104, 104, 105, 103, 104, 106, 104, 104, 104, 103, 105, 104, 104, 105, 104, 104, 104, 104, 104, 104, 104, 104, 209, 104, 105], - [1, 9, 3, 3, 2, 9, 1, 4, 2, 4, 2, 8, 1, 4, 2, 4, 2, 4, 2, 2, 1, 5, 2, 3, 3, 3, 2, 2, 106, 104, 104, 103, 105, 104, 104, 105, 104, 104, 104, 104, 105, 103, 104, 106, 103, 105, 104, 103, 105, 103, 105, 105, 104, 104, 104, 103, 105, 104, 104, 105, 104, 104, 104, 104, 105, 104, 103, 106, 207, 104, 105],] + data = [ + [ + 40, + 4, + 3, + 8, + 12, + 3, + 4, + 3, + 2, + 9, + 10, + 4, + 7, + 12, + 7, + 5, + 11, + 4, + 8, + 10, + 1, + 1, + 1, + 1, + 4, + 4, + 10, + 7, + 7, + 1, + 17, + 1, + 1, + 5, + 3, + 2, + 1, + 3, + 17, + 1, + 1, + 1, + 1, + 3, + 3, + 7, + 18, + 1, + 3, + 1, + 1, + 8, + 7, + 6, + 6, + 14, + 6, + 5, + 8, + 14, + 2, + 6, + 10, + 16, + 1, + 1, + 16, + 7, + 2, + 6, + 18, + 3, + 1, + 4, + 1, + 5, + 15, + 1, + 3, + 1, + 2, + 1, + 1, + 9, + 18, + 15, + 6, + 3, + 9, + 13, + 1, + 1, + 4, + 4, + 10, + 15, + 2, + 1, + 1, + 1, + 13, + 5, + 7, + 3, + 17, + 1, + 1, + 1, + 1, + 2, + 3, + 2, + 1, + 4, + 22, + 2, + 2, + 7, + 18, + 15, + 6, + 4, + 8, + 15, + 4, + 3, + 11, + 15, + 2, + 4, + 12, + 8, + 2, + 2, + 1, + 2, + 18, + 3, + 1, + 3, + 2, + 6, + 15, + 1, + 3, + 1, + 2, + 4, + 1, + 6, + 19, + 2, + 2, + 10, + 10, + 2, + 6, + 15, + 18, + 15, + 18, + 15, + 1, + 3, + 14, + 4, + 7, + 4, + 16, + 1, + 8, + 8, + 12, + 1, + 8, + 1, + 3, + 8, + 8, + 5, + 5, + 15, + 6, + 5, + 7, + 15, + 4, + 4, + 10, + 15, + 1, + 5, + 12, + 7, + 1, + 7, + 18, + 3, + 1, + 3, + 2, + 6, + 14, + 1, + 3, + 3, + 1, + 11, + 9, + 2, + 7, + 15, + 6, + 6, + 6, + 15, + 4, + 6, + 8, + 15, + 1, + 7, + 8, + 7, + 3, + 1, + 2, + 4, + 1, + 2, + 15, + 3, + 6, + 6, + 11, + 1, + 3, + 1, + 8, + 8, + 12, + 1, + 9, + 1, + 1, + 10, + 5, + 7, + 6, + 15, + 1, + 1, + 1, + 7, + 8, + 15, + 1, + 6, + 9, + 22, + 3, + 1, + 3, + 4, + 1, + 1, + 13, + 1, + 3, + 3, + 2, + 3, + 1, + 5, + 24, + 9, + 10, + 3, + 6, + 1, + 1, + 12, + 3, + 8, + 7, + 15, + 2, + 14, + 2, + 7, + 8, + 10, + 1, + 10, + 10, + 1, + 1, + 1, + 1, + 3, + 7, + 4, + 15, + 1, + 1, + 1, + 1, + 3, + 3, + 2, + 1, + 5, + 3, + 1, + 1, + 12, + 9, + 1, + 8, + 2, + 1, + 9, + 7, + 8, + 6, + 15, + 2, + 7, + 7, + 17, + 1, + 21, + 8, + 11, + 1, + 8, + 12, + 3, + 1, + 1, + 1, + 1, + 1, + 12, + 3, + 1, + 3, + 10, + 10, + 2, + 11, + 9, + 7, + 5, + 7, + 15, + 1, + 23, + 7, + 24, + 5, + 22, + 1, + 7, + 1, + 8, + 12, + 3, + 1, + 1, + 1, + 1, + 1, + 12, + 12, + 3, + 4, + 1, + 1, + 12, + 8, + 4, + 7, + 15, + 1, + 24, + 8, + 22, + 6, + 31, + 1, + 8, + 11, + 4, + 1, + 3, + 1, + 3, + 2, + 6, + 9, + 6, + 3, + 2, + 2, + 10, + 2, + 15, + 7, + 4, + 3, + 19, + 1, + 32, + 1, + 23, + 3, + 26, + 8, + 3, + 2, + 1, + 1, + 14, + 2, + 2, + 3, + 11, + 8, + 3, + 1, + 2, + 4, + 1, + 2, + 11, + 2, + 11, + 1, + 2, + 7, + 26, + 2, + 55, + 6, + 20, + 1, + 1, + 9, + 3, + 1, + 3, + 1, + 13, + 3, + 1, + 2, + 12, + 8, + 5, + 5, + 1, + 2, + 11, + 2, + 10, + 2, + 2, + 4, + 11, + 2, + 16, + 2, + 32, + 1, + 22, + 7, + 19, + 2, + 2, + 3, + 2, + 1, + 7, + 8, + 7, + 3, + 1, + 3, + 11, + 7, + 5, + 6, + 2, + 1, + 9, + 1, + 1, + 2, + 15, + 2, + 11, + 4, + 16, + 1, + 24, + 6, + 24, + 6, + 21, + 3, + 1, + 2, + 3, + 1, + 7, + 8, + 7, + 4, + 1, + 2, + 11, + 2, + 13, + 7, + 4, + 1, + 2, + 4, + 16, + 2, + 12, + 1, + 41, + 7, + 37, + 8, + 1, + 2, + 4, + 1, + 1, + 1, + 1, + 2, + 12, + 3, + 1, + 3, + 6, + 5, + 1, + 2, + 11, + 3, + 10, + 1, + 1, + 7, + 8, + 3, + 17, + 1, + 23, + 7, + 24, + 5, + 30, + 2, + 7, + 7, + 3, + 1, + 4, + 2, + 1, + 3, + 12, + 2, + 13, + 7, + 7, + 2, + 1, + 1, + 1, + 1, + 12, + 4, + 1, + 2, + 51, + 6, + 57, + 2, + 2, + 2, + 7, + 2, + 15, + 6, + 1, + 2, + 7, + 2, + 12, + 1, + 1, + 3, + 1, + 1, + 9, + 1, + 2, + 3, + 7, + 7, + 26, + 1, + 88, + 10, + 6, + 3, + 13, + 3, + 1, + 2, + 11, + 3, + 2, + 2, + 7, + 3, + 1, + 1, + 1, + 1, + 12, + 2, + 8, + 7, + 181, + 1, + 16, + 1, + 9, + 2, + 1, + 4, + 7, + 1, + 2, + 3, + 2, + 1, + 8, + 3, + 12, + 1, + 9, + 1, + 3, + 7, + 13, + 1, + 8, + 2, + 1, + 1, + 1, + 2, + 3, + 1, + 54, + 1, + 16, + 1, + 15, + 3, + ], + [ + 1, + 1, + 2, + 3660, + 1, + 634, + 1, + 465, + 1, + 50, + 1, + 66, + 1, + 16, + 1, + 815, + 1, + 522, + 1, + 97, + 1, + 14, + 1, + 78, + 1, + 21, + 1, + 142, + 1, + 28, + 1, + 57, + 1, + 129, + 1, + 129, + 1, + 7, + 1, + 14, + 1, + 28, + 1, + 34, + 1, + 196, + 1, + 14, + 1, + 22, + 1, + 159, + 1, + 68, + 1, + 88, + 1, + 51, + 1, + 25, + 1, + 119, + 1, + 370, + ], + [ + 4, + 2, + 2, + 1, + 8, + 1, + 1, + 1, + 6, + 2, + 6, + 2, + 2, + 1, + 1, + 1, + 6, + 1, + 1, + 2, + 1, + 1, + 2, + 2, + 1, + 1, + 3, + 2, + 3, + 1, + 6, + 1, + 4, + 2, + 2, + 1, + 4, + 2, + 3, + 2, + 1, + 2, + ], + [ + 1, + 66, + 1, + 13, + 1, + 2, + 1, + 2, + 104, + 104, + 104, + 105, + 104, + 104, + 104, + 105, + 104, + 104, + 104, + 104, + 104, + 104, + 104, + 105, + 104, + 104, + 104, + 104, + 105, + 104, + 104, + 104, + 104, + 104, + 104, + 105, + 104, + 104, + 104, + 104, + 105, + 104, + 104, + 104, + 104, + 104, + 104, + 104, + 209, + 104, + 105, + 208, + 104, + 312, + 105, + 104, + 104, + 104, + 521, + 416, + 105, + 104, + 208, + 104, + 313, + 208, + 209, + 104, + 104, + 104, + 417, + ], + [ + 1, + 73, + 1, + 2, + 1, + 6, + 1, + 1, + 105, + 104, + 104, + 105, + 104, + 104, + 104, + 105, + 104, + 104, + 104, + 104, + 104, + 104, + 104, + 105, + 104, + 104, + 104, + 105, + 104, + 104, + 104, + 104, + 104, + 104, + 104, + 105, + 104, + 104, + 104, + 104, + 105, + 104, + 104, + 104, + 105, + 103, + 104, + 105, + 208, + 104, + 104, + 209, + 104, + 312, + 105, + 104, + 104, + 104, + 521, + 417, + 104, + 104, + 208, + 104, + 313, + 208, + 209, + 104, + 104, + 104, + 416, + ], + [ + 1, + 76, + 1, + 2, + 1, + 3, + 1, + 1, + 105, + 104, + 104, + 104, + 105, + 104, + 104, + 104, + 105, + 103, + 104, + 105, + 104, + 104, + 104, + 105, + 104, + 104, + 104, + 104, + 105, + 103, + 104, + 105, + 104, + 104, + 104, + 104, + 105, + 104, + 104, + 104, + 105, + 103, + 104, + 105, + 104, + 104, + 104, + 105, + 208, + 104, + 104, + 209, + 103, + 313, + 105, + 103, + 104, + 105, + 521, + 416, + 104, + 105, + 208, + 104, + 313, + 208, + 209, + 103, + 104, + 105, + 416, + ], + [ + 1, + 11, + 1, + 10, + 1, + 10, + 1, + 10, + 1, + 5, + 1, + 4, + 1, + 5, + 1, + 4, + 2, + 4, + 1, + 3, + 3, + 3, + 3, + 2, + 104, + 105, + 104, + 104, + 105, + 104, + 103, + 104, + 105, + 104, + 104, + 104, + 105, + 104, + 104, + 104, + 104, + 105, + 104, + 104, + 104, + 104, + 104, + 104, + 105, + 104, + 104, + 104, + 104, + 105, + 104, + 104, + 103, + 105, + 104, + 104, + 105, + 104, + 104, + 104, + 208, + 104, + 105, + ], + [ + 1, + 12, + 1, + 22, + 1, + 10, + 1, + 3, + 1, + 1, + 1, + 4, + 1, + 5, + 1, + 3, + 2, + 4, + 2, + 4, + 2, + 3, + 2, + 3, + 104, + 104, + 105, + 104, + 104, + 104, + 105, + 104, + 104, + 104, + 104, + 104, + 105, + 104, + 104, + 104, + 104, + 104, + 105, + 104, + 105, + 103, + 104, + 104, + 104, + 105, + 104, + 104, + 104, + 105, + 104, + 103, + 105, + 104, + 104, + 104, + 105, + 104, + 104, + 104, + 209, + 103, + 105, + ], + [ + 1, + 12, + 1, + 22, + 1, + 10, + 1, + 5, + 1, + 3, + 2, + 5, + 1, + 3, + 2, + 4, + 2, + 3, + 3, + 3, + 2, + 3, + 104, + 105, + 104, + 104, + 105, + 103, + 104, + 105, + 104, + 104, + 104, + 104, + 105, + 104, + 104, + 104, + 104, + 105, + 104, + 103, + 105, + 104, + 104, + 104, + 104, + 105, + 104, + 104, + 104, + 104, + 105, + 103, + 105, + 104, + 104, + 104, + 104, + 105, + 104, + 104, + 208, + 104, + 104, + ], + [ + 1, + 66, + 1, + 2, + 1, + 6, + 1, + 6, + 1, + 1, + 105, + 104, + 104, + 104, + 105, + 104, + 104, + 104, + 105, + 103, + 105, + 104, + 104, + 104, + 104, + 105, + 104, + 104, + 104, + 104, + 105, + 103, + 105, + 104, + 104, + 104, + 104, + 104, + 105, + 104, + 104, + 104, + 105, + 103, + 104, + 105, + 104, + 104, + 104, + 105, + 208, + 104, + 104, + 209, + 104, + 312, + 105, + 104, + 104, + 104, + 521, + 417, + 103, + 104, + 209, + 104, + 313, + 208, + 209, + 103, + 104, + 105, + 416, + ], + [ + 1, + 66, + 1, + 13, + 1, + 2, + 1, + 2, + 105, + 103, + 104, + 105, + 104, + 104, + 104, + 105, + 104, + 104, + 104, + 104, + 105, + 103, + 104, + 105, + 104, + 104, + 104, + 104, + 105, + 104, + 104, + 104, + 105, + 104, + 103, + 105, + 104, + 104, + 104, + 105, + 104, + 104, + 104, + 105, + 104, + 104, + 104, + 104, + 208, + 105, + 104, + 208, + 104, + 312, + 105, + 104, + 104, + 104, + 521, + 417, + 104, + 104, + 208, + 105, + 312, + 208, + 209, + 104, + 104, + 105, + 416, + ], + [ + 1, + 66, + 1, + 6, + 1, + 6, + 1, + 2, + 1, + 2, + 105, + 104, + 104, + 104, + 105, + 103, + 104, + 105, + 104, + 104, + 104, + 104, + 105, + 104, + 104, + 105, + 104, + 103, + 104, + 105, + 104, + 104, + 104, + 104, + 105, + 104, + 104, + 104, + 104, + 104, + 105, + 104, + 104, + 104, + 104, + 104, + 105, + 104, + 104, + 104, + 208, + 105, + 104, + 208, + 104, + 312, + 105, + 104, + 104, + 104, + 521, + 417, + 104, + 105, + 207, + 104, + 314, + 208, + 208, + 104, + 104, + 105, + 416, + ], + [ + 2, + 3, + 13, + 1, + 5, + 1, + 1, + 1, + 26, + 1, + 2, + 1, + 2, + 1, + 6, + 1, + 5, + 1, + 2, + 1, + 5, + 1, + 3, + 1, + 6, + 1, + 3, + 1, + 3, + 1, + 7, + 1, + 1, + 1, + 3, + 1, + 19, + 1, + 7, + 1, + 26, + 1, + 26, + 1, + 2, + 1, + 5, + 1, + 2, + 1, + 3, + 1, + 7, + 1, + 12, + 1, + 6, + 1, + 24, + 1, + 4, + 1, + 6, + 1, + 6, + 1, + 4, + 1, + 1, + 1, + 27, + 1, + 6, + 1, + 7, + 1, + 13, + 1, + 6, + 1, + 7, + 1, + 6, + 1, + 16, + 1, + 1, + 1, + 11, + 1, + 6, + 1, + 1, + 1, + 3, + 1, + 2, + 1, + 1, + 1, + 4, + 1, + 6, + 1, + 3, + 1, + 2, + 1, + 3, + 1, + 2, + 1, + 6, + 1, + 3, + 1, + 2, + 1, + 1, + 1, + 2, + 1, + 3, + 1, + 2, + 1, + 3, + 1, + 6, + 1, + 2, + 1, + 3, + 1, + 4, + 1, + 112, + 1, + 2, + 1, + 5, + 1, + 1, + 1, + 4, + 1, + 1, + 1, + 4, + 1, + 1, + 1, + 4, + 1, + 1, + 2, + 3, + 1, + 1, + 1, + 2, + 1, + 1, + 1, + 1, + 3, + 4, + 2, + 1, + 1, + 2, + 1, + 1, + 1, + 1, + 1, + 2, + 1, + 3, + 2, + 1, + 1, + 1, + 1, + 4, + 1, + 4, + 1, + 1, + 1, + 4, + 1, + 6, + 1, + 28, + 1, + 83, + 1, + 1, + 1, + 5, + 1, + 6, + 1, + 6, + 1, + 4, + 1, + 2, + 1, + 3, + 1, + 2, + 1, + 6, + 1, + 3, + 1, + 2, + 1, + 3, + 1, + 2, + 1, + 3, + 1, + 4, + 1, + 1, + 1, + 4, + 1, + 2, + 1, + 3, + 1, + 4, + 1, + 1, + 1, + 4, + 1, + 1, + 1, + 5, + 1, + 9, + 1, + 6, + 1, + 4, + 1, + 11, + 1, + 13, + 1, + 7, + 1, + 6, + 1, + 40, + 1, + 3, + 1, + 1, + 1, + 2, + 1, + 6, + 1, + 3, + 1, + 2, + 1, + 3, + 1, + 13, + 1, + 6, + 1, + 6, + 1, + 25, + 1, + 6, + 1, + 4, + 1, + 6, + 1, + 45, + 1, + 14, + 1, + 6, + 1, + 6, + 1, + 14, + 1, + 16, + 1, + 1, + 1, + 3, + 2, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 2, + 1, + 1, + 1, + 1, + 4, + 1, + 6, + 1, + 1, + 1, + 1, + 1, + 2, + 1, + 4, + 1, + 1, + 1, + 3, + 1, + 2, + 1, + 4, + 1, + 1, + 1, + 4, + 1, + 6, + 1, + 3, + 1, + 2, + 1, + 4, + 1, + 6, + 1, + 10, + 1, + 112, + 1, + 1, + 1, + 1, + 1, + 4, + 1, + 1, + 1, + 4, + 1, + 2, + 1, + 3, + 1, + 1, + 1, + 4, + 1, + 1, + 1, + 4, + 1, + 1, + 2, + 3, + 1, + 1, + 2, + 1, + 1, + 1, + 1, + 1, + 4, + 1, + 1, + 1, + 2, + 1, + 1, + 2, + 1, + 1, + 1, + 2, + 1, + 1, + 1, + 4, + 1, + 1, + 1, + 4, + 1, + 4, + 1, + 1, + 1, + 4, + 1, + 3, + 1, + 24, + 1, + 78, + 1, + 7, + 1, + 20, + 1, + 7, + 1, + 6, + 1, + 3, + 1, + 2, + 1, + 3, + 1, + 2, + 1, + 3, + 1, + 4, + 1, + 2, + 1, + 3, + 1, + 2, + 1, + 3, + 1, + 6, + 1, + 4, + 1, + 1, + 1, + 11, + 1, + 7, + 1, + 7, + 1, + 25, + 1, + 11, + 1, + 7, + 1, + 27, + 1, + 9, + 1, + 1, + 1, + 2, + 1, + 1, + 1, + 3, + 1, + 2, + 1, + 3, + 1, + 2, + 1, + 3, + 1, + 2, + 1, + 3, + 1, + 2, + 1, + 3, + 1, + 6, + 1, + 25, + 1, + 13, + 1, + 11, + 1, + 65, + 1, + 13, + 1, + 7, + 1, + 6, + 1, + 6, + 1, + 3, + 1, + 4, + 1, + 1, + 1, + 2, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 2, + 1, + 1, + 1, + 1, + 2, + 1, + 1, + 1, + 1, + 2, + 1, + 1, + 1, + 4, + 1, + 1, + 1, + 4, + 1, + 1, + 1, + 4, + 1, + 1, + 1, + 4, + 1, + 6, + 1, + 3, + 1, + 2, + 1, + 4, + 1, + 1, + 1, + 1, + 1, + 2, + 1, + 6, + 1, + 3, + 1, + 2, + 1, + 3, + 1, + 108, + 1, + 3, + 1, + 1, + 1, + 2, + 1, + 3, + 1, + 2, + 1, + 3, + 1, + 1, + 1, + 4, + 1, + 1, + 1, + 4, + 1, + 2, + 1, + 3, + 1, + 2, + 1, + 3, + 1, + 4, + 1, + 1, + 1, + 1, + 2, + 1, + 1, + 1, + 1, + 4, + 1, + 1, + 1, + 2, + 1, + 1, + 1, + 2, + 1, + 1, + 1, + 1, + 1, + 2, + 1, + 1, + 1, + 2, + 1, + 1, + 1, + 2, + 1, + 1, + 1, + 4, + 1, + 10, + 1, + 7, + 1, + 6, + 1, + 14, + 1, + 66, + 1, + 8, + 1, + 6, + 1, + 6, + 1, + 6, + 1, + 10, + 1, + 6, + 1, + 6, + 1, + 6, + 1, + 7, + 1, + 3, + 1, + 6, + 1, + 4, + 1, + 1, + 1, + 4, + 1, + 2, + 1, + 3, + 1, + 19, + 1, + 7, + 1, + 14, + 1, + 18, + 1, + 10, + 1, + 7, + 1, + 6, + 1, + 13, + 1, + 7, + 1, + 1, + 1, + 6, + 1, + 1, + 1, + 4, + 1, + 5, + 1, + 2, + 1, + 3, + 1, + 7, + 1, + 6, + 1, + 6, + 1, + 3, + 1, + 6, + 1, + 6, + 1, + 18, + 1, + 11, + 1, + 57, + 1, + 14, + 1, + 13, + 1, + 6, + 1, + 11, + 1, + 1, + 1, + 1, + 1, + 4, + 1, + 1, + 1, + 1, + 2, + 1, + 1, + 1, + 1, + 2, + 1, + 1, + 1, + 1, + 2, + 1, + 1, + 1, + 1, + 1, + 2, + 1, + 1, + 4, + 1, + 1, + 1, + 4, + 1, + 1, + 1, + 4, + 1, + 1, + 1, + 4, + 1, + 3, + 1, + 2, + 1, + 4, + 1, + 1, + 1, + 4, + 1, + 3, + 1, + 2, + 1, + 3, + 1, + 2, + 1, + 4, + 1, + 13, + 1, + 97, + 1, + 1, + 1, + 2, + 1, + 3, + 1, + 2, + 1, + 3, + 1, + 1, + 1, + 4, + 1, + 2, + 1, + 3, + 1, + 2, + 1, + 3, + 1, + 4, + 1, + 1, + 1, + 4, + 1, + 1, + 1, + 4, + 1, + 1, + 1, + 4, + 1, + 6, + 1, + 1, + 2, + 1, + 1, + 1, + 1, + 1, + 2, + 1, + 1, + 1, + 2, + 1, + 1, + 1, + 1, + 2, + 4, + 1, + 1, + 1, + 2, + 12, + 1, + 6, + 1, + 7, + 1, + 21, + 1, + 14, + 1, + 13, + 1, + 26, + 1, + 8, + 1, + 5, + 1, + 6, + 1, + 13, + 1, + 10, + 1, + 6, + 1, + 7, + 1, + 6, + 1, + 3, + 1, + 6, + 1, + 4, + 1, + 2, + 1, + 3, + 1, + 2, + 1, + 3, + 1, + 31, + 1, + 7, + 1, + 14, + 1, + 3, + 1, + 25, + 1, + 7, + 1, + 16, + 1, + 8, + 1, + 1, + 1, + 4, + 1, + 1, + 1, + 4, + 1, + 1, + 1, + 4, + 1, + 6, + 1, + 1, + 1, + 4, + 1, + 6, + 1, + 3, + 1, + 2, + 1, + 3, + 1, + 6, + 1, + 7, + 1, + 3, + 1, + 13, + 1, + 52, + 1, + 21, + 1, + 21, + 1, + 6, + 1, + 5, + 1, + 2, + 1, + 6, + 1, + 1, + 1, + 1, + 2, + 3, + 1, + 1, + 2, + 1, + 1, + 1, + 1, + 1, + 2, + 1, + 1, + 1, + 1, + 2, + 1, + 1, + 1, + 1, + 2, + 1, + 1, + 1, + 2, + 1, + 1, + 1, + 1, + 4, + 1, + 1, + 1, + 4, + 1, + 4, + 1, + 1, + 1, + 4, + 1, + 1, + 1, + 4, + 1, + 3, + 1, + 2, + 1, + 3, + 1, + 2, + 1, + 4, + 1, + 3, + 1, + 108, + 1, + 1, + 1, + 5, + 1, + 6, + 1, + 2, + 1, + 3, + 1, + 6, + 1, + 4, + 1, + 1, + 1, + 6, + 1, + 4, + 1, + 2, + 1, + 3, + 1, + 2, + 1, + 3, + 1, + 1, + 2, + 3, + 1, + 4, + 1, + 1, + 1, + 4, + 1, + 1, + 2, + 1, + 1, + 1, + 1, + 1, + 2, + 1, + 1, + 1, + 1, + 1, + 1, + 15, + 1, + 3, + 1, + 6, + 1, + 7, + 1, + 29, + 1, + 46, + 1, + 2, + 1, + 8, + 1, + 12, + 1, + 25, + 1, + 13, + 1, + 11, + 1, + 3, + 1, + 6, + 1, + 6, + 1, + 21, + 1, + 7, + 1, + 14, + 1, + 6, + 1, + 7, + 1, + 6, + 1, + 5, + 1, + 4, + 1, + 11, + 1, + 6, + 1, + 7, + 1, + 6, + 1, + 20, + 1, + 6, + 1, + 6, + 1, + 13, + 1, + 57, + 1, + 1, + 1, + 6, + 1, + 6, + 1, + 6, + 1, + 6, + 1, + 6, + 1, + 6, + 1, + 3, + 1, + 2, + 1, + 3, + 1, + 2, + 1, + 3, + 1, + 6, + 1, + 4, + 1, + 2, + 1, + 3, + 1, + 6, + 1, + 4, + 1, + 2, + 1, + 1, + 1, + 6, + 1, + 15, + 1, + 5, + 1, + 7, + 1, + 7, + 1, + 3, + 1, + 4, + 1, + 7, + 1, + 5, + 1, + 21, + 1, + 6, + 1, + 9, + 1, + 3, + 1, + 1, + 1, + 2, + 1, + 3, + 1, + 2, + 1, + 6, + 1, + 6, + 1, + 6, + 1, + 3, + 1, + 2, + 1, + 3, + 1, + 2, + 1, + 3, + 1, + 11, + 1, + 6, + 1, + 6, + 1, + 11, + 1, + 6, + 1, + 6, + 1, + 11, + 1, + 3, + 1, + 6, + 1, + 4, + 1, + 2, + 1, + 3, + 1, + 6, + 1, + 4, + 1, + 2, + 1, + 3, + 1, + 2, + 1, + 1, + 1, + 1, + 1, + 4, + 1, + 2, + 1, + 3, + 1, + 2, + 1, + 1, + 1, + 1, + 1, + 4, + 1, + 4, + 1, + 1, + 1, + 1, + 2, + 1, + 1, + 9, + 1, + 25, + 1, + 7, + 1, + 6, + 1, + 14, + 1, + 6, + 1, + 28, + 1, + 6, + 1, + 2, + 1, + 1, + 1, + 6, + 1, + 6, + 1, + 6, + 1, + 10, + 1, + 13, + 1, + 6, + 1, + 10, + 1, + 7, + 1, + 6, + 1, + 3, + 1, + 7, + 1, + 6, + 1, + 3, + 1, + 6, + 1, + 4, + 1, + 2, + 1, + 3, + 1, + 2, + 1, + 4, + 1, + 3, + 1, + 2, + 1, + 3, + 1, + 2, + 1, + 1, + 1, + 1, + 1, + 4, + 1, + 2, + 1, + 3, + 1, + 1, + 2, + 1, + 1, + 1, + 1, + 4, + 1, + 1, + 2, + 1, + 1, + 1, + 1, + 1, + 2, + 1, + 1, + 2, + 1, + 1, + 1, + 1, + 1, + 2, + 1, + 1, + 2, + 1, + 1, + 1, + 1, + 2, + 1, + 1, + 1, + 3, + 2, + 1, + 1, + 4, + 1, + 1, + 1, + 4, + 1, + 4, + 1, + 1, + 1, + 4, + 1, + 1, + 1, + 4, + 1, + 4, + 1, + 6, + 1, + 3, + 1, + 2, + 1, + 4, + 1, + 3, + 1, + 2, + 1, + 3, + 1, + 7, + 1, + 3, + 1, + 2, + 1, + 3, + 1, + 4, + 1, + 82, + 1, + 21, + 1, + 3, + 1, + 5, + 1, + 1, + 1, + 4, + 1, + 1, + 1, + 6, + 1, + 4, + 1, + 1, + 1, + 4, + 1, + 1, + 1, + 4, + 1, + 1, + 1, + 2, + 1, + 1, + 1, + 1, + 1, + 4, + 1, + 1, + 2, + 1, + 1, + 1, + 2, + 1, + 1, + 1, + 1, + 1, + 2, + 1, + 1, + 1, + 2, + 1, + 1, + 1, + 1, + 2, + 1, + 1, + 1, + 4, + 1, + 1, + 1, + 1, + 2, + 1, + 1, + 3, + 1, + 4, + 1, + 8, + 1, + 22, + 1, + 71, + 1, + 8, + 1, + 6, + 1, + 5, + 1, + 7, + 1, + 6, + 1, + 3, + 1, + 2, + 1, + 3, + 1, + 6, + 1, + 2, + 1, + 3, + 1, + 4, + 1, + 1, + 1, + 4, + 1, + 2, + 1, + 3, + 1, + 4, + 1, + 1, + 1, + 4, + 1, + 1, + 1, + 4, + 1, + 5, + 1, + 7, + 1, + 6, + 1, + 8, + 1, + 7, + 1, + 8, + 1, + 5, + 1, + 6, + 1, + 14, + 1, + 6, + 1, + 28, + 1, + 103, + 1, + 42, + 1, + 6, + 1, + 6, + 1, + 6, + 1, + 20, + 1, + 5, + 1, + 8, + 1, + 2, + 1, + 4, + 1, + 7, + 1, + 6, + 1, + 12, + 1, + 6, + 1, + 28, + 1, + 6, + 1, + 153, + 1, + 6, + 1, + 6, + 1, + 20, + 1, + 5, + 1, + 7, + 1, + 2, + 1, + 13, + 1, + 5, + 1, + 8, + 1, + 5, + 1, + 2, + 1, + 6, + 1, + 1, + 1, + 1, + 1, + 2, + 1, + 3, + 1, + 2, + 1, + 6, + 1, + 3, + 1, + 2, + 1, + 6, + 1, + 4, + 1, + 6, + 1, + 6, + 1, + 3, + 1, + 6, + 1, + 7, + 1, + 10, + 1, + 18, + 1, + 6, + 1, + 11, + 1, + 3, + 1, + 2, + 1, + 6, + 1, + 3, + 1, + 7, + 1, + 3, + 1, + 2, + 1, + 4, + 1, + 3, + 1, + 2, + 1, + 3, + 1, + 4, + 1, + 2, + 1, + 3, + 1, + 2, + 1, + 1, + 1, + 3, + 1, + 8, + 1, + 7, + 1, + 14, + 1, + 22, + 1, + 14, + 1, + 6, + 1, + 21, + 1, + 6, + 1, + 6, + 1, + 96, + 1, + 1, + 1, + 5, + 1, + 7, + 1, + 6, + 1, + 5, + 1, + 6, + 1, + 4, + 1, + 2, + 1, + 3, + 1, + 2, + 1, + 3, + 1, + 6, + 1, + 4, + 1, + 1, + 1, + 4, + 1, + 2, + 1, + 3, + 1, + 1, + 2, + 3, + 1, + 1, + 2, + 1, + 1, + 1, + 1, + 4, + 1, + 6, + 1, + 8, + 1, + 2, + 1, + 14, + 1, + 6, + 1, + 13, + 1, + 7, + 1, + 6, + 1, + 28, + 1, + 6, + 1, + 104, + 1, + 2, + 1, + 5, + 1, + 2, + 1, + 6, + 1, + 5, + 1, + 4, + 1, + 2, + 1, + 3, + 1, + 2, + 1, + 3, + 1, + 2, + 1, + 3, + 1, + 1, + 2, + 1, + 1, + 1, + 1, + 1, + 2, + 1, + 1, + 1, + 1, + 4, + 1, + 1, + 1, + 4, + 1, + 1, + 2, + 1, + 1, + 1, + 1, + 2, + 1, + 1, + 1, + 1, + 2, + 1, + 4, + 1, + 1, + 2, + 1, + 22, + 1, + 6, + 1, + 162, + 1, + 6, + 1, + 35, + 1, + 6, + 1, + 6, + 1, + 5, + 1, + 7, + 1, + 3, + 1, + 3, + 1, + 8, + 1, + 5, + 1, + 20, + 1, + 4, + 1, + 4, + 1, + 1, + 1, + 1, + 1, + 4, + 1, + 1, + 1, + 3, + 1, + 2, + 1, + 3, + 1, + 2, + 1, + 4, + 1, + 6, + 1, + 6, + 1, + 6, + 1, + 10, + 1, + 18, + 1, + 6, + 1, + 6, + 1, + 11, + 1, + 11, + 1, + 5, + 1, + 7, + 1, + 3, + 1, + 6, + 1, + 4, + 1, + 2, + 1, + 3, + 1, + 4, + 1, + 1, + 1, + 4, + 1, + 2, + 1, + 4, + 1, + 3, + 1, + 6, + 1, + 4, + 1, + 1, + 1, + 4, + 1, + 22, + 1, + 17, + 1, + 6, + 1, + 7, + 1, + 6, + 1, + 21, + 1, + 6, + 1, + 28, + 1, + 98, + 1, + 2, + 1, + 3, + 1, + 2, + 1, + 3, + 1, + 2, + 1, + 3, + 1, + 2, + 1, + 3, + 1, + 2, + 1, + 3, + 1, + 6, + 1, + 4, + 1, + 1, + 1, + 4, + 1, + 2, + 1, + 3, + 1, + 1, + 1, + 4, + 1, + 1, + 2, + 1, + 1, + 1, + 1, + 4, + 1, + 1, + 1, + 4, + 1, + 1, + 2, + 1, + 1, + 1, + 1, + 4, + 1, + 10, + 1, + 5, + 1, + 14, + 1, + 14, + 1, + 35, + 1, + 21, + 1, + 1, + 1, + 5, + 1, + 7, + 1, + 5, + 1, + 6, + 1, + 6, + 1, + 24, + 1, + 7, + 1, + 3, + 1, + 2, + 1, + 3, + 1, + 7, + 1, + 3, + 1, + 2, + 1, + 33, + 1, + 14, + 1, + 6, + 1, + 6, + 1, + 14, + 1, + 2, + 1, + 1, + 1, + 11, + 1, + 5, + 1, + 6, + 1, + 6, + 1, + 28, + 1, + 146, + 1, + 6, + 1, + 6, + 1, + 34, + 1, + 6, + 1, + 7, + 1, + 5, + 1, + 2, + 1, + 8, + 1, + 4, + 1, + 5, + 1, + 6, + 1, + 6, + 1, + 7, + 1, + 17, + 1, + 1, + 1, + 5, + 1, + 2, + 1, + 3, + 1, + 2, + 1, + 6, + 1, + 6, + 1, + 6, + 1, + 3, + 1, + 2, + 1, + 3, + 1, + 13, + 1, + 11, + 1, + 6, + 1, + 48, + 1, + 36, + 1, + 13, + 1, + 6, + 1, + 7, + 1, + 6, + 1, + 2, + 1, + 1, + 1, + 1, + 2, + 3, + 1, + 2, + 1, + 1, + 1, + 1, + 1, + 2, + 1, + 1, + 1, + 1, + 2, + 1, + 1, + 1, + 1, + 1, + 2, + 1, + 1, + 1, + 1, + 4, + 1, + 1, + 1, + 4, + 1, + 3, + 2, + 1, + 1, + 4, + 1, + 1, + 1, + 4, + 1, + 1, + 1, + 4, + 1, + 3, + 1, + 2, + 1, + 3, + 1, + 2, + 1, + 4, + 1, + 3, + 1, + 2, + 1, + 3, + 1, + 2, + 1, + 4, + 1, + 10, + 1, + 6, + 1, + 11, + 1, + 11, + 1, + 13, + 1, + 11, + 1, + 3, + 1, + 6, + 1, + 7, + 1, + 3, + 1, + 37, + 1, + 6, + 1, + 22, + 1, + 6, + 1, + 6, + 1, + 11, + 1, + 3, + 1, + 7, + 1, + 3, + 1, + 6, + 1, + 1, + 1, + 1, + 1, + 4, + 1, + 1, + 1, + 4, + 1, + 1, + 1, + 4, + 1, + 1, + 1, + 4, + 1, + 1, + 1, + 4, + 1, + 6, + 1, + 4, + 1, + 1, + 1, + 3, + 1, + 7, + 1, + 3, + 1, + 2, + 1, + 3, + 1, + 2, + 1, + 3, + 1, + 7, + 1, + 3, + 1, + 82, + 1, + 6, + 1, + 20, + 1, + 14, + 1, + 6, + 1, + 6, + 1, + 6, + 1, + 29, + 1, + 6, + 1, + 6, + 1, + 6, + 1, + 6, + 1, + 8, + 1, + 6, + 1, + 1, + 1, + 3, + 1, + 2, + 1, + 3, + 1, + 2, + 1, + 3, + 1, + 2, + 1, + 6, + 1, + 3, + 1, + 2, + 1, + 3, + 1, + 6, + 1, + 6, + 1, + 7, + 1, + 10, + 1, + 18, + 1, + 41, + 1, + 57, + 1, + 7, + 1, + 16, + 1, + 18, + 1, + 6, + 1, + 7, + 1, + 6, + 1, + 20, + 1, + 6, + 1, + 6, + 1, + 153, + 1, + 6, + 1, + 20, + 1, + 21, + 1, + 13, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 2, + 1, + 1, + 1, + 2, + 1, + 1, + 1, + 6, + 1, + 1, + 1, + 1, + 1, + 2, + 1, + 4, + 1, + 1, + 1, + 3, + 1, + 2, + 1, + 4, + 1, + 1, + 1, + 3, + 1, + 7, + 1, + 3, + 1, + 2, + 1, + 3, + 1, + 2, + 1, + 3, + 1, + 7, + 1, + 3, + 1, + 107, + 1, + 4, + 1, + 2, + 1, + 5, + 1, + 2, + 1, + 3, + 1, + 1, + 1, + 4, + 1, + 1, + 1, + 4, + 1, + 1, + 1, + 4, + 1, + 1, + 2, + 3, + 1, + 1, + 1, + 4, + 1, + 1, + 2, + 3, + 1, + 1, + 2, + 1, + 1, + 1, + 1, + 2, + 1, + 1, + 1, + 2, + 1, + 1, + 1, + 2, + 1, + 1, + 1, + 4, + 1, + 1, + 1, + 4, + 1, + 3, + 2, + 1, + 1, + 43, + 1, + 21, + 1, + 111, + 1, + 6, + 1, + 21, + 1, + 6, + 1, + 6, + 1, + 6, + 1, + 6, + 1, + 6, + 1, + 10, + 1, + 1, + 1, + 2, + 1, + 7, + 1, + 5, + 1, + 6, + 1, + 6, + 1, + 6, + 1, + 13, + 1, + 6, + 1, + 6, + 1, + 8, + 1, + 3, + 1, + 2, + 1, + 5, + 1, + 7, + 1, + 6, + 1, + 6, + 1, + 5, + 1, + 4, + 1, + 6, + 1, + 11, + 1, + 13, + 1, + 48, + 1, + 14, + 1, + 6, + 1, + 21, + 1, + 6, + 1, + 6, + 1, + 7, + 1, + 6, + 1, + 15, + 1, + 5, + 1, + 6, + 1, + 6, + 1, + 28, + 1, + 167, + 1, + 6, + 1, + 13, + 1, + 6, + 1, + 6, + 1, + 30, + 1, + 5, + 1, + 6, + 1, + 6, + 1, + 6, + 1, + 28, + 1, + 6, + 1, + 13, + 1, + 110, + 1, + 27, + 1, + 28, + 1, + 6, + 1, + 30, + 1, + 19, + 1, + 6, + 1, + 6, + 1, + 49, + 1, + 103, + 1, + 6, + 1, + 6, + 1, + 13, + 1, + 27, + 1, + 5, + 1, + 1, + 1, + 1, + 1, + 1, + 2, + 1, + 1, + 1, + 1, + 2, + 1, + 1, + 1, + 1, + 1, + 2, + 1, + 1, + 1, + 2, + 1, + 1, + 1, + 3, + 2, + 1, + 1, + 4, + 1, + 1, + 1, + 4, + 1, + 1, + 1, + 4, + 1, + 1, + 1, + 4, + 1, + 3, + 1, + 2, + 1, + 4, + 1, + 1, + 1, + 4, + 1, + 1, + 1, + 4, + 1, + 3, + 1, + 2, + 1, + 4, + 1, + 148, + 1, + 6, + 1, + 6, + 1, + 6, + 1, + 6, + 1, + 19, + 1, + 16, + 1, + 6, + 1, + 6, + 1, + 7, + 1, + 20, + 1, + 27, + 1, + 110, + 1, + 56, + 1, + 6, + 1, + 6, + 1, + 6, + 1, + 4, + 1, + 16, + 1, + 6, + 1, + 7, + 1, + 6, + 1, + 20, + 1, + 6, + 1, + 89, + 1, + 6, + 1, + 6, + 1, + 6, + 1, + 6, + 1, + 3, + 1, + 2, + 1, + 3, + 1, + 6, + 1, + 6, + 1, + 4, + 1, + 2, + 1, + 3, + 1, + 2, + 1, + 3, + 1, + 6, + 1, + 4, + 1, + 2, + 1, + 3, + 1, + 2, + 1, + 14, + 1, + 6, + 1, + 6, + 1, + 8, + 1, + 3, + 1, + 3, + 1, + 7, + 1, + 6, + 1, + 6, + 1, + 6, + 1, + 14, + 1, + 6, + 1, + 6, + 1, + 14, + 1, + 131, + 1, + 28, + 1, + 6, + 1, + 6, + 1, + 6, + 1, + 5, + 1, + 6, + 1, + 6, + 1, + 2, + 1, + 5, + 1, + 7, + 1, + 6, + 1, + 20, + 1, + 6, + 1, + 167, + 1, + 6, + 1, + 6, + 1, + 6, + 1, + 6, + 1, + 20, + 1, + 6, + 1, + 6, + 1, + 2, + 1, + 5, + 1, + 7, + 1, + 5, + 1, + 6, + 1, + 6, + 1, + 14, + 1, + 20, + 1, + 159, + 1, + 1, + 1, + 1, + 1, + 6, + 1, + 2, + 1, + 3, + 1, + 1, + 1, + 4, + 1, + 1, + 2, + 3, + 1, + 1, + 1, + 2, + 1, + 1, + 1, + 1, + 3, + 2, + 1, + 1, + 2, + 1, + 1, + 1, + 2, + 1, + 1, + 1, + 1, + 2, + 1, + 3, + 2, + 1, + 1, + 1, + 1, + 2, + 1, + 1, + 1, + 4, + 1, + 6, + 1, + 3, + 1, + 2, + 1, + 4, + 1, + 2, + 1, + 8, + 1, + 156, + 1, + 6, + 1, + 6, + 1, + 6, + 1, + 20, + 1, + 6, + 1, + 7, + 1, + 5, + 1, + 2, + 1, + 8, + 1, + 3, + 1, + 13, + 1, + 7, + 1, + 27, + 1, + 6, + 1, + 131, + 1, + 35, + 1, + 6, + 1, + 6, + 1, + 6, + 1, + 6, + 1, + 13, + 1, + 2, + 1, + 7, + 1, + 4, + 1, + 20, + 1, + 6, + 1, + 6, + 1, + 28, + 1, + 13, + 1, + 117, + 1, + 13, + 1, + 34, + 1, + 7, + 1, + 6, + 1, + 5, + 1, + 2, + 1, + 7, + 1, + 5, + 1, + 20, + 1, + 6, + 1, + 13, + 1, + 6, + 1, + 167, + 1, + 6, + 1, + 20, + 1, + 6, + 1, + 7, + 1, + 5, + 1, + 2, + 1, + 7, + 1, + 5, + 1, + 5, + 1, + 6, + 1, + 6, + 1, + 28, + 1, + 6, + 1, + 181, + 1, + 6, + 1, + 6, + 1, + 12, + 1, + 2, + 1, + 7, + 1, + 5, + 1, + 20, + 1, + 6, + 1, + 6, + 1, + 6, + 1, + 41, + 1, + 2, + 1, + 8, + 1, + 6, + 1, + 3, + 1, + 20, + 1, + 13, + 1, + 6, + 1, + 3, + 1, + 6, + 1, + 7, + 1, + 6, + 1, + 3, + 1, + 4, + 1, + 2, + 1, + 3, + 1, + 6, + 1, + 4, + 1, + 1, + 1, + 4, + 1, + 2, + 1, + 3, + 1, + 4, + 1, + 2, + 1, + 3, + 1, + 1, + 2, + 1, + 1, + 1, + 1, + 4, + 1, + 1, + 1, + 2, + 1, + 1, + 1, + 1, + 2, + 1, + 1, + 1, + 1, + 1, + 2, + 1, + 1, + 1, + 3, + 2, + 1, + 2, + 1, + 2, + 3, + 1, + 1, + 1, + 2, + 1, + 1, + 4, + 1, + 1, + 1, + 4, + 1, + 1, + 1, + 2, + 1, + 1, + 1, + 4, + 1, + 1, + 1, + 3, + 1, + 4, + 1, + 2, + 1, + 4, + 1, + 6, + 1, + 3, + 1, + 2, + 1, + 3, + 1, + 2, + 1, + 4, + 1, + 3, + 1, + 2, + 1, + 4, + 1, + 6, + 1, + 3, + 1, + 6, + 1, + 4, + 1, + 109, + 1, + 2, + 1, + 1, + 1, + 2, + 1, + 3, + 1, + 1, + 1, + 4, + 1, + 1, + 1, + 4, + 1, + 1, + 1, + 4, + 1, + 1, + 1, + 2, + 1, + 1, + 1, + 1, + 2, + 3, + 1, + 4, + 1, + 1, + 1, + 2, + 1, + 1, + 2, + 1, + 1, + 1, + 1, + 1, + 2, + 1, + 1, + 1, + 1, + 4, + 1, + 4, + 1, + 1, + 1, + 4, + 1, + 1, + 1, + 4, + 1, + 3, + 1, + 2, + 1, + 37, + 1, + 7, + 1, + 65, + 1, + 2, + 1, + 5, + 1, + 6, + 1, + 6, + 1, + 7, + 1, + 3, + 1, + 2, + 1, + 3, + 1, + 2, + 1, + 3, + 1, + 6, + 1, + 4, + 1, + 1, + 1, + 7, + 1, + 3, + 1, + 4, + 1, + 1, + 1, + 2, + 1, + 1, + 1, + 1, + 1, + 4, + 1, + 1, + 1, + 2, + 1, + 4, + 1, + 7, + 1, + 16, + 1, + 14, + 1, + 7, + 1, + 59, + 1, + 6, + 1, + 2, + 1, + 6, + 1, + 3, + 1, + 13, + 1, + 6, + 1, + 25, + 1, + 6, + 1, + 10, + 1, + 6, + 1, + 2, + 1, + 22, + 1, + 14, + 1, + 14, + 1, + 6, + 1, + 20, + 1, + 6, + 1, + 6, + 1, + 2, + 1, + 5, + 1, + 7, + 1, + 6, + 1, + 6, + 1, + 6, + 1, + 6, + 1, + 28, + 1, + 6, + 1, + 131, + 1, + 35, + 1, + 6, + 1, + 6, + 1, + 5, + 1, + 6, + 1, + 6, + 1, + 2, + 1, + 13, + 1, + 6, + 1, + 6, + 1, + 13, + 1, + 6, + 1, + 6, + 1, + 160, + 1, + 13, + 1, + 13, + 1, + 14, + 1, + 5, + 1, + 5, + 1, + 7, + 1, + 2, + 1, + 5, + 1, + 7, + 1, + 5, + 1, + 6, + 1, + 39, + 1, + 3, + 1, + 1, + 1, + 2, + 1, + 3, + 1, + 2, + 1, + 3, + 1, + 2, + 1, + 3, + 1, + 2, + 1, + 6, + 1, + 3, + 1, + 6, + 1, + 32, + 1, + 10, + 1, + 7, + 1, + 68, + 1, + 20, + 1, + 6, + 1, + 7, + 1, + 5, + 1, + 2, + 1, + 7, + 1, + 5, + 1, + 20, + 1, + 6, + 1, + 13, + 1, + 6, + 1, + 167, + 1, + 6, + 1, + 20, + 1, + 6, + 1, + 7, + 1, + 5, + 1, + 2, + 1, + 6, + 1, + 1, + 1, + 3, + 1, + 6, + 1, + 6, + 1, + 7, + 1, + 27, + 1, + 6, + 1, + 78, + 1, + 6, + 1, + 6, + 1, + 5, + 1, + 6, + 1, + 7, + 1, + 3, + 1, + 6, + 1, + 4, + 1, + 1, + 1, + 4, + 1, + 2, + 1, + 3, + 1, + 2, + 1, + 3, + 1, + 4, + 1, + 2, + 1, + 41, + 1, + 16, + 1, + 11, + 1, + 7, + 1, + 29, + 1, + 5, + 1, + 2, + 1, + 3, + 1, + 2, + 1, + 1, + 1, + 3, + 1, + 2, + 1, + 4, + 1, + 5, + 1, + 7, + 1, + 3, + 1, + 2, + 1, + 3, + 1, + 6, + 1, + 6, + 1, + 4, + 1, + 13, + 1, + 6, + 1, + 4, + 1, + 6, + 1, + 6, + 1, + 3, + 1, + 7, + 1, + 3, + 1, + 2, + 1, + 3, + 1, + 4, + 1, + 2, + 1, + 3, + 1, + 6, + 1, + 4, + 1, + 2, + 1, + 3, + 1, + 6, + 1, + 4, + 1, + 2, + 1, + 3, + 1, + 4, + 1, + 1, + 1, + 4, + 1, + 1, + 1, + 2, + 1, + 3, + 1, + 9, + 1, + 5, + 1, + 2, + 1, + 7, + 1, + 6, + 1, + 6, + 1, + 6, + 1, + 7, + 1, + 6, + 1, + 6, + 1, + 14, + 1, + 123, + 1, + 2, + 1, + 1, + 1, + 3, + 1, + 2, + 1, + 3, + 1, + 2, + 1, + 3, + 1, + 2, + 1, + 3, + 1, + 6, + 1, + 1, + 1, + 4, + 1, + 6, + 1, + 4, + 1, + 1, + 1, + 4, + 1, + 1, + 1, + 4, + 1, + 1, + 2, + 3, + 1, + 2, + 1, + 1, + 1, + 1, + 1, + 2, + 1, + 1, + 1, + 2, + 1, + 1, + 2, + 1, + 1, + 1, + 1, + 11, + 1, + 7, + 1, + 7, + 1, + 212, + 1, + 6, + 1, + 6, + 1, + 13, + 1, + 15, + 1, + 27, + 1, + 6, + 1, + 6, + 1, + 153, + 1, + 6, + 1, + 6, + 1, + 6, + 1, + 6, + 1, + 20, + 1, + 7, + 1, + 13, + 1, + 3, + 1, + 11, + 1, + 5, + 1, + 6, + 1, + 7, + 1, + 27, + 1, + 80, + 1, + 20, + 1, + 2775, + 3, + 20, + 1, + 16, + 1, + 2, + 1, + 17, + ], + [ + 1, + 53, + 1, + 9, + 1, + 3, + 1, + 6, + 1, + 5, + 2, + 2, + 1, + 1, + 105, + 104, + 104, + 104, + 105, + 103, + 104, + 105, + 104, + 104, + 104, + 104, + 105, + 104, + 104, + 104, + 105, + 103, + 105, + 104, + 104, + 104, + 104, + 104, + 105, + 104, + 104, + 104, + 105, + 103, + 104, + 105, + 104, + 104, + 104, + 105, + 104, + 104, + 104, + 104, + 208, + 105, + 104, + 208, + 104, + 313, + 104, + 104, + 104, + 104, + 521, + 417, + 104, + 104, + 208, + 104, + 313, + 209, + 208, + 104, + 104, + 104, + 417, + ], + [ + 1, + 69, + 1, + 6, + 1, + 6, + 1, + 1, + 105, + 104, + 104, + 105, + 104, + 104, + 104, + 105, + 104, + 104, + 104, + 104, + 104, + 104, + 104, + 105, + 104, + 104, + 104, + 105, + 104, + 104, + 104, + 105, + 104, + 103, + 104, + 105, + 104, + 104, + 104, + 104, + 105, + 104, + 104, + 104, + 105, + 103, + 104, + 105, + 208, + 104, + 105, + 208, + 104, + 312, + 105, + 104, + 104, + 104, + 521, + 417, + 104, + 104, + 208, + 105, + 312, + 208, + 209, + 104, + 104, + 104, + 417, + ], + [ + 1, + 66, + 1, + 9, + 1, + 3, + 1, + 4, + 105, + 104, + 105, + 104, + 104, + 104, + 104, + 105, + 104, + 104, + 104, + 104, + 105, + 103, + 105, + 104, + 104, + 104, + 104, + 105, + 104, + 104, + 104, + 104, + 104, + 104, + 104, + 105, + 104, + 104, + 104, + 105, + 104, + 104, + 104, + 104, + 105, + 103, + 104, + 105, + 208, + 105, + 104, + 208, + 104, + 312, + 105, + 104, + 104, + 104, + 521, + 417, + 104, + 104, + 208, + 104, + 313, + 208, + 209, + 104, + 104, + 105, + 416, + ], + [ + 1, + 51, + 1, + 13, + 1, + 3, + 3, + 6, + 106, + 105, + 103, + 105, + 104, + 105, + 104, + 103, + 105, + 104, + 104, + 104, + 105, + 104, + 104, + 104, + 104, + 104, + 104, + 105, + 104, + 104, + 104, + 104, + 104, + 105, + 103, + 105, + 105, + 104, + 104, + 103, + 104, + 105, + 104, + 104, + 105, + 104, + 104, + 103, + 209, + 105, + 104, + ], + [ + 2, + 72, + 1, + 5, + 1, + 2, + 106, + 105, + 103, + 105, + 104, + 105, + 103, + 104, + 104, + 104, + 105, + 104, + 105, + 103, + 105, + 104, + 104, + 104, + 104, + 105, + 103, + 105, + 104, + 104, + 104, + 105, + 103, + 105, + 103, + 105, + 104, + 104, + 104, + 104, + 105, + 104, + 104, + 104, + 105, + 103, + 209, + 104, + 105, + ], + [ + 1, + 78, + 3, + 1, + 106, + 104, + 104, + 104, + 104, + 105, + 104, + 104, + 104, + 104, + 104, + 105, + 104, + 104, + 105, + 103, + 104, + 104, + 104, + 105, + 104, + 105, + 104, + 103, + 105, + 104, + 104, + 105, + 104, + 104, + 104, + 104, + 104, + 104, + 104, + 105, + 104, + 104, + 105, + 103, + 208, + 105, + 103, + ], + [ + 1, + 83, + 1, + 1, + 105, + 104, + 104, + 104, + 105, + 104, + 104, + 104, + 105, + 104, + 104, + 104, + 105, + 103, + 104, + 104, + 105, + 104, + 104, + 104, + 105, + 103, + 105, + 103, + 105, + 104, + 104, + 104, + 105, + 104, + 104, + 104, + 105, + 104, + 104, + 104, + 104, + 104, + 104, + 105, + 208, + 104, + 104, + 208, + 104, + 313, + 105, + 104, + 104, + 103, + 522, + 416, + 104, + 104, + 209, + 104, + 313, + 208, + 209, + 104, + 103, + 105, + 416, + ], + [ + 1, + 80, + 1, + 2, + 1, + 1, + 105, + 104, + 104, + 104, + 105, + 104, + 104, + 104, + 104, + 105, + 104, + 104, + 104, + 104, + 104, + 105, + 104, + 104, + 104, + 104, + 104, + 104, + 104, + 105, + 104, + 104, + 104, + 104, + 105, + 104, + 104, + 104, + 104, + 105, + 103, + 105, + 104, + 104, + 104, + 104, + 208, + 105, + 104, + 208, + 104, + 313, + 105, + 104, + 103, + 104, + 522, + 416, + 104, + 104, + 209, + 104, + 313, + 208, + 208, + 104, + 104, + 105, + 416, + ], + [ + 1, + 73, + 1, + 2, + 1, + 9, + 105, + 104, + 104, + 104, + 105, + 103, + 104, + 105, + 104, + 104, + 104, + 105, + 104, + 104, + 104, + 104, + 105, + 103, + 105, + 104, + 104, + 104, + 104, + 105, + 104, + 104, + 104, + 104, + 104, + 104, + 104, + 105, + 104, + 104, + 104, + 105, + 104, + 104, + 104, + 104, + 208, + 105, + 104, + 208, + 104, + 313, + 104, + 104, + 104, + 104, + 522, + 416, + 104, + 104, + 208, + 105, + 312, + 209, + 208, + 104, + 104, + 105, + 416, + ], + [ + 1, + 13, + 2, + 4, + 1, + 9, + 1, + 4, + 2, + 9, + 1, + 4, + 2, + 3, + 3, + 4, + 1, + 9, + 1, + 3, + 3, + 4, + 2, + 2, + 105, + 105, + 104, + 103, + 105, + 104, + 104, + 104, + 105, + 104, + 104, + 104, + 104, + 104, + 104, + 105, + 104, + 104, + 104, + 104, + 105, + 103, + 104, + 106, + 104, + 104, + 104, + 103, + 105, + 104, + 104, + 105, + 104, + 104, + 104, + 104, + 104, + 104, + 104, + 104, + 209, + 104, + 105, + ], + [ + 1, + 9, + 3, + 3, + 2, + 9, + 1, + 4, + 2, + 4, + 2, + 8, + 1, + 4, + 2, + 4, + 2, + 4, + 2, + 2, + 1, + 5, + 2, + 3, + 3, + 3, + 2, + 2, + 106, + 104, + 104, + 103, + 105, + 104, + 104, + 105, + 104, + 104, + 104, + 104, + 105, + 103, + 104, + 106, + 103, + 105, + 104, + 103, + 105, + 103, + 105, + 105, + 104, + 104, + 104, + 103, + 105, + 104, + 104, + 105, + 104, + 104, + 104, + 104, + 105, + 104, + 103, + 106, + 207, + 104, + 105, + ], + ] found_tolerances = [] for i, plateau_lengths in enumerate(data): - found_tolerances.append(AutoInterpretation.estimate_tolerance_from_plateau_lengths(plateau_lengths)) + found_tolerances.append( + AutoInterpretation.estimate_tolerance_from_plateau_lengths( + plateau_lengths + ) + ) - estimated_tolerance = AutoInterpretation.get_most_frequent_value(found_tolerances) + estimated_tolerance = AutoInterpretation.get_most_frequent_value( + found_tolerances + ) self.assertIn(estimated_tolerance, range(4, 7)) diff --git a/tests/auto_interpretation/test_message_segmentation.py b/tests/auto_interpretation/test_message_segmentation.py index 638033b2f6..33807b1926 100644 --- a/tests/auto_interpretation/test_message_segmentation.py +++ b/tests/auto_interpretation/test_message_segmentation.py @@ -3,7 +3,10 @@ import numpy as np from tests.test_util import get_path_for_data_file -from urh.ainterpretation.AutoInterpretation import segment_messages_from_magnitudes, merge_message_segments_for_ook +from urh.ainterpretation.AutoInterpretation import ( + segment_messages_from_magnitudes, + merge_message_segments_for_ook, +) from urh.signalprocessing.IQArray import IQArray from urh.signalprocessing.Modulator import Modulator from urh.signalprocessing.Signal import Signal @@ -24,7 +27,9 @@ def test_segmentation_for_ask(self): self.assertEqual(segments[0], (462, 12011)) def test_segmentation_enocean_multiple_messages(self): - signal = np.fromfile(get_path_for_data_file("enocean.complex"), dtype=np.complex64) + signal = np.fromfile( + get_path_for_data_file("enocean.complex"), dtype=np.complex64 + ) segments = segment_messages_from_magnitudes(np.abs(signal), 0.0448) segments = merge_message_segments_for_ook(segments) self.assertEqual(len(segments), 3) @@ -34,16 +39,26 @@ def test_segmentation_enocean_multiple_messages(self): def test_message_segmentation_fsk_xavax(self): signal = Signal(get_path_for_data_file("xavax.coco"), "") - segments = segment_messages_from_magnitudes(signal.iq_array.magnitudes, noise_threshold=0.002) + segments = segment_messages_from_magnitudes( + signal.iq_array.magnitudes, noise_threshold=0.002 + ) # Signal starts with overdrive, so one message more self.assertTrue(len(segments) == 6 or len(segments) == 7) if len(segments) == 7: segments = segments[1:] - self.assertEqual(segments, - [(275146, 293697), (321073, 338819), (618213, 1631898), (1657890, 1678041), (1803145, 1820892), - (1846213, 1866364)]) + self.assertEqual( + segments, + [ + (275146, 293697), + (321073, 338819), + (618213, 1631898), + (1657890, 1678041), + (1803145, 1820892), + (1846213, 1866364), + ], + ) def test_segmentation_ask_50(self): modulator = Modulator("ask50") @@ -67,13 +82,134 @@ def test_segmentation_elektromaten(self): signal.noise_threshold_relative = 0.1 - segments = segment_messages_from_magnitudes(signal.iq_array.magnitudes, noise_threshold=signal.noise_threshold) + segments = segment_messages_from_magnitudes( + signal.iq_array.magnitudes, noise_threshold=signal.noise_threshold + ) segments = merge_message_segments_for_ook(segments) self.assertEqual(len(segments), 11) def test_ook_merge(self): - input = [(26728, 27207), (28716, 29216), (30712, 32190), (32695, 34178), (34686, 35181), (36683, 38181), (38670, 39165), (40668, 42154), (42659, 44151), (44642, 46139), (46634, 47121), (47134, 47145), (48632, 50129), (50617, 51105), (52612, 54089), (54100, 54113), (54601, 56095), (56592, 58075), (58581, 59066), (59076, 59091), (60579, 61081), (62567, 64063), (64559, 66053), (66548, 67035), (68539, 69031), (70533, 71035), (72527, 73008), (73019, 73035), (74522, 75006), (90465, 90958), (92456, 92944), (94455, 95935), (96441, 97930), (98437, 98937), (100430, 101914), (102414, 102901), (104413, 105889), (106398, 107895), (108389, 109873), (110385, 110877), (112374, 113853), (114367, 114862), (116355, 117842), (118344, 119826), (120340, 121824), (122324, 122825), (124323, 124821), (126316, 127807), (128300, 129782), (130293, 130777), (132280, 132774), (134275, 134773), (136266, 136767), (138265, 138751), (154205, 154694), (156206, 156703), (158191, 159685), (160189, 161683), (162176, 162667), (164164, 165657), (166159, 166648), (168147, 169631), (170145, 171621), (172131, 173611), (174125, 174607), (176118, 177600), (178105, 178590), (180093, 181574), (181585, 181599), (182090, 183573), (184074, 185565), (186070, 186553), (188061, 188555), (190052, 191533), (192043, 193523), (194034, 194518), (196021, 196510), (198012, 198503), (200014, 200496), (202003, 202485), (202498, 202511), (217953, 218430), (218442, 218457), (219940, 220426), (221935, 223431), (223926, 225409), (225912, 226399), (227912, 229387), (229896, 230382), (231886, 233369), (233383, 233393), (233882, 235375), (235874, 237357), (237858, 238361), (239850, 241343), (241844, 242328), (243840, 245331), (245828, 247306), (247820, 249296), (249811, 250298), (251803, 252283), (252296, 252309), (253790, 255271), (255778, 257276), (257774, 258258), (259764, 260257), (261760, 262239), (263744, 264241), (265744, 266225), (281684, 282171), (283676, 284163), (285668, 287153), (287665, 289149), (289654, 290145), (291642, 293131), (293633, 294120), (295629, 297104), (297116, 297129)] + input = [ + (26728, 27207), + (28716, 29216), + (30712, 32190), + (32695, 34178), + (34686, 35181), + (36683, 38181), + (38670, 39165), + (40668, 42154), + (42659, 44151), + (44642, 46139), + (46634, 47121), + (47134, 47145), + (48632, 50129), + (50617, 51105), + (52612, 54089), + (54100, 54113), + (54601, 56095), + (56592, 58075), + (58581, 59066), + (59076, 59091), + (60579, 61081), + (62567, 64063), + (64559, 66053), + (66548, 67035), + (68539, 69031), + (70533, 71035), + (72527, 73008), + (73019, 73035), + (74522, 75006), + (90465, 90958), + (92456, 92944), + (94455, 95935), + (96441, 97930), + (98437, 98937), + (100430, 101914), + (102414, 102901), + (104413, 105889), + (106398, 107895), + (108389, 109873), + (110385, 110877), + (112374, 113853), + (114367, 114862), + (116355, 117842), + (118344, 119826), + (120340, 121824), + (122324, 122825), + (124323, 124821), + (126316, 127807), + (128300, 129782), + (130293, 130777), + (132280, 132774), + (134275, 134773), + (136266, 136767), + (138265, 138751), + (154205, 154694), + (156206, 156703), + (158191, 159685), + (160189, 161683), + (162176, 162667), + (164164, 165657), + (166159, 166648), + (168147, 169631), + (170145, 171621), + (172131, 173611), + (174125, 174607), + (176118, 177600), + (178105, 178590), + (180093, 181574), + (181585, 181599), + (182090, 183573), + (184074, 185565), + (186070, 186553), + (188061, 188555), + (190052, 191533), + (192043, 193523), + (194034, 194518), + (196021, 196510), + (198012, 198503), + (200014, 200496), + (202003, 202485), + (202498, 202511), + (217953, 218430), + (218442, 218457), + (219940, 220426), + (221935, 223431), + (223926, 225409), + (225912, 226399), + (227912, 229387), + (229896, 230382), + (231886, 233369), + (233383, 233393), + (233882, 235375), + (235874, 237357), + (237858, 238361), + (239850, 241343), + (241844, 242328), + (243840, 245331), + (245828, 247306), + (247820, 249296), + (249811, 250298), + (251803, 252283), + (252296, 252309), + (253790, 255271), + (255778, 257276), + (257774, 258258), + (259764, 260257), + (261760, 262239), + (263744, 264241), + (265744, 266225), + (281684, 282171), + (283676, 284163), + (285668, 287153), + (287665, 289149), + (289654, 290145), + (291642, 293131), + (293633, 294120), + (295629, 297104), + (297116, 297129), + ] merged = merge_message_segments_for_ook(input) self.assertEqual(len(merged), 5) diff --git a/tests/auto_interpretation/test_modulation_detection.py b/tests/auto_interpretation/test_modulation_detection.py index 1137b242f2..f5c4d973ec 100644 --- a/tests/auto_interpretation/test_modulation_detection.py +++ b/tests/auto_interpretation/test_modulation_detection.py @@ -8,9 +8,13 @@ class TestModulationDetection(unittest.TestCase): def test_fsk_detection(self): - fsk_signal = np.fromfile(get_path_for_data_file("fsk.complex"), dtype=np.complex64)[5:15000] + fsk_signal = np.fromfile( + get_path_for_data_file("fsk.complex"), dtype=np.complex64 + )[5:15000] - mod = AutoInterpretation.detect_modulation(fsk_signal, wavelet_scale=4, median_filter_order=7) + mod = AutoInterpretation.detect_modulation( + fsk_signal, wavelet_scale=4, median_filter_order=7 + ) self.assertEqual(mod, "FSK") def test_ook_detection(self): @@ -18,12 +22,20 @@ def test_ook_detection(self): mod = AutoInterpretation.detect_modulation(data) self.assertEqual(mod, "OOK") - data = np.fromfile(get_path_for_data_file("ASK_mod.complex"), dtype=np.complex64) + data = np.fromfile( + get_path_for_data_file("ASK_mod.complex"), dtype=np.complex64 + ) mod = AutoInterpretation.detect_modulation(data) self.assertEqual(mod, "OOK") def test_ask50_detection(self): - message_indices = [(0, 8000), (18000, 26000), (36000, 44000), (54000, 62000), (72000, 80000)] + message_indices = [ + (0, 8000), + (18000, 26000), + (36000, 44000), + (54000, 62000), + (72000, 80000), + ] data = np.fromfile(get_path_for_data_file("ask50.complex"), dtype=np.complex64) for start, end in message_indices: diff --git a/tests/auto_interpretation/test_noise_detection.py b/tests/auto_interpretation/test_noise_detection.py index 69092dfdb3..70a6c0cac9 100644 --- a/tests/auto_interpretation/test_noise_detection.py +++ b/tests/auto_interpretation/test_noise_detection.py @@ -21,25 +21,39 @@ def test_for_ask_signal(self): self.assertLessEqual(noise_level, 0.043) def test_for_fsk_signal_with_little_noise_before_and_after(self): - data = np.concatenate((np.fromfile(get_path_for_data_file("fsk.complex"), dtype=np.complex64)[-1000:], - np.fromfile(get_path_for_data_file("fsk.complex"), dtype=np.complex64)[0:18800])) + data = np.concatenate( + ( + np.fromfile(get_path_for_data_file("fsk.complex"), dtype=np.complex64)[ + -1000: + ], + np.fromfile(get_path_for_data_file("fsk.complex"), dtype=np.complex64)[ + 0:18800 + ], + ) + ) noise_level = detect_noise_level(np.abs(data)) self.assertGreaterEqual(noise_level, 0.0005) self.assertLessEqual(noise_level, 0.009) def test_for_enocean_ask_signal(self): - data = np.fromfile(get_path_for_data_file("enocean.complex"), dtype=np.complex64) + data = np.fromfile( + get_path_for_data_file("enocean.complex"), dtype=np.complex64 + ) noise_level = detect_noise_level(np.abs(data)) self.assertGreaterEqual(noise_level, 0.01) self.assertLessEqual(noise_level, 0.28) def test_for_noiseless_signal(self): - data = np.fromfile(get_path_for_data_file("fsk.complex"), dtype=np.complex64)[0:17639] + data = np.fromfile(get_path_for_data_file("fsk.complex"), dtype=np.complex64)[ + 0:17639 + ] noise_level = detect_noise_level(np.abs(data)) self.assertEqual(noise_level, 0) def test_multi_messages_different_rssi(self): - data = Signal(get_path_for_data_file("multi_messages_different_rssi.coco"), "").iq_array.data + data = Signal( + get_path_for_data_file("multi_messages_different_rssi.coco"), "" + ).iq_array.data noise_level = detect_noise_level(np.abs(data)) self.assertGreater(noise_level, 0.001) self.assertLess(noise_level, 0.002) diff --git a/tests/awre/AWRETestCase.py b/tests/awre/AWRETestCase.py index 24f2ef74e7..69455f03f8 100644 --- a/tests/awre/AWRETestCase.py +++ b/tests/awre/AWRETestCase.py @@ -20,7 +20,9 @@ def setUp(self): numpy.set_printoptions(linewidth=80) self.field_types = self.__init_field_types() - def get_format_finder_from_protocol_file(self, filename: str, clear_participant_addresses=True, return_messages=False): + def get_format_finder_from_protocol_file( + self, filename: str, clear_participant_addresses=True, return_messages=False + ): proto_file = get_path_for_data_file(filename) protocol = ProtocolAnalyzer(signal=None, filename=proto_file) protocol.from_xml_file(filename=proto_file, read_bits=True) @@ -55,8 +57,12 @@ def save_protocol(name, protocol_generator, silent=False): if isinstance(protocol_generator, ProtocolGenerator): protocol_generator.to_file(filename) elif isinstance(protocol_generator, ProtocolAnalyzer): - participants = list(set(msg.participant for msg in protocol_generator.messages)) - protocol_generator.to_xml_file(filename, [], participants=participants, write_bits=True) + participants = list( + set(msg.participant for msg in protocol_generator.messages) + ) + protocol_generator.to_xml_file( + filename, [], participants=participants, write_bits=True + ) info = "Protocol written to " + filename if not silent: print() diff --git a/tests/awre/AWRExperiments.py b/tests/awre/AWRExperiments.py index b4bd4a833d..e33eb47b9d 100644 --- a/tests/awre/AWRExperiments.py +++ b/tests/awre/AWRExperiments.py @@ -23,7 +23,9 @@ from urh.util.GenericCRC import GenericCRC -def run_for_num_broken(protocol_nr, num_broken: list, num_messages: int, num_runs: int) -> list: +def run_for_num_broken( + protocol_nr, num_broken: list, num_messages: int, num_runs: int +) -> list: random.seed(0) np.random.seed(0) @@ -32,14 +34,20 @@ def run_for_num_broken(protocol_nr, num_broken: list, num_messages: int, num_run tmp_accuracies = np.empty(num_runs, dtype=np.float64) tmp_accuracies_without_broken = np.empty(num_runs, dtype=np.float64) for i in range(num_runs): - protocol, expected_labels = AWRExperiments.get_protocol(protocol_nr, - num_messages=num_messages, - num_broken_messages=broken, - silent=True) + protocol, expected_labels = AWRExperiments.get_protocol( + protocol_nr, + num_messages=num_messages, + num_broken_messages=broken, + silent=True, + ) AWRExperiments.run_format_finder_for_protocol(protocol) - accuracy = AWRExperiments.calculate_accuracy(protocol.messages, expected_labels) - accuracy_without_broken = AWRExperiments.calculate_accuracy(protocol.messages, expected_labels, broken) + accuracy = AWRExperiments.calculate_accuracy( + protocol.messages, expected_labels + ) + accuracy_without_broken = AWRExperiments.calculate_accuracy( + protocol.messages, expected_labels, broken + ) tmp_accuracies[i] = accuracy tmp_accuracies_without_broken[i] = accuracy_without_broken @@ -47,8 +55,11 @@ def run_for_num_broken(protocol_nr, num_broken: list, num_messages: int, num_run avg_accuracy_without_broken = np.mean(tmp_accuracies_without_broken) result.append((avg_accuracy, avg_accuracy_without_broken)) - print("Protocol {} with {} broken: {:>3}% {:>3}%".format(protocol_nr, broken, int(avg_accuracy), - int(avg_accuracy_without_broken))) + print( + "Protocol {} with {} broken: {:>3}% {:>3}%".format( + protocol_nr, broken, int(avg_accuracy), int(avg_accuracy_without_broken) + ) + ) return result @@ -67,9 +78,11 @@ def _prepare_protocol_1() -> ProtocolGenerator: mb.add_label(FieldType.Function.DST_ADDRESS, 16) mb.add_label(FieldType.Function.SEQUENCE_NUMBER, 8) - pg = ProtocolGenerator([mb.message_type], - syncs_by_mt={mb.message_type: "0x1337"}, - participants=[alice, bob]) + pg = ProtocolGenerator( + [mb.message_type], + syncs_by_mt={mb.message_type: "0x1337"}, + participants=[alice, bob], + ) return pg @staticmethod @@ -85,11 +98,13 @@ def _prepare_protocol_2() -> ProtocolGenerator: mb.add_label(FieldType.Function.DST_ADDRESS, 24) mb.add_label(FieldType.Function.SEQUENCE_NUMBER, 16) - pg = ProtocolGenerator([mb.message_type], - syncs_by_mt={mb.message_type: "0x1337"}, - preambles_by_mt={mb.message_type: "10" * 36}, - sequence_number_increment=32, - participants=[alice, bob]) + pg = ProtocolGenerator( + [mb.message_type], + syncs_by_mt={mb.message_type: "0x1337"}, + preambles_by_mt={mb.message_type: "10" * 36}, + sequence_number_increment=32, + participants=[alice, bob], + ) return pg @@ -117,10 +132,12 @@ def _prepare_protocol_3() -> ProtocolGenerator: mb_ack.add_label(FieldType.Function.DST_ADDRESS, 16) mb_ack.add_checksum_label(8, checksum) - pg = ProtocolGenerator([mb.message_type, mb_ack.message_type], - syncs_by_mt={mb.message_type: "0x9a7d", mb_ack.message_type: "0x9a7d"}, - preambles_by_mt={mb.message_type: "10" * 8, mb_ack.message_type: "10" * 8}, - participants=[alice, bob]) + pg = ProtocolGenerator( + [mb.message_type, mb_ack.message_type], + syncs_by_mt={mb.message_type: "0x9a7d", mb_ack.message_type: "0x9a7d"}, + preambles_by_mt={mb.message_type: "10" * 8, mb_ack.message_type: "10" * 8}, + participants=[alice, bob], + ) return pg @@ -160,10 +177,12 @@ def _prepare_protocol_4() -> ProtocolGenerator: preamble = "10001000" * 2 - pg = ProtocolGenerator([mt1, mt2, mt3], - syncs_by_mt={mt1: "0x9a7d", mt2: "0x9a7d", mt3: "0x9a7d"}, - preambles_by_mt={mt1: preamble, mt2: preamble, mt3: preamble}, - participants=[alice, bob]) + pg = ProtocolGenerator( + [mt1, mt2, mt3], + syncs_by_mt={mt1: "0x9a7d", mt2: "0x9a7d", mt3: "0x9a7d"}, + preambles_by_mt={mt1: preamble, mt2: preamble, mt3: preamble}, + participants=[alice, bob], + ) return pg @@ -187,10 +206,12 @@ def _prepare_protocol_5() -> ProtocolGenerator: mb_ack.add_label(FieldType.Function.LENGTH, 8) mb_ack.add_label(FieldType.Function.DST_ADDRESS, 16) - pg = ProtocolGenerator([mb.message_type, mb_ack.message_type], - syncs_by_mt={mb.message_type: "0x9a7d", mb_ack.message_type: "0x9a7d"}, - preambles_by_mt={mb.message_type: "10" * 8, mb_ack.message_type: "10" * 8}, - participants=[alice, bob, carl]) + pg = ProtocolGenerator( + [mb.message_type, mb_ack.message_type], + syncs_by_mt={mb.message_type: "0x9a7d", mb_ack.message_type: "0x9a7d"}, + preambles_by_mt={mb.message_type: "10" * 8, mb_ack.message_type: "10" * 8}, + participants=[alice, bob, carl], + ) return pg @@ -205,10 +226,12 @@ def _prepare_protocol_6() -> ProtocolGenerator: mb.add_label(FieldType.Function.SRC_ADDRESS, 8) mb.add_label(FieldType.Function.SEQUENCE_NUMBER, 8) - pg = ProtocolGenerator([mb.message_type], - syncs_by_mt={mb.message_type: "0x8e88"}, - preambles_by_mt={mb.message_type: "10" * 8}, - participants=[alice, broadcast]) + pg = ProtocolGenerator( + [mb.message_type], + syncs_by_mt={mb.message_type: "0x8e88"}, + preambles_by_mt={mb.message_type: "10" * 8}, + participants=[alice, broadcast], + ) return pg @@ -245,12 +268,20 @@ def _prepare_protocol_7() -> ProtocolGenerator: mb_kex.add_label(FieldType.Function.DATA, 64 * 8) mb_kex.add_checksum_label(16, checksum) - pg = ProtocolGenerator([mb.message_type, mb_ack.message_type, mb_kex.message_type], - syncs_by_mt={mb.message_type: "0x0420", mb_ack.message_type: "0x2222", - mb_kex.message_type: "0x6767"}, - preambles_by_mt={mb.message_type: "10" * 8, mb_ack.message_type: "10" * 4, - mb_kex.message_type: "10" * 12}, - participants=[alice, bob, charly, daniel]) + pg = ProtocolGenerator( + [mb.message_type, mb_ack.message_type, mb_kex.message_type], + syncs_by_mt={ + mb.message_type: "0x0420", + mb_ack.message_type: "0x2222", + mb_kex.message_type: "0x6767", + }, + preambles_by_mt={ + mb.message_type: "10" * 8, + mb_ack.message_type: "10" * 4, + mb_kex.message_type: "10" * 12, + }, + participants=[alice, bob, charly, daniel], + ) return pg @@ -272,12 +303,14 @@ def _prepare_protocol_8() -> ProtocolGenerator: mb2.add_label(FieldType.Function.SEQUENCE_NUMBER, 16) mb2.add_label(FieldType.Function.DATA, 8 * 260) - pg = ProtocolGenerator([mb.message_type, mb2.message_type], - syncs_by_mt={mb.message_type: "0x9", mb2.message_type: "0x9"}, - preambles_by_mt={mb.message_type: "10" * 2, mb2.message_type: "10" * 2}, - sequence_number_increment=32, - participants=[alice], - little_endian=True) + pg = ProtocolGenerator( + [mb.message_type, mb2.message_type], + syncs_by_mt={mb.message_type: "0x9", mb2.message_type: "0x9"}, + preambles_by_mt={mb.message_type: "10" * 2, mb2.message_type: "10" * 2}, + sequence_number_increment=32, + participants=[alice], + little_endian=True, + ) return pg @@ -291,7 +324,9 @@ def test_export_to_latex(self): pg.export_to_latex(filename, i) @classmethod - def get_protocol(cls, protocol_number: int, num_messages, num_broken_messages=0, silent=False): + def get_protocol( + cls, protocol_number: int, num_messages, num_broken_messages=0, silent=False + ): if protocol_number == 1: pg = cls._prepare_protocol_1() elif protocol_number == 2: @@ -311,8 +346,11 @@ def get_protocol(cls, protocol_number: int, num_messages, num_broken_messages=0, else: raise ValueError("Unknown protocol number") - messages_types_with_data_field = [mt for mt in pg.protocol.message_types - if mt.get_first_label_with_type(FieldType.Function.DATA)] + messages_types_with_data_field = [ + mt + for mt in pg.protocol.message_types + if mt.get_first_label_with_type(FieldType.Function.DATA) + ] i = -1 while len(pg.protocol.messages) < num_messages: i += 1 @@ -330,25 +368,47 @@ def get_protocol(cls, protocol_number: int, num_messages, num_broken_messages=0, pg.generate_message(data=data, source=source, destination=destination) else: # search for message type with right data length - mt = messages_types_with_data_field[i % len(messages_types_with_data_field)] - data_length = mt.get_first_label_with_type(FieldType.Function.DATA).length + mt = messages_types_with_data_field[ + i % len(messages_types_with_data_field) + ] + data_length = mt.get_first_label_with_type( + FieldType.Function.DATA + ).length data = "".join(random.choice(["0", "1"]) for _ in range(data_length)) - pg.generate_message(message_type=mt, data=data, source=source, destination=destination) + pg.generate_message( + message_type=mt, data=data, source=source, destination=destination + ) - ack_message_type = next((mt for mt in pg.protocol.message_types if "ack" in mt.name), None) + ack_message_type = next( + (mt for mt in pg.protocol.message_types if "ack" in mt.name), None + ) if ack_message_type: - pg.generate_message(message_type=ack_message_type, data="", source=destination, destination=source) + pg.generate_message( + message_type=ack_message_type, + data="", + source=destination, + destination=source, + ) for i in range(num_broken_messages): msg = pg.protocol.messages[i] pos = random.randint(0, len(msg.plain_bits) // 2) - msg.plain_bits[pos:] = array.array("B", - [random.randint(0, 1) for _ in range(len(msg.plain_bits) - pos)]) + msg.plain_bits[pos:] = array.array( + "B", [random.randint(0, 1) for _ in range(len(msg.plain_bits) - pos)] + ) if num_broken_messages == 0: - cls.save_protocol("protocol{}_{}_messages".format(protocol_number, num_messages), pg, silent=silent) + cls.save_protocol( + "protocol{}_{}_messages".format(protocol_number, num_messages), + pg, + silent=silent, + ) else: - cls.save_protocol("protocol{}_{}_broken".format(protocol_number, num_broken_messages), pg, silent=silent) + cls.save_protocol( + "protocol{}_{}_broken".format(protocol_number, num_broken_messages), + pg, + silent=silent, + ) expected_message_types = [msg.message_type for msg in pg.protocol.messages] @@ -374,10 +434,13 @@ def calculate_accuracy(messages, expected_labels, num_broken_messages=0): :type expected_labels: list of MessageType :return: """ - accuracy = sum(len(set(expected_labels[i]) & set(messages[i].message_type)) / len(expected_labels[i]) - for i in range(num_broken_messages, len(messages))) + accuracy = sum( + len(set(expected_labels[i]) & set(messages[i].message_type)) + / len(expected_labels[i]) + for i in range(num_broken_messages, len(messages)) + ) try: - accuracy /= (len(messages) - num_broken_messages) + accuracy /= len(messages) - num_broken_messages except ZeroDivisionError: accuracy = 0 @@ -393,13 +456,21 @@ def test_against_num_messages(self): np.random.seed(0) for protocol_nr in protocols: for n in num_messages: - protocol, expected_labels = self.get_protocol(protocol_nr, num_messages=n) + protocol, expected_labels = self.get_protocol( + protocol_nr, num_messages=n + ) self.run_format_finder_for_protocol(protocol) accuracy = self.calculate_accuracy(protocol.messages, expected_labels) accuracies["protocol {}".format(protocol_nr)].append(accuracy) - self.__plot(num_messages, accuracies, xlabel="Number of messages", ylabel="Accuracy in %", grid=True) + self.__plot( + num_messages, + accuracies, + xlabel="Number of messages", + ylabel="Accuracy in %", + grid=True, + ) self.__export_to_csv("/tmp/accuray-vs-messages", num_messages, accuracies) def test_against_error(self): @@ -419,23 +490,44 @@ def test_against_error(self): np.random.seed(0) with multiprocessing.Pool() as p: - result = p.starmap(run_for_num_broken, - [(i, num_broken_messages, num_messages, num_runs) for i in protocols]) + result = p.starmap( + run_for_num_broken, + [(i, num_broken_messages, num_messages, num_runs) for i in protocols], + ) for i, acc in enumerate(result): accuracies["protocol {}".format(i + 1)] = [a[0] for a in acc] - accuracies_without_broken["protocol {}".format(i + 1)] = [a[1] for a in acc] - - self.__plot(100 * np.array(num_broken_messages) / num_messages, accuracies, - title="Overall Accuracy vs percentage of broken messages", - xlabel="Broken messages in %", - ylabel="Accuracy in %", grid=True) - self.__plot(100 * np.array(num_broken_messages) / num_messages, accuracies_without_broken, - title=" Accuracy of unbroken vs percentage of broken messages", - xlabel="Broken messages in %", - ylabel="Accuracy in %", grid=True) - self.__export_to_csv("/tmp/accuray-vs-error", num_broken_messages, accuracies, relative=num_messages) - self.__export_to_csv("/tmp/accuray-vs-error-without-broken", num_broken_messages, accuracies_without_broken, - relative=num_messages) + accuracies_without_broken["protocol {}".format(i + 1)] = [ + a[1] for a in acc + ] + + self.__plot( + 100 * np.array(num_broken_messages) / num_messages, + accuracies, + title="Overall Accuracy vs percentage of broken messages", + xlabel="Broken messages in %", + ylabel="Accuracy in %", + grid=True, + ) + self.__plot( + 100 * np.array(num_broken_messages) / num_messages, + accuracies_without_broken, + title=" Accuracy of unbroken vs percentage of broken messages", + xlabel="Broken messages in %", + ylabel="Accuracy in %", + grid=True, + ) + self.__export_to_csv( + "/tmp/accuray-vs-error", + num_broken_messages, + accuracies, + relative=num_messages, + ) + self.__export_to_csv( + "/tmp/accuray-vs-error-without-broken", + num_broken_messages, + accuracies_without_broken, + relative=num_messages, + ) def test_performance(self): Engine._DEBUG_ = False @@ -487,8 +579,13 @@ def test_performance_real_protocols(self): tmp_performances = np.empty(num_runs, dtype=np.float64) for i in range(num_runs): - print("\r{0} with {1:02d} messages ({2}/{3} runs)".format(protocol_name, messages, i + 1, num_runs), - flush=True, end="") + print( + "\r{0} with {1:02d} messages ({2}/{3} runs)".format( + protocol_name, messages, i + 1, num_runs + ), + flush=True, + end="", + ) t = time.time() self.run_format_finder_for_protocol(protocol) @@ -499,7 +596,13 @@ def test_performance_real_protocols(self): print(" {:.2f}s".format(mean_performance)) performances["{}".format(protocol_name)].append(mean_performance) - self.__plot(num_messages, performances, xlabel="Number of messages", ylabel="Time in seconds", grid=True) + self.__plot( + num_messages, + performances, + xlabel="Number of messages", + ylabel="Time in seconds", + grid=True, + ) self.__export_to_csv("/tmp/performance.csv", num_messages, performances) @staticmethod @@ -558,7 +661,10 @@ def generate_homematic(cls, num_messages: int, save_protocol=True): mb_r_frame = MessageTypeBuilder("rframe") mb_a_frame = MessageTypeBuilder("aframe") - participants = [Participant("CCU", address_hex="3927cc"), Participant("Switch", address_hex="3101cc")] + participants = [ + Participant("CCU", address_hex="3927cc"), + Participant("Switch", address_hex="3101cc"), + ] checksum = GenericCRC.from_standard_checksum("CRC16 CC1101") for mb_builder in [mb_m_frame, mb_c_frame, mb_r_frame, mb_a_frame]: @@ -572,32 +678,50 @@ def generate_homematic(cls, num_messages: int, save_protocol=True): if mb_builder.name == "mframe": mb_builder.add_label(FieldType.Function.DATA, 16, name="command") elif mb_builder.name == "cframe": - mb_builder.add_label(FieldType.Function.DATA, 16 * 4, name="command+challenge+magic") + mb_builder.add_label( + FieldType.Function.DATA, 16 * 4, name="command+challenge+magic" + ) elif mb_builder.name == "rframe": mb_builder.add_label(FieldType.Function.DATA, 32 * 4, name="cipher") elif mb_builder.name == "aframe": - mb_builder.add_label(FieldType.Function.DATA, 10 * 4, name="command + auth") + mb_builder.add_label( + FieldType.Function.DATA, 10 * 4, name="command + auth" + ) mb_builder.add_checksum_label(16, checksum) - message_types = [mb_m_frame.message_type, mb_c_frame.message_type, mb_r_frame.message_type, - mb_a_frame.message_type] + message_types = [ + mb_m_frame.message_type, + mb_c_frame.message_type, + mb_r_frame.message_type, + mb_a_frame.message_type, + ] preamble = "0xaaaaaaaa" sync = "0xe9cae9ca" initial_sequence_number = 36 - pg = ProtocolGenerator(message_types, participants, - preambles_by_mt={mt: preamble for mt in message_types}, - syncs_by_mt={mt: sync for mt in message_types}, - sequence_numbers={mt: initial_sequence_number for mt in message_types}, - message_type_codes={mb_m_frame.message_type: 42560, - mb_c_frame.message_type: 40962, - mb_r_frame.message_type: 40963, - mb_a_frame.message_type: 32770}) + pg = ProtocolGenerator( + message_types, + participants, + preambles_by_mt={mt: preamble for mt in message_types}, + syncs_by_mt={mt: sync for mt in message_types}, + sequence_numbers={mt: initial_sequence_number for mt in message_types}, + message_type_codes={ + mb_m_frame.message_type: 42560, + mb_c_frame.message_type: 40962, + mb_r_frame.message_type: 40963, + mb_a_frame.message_type: 32770, + }, + ) for i in range(num_messages): mt = pg.message_types[i % 4] data_length = mt.get_first_label_with_type(FieldType.Function.DATA).length data = "".join(random.choice(["0", "1"]) for _ in range(data_length)) - pg.generate_message(mt, data, source=pg.participants[i % 2], destination=pg.participants[(i + 1) % 2]) + pg.generate_message( + mt, + data, + source=pg.participants[i % 2], + destination=pg.participants[(i + 1) % 2], + ) if save_protocol: cls.save_protocol("homematic", pg) @@ -656,7 +780,7 @@ def bold_latex(s): 5: "three participants with ack frame", 6: "short address", 7: "four participants, varying preamble size, varying sync words", - 8: "nibble fields + LE" + 8: "nibble fields + LE", } bold = {i: defaultdict(bool) for i in range(1, 9)} @@ -678,35 +802,42 @@ def bold_latex(s): bold[8][FieldType.Function.PREAMBLE] = True bold[8][FieldType.Function.SYNC] = True - filename = os.path.expanduser("~/GIT/publications/awre/USENIX/protocol_table.tex") + filename = os.path.expanduser( + "~/GIT/publications/awre/USENIX/protocol_table.tex" + ) rowcolors = [r"\rowcolor{black!10}", r"\rowcolor{black!20}"] with open(filename, "w") as f: f.write(r"\begin{table*}[!h]" + "\n") f.write( - "\t" + r"\caption{Properties of tested protocols whereby $\times$ means field is not present and $N_P$ is the number of participants.}" + "\n") + "\t" + + r"\caption{Properties of tested protocols whereby $\times$ means field is not present and $N_P$ is the number of participants.}" + + "\n" + ) f.write("\t" + r"\label{tab:protocols}" + "\n") f.write("\t" + r"\centering" + "\n") f.write("\t" + r"\begin{tabularx}{\linewidth}{cp{2.5cm}llcccccccc}" + "\n") f.write("\t\t" + r"\hline" + "\n") f.write("\t\t" + r"\rowcolor{black!90}" + "\n") - f.write("\t\t" + r"\textcolor{white}{\textbf{\#}} & " - r"\textcolor{white}{\textbf{Comment}} & " - r"\textcolor{white}{$\mathbf{ N_P }$} & " - r"\textcolor{white}{\textbf{Message}} & " - r"\textcolor{white}{\textbf{Even/odd}} & " - r"\multicolumn{7}{c}{\textcolor{white}{\textbf{Size of field in bit (BE=Big Endian, LE=Little Endian)}}}\\" - "\n\t\t" - r"\rowcolor{black!90}" - "\n\t\t" - r"& & & \textcolor{white}{\textbf{Type}} & \textcolor{white}{\textbf{message data}} &" - r"\textcolor{white}{Preamble} & " - r"\textcolor{white}{Sync} & " - r"\textcolor{white}{Length} & " - r"\textcolor{white}{SRC} & " - r"\textcolor{white}{DST} & " - r"\textcolor{white}{SEQ Nr} & " - r"\textcolor{white}{CRC} \\" + "\n") + f.write( + "\t\t" + r"\textcolor{white}{\textbf{\#}} & " + r"\textcolor{white}{\textbf{Comment}} & " + r"\textcolor{white}{$\mathbf{ N_P }$} & " + r"\textcolor{white}{\textbf{Message}} & " + r"\textcolor{white}{\textbf{Even/odd}} & " + r"\multicolumn{7}{c}{\textcolor{white}{\textbf{Size of field in bit (BE=Big Endian, LE=Little Endian)}}}\\" + "\n\t\t" + r"\rowcolor{black!90}" + "\n\t\t" + r"& & & \textcolor{white}{\textbf{Type}} & \textcolor{white}{\textbf{message data}} &" + r"\textcolor{white}{Preamble} & " + r"\textcolor{white}{Sync} & " + r"\textcolor{white}{Length} & " + r"\textcolor{white}{SRC} & " + r"\textcolor{white}{DST} & " + r"\textcolor{white}{SEQ Nr} & " + r"\textcolor{white}{CRC} \\" + "\n" + ) f.write("\t\t" + r"\hline" + "\n") rowcolor_index = 0 @@ -718,8 +849,14 @@ def bold_latex(s): data1 = next(mt for mt in pg.message_types if mt.name == "data1") data2 = next(mt for mt in pg.message_types if mt.name == "data2") - data1_len = data1.get_first_label_with_type(FieldType.Function.DATA).length // 8 - data2_len = data2.get_first_label_with_type(FieldType.Function.DATA).length // 8 + data1_len = ( + data1.get_first_label_with_type(FieldType.Function.DATA).length + // 8 + ) + data2_len = ( + data2.get_first_label_with_type(FieldType.Function.DATA).length + // 8 + ) except StopIteration: data1_len, data2_len = 8, 64 @@ -741,18 +878,33 @@ def bold_latex(s): f.write("\t\t" + rowcolor + "\n") if len(pg.message_types) == 1 or ( - mt.name == "data1" and "ack" not in {m.name for m in pg.message_types}): - f.write("\t\t{} & {} & {} & {} &".format(protocol_nr, comments[i], participants, - mt.name.replace("1", ""))) + mt.name == "data1" + and "ack" not in {m.name for m in pg.message_types} + ): + f.write( + "\t\t{} & {} & {} & {} &".format( + protocol_nr, + comments[i], + participants, + mt.name.replace("1", ""), + ) + ) elif j == len(pg.message_types) - 1: f.write( - "\t\t{} & \\multirow{{{}}}{{\\linewidth}}{{{}}} & {} & {} &".format(protocol_nr, -rowcount, - comments[i], - participants, - mt.name.replace("1", - ""))) + "\t\t{} & \\multirow{{{}}}{{\\linewidth}}{{{}}} & {} & {} &".format( + protocol_nr, + -rowcount, + comments[i], + participants, + mt.name.replace("1", ""), + ) + ) else: - f.write("\t\t{} & & {} & {} &".format(protocol_nr, participants, mt.name.replace("1", ""))) + f.write( + "\t\t{} & & {} & {} &".format( + protocol_nr, participants, mt.name.replace("1", "") + ) + ) data_lbl = mt.get_first_label_with_type(FieldType.Function.DATA) if mt.name == "data1" or mt.name == "data2": @@ -764,18 +916,30 @@ def bold_latex(s): else: f.write(r"$ \times $ & ") - for t in (FieldType.Function.PREAMBLE, FieldType.Function.SYNC, FieldType.Function.LENGTH, - FieldType.Function.SRC_ADDRESS, FieldType.Function.DST_ADDRESS, - FieldType.Function.SEQUENCE_NUMBER, - FieldType.Function.CHECKSUM): + for t in ( + FieldType.Function.PREAMBLE, + FieldType.Function.SYNC, + FieldType.Function.LENGTH, + FieldType.Function.SRC_ADDRESS, + FieldType.Function.DST_ADDRESS, + FieldType.Function.SEQUENCE_NUMBER, + FieldType.Function.CHECKSUM, + ): lbl = mt.get_first_label_with_type(t) if lbl is not None: if bold[i][lbl.field_type.function]: f.write(bold_latex(lbl.length)) else: f.write(str(lbl.length)) - if lbl.length > 8 and t in (FieldType.Function.LENGTH, FieldType.Function.SEQUENCE_NUMBER): - f.write(" ({})".format(bold_latex("LE") if pg.little_endian else "BE")) + if lbl.length > 8 and t in ( + FieldType.Function.LENGTH, + FieldType.Function.SEQUENCE_NUMBER, + ): + f.write( + " ({})".format( + bold_latex("LE") if pg.little_endian else "BE" + ) + ) else: f.write(r"$ \times $") diff --git a/tests/awre/TestAWREHistograms.py b/tests/awre/TestAWREHistograms.py index 3a6a4341f2..b93b701bae 100644 --- a/tests/awre/TestAWREHistograms.py +++ b/tests/awre/TestAWREHistograms.py @@ -13,6 +13,7 @@ SHOW_PLOTS = True + class TestAWREHistograms(AWRETestCase): def test_very_simple_protocol(self): """ @@ -46,10 +47,16 @@ def test_simple_protocol(self): mb.add_label(FieldType.Function.LENGTH, 8) num_messages_by_data_length = {8: 5, 16: 10, 32: 15} - pg = ProtocolGenerator([mb.message_type], syncs_by_mt={mb.message_type: "0x9a9d"}) + pg = ProtocolGenerator( + [mb.message_type], syncs_by_mt={mb.message_type: "0x9a9d"} + ) for data_length, num_messages in num_messages_by_data_length.items(): for _ in range(num_messages): - pg.generate_message(data=pg.decimal_to_bits(random.randint(0, 2 ** data_length - 1), data_length)) + pg.generate_message( + data=pg.decimal_to_bits( + random.randint(0, 2**data_length - 1), data_length + ) + ) self.save_protocol("simple", pg) @@ -70,7 +77,9 @@ def test_simple_protocol(self): for i, (message_length, bitvectors) in enumerate(bitvectors_by_length.items()): plt.subplot(2, 2, i + 2) - plt.title("Messages with length {} ({})".format(message_length, len(bitvectors))) + plt.title( + "Messages with length {} ({})".format(message_length, len(bitvectors)) + ) Histogram(bitvectors).subplot_on(plt) if SHOW_PLOTS: @@ -93,10 +102,17 @@ def test_medium_protocol(self): bob = Participant("Bob", "B", "5a9d", color_index=1) num_messages = 100 - pg = ProtocolGenerator([mb.message_type], syncs_by_mt={mb.message_type: "0x1c"}, little_endian=False) + pg = ProtocolGenerator( + [mb.message_type], + syncs_by_mt={mb.message_type: "0x1c"}, + little_endian=False, + ) for i in range(num_messages): len_data = random.randint(1, 5) - data = "".join(pg.decimal_to_bits(random.randint(0, 2 ** 8 - 1), 8) for _ in range(len_data)) + data = "".join( + pg.decimal_to_bits(random.randint(0, 2**8 - 1), 8) + for _ in range(len_data) + ) if i % 2 == 0: source, dest = alice, bob else: @@ -112,9 +128,14 @@ def test_medium_protocol(self): h.subplot_on(plt) for i, (participant, bitvectors) in enumerate( - sorted(self.get_bitvectors_by_participant(pg.protocol.messages).items())): + sorted(self.get_bitvectors_by_participant(pg.protocol.messages).items()) + ): plt.subplot(2, 2, i + 3) - plt.title("Messages with participant {} ({})".format(participant.shortname, len(bitvectors))) + plt.title( + "Messages with participant {} ({})".format( + participant.shortname, len(bitvectors) + ) + ) Histogram(bitvectors).subplot_on(plt) if SHOW_PLOTS: @@ -122,9 +143,12 @@ def test_medium_protocol(self): def get_bitvectors_by_participant(self, messages): import numpy as np + result = defaultdict(list) for msg in messages: # type: Message - result[msg.participant].append(np.array(msg.decoded_bits, dtype=np.uint8, order="C")) + result[msg.participant].append( + np.array(msg.decoded_bits, dtype=np.uint8, order="C") + ) return result def test_ack_protocol(self): @@ -150,16 +174,23 @@ def test_ack_protocol(self): bob = Participant("Bob", "B", "5a9d", color_index=1) num_messages = 50 - pg = ProtocolGenerator([mb.message_type, mb_ack.message_type], - syncs_by_mt={mb.message_type: "0xbf", mb_ack.message_type: "0xbf"}, - little_endian=False) + pg = ProtocolGenerator( + [mb.message_type, mb_ack.message_type], + syncs_by_mt={mb.message_type: "0xbf", mb_ack.message_type: "0xbf"}, + little_endian=False, + ) for i in range(num_messages): if i % 2 == 0: source, dest = alice, bob else: source, dest = bob, alice pg.generate_message(data="0xffff", source=source, destination=dest) - pg.generate_message(data="", source=dest, destination=source, message_type=mb_ack.message_type) + pg.generate_message( + data="", + source=dest, + destination=source, + message_type=mb_ack.message_type, + ) self.save_protocol("proto_with_acks", pg) @@ -170,9 +201,14 @@ def test_ack_protocol(self): h.subplot_on(plt) for i, (participant, bitvectors) in enumerate( - sorted(self.get_bitvectors_by_participant(pg.protocol.messages).items())): + sorted(self.get_bitvectors_by_participant(pg.protocol.messages).items()) + ): plt.subplot(2, 2, i + 3) - plt.title("Messages with participant {} ({})".format(participant.shortname, len(bitvectors))) + plt.title( + "Messages with participant {} ({})".format( + participant.shortname, len(bitvectors) + ) + ) Histogram(bitvectors).subplot_on(plt) if SHOW_PLOTS: diff --git a/tests/awre/test_address_engine.py b/tests/awre/test_address_engine.py index 1bb9f2a767..0212266d42 100644 --- a/tests/awre/test_address_engine.py +++ b/tests/awre/test_address_engine.py @@ -36,14 +36,18 @@ def test_one_participant(self): mb.add_label(FieldType.Function.SRC_ADDRESS, 16) num_messages_by_data_length = {8: 5, 16: 10, 32: 15} - pg = ProtocolGenerator([mb.message_type], - syncs_by_mt={mb.message_type: "0x9a9d"}, - participants=[self.alice]) + pg = ProtocolGenerator( + [mb.message_type], + syncs_by_mt={mb.message_type: "0x9a9d"}, + participants=[self.alice], + ) for data_length, num_messages in num_messages_by_data_length.items(): for i in range(num_messages): - pg.generate_message(data=pg.decimal_to_bits(22 * i, data_length), source=self.alice) + pg.generate_message( + data=pg.decimal_to_bits(22 * i, data_length), source=self.alice + ) - #self.save_protocol("address_one_participant", pg) + # self.save_protocol("address_one_participant", pg) self.clear_message_types(pg.protocol.messages) ff = FormatFinder(pg.protocol.messages) @@ -63,9 +67,11 @@ def test_two_participants(self): num_messages = 50 - pg = ProtocolGenerator([mb.message_type], - syncs_by_mt={mb.message_type: "0x9a9d"}, - participants=[self.alice, self.bob]) + pg = ProtocolGenerator( + [mb.message_type], + syncs_by_mt={mb.message_type: "0x9a9d"}, + participants=[self.alice, self.bob], + ) for i in range(num_messages): if i % 2 == 0: @@ -74,9 +80,13 @@ def test_two_participants(self): else: source, destination = self.bob, self.alice data_length = 16 - pg.generate_message(data=pg.decimal_to_bits(4 * i, data_length), source=source, destination=destination) + pg.generate_message( + data=pg.decimal_to_bits(4 * i, data_length), + source=source, + destination=destination, + ) - #self.save_protocol("address_two_participants", pg) + # self.save_protocol("address_two_participants", pg) self.clear_message_types(pg.protocol.messages) ff = FormatFinder(pg.protocol.messages) @@ -97,10 +107,14 @@ def test_two_participants(self): ff.perform_iteration() self.assertEqual(len(ff.known_participant_addresses), 2) - self.assertIn(bytes([int(h, 16) for h in self.alice.address_hex]), - map(bytes, ff.known_participant_addresses.values())) - self.assertIn(bytes([int(h, 16) for h in self.bob.address_hex]), - map(bytes, ff.known_participant_addresses.values())) + self.assertIn( + bytes([int(h, 16) for h in self.alice.address_hex]), + map(bytes, ff.known_participant_addresses.values()), + ) + self.assertIn( + bytes([int(h, 16) for h in self.bob.address_hex]), + map(bytes, ff.known_participant_addresses.values()), + ) self.assertEqual(len(ff.message_types), 1) mt = ff.message_types[0] @@ -128,9 +142,11 @@ def test_two_participants_with_ack_messages(self): num_messages = 50 - pg = ProtocolGenerator([mb.message_type, mb_ack.message_type], - syncs_by_mt={mb.message_type: "0x6768", mb_ack.message_type: "0x6768"}, - participants=[self.alice, self.bob]) + pg = ProtocolGenerator( + [mb.message_type, mb_ack.message_type], + syncs_by_mt={mb.message_type: "0x6768", mb_ack.message_type: "0x6768"}, + participants=[self.alice, self.bob], + ) random.seed(0) for i in range(num_messages): @@ -140,11 +156,21 @@ def test_two_participants_with_ack_messages(self): else: source, destination = self.bob, self.alice data_length = 16 - pg.generate_message(data=pg.decimal_to_bits(random.randint(0, 2 ** (data_length - 1)), data_length), - source=source, destination=destination) - pg.generate_message(data="", message_type=mb_ack.message_type, destination=source, source=destination) - - #self.save_protocol("address_two_participants_with_acks", pg) + pg.generate_message( + data=pg.decimal_to_bits( + random.randint(0, 2 ** (data_length - 1)), data_length + ), + source=source, + destination=destination, + ) + pg.generate_message( + data="", + message_type=mb_ack.message_type, + destination=source, + source=destination, + ) + + # self.save_protocol("address_two_participants_with_acks", pg) self.clear_message_types(pg.protocol.messages) ff = FormatFinder(pg.protocol.messages) @@ -193,9 +219,11 @@ def test_two_participants_with_ack_messages_and_type(self): num_messages = 50 - pg = ProtocolGenerator([mb.message_type, mb_ack.message_type], - syncs_by_mt={mb.message_type: "0x6768", mb_ack.message_type: "0x6768"}, - participants=[self.alice, self.bob]) + pg = ProtocolGenerator( + [mb.message_type, mb_ack.message_type], + syncs_by_mt={mb.message_type: "0x6768", mb_ack.message_type: "0x6768"}, + participants=[self.alice, self.bob], + ) random.seed(0) for i in range(num_messages): @@ -205,11 +233,21 @@ def test_two_participants_with_ack_messages_and_type(self): else: source, destination = self.bob, self.alice data_length = 16 - pg.generate_message(data=pg.decimal_to_bits(random.randint(0, 2 ** (data_length - 1)), data_length), - source=source, destination=destination) - pg.generate_message(data="", message_type=mb_ack.message_type, destination=source, source=destination) - - #self.save_protocol("address_two_participants_with_acks_and_types", pg) + pg.generate_message( + data=pg.decimal_to_bits( + random.randint(0, 2 ** (data_length - 1)), data_length + ), + source=source, + destination=destination, + ) + pg.generate_message( + data="", + message_type=mb_ack.message_type, + destination=source, + source=destination, + ) + + # self.save_protocol("address_two_participants_with_acks_and_types", pg) self.clear_message_types(pg.protocol.messages) ff = FormatFinder(pg.protocol.messages) @@ -261,10 +299,12 @@ def test_three_participants_with_ack(self): mb_ack.add_label(FieldType.Function.LENGTH, 8) mb_ack.add_label(FieldType.Function.DST_ADDRESS, 16) - pg = ProtocolGenerator([mb.message_type, mb_ack.message_type], - syncs_by_mt={mb.message_type: "0x9a7d", mb_ack.message_type: "0x9a7d"}, - preambles_by_mt={mb.message_type: "10" * 8, mb_ack.message_type: "10" * 8}, - participants=[alice, bob, carl]) + pg = ProtocolGenerator( + [mb.message_type, mb_ack.message_type], + syncs_by_mt={mb.message_type: "0x9a7d", mb_ack.message_type: "0x9a7d"}, + preambles_by_mt={mb.message_type: "10" * 8, mb_ack.message_type: "10" * 8}, + participants=[alice, bob, carl], + ) i = -1 while len(pg.protocol.messages) < 20: @@ -280,7 +320,9 @@ def test_three_participants_with_ack(self): pg.generate_message(data=data, source=source, destination=destination) if "ack" in (msg_type.name for msg_type in pg.protocol.message_types): - pg.generate_message(message_type=1, data="", source=destination, destination=source) + pg.generate_message( + message_type=1, data="", source=destination, destination=source + ) self.clear_message_types(pg.protocol.messages) ff = FormatFinder(pg.protocol.messages) @@ -290,9 +332,18 @@ def test_three_participants_with_ack(self): # Since there are ACKS in this protocol, the engine must be able to assign the correct participant addresses # IN CORRECT ORDER! - self.assertEqual(util.convert_numbers_to_hex_string(ff.known_participant_addresses[0]), "1337") - self.assertEqual(util.convert_numbers_to_hex_string(ff.known_participant_addresses[1]), "4711") - self.assertEqual(util.convert_numbers_to_hex_string(ff.known_participant_addresses[2]), "cafe") + self.assertEqual( + util.convert_numbers_to_hex_string(ff.known_participant_addresses[0]), + "1337", + ) + self.assertEqual( + util.convert_numbers_to_hex_string(ff.known_participant_addresses[1]), + "4711", + ) + self.assertEqual( + util.convert_numbers_to_hex_string(ff.known_participant_addresses[2]), + "cafe", + ) def test_protocol_with_acks_and_checksum(self): proto_file = get_path_for_data_file("ack_frames_with_crc.proto.xml") @@ -305,8 +356,14 @@ def test_protocol_with_acks_and_checksum(self): ff.known_participant_addresses.clear() ff.run() - self.assertEqual(util.convert_numbers_to_hex_string(ff.known_participant_addresses[0]), "1337") - self.assertEqual(util.convert_numbers_to_hex_string(ff.known_participant_addresses[1]), "4711") + self.assertEqual( + util.convert_numbers_to_hex_string(ff.known_participant_addresses[0]), + "1337", + ) + self.assertEqual( + util.convert_numbers_to_hex_string(ff.known_participant_addresses[1]), + "4711", + ) for mt in ff.message_types: preamble = mt.get_first_label_with_type(FieldType.Function.PREAMBLE) @@ -320,7 +377,9 @@ def test_protocol_with_acks_and_checksum(self): self.assertEqual(length.length, 8) def test_address_engine_performance(self): - ff, messages = self.get_format_finder_from_protocol_file("35_messages.proto.xml", return_messages=True) + ff, messages = self.get_format_finder_from_protocol_file( + "35_messages.proto.xml", return_messages=True + ) engine = AddressEngine(ff.hexvectors, ff.participant_indices) engine.find() @@ -340,15 +399,20 @@ def test_paper_example(self): protocol = ProtocolAnalyzer(None) protocol.messages.extend([msg1, msg2, msg3, msg4]) - #self.save_protocol("paper_example", protocol) + # self.save_protocol("paper_example", protocol) bitvectors = FormatFinder.get_bitvectors_from_messages(protocol.messages) hexvectors = FormatFinder.get_hexvectors(bitvectors) - address_engine = AddressEngine(hexvectors, participant_indices=[participants.index(msg.participant) for msg in - protocol.messages]) + address_engine = AddressEngine( + hexvectors, + participant_indices=[ + participants.index(msg.participant) for msg in protocol.messages + ], + ) def test_find_common_sub_sequence(self): from urh.cythonext import awre_util + str1 = "0612345678" str2 = "0756781234" @@ -365,6 +429,7 @@ def test_find_common_sub_sequence(self): def test_find_first_occurrence(self): from urh.cythonext import awre_util + str1 = "00" * 100 + "1234500012345" + "00" * 100 str2 = "12345" @@ -373,14 +438,20 @@ def test_find_first_occurrence(self): indices = awre_util.find_occurrences(seq1, seq2) self.assertEqual(len(indices), 2) index = indices[0] - self.assertEqual(str1[index:index + len(str2)], str2) + self.assertEqual(str1[index : index + len(str2)], str2) # Test with ignoring indices - indices = awre_util.find_occurrences(seq1, seq2, array("L", list(range(0, 205)))) + indices = awre_util.find_occurrences( + seq1, seq2, array("L", list(range(0, 205))) + ) self.assertEqual(len(indices), 1) # Test with ignoring indices - indices = awre_util.find_occurrences(seq1, seq2, array("L", list(range(0, 210)))) + indices = awre_util.find_occurrences( + seq1, seq2, array("L", list(range(0, 210))) + ) self.assertEqual(len(indices), 0) - self.assertEqual(awre_util.find_occurrences(seq1, np.ones(10, dtype=np.uint8)), []) + self.assertEqual( + awre_util.find_occurrences(seq1, np.ones(10, dtype=np.uint8)), [] + ) diff --git a/tests/awre/test_awre_preprocessing.py b/tests/awre/test_awre_preprocessing.py index 27fdd68d3f..66ce7d739f 100644 --- a/tests/awre/test_awre_preprocessing.py +++ b/tests/awre/test_awre_preprocessing.py @@ -17,14 +17,18 @@ def test_very_simple_sync_word_finding(self): preamble = "10101010" sync = "1101" - pg = self.build_protocol_generator(preamble_syncs=[(preamble, sync)], - num_messages=(20,), - data=(lambda i: 10 * i,)) + pg = self.build_protocol_generator( + preamble_syncs=[(preamble, sync)], + num_messages=(20,), + data=(lambda i: 10 * i,), + ) - preprocessor = Preprocessor([np.array(msg.plain_bits, dtype=np.uint8) for msg in pg.protocol.messages]) + preprocessor = Preprocessor( + [np.array(msg.plain_bits, dtype=np.uint8) for msg in pg.protocol.messages] + ) possible_syncs = preprocessor.find_possible_syncs() - #self.save_protocol("very_simple_sync_test", pg) + # self.save_protocol("very_simple_sync_test", pg) self.assertGreaterEqual(len(possible_syncs), 1) self.assertEqual(preprocessor.find_possible_syncs()[0], sync) @@ -32,68 +36,88 @@ def test_simple_sync_word_finding(self): preamble = "10101010" sync = "1001" - pg = self.build_protocol_generator(preamble_syncs=[(preamble, sync), (preamble + "1010", sync)], - num_messages=(20, 5), - data=(lambda i: 10 * i, lambda i: 22 * i)) + pg = self.build_protocol_generator( + preamble_syncs=[(preamble, sync), (preamble + "1010", sync)], + num_messages=(20, 5), + data=(lambda i: 10 * i, lambda i: 22 * i), + ) - preprocessor = Preprocessor([np.array(msg.plain_bits, dtype=np.uint8) for msg in pg.protocol.messages]) + preprocessor = Preprocessor( + [np.array(msg.plain_bits, dtype=np.uint8) for msg in pg.protocol.messages] + ) possible_syncs = preprocessor.find_possible_syncs() - #self.save_protocol("simple_sync_test", pg) + # self.save_protocol("simple_sync_test", pg) self.assertGreaterEqual(len(possible_syncs), 1) self.assertEqual(preprocessor.find_possible_syncs()[0], sync) def test_sync_word_finding_odd_preamble(self): preamble = "0101010" sync = "1101" - pg = self.build_protocol_generator(preamble_syncs=[(preamble, sync), (preamble + "10", sync)], - num_messages=(20, 5), - data=(lambda i: 10 * i, lambda i: i)) + pg = self.build_protocol_generator( + preamble_syncs=[(preamble, sync), (preamble + "10", sync)], + num_messages=(20, 5), + data=(lambda i: 10 * i, lambda i: i), + ) # If we have a odd preamble length, the last bit of the preamble is counted to the sync - preprocessor = Preprocessor([np.array(msg.plain_bits, dtype=np.uint8) for msg in pg.protocol.messages]) + preprocessor = Preprocessor( + [np.array(msg.plain_bits, dtype=np.uint8) for msg in pg.protocol.messages] + ) possible_syncs = preprocessor.find_possible_syncs() - #self.save_protocol("odd_preamble", pg) + # self.save_protocol("odd_preamble", pg) self.assertEqual(preamble[-1] + sync[:-1], possible_syncs[0]) def test_sync_word_finding_special_preamble(self): preamble = "111001110011100" sync = "0110" - pg = self.build_protocol_generator(preamble_syncs=[(preamble, sync), (preamble + "10", sync)], - num_messages=(20, 5), - data=(lambda i: 10 * i, lambda i: i)) + pg = self.build_protocol_generator( + preamble_syncs=[(preamble, sync), (preamble + "10", sync)], + num_messages=(20, 5), + data=(lambda i: 10 * i, lambda i: i), + ) # If we have a odd preamble length, the last bit of the preamble is counted to the sync - preprocessor = Preprocessor([np.array(msg.plain_bits, dtype=np.uint8) for msg in pg.protocol.messages]) + preprocessor = Preprocessor( + [np.array(msg.plain_bits, dtype=np.uint8) for msg in pg.protocol.messages] + ) possible_syncs = preprocessor.find_possible_syncs() - #self.save_protocol("special_preamble", pg) + # self.save_protocol("special_preamble", pg) self.assertEqual(sync, possible_syncs[0]) def test_sync_word_finding_errored_preamble(self): preamble = "00010101010" # first bits are wrong sync = "0110" - pg = self.build_protocol_generator(preamble_syncs=[(preamble, sync), (preamble + "10", sync)], - num_messages=(20, 5), - data=(lambda i: 10 * i, lambda i: i)) + pg = self.build_protocol_generator( + preamble_syncs=[(preamble, sync), (preamble + "10", sync)], + num_messages=(20, 5), + data=(lambda i: 10 * i, lambda i: i), + ) # If we have a odd preamble length, the last bit of the preamble is counted to the sync - preprocessor = Preprocessor([np.array(msg.plain_bits, dtype=np.uint8) for msg in pg.protocol.messages]) + preprocessor = Preprocessor( + [np.array(msg.plain_bits, dtype=np.uint8) for msg in pg.protocol.messages] + ) possible_syncs = preprocessor.find_possible_syncs() - #self.save_protocol("errored_preamble", pg) + # self.save_protocol("errored_preamble", pg) self.assertIn(preamble[-1] + sync[:-1], possible_syncs) def test_sync_word_finding_with_two_sync_words(self): preamble = "0xaaaa" sync1, sync2 = "0x1234", "0xcafe" - pg = self.build_protocol_generator(preamble_syncs=[(preamble, sync1), (preamble, sync2)], - num_messages=(15, 10), - data=(lambda i: 12 * i, lambda i: 16 * i)) - preprocessor = Preprocessor([np.array(msg.plain_bits, dtype=np.uint8) for msg in pg.protocol.messages]) + pg = self.build_protocol_generator( + preamble_syncs=[(preamble, sync1), (preamble, sync2)], + num_messages=(15, 10), + data=(lambda i: 12 * i, lambda i: 16 * i), + ) + preprocessor = Preprocessor( + [np.array(msg.plain_bits, dtype=np.uint8) for msg in pg.protocol.messages] + ) possible_syncs = preprocessor.find_possible_syncs() - #self.save_protocol("two_syncs", pg) + # self.save_protocol("two_syncs", pg) self.assertGreaterEqual(len(possible_syncs), 2) self.assertIn(ProtocolGenerator.to_bits(sync1), possible_syncs) self.assertIn(ProtocolGenerator.to_bits(sync2), possible_syncs) @@ -123,11 +147,15 @@ def test_multiple_sync_words(self): self.assertEqual(len(ff.message_types), 1, msg=sync) - preamble = ff.message_types[0].get_first_label_with_type(FieldType.Function.PREAMBLE) + preamble = ff.message_types[0].get_first_label_with_type( + FieldType.Function.PREAMBLE + ) self.assertEqual(preamble.start, 0, msg=sync) self.assertEqual(preamble.length, 8, msg=sync) - sync = ff.message_types[0].get_first_label_with_type(FieldType.Function.SYNC) + sync = ff.message_types[0].get_first_label_with_type( + FieldType.Function.SYNC + ) self.assertEqual(sync.start, 8, msg=sync) self.assertEqual(sync.length, 8, msg=sync) @@ -137,7 +165,7 @@ def test_sync_word_finding_varying_message_length(self): "aaaa9a7d4747111337000134a4473c002b909630b11df37e34728c79c60396176aff2b5384e82f31511581d0cbb4822ad1b6734e2372ad5cf4af4c9d6b067e5f7ec359ec443c3b5ddc7a9e", "aaaa9a7d0f13374711000205ee081d26c86b8c", "aaaa9a7d474711133700037cae4cda789885f88f5fb29adc9acf954cb2850b9d94e7f3b009347c466790e89f2bcd728987d4670690861bbaa120f71f14d4ef8dc738a6d7c30e7d2143c267", - "aaaa9a7d0f133747110004c2906142300427f3" + "aaaa9a7d0f133747110004c2906142300427f3", ] messages = [Message.from_plain_hex_str(hex_msg) for hex_msg in hex_messages] @@ -148,7 +176,9 @@ def test_sync_word_finding_varying_message_length(self): ff.run() self.assertEqual(len(ff.message_types), 1) - preamble = ff.message_types[0].get_first_label_with_type(FieldType.Function.PREAMBLE) + preamble = ff.message_types[0].get_first_label_with_type( + FieldType.Function.PREAMBLE + ) self.assertEqual(preamble.start, 0) self.assertEqual(preamble.length, 16) @@ -178,10 +208,12 @@ def test_sync_word_finding_common_prefix(self): mb.add_label(FieldType.Function.DST_ADDRESS, 24) mb.add_label(FieldType.Function.SEQUENCE_NUMBER, 16) - pg = ProtocolGenerator([mb.message_type], - syncs_by_mt={mb.message_type: "0x1337"}, - preambles_by_mt={mb.message_type: "10" * 36}, - participants=[alice, bob]) + pg = ProtocolGenerator( + [mb.message_type], + syncs_by_mt={mb.message_type: "0x1337"}, + preambles_by_mt={mb.message_type: "10" * 36}, + participants=[alice, bob], + ) random.seed(0) for i in range(num_messages): @@ -191,38 +223,59 @@ def test_sync_word_finding_common_prefix(self): else: source, destination = bob, alice data_length = 16 - pg.generate_message(data=pg.decimal_to_bits(random.randint(0, 2 ** (data_length - 1)), data_length), - source=source, destination=destination) - - preprocessor = Preprocessor([np.array(msg.plain_bits, dtype=np.uint8) for msg in pg.protocol.messages]) + pg.generate_message( + data=pg.decimal_to_bits( + random.randint(0, 2 ** (data_length - 1)), data_length + ), + source=source, + destination=destination, + ) + + preprocessor = Preprocessor( + [np.array(msg.plain_bits, dtype=np.uint8) for msg in pg.protocol.messages] + ) possible_syncs = preprocessor.find_possible_syncs() - #self.save_protocol("sync_by_common_prefix", pg) + # self.save_protocol("sync_by_common_prefix", pg) self.assertEqual(len(possible_syncs), 1) # +0000 is okay, because this will get fixed by correction in FormatFinder - self.assertIn(possible_syncs[0], [ProtocolGenerator.to_bits(sync), ProtocolGenerator.to_bits(sync) + "0000"]) + self.assertIn( + possible_syncs[0], + [ProtocolGenerator.to_bits(sync), ProtocolGenerator.to_bits(sync) + "0000"], + ) def test_with_given_preamble_and_sync(self): preamble = "10101010" sync = "10011" - pg = self.build_protocol_generator(preamble_syncs=[(preamble, sync)], - num_messages=(20,), - data=(lambda i: 10 * i,)) + pg = self.build_protocol_generator( + preamble_syncs=[(preamble, sync)], + num_messages=(20,), + data=(lambda i: 10 * i,), + ) # If we have a odd preamble length, the last bit of the preamble is counted to the sync - preprocessor = Preprocessor([np.array(msg.plain_bits, dtype=np.uint8) for msg in pg.protocol.messages], - existing_message_types={i: msg.message_type for i, msg in - enumerate(pg.protocol.messages)}) + preprocessor = Preprocessor( + [np.array(msg.plain_bits, dtype=np.uint8) for msg in pg.protocol.messages], + existing_message_types={ + i: msg.message_type for i, msg in enumerate(pg.protocol.messages) + }, + ) preamble_starts, preamble_lengths, sync_len = preprocessor.preprocess() - #self.save_protocol("given_preamble", pg) + # self.save_protocol("given_preamble", pg) self.assertTrue(all(preamble_start == 0 for preamble_start in preamble_starts)) - self.assertTrue(all(preamble_length == len(preamble) for preamble_length in preamble_lengths)) + self.assertTrue( + all( + preamble_length == len(preamble) for preamble_length in preamble_lengths + ) + ) self.assertEqual(sync_len, len(sync)) @staticmethod - def build_protocol_generator(preamble_syncs: list, num_messages: tuple, data: tuple) -> ProtocolGenerator: + def build_protocol_generator( + preamble_syncs: list, num_messages: tuple, data: tuple + ) -> ProtocolGenerator: message_types = [] preambles_by_mt = dict() syncs_by_mt = dict() @@ -243,7 +296,9 @@ def build_protocol_generator(preamble_syncs: list, num_messages: tuple, data: tu preambles_by_mt[mb.message_type] = preamble syncs_by_mt[mb.message_type] = sync_word - pg = ProtocolGenerator(message_types, preambles_by_mt=preambles_by_mt, syncs_by_mt=syncs_by_mt) + pg = ProtocolGenerator( + message_types, preambles_by_mt=preambles_by_mt, syncs_by_mt=syncs_by_mt + ) for i, msg_type in enumerate(message_types): for j in range(num_messages[i]): if callable(data[i]): diff --git a/tests/awre/test_awre_real_protocols.py b/tests/awre/test_awre_real_protocols.py index 944c5bc752..50fd7c1467 100644 --- a/tests/awre/test_awre_real_protocols.py +++ b/tests/awre/test_awre_real_protocols.py @@ -11,6 +11,7 @@ from urh.signalprocessing.ProtocolAnalyzer import ProtocolAnalyzer import numpy as np + class TestAWRERealProtocols(AWRETestCase): def setUp(self): super().setUp() @@ -22,8 +23,12 @@ def test_format_finding_enocean(self): enocean_protocol = ProtocolAnalyzer(None) with open(get_path_for_data_file("enocean_bits.txt")) as f: for line in f: - enocean_protocol.messages.append(Message.from_plain_bits_str(line.replace("\n", ""))) - enocean_protocol.messages[-1].message_type = enocean_protocol.default_message_type + enocean_protocol.messages.append( + Message.from_plain_bits_str(line.replace("\n", "")) + ) + enocean_protocol.messages[ + -1 + ].message_type = enocean_protocol.default_message_type ff = FormatFinder(enocean_protocol.messages) ff.perform_iteration() @@ -31,7 +36,9 @@ def test_format_finding_enocean(self): message_types = ff.message_types self.assertEqual(len(message_types), 1) - preamble = message_types[0].get_first_label_with_type(FieldType.Function.PREAMBLE) + preamble = message_types[0].get_first_label_with_type( + FieldType.Function.PREAMBLE + ) self.assertEqual(preamble.start, 0) self.assertEqual(preamble.length, 8) @@ -39,29 +46,54 @@ def test_format_finding_enocean(self): self.assertEqual(sync.start, 8) self.assertEqual(sync.length, 4) - checksum = message_types[0].get_first_label_with_type(FieldType.Function.CHECKSUM) + checksum = message_types[0].get_first_label_with_type( + FieldType.Function.CHECKSUM + ) self.assertEqual(checksum.start, 56) self.assertEqual(checksum.length, 4) - self.assertIsNone(message_types[0].get_first_label_with_type(FieldType.Function.SRC_ADDRESS)) - self.assertIsNone(message_types[0].get_first_label_with_type(FieldType.Function.DST_ADDRESS)) - self.assertIsNone(message_types[0].get_first_label_with_type(FieldType.Function.LENGTH)) - self.assertIsNone(message_types[0].get_first_label_with_type(FieldType.Function.SEQUENCE_NUMBER)) + self.assertIsNone( + message_types[0].get_first_label_with_type(FieldType.Function.SRC_ADDRESS) + ) + self.assertIsNone( + message_types[0].get_first_label_with_type(FieldType.Function.DST_ADDRESS) + ) + self.assertIsNone( + message_types[0].get_first_label_with_type(FieldType.Function.LENGTH) + ) + self.assertIsNone( + message_types[0].get_first_label_with_type( + FieldType.Function.SEQUENCE_NUMBER + ) + ) def test_format_finding_rwe(self): - ff, messages = self.get_format_finder_from_protocol_file("rwe.proto.xml", return_messages=True) + ff, messages = self.get_format_finder_from_protocol_file( + "rwe.proto.xml", return_messages=True + ) ff.run() sync1, sync2 = "0x9a7d9a7d", "0x67686768" - preprocessor = Preprocessor([np.array(msg.plain_bits, dtype=np.uint8) for msg in messages]) + preprocessor = Preprocessor( + [np.array(msg.plain_bits, dtype=np.uint8) for msg in messages] + ) possible_syncs = preprocessor.find_possible_syncs() self.assertIn(ProtocolGenerator.to_bits(sync1), possible_syncs) self.assertIn(ProtocolGenerator.to_bits(sync2), possible_syncs) ack_messages = (3, 5, 7, 9, 11, 13, 15, 17, 20) - ack_message_type = next(mt for mt, messages in ff.existing_message_types.items() if ack_messages[0] in messages) - self.assertTrue(all(ack_msg in ff.existing_message_types[ack_message_type] for ack_msg in ack_messages)) + ack_message_type = next( + mt + for mt, messages in ff.existing_message_types.items() + if ack_messages[0] in messages + ) + self.assertTrue( + all( + ack_msg in ff.existing_message_types[ack_message_type] + for ack_msg in ack_messages + ) + ) for mt in ff.message_types: preamble = mt.get_first_label_with_type(FieldType.Function.PREAMBLE) @@ -115,7 +147,9 @@ def test_homematic(self): self.assertGreater(len(ff.message_types), 0) for i, message_type in enumerate(ff.message_types): - preamble = message_type.get_first_label_with_type(FieldType.Function.PREAMBLE) + preamble = message_type.get_first_label_with_type( + FieldType.Function.PREAMBLE + ) self.assertEqual(preamble.start, 0) self.assertEqual(preamble.length, 32) @@ -127,7 +161,9 @@ def test_homematic(self): self.assertEqual(length.start, 64) self.assertEqual(length.length, 8) - seq = message_type.get_first_label_with_type(FieldType.Function.SEQUENCE_NUMBER) + seq = message_type.get_first_label_with_type( + FieldType.Function.SEQUENCE_NUMBER + ) self.assertEqual(seq.start, 72) self.assertEqual(seq.length, 8) @@ -139,11 +175,13 @@ def test_homematic(self): self.assertEqual(dst.start, 120) self.assertEqual(dst.length, 24) - checksum = message_type.get_first_label_with_type(FieldType.Function.CHECKSUM) + checksum = message_type.get_first_label_with_type( + FieldType.Function.CHECKSUM + ) self.assertEqual(checksum.length, 16) self.assertIn("CC1101", checksum.checksum.caption) for msg_index in ff.existing_message_types[message_type]: msg_len = len(protocol.messages[msg_index]) - self.assertEqual(checksum.start, msg_len-16) + self.assertEqual(checksum.start, msg_len - 16) self.assertEqual(checksum.end, msg_len) diff --git a/tests/awre/test_checksum_engine.py b/tests/awre/test_checksum_engine.py index 97cd31ebcd..505d43190f 100644 --- a/tests/awre/test_checksum_engine.py +++ b/tests/awre/test_checksum_engine.py @@ -13,10 +13,13 @@ from urh.util.GenericCRC import GenericCRC from urh.cythonext import util as c_util + class TestChecksumEngine(AWRETestCase): def test_find_crc8(self): messages = ["aabbcc7d", "abcdee24", "dacafe33"] - message_bits = [np.array(msg, dtype=np.uint8) for msg in map(util.hex2bit, messages)] + message_bits = [ + np.array(msg, dtype=np.uint8) for msg in map(util.hex2bit, messages) + ] checksum_engine = ChecksumEngine(message_bits, n_gram_length=8) result = checksum_engine.find() @@ -33,7 +36,9 @@ def test_find_crc8(self): def test_find_crc16(self): messages = ["12345678347B", "abcdefffABBD", "cafe1337CE12"] - message_bits = [np.array(msg, dtype=np.uint8) for msg in map(util.hex2bit, messages)] + message_bits = [ + np.array(msg, dtype=np.uint8) for msg in map(util.hex2bit, messages) + ] checksum_engine = ChecksumEngine(message_bits, n_gram_length=8) result = checksum_engine.find() @@ -50,7 +55,9 @@ def test_find_crc16(self): def test_find_crc32(self): messages = ["deadcafe5D7F3F5A", "47111337E3319242", "beefaffe0DCD0E15"] - message_bits = [np.array(msg, dtype=np.uint8) for msg in map(util.hex2bit, messages)] + message_bits = [ + np.array(msg, dtype=np.uint8) for msg in map(util.hex2bit, messages) + ] checksum_engine = ChecksumEngine(message_bits, n_gram_length=8) result = checksum_engine.find() @@ -81,15 +88,20 @@ def test_find_generated_crc16(self): mb2.add_checksum_label(16, GenericCRC.from_standard_checksum("CRC16 CCITT")) - pg = ProtocolGenerator([mb.message_type, mb2.message_type], syncs_by_mt={mb.message_type: "0x1234", mb2.message_type: "0x1234"}) + pg = ProtocolGenerator( + [mb.message_type, mb2.message_type], + syncs_by_mt={mb.message_type: "0x1234", mb2.message_type: "0x1234"}, + ) num_messages = 5 for i in range(num_messages): pg.generate_message(data="{0:032b}".format(i), message_type=mb.message_type) - pg.generate_message(data="{0:016b}".format(i), message_type=mb2.message_type) + pg.generate_message( + data="{0:016b}".format(i), message_type=mb2.message_type + ) - #self.save_protocol("crc16_test", pg) + # self.save_protocol("crc16_test", pg) self.clear_message_types(pg.protocol.messages) ff = FormatFinder(pg.protocol.messages) diff --git a/tests/awre/test_format_finder.py b/tests/awre/test_format_finder.py index 191bc74186..a674ecd778 100644 --- a/tests/awre/test_format_finder.py +++ b/tests/awre/test_format_finder.py @@ -44,14 +44,22 @@ def test_create_message_types_2(self): def test_retransform_message_indices(self): sync_ends = np.array([12, 12, 12, 14, 14]) - rng = CommonRange(0, 8, "1" * 8, score=1, field_type="length", message_indices={0, 1, 2, 3, 4}) - retransformed_ranges = FormatFinder.retransform_message_indices([rng], [0, 1, 2, 3, 4], sync_ends) + rng = CommonRange( + 0, 8, "1" * 8, score=1, field_type="length", message_indices={0, 1, 2, 3, 4} + ) + retransformed_ranges = FormatFinder.retransform_message_indices( + [rng], [0, 1, 2, 3, 4], sync_ends + ) # two different sync ends self.assertEqual(len(retransformed_ranges), 2) - expected1 = CommonRange(12, 8, "1" * 8, score=1, field_type="length", message_indices={0, 1, 2}) - expected2 = CommonRange(14, 8, "1" * 8, score=1, field_type="length", message_indices={3, 4}) + expected1 = CommonRange( + 12, 8, "1" * 8, score=1, field_type="length", message_indices={0, 1, 2} + ) + expected2 = CommonRange( + 14, 8, "1" * 8, score=1, field_type="length", message_indices={3, 4} + ) self.assertIn(expected1, retransformed_ranges) self.assertIn(expected2, retransformed_ranges) diff --git a/tests/awre/test_generated_protocols.py b/tests/awre/test_generated_protocols.py index 0aa055b747..4f0d3f6e14 100644 --- a/tests/awre/test_generated_protocols.py +++ b/tests/awre/test_generated_protocols.py @@ -32,9 +32,16 @@ def __check_addresses(self, messages, format_finder, known_participant_addresses AutoAssigner.auto_assign_participant_addresses(messages, participants) for i in range(len(participants)): - self.assertIn(participants[i].address_hex, - list(map(util.convert_numbers_to_hex_string, known_participant_addresses.values())), - msg=" [ " + " ".join(p.address_hex for p in participants) + " ]") + self.assertIn( + participants[i].address_hex, + list( + map( + util.convert_numbers_to_hex_string, + known_participant_addresses.values(), + ) + ), + msg=" [ " + " ".join(p.address_hex for p in participants) + " ]", + ) def test_without_preamble(self): alice = Participant("Alice", address_hex="24") @@ -46,18 +53,22 @@ def test_without_preamble(self): mb.add_label(FieldType.Function.SRC_ADDRESS, 8) mb.add_label(FieldType.Function.SEQUENCE_NUMBER, 8) - pg = ProtocolGenerator([mb.message_type], - syncs_by_mt={mb.message_type: "0x8e88"}, - preambles_by_mt={mb.message_type: "10" * 8}, - participants=[alice, broadcast]) + pg = ProtocolGenerator( + [mb.message_type], + syncs_by_mt={mb.message_type: "0x8e88"}, + preambles_by_mt={mb.message_type: "10" * 8}, + participants=[alice, broadcast], + ) for i in range(20): data_bits = 16 if i % 2 == 0 else 32 source = pg.participants[i % 2] destination = pg.participants[(i + 1) % 2] - pg.generate_message(data="1010" * (data_bits // 4), source=source, destination=destination) + pg.generate_message( + data="1010" * (data_bits // 4), source=source, destination=destination + ) - #self.save_protocol("without_preamble", pg) + # self.save_protocol("without_preamble", pg) self.clear_message_types(pg.messages) ff = FormatFinder(pg.messages) ff.known_participant_addresses.clear() @@ -83,7 +94,9 @@ def test_without_preamble(self): self.assertEqual(seq.length, 8) def test_without_preamble_random_data(self): - ff = self.get_format_finder_from_protocol_file("without_ack_random_data.proto.xml") + ff = self.get_format_finder_from_protocol_file( + "without_ack_random_data.proto.xml" + ) ff.run() self.assertEqual(len(ff.message_types), 1) @@ -106,7 +119,9 @@ def test_without_preamble_random_data(self): self.assertEqual(seq.length, 8) def test_without_preamble_random_data2(self): - ff = self.get_format_finder_from_protocol_file("without_ack_random_data2.proto.xml") + ff = self.get_format_finder_from_protocol_file( + "without_ack_random_data2.proto.xml" + ) ff.run() self.assertEqual(len(ff.message_types), 1) @@ -129,34 +144,48 @@ def test_without_preamble_random_data2(self): self.assertEqual(seq.length, 8) def test_with_checksum(self): - ff = self.get_format_finder_from_protocol_file("with_checksum.proto.xml", clear_participant_addresses=False) + ff = self.get_format_finder_from_protocol_file( + "with_checksum.proto.xml", clear_participant_addresses=False + ) known_participant_addresses = ff.known_participant_addresses.copy() ff.known_participant_addresses.clear() ff.run() - self.assertIn(known_participant_addresses[0].tostring(), - list(map(bytes, ff.known_participant_addresses.values()))) - self.assertIn(known_participant_addresses[1].tostring(), - list(map(bytes, ff.known_participant_addresses.values()))) + self.assertIn( + known_participant_addresses[0].tostring(), + list(map(bytes, ff.known_participant_addresses.values())), + ) + self.assertIn( + known_participant_addresses[1].tostring(), + list(map(bytes, ff.known_participant_addresses.values())), + ) self.assertEqual(len(ff.message_types), 3) def test_with_only_one_address(self): - ff = self.get_format_finder_from_protocol_file("only_one_address.proto.xml", clear_participant_addresses=False) + ff = self.get_format_finder_from_protocol_file( + "only_one_address.proto.xml", clear_participant_addresses=False + ) known_participant_addresses = ff.known_participant_addresses.copy() ff.known_participant_addresses.clear() ff.run() - self.assertIn(known_participant_addresses[0].tostring(), - list(map(bytes, ff.known_participant_addresses.values()))) - self.assertIn(known_participant_addresses[1].tostring(), - list(map(bytes, ff.known_participant_addresses.values()))) + self.assertIn( + known_participant_addresses[0].tostring(), + list(map(bytes, ff.known_participant_addresses.values())), + ) + self.assertIn( + known_participant_addresses[1].tostring(), + list(map(bytes, ff.known_participant_addresses.values())), + ) def test_with_four_broken(self): - ff, messages = self.get_format_finder_from_protocol_file("four_broken.proto.xml", - clear_participant_addresses=False, - return_messages=True) + ff, messages = self.get_format_finder_from_protocol_file( + "four_broken.proto.xml", + clear_participant_addresses=False, + return_messages=True, + ) assert isinstance(ff, FormatFinder) known_participant_addresses = ff.known_participant_addresses.copy() @@ -167,13 +196,19 @@ def test_with_four_broken(self): self.__check_addresses(messages, ff, known_participant_addresses) for i in range(4, len(messages)): - mt = next(mt for mt, indices in ff.existing_message_types.items() if i in indices) - self.assertIsNotNone(mt.get_first_label_with_type(FieldType.Function.SEQUENCE_NUMBER)) + mt = next( + mt for mt, indices in ff.existing_message_types.items() if i in indices + ) + self.assertIsNotNone( + mt.get_first_label_with_type(FieldType.Function.SEQUENCE_NUMBER) + ) def test_with_one_address_one_message_type(self): - ff, messages = self.get_format_finder_from_protocol_file("one_address_one_mt.proto.xml", - clear_participant_addresses=False, - return_messages=True) + ff, messages = self.get_format_finder_from_protocol_file( + "one_address_one_mt.proto.xml", + clear_participant_addresses=False, + return_messages=True, + ) self.assertEqual(len(messages), 17) self.assertEqual(len(ff.hexvectors), 17) @@ -185,15 +220,21 @@ def test_with_one_address_one_message_type(self): self.assertEqual(len(ff.message_types), 1) - self.assertIn(known_participant_addresses[0].tostring(), - list(map(bytes, ff.known_participant_addresses.values()))) - self.assertIn(known_participant_addresses[1].tostring(), - list(map(bytes, ff.known_participant_addresses.values()))) + self.assertIn( + known_participant_addresses[0].tostring(), + list(map(bytes, ff.known_participant_addresses.values())), + ) + self.assertIn( + known_participant_addresses[1].tostring(), + list(map(bytes, ff.known_participant_addresses.values())), + ) def test_without_preamble_24_messages(self): - ff, messages = self.get_format_finder_from_protocol_file("no_preamble24.proto.xml", - clear_participant_addresses=False, - return_messages=True) + ff, messages = self.get_format_finder_from_protocol_file( + "no_preamble24.proto.xml", + clear_participant_addresses=False, + return_messages=True, + ) known_participant_addresses = ff.known_participant_addresses.copy() ff.known_participant_addresses.clear() @@ -202,13 +243,19 @@ def test_without_preamble_24_messages(self): self.assertEqual(len(ff.message_types), 1) - self.assertIn(known_participant_addresses[0].tostring(), - list(map(bytes, ff.known_participant_addresses.values()))) - self.assertIn(known_participant_addresses[1].tostring(), - list(map(bytes, ff.known_participant_addresses.values()))) + self.assertIn( + known_participant_addresses[0].tostring(), + list(map(bytes, ff.known_participant_addresses.values())), + ) + self.assertIn( + known_participant_addresses[1].tostring(), + list(map(bytes, ff.known_participant_addresses.values())), + ) def test_with_three_syncs_different_preamble_lengths(self): - ff, messages = self.get_format_finder_from_protocol_file("three_syncs.proto.xml", return_messages=True) + ff, messages = self.get_format_finder_from_protocol_file( + "three_syncs.proto.xml", return_messages=True + ) preprocessor = Preprocessor(ff.get_bitvectors_from_messages(messages)) sync_words = preprocessor.find_possible_syncs() self.assertIn("0000010000100000", sync_words, msg="Sync 1") @@ -217,15 +264,34 @@ def test_with_three_syncs_different_preamble_lengths(self): ff.run() - expected_sync_ends = [32, 24, 40, 24, 32, 24, 40, 24, 32, 24, 40, 24, 32, 24, 40, 24] + expected_sync_ends = [ + 32, + 24, + 40, + 24, + 32, + 24, + 40, + 24, + 32, + 24, + 40, + 24, + 32, + 24, + 40, + 24, + ] for i, (s1, s2) in enumerate(zip(expected_sync_ends, ff.sync_ends)): self.assertEqual(s1, s2, msg=str(i)) def test_with_four_participants(self): - ff, messages = self.get_format_finder_from_protocol_file("four_participants.proto.xml", - clear_participant_addresses=False, - return_messages=True) + ff, messages = self.get_format_finder_from_protocol_file( + "four_participants.proto.xml", + clear_participant_addresses=False, + return_messages=True, + ) known_participant_addresses = ff.known_participant_addresses.copy() ff.known_participant_addresses.clear() diff --git a/tests/awre/test_length_engine.py b/tests/awre/test_length_engine.py index 435a19e87f..87e1255a71 100644 --- a/tests/awre/test_length_engine.py +++ b/tests/awre/test_length_engine.py @@ -23,14 +23,19 @@ def test_simple_protocol(self): mb.add_label(FieldType.Function.LENGTH, 8) num_messages_by_data_length = {8: 5, 16: 10, 32: 15} - pg = ProtocolGenerator([mb.message_type], - syncs_by_mt={mb.message_type: "0x9a9d"}) + pg = ProtocolGenerator( + [mb.message_type], syncs_by_mt={mb.message_type: "0x9a9d"} + ) random.seed(0) for data_length, num_messages in num_messages_by_data_length.items(): for i in range(num_messages): - pg.generate_message(data="".join([random.choice(["0", "1"]) for _ in range(data_length)])) + pg.generate_message( + data="".join( + [random.choice(["0", "1"]) for _ in range(data_length)] + ) + ) - #self.save_protocol("simple_length", pg) + # self.save_protocol("simple_length", pg) self.clear_message_types(pg.protocol.messages) ff = FormatFinder(pg.protocol.messages) @@ -59,9 +64,11 @@ def test_easy_protocol(self): mb.add_label(FieldType.Function.SEQUENCE_NUMBER, 8) num_messages_by_data_length = {32: 10, 64: 15, 16: 5, 24: 7} - pg = ProtocolGenerator([mb.message_type], - preambles_by_mt={mb.message_type: "10" * 8}, - syncs_by_mt={mb.message_type: "0xcafe"}) + pg = ProtocolGenerator( + [mb.message_type], + preambles_by_mt={mb.message_type: "10" * 8}, + syncs_by_mt={mb.message_type: "0xcafe"}, + ) for data_length, num_messages in num_messages_by_data_length.items(): for i in range(num_messages): if i % 4 == 0: @@ -75,7 +82,7 @@ def test_easy_protocol(self): pg.generate_message(data=data) - #self.save_protocol("easy_length", pg) + # self.save_protocol("easy_length", pg) self.clear_message_types(pg.protocol.messages) ff = FormatFinder(pg.protocol.messages) @@ -108,16 +115,20 @@ def test_medium_protocol(self): mb2.add_label(FieldType.Function.PREAMBLE, 8) mb2.add_label(FieldType.Function.SYNC, 8) - pg = ProtocolGenerator([mb1.message_type, mb2.message_type], - syncs_by_mt={mb1.message_type: "11110011", - mb2.message_type: "11110011"}) + pg = ProtocolGenerator( + [mb1.message_type, mb2.message_type], + syncs_by_mt={mb1.message_type: "11110011", mb2.message_type: "11110011"}, + ) num_messages_by_data_length = {8: 5, 16: 10, 32: 5} for data_length, num_messages in num_messages_by_data_length.items(): for i in range(num_messages): - pg.generate_message(data=pg.decimal_to_bits(10 * i, data_length), message_type=mb1.message_type) + pg.generate_message( + data=pg.decimal_to_bits(10 * i, data_length), + message_type=mb1.message_type, + ) pg.generate_message(message_type=mb2.message_type, data="0xaf") - #self.save_protocol("medium_length", pg) + # self.save_protocol("medium_length", pg) self.clear_message_types(pg.protocol.messages) ff = FormatFinder(pg.protocol.messages) @@ -125,7 +136,10 @@ def test_medium_protocol(self): ff.perform_iteration() self.assertEqual(len(ff.message_types), 2) length_mt = next( - mt for mt in ff.message_types if mt.get_first_label_with_type(FieldType.Function.LENGTH) is not None) + mt + for mt in ff.message_types + if mt.get_first_label_with_type(FieldType.Function.LENGTH) is not None + ) length_label = length_mt.get_first_label_with_type(FieldType.Function.LENGTH) for i, sync_end in enumerate(ff.sync_ends): @@ -140,17 +154,23 @@ def test_little_endian_16_bit(self): mb.add_label(FieldType.Function.SYNC, 16) mb.add_label(FieldType.Function.LENGTH, 16) - num_messages_by_data_length = {256*8: 5, 16: 4, 512: 2} - pg = ProtocolGenerator([mb.message_type], - syncs_by_mt={mb.message_type: "0x9a9d"}, - little_endian=True) + num_messages_by_data_length = {256 * 8: 5, 16: 4, 512: 2} + pg = ProtocolGenerator( + [mb.message_type], + syncs_by_mt={mb.message_type: "0x9a9d"}, + little_endian=True, + ) random.seed(0) for data_length, num_messages in num_messages_by_data_length.items(): for i in range(num_messages): - pg.generate_message(data="".join([random.choice(["0", "1"]) for _ in range(data_length)])) + pg.generate_message( + data="".join( + [random.choice(["0", "1"]) for _ in range(data_length)] + ) + ) - #self.save_protocol("little_endian_16_length_test", pg) + # self.save_protocol("little_endian_16_length_test", pg) self.clear_message_types(pg.protocol.messages) ff = FormatFinder(pg.protocol.messages) diff --git a/tests/awre/test_partially_labeled.py b/tests/awre/test_partially_labeled.py index cf8c459bff..cf2a571d29 100644 --- a/tests/awre/test_partially_labeled.py +++ b/tests/awre/test_partially_labeled.py @@ -19,6 +19,7 @@ class TestPartiallyLabeled(AWRETestCase): Some tests if there are already information about the message types present """ + def test_fully_labeled(self): """ For fully labeled protocol, nothing should be done @@ -26,7 +27,9 @@ def test_fully_labeled(self): :return: """ protocol = self.__prepare_example_protocol() - message_types = sorted(copy.deepcopy(protocol.message_types), key=lambda x: x.name) + message_types = sorted( + copy.deepcopy(protocol.message_types), key=lambda x: x.name + ) ff = FormatFinder(protocol.messages) ff.perform_iteration() self.assertEqual(len(message_types), len(ff.message_types)) @@ -65,16 +68,44 @@ def test_given_address_information(self): ff.perform_iteration() self.assertEqual(2, len(ff.message_types)) - self.assertIsNotNone(ff.message_types[0].get_first_label_with_type(FieldType.Function.PREAMBLE)) - self.assertIsNotNone(ff.message_types[1].get_first_label_with_type(FieldType.Function.PREAMBLE)) - self.assertIsNotNone(ff.message_types[0].get_first_label_with_type(FieldType.Function.SYNC)) - self.assertIsNotNone(ff.message_types[1].get_first_label_with_type(FieldType.Function.SYNC)) - self.assertIsNotNone(ff.message_types[0].get_first_label_with_type(FieldType.Function.LENGTH)) - self.assertIsNotNone(ff.message_types[1].get_first_label_with_type(FieldType.Function.LENGTH)) - self.assertIsNotNone(ff.message_types[0].get_first_label_with_type(FieldType.Function.DST_ADDRESS)) - self.assertIsNotNone(ff.message_types[1].get_first_label_with_type(FieldType.Function.DST_ADDRESS)) - self.assertIsNone(ff.message_types[0].get_first_label_with_type(FieldType.Function.SRC_ADDRESS)) - self.assertIsNotNone(ff.message_types[1].get_first_label_with_type(FieldType.Function.SRC_ADDRESS)) + self.assertIsNotNone( + ff.message_types[0].get_first_label_with_type(FieldType.Function.PREAMBLE) + ) + self.assertIsNotNone( + ff.message_types[1].get_first_label_with_type(FieldType.Function.PREAMBLE) + ) + self.assertIsNotNone( + ff.message_types[0].get_first_label_with_type(FieldType.Function.SYNC) + ) + self.assertIsNotNone( + ff.message_types[1].get_first_label_with_type(FieldType.Function.SYNC) + ) + self.assertIsNotNone( + ff.message_types[0].get_first_label_with_type(FieldType.Function.LENGTH) + ) + self.assertIsNotNone( + ff.message_types[1].get_first_label_with_type(FieldType.Function.LENGTH) + ) + self.assertIsNotNone( + ff.message_types[0].get_first_label_with_type( + FieldType.Function.DST_ADDRESS + ) + ) + self.assertIsNotNone( + ff.message_types[1].get_first_label_with_type( + FieldType.Function.DST_ADDRESS + ) + ) + self.assertIsNone( + ff.message_types[0].get_first_label_with_type( + FieldType.Function.SRC_ADDRESS + ) + ) + self.assertIsNotNone( + ff.message_types[1].get_first_label_with_type( + FieldType.Function.SRC_ADDRESS + ) + ) def test_type_part_already_labeled(self): protocol = self.__prepare_simple_example_protocol() @@ -86,11 +117,25 @@ def test_type_part_already_labeled(self): ff.perform_iteration() self.assertEqual(1, len(ff.message_types)) - self.assertIsNotNone(ff.message_types[0].get_first_label_with_type(FieldType.Function.PREAMBLE)) - self.assertIsNotNone(ff.message_types[0].get_first_label_with_type(FieldType.Function.SYNC)) - self.assertIsNotNone(ff.message_types[0].get_first_label_with_type(FieldType.Function.LENGTH)) - self.assertIsNotNone(ff.message_types[0].get_first_label_with_type(FieldType.Function.DST_ADDRESS)) - self.assertIsNotNone(ff.message_types[0].get_first_label_with_type(FieldType.Function.SRC_ADDRESS)) + self.assertIsNotNone( + ff.message_types[0].get_first_label_with_type(FieldType.Function.PREAMBLE) + ) + self.assertIsNotNone( + ff.message_types[0].get_first_label_with_type(FieldType.Function.SYNC) + ) + self.assertIsNotNone( + ff.message_types[0].get_first_label_with_type(FieldType.Function.LENGTH) + ) + self.assertIsNotNone( + ff.message_types[0].get_first_label_with_type( + FieldType.Function.DST_ADDRESS + ) + ) + self.assertIsNotNone( + ff.message_types[0].get_first_label_with_type( + FieldType.Function.SRC_ADDRESS + ) + ) def test_length_part_already_labeled(self): protocol = self.__prepare_simple_example_protocol() @@ -102,11 +147,25 @@ def test_length_part_already_labeled(self): ff.perform_iteration() self.assertEqual(1, len(ff.message_types)) - self.assertIsNotNone(ff.message_types[0].get_first_label_with_type(FieldType.Function.PREAMBLE)) - self.assertIsNotNone(ff.message_types[0].get_first_label_with_type(FieldType.Function.SYNC)) - self.assertIsNone(ff.message_types[0].get_first_label_with_type(FieldType.Function.LENGTH)) - self.assertIsNotNone(ff.message_types[0].get_first_label_with_type(FieldType.Function.DST_ADDRESS)) - self.assertIsNotNone(ff.message_types[0].get_first_label_with_type(FieldType.Function.SRC_ADDRESS)) + self.assertIsNotNone( + ff.message_types[0].get_first_label_with_type(FieldType.Function.PREAMBLE) + ) + self.assertIsNotNone( + ff.message_types[0].get_first_label_with_type(FieldType.Function.SYNC) + ) + self.assertIsNone( + ff.message_types[0].get_first_label_with_type(FieldType.Function.LENGTH) + ) + self.assertIsNotNone( + ff.message_types[0].get_first_label_with_type( + FieldType.Function.DST_ADDRESS + ) + ) + self.assertIsNotNone( + ff.message_types[0].get_first_label_with_type( + FieldType.Function.SRC_ADDRESS + ) + ) def test_address_part_already_labeled(self): protocol = self.__prepare_simple_example_protocol() @@ -118,11 +177,25 @@ def test_address_part_already_labeled(self): ff.perform_iteration() self.assertEqual(1, len(ff.message_types)) - self.assertIsNotNone(ff.message_types[0].get_first_label_with_type(FieldType.Function.PREAMBLE)) - self.assertIsNotNone(ff.message_types[0].get_first_label_with_type(FieldType.Function.SYNC)) - self.assertIsNotNone(ff.message_types[0].get_first_label_with_type(FieldType.Function.LENGTH)) - self.assertIsNone(ff.message_types[0].get_first_label_with_type(FieldType.Function.DST_ADDRESS)) - self.assertIsNotNone(ff.message_types[0].get_first_label_with_type(FieldType.Function.SRC_ADDRESS)) + self.assertIsNotNone( + ff.message_types[0].get_first_label_with_type(FieldType.Function.PREAMBLE) + ) + self.assertIsNotNone( + ff.message_types[0].get_first_label_with_type(FieldType.Function.SYNC) + ) + self.assertIsNotNone( + ff.message_types[0].get_first_label_with_type(FieldType.Function.LENGTH) + ) + self.assertIsNone( + ff.message_types[0].get_first_label_with_type( + FieldType.Function.DST_ADDRESS + ) + ) + self.assertIsNotNone( + ff.message_types[0].get_first_label_with_type( + FieldType.Function.SRC_ADDRESS + ) + ) @staticmethod def __message_types_have_same_labels(mt1: MessageType, mt2: MessageType): @@ -154,9 +227,11 @@ def __prepare_example_protocol(self) -> ProtocolAnalyzer: num_messages = 50 - pg = ProtocolGenerator([mb.message_type, mb_ack.message_type], - syncs_by_mt={mb.message_type: "0x6768", mb_ack.message_type: "0x6768"}, - participants=[alice, bob]) + pg = ProtocolGenerator( + [mb.message_type, mb_ack.message_type], + syncs_by_mt={mb.message_type: "0x6768", mb_ack.message_type: "0x6768"}, + participants=[alice, bob], + ) random.seed(0) for i in range(num_messages): @@ -166,11 +241,21 @@ def __prepare_example_protocol(self) -> ProtocolAnalyzer: else: source, destination = bob, alice data_length = 16 - pg.generate_message(data=pg.decimal_to_bits(random.randint(0, 2 ** (data_length - 1)), data_length), - source=source, destination=destination) - pg.generate_message(data="", message_type=mb_ack.message_type, destination=source, source=destination) - - #self.save_protocol("labeled_protocol", pg) + pg.generate_message( + data=pg.decimal_to_bits( + random.randint(0, 2 ** (data_length - 1)), data_length + ), + source=source, + destination=destination, + ) + pg.generate_message( + data="", + message_type=mb_ack.message_type, + destination=source, + source=destination, + ) + + # self.save_protocol("labeled_protocol", pg) return pg.protocol @@ -187,12 +272,22 @@ def __prepare_simple_example_protocol(self): mb.add_label(FieldType.Function.DST_ADDRESS, 16) mb.add_label(FieldType.Function.SRC_ADDRESS, 16) - pg = ProtocolGenerator([mb.message_type], - syncs_by_mt={mb.message_type: "0x6768"}, - participants=[alice, bob]) + pg = ProtocolGenerator( + [mb.message_type], + syncs_by_mt={mb.message_type: "0x6768"}, + participants=[alice, bob], + ) for i in range(10): - pg.generate_message(data="".join([random.choice(["0", "1"]) for _ in range(16)]), source=alice, destination=bob) - pg.generate_message(data="".join([random.choice(["0", "1"]) for _ in range(8)]), source=bob, destination=alice) + pg.generate_message( + data="".join([random.choice(["0", "1"]) for _ in range(16)]), + source=alice, + destination=bob, + ) + pg.generate_message( + data="".join([random.choice(["0", "1"]) for _ in range(8)]), + source=bob, + destination=alice, + ) return pg.protocol diff --git a/tests/awre/test_sequence_number_engine.py b/tests/awre/test_sequence_number_engine.py index 6b02e9535b..5084ee35cb 100644 --- a/tests/awre/test_sequence_number_engine.py +++ b/tests/awre/test_sequence_number_engine.py @@ -23,13 +23,14 @@ def test_simple_protocol(self): num_messages = 20 - pg = ProtocolGenerator([mb.message_type], - syncs_by_mt={mb.message_type: "0x9a9d"}) + pg = ProtocolGenerator( + [mb.message_type], syncs_by_mt={mb.message_type: "0x9a9d"} + ) for i in range(num_messages): pg.generate_message(data="0xcafe") - #self.save_protocol("simple_sequence_number", pg) + # self.save_protocol("simple_sequence_number", pg) self.clear_message_types(pg.protocol.messages) ff = FormatFinder(pg.protocol.messages) @@ -41,8 +42,15 @@ def test_simple_protocol(self): ff.perform_iteration() self.assertEqual(len(ff.message_types), 1) self.assertGreater(len(ff.message_types[0]), 0) - self.assertEqual(ff.message_types[0].num_labels_with_type(FieldType.Function.SEQUENCE_NUMBER), 1) - label = ff.message_types[0].get_first_label_with_type(FieldType.Function.SEQUENCE_NUMBER) + self.assertEqual( + ff.message_types[0].num_labels_with_type( + FieldType.Function.SEQUENCE_NUMBER + ), + 1, + ) + label = ff.message_types[0].get_first_label_with_type( + FieldType.Function.SEQUENCE_NUMBER + ) self.assertEqual(label.start, 24) self.assertEqual(label.length, 8) @@ -54,15 +62,20 @@ def test_16bit_seq_nr(self): num_messages = 10 - pg = ProtocolGenerator([mb.message_type], - syncs_by_mt={mb.message_type: "0x9a9d"}, sequence_number_increment=64) + pg = ProtocolGenerator( + [mb.message_type], + syncs_by_mt={mb.message_type: "0x9a9d"}, + sequence_number_increment=64, + ) for i in range(num_messages): pg.generate_message(data="0xcafe") - #self.save_protocol("16bit_seq", pg) + # self.save_protocol("16bit_seq", pg) - bitvectors = FormatFinder.get_bitvectors_from_messages(pg.protocol.messages, sync_ends=[24]*num_messages) + bitvectors = FormatFinder.get_bitvectors_from_messages( + pg.protocol.messages, sync_ends=[24] * num_messages + ) seq_engine = SequenceNumberEngine(bitvectors, n_gram_length=8) highscored_ranges = seq_engine.find() self.assertEqual(len(highscored_ranges), 1) @@ -73,8 +86,15 @@ def test_16bit_seq_nr(self): self.assertEqual(len(ff.message_types), 1) self.assertGreater(len(ff.message_types[0]), 0) - self.assertEqual(ff.message_types[0].num_labels_with_type(FieldType.Function.SEQUENCE_NUMBER), 1) - label = ff.message_types[0].get_first_label_with_type(FieldType.Function.SEQUENCE_NUMBER) + self.assertEqual( + ff.message_types[0].num_labels_with_type( + FieldType.Function.SEQUENCE_NUMBER + ), + 1, + ) + label = ff.message_types[0].get_first_label_with_type( + FieldType.Function.SEQUENCE_NUMBER + ) self.assertEqual(label.start, 24) self.assertEqual(label.length, 16) @@ -87,15 +107,20 @@ def test_16bit_seq_nr_with_zeros_in_first_part(self): num_messages = 10 - pg = ProtocolGenerator([mb.message_type], - syncs_by_mt={mb.message_type: "0x9a9d"}, sequence_number_increment=1) + pg = ProtocolGenerator( + [mb.message_type], + syncs_by_mt={mb.message_type: "0x9a9d"}, + sequence_number_increment=1, + ) for i in range(num_messages): pg.generate_message(data="0xcafe" + "abc" * i) - #self.save_protocol("16bit_seq_first_byte_zero_test", pg) + # self.save_protocol("16bit_seq_first_byte_zero_test", pg) - bitvectors = FormatFinder.get_bitvectors_from_messages(pg.protocol.messages, sync_ends=[24]*num_messages) + bitvectors = FormatFinder.get_bitvectors_from_messages( + pg.protocol.messages, sync_ends=[24] * num_messages + ) seq_engine = SequenceNumberEngine(bitvectors, n_gram_length=8) highscored_ranges = seq_engine.find() self.assertEqual(len(highscored_ranges), 1) @@ -105,8 +130,15 @@ def test_16bit_seq_nr_with_zeros_in_first_part(self): ff.perform_iteration() self.assertEqual(len(ff.message_types), 1) self.assertGreater(len(ff.message_types[0]), 0) - self.assertEqual(ff.message_types[0].num_labels_with_type(FieldType.Function.SEQUENCE_NUMBER), 1) - label = ff.message_types[0].get_first_label_with_type(FieldType.Function.SEQUENCE_NUMBER) + self.assertEqual( + ff.message_types[0].num_labels_with_type( + FieldType.Function.SEQUENCE_NUMBER + ), + 1, + ) + label = ff.message_types[0].get_first_label_with_type( + FieldType.Function.SEQUENCE_NUMBER + ) # Not consider constants as part of SEQ Nr! self.assertEqual(label.start, 40) @@ -130,9 +162,11 @@ def test_no_sequence_number(self): num_messages = 3 - pg = ProtocolGenerator([mb.message_type], - syncs_by_mt={mb.message_type: "0x1337"}, - participants=[alice, bob]) + pg = ProtocolGenerator( + [mb.message_type], + syncs_by_mt={mb.message_type: "0x1337"}, + participants=[alice, bob], + ) for i in range(num_messages): if i % 2 == 0: @@ -141,7 +175,7 @@ def test_no_sequence_number(self): source, destination = bob, alice pg.generate_message(data="", source=source, destination=destination) - #self.save_protocol("protocol_1", pg) + # self.save_protocol("protocol_1", pg) # Delete message type information -> no prior knowledge self.clear_message_types(pg.protocol.messages) @@ -152,7 +186,12 @@ def test_no_sequence_number(self): self.assertEqual(len(ff.message_types), 1) - self.assertEqual(ff.message_types[0].num_labels_with_type(FieldType.Function.SEQUENCE_NUMBER), 0) + self.assertEqual( + ff.message_types[0].num_labels_with_type( + FieldType.Function.SEQUENCE_NUMBER + ), + 0, + ) def test_sequence_number_little_endian_16_bit(self): mb = MessageTypeBuilder("16bit_seq_test") @@ -162,21 +201,31 @@ def test_sequence_number_little_endian_16_bit(self): num_messages = 8 - pg = ProtocolGenerator([mb.message_type], - syncs_by_mt={mb.message_type: "0x9a9d"}, - little_endian=True, sequence_number_increment=64) + pg = ProtocolGenerator( + [mb.message_type], + syncs_by_mt={mb.message_type: "0x9a9d"}, + little_endian=True, + sequence_number_increment=64, + ) for i in range(num_messages): pg.generate_message(data="0xcafe") - #self.save_protocol("16bit_litte_endian_seq", pg) + # self.save_protocol("16bit_litte_endian_seq", pg) self.clear_message_types(pg.protocol.messages) ff = FormatFinder(pg.protocol.messages) ff.perform_iteration() self.assertEqual(len(ff.message_types), 1) - self.assertEqual(ff.message_types[0].num_labels_with_type(FieldType.Function.SEQUENCE_NUMBER), 1) - label = ff.message_types[0].get_first_label_with_type(FieldType.Function.SEQUENCE_NUMBER) + self.assertEqual( + ff.message_types[0].num_labels_with_type( + FieldType.Function.SEQUENCE_NUMBER + ), + 1, + ) + label = ff.message_types[0].get_first_label_with_type( + FieldType.Function.SEQUENCE_NUMBER + ) self.assertEqual(label.start, 24) self.assertEqual(label.length, 16) diff --git a/tests/cli/test_cli_parsing.py b/tests/cli/test_cli_parsing.py index da97c8f424..499a3b5914 100644 --- a/tests/cli/test_cli_parsing.py +++ b/tests/cli/test_cli_parsing.py @@ -13,19 +13,27 @@ def setUp(self): self.parser = urh_cli.create_parser() def test_build_modulator_from_args(self): - args = self.parser.parse_args("--device HackRF --frequency 433.92e6 --sample-rate 2e6 --raw".split()) + args = self.parser.parse_args( + "--device HackRF --frequency 433.92e6 --sample-rate 2e6 --raw".split() + ) self.assertIsNone(urh_cli.build_modulator_from_args(args)) - args = self.parser.parse_args("--device HackRF --frequency 433.92e6 --sample-rate 2e6".split()) + args = self.parser.parse_args( + "--device HackRF --frequency 433.92e6 --sample-rate 2e6".split() + ) with self.assertRaises(ValueError): urh_cli.build_modulator_from_args(args) - args = self.parser.parse_args("--device HackRF --frequency 433.92e6 --sample-rate 2e6 -p0 0".split()) + args = self.parser.parse_args( + "--device HackRF --frequency 433.92e6 --sample-rate 2e6 -p0 0".split() + ) with self.assertRaises(ValueError): urh_cli.build_modulator_from_args(args) - args = self.parser.parse_args("--device HackRF --frequency 433.92e6 --sample-rate 2e6" - " -pm 0 1 -mo ASK -cf 1337e3 -ca 0.9 -sps 24 -cp 30".split()) + args = self.parser.parse_args( + "--device HackRF --frequency 433.92e6 --sample-rate 2e6" + " -pm 0 1 -mo ASK -cf 1337e3 -ca 0.9 -sps 24 -cp 30".split() + ) modulator = urh_cli.build_modulator_from_args(args) self.assertEqual(modulator.modulation_type, "ASK") self.assertEqual(modulator.sample_rate, 2e6) @@ -36,37 +44,49 @@ def test_build_modulator_from_args(self): self.assertEqual(modulator.carrier_amplitude, 0.9) self.assertEqual(modulator.carrier_phase_deg, 30) - args = self.parser.parse_args("--device HackRF --frequency 433.92e6 --sample-rate 2e6" - " -pm 10% 20% -mo ASK -cf 1337e3 -ca 0.9 -sps 24 -cp 30".split()) + args = self.parser.parse_args( + "--device HackRF --frequency 433.92e6 --sample-rate 2e6" + " -pm 10% 20% -mo ASK -cf 1337e3 -ca 0.9 -sps 24 -cp 30".split() + ) modulator = urh_cli.build_modulator_from_args(args) self.assertEqual(modulator.parameters[0], 10) self.assertEqual(modulator.parameters[1], 20) - args = self.parser.parse_args("--device HackRF --frequency 433.92e6 --sample-rate 2e6" - " -pm 20e3 -20000 -mo FSK -cf 1337e3 -ca 0.9 -sps 24 -cp 30".split()) + args = self.parser.parse_args( + "--device HackRF --frequency 433.92e6 --sample-rate 2e6" + " -pm 20e3 -20000 -mo FSK -cf 1337e3 -ca 0.9 -sps 24 -cp 30".split() + ) modulator = urh_cli.build_modulator_from_args(args) self.assertEqual(modulator.modulation_type, "FSK") self.assertEqual(modulator.parameters[0], 20e3) self.assertEqual(modulator.parameters[1], -20e3) def test_build_backend_handler_from_args(self): - args = self.parser.parse_args("--device USRP --frequency 433.92e6 --sample-rate 2e6".split()) + args = self.parser.parse_args( + "--device USRP --frequency 433.92e6 --sample-rate 2e6".split() + ) bh = urh_cli.build_backend_handler_from_args(args) self.assertEqual(bh.device_backends["usrp"].selected_backend, Backends.native) - args = self.parser.parse_args("--device HackRF --frequency 433.92e6 --sample-rate 2e6" - " --device-backend native".split()) + args = self.parser.parse_args( + "--device HackRF --frequency 433.92e6 --sample-rate 2e6" + " --device-backend native".split() + ) bh = urh_cli.build_backend_handler_from_args(args) self.assertEqual(bh.device_backends["hackrf"].selected_backend, Backends.native) - args = self.parser.parse_args("--device RTL-SDR --frequency 433.92e6 --sample-rate 2e6" - " --device-backend gnuradio".split()) + args = self.parser.parse_args( + "--device RTL-SDR --frequency 433.92e6 --sample-rate 2e6" + " --device-backend gnuradio".split() + ) bh = urh_cli.build_backend_handler_from_args(args) self.assertEqual(bh.device_backends["rtl-sdr"].selected_backend, Backends.grc) def test_build_device_from_args(self): - args = self.parser.parse_args("--device HackRF --frequency 133.7e6 --sample-rate 2.5e6 -rx " - "-if 24 -bb 30 -g 0 --device-identifier abcde".split()) + args = self.parser.parse_args( + "--device HackRF --frequency 133.7e6 --sample-rate 2.5e6 -rx " + "-if 24 -bb 30 -g 0 --device-identifier abcde".split() + ) device = urh_cli.build_device_from_args(args) self.assertEqual(device.sample_rate, 2.5e6) self.assertEqual(device.bandwidth, 2.5e6) @@ -79,8 +99,10 @@ def test_build_device_from_args(self): self.assertEqual(device.baseband_gain, 30) self.assertEqual(device.device_serial, "abcde") - args = self.parser.parse_args("--device RTL-SDR --frequency 133.7e6 --sample-rate 1e6 " - "-rx -db native --device-identifier 42".split()) + args = self.parser.parse_args( + "--device RTL-SDR --frequency 133.7e6 --sample-rate 1e6 " + "-rx -db native --device-identifier 42".split() + ) device = urh_cli.build_device_from_args(args) self.assertEqual(device.sample_rate, 1e6) self.assertEqual(device.name, "RTL-SDR") @@ -89,8 +111,10 @@ def test_build_device_from_args(self): self.assertEqual(device.mode, Mode.receive) self.assertEqual(device.device_number, 42) - args = self.parser.parse_args("--device HackRF --frequency 133.7e6 --sample-rate 2.5e6 --bandwidth 5e6 " - "-tx -db native".split()) + args = self.parser.parse_args( + "--device HackRF --frequency 133.7e6 --sample-rate 2.5e6 --bandwidth 5e6 " + "-tx -db native".split() + ) device = urh_cli.build_device_from_args(args) self.assertEqual(device.sample_rate, 2.5e6) self.assertEqual(device.bandwidth, 5e6) @@ -100,10 +124,12 @@ def test_build_device_from_args(self): self.assertEqual(device.mode, Mode.send) def test_build_protocol_sniffer_from_args(self): - args = self.parser.parse_args("--device HackRF --frequency 50e3 --sample-rate 2.5e6 -rx " - "-if 24 -bb 30 -g 0 --device-identifier abcde " - "-sps 1337 --center 0.5 --noise 0.1234 --tolerance 42 " - "-cs 0.42 -bps 4".split()) + args = self.parser.parse_args( + "--device HackRF --frequency 50e3 --sample-rate 2.5e6 -rx " + "-if 24 -bb 30 -g 0 --device-identifier abcde " + "-sps 1337 --center 0.5 --noise 0.1234 --tolerance 42 " + "-cs 0.42 -bps 4".split() + ) sniffer = urh_cli.build_protocol_sniffer_from_args(args) self.assertEqual(sniffer.rcv_device.frequency, 50e3) self.assertEqual(sniffer.rcv_device.sample_rate, 2.5e6) @@ -123,26 +149,45 @@ def test_build_protocol_sniffer_from_args(self): self.assertEqual(sniffer.signal.tolerance, 42) def test_build_encoding_from_args(self): - args = self.parser.parse_args('--device HackRF --frequency 50e3 --sample-rate 2.5e6 -e "Test,Invert"'.split()) + args = self.parser.parse_args( + '--device HackRF --frequency 50e3 --sample-rate 2.5e6 -e "Test,Invert"'.split() + ) encoding = urh_cli.build_encoding_from_args(args) self.assertEqual(len(encoding.chain), 2) def test_read_messages_to_send(self): - args = self.parser.parse_args('--device HackRF --frequency 50e3 --sample-rate 2e6 -rx'.split()) + args = self.parser.parse_args( + "--device HackRF --frequency 50e3 --sample-rate 2e6 -rx".split() + ) self.assertIsNone(urh_cli.read_messages_to_send(args)) - args = self.parser.parse_args('--device HackRF --frequency 50e3 --sample-rate 2e6 -tx'.split()) + args = self.parser.parse_args( + "--device HackRF --frequency 50e3 --sample-rate 2e6 -tx".split() + ) with self.assertRaises(SystemExit): urh_cli.read_messages_to_send(args) - args = self.parser.parse_args('--device HackRF --frequency 50e3 --sample-rate 2e6 -tx ' - '-file /tmp/test -m 1111'.split()) + args = self.parser.parse_args( + "--device HackRF --frequency 50e3 --sample-rate 2e6 -tx " + "-file /tmp/test -m 1111".split() + ) with self.assertRaises(SystemExit): urh_cli.read_messages_to_send(args) - test_messages = ["101010/1s", "10000/50ms", "00001111/100.5µs", "111010101/500ns", "1111001", "111110000/2000"] - args = self.parser.parse_args(('--device HackRF --frequency 50e3 --sample-rate 2e6 -tx --pause 1337 ' - '-m ' + " ".join(test_messages)).split()) + test_messages = [ + "101010/1s", + "10000/50ms", + "00001111/100.5µs", + "111010101/500ns", + "1111001", + "111110000/2000", + ] + args = self.parser.parse_args( + ( + "--device HackRF --frequency 50e3 --sample-rate 2e6 -tx --pause 1337 " + "-m " + " ".join(test_messages) + ).split() + ) messages = urh_cli.read_messages_to_send(args) self.assertEqual(len(messages), len(test_messages)) self.assertEqual(messages[0].decoded_bits_str, "101010") @@ -168,8 +213,12 @@ def test_read_messages_to_send(self): with open(filepath, "w") as f: f.write("\n".join(test_messages)) - args = self.parser.parse_args(('--device HackRF --frequency 50e3 --sample-rate 2e6 -tx --pause 1337 --hex ' - '-file ' + filepath).split()) + args = self.parser.parse_args( + ( + "--device HackRF --frequency 50e3 --sample-rate 2e6 -tx --pause 1337 --hex " + "-file " + filepath + ).split() + ) messages = urh_cli.read_messages_to_send(args) self.assertEqual(len(messages), len(test_messages)) self.assertEqual(messages[0].decoded_bits_str, "1010101010111011") @@ -179,7 +228,9 @@ def test_parse_project_file(self): f = os.readlink(__file__) if os.path.islink(__file__) else __file__ path = os.path.realpath(os.path.join(f, "..")) - project_file = os.path.realpath(os.path.join(path, "..", "data", "TestProjectForCLI.xml")) + project_file = os.path.realpath( + os.path.join(path, "..", "data", "TestProjectForCLI.xml") + ) tmp_project_file = os.path.join(tempfile.mkdtemp(), "URHProject.xml") shutil.copy(project_file, tmp_project_file) diff --git a/tests/data/code.py b/tests/data/code.py index 34a40510a4..1840aef4f3 100755 --- a/tests/data/code.py +++ b/tests/data/code.py @@ -7,8 +7,24 @@ cur_dir = os.path.dirname(os.path.realpath(__file__)) if sys.argv[1] == "e": - call(sys.executable + ' "' + os.path.join(cur_dir, "encode.py") + '"' + " " + sys.argv[2], shell=True) + call( + sys.executable + + ' "' + + os.path.join(cur_dir, "encode.py") + + '"' + + " " + + sys.argv[2], + shell=True, + ) elif sys.argv[1] == "d": - call(sys.executable + ' "' + os.path.join(cur_dir, "decode.py") + '"' + " " + sys.argv[2], shell=True) + call( + sys.executable + + ' "' + + os.path.join(cur_dir, "decode.py") + + '"' + + " " + + sys.argv[2], + shell=True, + ) else: print("Unknown") diff --git a/tests/data/decode.py b/tests/data/decode.py index 2a5ec168d2..c1c72a93bc 100755 --- a/tests/data/decode.py +++ b/tests/data/decode.py @@ -5,5 +5,6 @@ """ import sys + bits = sys.argv[1] print("".join(b for b in bits[::2])) diff --git a/tests/data/encode.py b/tests/data/encode.py index 5fb54efbff..828e8d8d44 100755 --- a/tests/data/encode.py +++ b/tests/data/encode.py @@ -5,5 +5,6 @@ """ import sys + bits = sys.argv[1] -print("".join(b+b for b in bits)) +print("".join(b + b for b in bits)) diff --git a/tests/debug_tests.py b/tests/debug_tests.py index baefb7037b..3dbd86ea8b 100644 --- a/tests/debug_tests.py +++ b/tests/debug_tests.py @@ -14,13 +14,21 @@ try: filename = "/tmp/tests/" + str(datetime.datetime.now()).replace(" ", "-") t = time.time() - completed = subprocess.run("pytest -s -v ../tests", shell=True, stdout=subprocess.PIPE, - stderr=subprocess.STDOUT) + completed = subprocess.run( + "pytest -s -v ../tests", + shell=True, + stdout=subprocess.PIPE, + stderr=subprocess.STDOUT, + ) duration = time.time() - t if completed.returncode == 0: streak += 1 longest_streak = max(streak, longest_streak) - print("#{} was successful [{:.2f}s] (Streak: {}/{})".format(i + 1, duration, streak, longest_streak)) + print( + "#{} was successful [{:.2f}s] (Streak: {}/{})".format( + i + 1, duration, streak, longest_streak + ) + ) else: streak = 0 print("#{} failed [{:.2f}s]".format(i + 1, duration)) diff --git a/tests/device/HackRFTests.py b/tests/device/HackRFTests.py index 6f2c3687b6..4230101578 100644 --- a/tests/device/HackRFTests.py +++ b/tests/device/HackRFTests.py @@ -18,8 +18,8 @@ def callback_fun(self, buffer): print(buffer) for i in range(0, len(buffer), 4): try: - r = np.fromstring(buffer[i:i + 2], dtype=np.float16) / 32767.5 - i = np.fromstring(buffer[i + 2:i + 4], dtype=np.float16) / 32767.5 + r = np.fromstring(buffer[i : i + 2], dtype=np.float16) / 32767.5 + i = np.fromstring(buffer[i + 2 : i + 4], dtype=np.float16) / 32767.5 except ValueError: continue if r and i: @@ -29,15 +29,15 @@ def callback_fun(self, buffer): return 0 def test_fromstring(self): - buffer = b'\xfe\xfe\xfe\xfe\xfe\xfe\xfe\xfd\xff\xfd\xfe\xfe\xfe\xfe\xfe\xfe\xfe\xfe\xfd\xfe\xfd\xfe\xff\xfe\xfe\xfe\xfe\xfe\xfe\xfe\xfd\xfe' + buffer = b"\xfe\xfe\xfe\xfe\xfe\xfe\xfe\xfd\xff\xfd\xfe\xfe\xfe\xfe\xfe\xfe\xfe\xfe\xfd\xfe\xfd\xfe\xff\xfe\xfe\xfe\xfe\xfe\xfe\xfe\xfd\xfe" r = np.empty(len(buffer) // 2, dtype=np.float32) i = np.empty(len(buffer) // 2, dtype=np.float32) c = np.empty(len(buffer) // 2, dtype=np.complex64) # dtype = - unpacked = np.frombuffer(buffer, dtype=[('r', np.uint8), ('i', np.uint8)]) - ru = unpacked['r'] / 128.0 - iu = unpacked['i'] / 128.0 + unpacked = np.frombuffer(buffer, dtype=[("r", np.uint8), ("i", np.uint8)]) + ru = unpacked["r"] / 128.0 + iu = unpacked["i"] / 128.0 # for j in range(0, len(buffer)-1, 2): # r[j//2] = np.frombuffer(buffer[j:j + 1], dtype=np.int8) / 128.0 @@ -49,15 +49,15 @@ def test_fromstring(self): # x,y = np.frombuffer(buffer, dtype=[('x', np.float16), ('y', np.float16)]) def test_fromstring2(self): - buffer = b'\xfe\xfe\xfe\xfe\xfe\xfe\xfe\xfd\xff\xfd\xfe\xfe\xfe\xfe\xfe\xfe\xfe\xfe\xfd\xfe\xfd\xfe\xff\xfe\xfe\xfe\xfe\xfe\xfe\xfe\xfd\xfe' + buffer = b"\xfe\xfe\xfe\xfe\xfe\xfe\xfe\xfd\xff\xfd\xfe\xfe\xfe\xfe\xfe\xfe\xfe\xfe\xfd\xfe\xfd\xfe\xff\xfe\xfe\xfe\xfe\xfe\xfe\xfe\xfd\xfe" c = np.empty(len(buffer) // 2, dtype=np.complex64) # dtype = - unpacked = np.frombuffer(buffer, dtype="= 0: - self.assertEqual(self.form.compare_frame_controller.proto_analyzer.messages[row].participant.shortname, - shortname) + self.assertEqual( + self.form.compare_frame_controller.proto_analyzer.messages[ + row + ].participant.shortname, + shortname, + ) self.form.compare_frame_controller.refresh_assigned_participants_ui() self.form.save_project() self.form.close_all_files() self.assertEqual(self.form.compare_frame_controller.protocol_model.row_count, 0) - self.form.project_manager.set_project_folder(target_dir, ask_for_new_project=False) + self.form.project_manager.set_project_folder( + target_dir, ask_for_new_project=False + ) - self.assertEqual(self.form.compare_frame_controller.protocol_model.row_count, 22) + self.assertEqual( + self.form.compare_frame_controller.protocol_model.row_count, 22 + ) for row, shortname in target.items(): - self.assertEqual(self.form.compare_frame_controller.proto_analyzer.messages[row].participant.shortname, - shortname, msg=str(row)) + self.assertEqual( + self.form.compare_frame_controller.proto_analyzer.messages[ + row + ].participant.shortname, + shortname, + msg=str(row), + ) def test_save_and_load_with_fieldtypes(self): - target_dir = os.path.join(tempfile.gettempdir(), "urh", "project_fieldtype_test") + target_dir = os.path.join( + tempfile.gettempdir(), "urh", "project_fieldtype_test" + ) os.makedirs(target_dir, exist_ok=True) if os.path.isfile(os.path.join(target_dir, settings.PROJECT_FILE)): os.remove(os.path.join(target_dir, settings.PROJECT_FILE)) - self.form.project_manager.set_project_folder(target_dir, ask_for_new_project=False) + self.form.project_manager.set_project_folder( + target_dir, ask_for_new_project=False + ) self.add_signal_to_form("esaver.complex16s") - self.assertEqual(len(self.form.signal_tab_controller.signal_frames[0].proto_analyzer.messages), 3) - - preamble_field_type = next(ft for ft in self.form.compare_frame_controller.field_types - if ft.function == FieldType.Function.PREAMBLE) # type: FieldType - - sync_field_type = next(ft for ft in self.form.compare_frame_controller.field_types - if ft.function == FieldType.Function.SYNC) # type: FieldType - - checksum_field_type = next(ft for ft in self.form.compare_frame_controller.field_types - if ft.function == FieldType.Function.CHECKSUM) # type: FieldType + self.assertEqual( + len( + self.form.signal_tab_controller.signal_frames[0].proto_analyzer.messages + ), + 3, + ) + + preamble_field_type = next( + ft + for ft in self.form.compare_frame_controller.field_types + if ft.function == FieldType.Function.PREAMBLE + ) # type: FieldType + + sync_field_type = next( + ft + for ft in self.form.compare_frame_controller.field_types + if ft.function == FieldType.Function.SYNC + ) # type: FieldType + + checksum_field_type = next( + ft + for ft in self.form.compare_frame_controller.field_types + if ft.function == FieldType.Function.CHECKSUM + ) # type: FieldType self.form.compare_frame_controller.ui.cbProtoView.setCurrentText("Hex") self.form.compare_frame_controller.add_protocol_label(0, 9, 0, 1, False) @@ -143,28 +240,57 @@ def test_save_and_load_with_fieldtypes(self): self.form.compare_frame_controller.add_protocol_label(14, 16, 0, 1, False) self.__set_label_name(2, checksum_field_type.caption) - self.assertEqual(self.form.compare_frame_controller.active_message_type[0].field_type, preamble_field_type) - self.assertEqual(self.form.compare_frame_controller.active_message_type[1].field_type, sync_field_type) - self.assertEqual(self.form.compare_frame_controller.active_message_type[2].field_type, checksum_field_type) + self.assertEqual( + self.form.compare_frame_controller.active_message_type[0].field_type, + preamble_field_type, + ) + self.assertEqual( + self.form.compare_frame_controller.active_message_type[1].field_type, + sync_field_type, + ) + self.assertEqual( + self.form.compare_frame_controller.active_message_type[2].field_type, + checksum_field_type, + ) self.form.close_project() self.assertEqual(len(self.form.compare_frame_controller.active_message_type), 0) - self.form.project_manager.set_project_folder(target_dir, ask_for_new_project=False) + self.form.project_manager.set_project_folder( + target_dir, ask_for_new_project=False + ) self.assertEqual(len(self.form.compare_frame_controller.active_message_type), 3) - preamble_field_type = next(ft for ft in self.form.compare_frame_controller.field_types - if ft.function == FieldType.Function.PREAMBLE) # type: FieldType - - sync_field_type = next(ft for ft in self.form.compare_frame_controller.field_types - if ft.function == FieldType.Function.SYNC) # type: FieldType - - checksum_field_type = next(ft for ft in self.form.compare_frame_controller.field_types - if ft.function == FieldType.Function.CHECKSUM) # type: FieldType - - self.assertEqual(self.form.compare_frame_controller.active_message_type[0].field_type, preamble_field_type) - self.assertEqual(self.form.compare_frame_controller.active_message_type[1].field_type, sync_field_type) - self.assertEqual(self.form.compare_frame_controller.active_message_type[2].field_type, checksum_field_type) + preamble_field_type = next( + ft + for ft in self.form.compare_frame_controller.field_types + if ft.function == FieldType.Function.PREAMBLE + ) # type: FieldType + + sync_field_type = next( + ft + for ft in self.form.compare_frame_controller.field_types + if ft.function == FieldType.Function.SYNC + ) # type: FieldType + + checksum_field_type = next( + ft + for ft in self.form.compare_frame_controller.field_types + if ft.function == FieldType.Function.CHECKSUM + ) # type: FieldType + + self.assertEqual( + self.form.compare_frame_controller.active_message_type[0].field_type, + preamble_field_type, + ) + self.assertEqual( + self.form.compare_frame_controller.active_message_type[1].field_type, + sync_field_type, + ) + self.assertEqual( + self.form.compare_frame_controller.active_message_type[2].field_type, + checksum_field_type, + ) def __set_label_name(self, index: int, name: str): model = self.form.compare_frame_controller.ui.tblLabelValues.model() @@ -177,7 +303,9 @@ def test_project_dialog(self): gain = 42 descr = "URH rockz." - dialog = ProjectDialog(project_manager=self.form.project_manager, parent=self.form) + dialog = ProjectDialog( + project_manager=self.form.project_manager, parent=self.form + ) dialog.ui.spinBoxFreq.setValue(frequency) self.assertEqual(dialog.freq, frequency) @@ -235,14 +363,21 @@ def test_project_dialog(self): self.form.ui.tabWidget.setCurrentWidget(self.form.ui.tab_protocol) self.form.compare_frame_controller.ui.tabWidget.setCurrentWidget( - self.form.compare_frame_controller.ui.tab_participants) - self.assertGreater(self.form.compare_frame_controller.participant_list_model.rowCount(), 0) + self.form.compare_frame_controller.ui.tab_participants + ) + self.assertGreater( + self.form.compare_frame_controller.participant_list_model.rowCount(), 0 + ) self.assertTrue(os.path.isdir(test_path)) self.form.project_manager.from_dialog(dialog) - dialog = ProjectDialog(project_manager=self.form.project_manager, parent=self.form, new_project=False) + dialog = ProjectDialog( + project_manager=self.form.project_manager, + parent=self.form, + new_project=False, + ) self.assertEqual(dialog.ui.spinBoxFreq.value(), frequency) self.assertEqual(dialog.ui.spinBoxSampleRate.value(), sample_rate) self.assertEqual(dialog.ui.spinBoxBandwidth.value(), bandwidth) diff --git a/tests/test_protocol_analyzer.py b/tests/test_protocol_analyzer.py index 017d09feb7..687c6568fd 100644 --- a/tests/test_protocol_analyzer.py +++ b/tests/test_protocol_analyzer.py @@ -10,7 +10,9 @@ class TestProtocolAnalyzer(unittest.TestCase): def test_get_bit_sample_pos(self): - signal = Signal(get_path_for_data_file("ASK_mod.complex"), "Bit sample pos test") + signal = Signal( + get_path_for_data_file("ASK_mod.complex"), "Bit sample pos test" + ) signal.modulation_type = "ASK" signal.samples_per_symbol = 100 @@ -27,12 +29,14 @@ def test_fsk_freq_detection(self): s.samples_per_symbol = 100 pa = ProtocolAnalyzer(s) pa.get_protocol_from_signal() - self.assertEqual(pa.messages[0].plain_bits_str, - "101010101010101010101010101010101001101001111101100110100111110111010010011000010110110101111" - "010111011011000011000101000010001001101100101111010110100110011100100110000101001110100001111" - "111101000111001110000101110100100111010110110100001101101101010100011011010001010110011100011" - "010100010101111110011010011001000000110010011010001000100100100111101110110010011111011100010" - "10110010100011111101110111000010111100111101001011101101011011010110101011100") + self.assertEqual( + pa.messages[0].plain_bits_str, + "101010101010101010101010101010101001101001111101100110100111110111010010011000010110110101111" + "010111011011000011000101000010001001101100101111010110100110011100100110000101001110100001111" + "111101000111001110000101110100100111010110110100001101101101010100011011010001010110011100011" + "010100010101111110011010011001000000110010011010001000100100100111101110110010011111011100010" + "10110010100011111101110111000010111100111101001011101101011011010110101011100", + ) freq = pa.estimate_frequency_for_one(1e6) self.assertEqual(1, int(freq / 10000)) # Freq for 1 is 10K @@ -40,7 +44,9 @@ def test_fsk_freq_detection(self): self.assertEqual(3, int(freq / 10000)) # Freq for 0 is 30K def test_get_rssi_of_message(self): - signal = Signal(get_path_for_data_file("two_participants.complex16s"), "RSSI-Test") + signal = Signal( + get_path_for_data_file("two_participants.complex16s"), "RSSI-Test" + ) signal.modulation_type = "FSK" signal.samples_per_symbol = 100 signal.center = -0.0507 @@ -56,7 +62,13 @@ def test_get_rssi_of_message(self): def test_binary_format(self): pa = ProtocolAnalyzer(None) - pa.messages.append(Message([1, 1, 1, 0, 0, 0, 1, 1, 1, 0, 0, 1, 1, 0, 1, 1], 0, pa.default_message_type)) + pa.messages.append( + Message( + [1, 1, 1, 0, 0, 0, 1, 1, 1, 0, 0, 1, 1, 0, 1, 1], + 0, + pa.default_message_type, + ) + ) pa.messages.append(Message([1, 1, 1, 0, 1], 0, pa.default_message_type)) filename = os.path.join(tempfile.gettempdir(), "test_proto.bin") diff --git a/tests/test_protocol_label_dialog.py b/tests/test_protocol_label_dialog.py index abc8f908bf..284563a55f 100644 --- a/tests/test_protocol_label_dialog.py +++ b/tests/test_protocol_label_dialog.py @@ -7,25 +7,34 @@ class TestProtocolLabelDialog(QtTestCase): - def setUp(self): super().setUp() self.form.add_protocol_file(get_path_for_data_file("protocol.proto.xml")) self.cframe = self.form.compare_frame_controller - self.cframe.add_protocol_label(9, 19, 0, 0, edit_label_name=False) # equals 10-20 in view - self.cframe.add_protocol_label(39, 54, 1, 0, edit_label_name=False) # equals 40-55 in view + self.cframe.add_protocol_label( + 9, 19, 0, 0, edit_label_name=False + ) # equals 10-20 in view + self.cframe.add_protocol_label( + 39, 54, 1, 0, edit_label_name=False + ) # equals 40-55 in view self.assertEqual(len(self.cframe.proto_analyzer.protocol_labels), 2) - self.dialog = ProtocolLabelDialog(message=self.cframe.proto_analyzer.messages[0], - viewtype=0, parent=self.cframe) + self.dialog = ProtocolLabelDialog( + message=self.cframe.proto_analyzer.messages[0], + viewtype=0, + parent=self.cframe, + ) if self.SHOW: self.dialog.show() def test_protocol_label_dialog(self): - self.assertIn(self.cframe.proto_analyzer.default_message_type.name, self.dialog.windowTitle()) + self.assertIn( + self.cframe.proto_analyzer.default_message_type.name, + self.dialog.windowTitle(), + ) table_model = self.dialog.ui.tblViewProtoLabels.model() self.assertEqual(table_model.rowCount(), 2) @@ -72,7 +81,11 @@ def test_change_view_type(self): def test_remove_labels(self): self.dialog.ui.tblViewProtoLabels.selectAll() self.assertEqual(self.dialog.ui.tblViewProtoLabels.model().rowCount(), 2) - remove_action = self.dialog.ui.tblViewProtoLabels.create_context_menu().actions()[0] + remove_action = ( + self.dialog.ui.tblViewProtoLabels.create_context_menu().actions()[0] + ) remove_action.trigger() self.assertEqual(self.dialog.ui.tblViewProtoLabels.model().rowCount(), 0) - self.assertEqual(len(self.dialog.ui.tblViewProtoLabels.create_context_menu().actions()), 0) + self.assertEqual( + len(self.dialog.ui.tblViewProtoLabels.create_context_menu().actions()), 0 + ) diff --git a/tests/test_protocol_sniffer.py b/tests/test_protocol_sniffer.py index b24866cee5..746d40bc1f 100644 --- a/tests/test_protocol_sniffer.py +++ b/tests/test_protocol_sniffer.py @@ -6,7 +6,9 @@ from tests.QtTestCase import QtTestCase from urh import settings from urh.dev.BackendHandler import BackendHandler -from urh.plugins.NetworkSDRInterface.NetworkSDRInterfacePlugin import NetworkSDRInterfacePlugin +from urh.plugins.NetworkSDRInterface.NetworkSDRInterfacePlugin import ( + NetworkSDRInterfacePlugin, +) from urh.signalprocessing.IQArray import IQArray from urh.signalprocessing.Modulator import Modulator from urh.signalprocessing.ProtocolAnalyzer import ProtocolAnalyzer @@ -28,11 +30,18 @@ def test_protocol_sniffer(self): modulation_type = "FSK" sample_rate = 1e6 device_name = NetworkSDRInterfacePlugin.NETWORK_SDR_NAME - sniffer = ProtocolSniffer(samples_per_symbol=samples_per_symbol, center=center, center_spacing=0.1, - noise=noise, tolerance=tolerance, - modulation_type=modulation_type, bits_per_symbol=1, - device=device_name, backend_handler=BackendHandler(), - network_raw_mode=True) + sniffer = ProtocolSniffer( + samples_per_symbol=samples_per_symbol, + center=center, + center_spacing=0.1, + noise=noise, + tolerance=tolerance, + modulation_type=modulation_type, + bits_per_symbol=1, + device=device_name, + backend_handler=BackendHandler(), + network_raw_mode=True, + ) port = util.get_free_port() sniffer.rcv_device.set_server_port(port) @@ -75,7 +84,9 @@ def test_protocol_sniffer(self): time.sleep(1) # Send enough pauses to end sniffing - self.network_sdr_plugin_sender.send_raw_data(IQArray(None, np.float32, 10 * 2 * samples_per_symbol), 1) + self.network_sdr_plugin_sender.send_raw_data( + IQArray(None, np.float32, 10 * 2 * samples_per_symbol), 1 + ) time.sleep(1) sniffer.stop() diff --git a/tests/test_ringbuffer.py b/tests/test_ringbuffer.py index 2131ef4f81..9243378d23 100644 --- a/tests/test_ringbuffer.py +++ b/tests/test_ringbuffer.py @@ -44,7 +44,11 @@ def test_pop(self): ring_buffer.push(add4) self.assertFalse(ring_buffer.will_fit(1)) - self.assertTrue(np.array_equal(np.concatenate((add3.data[1:], add4.data)), ring_buffer.pop(5))) + self.assertTrue( + np.array_equal( + np.concatenate((add3.data[1:], add4.data)), ring_buffer.pop(5) + ) + ) def test_continuous_pop(self): ring_buffer = RingBuffer(size=10) @@ -60,7 +64,9 @@ def test_continuous_pop(self): def test_big_buffer(self): ring_buffer = RingBuffer(size=5) try: - ring_buffer.push(IQArray(np.array([1, 2, 3, 4, 5, 6, 7], dtype=np.complex64))) + ring_buffer.push( + IQArray(np.array([1, 2, 3, 4, 5, 6, 7], dtype=np.complex64)) + ) self.assertTrue(False) except ValueError: self.assertTrue(True) @@ -78,5 +84,5 @@ def test_will_fit(self): self.assertFalse(ring_buffer.will_fit(5)) -if __name__ == '__main__': +if __name__ == "__main__": unittest.main() diff --git a/tests/test_send_recv_dialog_gui.py b/tests/test_send_recv_dialog_gui.py index bd0b034719..eb07a78388 100644 --- a/tests/test_send_recv_dialog_gui.py +++ b/tests/test_send_recv_dialog_gui.py @@ -19,7 +19,9 @@ from urh.controller.dialogs.SendDialog import SendDialog from urh.controller.dialogs.SpectrumDialogController import SpectrumDialogController from urh.dev.BackendHandler import BackendContainer, Backends -from urh.plugins.NetworkSDRInterface.NetworkSDRInterfacePlugin import NetworkSDRInterfacePlugin +from urh.plugins.NetworkSDRInterface.NetworkSDRInterfacePlugin import ( + NetworkSDRInterfacePlugin, +) from urh.signalprocessing.ContinuousModulator import ContinuousModulator from urh.signalprocessing.IQArray import IQArray from urh.signalprocessing.Signal import Signal @@ -46,7 +48,7 @@ def receive(port, current_index, target_index, buffer, ready): arr = np.frombuffer(data, dtype=np.complex64) data = np.frombuffer(buffer.get_obj(), dtype=np.complex64) - data[current_index.value:current_index.value + len(arr)] = arr + data[current_index.value : current_index.value + len(arr)] = arr current_index.value += len(arr) if current_index.value >= target_index - 1: @@ -64,16 +66,22 @@ def setUp(self): self.form.ui.tabWidget.setCurrentIndex(2) def __get_recv_dialog(self): - receive_dialog = ReceiveDialog(self.form.project_manager, testing_mode=True, parent=self.form) + receive_dialog = ReceiveDialog( + self.form.project_manager, testing_mode=True, parent=self.form + ) if self.SHOW: receive_dialog.show() return receive_dialog def __get_send_dialog(self): - send_dialog = SendDialog(self.form.project_manager, modulated_data=self.signal.iq_array, - modulation_msg_indices=None, - testing_mode=True, parent=self.form) + send_dialog = SendDialog( + self.form.project_manager, + modulated_data=self.signal.iq_array, + modulation_msg_indices=None, + testing_mode=True, + parent=self.form, + ) if self.SHOW: send_dialog.show() @@ -83,17 +91,23 @@ def __get_send_dialog(self): def __get_continuous_send_dialog(self): gframe = self.form.generator_tab_controller - continuous_send_dialog = ContinuousSendDialog(self.form.project_manager, - gframe.table_model.protocol.messages, gframe.modulators, - self.form.generator_tab_controller.total_modulated_samples, - parent=self.form, testing_mode=True) + continuous_send_dialog = ContinuousSendDialog( + self.form.project_manager, + gframe.table_model.protocol.messages, + gframe.modulators, + self.form.generator_tab_controller.total_modulated_samples, + parent=self.form, + testing_mode=True, + ) if self.SHOW: continuous_send_dialog.show() return continuous_send_dialog def __get_spectrum_dialog(self): - spectrum_dialog = SpectrumDialogController(self.form.project_manager, testing_mode=True, parent=self.form) + spectrum_dialog = SpectrumDialogController( + self.form.project_manager, testing_mode=True, parent=self.form + ) if self.SHOW: spectrum_dialog.show() @@ -120,13 +134,17 @@ def __add_first_signal_to_generator(self): item = generator_frame.tree_model.rootItem.children[0].children[0] index = generator_frame.tree_model.createIndex(0, 0, item) mimedata = generator_frame.tree_model.mimeData([index]) - generator_frame.table_model.dropMimeData(mimedata, 1, -1, -1, generator_frame.table_model.createIndex(0, 0)) + generator_frame.table_model.dropMimeData( + mimedata, 1, -1, -1, generator_frame.table_model.createIndex(0, 0) + ) QApplication.instance().processEvents() def test_network_sdr_enabled(self): for dialog in self.__get_all_dialogs(): - items = [dialog.device_settings_widget.ui.cbDevice.itemText(i) for i in - range(dialog.device_settings_widget.ui.cbDevice.count())] + items = [ + dialog.device_settings_widget.ui.cbDevice.itemText(i) + for i in range(dialog.device_settings_widget.ui.cbDevice.count()) + ] self.assertIn(NetworkSDRInterfacePlugin.NETWORK_SDR_NAME, items) dialog.close() @@ -137,7 +155,9 @@ def test_receive(self): receive_dialog.device.set_server_port(port) receive_dialog.ui.btnStart.click() - data = np.array([complex(1, 2), complex(3, 4), complex(5, 6)], dtype=np.complex64) + data = np.array( + [complex(1, 2), complex(3, 4), complex(5, 6)], dtype=np.complex64 + ) sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM) sock.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1) @@ -150,7 +170,11 @@ def test_receive(self): QTest.qWait(100) self.assertEqual(receive_dialog.device.current_index, 3) - self.assertTrue(np.array_equal(receive_dialog.device.data[:3].flatten(), data.view(np.float32))) + self.assertTrue( + np.array_equal( + receive_dialog.device.data[:3].flatten(), data.view(np.float32) + ) + ) receive_dialog.ui.btnStop.click() receive_dialog.ui.btnClear.click() @@ -166,7 +190,9 @@ def test_spectrum(self): spectrum_dialog.ui.btnStart.click() self.assertEqual(len(spectrum_dialog.scene_manager.peak), 0) - data = np.array([complex(1, 1), complex(2, 2), complex(3, 3)], dtype=np.complex64) + data = np.array( + [complex(1, 1), complex(2, 2), complex(3, 3)], dtype=np.complex64 + ) sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM) sock.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1) @@ -201,11 +227,17 @@ def test_send(self): send_dialog.ui.btnStart.click() QTest.qWait(250) - #self.assertEqual(receive_dialog.device.current_index, 2 * self.signal.num_samples) - self.assertTrue(np.array_equal(receive_dialog.device.data[:receive_dialog.device.current_index // 2], - self.signal.iq_array.data)) - - self.assertEqual(send_dialog.ui.lblCurrentRepeatValue.text(), "Sending finished") + # self.assertEqual(receive_dialog.device.current_index, 2 * self.signal.num_samples) + self.assertTrue( + np.array_equal( + receive_dialog.device.data[: receive_dialog.device.current_index // 2], + self.signal.iq_array.data, + ) + ) + + self.assertEqual( + send_dialog.ui.lblCurrentRepeatValue.text(), "Sending finished" + ) self.assertFalse(send_dialog.ui.btnStop.isEnabled()) receive_dialog.ui.btnStop.click() self.assertFalse(receive_dialog.ui.btnStop.isEnabled()) @@ -219,7 +251,7 @@ def test_continuous_send_dialog(self): port = util.get_free_port() - gframe = self.form.generator_tab_controller # type: GeneratorTabController + gframe = self.form.generator_tab_controller # type: GeneratorTabController for msg in gframe.table_model.protocol.messages: msg.pause = 5000 @@ -229,7 +261,9 @@ def test_continuous_send_dialog(self): buffer = Array("f", 4 * len(expected)) ready = Value("i", 0) - process = Process(target=receive, args=(port, current_index, len(expected), buffer, ready)) + process = Process( + target=receive, args=(port, current_index, len(expected), buffer, ready) + ) process.daemon = True process.start() n = 0 @@ -280,11 +314,15 @@ def test_sniff(self): sniff_dialog.sniff_settings_widget.ui.checkBoxAdaptiveNoise.click() self.assertTrue(sniff_dialog.sniffer.adaptive_noise) sniff_dialog.sniff_settings_widget.ui.btn_sniff_use_signal.click() - self.assertEqual(sniff_dialog.sniff_settings_widget.ui.spinbox_sniff_SamplesPerSymbol.value(), - self.form.signal_tab_controller.signal_frames[0].signal.samples_per_symbol) + self.assertEqual( + sniff_dialog.sniff_settings_widget.ui.spinbox_sniff_SamplesPerSymbol.value(), + self.form.signal_tab_controller.signal_frames[0].signal.samples_per_symbol, + ) sniff_dialog.sniff_settings_widget.ui.checkBox_sniff_Timestamp.setChecked(False) - self.assertEqual(sniff_dialog.device.name, NetworkSDRInterfacePlugin.NETWORK_SDR_NAME) + self.assertEqual( + sniff_dialog.device.name, NetworkSDRInterfacePlugin.NETWORK_SDR_NAME + ) sniff_dialog.sniff_settings_widget.ui.comboBox_sniff_viewtype.setCurrentIndex(0) port = util.get_free_port() @@ -316,14 +354,20 @@ def test_sniff(self): sniff_dialog.ui.btnStop.click() sniff_dialog.sniff_settings_widget.ui.checkBox_sniff_Timestamp.click() - self.assertTrue(sniff_dialog.ui.txtEd_sniff_Preview.toPlainText().startswith("[")) + self.assertTrue( + sniff_dialog.ui.txtEd_sniff_Preview.toPlainText().startswith("[") + ) sniff_dialog.sniff_settings_widget.ui.checkBox_sniff_Timestamp.click() - self.assertFalse(sniff_dialog.ui.txtEd_sniff_Preview.toPlainText().startswith("[")) + self.assertFalse( + sniff_dialog.ui.txtEd_sniff_Preview.toPlainText().startswith("[") + ) n = self.form.compare_frame_controller.protocol_model.rowCount() sniff_dialog.protocol_accepted.emit(sniff_dialog.sniffer.messages) QTest.qWait(10) - self.assertEqual(self.form.compare_frame_controller.protocol_model.rowCount(), n + 3) + self.assertEqual( + self.form.compare_frame_controller.protocol_model.rowCount(), n + 3 + ) target_file = os.path.join(QDir.tempPath(), "sniff_file.txt") if os.path.isfile(target_file): @@ -331,7 +375,9 @@ def test_sniff(self): sniff_dialog.ui.btnClear.click() QApplication.instance().processEvents() - sniff_dialog.sniff_settings_widget.ui.lineEdit_sniff_OutputFile.setText(target_file) + sniff_dialog.sniff_settings_widget.ui.lineEdit_sniff_OutputFile.setText( + target_file + ) sniff_dialog.sniff_settings_widget.ui.lineEdit_sniff_OutputFile.editingFinished.emit() sniff_dialog.ui.btnStart.click() QApplication.instance().processEvents() @@ -352,12 +398,16 @@ def test_sniff(self): def test_send_dialog_scene_zoom(self): send_dialog = self.__get_send_dialog() QApplication.instance().processEvents() - self.assertEqual(send_dialog.graphics_view.sceneRect().width(), self.signal.num_samples) + self.assertEqual( + send_dialog.graphics_view.sceneRect().width(), self.signal.num_samples + ) view_width = send_dialog.graphics_view.view_rect().width() send_dialog.graphics_view.zoom(1.1) self.assertLess(send_dialog.graphics_view.view_rect().width(), view_width) send_dialog.graphics_view.zoom(0.8) - self.assertLessEqual(int(send_dialog.graphics_view.view_rect().width()), int(view_width)) + self.assertLessEqual( + int(send_dialog.graphics_view.view_rect().width()), int(view_width) + ) send_dialog.close() @@ -368,7 +418,9 @@ def test_send_dialog_delete(self): self.assertEqual(num_samples, len(send_dialog.device.samples_to_send)) send_dialog.graphics_view.set_horizontal_selection(0, 1337) send_dialog.graphics_view.delete_action.trigger() - self.assertEqual(send_dialog.scene_manager.signal.num_samples, num_samples - 1337) + self.assertEqual( + send_dialog.scene_manager.signal.num_samples, num_samples - 1337 + ) self.assertEqual(len(send_dialog.device.samples_to_send), num_samples - 1337) send_dialog.close() @@ -376,10 +428,15 @@ def test_send_dialog_delete(self): def test_send_dialog_y_slider(self): send_dialog = self.__get_send_dialog() QApplication.instance().processEvents() - y, h = send_dialog.graphics_view.view_rect().y(), send_dialog.graphics_view.view_rect().height() - - send_dialog.ui.sliderYscale.setValue(send_dialog.ui.sliderYscale.value() + - send_dialog.ui.sliderYscale.singleStep()) + y, h = ( + send_dialog.graphics_view.view_rect().y(), + send_dialog.graphics_view.view_rect().height(), + ) + + send_dialog.ui.sliderYscale.setValue( + send_dialog.ui.sliderYscale.value() + + send_dialog.ui.sliderYscale.singleStep() + ) self.assertNotEqual(y, send_dialog.graphics_view.view_rect().y()) self.assertNotEqual(h, send_dialog.graphics_view.view_rect().height()) @@ -401,17 +458,23 @@ def test_change_device_parameters(self): dialog.device_settings_widget.ui.spinBoxFreq.setValue(2e9) dialog.device_settings_widget.ui.spinBoxFreq.editingFinished.emit() - self.assertEqual(dialog.device_settings_widget.ui.spinBoxFreq.text()[-1], "G") + self.assertEqual( + dialog.device_settings_widget.ui.spinBoxFreq.text()[-1], "G" + ) self.assertEqual(dialog.device.frequency, 2e9) dialog.device_settings_widget.ui.spinBoxSampleRate.setValue(10e6) dialog.device_settings_widget.ui.spinBoxSampleRate.editingFinished.emit() - self.assertEqual(dialog.device_settings_widget.ui.spinBoxSampleRate.text()[-1], "M") + self.assertEqual( + dialog.device_settings_widget.ui.spinBoxSampleRate.text()[-1], "M" + ) self.assertEqual(dialog.device.sample_rate, 10e6) dialog.device_settings_widget.ui.spinBoxBandwidth.setValue(3e6) dialog.device_settings_widget.ui.spinBoxBandwidth.editingFinished.emit() - self.assertEqual(dialog.device_settings_widget.ui.spinBoxBandwidth.text()[-1], "M") + self.assertEqual( + dialog.device_settings_widget.ui.spinBoxBandwidth.text()[-1], "M" + ) self.assertEqual(dialog.device.bandwidth, 3e6) dialog.device_settings_widget.ui.spinBoxGain.setValue(5) @@ -431,7 +494,9 @@ def test_change_device_parameters(self): self.assertEqual(dialog.device.freq_correction, 40) dialog.device_settings_widget.ui.comboBoxDirectSampling.clear() - self.assertEqual(dialog.device_settings_widget.ui.comboBoxDirectSampling.count(), 0) + self.assertEqual( + dialog.device_settings_widget.ui.comboBoxDirectSampling.count(), 0 + ) dialog.device_settings_widget.ui.comboBoxDirectSampling.addItem("test") dialog.device_settings_widget.ui.comboBoxDirectSampling.addItem("test1") dialog.device_settings_widget.ui.comboBoxDirectSampling.setCurrentIndex(1) diff --git a/tests/test_signal_details_gui.py b/tests/test_signal_details_gui.py index 80f52e9e77..4773a09661 100644 --- a/tests/test_signal_details_gui.py +++ b/tests/test_signal_details_gui.py @@ -15,10 +15,14 @@ def setUp(self): self.dialog.show() def test_set_sample_rate(self): - self.assertEqual(Formatter.science_time(self.signal.num_samples / self.signal.sample_rate), - self.dialog.ui.lDuration.text()) + self.assertEqual( + Formatter.science_time(self.signal.num_samples / self.signal.sample_rate), + self.dialog.ui.lDuration.text(), + ) self.dialog.ui.dsb_sample_rate.setValue(5e6) self.assertEqual(self.signal.sample_rate, 5e6) - self.assertEqual(Formatter.science_time(self.signal.num_samples / self.signal.sample_rate), - self.dialog.ui.lDuration.text()) + self.assertEqual( + Formatter.science_time(self.signal.num_samples / self.signal.sample_rate), + self.dialog.ui.lDuration.text(), + ) diff --git a/tests/test_signal_tab_GUI.py b/tests/test_signal_tab_GUI.py index 89836d04b5..a42e313bdb 100644 --- a/tests/test_signal_tab_GUI.py +++ b/tests/test_signal_tab_GUI.py @@ -53,7 +53,10 @@ def test_zoom(self): def test_load_proto(self): self.form.add_files([get_path_for_data_file("protocol.proto.xml")]) - self.assertEqual(self.form.signal_tab_controller.signal_frames[0].ui.lSignalTyp.text(), "Protocol") + self.assertEqual( + self.form.signal_tab_controller.signal_frames[0].ui.lSignalTyp.text(), + "Protocol", + ) def test_graphic_view_selection(self): self.add_signal_to_form("esaver.complex16s") @@ -80,7 +83,16 @@ def test_graphic_view_zoom_to_selection(self): frame.ui.gvSignal.context_menu_position = QPoint(0, 0) menu = frame.ui.gvSignal.create_context_menu() self.assertTrue(frame.ui.gvSignal.selection_area.is_empty) - self.assertIsNone(next((action for action in menu.actions() if action.text() == "Zoom selection"), None)) + self.assertIsNone( + next( + ( + action + for action in menu.actions() + if action.text() == "Zoom selection" + ), + None, + ) + ) frame.ui.gvSignal.selection_area.start = 1337 frame.ui.gvSignal.selection_area.end = 4711 @@ -88,7 +100,9 @@ def test_graphic_view_zoom_to_selection(self): menu = frame.ui.gvSignal.create_context_menu() self.assertFalse(frame.ui.gvSignal.selection_area.is_empty) - zoom_action = next(action for action in menu.actions() if action.text() == "Zoom selection") + zoom_action = next( + action for action in menu.actions() if action.text() == "Zoom selection" + ) zoom_action.trigger() self.assertEqual(frame.ui.spinBoxSelectionStart.value(), 1337) self.assertEqual(frame.ui.spinBoxSelectionEnd.value(), 4711) @@ -175,7 +189,9 @@ def test_crop_and_save_signal(self): frame.ui.btnSaveSignal.click() self.form.close_signal_frame(frame) self.add_signal_to_form(os.path.join(QDir.tempPath(), "sig.complex")) - self.assertEqual(self.form.signal_tab_controller.signal_frames[0].signal.num_samples, 3000) + self.assertEqual( + self.form.signal_tab_controller.signal_frames[0].signal.num_samples, 3000 + ) os.remove(os.path.join(QDir.tempPath(), "sig.complex")) def test_selection_sync(self): @@ -187,11 +203,17 @@ def test_selection_sync(self): frame.ui.gvSignal.sel_area_start_end_changed.emit(89383, 128440) QApplication.instance().processEvents() QTest.qWait(100) - self.assertEqual(frame.proto_analyzer.messages[0].plain_bits_str, frame.ui.txtEdProto.selected_text.strip()) + self.assertEqual( + frame.proto_analyzer.messages[0].plain_bits_str, + frame.ui.txtEdProto.selected_text.strip(), + ) frame.ui.txtEdProto.show_proto_clicked.emit() QApplication.instance().processEvents() - self.assertAlmostEqual((128440 - 89383) / 1000000, - (frame.ui.gvSignal.view_rect().width()) / 1000000, places=1) + self.assertAlmostEqual( + (128440 - 89383) / 1000000, + (frame.ui.gvSignal.view_rect().width()) / 1000000, + places=1, + ) def test_auto_detect_button(self): self.add_signal_to_form("esaver.complex16s") @@ -214,7 +236,10 @@ def test_create_new_signal(self): QApplication.instance().processEvents() self.assertEqual(self.form.signal_tab_controller.num_frames, 2) - self.assertEqual(self.form.signal_tab_controller.signal_frames[1].signal.num_samples, end - start) + self.assertEqual( + self.form.signal_tab_controller.signal_frames[1].signal.num_samples, + end - start, + ) def test_demodulated_view(self): self.add_signal_to_form("esaver.complex16s") @@ -225,23 +250,39 @@ def test_demodulated_view(self): def test_context_menu_text_edit_protocol_view(self): self.add_signal_to_form("esaver.complex16s") - self.form.signal_tab_controller.signal_frames[0].ui.cbProtoView.setCurrentIndex(2) + self.form.signal_tab_controller.signal_frames[0].ui.cbProtoView.setCurrentIndex( + 2 + ) text_edit = self.form.signal_tab_controller.signal_frames[0].ui.txtEdProto menu = text_edit.create_context_menu() - line_wrap_action = next(action for action in menu.actions() if action.text().startswith("Linewrap")) + line_wrap_action = next( + action for action in menu.actions() if action.text().startswith("Linewrap") + ) checked = line_wrap_action.isChecked() line_wrap_action.trigger() menu = text_edit.create_context_menu() - line_wrap_action = next(action for action in menu.actions() if action.text().startswith("Linewrap")) + line_wrap_action = next( + action for action in menu.actions() if action.text().startswith("Linewrap") + ) self.assertNotEqual(checked, line_wrap_action.isChecked()) - self.assertEqual(len([action for action in menu.actions() if action.text() == "Participant"]), 0) + self.assertEqual( + len( + [action for action in menu.actions() if action.text() == "Participant"] + ), + 0, + ) self.form.project_manager.participants.append(Participant("Alice", "A")) text_edit.selectAll() menu = text_edit.create_context_menu() - self.assertEqual(len([action for action in menu.actions() if action.text() == "Participant"]), 1) + self.assertEqual( + len( + [action for action in menu.actions() if action.text() == "Participant"] + ), + 1, + ) def test_load_already_demodulated(self): self.add_signal_to_form("demodulated.wav") @@ -257,13 +298,24 @@ def test_load_already_demodulated(self): def test_export_demodulated(self): self.add_signal_to_form("esaver.complex16s") assert isinstance(self.form, MainController) - self.form.signal_tab_controller.signal_frames[0].ui.gvSignal.context_menu_position = QPoint(0,0) - cm = self.form.signal_tab_controller.signal_frames[0].ui.gvSignal.create_context_menu() - export_action = next((a for a in cm.actions() if "demodulated" in a.text().lower()), None) + self.form.signal_tab_controller.signal_frames[ + 0 + ].ui.gvSignal.context_menu_position = QPoint(0, 0) + cm = self.form.signal_tab_controller.signal_frames[ + 0 + ].ui.gvSignal.create_context_menu() + export_action = next( + (a for a in cm.actions() if "demodulated" in a.text().lower()), None + ) self.assertIsNone(export_action) - self.form.signal_tab_controller.signal_frames[0].ui.cbSignalView.setCurrentIndex(1) - cm = self.form.signal_tab_controller.signal_frames[0].ui.gvSignal.create_context_menu() - export_action = next((a for a in cm.actions() if "demodulated" in a.text().lower()), None) + self.form.signal_tab_controller.signal_frames[ + 0 + ].ui.cbSignalView.setCurrentIndex(1) + cm = self.form.signal_tab_controller.signal_frames[ + 0 + ].ui.gvSignal.create_context_menu() + export_action = next( + (a for a in cm.actions() if "demodulated" in a.text().lower()), None + ) self.assertIsNotNone(export_action) - diff --git a/tests/test_simulator.py b/tests/test_simulator.py index 3669824e85..7db66c1f20 100644 --- a/tests/test_simulator.py +++ b/tests/test_simulator.py @@ -6,6 +6,7 @@ import time import numpy as np + # import yappi from PyQt5.QtTest import QTest @@ -14,13 +15,19 @@ from urh import settings from urh.controller.SimulatorTabController import SimulatorTabController from urh.controller.dialogs.SimulatorDialog import SimulatorDialog -from urh.plugins.NetworkSDRInterface.NetworkSDRInterfacePlugin import NetworkSDRInterfacePlugin +from urh.plugins.NetworkSDRInterface.NetworkSDRInterfacePlugin import ( + NetworkSDRInterfacePlugin, +) from urh.signalprocessing.ChecksumLabel import ChecksumLabel from urh.signalprocessing.IQArray import IQArray from urh.signalprocessing.Modulator import Modulator from urh.signalprocessing.ProtocolAnalyzer import ProtocolAnalyzer from urh.signalprocessing.Signal import Signal -from urh.simulator.ActionItem import TriggerCommandActionItem, SleepActionItem, CounterActionItem +from urh.simulator.ActionItem import ( + TriggerCommandActionItem, + SleepActionItem, + CounterActionItem, +) from urh.simulator.SimulatorProtocolLabel import SimulatorProtocolLabel from urh.util import util from urh.util.Logger import logger @@ -37,13 +44,12 @@ def setUp(self): self.num_zeros_for_pause = 1000 def __wait_for_simulator_log_message(self, dialog, log_message): - n = 0 while not any(log_message in msg for msg in dialog.simulator.log_messages): if n < 50: time.sleep(self.TIMEOUT) else: - self.fail("Did not receive log message \"{}\"".format(log_message)) + self.fail('Did not receive log message "{}"'.format(log_message)) n += 1 def test_simulation_flow(self): @@ -59,13 +65,20 @@ def test_simulation_flow(self): profile = self.get_path_for_filename("testprofile.sim.xml") self.form.add_files([profile]) - self.assertEqual(len(self.form.simulator_tab_controller.simulator_scene.get_all_message_items()), 6) + self.assertEqual( + len( + self.form.simulator_tab_controller.simulator_scene.get_all_message_items() + ), + 6, + ) port = util.get_free_port() self.alice = NetworkSDRInterfacePlugin(raw_mode=True) self.alice.client_port = port - dialog = self.form.simulator_tab_controller.get_simulator_dialog() # type: SimulatorDialog + dialog = ( + self.form.simulator_tab_controller.get_simulator_dialog() + ) # type: SimulatorDialog name = NetworkSDRInterfacePlugin.NETWORK_SDR_NAME dialog.device_settings_rx_widget.ui.cbDevice.setCurrentText(name) @@ -87,8 +100,14 @@ def test_simulation_flow(self): conn, addr = s.accept() - msg = next(msg for msg in dialog.simulator_config.get_all_messages() if msg.source.name == "Alice") - checksum_label = next(lbl for lbl in msg.message_type if lbl.is_checksum_label).label # type: ChecksumLabel + msg = next( + msg + for msg in dialog.simulator_config.get_all_messages() + if msg.source.name == "Alice" + ) + checksum_label = next( + lbl for lbl in msg.message_type if lbl.is_checksum_label + ).label # type: ChecksumLabel modulator = dialog.project_manager.modulators[0] # type: Modulator @@ -169,7 +188,11 @@ def test_external_program_simulator(self): stc.ui.btnAddParticipant.click() stc.simulator_scene.add_counter_action(None, 0) - action = next(item for item in stc.simulator_scene.items() if isinstance(item, CounterActionItem)) + action = next( + item + for item in stc.simulator_scene.items() + if isinstance(item, CounterActionItem) + ) action.model_item.start = 3 action.model_item.step = 2 counter_item_str = "item" + str(action.model_item.index()) + ".counter_value" @@ -194,7 +217,11 @@ def test_external_program_simulator(self): lbl1 = messages[0].message_type[0] # type: SimulatorProtocolLabel lbl2 = messages[1].message_type[0] # type: SimulatorProtocolLabel - ext_program = get_path_for_data_file("external_program_simulator.py") + " " + counter_item_str + ext_program = ( + get_path_for_data_file("external_program_simulator.py") + + " " + + counter_item_str + ) if sys.platform == "win32": ext_program = sys.executable + " " + ext_program @@ -203,10 +230,18 @@ def test_external_program_simulator(self): lbl2.value_type_index = 3 lbl2.external_program = ext_program - action = next(item for item in stc.simulator_scene.items() if isinstance(item, SleepActionItem)) + action = next( + item + for item in stc.simulator_scene.items() + if isinstance(item, SleepActionItem) + ) action.model_item.sleep_time = 0.000000001 stc.simulator_scene.clearSelection() - action = next(item for item in stc.simulator_scene.items() if isinstance(item, TriggerCommandActionItem)) + action = next( + item + for item in stc.simulator_scene.items() + if isinstance(item, TriggerCommandActionItem) + ) action.setSelected(True) self.assertEqual(stc.ui.detail_view_widget.currentIndex(), 4) file_name = os.path.join(tempfile.gettempdir(), "external_test") @@ -214,7 +249,11 @@ def test_external_program_simulator(self): os.remove(file_name) self.assertFalse(os.path.isfile(file_name)) - external_command = "cmd.exe /C copy NUL {}".format(file_name) if os.name == "nt" else "touch {}".format(file_name) + external_command = ( + "cmd.exe /C copy NUL {}".format(file_name) + if os.name == "nt" + else "touch {}".format(file_name) + ) stc.ui.lineEditTriggerCommand.setText(external_command) self.assertEqual(action.model_item.command, external_command) @@ -248,7 +287,9 @@ def test_external_program_simulator(self): self.alice.send_raw_data(modulator.modulate("100" + "10101010" * 42), 1) time.sleep(self.TIMEOUT) - self.alice.send_raw_data(IQArray(None, np.float32, 2*self.num_zeros_for_pause), 1) + self.alice.send_raw_data( + IQArray(None, np.float32, 2 * self.num_zeros_for_pause), 1 + ) self.__wait_for_simulator_log_message(dialog, "Sending message") diff --git a/tests/test_simulator_dialog.py b/tests/test_simulator_dialog.py index eb187436cf..2fd04f81dd 100644 --- a/tests/test_simulator_dialog.py +++ b/tests/test_simulator_dialog.py @@ -19,17 +19,33 @@ def setUp(self): self.form.project_manager.project_updated.emit() mt = self.form.compare_frame_controller.proto_analyzer.default_message_type - msg1 = SimulatorMessage(source=bob, destination=alice, plain_bits=array("B", [1, 0, 1, 1]), pause=100, message_type=mt) - msg2 = SimulatorMessage(source=alice, destination=bob, plain_bits=array("B", [1, 0, 1, 1]), pause=100, message_type=mt) + msg1 = SimulatorMessage( + source=bob, + destination=alice, + plain_bits=array("B", [1, 0, 1, 1]), + pause=100, + message_type=mt, + ) + msg2 = SimulatorMessage( + source=alice, + destination=bob, + plain_bits=array("B", [1, 0, 1, 1]), + pause=100, + message_type=mt, + ) simulator_manager = self.form.simulator_tab_controller.simulator_config simulator_manager.add_items([msg1, msg2], 0, simulator_manager.rootItem) - simulator_manager.add_label(5, 15, "test", parent_item=simulator_manager.rootItem.children[0]) + simulator_manager.add_label( + 5, 15, "test", parent_item=simulator_manager.rootItem.children[0] + ) - self.dialog = SimulatorDialog(self.form.simulator_tab_controller.simulator_config, - self.form.generator_tab_controller.modulators, - self.form.simulator_tab_controller.sim_expression_parser, - self.form.project_manager) + self.dialog = SimulatorDialog( + self.form.simulator_tab_controller.simulator_config, + self.form.generator_tab_controller.modulators, + self.form.simulator_tab_controller.sim_expression_parser, + self.form.project_manager, + ) if self.SHOW: self.dialog.show() @@ -73,7 +89,9 @@ def test_set_rx_parameters(self): def test_set_sniff_parameters(self): sniff_settings_widget = self.dialog.sniff_settings_widget simulator = self.dialog.simulator - self.__edit_spinbox_value(sniff_settings_widget.ui.spinbox_sniff_SamplesPerSymbol, 111) + self.__edit_spinbox_value( + sniff_settings_widget.ui.spinbox_sniff_SamplesPerSymbol, 111 + ) self.assertEqual(simulator.sniffer.signal.samples_per_symbol, 111) self.__edit_spinbox_value(sniff_settings_widget.ui.spinbox_sniff_Center, 0.1337) @@ -82,7 +100,9 @@ def test_set_sniff_parameters(self): self.__edit_spinbox_value(sniff_settings_widget.ui.spinBoxCenterSpacing, 0.4) self.assertEqual(simulator.sniffer.signal.center_spacing, 0.4) - self.__edit_spinbox_value(sniff_settings_widget.ui.spinbox_sniff_ErrorTolerance, 13) + self.__edit_spinbox_value( + sniff_settings_widget.ui.spinbox_sniff_ErrorTolerance, 13 + ) self.assertEqual(simulator.sniffer.signal.tolerance, 13) self.__edit_spinbox_value(sniff_settings_widget.ui.spinbox_sniff_Noise, 0.1234) @@ -94,8 +114,10 @@ def test_set_sniff_parameters(self): self.__edit_spinbox_value(sniff_settings_widget.ui.spinBoxBitsPerSymbol, 5) self.assertEqual(simulator.sniffer.signal.bits_per_symbol, 5) - decodings = [sniff_settings_widget.ui.comboBox_sniff_encoding.itemText(i) for i in - range(sniff_settings_widget.ui.comboBox_sniff_encoding.count())] + decodings = [ + sniff_settings_widget.ui.comboBox_sniff_encoding.itemText(i) + for i in range(sniff_settings_widget.ui.comboBox_sniff_encoding.count()) + ] sniff_settings_widget.ui.comboBox_sniff_encoding.setCurrentIndex(2) self.assertEqual(simulator.sniffer.decoder.name, decodings[2]) diff --git a/tests/test_simulator_tab_gui.py b/tests/test_simulator_tab_gui.py index 11c02b2656..4d7fc41c6b 100644 --- a/tests/test_simulator_tab_gui.py +++ b/tests/test_simulator_tab_gui.py @@ -13,7 +13,9 @@ from urh import settings from urh.controller.MainController import MainController from urh.controller.SimulatorTabController import SimulatorTabController -from urh.plugins.NetworkSDRInterface.NetworkSDRInterfacePlugin import NetworkSDRInterfacePlugin +from urh.plugins.NetworkSDRInterface.NetworkSDRInterfacePlugin import ( + NetworkSDRInterfacePlugin, +) from urh.signalprocessing.IQArray import IQArray from urh.signalprocessing.Modulator import Modulator from urh.signalprocessing.Participant import Participant @@ -146,11 +148,20 @@ def test_edit_simulator_label_table(self): self.assertEqual(model.data(model.index(0, 3)), "") stc.ui.tblViewFieldValues.openPersistentEditor(model.index(0, 3)) model.setData(model.index(0, 3), "4+5", role=Qt.EditRole) - self.assertNotEqual(model.data(model.index(0, 3), role=Qt.BackgroundColorRole), settings.ERROR_BG_COLOR) + self.assertNotEqual( + model.data(model.index(0, 3), role=Qt.BackgroundColorRole), + settings.ERROR_BG_COLOR, + ) model.setData(model.index(0, 3), "item1.preamble + 42", role=Qt.EditRole) - self.assertNotEqual(model.data(model.index(0, 3), role=Qt.BackgroundColorRole), settings.ERROR_BG_COLOR) + self.assertNotEqual( + model.data(model.index(0, 3), role=Qt.BackgroundColorRole), + settings.ERROR_BG_COLOR, + ) model.setData(model.index(0, 3), "item1.preamble + 42/", role=Qt.EditRole) - self.assertEqual(model.data(model.index(0, 3), role=Qt.BackgroundColorRole), settings.ERROR_BG_COLOR) + self.assertEqual( + model.data(model.index(0, 3), role=Qt.BackgroundColorRole), + settings.ERROR_BG_COLOR, + ) # external program model.setData(model.index(0, 2), 3, role=Qt.EditRole) @@ -174,13 +185,17 @@ def test_insert_column(self): stc.ui.tblViewMessage.selectAll() stc.ui.tblViewMessage._insert_column(2) for i, l in enumerate(lens): - self.assertEqual(lens[i] + 4, len(stc.simulator_message_table_model.protocol.messages[i])) + self.assertEqual( + lens[i] + 4, len(stc.simulator_message_table_model.protocol.messages[i]) + ) stc.ui.cbViewType.setCurrentText("Bit") stc.ui.tblViewMessage.selectAll() stc.ui.tblViewMessage._insert_column(6) for i, l in enumerate(lens): - self.assertEqual(lens[i] + 5, len(stc.simulator_message_table_model.protocol.messages[i])) + self.assertEqual( + lens[i] + 5, len(stc.simulator_message_table_model.protocol.messages[i]) + ) def test_simulator_graphics_view(self): self.__setup_project() @@ -194,23 +209,35 @@ def test_simulator_graphics_view(self): messages = stc.simulator_scene.get_all_message_items() pos = stc.ui.gvSimulator.mapFromScene(messages[0].scenePos()) - QTest.mouseClick(stc.ui.gvSimulator.viewport(), Qt.LeftButton, Qt.NoModifier, pos) + QTest.mouseClick( + stc.ui.gvSimulator.viewport(), Qt.LeftButton, Qt.NoModifier, pos + ) self.assertEqual(len(stc.simulator_scene.selectedItems()), 1) self.assertIsInstance(stc.simulator_scene.selectedItems()[0], MessageItem) - rules = [item for item in stc.simulator_scene.items() if isinstance(item, RuleItem)] + rules = [ + item for item in stc.simulator_scene.items() if isinstance(item, RuleItem) + ] self.assertEqual(len(rules), 0) - self.menus_to_ignore = [w for w in QApplication.topLevelWidgets() if isinstance(w, QMenu)] + self.menus_to_ignore = [ + w for w in QApplication.topLevelWidgets() if isinstance(w, QMenu) + ] timer = QTimer(self.form) timer.setInterval(1) timer.setSingleShot(True) - timer.timeout.connect(self.__on_context_menu_simulator_graphics_view_timer_timeout) + timer.timeout.connect( + self.__on_context_menu_simulator_graphics_view_timer_timeout + ) timer.start() - stc.ui.gvSimulator.contextMenuEvent(QContextMenuEvent(QContextMenuEvent.Mouse, pos)) + stc.ui.gvSimulator.contextMenuEvent( + QContextMenuEvent(QContextMenuEvent.Mouse, pos) + ) - rules = [item for item in stc.simulator_scene.items() if isinstance(item, RuleItem)] + rules = [ + item for item in stc.simulator_scene.items() if isinstance(item, RuleItem) + ] self.assertEqual(len(rules), 1) def test_simulator_message_table_context_menu(self): @@ -223,14 +250,18 @@ def test_simulator_message_table_context_menu(self): self.assertEqual(stc.simulator_message_field_model.rowCount(), 1) stc.ui.tblViewMessage.selectColumn(4) - x, y = stc.ui.tblViewMessage.columnViewportPosition(4), stc.ui.tblViewMessage.rowViewportPosition(0) + x, y = stc.ui.tblViewMessage.columnViewportPosition( + 4 + ), stc.ui.tblViewMessage.rowViewportPosition(0) pos = QPoint(x, y) stc.ui.tblViewMessage.context_menu_pos = pos menu = stc.ui.tblViewMessage.create_context_menu() names = [action.text() for action in menu.actions()] self.assertIn("Enforce encoding", names) - add_label_action = next(action for action in menu.actions() if action.text() == "Create label...") + add_label_action = next( + action for action in menu.actions() if action.text() == "Create label..." + ) add_label_action.trigger() menu.close() stc.ui.tblViewMessage.selectRow(0) @@ -239,8 +270,14 @@ def test_simulator_message_table_context_menu(self): def test_expression_line_edit(self): e = ExpressionLineEdit() - e.setCompleter(QCompleter(self.form.simulator_tab_controller.completer_model, e)) - e.setValidator(RuleExpressionValidator(self.form.simulator_tab_controller.sim_expression_parser)) + e.setCompleter( + QCompleter(self.form.simulator_tab_controller.completer_model, e) + ) + e.setValidator( + RuleExpressionValidator( + self.form.simulator_tab_controller.sim_expression_parser + ) + ) self.assertEqual(e.text(), "") QTest.keyClick(e, Qt.Key_R, Qt.NoModifier) @@ -289,12 +326,24 @@ def test_participants_list(self): self.form.project_manager.project_updated.emit() mt = self.form.compare_frame_controller.proto_analyzer.default_message_type - msg1 = SimulatorMessage(destination=alice, plain_bits=array("B", [1, 0, 1, 1]), pause=100, message_type=mt) - msg2 = SimulatorMessage(destination=bob, plain_bits=array("B", [1, 0, 1, 1]), pause=100, message_type=mt) + msg1 = SimulatorMessage( + destination=alice, + plain_bits=array("B", [1, 0, 1, 1]), + pause=100, + message_type=mt, + ) + msg2 = SimulatorMessage( + destination=bob, + plain_bits=array("B", [1, 0, 1, 1]), + pause=100, + message_type=mt, + ) simulator_manager = self.form.simulator_tab_controller.simulator_config simulator_manager.add_items([msg1, msg2], 0, simulator_manager.rootItem) - simulator_manager.add_label(5, 15, "test", parent_item=simulator_manager.rootItem.children[0]) + simulator_manager.add_label( + 5, 15, "test", parent_item=simulator_manager.rootItem.children[0] + ) stc = self.form.simulator_tab_controller # type: SimulatorTabController model = stc.ui.listViewSimulate.model() @@ -302,9 +351,13 @@ def test_participants_list(self): self.assertEqual(model.data(model.index(0, 0)), "Alice (A)") self.assertEqual(model.data(model.index(1, 0)), "Bob (B)") self.assertFalse(self.form.project_manager.participants[0].simulate) - self.assertEqual(model.data(model.index(0, 0), role=Qt.CheckStateRole), Qt.Unchecked) + self.assertEqual( + model.data(model.index(0, 0), role=Qt.CheckStateRole), Qt.Unchecked + ) self.assertFalse(self.form.project_manager.participants[1].simulate) - self.assertEqual(model.data(model.index(1, 0), role=Qt.CheckStateRole), Qt.Unchecked) + self.assertEqual( + model.data(model.index(1, 0), role=Qt.CheckStateRole), Qt.Unchecked + ) model.setData(model.index(0, 0), Qt.Checked, role=Qt.CheckStateRole) self.assertTrue(self.form.project_manager.participants[0].simulate) @@ -318,24 +371,29 @@ def test_valid_goto_targets(self): self.assertEqual(len(stc.simulator_config.get_all_messages()), 3) stc.ui.gvSimulator.on_add_goto_action_triggered() - self.assertEqual(stc.ui.detail_view_widget.currentWidget(), stc.ui.page_goto_action) - self.assertEqual(stc.ui.goto_combobox.count(), 3 + 1) # select item... also in combobox + self.assertEqual( + stc.ui.detail_view_widget.currentWidget(), stc.ui.page_goto_action + ) + self.assertEqual( + stc.ui.goto_combobox.count(), 3 + 1 + ) # select item... also in combobox stc.ui.gvSimulator.on_add_counter_action_triggered() stc.ui.gvSimulator.on_add_sleep_action_triggered() stc.ui.gvSimulator.on_add_goto_action_triggered() - self.assertEqual(stc.ui.goto_combobox.count(), 5 + 1) # select item... also in combobox + self.assertEqual( + stc.ui.goto_combobox.count(), 5 + 1 + ) # select item... also in combobox def test_open_simulator_dialog_and_send_message(self): def __wait_for_simulator_log_message(dialog, log_message): - n = 0 while not any(log_message in msg for msg in dialog.simulator.log_messages): if n < 50: time.sleep(0.5) else: - self.fail("Did not receive log message \"{}\"".format(log_message)) + self.fail('Did not receive log message "{}"'.format(log_message)) n += 1 stc = self.form.simulator_tab_controller @@ -352,7 +410,9 @@ def __wait_for_simulator_log_message(dialog, log_message): list_model = stc.ui.listViewSimulate.model() self.assertEqual(list_model.rowCount(), 2) - list_model.setData(list_model.createIndex(1, 0), Qt.Checked, role=Qt.CheckStateRole) + list_model.setData( + list_model.createIndex(1, 0), Qt.Checked, role=Qt.CheckStateRole + ) dialog = stc.get_simulator_dialog() @@ -386,11 +446,18 @@ def __wait_for_simulator_log_message(dialog, log_message): dialog.close() def __on_context_menu_simulator_graphics_view_timer_timeout(self): - menu = next(w for w in QApplication.topLevelWidgets() if isinstance(w, QMenu) - and w.parent() is None and w not in self.menus_to_ignore) + menu = next( + w + for w in QApplication.topLevelWidgets() + if isinstance(w, QMenu) + and w.parent() is None + and w not in self.menus_to_ignore + ) names = [action.text() for action in menu.actions()] self.assertIn("Source", names) - add_rule_action = next(action for action in menu.actions() if action.text() == "Add rule") + add_rule_action = next( + action for action in menu.actions() if action.text() == "Add rule" + ) add_rule_action.trigger() menu.close() @@ -403,15 +470,23 @@ def __setup_project(self): if os.path.isfile(os.path.join(directory, "URHProject.xml")): os.remove(os.path.join(directory, "URHProject.xml")) - self.form.project_manager.set_project_folder(directory, ask_for_new_project=False) + self.form.project_manager.set_project_folder( + directory, ask_for_new_project=False + ) self.form.project_manager.participants[:] = self.participants self.form.project_manager.project_updated.emit() self.add_signal_to_form("esaver.complex16s") self.assertEqual(self.form.signal_tab_controller.num_frames, 1) - self.assertEqual(self.form.compare_frame_controller.participant_list_model.rowCount(), 3) + self.assertEqual( + self.form.compare_frame_controller.participant_list_model.rowCount(), 3 + ) for i in range(3): - self.form.compare_frame_controller.proto_analyzer.messages[i].participant = self.carl + self.form.compare_frame_controller.proto_analyzer.messages[ + i + ].participant = self.carl self.form.compare_frame_controller.add_protocol_label(8, 15, 0, 0, False) - self.assertEqual(self.form.compare_frame_controller.label_value_model.rowCount(), 1) + self.assertEqual( + self.form.compare_frame_controller.label_value_model.rowCount(), 1 + ) diff --git a/tests/test_spectrogram.py b/tests/test_spectrogram.py index c041b4b7f3..58f74c8e5c 100644 --- a/tests/test_spectrogram.py +++ b/tests/test_spectrogram.py @@ -8,7 +8,9 @@ class TestSpectrogram(QtTestCase): def setUp(self): - self.signal = Signal(self.get_path_for_filename("two_participants.complex16s"), "test") + self.signal = Signal( + self.get_path_for_filename("two_participants.complex16s"), "test" + ) self.spectrogram = Spectrogram(self.signal.iq_array.data) def test_create_spectrogram_image(self): @@ -29,9 +31,30 @@ def test_channel_separation_with_negative_frequency(self): signal_frame = self.form.signal_tab_controller.signal_frames[0] self.__prepare_channel_separation(signal_frame) - self.__test_extract_channel(signal_frame, freq1=650, freq2=850, bandwidth="195,312KHz", target_bits="11001101", center=0.1) - self.__test_extract_channel(signal_frame, freq1=500, freq2=620, bandwidth="117,188KHz", target_bits="10101001", center=0.1) - self.__test_extract_channel(signal_frame, freq1=217, freq2=324, bandwidth="104,492KHz", target_bits="10010111", center=0.1) + self.__test_extract_channel( + signal_frame, + freq1=650, + freq2=850, + bandwidth="195,312KHz", + target_bits="11001101", + center=0.1, + ) + self.__test_extract_channel( + signal_frame, + freq1=500, + freq2=620, + bandwidth="117,188KHz", + target_bits="10101001", + center=0.1, + ) + self.__test_extract_channel( + signal_frame, + freq1=217, + freq2=324, + bandwidth="104,492KHz", + target_bits="10010111", + center=0.1, + ) def test_cancel_filtering(self): super().setUp() @@ -41,7 +64,9 @@ def test_cancel_filtering(self): signal_frame.ui.spinBoxSelectionStart.setValue(100) signal_frame.ui.spinBoxSelectionEnd.setValue(200) menu = signal_frame.ui.gvSpectrogram.create_context_menu() - create_action = next(action for action in menu.actions() if "bandpass filter" in action.text()) + create_action = next( + action for action in menu.actions() if "bandpass filter" in action.text() + ) timer = QTimer(self.form) timer.setSingleShot(True) timer.timeout.connect(self.form.cancel_action.trigger) @@ -61,7 +86,9 @@ def __prepare_channel_separation(self, signal_frame): signal_frame.ui.cbSignalView.setCurrentIndex(2) self.assertTrue(signal_frame.spectrogram_is_active) - def __test_extract_channel(self, signal_frame, freq1, freq2, bandwidth: str, target_bits: str, center=None): + def __test_extract_channel( + self, signal_frame, freq1, freq2, bandwidth: str, target_bits: str, center=None + ): num_frames = self.form.signal_tab_controller.num_frames signal_frame.ui.spinBoxSelectionStart.setValue(freq1) @@ -71,7 +98,9 @@ def __test_extract_channel(self, signal_frame, freq1, freq2, bandwidth: str, tar self.assertEqual(signal_frame.ui.lNumSelectedSamples.text(), str(freq2 - freq1)) self.assertEqual(signal_frame.ui.lDuration.text().replace(".", ","), bandwidth) menu = signal_frame.ui.gvSpectrogram.create_context_menu() - create_action = next(action for action in menu.actions() if "bandpass filter" in action.text()) + create_action = next( + action for action in menu.actions() if "bandpass filter" in action.text() + ) create_action.trigger() self.assertEqual(self.form.signal_tab_controller.num_frames, num_frames + 1) diff --git a/tests/test_util.py b/tests/test_util.py index bcd2d34ddd..c6238d23be 100644 --- a/tests/test_util.py +++ b/tests/test_util.py @@ -37,21 +37,33 @@ def test_set_shared_lib_path(self): util.set_shared_library_path() def test_create_textbox_dialog(self): - dialog = util.create_textbox_dialog("Test content", "Test title", parent=self.form) + dialog = util.create_textbox_dialog( + "Test content", "Test title", parent=self.form + ) self.assertEqual(dialog.windowTitle(), "Test title") - self.assertEqual(dialog.layout().itemAt(0).widget().toPlainText(), "Test content") + self.assertEqual( + dialog.layout().itemAt(0).widget().toPlainText(), "Test content" + ) dialog.close() def test_get_receive_buffer_size(self): settings.OVERWRITE_RECEIVE_BUFFER_SIZE = None - ns = settings.get_receive_buffer_size(resume_on_full_receive_buffer=True, spectrum_mode=True) + ns = settings.get_receive_buffer_size( + resume_on_full_receive_buffer=True, spectrum_mode=True + ) self.assertEqual(ns, settings.SPECTRUM_BUFFER_SIZE) - ns = settings.get_receive_buffer_size(resume_on_full_receive_buffer=True, spectrum_mode=False) + ns = settings.get_receive_buffer_size( + resume_on_full_receive_buffer=True, spectrum_mode=False + ) self.assertEqual(ns, settings.SNIFF_BUFFER_SIZE) - ns1 = settings.get_receive_buffer_size(resume_on_full_receive_buffer=False, spectrum_mode=True) - ns2 = settings.get_receive_buffer_size(resume_on_full_receive_buffer=False, spectrum_mode=False) + ns1 = settings.get_receive_buffer_size( + resume_on_full_receive_buffer=False, spectrum_mode=True + ) + ns2 = settings.get_receive_buffer_size( + resume_on_full_receive_buffer=False, spectrum_mode=False + ) self.assertEqual(len(str(ns1)), len(str(ns2))) def test_write_pcap(self): @@ -70,7 +82,11 @@ def test_write_pcap(self): proto_analyzer.messages.append(copy.deepcopy(proto_analyzer.messages[0])) pcap = PCAP() - pcap.write_packets(proto_analyzer.messages, os.path.join(tempfile.gettempdir(), "test.pcap"), 1e6) + pcap.write_packets( + proto_analyzer.messages, + os.path.join(tempfile.gettempdir(), "test.pcap"), + 1e6, + ) def test_write_pcapng(self): signal = Signal(get_path_for_data_file("ask.complex"), "ASK-Test") @@ -88,36 +104,57 @@ def test_write_pcapng(self): proto_analyzer.messages.append(copy.deepcopy(proto_analyzer.messages[0])) filepath = os.path.join(tempfile.gettempdir(), "test.pcapng") - PCAPNG.create_pcapng_file(filepath, "Universal Radio Hacker Test", "TestHW", 147) + PCAPNG.create_pcapng_file( + filepath, "Universal Radio Hacker Test", "TestHW", 147 + ) PCAPNG.append_packets_to_pcapng( filename=filepath, packets=(msg.decoded_ascii_buffer for msg in proto_analyzer.messages), - timestamps=(msg.timestamp for msg in proto_analyzer.messages)) + timestamps=(msg.timestamp for msg in proto_analyzer.messages), + ) # As we don't have PCAPNG importers, we'll verify output just by checking file size, PCAPNG SHB type number # and that all msg bytes were written somewhere inside output file filechecks = False - if os.path.isfile(filepath): # ok, file exist + if os.path.isfile(filepath): # ok, file exist with open(filepath, "rb") as f: filecontents = f.read() # min file len= SHB + IDB + 4 EPB msgs - minfilelen = 28 + 20 + (4 * (32 + len(proto_analyzer.messages[0].decoded_ascii_buffer))) - if len(filecontents) >= minfilelen: # ok, min file length passed - if filecontents.find(b'\x0A\x0D\x0D\x0A') >= 0: # ok, seems that SHB was written - if filecontents.find(proto_analyzer.messages[0].decoded_ascii_buffer) >= 0: # ok, msg bytes written + minfilelen = ( + 28 + + 20 + + (4 * (32 + len(proto_analyzer.messages[0].decoded_ascii_buffer))) + ) + if len(filecontents) >= minfilelen: # ok, min file length passed + if ( + filecontents.find(b"\x0A\x0D\x0D\x0A") >= 0 + ): # ok, seems that SHB was written + if ( + filecontents.find( + proto_analyzer.messages[0].decoded_ascii_buffer + ) + >= 0 + ): # ok, msg bytes written filechecks = True - + self.assertTrue(filechecks) def test_de_bruijn_fuzzing(self): - self.assertEqual(c_util.de_bruijn(3), array.array("B", [0, 0, 0, 1, 0, 1, 1, 1])) - self.assertEqual(c_util.de_bruijn(4), array.array("B", [0, 0, 0, 0, 1, 0, 0, 1, 1, 0, 1, 0, 1, 1, 1, 1])) + self.assertEqual( + c_util.de_bruijn(3), array.array("B", [0, 0, 0, 1, 0, 1, 1, 1]) + ) + self.assertEqual( + c_util.de_bruijn(4), + array.array("B", [0, 0, 0, 0, 1, 0, 0, 1, 1, 0, 1, 0, 1, 1, 1, 1]), + ) def test_native_backends_installed(self): from urh.util import util if not util.get_shared_library_path(): - logger.info("Shared library dir not found, skipping check of native device extensions") + logger.info( + "Shared library dir not found, skipping check of native device extensions" + ) return util.set_shared_library_path() diff --git a/tests/utils_testing.py b/tests/utils_testing.py index 71b1909e7a..0209f5fe54 100644 --- a/tests/utils_testing.py +++ b/tests/utils_testing.py @@ -4,11 +4,11 @@ def trace_calls(frame, event, arg): - if event != 'call': + if event != "call": return co = frame.f_code func_name = co.co_name - if func_name == 'write': + if func_name == "write": # Ignore write() calls from print statements return func_line_no = frame.f_lineno @@ -21,16 +21,25 @@ def trace_calls(frame, event, arg): return if "_test" in caller_filename or "_test" in func_filename: - start = '\033[91m' + start = "\033[91m" else: start = "\033[0;32m" end = "\033[0;0m" else: start, end = "", "" - print('%s Call to %s on line %s of %s from line %s of %s %s' % \ - (start, func_name, func_line_no, func_filename, - caller_line_no, caller_filename, end)) + print( + "%s Call to %s on line %s of %s from line %s of %s %s" + % ( + start, + func_name, + func_line_no, + func_filename, + caller_line_no, + caller_filename, + end, + ) + ) return @@ -43,7 +52,9 @@ def write_settings(): settings_written except NameError: settings_written = True - settings.write("not_show_close_dialog", True) # prevent interactive close questions + settings.write( + "not_show_close_dialog", True + ) # prevent interactive close questions settings.write("not_show_save_dialog", True) settings.write("NetworkSDRInterface", True) settings.write("align_labels", True)