0
# Descriptors and Metadata
1
2
Descriptors and metadata provide access to USB descriptors to understand device capabilities, configuration, and structure. This includes device descriptors, configuration descriptors, interface descriptors, endpoint descriptors, and Binary Object Store (BOS) descriptors.
3
4
## Capabilities
5
6
### Device Descriptors
7
8
Access device-level information and characteristics.
9
10
```typescript { .api }
11
/**
12
* USB Device Descriptor - describes device characteristics
13
*/
14
interface DeviceDescriptor {
15
/** Size of this descriptor (in bytes) */
16
bLength: number;
17
18
/** Descriptor type (should be LIBUSB_DT_DEVICE = 1) */
19
bDescriptorType: number;
20
21
/** USB specification release number in binary-coded decimal */
22
bcdUSB: number;
23
24
/** USB-IF class code for the device */
25
bDeviceClass: number;
26
27
/** USB-IF subclass code for the device, qualified by bDeviceClass */
28
bDeviceSubClass: number;
29
30
/** USB-IF protocol code for the device, qualified by bDeviceClass and bDeviceSubClass */
31
bDeviceProtocol: number;
32
33
/** Maximum packet size for endpoint 0 */
34
bMaxPacketSize0: number;
35
36
/** USB-IF vendor ID */
37
idVendor: number;
38
39
/** USB-IF product ID */
40
idProduct: number;
41
42
/** Device release number in binary-coded decimal */
43
bcdDevice: number;
44
45
/** Index of string descriptor describing manufacturer */
46
iManufacturer: number;
47
48
/** Index of string descriptor describing product */
49
iProduct: number;
50
51
/** Index of string descriptor containing device serial number */
52
iSerialNumber: number;
53
54
/** Number of possible configurations */
55
bNumConfigurations: number;
56
}
57
```
58
59
**Usage Examples:**
60
61
```typescript
62
import { getDeviceList } from 'usb';
63
64
// Analyze device descriptors
65
function analyzeDeviceDescriptors() {
66
const devices = getDeviceList();
67
68
devices.forEach((device, index) => {
69
const desc = device.deviceDescriptor;
70
71
console.log(`Device ${index}:`);
72
console.log(` Descriptor Length: ${desc.bLength}`);
73
console.log(` Descriptor Type: ${desc.bDescriptorType}`);
74
75
// Decode USB version
76
const usbMajor = (desc.bcdUSB >> 8) & 0xFF;
77
const usbMinor = (desc.bcdUSB >> 4) & 0x0F;
78
const usbSub = desc.bcdUSB & 0x0F;
79
console.log(` USB Version: ${usbMajor}.${usbMinor}.${usbSub}`);
80
81
console.log(` Device Class: ${desc.bDeviceClass} (${getDeviceClassName(desc.bDeviceClass)})`);
82
console.log(` Device Subclass: ${desc.bDeviceSubClass}`);
83
console.log(` Device Protocol: ${desc.bDeviceProtocol}`);
84
console.log(` Max Packet Size (EP0): ${desc.bMaxPacketSize0}`);
85
86
console.log(` Vendor ID: 0x${desc.idVendor.toString(16).padStart(4, '0')}`);
87
console.log(` Product ID: 0x${desc.idProduct.toString(16).padStart(4, '0')}`);
88
89
// Decode device version
90
const deviceMajor = (desc.bcdDevice >> 8) & 0xFF;
91
const deviceMinor = (desc.bcdDevice >> 4) & 0x0F;
92
const deviceSub = desc.bcdDevice & 0x0F;
93
console.log(` Device Version: ${deviceMajor}.${deviceMinor}.${deviceSub}`);
94
95
console.log(` Manufacturer String Index: ${desc.iManufacturer}`);
96
console.log(` Product String Index: ${desc.iProduct}`);
97
console.log(` Serial Number String Index: ${desc.iSerialNumber}`);
98
console.log(` Number of Configurations: ${desc.bNumConfigurations}`);
99
console.log('');
100
});
101
}
102
103
function getDeviceClassName(classCode: number): string {
104
const classNames: { [key: number]: string } = {
105
0: 'Per Interface',
106
1: 'Audio',
107
2: 'Communications',
108
3: 'HID',
109
5: 'Physical',
110
6: 'Image',
111
7: 'Printer',
112
8: 'Mass Storage',
113
9: 'Hub',
114
10: 'CDC Data',
115
11: 'Smart Card',
116
13: 'Content Security',
117
14: 'Video',
118
15: 'Personal Healthcare',
119
16: 'Audio/Video',
120
17: 'Billboard',
121
18: 'USB Type-C Bridge',
122
220: 'Diagnostic',
123
224: 'Wireless',
124
239: 'Miscellaneous',
125
254: 'Application Specific',
126
255: 'Vendor Specific'
127
};
128
129
return classNames[classCode] || 'Unknown';
130
}
131
132
// Get device strings from descriptor indices
133
async function getDeviceStrings(device: Device) {
134
const desc = device.deviceDescriptor;
135
const strings: any = {};
136
137
device.open();
138
139
try {
140
// Get manufacturer string
141
if (desc.iManufacturer > 0) {
142
strings.manufacturer = await new Promise<string>((resolve, reject) => {
143
device.getStringDescriptor(desc.iManufacturer, (error, value) => {
144
if (error) reject(error);
145
else resolve(value || '');
146
});
147
});
148
}
149
150
// Get product string
151
if (desc.iProduct > 0) {
152
strings.product = await new Promise<string>((resolve, reject) => {
153
device.getStringDescriptor(desc.iProduct, (error, value) => {
154
if (error) reject(error);
155
else resolve(value || '');
156
});
157
});
158
}
159
160
// Get serial number string
161
if (desc.iSerialNumber > 0) {
162
strings.serialNumber = await new Promise<string>((resolve, reject) => {
163
device.getStringDescriptor(desc.iSerialNumber, (error, value) => {
164
if (error) reject(error);
165
else resolve(value || '');
166
});
167
});
168
}
169
170
} catch (error) {
171
console.warn('Could not retrieve some string descriptors:', error);
172
} finally {
173
device.close();
174
}
175
176
return strings;
177
}
178
```
179
180
### Configuration Descriptors
181
182
Access device configuration information and interface layout.
183
184
```typescript { .api }
185
/**
186
* USB Configuration Descriptor - describes device configuration
187
*/
188
interface ConfigDescriptor {
189
/** Size of this descriptor (in bytes) */
190
bLength: number;
191
192
/** Descriptor type (should be LIBUSB_DT_CONFIG = 2) */
193
bDescriptorType: number;
194
195
/** Total length of data returned for this configuration */
196
wTotalLength: number;
197
198
/** Number of interfaces supported by this configuration */
199
bNumInterfaces: number;
200
201
/** Identifier value for this configuration */
202
bConfigurationValue: number;
203
204
/** Index of string descriptor describing this configuration */
205
iConfiguration: number;
206
207
/** Configuration characteristics */
208
bmAttributes: number;
209
210
/** Maximum power consumption from bus in this configuration (in 2mA units) */
211
bMaxPower: number;
212
213
/** Extra descriptors */
214
extra: Buffer;
215
216
/** Array of interfaces supported by this configuration */
217
interfaces: InterfaceDescriptor[][];
218
}
219
```
220
221
**Usage Examples:**
222
223
```typescript
224
import { findByIds } from 'usb';
225
226
async function analyzeConfiguration() {
227
const device = findByIds(0x1234, 0x5678);
228
if (!device) return;
229
230
device.open();
231
232
try {
233
// Get current configuration descriptor
234
const configDesc = device.configDescriptor;
235
if (configDesc) {
236
console.log('Configuration Descriptor:');
237
console.log(` Length: ${configDesc.bLength}`);
238
console.log(` Type: ${configDesc.bDescriptorType}`);
239
console.log(` Total Length: ${configDesc.wTotalLength}`);
240
console.log(` Number of Interfaces: ${configDesc.bNumInterfaces}`);
241
console.log(` Configuration Value: ${configDesc.bConfigurationValue}`);
242
console.log(` Configuration String Index: ${configDesc.iConfiguration}`);
243
244
// Decode attributes
245
const attributes = configDesc.bmAttributes;
246
console.log(` Attributes: 0x${attributes.toString(16)}`);
247
console.log(` Self Powered: ${(attributes & 0x40) ? 'Yes' : 'No'}`);
248
console.log(` Remote Wakeup: ${(attributes & 0x20) ? 'Yes' : 'No'}`);
249
250
console.log(` Max Power: ${configDesc.bMaxPower * 2}mA`);
251
console.log(` Extra Descriptors: ${configDesc.extra.length} bytes`);
252
253
// Analyze interfaces
254
configDesc.interfaces.forEach((interfaceGroup, groupIndex) => {
255
console.log(` Interface Group ${groupIndex}:`);
256
interfaceGroup.forEach((altSetting, altIndex) => {
257
console.log(` Alternate Setting ${altIndex}:`);
258
console.log(` Interface Number: ${altSetting.bInterfaceNumber}`);
259
console.log(` Alternate Setting: ${altSetting.bAlternateSetting}`);
260
console.log(` Interface Class: ${altSetting.bInterfaceClass}`);
261
console.log(` Interface Subclass: ${altSetting.bInterfaceSubClass}`);
262
console.log(` Interface Protocol: ${altSetting.bInterfaceProtocol}`);
263
console.log(` Number of Endpoints: ${altSetting.bNumEndpoints}`);
264
});
265
});
266
}
267
268
// Get all configuration descriptors
269
const allConfigs = device.allConfigDescriptors;
270
console.log(`\nDevice has ${allConfigs.length} configuration(s):`);
271
272
allConfigs.forEach((config, index) => {
273
console.log(`Configuration ${index}:`);
274
console.log(` Value: ${config.bConfigurationValue}`);
275
console.log(` Interfaces: ${config.bNumInterfaces}`);
276
console.log(` Power: ${config.bMaxPower * 2}mA`);
277
278
if (config.iConfiguration > 0) {
279
device.getStringDescriptor(config.iConfiguration, (error, configName) => {
280
if (!error && configName) {
281
console.log(` Name: ${configName}`);
282
}
283
});
284
}
285
});
286
287
} finally {
288
device.close();
289
}
290
}
291
292
// Find devices with specific configuration characteristics
293
function findDevicesByPowerRequirement(maxPowerMa: number) {
294
const devices = getDeviceList();
295
const matchingDevices: Device[] = [];
296
297
devices.forEach(device => {
298
try {
299
device.open();
300
const configDesc = device.configDescriptor;
301
302
if (configDesc && (configDesc.bMaxPower * 2) <= maxPowerMa) {
303
matchingDevices.push(device);
304
console.log(`Found low-power device: VID:PID = ${device.deviceDescriptor.idVendor.toString(16)}:${device.deviceDescriptor.idProduct.toString(16)}`);
305
console.log(` Power consumption: ${configDesc.bMaxPower * 2}mA`);
306
}
307
308
device.close();
309
} catch (error) {
310
// Skip devices that can't be opened
311
}
312
});
313
314
return matchingDevices;
315
}
316
```
317
318
### Interface Descriptors
319
320
Access interface-level information and endpoint configuration.
321
322
```typescript { .api }
323
/**
324
* USB Interface Descriptor - describes interface characteristics
325
*/
326
interface InterfaceDescriptor {
327
/** Size of this descriptor (in bytes) */
328
bLength: number;
329
330
/** Descriptor type (should be LIBUSB_DT_INTERFACE = 4) */
331
bDescriptorType: number;
332
333
/** Number of this interface */
334
bInterfaceNumber: number;
335
336
/** Value used to select this alternate setting for this interface */
337
bAlternateSetting: number;
338
339
/** Number of endpoints used by this interface (excluding control endpoint) */
340
bNumEndpoints: number;
341
342
/** USB-IF class code for this interface */
343
bInterfaceClass: number;
344
345
/** USB-IF subclass code for this interface, qualified by bInterfaceClass */
346
bInterfaceSubClass: number;
347
348
/** USB-IF protocol code for this interface, qualified by bInterfaceClass and bInterfaceSubClass */
349
bInterfaceProtocol: number;
350
351
/** Index of string descriptor describing this interface */
352
iInterface: number;
353
354
/** Extra descriptors */
355
extra: Buffer;
356
357
/** Array of endpoint descriptors */
358
endpoints: EndpointDescriptor[];
359
}
360
```
361
362
**Usage Examples:**
363
364
```typescript
365
import { findByIds } from 'usb';
366
367
function analyzeInterfaces() {
368
const device = findByIds(0x1234, 0x5678);
369
if (!device) return;
370
371
device.open();
372
373
try {
374
const configDesc = device.configDescriptor;
375
if (!configDesc) return;
376
377
configDesc.interfaces.forEach((interfaceGroup, groupIndex) => {
378
console.log(`Interface Group ${groupIndex}:`);
379
380
interfaceGroup.forEach((ifaceDesc, altIndex) => {
381
console.log(` Alternate Setting ${altIndex}:`);
382
console.log(` Length: ${ifaceDesc.bLength}`);
383
console.log(` Type: ${ifaceDesc.bDescriptorType}`);
384
console.log(` Interface Number: ${ifaceDesc.bInterfaceNumber}`);
385
console.log(` Alternate Setting: ${ifaceDesc.bAlternateSetting}`);
386
console.log(` Number of Endpoints: ${ifaceDesc.bNumEndpoints}`);
387
console.log(` Interface Class: ${ifaceDesc.bInterfaceClass} (${getInterfaceClassName(ifaceDesc.bInterfaceClass)})`);
388
console.log(` Interface Subclass: ${ifaceDesc.bInterfaceSubClass}`);
389
console.log(` Interface Protocol: ${ifaceDesc.bInterfaceProtocol}`);
390
console.log(` Interface String Index: ${ifaceDesc.iInterface}`);
391
console.log(` Extra Descriptors: ${ifaceDesc.extra.length} bytes`);
392
393
// Get interface string if available
394
if (ifaceDesc.iInterface > 0) {
395
device.getStringDescriptor(ifaceDesc.iInterface, (error, interfaceName) => {
396
if (!error && interfaceName) {
397
console.log(` Interface Name: ${interfaceName}`);
398
}
399
});
400
}
401
402
// Analyze endpoints
403
ifaceDesc.endpoints.forEach((endpoint, epIndex) => {
404
console.log(` Endpoint ${epIndex}:`);
405
analyzeEndpointDescriptor(endpoint);
406
});
407
408
console.log('');
409
});
410
});
411
412
} finally {
413
device.close();
414
}
415
}
416
417
function getInterfaceClassName(classCode: number): string {
418
const classNames: { [key: number]: string } = {
419
1: 'Audio',
420
2: 'Communications',
421
3: 'HID',
422
5: 'Physical',
423
6: 'Image',
424
7: 'Printer',
425
8: 'Mass Storage',
426
9: 'Hub',
427
10: 'CDC Data',
428
11: 'Smart Card',
429
13: 'Content Security',
430
14: 'Video',
431
15: 'Personal Healthcare',
432
255: 'Vendor Specific'
433
};
434
435
return classNames[classCode] || 'Unknown';
436
}
437
438
// Find interfaces by class
439
function findInterfacesByClass(targetClass: number) {
440
const devices = getDeviceList();
441
const matchingInterfaces: any[] = [];
442
443
devices.forEach(device => {
444
try {
445
device.open();
446
const configDesc = device.configDescriptor;
447
448
if (configDesc) {
449
configDesc.interfaces.forEach((interfaceGroup, groupIndex) => {
450
interfaceGroup.forEach((ifaceDesc, altIndex) => {
451
if (ifaceDesc.bInterfaceClass === targetClass) {
452
matchingInterfaces.push({
453
device: device,
454
interfaceNumber: ifaceDesc.bInterfaceNumber,
455
alternateSetting: ifaceDesc.bAlternateSetting,
456
descriptor: ifaceDesc
457
});
458
459
console.log(`Found ${getInterfaceClassName(targetClass)} interface:`);
460
console.log(` Device: VID:PID = ${device.deviceDescriptor.idVendor.toString(16)}:${device.deviceDescriptor.idProduct.toString(16)}`);
461
console.log(` Interface: ${ifaceDesc.bInterfaceNumber}, Alt: ${ifaceDesc.bAlternateSetting}`);
462
}
463
});
464
});
465
}
466
467
device.close();
468
} catch (error) {
469
// Skip devices that can't be opened
470
}
471
});
472
473
return matchingInterfaces;
474
}
475
```
476
477
### Endpoint Descriptors
478
479
Access endpoint-level information for data transfer configuration.
480
481
```typescript { .api }
482
/**
483
* USB Endpoint Descriptor - describes endpoint characteristics
484
*/
485
interface EndpointDescriptor {
486
/** Size of this descriptor (in bytes) */
487
bLength: number;
488
489
/** Descriptor type (should be LIBUSB_DT_ENDPOINT = 5) */
490
bDescriptorType: number;
491
492
/** The address of the endpoint described by this descriptor */
493
bEndpointAddress: number;
494
495
/** Attributes which apply to the endpoint when configured using bConfigurationValue */
496
bmAttributes: number;
497
498
/** Maximum packet size this endpoint is capable of sending/receiving */
499
wMaxPacketSize: number;
500
501
/** Interval for polling endpoint for data transfers */
502
bInterval: number;
503
504
/** For audio devices only: the rate at which synchronization feedback is provided */
505
bRefresh: number;
506
507
/** For audio devices only: the address of the synch endpoint */
508
bSynchAddress: number;
509
510
/** Extra descriptors */
511
extra: Buffer;
512
}
513
```
514
515
**Usage Examples:**
516
517
```typescript
518
import { findByIds, LIBUSB_ENDPOINT_IN } from 'usb';
519
520
function analyzeEndpointDescriptor(endpointDesc: EndpointDescriptor) {
521
console.log(` Length: ${endpointDesc.bLength}`);
522
console.log(` Type: ${endpointDesc.bDescriptorType}`);
523
console.log(` Address: 0x${endpointDesc.bEndpointAddress.toString(16)}`);
524
525
// Decode endpoint address
526
const endpointNumber = endpointDesc.bEndpointAddress & 0x7F;
527
const direction = (endpointDesc.bEndpointAddress & LIBUSB_ENDPOINT_IN) ? 'IN' : 'OUT';
528
console.log(` Endpoint Number: ${endpointNumber}`);
529
console.log(` Direction: ${direction}`);
530
531
// Decode attributes
532
const transferType = endpointDesc.bmAttributes & 0x03;
533
const syncType = (endpointDesc.bmAttributes >> 2) & 0x03;
534
const usageType = (endpointDesc.bmAttributes >> 4) & 0x03;
535
536
const transferTypes = ['Control', 'Isochronous', 'Bulk', 'Interrupt'];
537
const syncTypes = ['No Sync', 'Asynchronous', 'Adaptive', 'Synchronous'];
538
const usageTypes = ['Data', 'Feedback', 'Implicit Feedback', 'Reserved'];
539
540
console.log(` Transfer Type: ${transferTypes[transferType] || 'Unknown'}`);
541
if (transferType === 1) { // Isochronous
542
console.log(` Sync Type: ${syncTypes[syncType] || 'Unknown'}`);
543
console.log(` Usage Type: ${usageTypes[usageType] || 'Unknown'}`);
544
}
545
546
console.log(` Max Packet Size: ${endpointDesc.wMaxPacketSize}`);
547
console.log(` Polling Interval: ${endpointDesc.bInterval}`);
548
549
if (endpointDesc.bRefresh > 0) {
550
console.log(` Refresh: ${endpointDesc.bRefresh}`);
551
}
552
553
if (endpointDesc.bSynchAddress > 0) {
554
console.log(` Synch Address: 0x${endpointDesc.bSynchAddress.toString(16)}`);
555
}
556
557
console.log(` Extra Descriptors: ${endpointDesc.extra.length} bytes`);
558
}
559
560
function findEndpointsByType(transferType: number) {
561
const devices = getDeviceList();
562
const matchingEndpoints: any[] = [];
563
564
devices.forEach(device => {
565
try {
566
device.open();
567
const configDesc = device.configDescriptor;
568
569
if (configDesc) {
570
configDesc.interfaces.forEach((interfaceGroup) => {
571
interfaceGroup.forEach((ifaceDesc) => {
572
ifaceDesc.endpoints.forEach((endpoint) => {
573
if ((endpoint.bmAttributes & 0x03) === transferType) {
574
matchingEndpoints.push({
575
device: device,
576
interfaceNumber: ifaceDesc.bInterfaceNumber,
577
endpoint: endpoint
578
});
579
580
const transferTypes = ['Control', 'Isochronous', 'Bulk', 'Interrupt'];
581
console.log(`Found ${transferTypes[transferType]} endpoint:`);
582
console.log(` Device: VID:PID = ${device.deviceDescriptor.idVendor.toString(16)}:${device.deviceDescriptor.idProduct.toString(16)}`);
583
console.log(` Interface: ${ifaceDesc.bInterfaceNumber}`);
584
console.log(` Endpoint: 0x${endpoint.bEndpointAddress.toString(16)}`);
585
console.log(` Max Packet Size: ${endpoint.wMaxPacketSize}`);
586
}
587
});
588
});
589
});
590
}
591
592
device.close();
593
} catch (error) {
594
// Skip devices that can't be opened
595
}
596
});
597
598
return matchingEndpoints;
599
}
600
601
// Analyze endpoint capabilities for optimal transfer settings
602
function analyzeEndpointCapabilities(device: Device, interfaceNumber: number) {
603
device.open();
604
605
try {
606
const interface0 = device.interface(interfaceNumber);
607
const ifaceDesc = interface0.descriptor;
608
609
console.log(`Interface ${interfaceNumber} Endpoint Analysis:`);
610
611
interface0.endpoints.forEach((endpoint, index) => {
612
const desc = endpoint.descriptor;
613
console.log(` Endpoint ${index} (0x${desc.bEndpointAddress.toString(16)}):`);
614
console.log(` Max Packet Size: ${desc.wMaxPacketSize}`);
615
console.log(` Transfer Type: ${endpoint.transferType}`);
616
console.log(` Direction: ${endpoint.direction}`);
617
618
// Calculate optimal transfer settings
619
if (endpoint.direction === 'in') {
620
console.log(` Recommended read size: ${desc.wMaxPacketSize * 8} bytes`);
621
console.log(` Polling interval: ${desc.bInterval}ms`);
622
} else {
623
console.log(` Recommended write chunk: ${desc.wMaxPacketSize} bytes`);
624
}
625
626
// Check for high-speed capabilities
627
if (desc.wMaxPacketSize > 64) {
628
console.log(` High-speed capable (packet size > 64)`);
629
}
630
631
// Isochronous-specific analysis
632
if ((desc.bmAttributes & 0x03) === 1) {
633
const packetsPerFrame = ((desc.wMaxPacketSize >> 11) & 0x03) + 1;
634
const actualPacketSize = desc.wMaxPacketSize & 0x7FF;
635
console.log(` Packets per microframe: ${packetsPerFrame}`);
636
console.log(` Actual packet size: ${actualPacketSize}`);
637
console.log(` Max bandwidth: ${actualPacketSize * packetsPerFrame * 8000} bytes/sec`);
638
}
639
});
640
641
} finally {
642
device.close();
643
}
644
}
645
```
646
647
### Binary Object Store (BOS) Descriptors
648
649
Access advanced device capabilities through BOS descriptors.
650
651
```typescript { .api }
652
/**
653
* Binary Object Store (BOS) Descriptor - describes device capabilities
654
*/
655
interface BosDescriptor {
656
/** Size of this descriptor (in bytes) */
657
bLength: number;
658
659
/** Descriptor type (should be LIBUSB_DT_BOS = 15) */
660
bDescriptorType: number;
661
662
/** Length of this descriptor and all of its sub descriptors */
663
wTotalLength: number;
664
665
/** The number of separate device capability descriptors in the BOS */
666
bNumDeviceCaps: number;
667
668
/** Device Capability Descriptors */
669
capabilities: CapabilityDescriptor[];
670
}
671
672
/**
673
* Generic representation of a BOS Device Capability descriptor
674
*/
675
interface CapabilityDescriptor {
676
/** Size of this descriptor (in bytes) */
677
bLength: number;
678
679
/** Descriptor type (should be DEVICE_CAPABILITY = 16) */
680
bDescriptorType: number;
681
682
/** Device Capability type */
683
bDevCapabilityType: number;
684
685
/** Device Capability data (bLength - 3 bytes) */
686
dev_capability_data: Buffer;
687
}
688
689
/**
690
* Capability class for accessing BOS capabilities
691
*/
692
interface Capability {
693
/** Object with fields from the capability descriptor */
694
descriptor: CapabilityDescriptor;
695
696
/** Integer capability type */
697
type: number;
698
699
/** Buffer capability data */
700
data: Buffer;
701
}
702
```
703
704
**Usage Examples:**
705
706
```typescript
707
import { findByIds } from 'usb';
708
709
async function analyzeBOSDescriptor() {
710
const device = findByIds(0x1234, 0x5678);
711
if (!device) return;
712
713
device.open();
714
715
try {
716
// Get BOS descriptor
717
const bosDescriptor = await new Promise<BosDescriptor | undefined>((resolve, reject) => {
718
device.getBosDescriptor((error, descriptor) => {
719
if (error) reject(error);
720
else resolve(descriptor);
721
});
722
});
723
724
if (bosDescriptor) {
725
console.log('BOS Descriptor:');
726
console.log(` Length: ${bosDescriptor.bLength}`);
727
console.log(` Type: ${bosDescriptor.bDescriptorType}`);
728
console.log(` Total Length: ${bosDescriptor.wTotalLength}`);
729
console.log(` Number of Capabilities: ${bosDescriptor.bNumDeviceCaps}`);
730
731
// Analyze each capability
732
bosDescriptor.capabilities.forEach((capability, index) => {
733
console.log(` Capability ${index}:`);
734
console.log(` Length: ${capability.bLength}`);
735
console.log(` Type: ${capability.bDescriptorType}`);
736
console.log(` Capability Type: ${capability.bDevCapabilityType} (${getCapabilityTypeName(capability.bDevCapabilityType)})`);
737
console.log(` Data Length: ${capability.dev_capability_data.length} bytes`);
738
739
if (capability.dev_capability_data.length > 0) {
740
console.log(` Data: ${capability.dev_capability_data.toString('hex')}`);
741
}
742
});
743
} else {
744
console.log('Device does not have BOS descriptor (USB 2.0 or earlier)');
745
}
746
747
// Get capabilities using Capability class
748
const capabilities = await new Promise<Capability[]>((resolve, reject) => {
749
device.getCapabilities((error, capabilities) => {
750
if (error) reject(error);
751
else resolve(capabilities || []);
752
});
753
});
754
755
console.log(`\nFound ${capabilities.length} capabilities:`);
756
capabilities.forEach((capability, index) => {
757
console.log(`Capability ${index}:`);
758
console.log(` Type: ${capability.type}`);
759
console.log(` Data Length: ${capability.data.length}`);
760
console.log(` Data: ${capability.data.toString('hex')}`);
761
});
762
763
} catch (error) {
764
console.log('Could not retrieve BOS descriptor:', error.message);
765
} finally {
766
device.close();
767
}
768
}
769
770
function getCapabilityTypeName(capabilityType: number): string {
771
const capabilityTypes: { [key: number]: string } = {
772
1: 'Wireless USB',
773
2: 'USB 2.0 Extension',
774
3: 'SuperSpeed USB',
775
4: 'Container ID',
776
5: 'Platform',
777
6: 'Power Delivery Capability',
778
7: 'Battery Info Capability',
779
8: 'PD Consumer Port Capability',
780
9: 'PD Provider Port Capability',
781
10: 'SuperSpeed Plus',
782
11: 'Precision Time Measurement',
783
12: 'Wireless USB Ext'
784
};
785
786
return capabilityTypes[capabilityType] || 'Unknown';
787
}
788
789
// Analyze USB 3.0 SuperSpeed capabilities
790
function analyzeSuperspeedCapabilities(capability: Capability) {
791
if (capability.type === 3) { // SuperSpeed USB capability
792
const data = capability.data;
793
794
if (data.length >= 6) {
795
const bmAttributes = data.readUInt8(0);
796
const wSpeedsSupported = data.readUInt16LE(1);
797
const bFunctionalitySupport = data.readUInt8(3);
798
const bU1DevExitLat = data.readUInt8(4);
799
const bU2DevExitLat = data.readUInt16LE(5);
800
801
console.log('SuperSpeed USB Capability:');
802
console.log(` Attributes: 0x${bmAttributes.toString(16)}`);
803
console.log(` LTM Capable: ${(bmAttributes & 0x02) ? 'Yes' : 'No'}`);
804
console.log(` Speeds Supported: 0x${wSpeedsSupported.toString(16)}`);
805
console.log(` Low Speed: ${(wSpeedsSupported & 0x01) ? 'Yes' : 'No'}`);
806
console.log(` Full Speed: ${(wSpeedsSupported & 0x02) ? 'Yes' : 'No'}`);
807
console.log(` High Speed: ${(wSpeedsSupported & 0x04) ? 'Yes' : 'No'}`);
808
console.log(` SuperSpeed: ${(wSpeedsSupported & 0x08) ? 'Yes' : 'No'}`);
809
console.log(` Functionality Support: ${bFunctionalitySupport}`);
810
console.log(` U1 Device Exit Latency: ${bU1DevExitLat}μs`);
811
console.log(` U2 Device Exit Latency: ${bU2DevExitLat}μs`);
812
}
813
}
814
}
815
816
// Find USB 3.0 capable devices
817
async function findUSB3Devices() {
818
const devices = getDeviceList();
819
const usb3Devices: Device[] = [];
820
821
for (const device of devices) {
822
try {
823
device.open();
824
825
const capabilities = await new Promise<Capability[]>((resolve, reject) => {
826
device.getCapabilities((error, capabilities) => {
827
if (error) reject(error);
828
else resolve(capabilities || []);
829
});
830
});
831
832
const hasSuperspeed = capabilities.some(cap => cap.type === 3);
833
if (hasSuperspeed) {
834
usb3Devices.push(device);
835
console.log(`USB 3.0 device: VID:PID = ${device.deviceDescriptor.idVendor.toString(16)}:${device.deviceDescriptor.idProduct.toString(16)}`);
836
837
// Analyze SuperSpeed capability
838
const sspeedCap = capabilities.find(cap => cap.type === 3);
839
if (sspeedCap) {
840
analyzeSuperspeedCapabilities(sspeedCap);
841
}
842
}
843
844
device.close();
845
} catch (error) {
846
// Skip devices that can't be opened or don't have BOS
847
try { device.close(); } catch {}
848
}
849
}
850
851
return usb3Devices;
852
}
853
```