2026-03-02 00:27:49 -05:00
|
|
|
String normalizeUsbPortName(String portLabel) {
|
|
|
|
|
final separatorIndex = portLabel.indexOf(' - ');
|
|
|
|
|
final normalized = separatorIndex >= 0
|
|
|
|
|
? portLabel.substring(0, separatorIndex)
|
|
|
|
|
: portLabel;
|
|
|
|
|
return normalized.trim();
|
|
|
|
|
}
|
|
|
|
|
|
2026-03-02 19:21:06 -08:00
|
|
|
/// Returns a human-readable name for a serial port label.
|
|
|
|
|
///
|
|
|
|
|
/// The native flserial library encodes port info as a ` - `-separated string:
|
|
|
|
|
/// `"<port> - <description> - <hardware_id>"`
|
|
|
|
|
///
|
|
|
|
|
/// This function extracts the *description* field (index 1) and discards the
|
|
|
|
|
/// raw hardware_id, which is not user-friendly. If the description is missing
|
|
|
|
|
/// or unhelpful (e.g. "n/a"), it falls back to the raw port name.
|
2026-03-02 00:27:49 -05:00
|
|
|
String friendlyUsbPortName(String portLabel) {
|
2026-03-02 19:21:06 -08:00
|
|
|
final parts = portLabel.split(' - ');
|
|
|
|
|
if (parts.length < 2) {
|
2026-03-02 00:27:49 -05:00
|
|
|
return portLabel.trim();
|
|
|
|
|
}
|
2026-03-02 19:21:06 -08:00
|
|
|
// parts[0] = port name, parts[1] = description, parts[2+] = hardware id
|
|
|
|
|
final description = parts[1].trim();
|
|
|
|
|
if (description.isEmpty || description.toLowerCase() == 'n/a') {
|
|
|
|
|
return parts[0].trim();
|
2026-03-02 00:27:49 -05:00
|
|
|
}
|
2026-03-02 19:21:06 -08:00
|
|
|
return description;
|
2026-03-02 00:27:49 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
String describeWebUsbPort({
|
|
|
|
|
required int? vendorId,
|
|
|
|
|
required int? productId,
|
2026-03-02 05:28:31 -05:00
|
|
|
String requestPortLabel = 'Choose USB Device',
|
2026-03-07 12:38:28 -07:00
|
|
|
String fallbackDeviceName = 'Web Serial Device',
|
2026-03-02 00:27:49 -05:00
|
|
|
Map<String, String> knownUsbNames = const <String, String>{},
|
|
|
|
|
}) {
|
|
|
|
|
if (vendorId == null && productId == null) {
|
2026-03-02 05:28:31 -05:00
|
|
|
return requestPortLabel;
|
2026-03-02 00:27:49 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
final vendorHex = vendorId?.toRadixString(16).padLeft(4, '0').toUpperCase();
|
|
|
|
|
final productHex = productId?.toRadixString(16).padLeft(4, '0').toUpperCase();
|
|
|
|
|
final knownName = (vendorHex != null && productHex != null)
|
|
|
|
|
? knownUsbNames['${vendorHex.toLowerCase()}:${productHex.toLowerCase()}']
|
|
|
|
|
: null;
|
|
|
|
|
|
2026-03-07 12:38:28 -07:00
|
|
|
final parts = <String>[knownName ?? fallbackDeviceName];
|
2026-03-02 00:27:49 -05:00
|
|
|
if (vendorHex != null) {
|
|
|
|
|
parts.add('VID:$vendorHex');
|
|
|
|
|
}
|
|
|
|
|
if (productHex != null) {
|
|
|
|
|
parts.add('PID:$productHex');
|
|
|
|
|
}
|
|
|
|
|
return '${parts.first} (${parts.skip(1).join(' ')})';
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
String buildUsbDisplayLabel({
|
|
|
|
|
required String basePortLabel,
|
|
|
|
|
String? deviceName,
|
|
|
|
|
}) {
|
|
|
|
|
final trimmedName = deviceName?.trim() ?? '';
|
|
|
|
|
if (trimmedName.isEmpty) {
|
|
|
|
|
return basePortLabel;
|
|
|
|
|
}
|
|
|
|
|
return '$basePortLabel - $trimmedName';
|
|
|
|
|
}
|