0

I have recently bought an 2D barcode scanner module from china. As per their datasheet, it worked fine scanning barcodes when I open a notepad. All i need to do is try using libusb and read the barcode on my c code. I use Intel edison with Adrunio breakout board which is configured as usb host.

I have installed libusb-1.0.20 and unfortunately I couldn't install libusb-1.0.20-devel. Please note I am not using libusbx and libusbx-devel here.

As it is bardcode scanner device, it was supposed to get detected as HID keyboard. Yes it was.

Bus 001 Device 003: ID 1eab:8203
Device Descriptor:
  bLength                18
  bDescriptorType         1
  bcdUSB               1.10
  bDeviceClass            0 (Defined at Interface level)
  bDeviceSubClass         0
  bDeviceProtocol         0
  bMaxPacketSize0        64
  idVendor           0x1eab
  idProduct          0x8203
  bcdDevice            1.00
  iManufacturer           1 NewLand
  iProduct                2 HidKeyBoard
  iSerial                 0
  bNumConfigurations      1
  Configuration Descriptor:
    bLength                 9
    bDescriptorType         2
    wTotalLength           34
    bNumInterfaces          1
    bConfigurationValue     1
    iConfiguration          0
    bmAttributes         0x80
      (Bus Powered)
    MaxPower              200mA
    Interface Descriptor:
      bLength                 9
      bDescriptorType         4
      bInterfaceNumber        0
      bAlternateSetting       0
      bNumEndpoints           1
      bInterfaceClass         3 Human Interface Device
      bInterfaceSubClass      1 Boot Interface Subclass
      bInterfaceProtocol      1 Keyboard
      iInterface              0
        HID Device Descriptor:
          bLength                 9
          bDescriptorType        33
          bcdHID               1.10
          bCountryCode            0 Not supported
          bNumDescriptors         1
          bDescriptorType        34 Report
          wDescriptorLength      63
         Report Descriptors:
           ** UNAVAILABLE **
      Endpoint Descriptor:
        bLength                 7
        bDescriptorType         5
        bEndpointAddress     0x84  EP 4 IN
        bmAttributes            3
          Transfer Type            Interrupt
          Synch Type               None
          Usage Type               Data
        wMaxPacketSize     0x0008  1x 8 bytes
        bInterval               1
Device Status:     0x0001
  Self Powered

And my c code is:

#include <stdio.h>
#include <stdlib.h>
#include <stdint.h>
//gcc -o usbtest usbtest.c -lusb-1.0
//libusbx-devel, libusbx
#include <libusb-1.0/libusb.h>
void print_devices(libusb_device *dev)
{
    struct libusb_device_descriptor desc;
    struct libusb_config_descriptor *config;
    const struct libusb_interface *inter;
    const struct libusb_interface_descriptor *interdesc;
    const struct libusb_endpoint_descriptor *endpointdesc;

int ret;
int i,j,k;

ret = libusb_get_device_descriptor(dev, & desc);
if(ret < 0)
{
    fprintf(stderr, "error in getting device descriptor\n");
    return;
}

printf("Number of possible configs is %d\n",desc.bNumConfigurations);
printf("Vendor ID  : 0x%x\n", desc.idVendor);
printf("Product ID : 0x%x\n", desc.idProduct);

libusb_get_config_descriptor(dev, 0, &config);

printf("Interface %d\n", config->bNumInterfaces);

for(i=0; i < config->bNumInterfaces; i++)
{
    inter = &config->interface[i];
    printf("Number of alternate settings : %d\n", inter->num_altsetting);
    for(j=0; j < inter->num_altsetting; j++)
    {
        interdesc = &inter->altsetting[j];
        printf("   Interface number : %d, ", interdesc->bInterfaceNumber);
        printf("   Num of endpoints : %d\n", interdesc->bNumEndpoints);
        for(k=0; k < interdesc->bNumEndpoints; k++)
        {
            endpointdesc = &interdesc->endpoint[k];
            printf("     Desc type : %d ",endpointdesc->bDescriptorType);
            printf("      EP Addr: %d\n", endpointdesc->bEndpointAddress);
        }
    }
}
printf("\n\n");
libusb_free_config_descriptor(config);
}


int main(int argc, char *argv[])
{
    libusb_device **devs; //pointer to pointer of device, used to retrieve a list of devices
    libusb_context *context = NULL; //a libusb session
    libusb_device_handle *dev_handle; //a device handle

size_t list;
size_t iter;
int retVal;
int kernelDriverDetached     = 0;  /* Set to 1 if kernel driver detached */

retVal = libusb_init(&context);
if(retVal < 0)
{
    perror("libusb_init");
    exit(1);
}

libusb_set_debug(context, 3); //set verbosity level to 3, as suggested in the documentation

list = libusb_get_device_list(context, &devs);
if(list < 0){
    fprintf(stderr, "Error in getting device list\n");
    libusb_free_device_list(devs, 1);
    libusb_exit(context);
    exit(1);
}

printf("There are %d devices found\n",list);

for(iter = 0; iter < list; iter++)
{
    /* print devices specs */
    print_devices(devs[iter]);
}

dev_handle = libusb_open_device_with_vid_pid(context, 0x1eab, 0x8203/*0x1d6b,0x0002*/); //these are vendorID and productID I found for my usb device
    if(dev_handle == NULL) {
    fprintf(stderr, "Unable to open device.\n");
        return 1;

}

/* Check whether a kernel driver is attached to interface #0. If so, we'll 
 * need to detach it.
 */
if (libusb_kernel_driver_active(dev_handle, 0))
{
        retVal = libusb_detach_kernel_driver(dev_handle, 0);
        if (retVal == 0)
        {
            kernelDriverDetached = 1;
        }
        else
        {
            fprintf(stderr, "Error detaching kernel driver.\n");
            return 1;
        }
}

/* Claim interface #0. */
retVal = libusb_claim_interface(dev_handle, 0);
if (retVal != 0)
{
        fprintf(stderr, "Error claiming interface.\n");
        return 1;
}

printf("Scanner Device Opened\n");

    struct libusb_transfer *transfer = libusb_alloc_transfer(0);
char buf[24];
int actualbytes;    
retVal = libusb_interrupt_transfer(dev_handle, /*0x84*/(4 | LIBUSB_ENDPOINT_IN), buf, 24, &actualbytes, 0);
if(retVal == 0) {
    printf("Received %d bytes\n",actualbytes);
}
else
{
    fprintf(stderr, "Error Receiving message. retVal : %d, Actual : %d\n",retVal,actualbytes);
}

for(iter = 0; iter < actualbytes; iter++){
    printf("Data[%d] = %d\n",iter,buf[iter]);
}

/* Release interface #0. */
retVal = libusb_release_interface(dev_handle, 0);
if (0 != retVal)
{
        fprintf(stderr, "Error releasing interface.\n");
}

/* If we detached a kernel driver from interface #0 earlier, we'll now 
 * need to attach it again.  */
if (kernelDriverDetached)
{
        libusb_attach_kernel_driver(dev_handle, 0);
}

/* Shutdown libusb. */
libusb_free_device_list(devs, 1); //free the list, unref the devices in it
libusb_exit(context);


return 0;
}

I could able to compile and run the code, scan, open, read the device. But the data what I could read is all zero. Even though it says wMaxPacketSize 0x0008 1x 8 bytes and bLength 18 it gave me error when I tried with length as 8,16,18. So I changed to 24. My actual barcode (1D) data size is 12bytes.

Is it something wrong on the code or should I need to add more core to read the actual bardcode.

kar
  • 495
  • 1
  • 8
  • 19
  • 1
    Are really all bytes zero? Normally 1 or 2 out of 8 bytes shouldhave a value != 0 where all the remaining ones are supposed to be 0 because that is how HID works. – dryman May 23 '16 at 07:45
  • not all first and 3rd bytes have some values in it – kar May 23 '16 at 19:27
  • Yes like you already wrote in your answer you only got the HID data. That is supposed to be like this. – dryman May 24 '16 at 09:25

1 Answers1

0

I understood that since it detects as a HID keyboard device, the data which I had received will not be in ASCII format(which is what I was expecting). I have modified the code according to https://www.win.tue.nl/~aeb/linux/kbd/scancodes-14.html

Even though the document says 16-bit keycode, I was getting correct data only if I read 16 bytes. based on the keycode, I have created a table which converts HID keycode to ASCII.

But still this doesn't works on my Windows machine, as it says it cannot open the device.

kar
  • 495
  • 1
  • 8
  • 19
  • About the thing with not working on Windows: Have you installed a backend driveR? Windows won't surrender HID keyboards and mice without changing the driver. – dryman May 24 '16 at 09:26
  • i am trying for it.. is it libusb-win32 or WinUSB? Is there any specific link that could help me – kar May 25 '16 at 00:17
  • Since you use libusb 1 you can choose yourself which one you prefer. libusb-win32 is afaik opensource but not maintained anymore and WinUSB is proprietary but maintained by Microsoft. An easy way to create and/or install a driver for libusb is Zadig. Zadig automates more or less the complete process. – dryman May 25 '16 at 07:04
  • @dryman: yeah.. i am trying with Zadig but when choose my device it say it has `HidUsb (v10.0.10586.306)`. Should I need to replace the driver. when I tried for both libusb-win32 (v1.2.6.0) and/or WinUSB (v6.1.7600.16385) it give me an error message saying installation failed. – kar May 25 '16 at 18:12
  • when I tried to execute the code which uses libusb, i got messages like `libusb: warning [windows_get_device_list] could not retrieve port number for device '\\.\ROOT#INTEL_UOIP_BUS_DRIVER#0000', skipping: [13] The data is invalid. libusb: warning [hid_open] could not open HID device in R/W mode (keyboard or mouse?) - trying without libusb: error [hid_submit_bulk_transfer] unable to match endpoint to an open interface - cancelling transfer` – kar May 25 '16 at 18:14
  • The problem is that you have a HID keyboard which is protected on Windows. Therefore you can not directly access it and need your own driver to access it via libusb. About Zadiq: Have you tried just extracting the driver and installing it with the device manager? Another way around it without libusb is using RawInput on Windows to access the HID data somewhere up the driver ladder. – dryman May 27 '16 at 07:30