Teensy 4: Trouble with claiming USB Raw HID

Status
Not open for further replies.

Bob Randall

New member
Hello,

I'm new to this forum and have a question on using the Teensy 4.1.

I have a project I am porting from a Cypress PSoC 5LP to the Teensy 4.1 to make use of the much faster Teensy part.

The PSoC part has code which is working. I'm using its USB interface to talk to a Jetson Xavier NX running Linux. This works.

In the Teensy 4.1 project I've configured it to Tools-> USB Type: "Raw HID".

On the Linux board I can run lsusb in a terminal. It lists all the USB devices and does show the Teensy board.

Then I run my program on the Linux board which is written in C++. When that code starts up it opens the USB device (the Teensy) with code that looks like this:

Code:
dev = libusb_open_device_with_vid_pid(NULL, vendor_id, product_id);

The return value dev is not NULL so it found and opened the device. The next line of code is where the trouble is:

Code:
err = libusb_claim_interface(dev, INTERFACE);

This returns an error and when I print the error text I get
Code:
Error: LIBUSB_ERROR_BUSY

So somehow the Linux system is claiming the Teensy USB. The same code works fine with the PSoC. Why is my Linux system claiming the Teensy but not the PSoC? I've tried changing these in the file "usb_desc.h":

#define VENDOR_ID 0x16C0
#define PRODUCT_ID 0x0486
#define RAWHID_USAGE_PAGE 0xFFAB // recommended: 0xFF00 to 0xFFFF
#define RAWHID_USAGE 0x0200 // recommended: 0x0100 to 0xFFFF

and adjusting the code on the Linux side to match. It finds the device but still gives LIBUSB_ERROR_BUSY

I don't understand enough of the USB to know why this works for the PSoC but not the Teensy.

Can anyone point me to the culprit?
 
So somehow the Linux system is claiming the Teensy USB. The same code works fine with the PSoC. Why is my Linux system claiming the Teensy but not the PSoC?

I can't answer for PSoC, but I can tell you Teensy's descriptors say the interface is HID. Most Linux systems have a "hidraw" driver which loads automatically for all HID interfaces which aren't recognized by other drivers. That is (probably) why.

You can check by watching the kernel's syslog messages. On Ubuntu 18, use "tail -f /var/log/syslog". The kernel gives info about the loading and unloading of drivers, so you should what's happening.

Probably the simplest solution is to call libusb_detach_kernel_driver(). In no programs have opened the device, this should work. Hopefully then you can just reuse the rest of that libusb code.

Alternately, you could open the /dev/hidraw# device, and use ordinary read() and write(). But that requires rewriting more code than staying with libusb and just detaching the hidraw driver.

Another (maybe) possible alternative would be to craft a special udev rule which tells the kernel not to load a driver. But I'm not sure how to do that, or even 100% sure it's possible. Still, might be worth a try if you want to use that libusb code without any changes.

Or if you want to leave the PC side unchanged, but you're willing to edit Teensy's core library code, you could edit usb_desc.c to change the protocol byte for this interface, so it's not marked as HID.
 
One more detail to keep in mind is Teensy creates 2 HID interfaces. One is RawHID. The other is meant to emulate Serial, so you can still use Serial.print() to the Arduino Serial Monitor. In your libusb code, make sure you're opening the right interface.
 
With a little more searching on the internet I found this code:

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

This successfully released the kernel driver, so I got past that step. Now I can transmit to the Teensy, but having trouble receiving. I'm checking that now. Almost have it all working...
 
Is there a simple way to get that "Serial.printf" Serial Monitor output on linux without running the Arduino IDE/Serial Monitor?
I ask because I've created a device that uses the RawHID for doing data transfer, but it prints useful debug messages to the Serial.printf() which I can (for now) view by running the arduino IDE+Teensyduino over X11 through an SSH tunnel.

I'd like to be able to run another program (not the full arduino graphical IDE) that just streams the output into a log file that I could periodically parse and take action upon. This would let me get the debug info even when running on a headless system.

Is there a simple way, on Linux, to get those serial-over-RawHID messages from another program that could take action on them, without interfering with the working RawHID connection used by my linux host application?

I'm hoping there's some simple thing here I'm just not seeing...
Thanks,
-Tom
 
Well one thought might be to use one of the real serial UARTs and hook that RX/TX to a serial to USB dongle, and then just read the new USB tty that is created by the dongle. I've not used one, but in theory it should work.

Something like this: https://www.adafruit.com/product/954.

I would suspect you may not want to connect the 3.3v pin, but connect the other 3 wires.
 
Is there a simple way, on Linux, to get those serial-over-RawHID messages from another program that could take action on them, without interfering with the working RawHID connection used by my linux host application?
Did you try TyCommander (https://github.com/Koromix/tytools)? Its main purpose is to provide a more versatile uploader for Teensy. But, it also includes a serial monitor which works with the SerEmu output and can write it to a log file. There also is a command line version (tycmd) of it which might meet your needs.
 
Last edited:
You can try running the teensy_serialmon program. It's installed in {Arduino}/hardware/tools. It expects a single command line parameter for the USB port path. Look in the lower right corner of Arduino after you've selected it in Tools > Ports to get the exact syntax.

Once it opens the port, anything Teensy sends will print to stdout, and anything you type to stdin will be sent to Teensy as if you had used the "Send" line in the Arduino serial monitor.
 
Status
Not open for further replies.
Back
Top