from contextlib import contextmanager import ics import time import argparse def serial_base36enc(ser_no): """ Encode serial as base36 if needed and return the string representation of the serial number Args: ser_no: Serial number integer """ if int("AA0000", 36) < ser_no < int("ZZZZZZ", 36): return ics.base36enc(ser_no) else: return str(ser_no) # Old devices don't do base36 def serial_base36dec(ser_no): """ Decode serial as base36 if needed and return the integer representation of the serial number Args: ser_no: Serial number string """ serial36 = int(ser_no, 36) if int("AA0000", 36) < serial36 < int("ZZZZZZ", 36): return serial36 else: return int(ser_no, 10) # Old devices don't do base36 def filter_by_netid(msgs, netid): """ Filters the list of messages by netid Args: msgs: A list of spy messages, likely from ics.get_messages netid: The desired netid Returns: The filtered message list """ netids = [netid] return filter_by_netids(msgs, netids) def filter_by_netids(msgs, netids): """ Filters the provided messages by those that match the provided netids Args: msgs: The messages to filter netids: The valid netids to keep Returns: All messages with the provided netids """ ret = [msg for msg in msgs if get_netid(msg) in netids] return ret def get_netid(msg): """ Gets the netid for the message Args: msg: The message to check Returns: The netid (the number) for the message """ netid = (msg.NetworkID2 << 8) | (msg.NetworkID & 0xFF) return netid @contextmanager def open_device(ser_no, tries=10, delay=1.0): """ Context manager for a neovi device. Opens the device, then auto-closes once the context manager falls out of scope Args: ser_no: Serial number string of a connected device, will be validated Yields: an open device Examples: with open("GS0137") as device: ics_do_stuff(device) """ device = None serial = serial_base36dec(ser_no) for i in range(tries): try: found = False # work around for supporting neovi server connections # ics.open_device will not work if already open in Vspy with server devices = ics.find_devices() for d in devices: if d.SerialNumber == serial: device = ics.open_device(d) found = True break if found: # successfully opened break else: raise Exception(f"Could not find device to open {ser_no}") except Exception: device = None print(f"Failed to Open {ser_no}, Trying again... ({i+1}/{tries})") time.sleep(delay) if device is None: # could not find device and multiple retries devices = ics.find_devices() print("ERROR: Device not found. Known devices are:") print([serial_base36enc(dev.SerialNumber) for dev in devices]) exit(1) try: yield device except Exception as e: print("ERROR: Open device succeeded, but yielding failed?") raise e finally: if device is not None: ics.close_device(device) def get_hwnetid(name): """ Get hardware network ID from string name in one of the following forms: COREMINI_NETWORK_ETHERNET, NETID_ETHERNET, or ETHERNET Args: name: Network name Returns: Hardware network ID """ # NETID_XXX, use as is if name.startswith("NETID_"): if hasattr(ics, name): return getattr(ics, name) # COREMINI_NETWORK_XXX, convert if name.startswith("COREMINI_NETWORK_"): newname = "NETID_" + name[len("COREMINI_NETWORK_") :] if hasattr(ics, newname): return getattr(ics, newname) # assume no prefix, so try adding it newname = "NETID_" + name if hasattr(ics, newname): return getattr(ics, newname) raise AttributeError(f"Could not match network for {name}") class MyArgParseHelpFormatter(argparse.ArgumentDefaultsHelpFormatter): def _split_lines(self, text, width): if text.startswith("R|"): lines = text.splitlines()[1:] return lines return super()._split_lines(text, width) def set_process_priority(pid=None, priority=2): """ Set The Priority of a Process. Priority is a value between 0-5 where 2 is normal priority, 5 is highest priority. Default sets the priority of the current python process but can take any valid process ID. """ import sys try: sys.getwindowsversion() except AttributeError: isWindows = False else: isWindows = True if isWindows: # Based on: # "Recipe 496767: Set Process Priority In Windows" on ActiveState # http://code.activestate.com/recipes/496767/ import win32api import win32process import win32con priorityclasses = [ win32process.IDLE_PRIORITY_CLASS, win32process.BELOW_NORMAL_PRIORITY_CLASS, win32process.NORMAL_PRIORITY_CLASS, win32process.ABOVE_NORMAL_PRIORITY_CLASS, win32process.HIGH_PRIORITY_CLASS, win32process.REALTIME_PRIORITY_CLASS, ] if pid is None: pid = win32api.GetCurrentProcessId() handle = win32api.OpenProcess(win32con.PROCESS_ALL_ACCESS, True, pid) win32process.SetPriorityClass(handle, priorityclasses[priority]) else: # untested! import os nice_levels = [19, 9, 0, -7, -14, -20] os.nice(nice_levels[priority]) def dict_align_str(d, sort=False, nz=False): """ Prints a dict nicely and key value pairs in aligned rows Primarily limited to simple "a": "b" dicts, might not look nice for complex value types Args: d: Some dictionary sort: Sort dictionary items nz: Excludes key value pairs with int value = 0 Returns: A string that looks like this: aardvark: banana monkey: apple ant: pear """ strings = [] longest_key_len = len(max(d.keys(), key=len)) if sort: d = dict(sorted(d.items())) for k, v in d.items(): key_len = len(k) diff = longest_key_len - key_len spaces = " " * diff string = f"{k}:{spaces} {v}" if nz: if not isinstance(v, int) or v > 0: strings.append(string) else: strings.append(string) ret = "\n".join(strings) + "\n" return ret # Print iterations progress # https://stackoverflow.com/questions/3173320/text-progress-bar-in-terminal-with-block-characters def print_progress_bar( iteration, total, prefix="", suffix="", decimals=1, length=100, fill="█", printEnd="\r", start=None, ): """ Call in a loop to create terminal progress bar @params: iteration - Required : current iteration (Int) total - Required : total iterations (Int) prefix - Optional : prefix string (Str) suffix - Optional : suffix string (Str) decimals - Optional : positive number of decimals in percent complete (Int) length - Optional : character length of bar (Int) fill - Optional : bar fill character (Str) printEnd - Optional : end character (e.g. "\r", "\r\n") (Str) """ percent = ("{0:." + str(decimals) + "f}").format(100 * (iteration / float(total))) filledLength = int(length * iteration // total) bar = fill * filledLength + "-" * (length - filledLength) if iteration == total: if start is not None: timestr = str(timedelta(seconds=time.time() - start)) suffix = f"{suffix} -- {timestr}" print(f"\r{prefix} |{bar}| {percent}% {suffix}", end=printEnd) # Print New Line on Complete if iteration == total: print()