Tools: Enable uploader.py and waf --upload to work on WSL2

This commit is contained in:
Tom Pittenger 2022-02-02 17:29:16 -08:00 committed by Peter Barker
parent b6a089f90e
commit c60f7bff91
2 changed files with 62 additions and 1 deletions

View File

@ -52,18 +52,74 @@ class upload_fw(Task.Task):
color='BLUE' color='BLUE'
always_run = True always_run = True
def run(self): def run(self):
import platform
upload_tools = self.env.get_flat('UPLOAD_TOOLS') upload_tools = self.env.get_flat('UPLOAD_TOOLS')
upload_port = self.generator.bld.options.upload_port upload_port = self.generator.bld.options.upload_port
src = self.inputs[0] src = self.inputs[0]
# Refer Tools/scripts/macos_remote_upload.sh for details # Refer Tools/scripts/macos_remote_upload.sh for details
if 'AP_OVERRIDE_UPLOAD_CMD' in os.environ: if 'AP_OVERRIDE_UPLOAD_CMD' in os.environ:
cmd = "{} '{}'".format(os.environ['AP_OVERRIDE_UPLOAD_CMD'], src.abspath()) cmd = "{} '{}'".format(os.environ['AP_OVERRIDE_UPLOAD_CMD'], src.abspath())
elif "microsoft-standard-WSL2" in platform.release():
if not self.wsl2_prereq_checks():
return
print("If this takes takes too long here, try power-cycling your hardware\n")
cmd = "{} '{}/uploader.py' '{}'".format('python.exe', upload_tools, src.abspath())
else: else:
cmd = "{} '{}/uploader.py' '{}'".format(self.env.get_flat('PYTHON'), upload_tools, src.abspath()) cmd = "{} '{}/uploader.py' '{}'".format(self.env.get_flat('PYTHON'), upload_tools, src.abspath())
if upload_port is not None: if upload_port is not None:
cmd += " '--port' '%s'" % upload_port cmd += " '--port' '%s'" % upload_port
return self.exec_command(cmd) return self.exec_command(cmd)
def wsl2_prereq_checks(self):
# As of July 2022 WSL2 does not support native USB support. The workaround from Microsoft
# using 'usbipd' does not work due to the following workflow:
#
# 1) connect USB device to Windows computer running WSL2
# 2) device boots into app
# 3) use 'usbipd' from Windows Cmd/PowerShell to determine busid, this is very hard to automate on Windows
# 4) use 'usbipd' from Windows Cmd/PowerShell to attach, this is very hard to automate on Windows
# -- device is now viewable via 'lsusb' but you need sudo to read from it.
# either run 'chmod666 /dev/ttyACM*' or use udev to automate chmod on device connect
# 5) uploader.py detects device, sends reboot command which disconnects the USB port and reboots into
# bootloader (different USB device)
# 6) manually repeat steps 3 & 4
# 7) doing steps 3 and 4 will most likely take several seconds and in many cases the bootloader has
# moved on into the app
#
# Solution: simply call "python.exe" instead of 'python' which magically calls it from the windows
# system using the same absolute path back into the WSL2's user's directory
# Requirements: Windows must have Python3.9.x (NTO 3.10.x) installed and a few packages.
import subprocess
try:
where_python = subprocess.check_output('where.exe python.exe', shell=True, text=True)
except subprocess.CalledProcessError:
#if where.exe can't find the file it returns a non-zero result which throws this exception
where_python = ""
if not where_python or not "\Python\Python" in where_python or "python.exe" not in where_python:
print(self.get_full_wsl2_error_msg("Windows python.exe not found"))
return False
python_version = subprocess.check_output('python.exe --version', shell=True, text=True)
if "3.10." in python_version:
print(self.get_full_wsl2_error_msg("Your Windows %s version is not compatible" % python_version.strip()))
return False
return True
def get_full_wsl2_error_msg(self, error_msg):
return ("""
****************************************
****************************************
WSL2 firmware uploads use the host's Windows Python.exe so it has access to the COM ports.
%s
Please download Windows Installer 3.9.x (not 3.10) from https://www.python.org/downloads/
and make sure to add it to your path during the installation. Once installed, run this
command in Powershell or Command Prompt to install some packages:
pip.exe install empy pyserial
****************************************
****************************************
""" % error_msg)
def exec_command(self, cmd, **kw): def exec_command(self, cmd, **kw):
kw['stdout'] = sys.stdout kw['stdout'] = sys.stdout
return super(upload_fw, self).exec_command(cmd, **kw) return super(upload_fw, self).exec_command(cmd, **kw)

View File

@ -72,6 +72,7 @@ import re
from sys import platform as _platform from sys import platform as _platform
is_WSL = bool("Microsoft" in platform.uname()[2]) is_WSL = bool("Microsoft" in platform.uname()[2])
is_WSL2 = bool("microsoft-standard-WSL2" in platform.release())
# default list of port names to look for autopilots # default list of port names to look for autopilots
default_ports = ['/dev/serial/by-id/usb-Ardu*', default_ports = ['/dev/serial/by-id/usb-Ardu*',
@ -93,6 +94,10 @@ default_ports = ['/dev/serial/by-id/usb-Ardu*',
if "cygwin" in _platform or is_WSL: if "cygwin" in _platform or is_WSL:
default_ports += ['/dev/ttyS*'] default_ports += ['/dev/ttyS*']
if "win32" in _platform:
for com_port in range(1, 255):
default_ports += ['COM' + str(com_port)]
# Detect python version # Detect python version
if sys.version_info[0] < 3: if sys.version_info[0] < 3:
runningPython3 = False runningPython3 = False
@ -1146,7 +1151,7 @@ def main():
args.no_extf) args.no_extf)
except Exception as e: except Exception as e:
if not is_WSL: if not is_WSL and not is_WSL2 and "win32" not in _platform:
# open failed, WSL must cycle through all ttyS* ports quickly but rate limit everything else # open failed, WSL must cycle through all ttyS* ports quickly but rate limit everything else
print("Exception creating uploader: %s" % str(e)) print("Exception creating uploader: %s" % str(e))
time.sleep(0.05) time.sleep(0.05)