detectPrinterConfiguration method

Future<Map<String, dynamic>> detectPrinterConfiguration(
  1. int vendorId,
  2. int productId
)

Implementation

Future<Map<String, dynamic>> detectPrinterConfiguration(
    int vendorId, int productId) async {
  final Pointer<libusb_device_handle>? handleNullable =
      openDevice(vendorId, productId);
  if (handleNullable == nullptr || handleNullable == null) {
    return {'success': false, 'error': 'Could not open device'};
  }

  final handle = handleNullable;

  try {
    final device = _bindings.libusb_get_device(handle);

    final deviceDescriptor = calloc<libusb_device_descriptor>();
    final descResult =
        _bindings.libusb_get_device_descriptor(device, deviceDescriptor);
    if (descResult < 0) {
      calloc.free(deviceDescriptor);
      return {
        'success': false,
        'error': 'Could not obtain device descriptor',
        'errorCode': descResult
      };
    }

    final configDescPtr = calloc<Pointer<libusb_config_descriptor>>();
    final configResult =
        _bindings.libusb_get_active_config_descriptor(device, configDescPtr);
    if (configResult < 0) {
      calloc.free(deviceDescriptor);
      calloc.free(configDescPtr);
      return {
        'success': false,
        'error': 'Could not obtain configuration descriptor',
        'errorCode': configResult
      };
    }

    final config = configDescPtr.value;
    final numInterfaces = config.ref.bNumInterfaces;

    Map<String, dynamic> deviceInfo = {
      'vendorId': deviceDescriptor.ref.idVendor,
      'productId': deviceDescriptor.ref.idProduct,
      'deviceClass': deviceDescriptor.ref.bDeviceClass,
      'deviceSubClass': deviceDescriptor.ref.bDeviceSubClass,
      'deviceProtocol': deviceDescriptor.ref.bDeviceProtocol,
      'busNumber': _bindings.libusb_get_bus_number(device),
      'deviceAddress': _bindings.libusb_get_device_address(device),
      'numInterfaces': numInterfaces,
      'interfaces': <Map<String, dynamic>>[]
    };

    for (int i = 0; i < numInterfaces; i++) {
      if (Platform.isLinux || Platform.isMacOS) {
        try {
          final hasKernelDriver =
              _bindings.libusb_kernel_driver_active(handle, i);
          if (hasKernelDriver == 1) {
            _bindings.libusb_detach_kernel_driver(handle, i);
          }
        } catch (e) {
          log("Error checking/detaching kernel driver for interface $i: $e");
        }
      }

      int claimResult = _bindings.libusb_claim_interface(handle, i);
      if (claimResult < 0) {
        log("Could not claim interface $i: $claimResult");
        continue;
      }

      Map<String, dynamic> interfaceInfo = {
        'number': i,
        'canClaim': true,
        'endpoints': <Map<String, dynamic>>[]
      };

      List<int> commonEndpoints = [0x01, 0x02, 0x03, 0x81, 0x82, 0x83];

      for (int epAddress in commonEndpoints) {
        bool isOutput = (epAddress & 0x80) == 0;

        interfaceInfo['endpoints'].add({
          'address': epAddress,
          'type': 'bulk',
          'direction': isOutput ? 'output' : 'input'
        });
      }

      _bindings.libusb_release_interface(handle, i);

      if (Platform.isLinux || Platform.isMacOS) {
        try {
          final hasKernelDriver =
              _bindings.libusb_kernel_driver_active(handle, i);
          if (hasKernelDriver == 1) {
            _bindings.libusb_attach_kernel_driver(handle, i);
          }
        } catch (e) {
          log("Error reconnecting kernel driver for interface $i: $e");
        }
      }

      deviceInfo['interfaces'].add(interfaceInfo);
    }

    _bindings.libusb_free_config_descriptor(config);
    calloc.free(configDescPtr);
    calloc.free(deviceDescriptor);

    return {
      'success': true,
      'deviceInfo': deviceInfo,
      'note':
          'The listed endpoints are common endpoints for printers and may not correspond exactly to the actual endpoints of the device.'
    };
  } catch (e) {
    return {
      'success': false,
      'error': 'Error detecting configuration',
      'exception': e.toString()
    };
  } finally {
    closeDevice(handle);
  }
}