El dispositivo USB HID solo dispara 1 evento

10

Tengo un eDIO USB Multi Remote Controller (un receptor infrarrojo) que viene con el control remoto de navegación web ASUS PSR 2000.

Estoy tratando de conectar el controlador remoto a mi pi para que reciba las pulsaciones de teclas enviadas por el control remoto.

El controlador se detecta como un dispositivo HID. Aquí están los detalles del comando lsusb -v

    Bus 001 Device 007: ID 147a:e001 Formosa Industrial Computing, Inc.
    Couldn't open device, some information will be missing
    Device Descriptor:
    bLength                18
    bDescriptorType         1
    bcdUSB               1.10
    bDeviceClass            0 (Defined at Interface level)
   bDeviceSubClass         0
   bDeviceProtocol         0
   bMaxPacketSize0         8
   idVendor           0x147a Formosa Industrial Computing, Inc.
   idProduct          0xe001
   bcdDevice            1.22
   iManufacturer           1
   iProduct                2
   iSerial                 0
   bNumConfigurations      1
  Configuration Descriptor:
  bLength                 9
  bDescriptorType         2
wTotalLength           34
bNumInterfaces          1
bConfigurationValue     1
iConfiguration          4
bmAttributes         0xa0
  (Bus Powered)
  Remote Wakeup
MaxPower              300mA
Interface Descriptor:
  bLength                 9
  bDescriptorType         4
  bInterfaceNumber        0
  bAlternateSetting       0
  bNumEndpoints           1
  bInterfaceClass         3 Human Interface Device
  bInterfaceSubClass      1 Boot Interface Subclass
  bInterfaceProtocol      2 Mouse
  iInterface              0
    HID Device Descriptor:
      bLength                 9
      bDescriptorType        33
      bcdHID               1.10
      bCountryCode            0 Not supported
      bNumDescriptors         1
      bDescriptorType        34 Report
      wDescriptorLength      20
     Report Descriptors:
       ** UNAVAILABLE **
  Endpoint Descriptor:
    bLength                 7
    bDescriptorType         5
    bEndpointAddress     0x81  EP 1 IN
    bmAttributes            3
      Transfer Type            Interrupt
      Synch Type               None
      Usage Type               Data
    wMaxPacketSize     0x0004  1x 4 bytes
    bInterval              10

También puedo ver el dispositivo de destino en la carpeta de desarrollo con un evento creado

    pi@raspberrypi /dev/input/by-id $ dir
    usb-Cypress_Semiconductor_eDio_USB_Multi_Remote_Controlle-event-if00

El controlador de eventos asociado es el siguiente, como se ve en el siguiente comando.

pi@raspberrypi /proc/bus/input $ cat devices
I: Bus=0003 Vendor=147a Product=e001 Version=0110
N: Name="Cypress Semiconductor eDio USB Multi Remote Controlle"
P: Phys=usb-bcm2708_usb-1.2/input0
S: Sysfs=/devices/platform/bcm2708_usb/usb1/1-1/1-1.2/1-1.2:1.0/input/input2
U: Uniq=
H: Handlers=event0
B: PROP=0
B: EV=1

El problema es cuando intento leer la salida del controlador de eventos creado para el dispositivo. La primera pulsación de tecla se registra pero las pulsaciones de tecla posteriores no se muestran mediante el comando CAT.

 pi@raspberrypi /dev/input $ cat event0 | xxd
 0000000: e007 9450 9476 0900 0000 0000 0000 0000  ...P.v..........

Sugiérame qué puedo hacer para que el dispositivo funcione. Presionar cualquier tecla después de la primera pulsación no devuelve nada a menos que el dispositivo se vuelva a enchufar.

Sugiera qué debe hacerse para solucionar el problema.

SteveIrwin
fuente
Alguien cualquier cosa? No tengo ni idea de lo que está pasando con el dispositivo. ¿Quizás un moderador pueda ayudarme a formular la pregunta mejor si eso es un problema aquí?
SteveIrwin el
La pregunta es buena. Sin embargo, está bastante localizado, así que estoy seguro de que no muchas personas habrían tenido el mismo problema. Puede tranquilizarte saber que he visto algo muy similar utilizado por el barco parlante de Chris Wallace para que puedas echarle un vistazo. Lo primero que pediría para diagnosticar el problema es; ¿Está utilizando un concentrador autoalimentado porque podría ser un problema de alimentación?
Jivings
¿Has probado sin |xxd? Se amortigua la salida. Utilicé el irwpaquete lircpara obtener los códigos de clave enviados por mi control remoto.
macrojames
controlador personalizado significaría un parche de kernel de Linux. La opción más fácil es usar libusb ya que libusb da acceso directo a los puntos finales USB.
Lars Pötter

Respuestas:

5

El problema parece ser los descriptores USB incompletos:

  Couldn't open device, some information will be missing
  Report Descriptors:
  ** UNAVAILABLE **

El descriptor que se puede leer dice que se trata de un mouse.

  bInterfaceProtocol      2 Mouse

Y que habría un Descriptor de 20 Bytes que describe el formato de datos:

  bDescriptorType        34 Report
  wDescriptorLength      20

Pero ese falta.

Hay un problema extraño con su combinación específica de hardware y software o el programador fue flojo y no implementó el Descriptor de informes, ya que su propio controlador probablemente no lo necesita. Pero lo más probable es que haya confundido el controlador que crea el dispositivo de entrada.

Puede intentar usar libusb para leer los 4 bytes desde el punto final. Quizás las encuestas funcionen. O eche un vistazo a la comunicación USB cuando use el dispositivo con el controlador original. Y sí, esto es muy complicado si no tiene uno de los registradores USB caros por ahí. Pero el Kernel de Linux tiene soporte para Software USB Logging y hay algunos Loggers de software disponibles para Windows.

Lars Pötter
fuente
4

Finalmente tuve tiempo de escribir mi propia implementación usando la biblioteca PyUSB, que es un contenedor para Libusb.

Estoy publicando el código aquí. Podría ayudar a alguien.

Tengo otro código que crea el archivo de configuración que se usa aquí. No he asignado todas las claves remotas ya que no las necesito todas.

import usb.core
import usb.util
import ConfigParser 
import shlex
import subprocess
import logging

# find our device
diction={
  6402315641282315:'1',
  6402415641282415:'2',
  6402515641282515:'3',
  6402615641282615:'4',
  6402715641282715:'5',
  6402815641282815:'6',
  6402915641282915:'7',
  6403015641283015:'8',
  6403115641283115:'9',
  }



def load_config():
    dict={}
    config = ConfigParser.RawConfigParser()
    config.read('/codes/remote/remote.cfg')

    dict['vendor']=config.getint('Settings','idVendor')

    dict['product']=config.getint('Settings','idProduct')

    dict['interface']=config.getint('Settings', 'interface')

    r=config.options('Key Mappings')

    for item in r:
        if config.get('Key Mappings',item)!='': 
            dict[item]=config.get('Key Mappings',item)
            #print config.get('Key Mappings',item)
    return dict

def pyus():

    try:
        load_log()
        dict=load_config()
        join_int = lambda nums: int(''.join(str(i) for i in nums))
        #print dict

        dev = usb.core.find(idVendor=dict['vendor'], idProduct=dict['product'])
        interface=dict['interface']

        if dev is None:
            raise ValueError('Device not found')

        if dev.is_kernel_driver_active(interface) is True:
                #print "but we need to detach kernel driver"
                dev.detach_kernel_driver(interface)
        #dev.detatch_kernel_driver(interface) 
        # set the active configuration. With no arguments, the first
        # configuration will be the active one
        dev.set_configuration()

        # get an endpoint instance
        cfg = dev.get_active_configuration()
        interface_number = cfg[(0,0)].bInterfaceNumber
        alternate_setting = usb.control.get_interface(dev,interface_number)
        intf = usb.util.find_descriptor(
            cfg, bInterfaceNumber = interface_number,
            bAlternateSetting = alternate_setting
        )

        ep = usb.util.find_descriptor(
            intf,
            # match the first IN endpoint
            custom_match = \
            lambda e: \
                usb.util.endpoint_direction(e.bEndpointAddress) == \
                usb.util.ENDPOINT_IN
        )

        assert ep is not None
        #print 'packet details',ep.bEndpointAddress , ep.wMaxPacketSize

        while 1:
            try:
                data = dev.read(ep.bEndpointAddress, ep.wMaxPacketSize*2,interface,1000)
                data=data.tolist()
                key=join_int(data)
                #print "Key is " , key
                if  key in diction:

                    try:
                        args=shlex.split(dict[diction[key]])
                        #print args
                        p=subprocess.Popen(args, stderr=subprocess.STDOUT, stdout=subprocess.PIPE)
                        #print "Pressed key is ",diction[key]
                    except:
                        pass


            except usb.core.USBError as e:
                pass
    except:
        pass

pyus()
SteveIrwin
fuente