181 lines
5.0 KiB
JavaScript
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,
|
|
};
|