最新消息:雨落星辰是一个专注网站SEO优化、网站SEO诊断、搜索引擎研究、网络营销推广、网站策划运营及站长类的自媒体原创博客

usb - How to write libusb code to read raw mouse data - Stack Overflow

programmeradmin1浏览0评论

I am a beginner with USB and libusb.

I am looking for libusb 1.0 code, capable of reading data from a usb mouse.

I have found some relevant code online, e.g. .c, but does not work for my purpose.

As explained here , the mouse does not receive data.

I am also attaching the code here for convenience:

int main(void)
{
  libusb_device **devs;
  int r;
  int numread;
  ssize_t cnt;
  int counter = 0;
  
  r = libusb_init(&ctx);
  //  r = libusb_init_context(/*ctx=*/NULL, /*options=*/NULL, /*num_options=*/0);  

  if (r < 0)
    return r;

  libusb_set_option(ctx, LIBUSB_OPTION_LOG_LEVEL, LIBUSB_LOG_LEVEL_DEBUG);
  
  libusb_set_debug(ctx, 3); // debug level 3 //

  cnt = libusb_get_device_list(ctx, &devs); // returns device list //
  if (cnt < 0)
    {
      libusb_exit(NULL);
      return (int) cnt;
    }
  
  print_devs(devs);

  libusb_free_device_list(devs, 1);

 // open device //
  handle = libusb_open_device_with_vid_pid(ctx, USB_VENDOR_ID, USB_PRODUCT_ID);

  if (!handle)
    {
      perror("device not found");
      return 1;
    }

  // set auto detach/attach kernel driver //

  r = libusb_set_auto_detach_kernel_driver(handle, 1); // enable = 1 //

  //  r = libusb_detach_kernel_driver(handle, 1); // enable = 1 //

  printf("auto_detach result = %d\n", r);
  
  // claim interface //
  r = libusb_claim_interface(handle, 0);

  if (r < 0)
    {
      fprintf(stderr, "usb_claim_interface error %d\n", r);
      return 2;
    }
  
  printf("Interface claimed\n");

// allocate transfer of data IN (IN to host PC from USB-device)
  transfer_in = libusb_alloc_transfer(1);

  if (transfer_in == NULL)
    {
      printf("ERROR allocating usb transfer.\n");
    }

  // Note: in_buffer is where input data is written //
  //  libusb_fill_bulk_transfer(transfer_in, handle, USB_ENDPOINT_IN, in_buffer, LEN_IN_BUFFER, callback_in, NULL, 0); // NULL for no user data //
  libusb_fill_interrupt_transfer(transfer_in, handle, USB_ENDPOINT_IN, in_buffer, 1, callback_in, NULL, 1); // NULL for no user data, 1 is TIMEOUT //

  // submit next transfer //
  r = libusb_submit_transfer(transfer_in);

  if (r < 0)
    {
      printf("submit transter result = %d\n", r);
    }
  
  // connect SIGINT to function sigint_handler() //
  if (signal(SIGINT, sigint_handler) == SIG_ERR)
    {
      printf("ERROR: Cannot Connect to SIGINT!");
    }

  // Block SIGALRM in the main thread //
  sigset_t sigset;
  sigemptyset(&sigset);
  sigaddset(&sigset, SIGALRM);
  pthread_sigmask(SIG_BLOCK, &sigset, NULL);
  
  printf("WAITING...\n");

  while (exitprogram == 0)
    {
      printf("exitprogram = %d\n", exitprogram);
      
      // waiting //
      //      r = libusb_handle_events_completed(ctx, NULL);
      r = libusb_handle_events(ctx);
      if (r < 0)
    {
      printf("ERROR at events handling\n");
      break;
    }
    }

printf("exitprogram = %d\n", exitprogram);
  
  if (transfer_in)
    {
      r = libusb_cancel_transfer(transfer_in);
      if (r == 0)
    {
      printf("transfer_in successfully cancelled.\n");
    }
      else
    {
      printf("ERROR cancelling transfer\n");
    }
    }

  // close device usb handle //
  
  libusb_close(handle);
  
  libusb_exit(ctx);
  
  return 0;
}

and the callback and signal handlers are as follows:

// called when data for in_buffer is AVAILABLE //
void callback_in(struct libusb_transfer *transfer)
{
  switch (transfer->status)
    {
      case LIBUSB_TRANSFER_COMPLETED:
        {
            // Success here, data transfered are inside 
            // xfr->buffer
            // and the length is
            // xfr->actual_length
      
          printf("LIBUSB_TRANSFER_COMPLETED\n");
          break;
        }
      case LIBUSB_TRANSFER_CANCELLED:
        {
          printf("LIBUSB_TRANSFER_CANCELLED\n");
          break;
        }
      case LIBUSB_TRANSFER_NO_DEVICE:
        {
          printf("LIBUSB_TRANSFER_NO_DEVICE\n");
          break;
        }
      case LIBUSB_TRANSFER_TIMED_OUT:
        {
          printf("LIBUSB_TRANSFER_TIMED_OUT\n");
          break;
        }
      case LIBUSB_TRANSFER_ERROR:
        {
          printf("LIBUSB_TRANSFER_ERROR\n");
          break;
        }
      case LIBUSB_TRANSFER_STALL:
        {
          printf("LIBUSB_TRANSFER_STALL\n");
          break;
        }
      case LIBUSB_TRANSFER_OVERFLOW:
        {
          printf("LIBUSB_TRANSFER_OVERFLOW\n");
          break;
        }
      break;
    }

  printf("transfer flags = %b\n", transfer->flags)

  printf("transfer actual length = %d\n", transfer->actual_length);
  printf("transfer data = %d\n", *(transfer->buffer + 0));

  totalbytes = totalbytes + transfer->actual_length;

  // submit next transfer //
  libusb_submit_transfer(transfer_in);
}

// *** sigint_handler *** //
// note that the SIGINT interupts the main thread //
void sigint_handler(int signo)
{
  write(fileno(stderr), "\nCtrl-C Interrupt Detected.\n", 28);

  exitprogram = 1;
}

What happens is that I don't get ANY interrupt transfers from USB at all, only callback timeouts.

Any help is much appreciated!!!

I am a beginner with USB and libusb.

I am looking for libusb 1.0 code, capable of reading data from a usb mouse.

I have found some relevant code online, e.g. https://github/Mathias-L/STM32F4-libusb-example/blob/master/async.c, but does not work for my purpose.

As explained here https://github/libusb/libusb/discussions/1613, the mouse does not receive data.

I am also attaching the code here for convenience:

int main(void)
{
  libusb_device **devs;
  int r;
  int numread;
  ssize_t cnt;
  int counter = 0;
  
  r = libusb_init(&ctx);
  //  r = libusb_init_context(/*ctx=*/NULL, /*options=*/NULL, /*num_options=*/0);  

  if (r < 0)
    return r;

  libusb_set_option(ctx, LIBUSB_OPTION_LOG_LEVEL, LIBUSB_LOG_LEVEL_DEBUG);
  
  libusb_set_debug(ctx, 3); // debug level 3 //

  cnt = libusb_get_device_list(ctx, &devs); // returns device list //
  if (cnt < 0)
    {
      libusb_exit(NULL);
      return (int) cnt;
    }
  
  print_devs(devs);

  libusb_free_device_list(devs, 1);

 // open device //
  handle = libusb_open_device_with_vid_pid(ctx, USB_VENDOR_ID, USB_PRODUCT_ID);

  if (!handle)
    {
      perror("device not found");
      return 1;
    }

  // set auto detach/attach kernel driver //

  r = libusb_set_auto_detach_kernel_driver(handle, 1); // enable = 1 //

  //  r = libusb_detach_kernel_driver(handle, 1); // enable = 1 //

  printf("auto_detach result = %d\n", r);
  
  // claim interface //
  r = libusb_claim_interface(handle, 0);

  if (r < 0)
    {
      fprintf(stderr, "usb_claim_interface error %d\n", r);
      return 2;
    }
  
  printf("Interface claimed\n");

// allocate transfer of data IN (IN to host PC from USB-device)
  transfer_in = libusb_alloc_transfer(1);

  if (transfer_in == NULL)
    {
      printf("ERROR allocating usb transfer.\n");
    }

  // Note: in_buffer is where input data is written //
  //  libusb_fill_bulk_transfer(transfer_in, handle, USB_ENDPOINT_IN, in_buffer, LEN_IN_BUFFER, callback_in, NULL, 0); // NULL for no user data //
  libusb_fill_interrupt_transfer(transfer_in, handle, USB_ENDPOINT_IN, in_buffer, 1, callback_in, NULL, 1); // NULL for no user data, 1 is TIMEOUT //

  // submit next transfer //
  r = libusb_submit_transfer(transfer_in);

  if (r < 0)
    {
      printf("submit transter result = %d\n", r);
    }
  
  // connect SIGINT to function sigint_handler() //
  if (signal(SIGINT, sigint_handler) == SIG_ERR)
    {
      printf("ERROR: Cannot Connect to SIGINT!");
    }

  // Block SIGALRM in the main thread //
  sigset_t sigset;
  sigemptyset(&sigset);
  sigaddset(&sigset, SIGALRM);
  pthread_sigmask(SIG_BLOCK, &sigset, NULL);
  
  printf("WAITING...\n");

  while (exitprogram == 0)
    {
      printf("exitprogram = %d\n", exitprogram);
      
      // waiting //
      //      r = libusb_handle_events_completed(ctx, NULL);
      r = libusb_handle_events(ctx);
      if (r < 0)
    {
      printf("ERROR at events handling\n");
      break;
    }
    }

printf("exitprogram = %d\n", exitprogram);
  
  if (transfer_in)
    {
      r = libusb_cancel_transfer(transfer_in);
      if (r == 0)
    {
      printf("transfer_in successfully cancelled.\n");
    }
      else
    {
      printf("ERROR cancelling transfer\n");
    }
    }

  // close device usb handle //
  
  libusb_close(handle);
  
  libusb_exit(ctx);
  
  return 0;
}

and the callback and signal handlers are as follows:

// called when data for in_buffer is AVAILABLE //
void callback_in(struct libusb_transfer *transfer)
{
  switch (transfer->status)
    {
      case LIBUSB_TRANSFER_COMPLETED:
        {
            // Success here, data transfered are inside 
            // xfr->buffer
            // and the length is
            // xfr->actual_length
      
          printf("LIBUSB_TRANSFER_COMPLETED\n");
          break;
        }
      case LIBUSB_TRANSFER_CANCELLED:
        {
          printf("LIBUSB_TRANSFER_CANCELLED\n");
          break;
        }
      case LIBUSB_TRANSFER_NO_DEVICE:
        {
          printf("LIBUSB_TRANSFER_NO_DEVICE\n");
          break;
        }
      case LIBUSB_TRANSFER_TIMED_OUT:
        {
          printf("LIBUSB_TRANSFER_TIMED_OUT\n");
          break;
        }
      case LIBUSB_TRANSFER_ERROR:
        {
          printf("LIBUSB_TRANSFER_ERROR\n");
          break;
        }
      case LIBUSB_TRANSFER_STALL:
        {
          printf("LIBUSB_TRANSFER_STALL\n");
          break;
        }
      case LIBUSB_TRANSFER_OVERFLOW:
        {
          printf("LIBUSB_TRANSFER_OVERFLOW\n");
          break;
        }
      break;
    }

  printf("transfer flags = %b\n", transfer->flags)

  printf("transfer actual length = %d\n", transfer->actual_length);
  printf("transfer data = %d\n", *(transfer->buffer + 0));

  totalbytes = totalbytes + transfer->actual_length;

  // submit next transfer //
  libusb_submit_transfer(transfer_in);
}

// *** sigint_handler *** //
// note that the SIGINT interupts the main thread //
void sigint_handler(int signo)
{
  write(fileno(stderr), "\nCtrl-C Interrupt Detected.\n", 28);

  exitprogram = 1;
}

What happens is that I don't get ANY interrupt transfers from USB at all, only callback timeouts.

Any help is much appreciated!!!

Share Improve this question asked Mar 6 at 14:54 ChristosChristos 1 2
  • You are only giving it a 1-byte buffer. You need to read and decode the USB HID descriptor to know how long the input reports are. USB is a packet protocol; you don't read a byte at a time. Also, you haven't included the endpoint number. USB_ENDPOINT_IN is just flag. You need to get the appropriate endpoint number from the configuration descriptor. lsusb can help with that. – Tim Roberts Commented Mar 6 at 19:11
  • As a side note, there are a lot of USB experimenter's kits that would allow you to play with simple USB concepts without dealing with the complexities of an existing class device. – Tim Roberts Commented Mar 6 at 19:12
Add a comment  | 

1 Answer 1

Reset to default 0

I have managed to make good progress with this. I switched to using a simple Microsoft Basic Optical Mouse:

// Microsoft Corp. Basic Optical Mouse 
#define USB_VENDOR_ID       0x045e      /* USB vendor ID used by the device */ 
#define USB_PRODUCT_ID      0x0084      /* USB product ID used by the device */ 

and the following code now works for the former mouse:

int main(void)
{
  libusb_device **devs;
  int r;
  int numread;
  ssize_t cnt;
  int counter = 0;
  
  // connect SIGINT to function sigint_handler() //
  if (signal(SIGINT, sigint_handler) == SIG_ERR)
    {
      printf("ERROR: Cannot Connect to SIGINT!");
    }

  // Block SIGALRM in the main thread //
  sigset_t sigset;
  sigemptyset(&sigset);
  sigaddset(&sigset, SIGALRM);
  pthread_sigmask(SIG_BLOCK, &sigset, NULL);
  
  r = libusb_init(&ctx);
  //  r = libusb_init_context(/*ctx=*/NULL, /*options=*/NULL, /*num_options=*/0);  

  if (r < 0)
    return r;

  //  libusb_set_option(ctx, LIBUSB_LOG_LEVEL_WARNING);
  
  libusb_set_debug(ctx, 3); // debug level 3 //

  cnt = libusb_get_device_list(ctx, &devs); // returns device list //
  if (cnt < 0)
    {
      libusb_exit(NULL);
      return (int) cnt;
    }
  
  print_devs(devs);

  libusb_free_device_list(devs, 1);

  // open device //
  handle = libusb_open_device_with_vid_pid(ctx, USB_VENDOR_ID, USB_PRODUCT_ID);

  if (!handle)
    {
      perror("device not found");
      return 1;
    }

  // set auto detach/attach kernel driver //
  r = libusb_set_auto_detach_kernel_driver(handle, 1); // enable = 1 //
  
  printf("auto_detach result = %d\n", r);
  
  // claim interface //
  r = libusb_claim_interface(handle, 0);

  if (r < 0)
    {
      fprintf(stderr, "usb_claim_interface error %d\n", r);
      return 2;
    }
  
  printf("Interface claimed\n");

  printf("Resetting Device\n");

  r = libusb_reset_device(handle);

  if (r < 0)
    {
      printf("ERROR %d resetting device!\n");
    }
  
  printf("*** Device Descriptor ***\n");

  r = libusb_get_descriptor(handle, LIBUSB_DT_DEVICE, 0, desc_buffer, 1024);

  dump_descriptor(r, desc_buffer, r);

  //////////////////////////////////////////////////////
  
  // allocate transfer of data IN (IN to host PC from USB-device)
  transfer_in = libusb_alloc_transfer(1);

  if (transfer_in == NULL)
    {
      printf("ERROR allocating usb transfer.\n");
    }

  // Note: in_buffer is where input data is written //
  //  libusb_fill_bulk_transfer(transfer_in, handle, USB_ENDPOINT_IN, in_buffer, LEN_IN_BUFFER, callback_in, NULL, 0); // NULL for no user data //
  libusb_fill_interrupt_transfer(transfer_in, handle, USB_ENDPOINT_IN, in_buffer, 8, callback_in, NULL, 0); // NULL for no user data //

  // submit next transfer //
  r = libusb_submit_transfer(transfer_in);

  if (r < 0)
    {
      printf("submit transter result = %d\n", r);
    }

  while (exitprogram == 0)
    {
      printf("exitprogram = %d\n", exitprogram);
      
      // waiting //
      //      r = libusb_handle_events_completed(ctx, NULL);
      r = libusb_handle_events(ctx);
      if (r < 0)
    {
      printf("ERROR at events handling\n");
      break;
    }
    }

  printf("exitprogram = %d\n", exitprogram);
  
  if (transfer_in)
    {
      r = libusb_cancel_transfer(transfer_in);
      if (r == 0)
    {
      printf("transfer_in successfully cancelled.\n");
    }
      else
    {
      printf("ERROR cancelling transfer\n");
    }
    }

    //////////////////////////////////////////////////////

  // if you DONT release the interface, communication halts //

  // release interface //
  r = libusb_release_interface(handle, 0);

  if (r < 0)
    {
      fprintf(stderr, "usb_release_interface error %d\n", r);
    }
  
  printf("Interface released\n");

  // close device usb handle //
  
  libusb_close(handle);
  
  libusb_exit(ctx); 

}



and in my callback function callback_in(), I dump the libusb_tranfer, i.e. transfer->status and the raw bytes received.

For the Microsoft mouse it all works well, and I get the following output, based on the mouse movement and buttons pressed:

...

LIBUSB_TRANSFER_COMPLETED
transfer flags = %b
transfer actual length = 8
0: transfer data = 4
1: transfer data = 0
2: transfer data = 255
3: transfer data = 0
4: transfer data = 4
5: transfer data = 0
6: transfer data = 255
7: transfer data = 0
exitprogram = 0
LIBUSB_TRANSFER_COMPLETED
transfer flags = %b
transfer actual length = 8
0: transfer data = 4
1: transfer data = 0
2: transfer data = 255
3: transfer data = 0
4: transfer data = 0
5: transfer data = 0
6: transfer data = 0
7: transfer data = 0
exitprogram = 0

...

The buffer size I use is 8, which is equal to the value of the maximum packet size of the USB Device descriptor, and in this case it works.

I am NOT sure what size of transfer to specify, but 8 works in this case.

When using difference mice, e.g. Logitech G5 Laser, or wireless Logitech mini mouse, instead of getting LIBUSB_TRANSFER_COMPLETED I get LIBUSB_TRANSFER_OVERFLOW, even if I use a HUGE buffer of 1024 bytes...

I looked up the USB HID document, but I am not sure HOW to send the proper control packet to configure other mice. On this webpage, https://www.usbmadesimple.co.uk/ums_5.htm it is explaned that you must send "an HID class report descriptor, which in this case informs the appropriate driver to expect to receive a 4 byte report of mouse events on its interrupt IN endpoint."

Any help of sending the proper HID class report descriptor would be much appreciated.

发布评论

评论列表(0)

  1. 暂无评论