Teensy 4.0 USB Host not working properly

skylight

Member
Hi guys.

I posted a thread before about this issue I have, for some reason I am posting another one with more details.
So basically I have this DTV and I want to connect to my teensy usb host to be able to receive and send data and see this data traffic in general. I connected it physically to teensy's usb host port. I also extracted some information about DTV like its PID, VID with usb tree view. Then I programmed my teensy with this sketch which is very similar to one of the examples of USBHost_t36 (USB to USBHost example if I'm not mistaken):

Code:
#include <USBHost_t36.h>

#define BAUD 115200


uint32_t             format = USBHOST_SERIAL_8N1;
USBHost              myusb;
USBSerial_BigBuffer  userial(myusb, 1, 0xPID, 0xVID, USBSerialBase::CP210X, 0); // types: FTDI, PL2303, CH341, CP210X
char                 buffer[512];
char                 mybuffer[512] = "some dummy data";


void setup() {
  myusb.begin();
  userial.begin(BAUD);
  Serial.begin(BAUD);
  Serial.println("setup completed.");
}


void loop() {
  myusb.Task();
  uint16_t rd, wr, n;
 
    // write to usb host
    wr = userial.availableForWrite();
    if (wr > 0){
      userial.write(mybuffer, sizeof(mybuffer));
      Serial.println("write successful!");
    }
    else{
      Serial.println("userial not available");
    }


    // read from usb host
    rd = userial.available();
    if (rd > 0) {
      Serial.println("usb host available");
      n = userial.readBytes((char *)buffer, rd);
      Serial.println((char *)buffer);
      // check if the USB virtual serial port is ready to transmit
      wr = Serial.availableForWrite();
      if (wr > 0) {
        if (rd > wr) rd = wr;
        if (rd > 80) rd = 80;
        // read data from the USB host serial port
        n = userial.readBytes((char *)buffer, rd);
        Serial.println("read successful!");
      }
    }
 
 }


The issue I'm facing is that I can write to this device, but can't read from it!
In Serial Monitor, I only see "write successful!" and there's no "read successful!".

What could possibly be the reason? To be honest I don't understand much about this type of communication since it's a vendor specific device and perhaps not very straightforward to work with.



I appreciate your help <3
 
Are you sure the "DTV" is actually a USB serial device? What do the USB descriptors for it look like?
 
What is the serial protocol on the DTV ? Is it binary ? Text ? command-response, either binary or text ???
It will probably accept commands ending by a carriage return. And the respond with datas.
In you example, you don't send any carriage return.
 
Are you sure the "DTV" is actually a USB serial device? What do the USB descriptors for it look like?
yes, I think so. The descriptor and protocol looks something like this:
Code:
    ---------------------- Device Descriptor ----------------------
bLength                  : 0x12 (18 bytes)
bDescriptorType          : 0x01 (Device Descriptor)
bcdUSB                   : 0x200 (USB Version 2.0)
bDeviceClass             : 0x00 (defined by the interface descriptors)
bDeviceSubClass          : 0x00
bDeviceProtocol          : 0x00
bMaxPacketSize0          : 0x40 (64 bytes)

......

and the rest is some manufacturer info. Interface descriptor looks like this:
Code:
        ---------------- Interface Descriptor -----------------
bLength                  : 0x09 (9 bytes)
bDescriptorType          : 0x04 (Interface Descriptor)
bInterfaceNumber         : 0x00 (Interface 0)
bAlternateSetting        : 0x00
bNumEndpoints            : 0x04 (4 Endpoints)
bInterfaceClass          : 0xFF (Vendor Specific)
bInterfaceSubClass       : 0x00
bInterfaceProtocol       : 0x00
iInterface               : 0x00 (No String Descriptor)
Data (HexDump)           : 09 04 00 00 04 FF 00 00 00                        .........

Unfortunately I don't really understand how the packet transmission and protocols work...
 
What is the serial protocol on the DTV ? Is it binary ? Text ? command-response, either binary or text ???
It will probably accept commands ending by a carriage return. And the respond with datas.
In you example, you don't send any carriage return.
I posted some descriptor info if that helps. I'm not really sure how the protocol works, thus I just send dummy data with no carriage return or any special characters in my example.
 
That doesn't really look anything like any of the common USB serial device descriptors, it looks like a very vendor-specific device.
 
That doesn't really look anything like any of the common USB serial device descriptors, it looks like a very vendor-specific device.
Yes, it's totally vendor specific (and is making it difficult for me to work with). I am using its driver on windows.
What I'm basically trying to do, is to see the traffic before it gets to PC and improve its image quality if necessary.
Image processing part is not my duty and is not related to me, I'm just trying to see usb data transmission. I can do the userial.write operation but can't do a read operation which is odd.
 
You can't just read and write to any USB device like a serial port. USBSerial_BigBuffer will only work with devices that match one of the supported protocols.
 
Sorry this is almost nothing to go on here.

If you have not already done so, you should try running with the USBHost debug turned on:
Edit USBHost_t36.h At about line 63 you should see:
Code:
//#define USBHOST_PRINT_DEBUG
Uncomment it and rebuild.

It should show the stuff like PID/VID and stuff in some cases where different derives like the Serial object takes a look at it.

The claim for Serial code starts with:
Code:
bool USBSerialBase::claim(Device_t *dev, int type, const uint8_t *descriptors, uint32_t len)
{
    print("USBSerial(", _max_rxtx, DEC);
    println(")claim this=", (uint32_t)this, HEX);
    print("vid=", dev->idVendor, HEX);
    print(", pid=", dev->idProduct, HEX);
    print(", bDeviceClass = ", dev->bDeviceClass);
       print(", bDeviceSubClass = ", dev->bDeviceSubClass);
       println(", bDeviceProtocol = ", dev->bDeviceProtocol);
    print_hexbytes(descriptors, len);

Which will be enabled by that define.

If it is not a Serial device and with it all vendor specific, I doubt it would work, but RAWHID reads in and writes out full 64 byte packets.

You could try to create your own simple class, like I did in the example sketch HIDDeviceInfo,
Which claims the different interfaces and prints out information about them.
You could have it claim your object and see if by chance it will send you data..

It may or may not. As many devices have their own protocol to setup before they will send. Like maybe an enable message, maybe a report selection... Hard to say.

What I would typically do, is:
a) See if there is anyone who has done a driver for this device. Like is there a linux driver for it, that you can look at the sources?

b) And/or I would try to hook it up to some device that supports it and hook up a logic analyzer to try to capture the USB traffic and decode it and then see if we can emulate it. This is what we did for several of the devices we do support. But my logic analyzer can only handle
Low speed and full speed devices(12Mbs), not High speed (480Mbs), you may be in luck and it is FS if it is 64 packets. A lot of High speed ones are defined with 512...

c) Use a USB analyzer. I don't have one, but for example Paul has one by Beagle (I think).
c1) There are some software packages like: WireShark that runs on PC or Linux which can capture some of this.

Good luck
 
Sorry this is almost nothing to go on here.

If you have not already done so, you should try running with the USBHost debug turned on:
Edit USBHost_t36.h At about line 63 you should see:
Code:
//#define USBHOST_PRINT_DEBUG
Uncomment it and rebuild.

It should show the stuff like PID/VID and stuff in some cases where different derives like the Serial object takes a look at it.

The claim for Serial code starts with:
Code:
bool USBSerialBase::claim(Device_t *dev, int type, const uint8_t *descriptors, uint32_t len)
{
    print("USBSerial(", _max_rxtx, DEC);
    println(")claim this=", (uint32_t)this, HEX);
    print("vid=", dev->idVendor, HEX);
    print(", pid=", dev->idProduct, HEX);
    print(", bDeviceClass = ", dev->bDeviceClass);
       print(", bDeviceSubClass = ", dev->bDeviceSubClass);
       println(", bDeviceProtocol = ", dev->bDeviceProtocol);
    print_hexbytes(descriptors, len);

Which will be enabled by that define.

If it is not a Serial device and with it all vendor specific, I doubt it would work, but RAWHID reads in and writes out full 64 byte packets.

You could try to create your own simple class, like I did in the example sketch HIDDeviceInfo,
Which claims the different interfaces and prints out information about them.
You could have it claim your object and see if by chance it will send you data..

It may or may not. As many devices have their own protocol to setup before they will send. Like maybe an enable message, maybe a report selection... Hard to say.

What I would typically do, is:
a) See if there is anyone who has done a driver for this device. Like is there a linux driver for it, that you can look at the sources?

b) And/or I would try to hook it up to some device that supports it and hook up a logic analyzer to try to capture the USB traffic and decode it and then see if we can emulate it. This is what we did for several of the devices we do support. But my logic analyzer can only handle
Low speed and full speed devices(12Mbs), not High speed (480Mbs), you may be in luck and it is FS if it is 64 packets. A lot of High speed ones are defined with 512...

c) Use a USB analyzer. I don't have one, but for example Paul has one by Beagle (I think).
c1) There are some software packages like: WireShark that runs on PC or Linux which can capture some of this.

Good luck
I'm going to try this step by step. Thanks a lot!
<3
 
Hi there again..
Sorry this is almost nothing to go on here.

If you have not already done so, you should try running with the USBHost debug turned on:
Edit USBHost_t36.h At about line 63 you should see:
Code:
//#define USBHOST_PRINT_DEBUG
Uncomment it and rebuild.

It should show the stuff like PID/VID and stuff in some cases where different derives like the Serial object takes a look at it.

The claim for Serial code starts with:
Code:
bool USBSerialBase::claim(Device_t *dev, int type, const uint8_t *descriptors, uint32_t len)
{
    print("USBSerial(", _max_rxtx, DEC);
    println(")claim this=", (uint32_t)this, HEX);
    print("vid=", dev->idVendor, HEX);
    print(", pid=", dev->idProduct, HEX);
    print(", bDeviceClass = ", dev->bDeviceClass);
       print(", bDeviceSubClass = ", dev->bDeviceSubClass);
       println(", bDeviceProtocol = ", dev->bDeviceProtocol);
    print_hexbytes(descriptors, len);

Which will be enabled by that define.

If it is not a Serial device and with it all vendor specific, I doubt it would work, but RAWHID reads in and writes out full 64 byte packets.

You could try to create your own simple class, like I did in the example sketch HIDDeviceInfo,
Which claims the different interfaces and prints out information about them.
You could have it claim your object and see if by chance it will send you data..

It may or may not. As many devices have their own protocol to setup before they will send. Like maybe an enable message, maybe a report selection... Hard to say.

What I would typically do, is:
a) See if there is anyone who has done a driver for this device. Like is there a linux driver for it, that you can look at the sources?

b) And/or I would try to hook it up to some device that supports it and hook up a logic analyzer to try to capture the USB traffic and decode it and then see if we can emulate it. This is what we did for several of the devices we do support. But my logic analyzer can only handle
Low speed and full speed devices(12Mbs), not High speed (480Mbs), you may be in luck and it is FS if it is 64 packets. A lot of High speed ones are defined with 512...

c) Use a USB analyzer. I don't have one, but for example Paul has one by Beagle (I think).
c1) There are some software packages like: WireShark that runs on PC or Linux which can capture some of this.

Good luck

So I have been working on this and using Wireshark captures and frame packets, I am now able to do a handshake - I can now both perform the read and write operations.
The next step for me is to connect teensy to my pc in a way that it becomes transparent. For this purpose, I modified teensy descriptor files (usb_desc.h and usb_desc.c) similar to the DTV's and installed its driver on teensy in device manager. So it would seem like the DTV is connected to the pc and sends/receives data but it's actually not directly connected (it's connected to teensy's USB host).
I should be able to open VLC player and watch television just like I do with DTV directly connected to pc.
The problem I'm facing now, is that when I connect teensy to my pc, there's a yellow warning sign appearing in device manager and in device status it says:

This device cannot start. (Code 10)
{Operation Failed}
The requested operation was unsuccessful.


What could be the reason? Is this approach practical? If so, am I actually doing this right?


Thanks.
 
Back
Top