or run

npx @tessl/cli init
Log in

Version

Tile

Overview

Evals

Files

Files

docs

constants-errors.mddata-transfers.mddescriptors.mddevice-communication.mddevice-management.mdevent-handling.mdindex.mdinterfaces-endpoints.mdwebusb-api.md

constants-errors.mddocs/

0

# Constants and Error Handling

1

2

Constants and error handling provide USB constants, error codes, and exception handling for robust USB applications. This includes USB class codes, transfer types, error constants, and comprehensive error handling patterns.

3

4

## Capabilities

5

6

### LibUSB Exception Handling

7

8

Handle errors and exceptions from libusb operations.

9

10

```typescript { .api }

11

/**

12

* LibUSB Exception class for USB operation errors

13

*/

14

interface LibUSBException extends Error {

15

/** LibUSB error number/code */

16

errno: number;

17

18

/** Error message */

19

message: string;

20

21

/** Error name */

22

name: string;

23

}

24

```

25

26

**Usage Examples:**

27

28

```typescript

29

import { findByIds, LibUSBException } from 'usb';

30

31

function handleUSBErrors() {

32

const device = findByIds(0x1234, 0x5678);

33

if (!device) return;

34

35

try {

36

device.open();

37

38

// Attempt control transfer that might fail

39

device.controlTransfer(0x80, 0x06, 0x0100, 0x0000, 18, (error, data) => {

40

if (error) {

41

console.error('Control transfer failed:');

42

console.error(` Error: ${error.message}`);

43

console.error(` LibUSB Error Code: ${error.errno}`);

44

console.error(` Error Name: ${error.name}`);

45

46

// Handle specific error types

47

handleSpecificError(error);

48

} else {

49

console.log('Control transfer successful');

50

}

51

});

52

53

} catch (error) {

54

console.error('Device operation failed:', error);

55

56

if (error instanceof LibUSBException) {

57

console.error(`LibUSB Error Code: ${error.errno}`);

58

handleSpecificError(error);

59

}

60

} finally {

61

try {

62

device.close();

63

} catch (closeError) {

64

console.warn('Failed to close device:', closeError);

65

}

66

}

67

}

68

69

function handleSpecificError(error: LibUSBException) {

70

switch (error.errno) {

71

case LIBUSB_ERROR_TIMEOUT:

72

console.error('Operation timed out - device may be unresponsive');

73

break;

74

case LIBUSB_ERROR_NO_DEVICE:

75

console.error('Device was disconnected');

76

break;

77

case LIBUSB_ERROR_ACCESS:

78

console.error('Access denied - check permissions or kernel drivers');

79

break;

80

case LIBUSB_ERROR_BUSY:

81

console.error('Resource is busy - device may be in use by another process');

82

break;

83

case LIBUSB_ERROR_NOT_SUPPORTED:

84

console.error('Operation not supported by this device or platform');

85

break;

86

case LIBUSB_ERROR_PIPE:

87

console.error('Pipe error - endpoint may be stalled');

88

break;

89

default:

90

console.error(`Unhandled LibUSB error: ${error.errno}`);

91

}

92

}

93

```

94

95

### USB Error Constants

96

97

Standard libusb error codes for error handling.

98

99

```typescript { .api }

100

/**

101

* LibUSB Error Constants

102

*/

103

104

/** Input/output error */

105

const LIBUSB_ERROR_IO: number;

106

107

/** Invalid parameter */

108

const LIBUSB_ERROR_INVALID_PARAM: number;

109

110

/** Access denied (insufficient permissions) */

111

const LIBUSB_ERROR_ACCESS: number;

112

113

/** No such device (it may have been disconnected) */

114

const LIBUSB_ERROR_NO_DEVICE: number;

115

116

/** Entity not found */

117

const LIBUSB_ERROR_NOT_FOUND: number;

118

119

/** Resource busy */

120

const LIBUSB_ERROR_BUSY: number;

121

122

/** Operation timed out */

123

const LIBUSB_ERROR_TIMEOUT: number;

124

125

/** Overflow */

126

const LIBUSB_ERROR_OVERFLOW: number;

127

128

/** Pipe error */

129

const LIBUSB_ERROR_PIPE: number;

130

131

/** System call interrupted (perhaps due to signal) */

132

const LIBUSB_ERROR_INTERRUPTED: number;

133

134

/** Insufficient memory */

135

const LIBUSB_ERROR_NO_MEM: number;

136

137

/** Operation not supported or unimplemented on this platform */

138

const LIBUSB_ERROR_NOT_SUPPORTED: number;

139

140

/** Other error */

141

const LIBUSB_ERROR_OTHER: number;

142

```

143

144

**Usage Examples:**

145

146

```typescript

147

import {

148

findByIds,

149

LIBUSB_ERROR_TIMEOUT,

150

LIBUSB_ERROR_NO_DEVICE,

151

LIBUSB_ERROR_ACCESS,

152

LIBUSB_ERROR_BUSY,

153

LIBUSB_ERROR_NOT_SUPPORTED,

154

LIBUSB_ERROR_PIPE

155

} from 'usb';

156

157

async function robustDeviceOperation() {

158

const device = findByIds(0x1234, 0x5678);

159

if (!device) {

160

throw new Error('Device not found');

161

}

162

163

let attempts = 0;

164

const maxAttempts = 3;

165

166

while (attempts < maxAttempts) {

167

try {

168

device.open();

169

170

// Perform operation with timeout handling

171

const data = await performTransferWithRetry(device);

172

console.log('Operation successful:', data);

173

174

device.close();

175

return data;

176

177

} catch (error) {

178

attempts++;

179

console.error(`Attempt ${attempts} failed:`, error.message);

180

181

if (error.errno) {

182

switch (error.errno) {

183

case LIBUSB_ERROR_TIMEOUT:

184

console.log('Timeout - retrying with longer timeout');

185

if (attempts < maxAttempts) {

186

await sleep(1000 * attempts); // Progressive delay

187

continue;

188

}

189

break;

190

191

case LIBUSB_ERROR_NO_DEVICE:

192

console.error('Device disconnected - cannot retry');

193

throw error;

194

195

case LIBUSB_ERROR_ACCESS:

196

console.error('Access denied - check permissions');

197

throw error;

198

199

case LIBUSB_ERROR_BUSY:

200

console.log('Device busy - waiting before retry');

201

if (attempts < maxAttempts) {

202

await sleep(2000);

203

continue;

204

}

205

break;

206

207

case LIBUSB_ERROR_PIPE:

208

console.log('Pipe error - attempting to clear halt');

209

try {

210

// Clear halt and retry

211

await clearEndpointHalt(device);

212

continue;

213

} catch (clearError) {

214

console.error('Failed to clear halt:', clearError);

215

}

216

break;

217

218

default:

219

console.error('Unrecoverable error');

220

throw error;

221

}

222

}

223

224

if (attempts >= maxAttempts) {

225

throw new Error(`Operation failed after ${maxAttempts} attempts`);

226

}

227

}

228

}

229

}

230

231

function sleep(ms: number): Promise<void> {

232

return new Promise(resolve => setTimeout(resolve, ms));

233

}

234

```

235

236

### USB Class Constants

237

238

USB device and interface class codes.

239

240

```typescript { .api }

241

/**

242

* USB Class Constants

243

*/

244

245

/** Each interface specifies its own class information */

246

const LIBUSB_CLASS_PER_INTERFACE: number;

247

248

/** Audio class */

249

const LIBUSB_CLASS_AUDIO: number;

250

251

/** Communications class */

252

const LIBUSB_CLASS_COMM: number;

253

254

/** Human Interface Device class */

255

const LIBUSB_CLASS_HID: number;

256

257

/** Printer class */

258

const LIBUSB_CLASS_PRINTER: number;

259

260

/** Image class */

261

const LIBUSB_CLASS_PTP: number;

262

263

/** Mass storage class */

264

const LIBUSB_CLASS_MASS_STORAGE: number;

265

266

/** Hub class */

267

const LIBUSB_CLASS_HUB: number;

268

269

/** Data class */

270

const LIBUSB_CLASS_DATA: number;

271

272

/** Wireless class */

273

const LIBUSB_CLASS_WIRELESS: number;

274

275

/** Application class */

276

const LIBUSB_CLASS_APPLICATION: number;

277

278

/** Class is vendor-specific */

279

const LIBUSB_CLASS_VENDOR_SPEC: number;

280

```

281

282

**Usage Examples:**

283

284

```typescript

285

import {

286

getDeviceList,

287

LIBUSB_CLASS_HID,

288

LIBUSB_CLASS_MASS_STORAGE,

289

LIBUSB_CLASS_AUDIO,

290

LIBUSB_CLASS_HUB,

291

LIBUSB_CLASS_VENDOR_SPEC

292

} from 'usb';

293

294

function categorizeDevicesByClass() {

295

const devices = getDeviceList();

296

const devicesByClass: { [key: string]: Device[] } = {};

297

298

devices.forEach(device => {

299

const deviceClass = device.deviceDescriptor.bDeviceClass;

300

const className = getClassNameFromCode(deviceClass);

301

302

if (!devicesByClass[className]) {

303

devicesByClass[className] = [];

304

}

305

306

devicesByClass[className].push(device);

307

});

308

309

// Display results

310

Object.entries(devicesByClass).forEach(([className, devices]) => {

311

console.log(`${className} devices: ${devices.length}`);

312

devices.forEach(device => {

313

console.log(` VID:PID = ${device.deviceDescriptor.idVendor.toString(16)}:${device.deviceDescriptor.idProduct.toString(16)}`);

314

});

315

});

316

317

return devicesByClass;

318

}

319

320

function getClassNameFromCode(classCode: number): string {

321

switch (classCode) {

322

case LIBUSB_CLASS_AUDIO:

323

return 'Audio';

324

case LIBUSB_CLASS_COMM:

325

return 'Communications';

326

case LIBUSB_CLASS_HID:

327

return 'HID';

328

case LIBUSB_CLASS_PRINTER:

329

return 'Printer';

330

case LIBUSB_CLASS_PTP:

331

return 'Image/PTP';

332

case LIBUSB_CLASS_MASS_STORAGE:

333

return 'Mass Storage';

334

case LIBUSB_CLASS_HUB:

335

return 'Hub';

336

case LIBUSB_CLASS_DATA:

337

return 'Data';

338

case LIBUSB_CLASS_WIRELESS:

339

return 'Wireless';

340

case LIBUSB_CLASS_APPLICATION:

341

return 'Application';

342

case LIBUSB_CLASS_VENDOR_SPEC:

343

return 'Vendor Specific';

344

case LIBUSB_CLASS_PER_INTERFACE:

345

return 'Per Interface';

346

default:

347

return 'Unknown';

348

}

349

}

350

351

// Find specific device types

352

function findHIDDevices() {

353

const devices = getDeviceList();

354

return devices.filter(device =>

355

device.deviceDescriptor.bDeviceClass === LIBUSB_CLASS_HID

356

);

357

}

358

359

function findMassStorageDevices() {

360

const devices = getDeviceList();

361

return devices.filter(device =>

362

device.deviceDescriptor.bDeviceClass === LIBUSB_CLASS_MASS_STORAGE

363

);

364

}

365

```

366

367

### Transfer Type Constants

368

369

USB transfer type constants for endpoint configuration.

370

371

```typescript { .api }

372

/**

373

* Transfer Type Constants

374

*/

375

376

/** Control endpoint */

377

const LIBUSB_TRANSFER_TYPE_CONTROL: number;

378

379

/** Isochronous endpoint */

380

const LIBUSB_TRANSFER_TYPE_ISOCHRONOUS: number;

381

382

/** Bulk endpoint */

383

const LIBUSB_TRANSFER_TYPE_BULK: number;

384

385

/** Interrupt endpoint */

386

const LIBUSB_TRANSFER_TYPE_INTERRUPT: number;

387

```

388

389

**Usage Examples:**

390

391

```typescript

392

import {

393

findByIds,

394

LIBUSB_TRANSFER_TYPE_CONTROL,

395

LIBUSB_TRANSFER_TYPE_BULK,

396

LIBUSB_TRANSFER_TYPE_INTERRUPT,

397

LIBUSB_TRANSFER_TYPE_ISOCHRONOUS

398

} from 'usb';

399

400

function analyzeEndpointTypes() {

401

const device = findByIds(0x1234, 0x5678);

402

if (!device) return;

403

404

device.open();

405

406

try {

407

const interface0 = device.interface(0);

408

interface0.claim();

409

410

console.log('Endpoint Analysis:');

411

interface0.endpoints.forEach((endpoint, index) => {

412

const transferType = endpoint.transferType;

413

const typeName = getTransferTypeName(transferType);

414

415

console.log(` Endpoint ${index} (0x${endpoint.address.toString(16)}):`);

416

console.log(` Transfer Type: ${typeName}`);

417

console.log(` Direction: ${endpoint.direction}`);

418

console.log(` Max Packet Size: ${endpoint.descriptor.wMaxPacketSize}`);

419

420

// Provide recommendations based on transfer type

421

switch (transferType) {

422

case LIBUSB_TRANSFER_TYPE_BULK:

423

console.log(` Recommended for: Large data transfers, file transfers`);

424

console.log(` Characteristics: Reliable, error correction, no guaranteed timing`);

425

break;

426

427

case LIBUSB_TRANSFER_TYPE_INTERRUPT:

428

console.log(` Recommended for: Small, periodic data, HID reports`);

429

console.log(` Characteristics: Guaranteed timing, error correction`);

430

console.log(` Polling interval: ${endpoint.descriptor.bInterval}ms`);

431

break;

432

433

case LIBUSB_TRANSFER_TYPE_ISOCHRONOUS:

434

console.log(` Recommended for: Audio/video streaming`);

435

console.log(` Characteristics: Guaranteed timing, no error correction`);

436

break;

437

438

case LIBUSB_TRANSFER_TYPE_CONTROL:

439

console.log(` Recommended for: Device configuration, commands`);

440

console.log(` Characteristics: Reliable, structured format`);

441

break;

442

}

443

});

444

445

interface0.release(() => {});

446

} finally {

447

device.close();

448

}

449

}

450

451

function getTransferTypeName(transferType: number): string {

452

switch (transferType) {

453

case LIBUSB_TRANSFER_TYPE_CONTROL:

454

return 'Control';

455

case LIBUSB_TRANSFER_TYPE_ISOCHRONOUS:

456

return 'Isochronous';

457

case LIBUSB_TRANSFER_TYPE_BULK:

458

return 'Bulk';

459

case LIBUSB_TRANSFER_TYPE_INTERRUPT:

460

return 'Interrupt';

461

default:

462

return 'Unknown';

463

}

464

}

465

```

466

467

### Transfer Status Constants

468

469

USB transfer completion status codes.

470

471

```typescript { .api }

472

/**

473

* Transfer Status Constants

474

*/

475

476

/** Transfer completed without error */

477

const LIBUSB_TRANSFER_COMPLETED: number;

478

479

/** Transfer failed */

480

const LIBUSB_TRANSFER_ERROR: number;

481

482

/** Transfer timed out */

483

const LIBUSB_TRANSFER_TIMED_OUT: number;

484

485

/** Transfer was cancelled */

486

const LIBUSB_TRANSFER_CANCELLED: number;

487

488

/** Halt condition detected (endpoint stalled) or control request not supported */

489

const LIBUSB_TRANSFER_STALL: number;

490

491

/** Device was disconnected */

492

const LIBUSB_TRANSFER_NO_DEVICE: number;

493

494

/** Device sent more data than requested */

495

const LIBUSB_TRANSFER_OVERFLOW: number;

496

```

497

498

**Usage Examples:**

499

500

```typescript

501

import {

502

findByIds,

503

LIBUSB_TRANSFER_COMPLETED,

504

LIBUSB_TRANSFER_ERROR,

505

LIBUSB_TRANSFER_TIMED_OUT,

506

LIBUSB_TRANSFER_CANCELLED,

507

LIBUSB_TRANSFER_STALL,

508

LIBUSB_TRANSFER_NO_DEVICE,

509

LIBUSB_TRANSFER_OVERFLOW

510

} from 'usb';

511

512

function handleTransferStatus() {

513

const device = findByIds(0x1234, 0x5678);

514

if (!device) return;

515

516

device.open();

517

518

try {

519

const interface0 = device.interface(0);

520

interface0.claim();

521

522

const inEndpoint = interface0.endpoints.find(ep => ep.direction === 'in');

523

if (inEndpoint) {

524

// Create transfer with detailed status handling

525

const transfer = inEndpoint.makeTransfer(5000, (error, buffer, actualLength) => {

526

if (error) {

527

console.error('Transfer failed:', error.message);

528

console.error('LibUSB Error Code:', error.errno);

529

530

// Handle transfer-specific errors

531

switch (error.errno) {

532

case LIBUSB_TRANSFER_TIMED_OUT:

533

console.error('Transfer timed out - device may be slow or unresponsive');

534

break;

535

536

case LIBUSB_TRANSFER_STALL:

537

console.error('Endpoint stalled - may need to clear halt');

538

// Clear halt and retry

539

inEndpoint.clearHalt((clearError) => {

540

if (!clearError) {

541

console.log('Halt cleared, can retry transfer');

542

}

543

});

544

break;

545

546

case LIBUSB_TRANSFER_NO_DEVICE:

547

console.error('Device disconnected during transfer');

548

break;

549

550

case LIBUSB_TRANSFER_OVERFLOW:

551

console.error('Device sent more data than expected');

552

break;

553

554

case LIBUSB_TRANSFER_CANCELLED:

555

console.log('Transfer was cancelled');

556

break;

557

558

default:

559

console.error('Unknown transfer error');

560

}

561

} else {

562

console.log(`Transfer completed successfully: ${actualLength} bytes`);

563

564

if (actualLength < buffer.length) {

565

console.log('Short transfer - received less data than buffer size');

566

}

567

568

console.log('Data:', buffer.slice(0, actualLength).toString('hex'));

569

}

570

});

571

572

// Submit transfer

573

const buffer = Buffer.alloc(64);

574

transfer.submit(buffer);

575

576

// Cancel transfer after 2 seconds for demonstration

577

setTimeout(() => {

578

const cancelled = transfer.cancel();

579

if (cancelled) {

580

console.log('Transfer cancellation requested');

581

}

582

}, 2000);

583

}

584

585

interface0.release(() => {});

586

} finally {

587

device.close();

588

}

589

}

590

```

591

592

### Endpoint Direction Constants

593

594

Endpoint direction constants for transfer operations.

595

596

```typescript { .api }

597

/**

598

* Endpoint Direction Constants

599

*/

600

601

/** IN: device-to-host */

602

const LIBUSB_ENDPOINT_IN: number;

603

604

/** OUT: host-to-device */

605

const LIBUSB_ENDPOINT_OUT: number;

606

```

607

608

**Usage Examples:**

609

610

```typescript

611

import {

612

findByIds,

613

LIBUSB_ENDPOINT_IN,

614

LIBUSB_ENDPOINT_OUT

615

} from 'usb';

616

617

function demonstrateEndpointDirections() {

618

const device = findByIds(0x1234, 0x5678);

619

if (!device) return;

620

621

device.open();

622

623

try {

624

const interface0 = device.interface(0);

625

interface0.claim();

626

627

// Find endpoints by direction

628

const inEndpoints = interface0.endpoints.filter(ep => ep.direction === 'in');

629

const outEndpoints = interface0.endpoints.filter(ep => ep.direction === 'out');

630

631

console.log(`Found ${inEndpoints.length} IN endpoints and ${outEndpoints.length} OUT endpoints`);

632

633

// Demonstrate control transfer with direction

634

const bmRequestTypeIn = LIBUSB_ENDPOINT_IN | 0x00 | 0x80; // Standard, device, IN

635

device.controlTransfer(bmRequestTypeIn, 0x06, 0x0100, 0x0000, 18, (error, data) => {

636

if (!error && data) {

637

console.log('IN control transfer successful');

638

}

639

});

640

641

const bmRequestTypeOut = LIBUSB_ENDPOINT_OUT | 0x00 | 0x00; // Standard, device, OUT

642

const outData = Buffer.from([0x01, 0x02, 0x03]);

643

device.controlTransfer(bmRequestTypeOut, 0x09, 0x0001, 0x0000, outData, (error, bytesWritten) => {

644

if (!error) {

645

console.log('OUT control transfer successful');

646

}

647

});

648

649

interface0.release(() => {});

650

} finally {

651

device.close();

652

}

653

}

654

655

// Helper function to determine endpoint direction from address

656

function getEndpointDirection(endpointAddress: number): 'in' | 'out' {

657

return (endpointAddress & LIBUSB_ENDPOINT_IN) ? 'in' : 'out';

658

}

659

660

// Create endpoint address with direction

661

function createEndpointAddress(endpointNumber: number, direction: 'in' | 'out'): number {

662

const directionBit = direction === 'in' ? LIBUSB_ENDPOINT_IN : LIBUSB_ENDPOINT_OUT;

663

return (endpointNumber & 0x7F) | directionBit;

664

}

665

```

666

667

### Request Type Constants

668

669

USB request type constants for control transfers.

670

671

```typescript { .api }

672

/**

673

* Request Type Constants

674

*/

675

676

/** Standard request */

677

const LIBUSB_REQUEST_TYPE_STANDARD: number;

678

679

/** Class-specific request */

680

const LIBUSB_REQUEST_TYPE_CLASS: number;

681

682

/** Vendor-specific request */

683

const LIBUSB_REQUEST_TYPE_VENDOR: number;

684

685

/** Reserved request type */

686

const LIBUSB_REQUEST_TYPE_RESERVED: number;

687

688

/**

689

* Request Recipient Constants

690

*/

691

692

/** Device recipient */

693

const LIBUSB_RECIPIENT_DEVICE: number;

694

695

/** Interface recipient */

696

const LIBUSB_RECIPIENT_INTERFACE: number;

697

698

/** Endpoint recipient */

699

const LIBUSB_RECIPIENT_ENDPOINT: number;

700

701

/** Other recipient */

702

const LIBUSB_RECIPIENT_OTHER: number;

703

```

704

705

**Usage Examples:**

706

707

```typescript

708

import {

709

findByIds,

710

LIBUSB_ENDPOINT_IN,

711

LIBUSB_ENDPOINT_OUT,

712

LIBUSB_REQUEST_TYPE_STANDARD,

713

LIBUSB_REQUEST_TYPE_CLASS,

714

LIBUSB_REQUEST_TYPE_VENDOR,

715

LIBUSB_RECIPIENT_DEVICE,

716

LIBUSB_RECIPIENT_INTERFACE,

717

LIBUSB_RECIPIENT_ENDPOINT

718

} from 'usb';

719

720

function demonstrateControlTransferTypes() {

721

const device = findByIds(0x1234, 0x5678);

722

if (!device) return;

723

724

device.open();

725

726

try {

727

// Standard device request - Get device descriptor

728

const standardRequest = LIBUSB_ENDPOINT_IN | LIBUSB_REQUEST_TYPE_STANDARD | LIBUSB_RECIPIENT_DEVICE;

729

device.controlTransfer(standardRequest, 0x06, 0x0100, 0x0000, 18, (error, data) => {

730

if (!error && data) {

731

console.log('Standard device request successful');

732

console.log('Device descriptor received:', data.length, 'bytes');

733

}

734

});

735

736

// Vendor-specific request

737

const vendorRequest = LIBUSB_ENDPOINT_IN | LIBUSB_REQUEST_TYPE_VENDOR | LIBUSB_RECIPIENT_DEVICE;

738

device.controlTransfer(vendorRequest, 0x01, 0x0000, 0x0000, 64, (error, data) => {

739

if (!error && data) {

740

console.log('Vendor-specific request successful');

741

} else if (error) {

742

console.log('Vendor request not supported (expected for most devices)');

743

}

744

});

745

746

// Class-specific interface request (example for HID)

747

const classRequest = LIBUSB_ENDPOINT_IN | LIBUSB_REQUEST_TYPE_CLASS | LIBUSB_RECIPIENT_INTERFACE;

748

device.controlTransfer(classRequest, 0x01, 0x0000, 0x0000, 8, (error, data) => {

749

if (!error && data) {

750

console.log('Class-specific interface request successful');

751

} else if (error) {

752

console.log('Class request not applicable for this device');

753

}

754

});

755

756

// Endpoint-specific request - Clear halt

757

const endpointRequest = LIBUSB_ENDPOINT_OUT | LIBUSB_REQUEST_TYPE_STANDARD | LIBUSB_RECIPIENT_ENDPOINT;

758

device.controlTransfer(endpointRequest, 0x01, 0x0000, 0x0081, 0, (error) => {

759

if (!error) {

760

console.log('Clear halt request successful');

761

} else {

762

console.log('Clear halt not needed or failed');

763

}

764

});

765

766

} finally {

767

device.close();

768

}

769

}

770

771

// Helper function to build request type byte

772

function buildRequestType(direction: 'in' | 'out', type: 'standard' | 'class' | 'vendor', recipient: 'device' | 'interface' | 'endpoint' | 'other'): number {

773

let requestType = 0;

774

775

// Direction

776

if (direction === 'in') {

777

requestType |= LIBUSB_ENDPOINT_IN;

778

}

779

780

// Type

781

switch (type) {

782

case 'standard':

783

requestType |= LIBUSB_REQUEST_TYPE_STANDARD;

784

break;

785

case 'class':

786

requestType |= LIBUSB_REQUEST_TYPE_CLASS;

787

break;

788

case 'vendor':

789

requestType |= LIBUSB_REQUEST_TYPE_VENDOR;

790

break;

791

}

792

793

// Recipient

794

switch (recipient) {

795

case 'device':

796

requestType |= LIBUSB_RECIPIENT_DEVICE;

797

break;

798

case 'interface':

799

requestType |= LIBUSB_RECIPIENT_INTERFACE;

800

break;

801

case 'endpoint':

802

requestType |= LIBUSB_RECIPIENT_ENDPOINT;

803

break;

804

case 'other':

805

requestType |= LIBUSB_RECIPIENT_OTHER;

806

break;

807

}

808

809

return requestType;

810

}

811

812

// Usage example

813

function sendVendorCommand() {

814

const device = findByIds(0x1234, 0x5678);

815

if (!device) return;

816

817

device.open();

818

819

try {

820

// Build vendor-specific device OUT request

821

const requestType = buildRequestType('out', 'vendor', 'device');

822

const commandData = Buffer.from([0x12, 0x34, 0x56, 0x78]);

823

824

device.controlTransfer(requestType, 0x42, 0x1234, 0x0000, commandData, (error, bytesWritten) => {

825

if (!error) {

826

console.log(`Vendor command sent: ${bytesWritten} bytes`);

827

} else {

828

console.error('Vendor command failed:', error.message);

829

}

830

});

831

832

} finally {

833

device.close();

834

}

835

}

836

```