Control LED con libusb

LedController for GNU/Linux

LedController for GNU/Linux

Hoy me ha llegado un chinagadget comprado en DealExtreme.

Se trata de un notificador de nuevos emails o eventos de mensajería.

Como era de esperar el driver/software sólo funciona para sistemas Windows pero me gustaría poder utilizar este “cachibache” en mi Ubuntu.

He supuesto que encender una bombilla vía USB no debía ser muy complicado y me he puesto manos a la obra.

Lo primero que tenia que averiguar era la configuración y el protocolo del driver para encender/apagar el LED a voluntad.

Para hacer esta mini ingeniería inversa he utilizado VirtualBox y Wireshark.

Wireshark es ampliamente usado como sistema de captura y análisis de paquetes de red. Ahora además nos permite “sniffar” el tráfico USB.

Con VirtualBox se crea una maquina virtual Windows donde instalamos los drivers oficiales del notificador.

Con nuestra máquina virtual corriendo, ponemos a escuchar a nuestro sniffer.

Es necesario saber en que bus se encuentra nuestro dispositivo. Ésto se soluciona con un simple lsusb.

Ahora le indicamos a WireShark que escuche en dicho bus y ejecutamos un escenario donde se encienda/apague el led.

El resultado es un gran fichero de captura con mucha morralla.

Analizando el tráfico se observa un incontable número de paquetes enviados por interrupción pero cuyo contenido es siempre el mismo. Desconozco su propósito (¿quizás un sistema rudimentario de heartbeat?).

Filtrando por endpoint, se ve que hay dos endpoints, 1 y 2 (además del EP de control 0).

El EP 1 es el que usa para transferencias por interrupción del mensaje repetitivo.

El EP 2 es el que se usa para el envio de comandos de encendido.

En concreto, después de jugar con la aplicación de notificación, detecte la siguiente trama para encender el led rojo:


0x02 0x04 0x04 0x04 0x04

Para apagarlo, se usa ésta otra:


0x00 0x04 0x04 0x04 0x04

Con el protocolo (a priori) detectado, decidí hacer el driver en espacio de usuario para GNU/Linux.

Para acometer ésto, opté por usar la librería de acceso a USB, libusb.

Esta librería permite el desarrollo rápido de drivers/aplicaciones USB en GNU/Linux (también está disponible para Windows). Para dispositivos sencillos como este se ajusta perfectamente. Si por el contrario queremos controlar un dispositivo con alta intesidad de E/S, es recomendable implementarlo mediante un módulo kernel.

La implementación es sencilla. Se pasa como parámetro el color del LED a encender (en la secuencia, 2 = rojo, 1 = azul, 2 = verde).

Lo relevante está en la línea 55. Aquí es donde se envía por interrupción, el comando por el EP 2.

También es interesante la línea 41. Aquí se descarga el manejador kernel de dispositivo en caso de que algún driver lo haya reclamado (en este caso el driver HID).


#include <stdio.h>
#include <libusb.h>
#include <errno.h>

#define VID 0x1294
#define PID 0x1320

static struct libusb_device_handle *devh = NULL;

int main(int argc,char** argv)
{
 int ret;
 unsigned char code = 0;
 if (argc != 2 )
 {
    printf("syntax: %s red | green | blue | off\n",argv[0]);
    return -1;
 }
 if ( strcmp(argv[1],"red") == 0 )
 {
     code = 2;
 }
 else if ( strcmp(argv[1],"green") == 0 )
 {
     code = 3;
 }
 else if ( strcmp(argv[1],"blue") == 0 )
 {
     code = 1;
 }
 libusb_init(NULL);
 devh = libusb_open_device_with_vid_pid(NULL, VID, PID);
 if (devh == NULL )
 {
	printf("not found\n");
        return -1;
 }
 if ( libusb_kernel_driver_active(devh,0) )
 {
	printf("detach from kernel\n");
        ret = libusb_detach_kernel_driver(devh,0);
        if (ret < 0 )
        {
		printf("can't detach\n");
                return -1;
        }
 }
 char data[5];
 data[0] = code;
 data[1] = 0x4;
 data[2] = 0x4;
 data[3] = 0x4;
 data[4] = 0x4;
 int dummy;
 ret =  libusb_interrupt_transfer(devh,0x2,data,5,&dummy,0);
 if ( ret < 0 )
 {
  perror("error");
 }
return 0;
}

Os dejo el fuente de programa, una versión compilada dinámicamente y otra estáticamente.
Fuente: ledcontroller.tar.gz

Anuncios

Análisis y desarrollo de un driver para Xorg: EloTouch (I)

Análisis y desarrollo de driver para Elo Touch

Análisis y desarrollo de driver para Elo Touch

EloTouch es una empresa que se dedica a la fabricación de pantallas táctiles.

No tengo queja de su hardware. Sus controladores tienen interfaz serie y/o USB. Particularmente me gusta más el controlador USB debido a que existe un perfil HID que recoge este tipo de periférico y GNU/Linux tiene un driver HID que no funciona mal.

El caso es que recientemente he tenido que desarrollar un driver para una pantalla resistiva de EloTouch que funciona bajo GNU/Linux con Xorg.

La motivación viene de la necesidad de poder asociar un controlador touch a una pantalla (screen) determinada. De este modo podemos tener un escritorio extendido con dos monitores, cada uno de ellos con una interfaz táctil. Tanto los monitores como los controladores de touch están conectados a una misma CPU.

El fabricante tiene un driver (bastante tedioso de instalar) que no contempla esta posibilidad: asociar un controlador a un screen arbitrario.

Lo primero que se me vino a la mente fue buscar un driver GPL que cumpliera con este requisito.

Para “mi sorpresa” encontré en el repositorio de Xorg, los siguientes drivers:

La estructura de ambos es muy parecida y para mi asombro sí que implementan la funcionalidad que demandaba.

¿funcionarán con mi controlador?

No hubo suerte. Ni uno ni otro funcionaba a pesar de establecer la configuración tal y como describía la documentación asociada.

No queda más remedio que hacer mi propio driver.

Leer más de esta entrada