55 lines
1.7 KiB
Python
55 lines
1.7 KiB
Python
from __future__ import annotations
|
||
|
||
from pathlib import Path
|
||
from typing import Optional
|
||
|
||
from tkinter import messagebox
|
||
|
||
from .path_utils import get_base_dir
|
||
from .tooling import run_command
|
||
|
||
|
||
def ensure_pyserial(python_cmd: Optional[Path], show_dialog: bool) -> bool:
|
||
try:
|
||
import serial # noqa: F401
|
||
|
||
return True
|
||
except Exception:
|
||
if not show_dialog:
|
||
return False
|
||
if python_cmd is None:
|
||
messagebox.showerror("缺少依赖", "内置环境缺少 pyserial,请重新打包。")
|
||
return False
|
||
if not messagebox.askyesno("缺少依赖", "未检测到 pyserial,是否自动安装?"):
|
||
return False
|
||
cmd = [str(python_cmd), "-m", "pip", "install", "pyserial"]
|
||
code, output = run_command(cmd, cwd=get_base_dir(), stream=False)
|
||
if code != 0:
|
||
messagebox.showerror(
|
||
"安装失败",
|
||
"pyserial 安装失败,请手动执行:\n"
|
||
f"{python_cmd} -m pip install pyserial\n\n{output}",
|
||
)
|
||
return False
|
||
messagebox.showinfo("安装完成", "pyserial 已安装,请重试检测。")
|
||
return True
|
||
|
||
|
||
def list_serial_ports(python_cmd: Optional[Path], show_dialog: bool) -> list[str]:
|
||
if not ensure_pyserial(python_cmd, show_dialog):
|
||
return []
|
||
from serial.tools import list_ports
|
||
|
||
return [p.device for p in list_ports.comports()]
|
||
|
||
|
||
def pick_preferred_port(ports: list[str]) -> str:
|
||
if not ports:
|
||
return ""
|
||
hints = ("wchusbserial", "usbserial", "ttyusb", "ttyacm", "com")
|
||
for hint in hints:
|
||
for port in ports:
|
||
if hint in port.lower():
|
||
return port
|
||
return ports[0]
|