getPrinterStatus method
Future<Map<String, dynamic>>
getPrinterStatus(
- int vendorId,
- int productId,
- List<int> command, {
- int interfaceNumber = 0,
- int endpointAddress = 0x01,
- int readEndpointAddress = 0x81,
- int timeout = 10000,
- bool expectResponse = false,
- int maxResponseLength = 542,
})
Implementation
Future<Map<String, dynamic>> getPrinterStatus(
int vendorId,
int productId,
List<int> command, {
int interfaceNumber = 0,
int endpointAddress = 0x01,
int readEndpointAddress = 0x81,
int timeout = 10000,
bool expectResponse = false,
int maxResponseLength = 542,
}) async {
// Abre el dispositivo
final Pointer<libusb_device_handle>? handleNullable =
openDevice(vendorId, productId);
if (handleNullable == nullptr || handleNullable == null) {
return {
'success': false,
'error': 'No se pudo abrir el dispositivo',
'isConnected': false,
'statusType': command.length >= 3 ? command[2] : 0
};
}
// Aquí convertimos de Pointer? a Pointer, ahora que sabemos que no es nulo
final handle = handleNullable;
Map<String, dynamic> statusInfo = {
'success': false,
'isConnected': false,
'rawData': null,
'statusType': command.length >= 3 ? command[2] : 0
};
try {
// Verificar si hay un kernel driver activo y desconectarlo si es necesario
int hasKernelDriver = 0;
if (Platform.isLinux || Platform.isMacOS) {
try {
hasKernelDriver =
_bindings.libusb_kernel_driver_active(handle, interfaceNumber);
if (hasKernelDriver == 1) {
log("Desconectando el driver del kernel...");
final detachResult =
_bindings.libusb_detach_kernel_driver(handle, interfaceNumber);
if (detachResult < 0) {
log("No se pudo desconectar el driver del kernel: $detachResult");
} else {
log("Driver del kernel desconectado con éxito");
}
}
} catch (e) {
log("Error al verificar/desconectar el driver del kernel: $e");
}
}
// Configurar el dispositivo si es necesario
final configResult = _bindings.libusb_set_configuration(handle, 1);
if (configResult < 0) {
log("Advertencia: No se pudo establecer la configuración: $configResult");
// Continuamos a pesar del error, ya que algunas impresoras funcionan sin esto
}
// Reclamar la interfaz con múltiples intentos
int claimResult = -1;
int attempts = 0;
const maxAttempts = 3;
while (attempts < maxAttempts) {
claimResult = _bindings.libusb_claim_interface(handle, interfaceNumber);
if (claimResult == 0) break;
log("Intento ${attempts + 1} fallido con error $claimResult. Reintentando...");
// Esperar un poco antes de reintentar
await Future.delayed(Duration(milliseconds: 500));
attempts++;
}
if (claimResult < 0) {
return {
'success': false,
'error': 'No se pudo reclamar la interfaz',
'isConnected': false,
'statusType': command.length >= 3 ? command[2] : 0
};
}
final buffer = calloc<Uint8>(command.length);
final bufferList = buffer.asTypedList(command.length);
bufferList.setAll(0, command);
final transferredPtr = calloc<Int>();
log("Enviando comando $command...");
int transferResult = _bindings.libusb_bulk_transfer(
handle,
endpointAddress,
buffer.cast<UnsignedChar>(),
command.length,
transferredPtr,
timeout);
await Future.delayed(Duration(milliseconds: 100));
//final bytesSent = transferredPtr.value;
calloc.free(buffer);
calloc.free(transferredPtr);
if (transferResult < 0) {
String errorDescription = _getUsbErrorDescription(transferResult);
return {
'success': false,
'error':
'Error al enviar comando: $command, detalle: $errorDescription',
'isConnected': false,
'statusType': command.length >= 3 ? command[2] : 0
};
}
//log("Transferencia exitosa: $bytesSent bytes enviados");
Uint8List buffer2 = Uint8List(512);
final Pointer<UnsignedChar> dataPointer =
malloc.allocate<UnsignedChar>(buffer2.length);
for (var i = 0; i < buffer2.length; i++) {
dataPointer[i] = buffer[i];
}
final Pointer<Int> transferredPointer = malloc.allocate<Int>(1);
transferredPointer.value = 0;
// Llamar a la función correctamente
int readResult = _bindings.libusb_bulk_transfer(
handle, // libusb_device_handle*
0x81, // unsigned char endpoint
dataPointer, // unsigned char* data
buffer2.length, // int length
transferredPointer, // int* transferred
timeout, // unsigned int timeout
);
// Leer cuántos bytes se transfirieron
int bytesReceived = transferredPointer.value;
if (readResult == 0 && bytesReceived > 0) {
// Copiar los datos recibidos de vuelta a un Uint8List
Uint8List receivedData = Uint8List(bytesReceived);
for (var i = 0; i < bytesReceived; i++) {
receivedData[i] = dataPointer[i];
}
// Determinar qué tipo de comando es según el tercer byte
int statusType = command.length >= 3 ? command[2] : 0;
statusInfo['success'] = true;
statusInfo['isConnected'] = true;
statusInfo['rawData'] = receivedData;
statusInfo['binaryResponse'] =
receivedData[0].toRadixString(2).padLeft(8, '0');
statusInfo['statusType'] = statusType;
// Interpretar los datos según el tipo de estado
if (bytesReceived > 0) {
//interpretPrinterStatus(receivedData[0]);
//bool isOnline = (receivedData[0] & (1 << 3)) == 0;
//log('Impresora en línea: $isOnline');
//statusInfo['status'] = 'Impresora en línea: $isOnline';
// Interpretar la respuesta según el tipo de comando
switch (statusType) {
case 1: // Estado de la impresora [0x10, 0x04, 0x01]
statusInfo['isOnline'] = (receivedData[0] & (1 << 3)) == 0;
statusInfo['cashDrawerOpen'] = (receivedData[0] & (1 << 2)) != 0;
break;
case 2: // Estado offline [0x10, 0x04, 0x02]
statusInfo['isCoverOpen'] = (receivedData[0] & (1 << 2)) != 0;
statusInfo['isPaperFeedByButton'] =
(receivedData[0] & (1 << 3)) != 0;
break;
case 4: // Estado del sensor de papel [0x10, 0x04, 0x04]
// Evaluamos los bits 2-3 (estado del papel cerca del final)
bool bit2 = (receivedData[0] & (1 << 2)) != 0;
bool bit3 = (receivedData[0] & (1 << 3)) != 0;
// Evaluamos los bits 5-6 (estado del sensor de fin de papel)
bool bit5 = (receivedData[0] & (1 << 5)) != 0;
bool bit6 = (receivedData[0] & (1 << 6)) != 0;
statusInfo['paperStatus'] = {
'paperNearEnd': bit2 ||
bit3, // Si cualquiera de estos bits está activado, el papel está cerca del final
'paperEnd': bit5 ||
bit6, // Si cualquiera de estos bits está activado, se ha detectado el fin del papel
'paperPresent': !(bit5 ||
bit6), // Si los bits 5-6 están desactivados, hay papel presente
'paperAdequate': !(bit2 ||
bit3), // Si los bits 2-3 están desactivados, el papel es adecuado
};
break;
default:
statusInfo['error'] = 'Tipo de comando no reconocido';
}
}
} else {
log("Error: ${_bindings.libusb_error_name(readResult)}");
log("Description: ${_getUsbErrorDescription(readResult)}");
statusInfo['error'] =
'Error al leer respuesta: ${_bindings.libusb_error_name(readResult)}';
}
// Liberar la memoria
malloc.free(dataPointer);
malloc.free(transferredPointer);
// Liberar la interfaz
_bindings.libusb_release_interface(handle, interfaceNumber);
// Reconectar el driver del kernel si lo desconectamos
if (hasKernelDriver == 1 && (Platform.isLinux || Platform.isMacOS)) {
_bindings.libusb_attach_kernel_driver(handle, interfaceNumber);
}
} catch (e) {
log('Exception: $e');
return {
'success': false,
'error': 'Error al comunicarse con la impresora: ${e.toString()}',
'isConnected': false,
'statusType': command.length >= 3 ? command[2] : 0
};
} finally {
closeDevice(handle);
}
return statusInfo;
}