from SCons.Errors import StopError class BlackmagicResolver: BLACKMAGIC_HOSTNAME = "blackmagic.local" def __init__(self, env): self.env = env # On Win: # 'location': '1-5:x.0', 'name': 'COM4', # 'location': '1-5:x.2', 'name': 'COM13', # On Linux: # 'location': '1-1.2:1.0', 'name': 'ttyACM0', # 'location': '1-1.2:1.2', 'name': 'ttyACM1', # On MacOS: # 'location': '0-1.3', 'name': 'cu.usbmodemblackmagic1', # 'location': '0-1.3', 'name': 'cu.usbmodemblackmagic3', def _find_probe(self): import serial.tools.list_ports as list_ports ports = list(list_ports.grep("blackmagic")) if len(ports) == 0: # Blackmagic probe serial port not found, will be handled later pass elif len(ports) > 2: raise StopError("More than one Blackmagic probe found") else: # If you're getting any issues with auto lookup, uncomment this # print("\n".join([f"{p.device} {vars(p)}" for p in ports])) return sorted(ports, key=lambda p: f"{p.location}_{p.name}")[0] # Look up blackmagic probe hostname with dns def _resolve_hostname(self): import socket try: return socket.gethostbyname(self.BLACKMAGIC_HOSTNAME) except socket.gaierror: print("Failed to resolve Blackmagic hostname") return None def get_serial(self): if not (probe := self._find_probe()): return None # print(f"Found Blackmagic probe on {probe.device}") if self.env.subst("$PLATFORM") == "win32": return f"\\\\.\\{probe.device}" return probe.device def get_networked(self): if not (probe := self._resolve_hostname()): return None return f"tcp:{probe}:2345" def __str__(self): # print("distenv blackmagic", self.env.subst("$BLACKMAGIC")) if (blackmagic := self.env.subst("$BLACKMAGIC")) != "auto": return blackmagic # print("Looking for Blackmagic...") if probe := self.get_serial() or self.get_networked(): return probe raise Exception("Please specify BLACKMAGIC=...") def generate(env): env.SetDefault(BLACKMAGIC_ADDR=BlackmagicResolver(env)) def exists(env): return True