Files
DTM_RTT_Tester/electron/services/jlink/jlinkProbe.cjs
T
2026-05-18 17:36:05 +09:00

181 lines
5.0 KiB
JavaScript

const fs = require('fs');
const os = require('os');
const path = require('path');
const { execFile } = require('child_process');
const { promisify } = require('util');
const {
getJLinkExe,
getNrfjprogExe,
getJLinkDiagnostics,
clearJLinkDiagnosticsCache,
} = require('./jlinkPaths.cjs');
const execFileAsync = promisify(execFile);
const parseShowEmuList = output => {
const probes = [];
const patterns = [
/Serial number:\s*(\d+).*?(?:ProductName|Product name):\s*([^,\r\n]+).*?(?:Connection):\s*([^,\r\n]+)/i,
/Serial number:\s*(\d+).*?(?:ProductName|Product name):\s*([^,\r\n]+)/i,
/Serial number:\s*(\d+)/i,
];
for (const line of output.split(/\r?\n/)) {
if (!/serial number/i.test(line)) continue;
let serialNumber;
let productName = 'J-Link';
let connection = 'USB';
for (const pattern of patterns) {
const match = line.match(pattern);
if (!match) continue;
serialNumber = match[1];
if (match[2]) productName = match[2].trim();
if (match[3]) connection = match[3].trim();
break;
}
if (!serialNumber) continue;
probes.push({
path: serialNumber,
serialNumber,
friendlyName: productName,
manufacturer: 'SEGGER',
connection,
source: 'jlink',
});
}
return probes;
};
const parseNrfjprogIds = output =>
output
.split(/\r?\n/)
.map(line => line.trim())
.filter(line => /^\d+$/.test(line))
.map(serialNumber => ({
path: serialNumber,
serialNumber,
friendlyName: `J-Link (${serialNumber})`,
manufacturer: 'SEGGER',
connection: 'USB',
source: 'nrfjprog',
}));
const listViaJLinkExe = async jlinkExe => {
const scriptPath = path.join(os.tmpdir(), `dtm-jlink-emu-${process.pid}.jlink`);
await fs.promises.writeFile(scriptPath, 'ShowEmuList\nexit\n', 'utf8');
try {
const { stdout, stderr } = await execFileAsync(
jlinkExe,
['-CommandFile', scriptPath, '-nogui', '1'],
{
timeout: 15000,
windowsHide: true,
maxBuffer: 1024 * 1024,
}
);
return parseShowEmuList(`${stdout}\n${stderr}`);
} finally {
await fs.promises.unlink(scriptPath).catch(() => {});
}
};
const listViaNrfjprog = async nrfjprogExe => {
const { stdout, stderr } = await execFileAsync(nrfjprogExe, ['--ids'], {
timeout: 10000,
windowsHide: true,
maxBuffer: 1024 * 1024,
});
return parseNrfjprogIds(`${stdout}\n${stderr}`);
};
const listJLinkProbes = async () => {
clearJLinkDiagnosticsCache();
const jlinkExe = getJLinkExe();
const nrfjprogExe = getNrfjprogExe();
const errors = [];
if (jlinkExe) {
try {
const probes = await listViaJLinkExe(jlinkExe);
if (probes.length > 0) {
return probes;
}
} catch (error) {
errors.push(
error instanceof Error ? error.message : String(error)
);
}
}
if (nrfjprogExe) {
try {
const probes = await listViaNrfjprog(nrfjprogExe);
if (probes.length > 0) {
return probes;
}
} catch (error) {
errors.push(
error instanceof Error ? error.message : String(error)
);
}
}
const diagnostics = getJLinkDiagnostics();
if (!jlinkExe && !nrfjprogExe) {
throw new Error(
'nrfjprog and JLink.exe were not found. Install nRF Command Line Tools or SEGGER J-Link software, or set SEGGER_JLINK_PATH.'
);
}
if (diagnostics.nrfjprogIds.length > 0) {
return parseNrfjprogIds(diagnostics.nrfjprogIds.join('\n'));
}
const detail = errors.length > 0 ? ` (${errors.join('; ')})` : '';
throw new Error(
`No J-Link responded on USB. Plug in the probe, close Ozone or RTT Viewer, then refresh.${detail}`
);
};
const getJLinkSetupHint = () => {
const diagnostics = getJLinkDiagnostics();
if (!diagnostics.gdbServerExe) {
const ids =
diagnostics.nrfjprogIds.length > 0
? ` Detected probe SN: ${diagnostics.nrfjprogIds.join(', ')}.`
: '';
const searched =
diagnostics.installDirectories?.length > 0
? ` Searched: ${diagnostics.installDirectories.slice(0, 4).join('; ')}`
: '';
return (
'RTT needs JLinkGDBServerCL.exe (e.g. C:\\Program Files\\SEGGER\\JLink_V942). Install or set SEGGER_JLINK_PATH.' +
ids +
searched +
' nrfjprog alone is not enough for RTT.'
);
}
return '';
};
module.exports = {
listJLinkProbes,
parseShowEmuList,
parseNrfjprogIds,
getJLinkSetupHint,
};