Uso del lector de tarjetas ACS ACR1252U USB NFC en Linux

Estoy usando un lector de tarjetas ACS ACR1252U ( http://www.acs.com.hk/en/products/342/acr1252u-usbnfc-reader-iii-nfc-forum-certified-reader/ ) conectado a través de USB Y, para ser honesto, no tengo idea de cómo hacer que funcione. He buscado en Google un montón de cosas, pero no hay suerte. Estoy usando una variante de Debian. Lo siguiente es más o menos lo que he hecho:

Obtengo lo siguiente usando dmesg:

[ 7173.059710] usb 1-1.3: new full-speed USB device number 6 using dwc_otg [ 7173.160500] usb 1-1.3: not running at top speed; connect to a high speed hub [ 7173.163114] usb 1-1.3: New USB device found, idVendor=072f, idProduct=223b [ 7173.163147] usb 1-1.3: New USB device strings: Mfr=1, Product=2, SerialNumber=0 [ 7173.163168] usb 1-1.3: Product: ACR1252 Dual Reader [ 7173.163186] usb 1-1.3: Manufacturer: ACS 

Usé el siguiente código de Python para obtener más detalles sobre los dispositivos:

 #!/usr/bin/python import sys import usb.core # find USB devices dev = usb.core.find(find_all=True) # loop through devices, printing vendor and product ids in decimal and hex for cfg in dev: print cfg sys.stdout.write('Decimal VendorID=' + str(cfg.idVendor) + ' & ProductID=' + str(cfg.idProduct) + '\n') sys.stdout.write('Hexadecimal VendorID=' + hex(cfg.idVendor) + ' & ProductID=' + hex(cfg.idProduct) + '\n\n') 

La salida para este dispositivo específico es:

 DEVICE ID 072f:223b on Bus 001 Address 004 ================= bLength : 0x12 (18 bytes) bDescriptorType : 0x1 Device bcdUSB : 0x200 USB 2.0 bDeviceClass : 0x0 Specified at interface bDeviceSubClass : 0x0 bDeviceProtocol : 0x0 bMaxPacketSize0 : 0x40 (64 bytes) idVendor : 0x072f idProduct : 0x223b bcdDevice : 0x100 Device 1.0 iManufacturer : 0x1 ACS iProduct : 0x2 ACR1252 Dual Reader iSerialNumber : 0x0 bNumConfigurations : 0x1 CONFIGURATION 1: 200 mA ================================== bLength : 0x9 (9 bytes) bDescriptorType : 0x2 Configuration wTotalLength : 0xb1 (177 bytes) bNumInterfaces : 0x2 bConfigurationValue : 0x1 iConfiguration : 0x0 bmAttributes : 0x80 Bus Powered bMaxPower : 0x64 (200 mA) INTERFACE 0: Smart Card ================================ bLength : 0x9 (9 bytes) bDescriptorType : 0x4 Interface bInterfaceNumber : 0x0 bAlternateSetting : 0x0 bNumEndpoints : 0x3 bInterfaceClass : 0xb Smart Card bInterfaceSubClass : 0x0 bInterfaceProtocol : 0x0 iInterface : 0x4 ACR1252 Dual Reader PICC ENDPOINT 0x1: Bulk OUT =============================== bLength : 0x7 (7 bytes) bDescriptorType : 0x5 Endpoint bEndpointAddress : 0x1 OUT bmAttributes : 0x2 Bulk wMaxPacketSize : 0x40 (64 bytes) bInterval : 0x0 ENDPOINT 0x81: Bulk IN =============================== bLength : 0x7 (7 bytes) bDescriptorType : 0x5 Endpoint bEndpointAddress : 0x81 IN bmAttributes : 0x2 Bulk wMaxPacketSize : 0x40 (64 bytes) bInterval : 0x0 ENDPOINT 0x84: Interrupt IN ========================== bLength : 0x7 (7 bytes) bDescriptorType : 0x5 Endpoint bEndpointAddress : 0x84 IN bmAttributes : 0x3 Interrupt wMaxPacketSize : 0x40 (64 bytes) bInterval : 0xa INTERFACE 1: Smart Card ================================ bLength : 0x9 (9 bytes) bDescriptorType : 0x4 Interface bInterfaceNumber : 0x1 bAlternateSetting : 0x0 bNumEndpoints : 0x3 bInterfaceClass : 0xb Smart Card bInterfaceSubClass : 0x0 bInterfaceProtocol : 0x0 iInterface : 0x5 ACR1252 Dual Reader SAM ENDPOINT 0x2: Bulk OUT =============================== bLength : 0x7 (7 bytes) bDescriptorType : 0x5 Endpoint bEndpointAddress : 0x2 OUT bmAttributes : 0x2 Bulk wMaxPacketSize : 0x40 (64 bytes) bInterval : 0x0 ENDPOINT 0x82: Bulk IN =============================== bLength : 0x7 (7 bytes) bDescriptorType : 0x5 Endpoint bEndpointAddress : 0x82 IN bmAttributes : 0x2 Bulk wMaxPacketSize : 0x40 (64 bytes) bInterval : 0x0 ENDPOINT 0x83: Interrupt IN ========================== bLength : 0x7 (7 bytes) bDescriptorType : 0x5 Endpoint bEndpointAddress : 0x83 IN bmAttributes : 0x3 Interrupt wMaxPacketSize : 0x40 (64 bytes) bInterval : 0xa Decimal VendorID=1839 & ProductID=8763 Hexadecimal VendorID=0x72f & ProductID=0x223b 

Instalé PyUSB y puedo detectar el dispositivo usando parte del código de muestra, pero no hay nada como leer la tarjeta NFC cuando está cerca (aunque hay un pitido, lo que me hace creer que el dispositivo USB en sí funciona bien ).

También instalé el paquete libacsccid1 que dice que es compatible con este dispositivo https://github.com/acshk/acsccid , pero no sé exactamente cómo usarlo.

Además de eso, no sé qué más hacer. Cualquier ayuda será apreciada. El objective de mi proyecto es controlar una salida GPIO en función del valor de la etiqueta NFC detectada.

Actualización

He trabajado un poco más y, aunque todavía no puedo hacerlo funcionar, tengo más datos. Específicamente estoy trabajando fuera de esto: http://www.digitalmihailo.com/usb-programming-with-python-on-linux-pyusb-version/

De las hojas de datos puedo confirmar que es un dispositivo de velocidad completa USB 2.0:

introduzca la descripción de la imagen aquí

Para las pruebas, solo quiero hacer sonar el timbre. Aquí está la captura de pantalla del documento API del dispositivo para esta funcionalidad:

introduzca la descripción de la imagen aquí

Entonces, una versión simplificada de http://www.digitalmihailo.com/usb-programming-with-python-on-linux-pyusb-version/ para mi dispositivo sería:

 #!/usr/bin/python import os import sys import time import usb.core import usb.util # According to what I've read, full speed USB is 64 byte packet size. packet_len = 64 # Packing a request. # Packets are 64 bytes long, most of the commands are 4 bytes long. So up to 18 # can be batched into a packet. For example command with bytes [0x94, 0x0, 0x0, 0x0] is getting firmware id def pack_request(*arguments): packet = [0x0] * packet_len i = 0 for arg in arguments: packet[i] = arg i += 1 #packet[0:4] = [0x94, 0x0, 0x0, 0x0] #get firmware id return ''.join([chr(c) for c in packet]) def main(): #Updated for the ACS ACR1252U dev = usb.core.find(idVendor=0x72f, idProduct=0x223b) # was it found? if dev is None: raise ValueError('Device not found') try: dev.detach_kernel_driver(0) except: # this usually mean that kernel driver has already been dettached pass # ACS ACR1252U only has 1 configuration dev.set_configuration() # Interface 0: Dual Reader PICC. This is what we want # Interface 1: Dual Reader SAM try: dev.set_interface_altsetting(0) except usb.core.USBError: print 'Error setting interface!' pass # According to the API, to sound the buzzer we must send: # # Class: 0xe0 # INS: 0x00 # P1: 0x00 # P2: 0x28 # Lc: 0x01 # DataIn (duration): 0xff (for 255 * 10ms = 2.55 seconds) raw = pack_request(0xe0, 0x00, 0x00, 0x28, 0x01, 0xff) #send the packet # Params are (endpoint, data, timeout) # # According to the script output: # ENDPOINT 0x01: Bulk OUT dev.write(endpoint=0x01, data=raw) #done if __name__ == '__main__': main() 

Cuando ejecuto esto, no pasa nada … no hay ningún zumbador, no hay mensaje de error. ¿Qué podría estar mal aquí?

¡Gracias!

Solo por curiosidad abrí Info.plist (en /usr/lib/pcsc/drivers/ifd-acsccid.bundle/Contents/) y noté que mi dispositivo no estaba en la lista.

Así que seguí adelante y agregué mi información en los arreglos ifdVendorID (0x072F), ifdProductID (0x223B) e ifdFriendlyName (ACS ACR1252U Dual PICC-SAM Reader), y ejecuté pcscd -fd.

Solo después de este paso, pcsc_scan realmente detectó mi dispositivo y todo lo demás comenzó a funcionar más o menos. Al final no trabajé con USB directamente, sino que estoy usando la biblioteca pyscard ( http://pyscard.sourceforge.net/ ).

Esto hace que el zumbador funcione:

 def sound_buzzer(reps): #NOTE: This function only works if a card is present! try: hresult, hcontext = SCardEstablishContext(SCARD_SCOPE_USER) assert hresult == SCARD_S_SUCCESS hresult, readers = SCardListReaders(hcontext, []) assert len(readers) > 0 reader = readers[0] hresult, hcard, dwActiveProtocol = SCardConnect(hcontext, reader, SCARD_SHARE_SHARED, SCARD_PROTOCOL_T0 | SCARD_PROTOCOL_T1) while reps > 0: buzzer = [0xE0, 0x00, 0x00, 0x28, 0x01, 0x0F] # 0x0F = 15 * 10ms hresult, response = SCardControl(hcard, SCARD_CTL_CODE(3500), buzzer) sleep(0.15) reps = reps - 1 except Exception, e: #print 'Exception: '+ str(e) pass return