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': 'No se pudo abrir el dispositivo'};
  }

  // Una vez verificado que no es nulo, lo asignamos a una variable no nullable
  final handle = handleNullable;

  try {
    // Obtener el dispositivo a partir del handle
    final device = _bindings.libusb_get_device(handle);

    // Obtener el descriptor del dispositivo
    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': 'No se pudo obtener el descriptor del dispositivo',
        'errorCode': descResult
      };
    }

    // Obtener información de configuración
    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': 'No se pudo obtener el descriptor de configuración',
        'errorCode': configResult
      };
    }

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

    // Información básica del dispositivo
    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>>[]
    };

    // Probar a reclamar interfaces y detectar endpoints manualmente
    for (int i = 0; i < numInterfaces; i++) {
      // Primero desconectamos el driver del kernel si es necesario
      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 al verificar/desconectar driver del kernel para interfaz $i: $e");
        }
      }

      // Intentar reclamar la interfaz
      int claimResult = _bindings.libusb_claim_interface(handle, i);
      if (claimResult < 0) {
        log("No se pudo reclamar la interfaz $i: $claimResult");
        continue;
      }

      // Crear una estructura para guardar la información de la interfaz
      Map<String, dynamic> interfaceInfo = {
        'number': i,
        'canClaim': true,
        'endpoints': <Map<String, dynamic>>[]
      };

      // Probar endpoints comunes para impresoras
      List<int> commonEndpoints = [0x01, 0x02, 0x03, 0x81, 0x82, 0x83];

      for (int epAddress in commonEndpoints) {
        // Para simplificar, asumimos que todos los endpoints son de tipo bulk
        bool isOutput = (epAddress & 0x80) ==
            0; // Si el bit más significativo es 0, es de salida

        // Para detectar si un endpoint funciona, podríamos intentar una transferencia de prueba
        // Pero esto podría causar efectos no deseados, así que solo reportamos la dirección
        interfaceInfo['endpoints'].add({
          'address': epAddress,
          'type': 'bulk', // Asumimos tipo bulk para impresoras
          'direction': isOutput ? 'output' : 'input'
        });
      }

      // Liberar la interfaz
      _bindings.libusb_release_interface(handle, i);

      // Reconectar el driver del kernel si es necesario
      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 al reconectar driver del kernel para interfaz $i: $e");
        }
      }

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

    // Liberar recursos
    _bindings.libusb_free_config_descriptor(config);
    calloc.free(configDescPtr);
    calloc.free(deviceDescriptor);

    return {
      'success': true,
      'deviceInfo': deviceInfo,
      'note':
          'Los endpoints listados son endpoints comunes para impresoras y pueden no corresponder exactamente a los endpoints reales del dispositivo.'
    };
  } catch (e) {
    return {
      'success': false,
      'error': 'Error al detectar configuración',
      'exception': e.toString()
    };
  } finally {
    closeDevice(handle);
  }
}