Le périphérique USB HID ne déclenche qu'un événement

11

J'ai une multi-télécommande USB eDIO (un récepteur infrarouge) fourni avec la télécommande de navigation Web ASUS PSR 2000.

J'essaie de connecter le Remote COntroller à mon pi pour qu'il reçoive les frappes envoyées par la télécommande.

Le contrôleur est détecté en tant que périphérique HID. Voici les détails de la commande 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

Je peux également voir le périphérique cible dans le dossier de développement avec un événement créé

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

Le gestionnaire d'événements qui lui est associé est le suivant, comme le montre la commande suivante.

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

Le problème est lorsque j'essaie de lire la sortie du gestionnaire d'événements créé pour le périphérique. La première frappe est enregistrée mais les touches suivantes ne sont pas affichées par la commande CAT.

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

Veuillez me suggérer ce que je peux faire pour que l'appareil fonctionne. Appuyer sur n'importe quelle touche après la première frappe ne renvoie rien sauf si l'appareil est rebranché.

Veuillez suggérer ce qui doit être fait pour résoudre le problème.

SteveIrwin
la source
N'importe qui? Je ne sais absolument pas ce qui se passe avec l'appareil. Peut-être qu'un modérateur peut m'aider à mieux formuler la question si c'est un problème ici?
SteveIrwin
La question est bonne. Cependant, c'est assez localisé, donc je suis sûr que peu de gens auraient eu le même problème. Cela peut vous calmer de savoir que j'ai vu quelque chose de très similaire utilisé par le bateau parlant de Chris Wallace afin que vous puissiez y jeter un œil. La première chose que je demanderais pour diagnostiquer le problème est; utilisez-vous un concentrateur auto-alimenté, car cela pourrait être un problème d'alimentation.
Jivings
Avez-vous essayé sans |xxd? Il met en mémoire tampon la sortie. J'ai utilisé à irwpartir du package lircpour obtenir les codes clés envoyés par ma télécommande.
macrojames
pilote personnalisé signifierait un correctif du noyau Linux. L'option la plus simple consiste à utiliser libusb car libusb donne un accès direct aux points de terminaison USB.
Lars Pötter

Réponses:

5

Le problème semble être les descripteurs USB incomplets:

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

Le descripteur qui pourrait être lu dit que c'est une souris.

  bInterfaceProtocol      2 Mouse

Et qu'il y aurait un descripteur de 20 octets qui décrit le format des données:

  bDescriptorType        34 Report
  wDescriptorLength      20

Mais celui-là manque.

Il y a un problème étrange avec votre combinaison spécifique de matériel et de logiciel ou le programmeur était paresseux et n'a pas implémenté le descripteur de rapport, car son propre pilote n'en a probablement pas besoin. Mais très probablement, le pilote qui crée le périphérique d'entrée est confus.

Vous pouvez essayer d'utiliser libusb pour lire les 4 octets du point de terminaison. Peut-être que le sondage fonctionne. Ou jetez un œil à la communication USB lorsque vous utilisez l'appareil avec le pilote d'origine. Et oui, c'est très délicat si vous n'avez pas l'un des enregistreurs USB coûteux qui traîne. Mais le noyau Linux prend en charge la journalisation USB des logiciels et certains enregistreurs de logiciels pour Windows sont disponibles.

Lars Pötter
la source
4

Enfin, j'ai eu le temps d'écrire ma propre implémentation en utilisant la bibliothèque PyUSB qui est un wrapper pour Libusb.

Je publie le code ici. Peut aider quelqu'un.

J'ai un autre morceau de code qui crée le fichier de configuration qui est utilisé ici. Je n'ai pas mappé toutes les clés distantes car je n'ai pas besoin de toutes.

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
la source