Dispositivos USB

En este documento, se describe cómo usar la API de USB para comunicarte con dispositivos USB. Algunos dispositivos No se puede acceder a través de la API de USB (consulta la sección Advertencias a continuación para obtener más información). Apps de Chrome También se puede conectar a dispositivos en serie y Bluetooth.

Para obtener información general sobre USB, consulta las especificaciones de USB oficiales. USB en NutShell es un curso intensivo razonable que puede resultarte útil.

Requisito del manifiesto

La API con USB requiere el módulo "usb" en el archivo de manifiesto:

"permissions": [
  "usb"
]

Además, para evitar la creación de huellas digitales, debes declarar todos los tipos de dispositivos que a los que quiere acceder en el archivo de manifiesto. Cada tipo de dispositivo USB corresponde a un ID de proveedor o de producto. (VID/PID). Puedes usar usb.getDevices para enumerar dispositivos según su par de VID/PID.

Debes declarar los pares de VID/PID para cada tipo de dispositivo que quieras usar en el usbDevices. permiso en el archivo de manifiesto de tu app, como se muestra en el siguiente ejemplo:

"permissions": [
  {
    "usbDevices": [
      {
        "vendorId": 123,
        "productId": 456
      }
    ]
  }
]

A partir de Chrome 57, el requisito para declarar todos los tipos de dispositivos en el manifiesto de la app es el siguiente: para las apps que se ejecutan como apps de kiosco de ChromeOS. Para las aplicaciones de kiosco, puedes usar la La propiedad de permiso interfaceClass permite solicitar permiso para acceder a dispositivos USB que:

  • implementar una interfaz USB de una clase de interfaz específica
  • tienen una clase de dispositivo USB específica

Por ejemplo, el siguiente permiso usbDevices otorgaría a una app acceso a todos los dispositivos USB que implementar una interfaz de impresora (código de clase de interfaz 7) y dispositivos concentradores USB (código de clase de dispositivo) 9).

"permissions": [
  {
    "usbDevices": [
      {"interfaceClass": 7},
      {"interfaceClass": 9}
    ]
  }
]

Para obtener la lista de valores interfaceClass aceptables, consulta Códigos de clase USB.

La propiedad interfaceClass se puede combinar con la propiedad vendorId para obtener acceso solo al USB. de un proveedor específico, como se demuestra en el siguiente ejemplo:

"permissions": [
  {
    "usbDevices": [
      {
        "vendorId": 123,
        "interfaceClass": 7
      }
    ]
  }
]

Cómo encontrar un dispositivo

Para determinar si uno o más dispositivos específicos están conectados al sistema de un usuario, utiliza la usb.getDevices:

chrome.usb.getDevices(enumerateDevicesOptions, callback);
Parámetro (tipo)Descripción
EnumerateDevicesOptions (objeto)Un objeto que especifica un vendorId (largo) y un productId (largo) que se usan para encontrar el tipo correcto de dispositivo en el bus. Tu manifiesto debe declarar la sección de permisos usbDevices que enumere todos los pares vendorId y deviceId a los que tu app quiere acceder.
devolución de llamada (función)Se llama cuando finaliza la enumeración de dispositivos. La devolución de llamada se ejecutará con un parámetro, un array de objetos Device con tres propiedades: device, vendorId y productId. La propiedad del dispositivo es un identificador estable de un dispositivo conectado. No cambiará hasta que se desenchufe el dispositivo. Los detalles del identificador son opacos y están sujetos a cambios. No confíes en su tipo actual.
Si no se encuentran dispositivos, el array estará vacío.

Ejemplo:

function onDeviceFound(devices) {
  this.devices=devices;
  if (devices) {
    if (devices.length > 0) {
      console.log("Device(s) found: "+devices.length);
    } else {
      console.log("Device could not be found");
    }
  } else {
    console.log("Permission denied.");
  }
}

chrome.usb.getDevices({"vendorId": vendorId, "productId": productId}, onDeviceFound);

Abrir un dispositivo

Una vez que se devuelvan los objetos Device, podrás abrir un dispositivo con usb.openDevice para obtener un controlador de conexión. Solo puedes comunicarte con dispositivos USB mediante los controladores de conexión.

PropiedadDescripción
dispositivoObjeto recibido en la devolución de llamada usb.getDevices.
datos (búfer de matriz)Contiene los datos que envió el dispositivo si la transferencia fue entrante.

Ejemplo:

var usbConnection = null;
var onOpenCallback = function(connection) {
  if (connection) {
    usbConnection = connection;
    console.log("Device opened.");
  } else {
    console.log("Device failed to open.");
  }
};

chrome.usb.openDevice(device, onOpenCallback);

Para simplificar el proceso de apertura, puedes usar el método usb.findDevices, que enumera, solicita acceso y abre los dispositivos en una llamada:

chrome.usb.findDevices({"vendorId": vendorId, "productId": productId, "interfaceId": interfaceId}, callback);

que equivale a lo siguiente:

chrome.usb.getDevices({"vendorId": vendorId, "productId": productId}, function (devices) {
  if (!devices) {
    console.log("Error enumerating devices.");
    callback();
    return;
  }
  var connections = [], pendingAccessRequests = devices.length;
  devices.forEach(function (device) {
    chrome.usb.requestAccess(interfaceId, function () {
      // No need to check for errors at this point.
      // Nothing can be done if an error occurs anyway. You should always try
      // to open the device.
      chrome.usb.openDevices(device, function (connection) {
        if (connection) connections.push(connection);
        pendingAccessRequests--;
        if (pendingAccessRequests == 0) {
          callback(connections);
        }
      });
    });
  })
});

Transferencias USB y recepción de datos de un dispositivo

El protocolo USB define cuatro tipos de transferencias: de control, masiva, isocónica y interrumpir. Estas transferencias se describen a continuación.

Las transferencias pueden ocurrir en ambas direcciones: de dispositivo a host (entrante) y de host a dispositivo (saliente). Venc. a la naturaleza del protocolo USB, tanto los mensajes entrantes como los salientes deben ser iniciados por el host (la computadora que ejecuta la aplicación de Chrome). Para mensajes entrantes (de dispositivo a host), el host (iniciado por tu código JavaScript) envía un mensaje marcado como “entrante” al dispositivo. Los detalles del dependen del dispositivo, pero generalmente tendrán alguna identificación de lo que solicites. a partir de ella. Luego, el dispositivo responde con los datos solicitados. La respuesta del dispositivo se controla Chrome y se entrega de forma asíncrona a la devolución de llamada que especifiques en el método de transferencia. Un (host-a-dispositivo) es similar, pero la respuesta no contiene los datos devueltos por el dispositivo.

Para cada mensaje del dispositivo, la devolución de llamada especificada recibirá un objeto de evento con el siguientes propiedades:

PropiedadDescripción
resultCode (número entero)0 significa éxito; otros valores indican un error. Se puede leer una cadena de error
desde chrome.extension.lastError cuando se indica
una falla.
datos (búfer de matriz)Contiene los datos que envió el dispositivo si la transferencia fue entrante.

Ejemplo:

var onTransferCallback = function(event) {
   if (event && event.resultCode === 0 && event.data) {
     console.log("got " + event.data.byteLength + " bytes");
   }
};

chrome.usb.bulkTransfer(connectionHandle, transferInfo, onTransferCallback);

CONTROLAR transferencias

Las transferencias de control se usan generalmente para enviar o recibir parámetros de configuración o comando a un dispositivo USB dispositivo. El método controlTransfer siempre envía o lee desde el extremo 0, y no se procesa ninguna claimInterface como en los productos necesarios. El método es simple y recibe tres parámetros:

chrome.usb.controlTransfer(connectionHandle, transferInfo, transferCallback)
Parámetro (tipos)Descripción
connectionHandleObjeto recibido en la devolución de llamada usb.openDevice.
transferInfoEs un objeto de parámetro con valores de la siguiente tabla. Consulta las especificaciones del protocolo de tu dispositivo USB para obtener más detalles.
transferCallback()Se invoca cuando se completa la transferencia.

Valores para el objeto transferInfo:

ValorDescripción
requestType (cadena)“vendor”, “standard”, “class” o "reservado".
destinatario (cadena)"dispositivo", "interfaz", "extremo" o en "otro".
dirección (cadena)“en” o "fuera". Los "en" se utiliza para notificar al dispositivo que
debe enviar información al host. Toda la comunicación en un bus
USB se inicia por el host, así que usa un puerto "en" para permitir que un dispositivo
devuelva información.
request (número entero)lo define el protocolo de tu dispositivo.
valor (número entero)lo define el protocolo de tu dispositivo.
índice (número entero)lo define el protocolo de tu dispositivo.
length (número entero)Solo se utiliza cuando la dirección es "en". Notifica al dispositivo que esta es la cantidad de datos que el host espera como respuesta.
datos (búfer de matriz)Definido por el protocolo de tu dispositivo. Se requiere cuando la dirección está "fuera".

Ejemplo:

var transferInfo = {
  "requestType": "vendor",
   "recipient": "device",
  "direction": "out",
  "request":  0x31,
  "value": 120,
  "index": 0,
  // Note that the ArrayBuffer, not the TypedArray itself is used.
  "data": new Uint8Array([4, 8, 15, 16, 23, 42]).buffer
};
chrome.usb.controlTransfer(connectionHandle, transferInfo, optionalCallback);

Transferencias ISOCHRONOS

Las transferencias asíncronas son el tipo de transferencia USB más complejo. Por lo general, se usan para transmisiones de datos, como video y sonido. Para iniciar una transferencia isócrona (ya sea entrante o saliente), puedes debes usar el método usb.isochronousTransfer:

chrome.usb.isochronousTransfer(connectionHandle, isochronousTransferInfo, transferCallback)
ParámetroDescripción
connectionHandleObjeto recibido en la devolución de llamada usb.openDevice.
isochronousTransferInfoObjeto de parámetro con los valores de la siguiente tabla.
transferCallback()Se invoca cuando se completa la transferencia.

Valores para el objeto isochronousTransferInfo:

ValorDescripción
transferInfo (objeto)Un objeto con los siguientes atributos:
direction (string): "in" o "out".
endpoint (número entero): definido por el dispositivo. Por lo general, se puede encontrar mirando una herramienta de inspección USB, como lsusb -v
length (integer): solo se usa cuando la dirección es "in". Notifica al dispositivo que esta es la cantidad de datos que el host espera como respuesta.
Debe ser, AL MENOS, packets × packetLength.
datos (arraybuffer): definido por el protocolo de tu dispositivo. solo se utiliza cuando la dirección es "fuera".
paquetes (número entero)Cantidad total de paquetes esperados en esta transferencia.
packageLength (número entero)Longitud esperada de cada paquete en esta transferencia.

Ejemplo:

var transferInfo = {
  "direction": "in",
  "endpoint": 1,
  "length": 2560
};

var isoTransferInfo = {
  "transferInfo": transferInfo,
  "packets": 20,
  "packetLength": 128
};

chrome.usb.isochronousTransfer(connectionHandle, isoTransferInfo, optionalCallback);

Transferencias en forma masiva

Las transferencias masivas se usan comúnmente para transferir una gran cantidad de datos no urgentes de una nueva manera. usb.bulkTransfer tiene tres parámetros:

chrome.usb.bulkTransfer(connectionHandle, transferInfo, transferCallback);
ParámetroDescripción
connectionHandleObjeto recibido en la devolución de llamada usb.openDevice.
transferInfoObjeto de parámetro con los valores de la siguiente tabla.
transferCallbackSe invoca cuando se completa la transferencia.

Valores para el objeto transferInfo:

ValorDescripción
dirección (cadena)“en” o "fuera".
endpoint (número entero)lo define el protocolo de tu dispositivo.
length (número entero)Solo se utiliza cuando la dirección es "en". Notifica al dispositivo que esta es la cantidad de datos que el host espera como respuesta.
datos (ArrayBuffer)Se definen según el protocolo de tu dispositivo. solo se utiliza cuando la dirección es "fuera".

Ejemplo:

var transferInfo = {
  "direction": "out",
  "endpoint": 1,
  "data": new Uint8Array([4, 8, 15, 16, 23, 42]).buffer
};

Transferencias INTERRUPT

Las transferencias interrumpidas se usan en una pequeña cantidad de datos urgentes. Como todas las comunicaciones USB que el host inicia, por lo general, sondea el dispositivo de forma periódica y envía interrupciones IN transferencias que hagan que el dispositivo devuelva datos si hay algo en la cola de interrupción (mantenida por el dispositivo). usb.interruptTransfer tiene tres parámetros:

chrome.usb.interruptTransfer(connectionHandle, transferInfo, transferCallback);
ParámetroDescripción
connectionHandleObjeto recibido en la devolución de llamada usb.openDevice.
transferInfoObjeto de parámetro con los valores de la siguiente tabla.
transferCallbackSe invoca cuando se completa la transferencia. Observa que esta devolución de llamada no contiene la respuesta del dispositivo. El propósito de la devolución de llamada es simplemente notificar a tu código que se procesaron las solicitudes de transferencia asíncrona.

Valores para el objeto transferInfo:

ValorDescripción
dirección (cadena)“en” o "fuera".
endpoint (número entero)lo define el protocolo de tu dispositivo.
length (número entero)Solo se utiliza cuando la dirección es "en". Notifica al dispositivo que esta es la cantidad de datos que el host espera como respuesta.
datos (ArrayBuffer)Se definen según el protocolo de tu dispositivo. solo se utiliza cuando la dirección es "fuera".

Ejemplo:

var transferInfo = {
  "direction": "in",
  "endpoint": 1,
  "length": 2
};
chrome.usb.interruptTransfer(connectionHandle, transferInfo, optionalCallback);

Advertencias

No se puede acceder a todos los dispositivos con la API de USB. En general, no se puede acceder a los dispositivos el kernel del sistema operativo o un controlador nativo los retiene del código de espacio del usuario. Algunos algunos ejemplos son los dispositivos con perfiles HID en sistemas OSX y las memorias USB.

En la mayoría de los sistemas Linux, los dispositivos USB se asignan con permisos de solo lectura de forma predeterminada. Para abrir una dispositivo a través de esta API, el usuario también necesitará tener acceso de escritura a ella. Una solución sencilla es establece una regla udev. Crea un archivo /etc/udev/rules.d/50-yourdevicename.rules con lo siguiente: contenido:

SUBSYSTEM=="usb", ATTR{idVendor}=="[yourdevicevendor]", MODE="0664", GROUP="plugdev"

Luego, solo reinicia el daemon udev: service udev restart. Puedes comprobar si los permisos del dispositivo de forma correcta siguiendo estos pasos:

  • Ejecuta lsusb para encontrar los números de autobús y de dispositivo.
  • Ejecuta ls -al /dev/bus/usb/[bus]/[device]. Este archivo debe ser propiedad del grupo "plugdev" y tener permisos de escritura de grupo.

Tu app no puede hacerlo automáticamente, ya que este procedimiento requiere acceso con permisos de administrador. Recomendaciones proporcionar instrucciones a los usuarios finales y vincular a la sección Advertencias de esta página para obtener explicación.

En ChromeOS, solo debes llamar a usb.requestAccess. El agente de permisos lo hace por ti.