initial commit
This commit is contained in:
@@ -0,0 +1,180 @@
|
||||
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,
|
||||
};
|
||||
Reference in New Issue
Block a user