fix: auto-detect devicepod uart ports

This commit is contained in:
Codex
2026-06-02 15:27:31 +08:00
parent 11dc7df502
commit 08fec46af9
@@ -1362,7 +1362,7 @@ async function runKeilDownload(profile, payload = {}) {
}
async function runKeilDownloadWithUartCapture(profile, uv4Path, uv4Args, cwd, payload = {}) {
const uart = resolveUart(profile, payload['capture-uart'] || payload.captureUart, payload);
const uart = await resolveUart(profile, payload['capture-uart'] || payload.captureUart, payload);
const captureDurationMs = Number(payload['capture-duration-ms'] || payload.captureDurationMs || payload['duration-ms'] || payload.durationMs || 8000);
const timeoutMs = Number(payload.timeoutMs || 300000);
const logDir = path.join(stateRoot(profile.__workspaceRoot), 'serial');
@@ -1551,12 +1551,56 @@ async function serialPorts() {
ok('io-probe.ports', { configured: profile.ioInterface?.uart || [], ports, stderr: result.stderr, exitCode: result.exitCode });
}
function resolveUart(profile, uartId, options = {}) {
async function resolveSerialPortNames() {
const script = "[System.IO.Ports.SerialPort]::GetPortNames() | Sort-Object | ConvertTo-Json -Compress";
const result = await runPowerShell(script, 15000);
if (result.exitCode !== 0) return { ports: [], error: shortTail(result.stderr || result.stdout) };
const text = result.stdout.trim();
if (!text) return { ports: [], error: null };
try {
const parsed = JSON.parse(text);
const ports = (Array.isArray(parsed) ? parsed : [parsed]).map((item) => String(item || '').trim()).filter(Boolean);
return { ports, error: null };
} catch (error) {
return { ports: [], error: `unable to parse serial port list: ${error instanceof Error ? error.message : String(error)}` };
}
}
function sameSerialPort(left, right) {
return String(left || '').trim().toUpperCase() === String(right || '').trim().toUpperCase();
}
async function resolveUartPort(configuredPort, options = {}) {
if (options.port) return { port: String(options.port), source: 'explicit-option', configuredPort: configuredPort || null, availablePorts: null, resolutionWarning: null };
const configured = String(configuredPort || '').trim();
const discovery = await resolveSerialPortNames();
const availablePorts = discovery.ports;
if (configured && availablePorts.some((port) => sameSerialPort(port, configured))) {
return { port: configured, source: 'profile', configuredPort: configured, availablePorts, resolutionWarning: null };
}
if (availablePorts.length > 0) {
return {
port: availablePorts[0],
source: configured ? 'host-auto-detected-profile-missing' : 'host-auto-detected',
configuredPort: configured || null,
availablePorts,
resolutionWarning: configured ? `configured UART port ${configured} is not present on this host; using ${availablePorts[0]}` : null,
};
}
return { port: configured, source: configured ? 'profile-unverified' : 'missing', configuredPort: configured || null, availablePorts, resolutionWarning: discovery.error || 'no serial ports detected on this host' };
}
async function resolveUart(profile, uartId, options = {}) {
const normalized = String(uartId || 'uart/1').trim().replace(/\\/gu, '/').replace(/\s*\/\s*/gu, '/').replace(/^\/+/, '');
const item = (profile.ioInterface?.uart || []).find((entry) => entry.id === normalized);
if (!item) throw new Error(`uart profile not found: ${normalized}`);
const resolved = { ...item };
if (options.port) resolved.port = String(options.port);
const portResolution = await resolveUartPort(resolved.port, options);
resolved.port = portResolution.port;
resolved.resolvedPortSource = portResolution.source;
resolved.configuredPort = portResolution.configuredPort;
resolved.availablePorts = portResolution.availablePorts;
if (portResolution.resolutionWarning) resolved.resolutionWarning = portResolution.resolutionWarning;
const baudRate = options['baud-rate'] || options.baudRate;
if (baudRate !== undefined) {
const parsed = Number(baudRate);
@@ -1568,7 +1612,7 @@ function resolveUart(profile, uartId, options = {}) {
async function serialRead(uartId, options) {
const profile = loadProfile();
const uart = resolveUart(profile, uartId, options);
const uart = await resolveUart(profile, uartId, options);
const durationMs = Number(options['duration-ms'] || options.durationMs || 1000);
const script = [
'$ErrorActionPreference = \'Stop\';',
@@ -1593,7 +1637,7 @@ async function serialRead(uartId, options) {
async function serialReadAfterLaunchFlash(uartId, options) {
const profile = loadProfile();
const uart = resolveUart(profile, uartId, options);
const uart = await resolveUart(profile, uartId, options);
const tools = await toolInfo(profile);
if (!tools.pyocd.found) throw new Error('pyOCD executable not found');
const debug = profile.debugInterface || {};
@@ -1660,7 +1704,7 @@ async function serialReadAfterLaunchFlash(uartId, options) {
async function serialWrite(uartId, options) {
const profile = loadProfile();
const uart = resolveUart(profile, uartId, options);
const uart = await resolveUart(profile, uartId, options);
const message = options.hex ? Buffer.from(String(options._[0] || ''), 'hex').toString('binary') : String(options._[0] || '');
const encoded = Buffer.from(message, options.hex ? 'binary' : 'utf8').toString('base64');
const script = [
@@ -1759,7 +1803,7 @@ function serialLineEnding(options) {
async function serialJsonRpc(uartId, options) {
const profile = loadProfile();
const uart = resolveUart(profile, uartId, options);
const uart = await resolveUart(profile, uartId, options);
const request = buildJsonRpcRequest(options);
const ending = serialLineEnding(options);
const requestText = `${JSON.stringify(request)}${ending.text}`;