T4.x support for Raw HID 512? wonder if it makes sense to add to system?

KurtE

Senior Member+
While pulling out the last few my hairs trying to figure out why in the FS Integration thread: https://forum.pjrc.com/threads/68139-Teensyduino-File-System-Integration-including-MTP-and-MSC
why at times when we transfer a file to one of the storage areas on Teensy, sometimes we get incomplete transfers, other times maybe reboots... I thought I would play with Raw HID.

This is not completely random as a lot of the MTP USB code is very similar to the raw hid support. Also sounded like a fun distraction while waiting for inspiration or answers to some of the pending issues in the integration.

So I started playing with it and have some stuff working I believe. I have this up in a Fork/Branch of cores:
https://github.com/KurtE/cores/tree/rawhid_512

I also have it setup, on the T4.x to be able to build for either 64 or 512 by choosing different USB option... My boards.local.txt have:
Code:
teensy41.menu.usb.rawhid512=Raw HID 512
teensy41.menu.usb.rawhid512.build.usbtype=USB_RAWHID512
teensy41.menu.usb.rawhid512.fake_serial=teensy_gateway

teensyMM.menu.usb.rawhid512=Raw HID 512
teensyMM.menu.usb.rawhid512.build.usbtype=USB_RAWHID512
teensyMM.menu.usb.rawhid512.fake_serial=teensy_gateway

teensy40.menu.usb.rawhid512=Raw HID 512
teensy40.menu.usb.rawhid512.build.usbtype=USB_RAWHID512
teensy40.menu.usb.rawhid512.fake_serial=teensy_gateway

Note: I added a couple of methods to RawHid to allow the sketch to see what is the size of transfers. As there are chances even if you build for 512 it will run at 64 if the host does not support High speed.

I updated the Host side code, so far only Linux as don't know how to build for windows... Have not tried yet, my guess is, it will require installing additional stuff...

With the Linux side, again there are methods to query the size of transfers.

I have not played yet with the writes on Teensy to host, as I am mainly interested in emulating the SendObject functionality. Still more testing there, like introducing delays.

Example sketch:
Code:
/* RawHID receive big 
  This example code is in the public domain.
*/

// RawHID packets are always 64 bytes
byte buffer[512];

int rx_size;

unsigned int packetCount = 0;
uint32_t last_packet_number = (uint32_t) - 1;
uint32_t packet_count = 0;
elapsedMillis em;
elapsedMillis emTotal;
bool run_active = false;

void setup() {
  while (!Serial);
  pinMode(13, OUTPUT);
  Serial.begin(9600);
  Serial.println(F("RawHID lots of input test"));
  rx_size = RawHID.rxSize();
//  rx_size = 64;
  Serial.printf("RawHid RX Size: %d\n", rx_size);
  em = 0;
  Serial.println(F("Waiting for packets"));
}


void loop() {
  int n;
  n = RawHID.recv(buffer, 0); // 0 timeout = do not wait
  if (n > 0) {
    packet_count++;
    digitalToggleFast(13);
    // check Serial numbers
    uint32_t packet_number = 0;
    for (int i = 0; buffer[i] >= '0' && buffer[i] <= '9'; i++) {
      packet_number = packet_number * 10 + buffer[i] - '0';
    }
    if (packet_number == 0) {
      Serial.println("Looks like new run started");
      last_packet_number = 0;
      packet_count = 1;
      emTotal = 0;
    } else if (packet_number != (last_packet_number + 1)) {
      Serial.printf("Missing? cnt: %u, Last: %u cur:%u\n", packet_count, packet_number, last_packet_number);
    } else if ((buffer[8] != buffer[rx_size-2]) || (buffer[rx_size-1] != '\n')) {
      Serial.printf("msg format error: %u\n", packet_count);
    }
    if (buffer[7] == '$') {
      Serial.printf("Received end marker: %u %u Time:%u\n", packet_count, packet_number,
        (uint32_t)emTotal);
    }
    last_packet_number = packet_number;
    run_active = true;
    em = 0;
    if ((packet_count & 0x3ff) == 0) Serial.print(".");
    if ((packet_count & 0xffff) == 0) Serial.println();
  } else if (run_active && (em > 1000)) {
    Serial.printf("\nTimeout: %u %u\n", packet_count, last_packet_number);
    run_active = false;
    
  }
}

Linux code:
Code:
#include <stdio.h>
#include <stdlib.h>
#include <stdarg.h>
#include <stdint.h>
#include <string.h>

#if defined(OS_LINUX) || defined(OS_MACOSX)
#include <sys/ioctl.h>
#include <termios.h>
#elif defined(OS_WINDOWS)
#include <conio.h>
#endif

#include "hid.h"

#define MAX_PACKET_SIZE 512

#define FILE_SIZE 22400000ul
int packet_size;
uint32_t count_packets;

int main()
{
	int r;
	char buf[MAX_PACKET_SIZE];

	// C-based example is 16C0:0480:FFAB:0200
	r = rawhid_open(1, 0x16C0, 0x0480, 0xFFAB, 0x0200);
	if (r <= 0) {
		// Arduino-based example is 16C0:0486:FFAB:0200
		r = rawhid_open(1, 0x16C0, 0x0486, 0xFFAB, 0x0200);
		if (r <= 0) {
			printf("no rawhid device found\n");
			return -1;
		}
	}
	printf("found rawhid device\n");

	printf("Starting output(%u)\n", count_packets);
	printf("Rx Size:%d Tx Size:%d\n", rawhid_rxSize(0), rawhid_txSize(0));
	packet_size = rawhid_txSize(0);
	if (packet_size <= 0) {
		printf("invalid size field");
		return -1;
	}
	count_packets = FILE_SIZE / packet_size;

	for (uint32_t packet_num = 0; packet_num < count_packets; packet_num++){
		memset(buf, 'A' + (packet_num & 0xf), packet_size) ;
		sprintf(buf, "%07u", packet_num);
		buf[7] = (packet_num == (count_packets-1))? '$' : ' ';
		buf[packet_size-1] = '\n';
		rawhid_send(0, buf, packet_size, 100);
		if ((packet_num & 0x1ff) == 0) printf(".");
		if ((packet_num & 0xffff) == 0) printf("\n");
	}
	printf("\nDone...\n");
	return 0;
}

I have included here update Rawhid host download, which is my WIP including above program. Note Makefile updated to build this one instead of main example.

Does this make a difference?
Well the example sketch tries to upload logically a 22mb file. With normal Rawhid this takes about 88 seconds, converting to 512 this now takes < 11 seconds. As expected 8 times faster.

Again not sure if there is any interest in this... If not probably won't take it much farther.

There is a minor issue in the HID descriptor where I say the size is still 64 as the count field is one byte... Probably a way to update, but not sure if anyone actually looks.

Also might update USBHost_t35 hid support to handle it being plugged in, which would give a very fast transfer rate between two T4.xs...

Now back to playing
 

Attachments

  • rawhid.zip
    29.5 KB · Views: 155
@KurtE
Nice work - doubt I can be much help here - don't really use linux, only windows.
 
@KurtE
Nice work - doubt I can be much help here - don't really use linux, only windows.

I hear you... I want to make it work on Windows as well.

As a curiosity I tried on my windows machine open up the Ubuntu sub-system... I edited makefile to say windows.
Installed make and it built... the .exe file... But trying to run it says it is for wrong architecture...
I think it built for 32 bits and I am running 64 bits...

Not sure how hard it is to get it to build 64 bits... Will try building in Visual studio... Have it feeling it will want lots of things installed to allow it to build.

Would be interesting to know if anyone else has built the Rawhid stuff for windows using native windows tools?
 
Quick update: Mostly talking to myself ;) I was able to get the Windows version to build now :D

I have it building two different ways:

By the Makefile in an Ubuntu on Windows which looks like it is running 18.04...
Note: I had to edit both sources and makefiles. The i586...ming32 stuff needed to be replaced by the ming64 stuff:
I think I need to: sudo apt-get install mingw-w64 mingw-w64-tools

Windows part of makefile changed to:
Code:
else ifeq ($(OS), WINDOWS)
TARGET = $(PROG).exe
CC = i686-w64-mingw32-gcc
STRIP = i686-w64-mingw32-strip
CFLAGS = -Wall -O2 -DOS_$(OS)
LIBS = -lhid -lsetupapi
endif

Then hid_windows.c - was in header file hell for awhile... The set of includes that built yesterday:
Code:
#include <stdio.h>
#include <stdlib.h>
#include <stdint.h>
#include <windows.h>
#include <setupapi.h>
#include <hidsdi.h>
//#include <ddk/wdm.h>
//#include <ddk/miniport.h>
//#include <ddk/hidclass.h>
//#include <hidsdi.h>
//#include <hidclass.h>

#include "hid.h"

I was this morning also able to build it now using VS 2019 after installing SDK and WDK. I don't have a very clean project file, but it worked... It does run, I have not tried plugging in board yet to see if the new windows one will see the hid device.

The next thing I would like to figure out here is how to detect when I connect, what the max packet length for that endpoint... Have that working in Linux...

Wondering now if I should post the stuff here and/or create a github project? Did not see one...

Now back to playing
 
If you are looking for people with an interest in this to continue.. I'm interested as having battled with the Rawhid stuff myself
 
Just updated the VS2019 here - not sure I completed SDK and WDK install the other week ... with a github I could maybe build along.
> SDK : Yes ( Win 11 )
> WDK : installing

DONE:
Code:
'Installing Windows Driver Kit...'
- The following target products have been selected...
- 	Visual Studio Enterprise 2019

If you are looking for people with an interest in this to continue.. I'm interested as having battled with the Rawhid stuff myself

Having others play along is fun and helpful ... it's my main help here ...
 
Last edited:
I pushed up my WIP stuff up into a github project rawhid...

Got it - build fail:
Code:
Severity	Code	Description	Project	File	Line	Suppression State
Warning	C26451	Arithmetic overflow: Using operator '+' on a 4 byte value and then casting the result to a 8 byte value. Cast the value to the wider type before calling operator '+' to avoid overflow (io.2).	RawHid	C:\T_Drive\tCode\pjrc_latency_test\RawHid\hid_WINDOWS.c	135	
Error (active)	E1696	cannot open source file "hid.h"	RawHid	C:\T_Drive\tCode\pjrc_latency_test\RawHid\VS\RawHid\RawHid\SendALot.cpp	14	
Error (active)	E0020	identifier "rawhid_open" is undefined	RawHid	C:\T_Drive\tCode\pjrc_latency_test\RawHid\VS\RawHid\RawHid\SendALot.cpp	28	
Error (active)	E0020	identifier "rawhid_rxSize" is undefined	RawHid	C:\T_Drive\tCode\pjrc_latency_test\RawHid\VS\RawHid\RawHid\SendALot.cpp	40	
Error (active)	E0020	identifier "rawhid_txSize" is undefined	RawHid	C:\T_Drive\tCode\pjrc_latency_test\RawHid\VS\RawHid\RawHid\SendALot.cpp	40	
Error (active)	E0020	identifier "rawhid_send" is undefined	RawHid	C:\T_Drive\tCode\pjrc_latency_test\RawHid\VS\RawHid\RawHid\SendALot.cpp	53	
Warning	C26451	Arithmetic overflow: Using operator '+' on a 4 byte value and then casting the result to a 8 byte value. Cast the value to the wider type before calling operator '+' to avoid overflow (io.2).	RawHid	C:\T_Drive\tCode\pjrc_latency_test\RawHid\hid_WINDOWS.c	89	
Error	LNK2019	unresolved external symbol __imp_SetupDiEnumDeviceInterfaces referenced in function rawhid_open	RawHid	C:\T_Drive\tCode\pjrc_latency_test\RawHid\VS\RawHid\RawHid\hid_WINDOWS.obj	1	
Error	LNK2019	unresolved external symbol __imp_SetupDiGetDeviceInterfaceDetailW referenced in function rawhid_open	RawHid	C:\T_Drive\tCode\pjrc_latency_test\RawHid\VS\RawHid\RawHid\hid_WINDOWS.obj	1	
Error	LNK2019	unresolved external symbol __imp_SetupDiGetClassDevsW referenced in function rawhid_open	RawHid	C:\T_Drive\tCode\pjrc_latency_test\RawHid\VS\RawHid\RawHid\hid_WINDOWS.obj	1	
Error	LNK2019	unresolved external symbol HidP_GetCaps referenced in function rawhid_open	RawHid	C:\T_Drive\tCode\pjrc_latency_test\RawHid\VS\RawHid\RawHid\hid_WINDOWS.obj	1	
Error	LNK2019	unresolved external symbol HidD_GetAttributes referenced in function rawhid_open	RawHid	C:\T_Drive\tCode\pjrc_latency_test\RawHid\VS\RawHid\RawHid\hid_WINDOWS.obj	1	
Error	LNK2019	unresolved external symbol HidD_GetHidGuid referenced in function rawhid_open	RawHid	C:\T_Drive\tCode\pjrc_latency_test\RawHid\VS\RawHid\RawHid\hid_WINDOWS.obj	1	
Error	LNK2019	unresolved external symbol HidD_GetPreparsedData referenced in function rawhid_open	RawHid	C:\T_Drive\tCode\pjrc_latency_test\RawHid\VS\RawHid\RawHid\hid_WINDOWS.obj	1	
Error	LNK2019	unresolved external symbol HidD_FreePreparsedData referenced in function rawhid_open	RawHid	C:\T_Drive\tCode\pjrc_latency_test\RawHid\VS\RawHid\RawHid\hid_WINDOWS.obj	1	
Error	LNK1120	8 unresolved externals	RawHid	C:\T_Drive\tCode\pjrc_latency_test\RawHid\VS\RawHid\x64\Debug\RawHid.exe	1

Moved the hid.h into src folder ... not sure what else ...
 
makes two of us :)
Feeling more with it today...

I think one issue with the stuff I uploaded was I had a hard coded path in the include directory list... Trying to make sure it is now resolved. I pushed up a change
to convert it to ..\..\.. Will see if that resolved it.

Note: the Ubuntu window works for me as well.
 
Pushed up a few more changes today, both in cores and now the rawhid library.

Cores: updated the HID report, such that it says the report data is now 512 bytes long (when appropriate). Could not do this directly as the count is mainly by a repeat count which is only one byte... But instead change the underlying data size to be 64 bits instead of 8 bit...

in the rawhid project:
I now include both of the test sketches I have, including building a large file... Actually not needed here.
And the send a logically large file code which is main test...

Tested on windows, that it could run with the hid test program here. in either 64 or 512 byte packet sizes...
 
Finally got done with my chores and updated cores, sketch and VS project. Did have to update Linker Input to add hib.lib and setupapi.lib as well as changing the hid.h path in SendALot.cpp. But it worked at 512:
Capture.jpg

Would be interesting it would work USB1 to USB1 :)
 
USB1 to USB1... Is this asking saying SerUSB1? Or USB Host...

As for USBHost having a rawhid plugged in... Playing with it now... so far extracted some RAWHID test code out of several of the examples and creating it's own sample...

So far I have:
Code:
// Simple test of USB Host Mouse/Keyboard
//
// This example is in the public domain

#include "USBHost_t36.h"


USBHost myusb;
USBHub hub1(myusb);
USBHub hub2(myusb);
USBHIDParser hid1(myusb);
USBHIDParser hid2(myusb);

RawHIDController rawhid1(myusb);
RawHIDController rawSEMU(myusb, 0xffc90004);

USBDriver *drivers[] = {&hub1, &hub2, &hid1, &hid2};
#define CNT_DEVICES (sizeof(drivers)/sizeof(drivers[0]))
const char * driver_names[CNT_DEVICES] = {"Hub1", "Hub2", "HID1" , "HID2"};
bool driver_active[CNT_DEVICES] = {false, false, false, false};

// Lets also look at HID Input devices
USBHIDInput *hiddrivers[] = {&rawhid1, &rawSEMU};
#define CNT_HIDDEVICES (sizeof(hiddrivers)/sizeof(hiddrivers[0]))
const char * hid_driver_names[CNT_DEVICES] = {"RawHid1", "rawSEMU"};
bool hid_driver_active[CNT_DEVICES] = {false, false};
void setup()
{
  while (!Serial) ; // wait for Arduino Serial Monitor

  if (CrashReport) {
    Serial.print(CrashReport);
  }

  Serial.println("\n\nUSB Host Testing");
  Serial.println(sizeof(USBHub), DEC);
  myusb.begin();

  rawhid1.attachReceive(OnReceiveHidData);
  rawSEMU.attachReceive(OnReceiveSEMU);
}


void loop()
{
  myusb.Task();
  UpdateActiveDeviceInfo();
  if (Serial.available()) {
    int ch = Serial.read(); // get the first char.
    while (Serial.read() != -1) ;
  }


  // See if we have some RAW data
  if (rawhid1) {
    int ch;
    uint8_t buffer[64];
    uint8_t count_chars = 0;
    memset(buffer, 0, sizeof(buffer));
    if (Serial.available()) {
      while (((ch = Serial.read()) != -1) && (count_chars < sizeof(buffer))) {
        buffer[count_chars++] = ch;
      }
      rawhid1.sendPacket(buffer);
    }
  }
}

// check to see if the device list has changed:
void UpdateActiveDeviceInfo() {
  for (uint8_t i = 0; i < CNT_DEVICES; i++) {
    if (*drivers[i] != driver_active[i]) {
      if (driver_active[i]) {
        Serial.printf("*** Device %s - disconnected ***\n", driver_names[i]);
        driver_active[i] = false;
      } else {
        Serial.printf("*** Device %s %x:%x - connected ***\n", driver_names[i], drivers[i]->idVendor(), drivers[i]->idProduct());
        driver_active[i] = true;

        const uint8_t *psz = drivers[i]->manufacturer();
        if (psz && *psz) Serial.printf("  manufacturer: %s\n", psz);
        psz = drivers[i]->product();
        if (psz && *psz) Serial.printf("  product: %s\n", psz);
        psz = drivers[i]->serialNumber();
        if (psz && *psz) Serial.printf("  Serial: %s\n", psz);

        // Note: with some keyboards there is an issue that they don't output in boot protocol mode
        // and may not work.  The above code can try to force the keyboard into boot mode, but there
        // are issues with doing this blindly with combo devices like wireless keyboard/mouse, which
        // may cause the mouse to not work.  Note: the above id is in the builtin list of
        // vendor IDs that are already forced
      }
    }
  }

  for (uint8_t i = 0; i < CNT_HIDDEVICES; i++) {
    if (*hiddrivers[i] != hid_driver_active[i]) {
      if (hid_driver_active[i]) {
        Serial.printf("*** HID Device %s - disconnected ***\n", hid_driver_names[i]);
        hid_driver_active[i] = false;
      } else {
        Serial.printf("*** HID Device %s %x:%x - connected ***\n", hid_driver_names[i], hiddrivers[i]->idVendor(), hiddrivers[i]->idProduct());
        hid_driver_active[i] = true;

        const uint8_t *psz = hiddrivers[i]->manufacturer();
        if (psz && *psz) Serial.printf("  manufacturer: %s\n", psz);
        psz = hiddrivers[i]->product();
        if (psz && *psz) Serial.printf("  product: %s\n", psz);
        psz = hiddrivers[i]->serialNumber();
        if (psz && *psz) Serial.printf("  Serial: %s\n", psz);
      }
    }
  }

}
bool OnReceiveHidData(uint32_t usage, const uint8_t *data, uint32_t len) {
  Serial.print("RawHID data: ");
  Serial.println(usage, HEX);
  while (len) {
    uint8_t cb = (len > 16) ? 16 : len;
    const uint8_t *p = data;
    uint8_t i;
    for (i = 0; i < cb; i++) {
      Serial.printf("%02x ", *p++);
    }
    Serial.print(": ");
    for (i = 0; i < cb; i++) {
      Serial.write(((*data >= ' ') && (*data <= '~')) ? *data : '.');
      data++;
    }
    len -= cb;
    Serial.println();
  }
  return true;
}

bool OnReceiveSEMU(uint32_t usage, const uint8_t *data, uint32_t len) {
  // Lets trim off trailing null characters.
  while ((len > 0) && (data[len - 1] == 0)) {
    len--;
  }
  if (len) {
    Serial.print("RawHid Serial: ");
    Serial.write(data, len);
  }
}

And it detects that it is plugged in...
Code:
USB Host Testing
960
*** Device HID1 16c0:486 - connected ***
  manufacturer: Teensyduino
  product: Teensyduino RawHID
  Serial: 10883560
*** Device HID2 16c0:486 - connected ***
  manufacturer: Teensyduino
  product: Teensyduino RawHID
  Serial: 10883560
*** HID Device RawHid1 16c0:486 - connected ***
  manufacturer: Teensyduino
  product: Teensyduino RawHID
  Serial: 10883560
*** HID Device rawSEMU 16c0:486 - connected ***
  manufacturer: Teensyduino
  product: Teensyduino RawHID
  Serial: 10883560


So if the sketch plugged in should send something on its Seremu, I will forward it... But right now not getting anything as the sketch on other side has;
while (!Serial) ;

And my Seremu code is not doing what SEREMU needs to tell other side, I am connected... Could avoid this by using timeout on this... But taking a quick look
 
USB1 to USB1... Is this asking saying SerUSB1? Or USB Host...
Meant USB_Host :)

Wanted can I tell you great minds think a like but need to stop now - wrist. Its a fun problem isn't it
 
Seems to be building ... not as far as knowing what is going on yet:
Code:
C:\T_Drive\tCode\pjrc_latency_test\RawHid\VS\RawHid\x64\Debug>RawHid.exe
$$$ Hid report sizes In:513 Out: 513
found rawhid device
Starting output(0)
Rx Size:512 Tx Size:512
.
.....................................................................................
Done...

Edit to TSET for 'r' rawhid512: TSet.cmd
Code:
...
Echo 	o :: mtpserial
[B]Echo 	r :: rawhid512
Echo.
Choice /C 123456789abcdefghijklmnor /M "What USB"
If Errorlevel 25 Goto U25
[/B]If Errorlevel 24 Goto U24
...
REM >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>   USB

[B]:U25
set usb=rawhid512
goto BeDone

[/B]:U24
...

Update: TyComm doesn't get the 'Serial.print' from the sketch - but T_sermon does:
Code:
RawHID lots of input test
RawHid RX Size: 512
Waiting for packets
Looks like new run started
Missing? cnt: 5, Last: 9165 cur:3
.........................

TyComm 'connects' - but that output was buffered and showed up when T_sermon was opened.

Output is after it completed the 'Done' pass - then after a wait ( maybe the 5 missing? ) I restarted the EXE.
 
Last edited:
I am playing again this morning... Trying to make it work with USBHost...

Just having some fun... Will pull in you tset changes soon!
 
Making progress on supporting rawhid512 in usb host... can still improve it...

Pushed up more changes in my fork/branch of usbhost_t36 fs_integration...

Here is wip sketch:
Code:
// Simple test of USB Host Mouse/Keyboard
//
// This example is in the public domain

#include "USBHost_t36.h"


USBHost myusb;
USBHub hub1(myusb);
USBHub hub2(myusb);
USBHIDParser hid1(myusb);
USBHIDParser hid2(myusb);

DMAMEM uint8_t rawhid_big_buffer[2048] __attribute__ ((aligned(32)));
RawHIDController rawhid1(myusb, 0, rawhid_big_buffer, sizeof(rawhid_big_buffer));
USBSerialEmu seremu(myusb);

USBDriver *drivers[] = {&hub1, &hub2, &hid1, &hid2};
#define CNT_DEVICES (sizeof(drivers)/sizeof(drivers[0]))
const char * driver_names[CNT_DEVICES] = {"Hub1", "Hub2", "HID1" , "HID2"};
bool driver_active[CNT_DEVICES] = {false, false, false, false};

// Lets also look at HID Input devices
USBHIDInput *hiddrivers[] = {&rawhid1, &seremu};
#define CNT_HIDDEVICES (sizeof(hiddrivers)/sizeof(hiddrivers[0]))
const char * hid_driver_names[CNT_DEVICES] = {"RawHid1", "SerEmu"};
bool hid_driver_active[CNT_DEVICES] = {false, false};

#define FILE_SIZE 22400000ul
int packet_size;
int count_packets;

int packet_num = -1; // say we are not active

Stream* SerialEmuEcho;

void setup()
{
  while (!Serial) ; // wait for Arduino Serial Monitor

  if (CrashReport) {
    Serial.print(CrashReport);
  }
  Serial.println("\n\nUSB Host Testing");
  Serial.println(sizeof(USBHub), DEC);
#if defined(USB_DUAL_SERIAL) || defined(USB_TRIPLE_SERIAL)
  SerialUSB1.begin(115200);
  SerialEmuEcho = &SerialUSB1;  
#else
  SerialEmuEcho = &Serial;  
#endif  


  myusb.begin();

  rawhid1.attachReceive(OnReceiveHidData);
}

uint8_t buf[512];

void loop()
{
  myusb.Task();
  UpdateActiveDeviceInfo();
  if (Serial.available()) {
    while (Serial.read() != -1) ;
    if (rawhid1 && (packet_num == -1)) {
      packet_num = 0;
      packet_size = rawhid1.txSize();
      count_packets = FILE_SIZE / packet_size;

      Serial.println("Start sending rawhid data");
    } else {
      Serial.println("End sending Rawhid data");
    }
  }

  if (seremu) {
    uint8_t emu_buffer[64];
    uint16_t cb;
    if ((cb = seremu.available())) {
      if (cb > sizeof(emu_buffer)) cb = sizeof(emu_buffer);
      int rd = seremu.readBytes(emu_buffer, cb);
      SerialEmuEcho->write(emu_buffer, rd);
    }
  }

  // See if we have some RAW data
  if (rawhid1 && (packet_num >= 0) ) {
    memset(buf, 'A' + (packet_num & 0xf), packet_size) ;
    snprintf((char *)buf, sizeof(buf), "%07u", packet_num);
    buf[7] = (packet_num == (count_packets - 1)) ? '$' : ' ';
    buf[packet_size - 1] = '\n';
    if (rawhid1.sendPacket(buf, packet_size)) {
      if ((packet_num & 0x1ff) == 0) Serial.print("+");
      if ((packet_num & 0xffff) == 0) Serial.println();
      packet_num++;
      if (packet_num == count_packets) {
        Serial.println("\nDone...");
        packet_num = -1;
      }
    }
  }
}

// check to see if the device list has changed:
void UpdateActiveDeviceInfo() {
  for (uint8_t i = 0; i < CNT_DEVICES; i++) {
    if (*drivers[i] != driver_active[i]) {
      if (driver_active[i]) {
        Serial.printf("*** Device %s - disconnected ***\n", driver_names[i]);
        driver_active[i] = false;
      } else {
        Serial.printf("*** Device %s %x:%x - connected ***\n", driver_names[i], drivers[i]->idVendor(), drivers[i]->idProduct());
        driver_active[i] = true;

        const uint8_t *psz = drivers[i]->manufacturer();
        if (psz && *psz) Serial.printf("  manufacturer: %s\n", psz);
        psz = drivers[i]->product();
        if (psz && *psz) Serial.printf("  product: %s\n", psz);
        psz = drivers[i]->serialNumber();
        if (psz && *psz) Serial.printf("  Serial: %s\n", psz);

        // Note: with some keyboards there is an issue that they don't output in boot protocol mode
        // and may not work.  The above code can try to force the keyboard into boot mode, but there
        // are issues with doing this blindly with combo devices like wireless keyboard/mouse, which
        // may cause the mouse to not work.  Note: the above id is in the builtin list of
        // vendor IDs that are already forced
      }
    }
  }

  for (uint8_t i = 0; i < CNT_HIDDEVICES; i++) {
    if (*hiddrivers[i] != hid_driver_active[i]) {
      if (hid_driver_active[i]) {
        Serial.printf("*** HID Device %s - disconnected ***\n", hid_driver_names[i]);
        hid_driver_active[i] = false;
      } else {
        Serial.printf("*** HID Device %s %x:%x - connected ***\n", hid_driver_names[i], hiddrivers[i]->idVendor(), hiddrivers[i]->idProduct());
        hid_driver_active[i] = true;

        const uint8_t *psz = hiddrivers[i]->manufacturer();
        if (psz && *psz) Serial.printf("  manufacturer: %s\n", psz);
        psz = hiddrivers[i]->product();
        if (psz && *psz) Serial.printf("  product: %s\n", psz);
        psz = hiddrivers[i]->serialNumber();
        if (psz && *psz) Serial.printf("  Serial: %s\n", psz);
        if (hiddrivers[i] == &seremu) {
          Serial.printf("   RX Size:%u TX Size:%u\n", seremu.rxSize(), seremu.txSize());
        }
        if (hiddrivers[i] == &rawhid1) {
          Serial.printf("   RX Size:%u TX Size:%u\n", rawhid1.rxSize(), rawhid1.txSize());
        }
      }
    }
  }

}
bool OnReceiveHidData(uint32_t usage, const uint8_t *data, uint32_t len) {
  Serial.print("RawHID data: ");
  Serial.println(usage, HEX);
  while (len) {
    uint8_t cb = (len > 16) ? 16 : len;
    const uint8_t *p = data;
    uint8_t i;
    for (i = 0; i < cb; i++) {
      Serial.printf("%02x ", *p++);
    }
    Serial.print(": ");
    for (i = 0; i < cb; i++) {
      Serial.write(((*data >= ' ') && (*data <= '~')) ? *data : '.');
      data++;
    }
    len -= cb;
    Serial.println();
  }
  return true;
}

So talks to same sketch on the rawhid disk that was testing host stuff with...

Edit: addded above sketch to my rawhid project.
 
Last edited:
I am playing again this morning... Trying to make it work with USBHost...

Just having some fun... Will pull in you tset changes soon!

Good work Kurt. I updated Defragster/Tset - just that change to TSet.cmd for WIP with manual Boards.txt edit to work.

Interesting that RawHid on T_sermon works to support Serial.print and TyComm loses it? Wonder if @koromix might have a way to enable that ...
> is PJRC T_sermon rawhid512 aware ? to make that work or is there something else going on that breaks TyComm ?


BTW: When I moved TSET.cmd into github folder for upload --- did a file copy with Win 11 File Explorer and NO 15 SECOND WAIT !!!!!! Did a purge and rebuild of the 'Index' file - also deleted two random REG keys that may have been part of it.
 
Quick update:

I now have it working reasonably well with USBHost talking to the Rawhid or Rawhid 512. Updated the HID class to detect the size of the rx and tx pipes...

enhanced the HID calls to allow the hid object that claims it to provide external larger buffers, now up to 4 of them for rx and tx...

Sketch also talks using the seremu code in USBHost... Fixed a seremu bug... Sketch detects if SerialUSB1 exists.. if so forwards to it...

Right now does the send a large index file like data to the other test sketch...

Sample run:
Serial:
Code:
USB Host RawHid and Seremu Testing
960
*** Device HID1 16c0:486 - connected ***
  manufacturer: Teensyduino
  product: Teensyduino RawHID
  Serial: 10883560
*** Device HID2 16c0:486 - connected ***
  manufacturer: Teensyduino
  product: Teensyduino RawHID
  Serial: 10883560
Rawhid Claim: 16c0:486 usage: ffab0200
    >> setTXBuffers: 20200000 20200200 20200400 20200600
    >> setRXBuffers: 20200800 20200a00 20200c00 20200e00
Rawhid Claim: 16c0:486 usage: ffc90004
*** HID Device RawHid1 16c0:486 - connected ***
  manufacturer: Teensyduino
  product: Teensyduino RawHID
  Serial: 10883560
   RX Size:512 TX Size:512
*** HID Device SerEmu 16c0:486 - connected ***
  manufacturer: Teensyduino
  product: Teensyduino RawHID
  Serial: 10883560
   RX Size:64 TX Size:32

*** press any keyboard keys to start sending data ***
Start sending rawhid data
+
+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Done...

*** press any keyboard keys to start sending data ***
SerialUSB1:
Code:
RawHID lots of input test
RawHid RX Size: 512
Waiting for packets
Looks like new run started
..........................................Received end marker: 43750 43749 Time:32888

Timeout: 43750 43749
Not as fast as talking to PC, may check to see the timing settings...

back to other diversions.
 
Now back to something complete random.... Sort of...

Today I played a little more with the Rawhid stuff to see if I can make it work closer to the MTP transfer code to see if I could replicate maybe losing messages.

One main difference is RAWHID uses interrupt transfers and MTP uses bulk transfers... So hacked up another variant of the RAWHID that uses bulk transfers...

So hacked it pushed up a cores branch rawhid_512_bulk that had another USB type...

boards.local.txt
Code:
teensy41.menu.usb.rawhid512=Raw HID 512
teensy41.menu.usb.rawhid512.build.usbtype=USB_RAWHID512
teensy41.menu.usb.rawhid512.fake_serial=teensy_gateway

teensyMM.menu.usb.rawhid512=Raw HID 512
teensyMM.menu.usb.rawhid512.build.usbtype=USB_RAWHID512
teensyMM.menu.usb.rawhid512.fake_serial=teensy_gateway

teensy40.menu.usb.rawhid512=Raw HID 512
teensy40.menu.usb.rawhid512.build.usbtype=USB_RAWHID512
teensy40.menu.usb.rawhid512.fake_serial=teensy_gateway

teensy41.menu.usb.rawhid512B=Raw HID 512 Bulk
teensy41.menu.usb.rawhid512B.build.usbtype=USB_RAWHID512B
teensy41.menu.usb.rawhid512B.fake_serial=teensy_gateway

teensyMM.menu.usb.rawhid512B=Raw HID 512 Bulk
teensyMM.menu.usb.rawhid512B.build.usbtype=USB_RAWHID512B
teensyMM.menu.usb.rawhid512B.fake_serial=teensy_gateway

teensy40.menu.usb.rawhid512B=Raw HID 512 Bulk
teensy40.menu.usb.rawhid512B.build.usbtype=USB_RAWHID512B
teensy40.menu.usb.rawhid512B.fake_serial=teensy_gateway


I then also hacked up my rawhid project, hid code so far on linux to detect it is BULK and use the bulk api instead of the interrupt api...
So far only on write.

Plus updated the test sketch to detect it and then try to send 32 packets at a time...
Appears to be working... Not seeing any lost packets yet.

Screenshot from 2021-11-29 15-58-43.png
 
Last edited:
Over the last week, I have been playing some more with the RAWHID stuff. While I am waiting for progress and the like on some other projects.

Was wondering about seeing how well it would work to transfer files between two teensy boards. One plugged into the other.

I have two sketches that needs lots of cleanup plus maybe factoring the code to share between the two.

The sketch(RawHIDFileTransferRemote.ino) of the Teensy that plugs into the USBHost of the other, is built with USB type of RAWHID.
The other sketch (RawHIDFileTransferHost.ino) can be built with different USB Types but if includes MTP it will show it's local SD or LittleFS Program disk.

It is pretty rudimentary, and only partially working. Like I can download a file from the USBHost teensy to the other. And that appears to be working.
I have yet tried integrating this with the 512 byte code mentioned in this thread. The upload of a file is not properly working. There are likely bugs in this code.

But I am also wondering if I am running into some more lower level issue, where when I try to send as fast as possible the 64 byte packets,
in this case the packets are sent over USBHost and received using USB type rawhid.

My data loop should keep receiving messages until it gets at least 4096 which I then issue a write to the SD card. Again receiving 60 bytes at a time...
Debug on one hosted usbhost, I was forwarding SEREMU messages out, but now have most of the debug output on Serial1.
And the debug outptu shows stuff like:
Code:
ORRF DATA : 4080
ORRF DATA : 4140

>>>>>> Exit data loop (4140 0 0) <<<<<<<<
Receive file write: 4096 4096 dt:2
ORRF DATA : 104

>>>>>> Enter data loop (104 0 0) <<<<<<<<
ORRF DATA : 164
ORRF DATA : 224
ORRF DATA : 284
ORRF DATA : 344
ORRF DATA : 404
ORRF DATA : 464
ORRF DATA : 524
ORRF DATA : 584
ORRF DATA : 644
ORRF DATA : 704
ORRF DATA : 764
ORRF DATA : 824
ORRF DATA : 884
ORRF DATA : 944
ORRF DATA : 1004
ORRF DATA : 1064
ORRF DATA : 1124
ORRF DATA : 1184
ORRF DATA : 1244
ORRF DATA : 1304
ORRF DATA : 1364
ORRF DATA : 1424
ORRF DATA : 1484
ORRF DATA : 1544
...
ORRF DATA : 3524
ORRF DATA : 3584
ORRF DATA : 3644
ORRF DATA : 3704
ORRF DATA : 3764
ORRF DATA : 3824
ORRF DATA : 3884
ORRF DATA : 3944

And hangs there.
And on the other side, I see it:
Sending stuff, and then the send times out:
Code:
lsrhid: 0 0x20008894 60 5000
lsrhid: 0 0x200088d0 60 5000
lsrhid: 0 0x2000890c 60 5000
lsrhid: 0 0x20008948 60 5000
$$upload read: cb read:4096 buf:4128
lsrhid: 0 0x20007994 60 5000
	 *** Timeout(5001) ***
lsrhid: 0 0x200079d0 60 5000
	 *** Timeout(5001) ***
lsrhid: 0 0x20007a0c 60 5000
	 *** Timeout(5001) ***
lsrhid: 0 0x20007a48 60 5000
	 *** Timeout(5001) ***

Again probably bugs on my side, but will be interesting to debug some more.
Back to playing
 
@KurtE - This is so strange:) I have been playing with the same library this weekend. I have two Teensy's connected together. One is loaded with "Basic.ino" and is connected to the USB host port on the second T4.1 which is loaded with "RawHIDtoUSBHostRawHID.ino". Then I used "rawhid_test" which worked well as a pass through. I downloaded RawHID again from your GitHub which was two hours old. Hopefully I can play with it a little tonight.

I really am interested in being able to use rawhid with USBSerial bidirectionally between two T4.1's at 480MBs... (Is MBS right):)
 
...
I really am interested in being able to use rawhid with USBSerial bidirectionally between two T4.1's at 480MBs... (Is MBS right):)

Mbs - meg bits/sec

Did a RawHID echo through USBHost and it worked well. Host was running QEthernet UDP Chat that worked well ...
 
Back
Top