Raw HID - TeensyUser/doc GitHub Wiki

Tutorial

General HID information

HID devices usually do not require a device driver, which makes them very attractive. A user can plug in a HID compatible device at any time and it works without any additional software installation.

To exchange data with the host, all HID devices use so-called HID reports. Device developers are basically free to design the content of these reports as they wish. To enable the Host to find out how the data for a special device is structured, a HID device must provide a report descriptor which the Host can query if necessary. The HID report of a Teensy RAWHID device is a simple 64-byte data block, making data exchange extremely easy for both the host and the device application.

HID devices can not actively send data to the PC. Instead, they prepare a report and inform the host about it. As soon as the host finds time it will collect the report from a buffer in the device.

Sending data from a Teensy to a PC

Sending HID reports with a Teensy

Using the Teensy RawHID usb mode is very easy. If, for example, you want to send data to the PC you simply fill a 64 byte buffer with your data and provide it for collecting by usb_rawhid_send(void* buffer, int timeout). The first parameter is the address of the 64 byte buffer, the second parameter is a timeout in ms. If the host didn't collect the report after the timeout the teensy will abort the operation.

Here a working example which sends an incrementing value in the first byte of the report. You can download this and the following examples from here: https://github.com/TeensyUser/doc/tree/master/examples/HID

uint8_t report[64];

void setup(){}

void loop()
{
    report[0] = millis()/100;
    usb_rawhid_send(report, 1000);
    delay(100);
}

Receiving HID Reports on the PC

Generated HID devcies

Receiving data on the PC is nearly as easy as sending it from the Teensy. However, it is important to understand that RAWHID exposes two HID interfaces, the first one is the actual RAWHID, the second one is a SEREMU interface. Operating systems (at least Win10, what about LINUX?) generate a dedicated HID device for each HID interface a device provides. Thus, if you plug in the Teeny two HID devices, one RAWHID and one SEREMU device will appear.

You can distinguish them by having a look at their usagepage and usages:

  • RAWHID: usage page = 0xFFAB, usage: 0x0200
  • SEREMU: usage page = 0xFFC9, usage: 0x0004

The following examples (Win10, c# and python) show how to read in those packages. The application looks for devices with the correct VID/PID and identifies the correct one by checking its usage identifier. If it finds the correct device it waits for HID Reports from the Teensy and prints out the first byte of the received report on the console.

PC Examples

DotNet C-Sharp This example uses [Mike ò Brians hidlibrary](https://www.nuget.org/packages/hidlibrary/3.3.24) to talk to the HID devices.
using HidLibrary;
using System;
using System.Linq;

namespace receiver
{
    class Program
    {
        static void Main(string[] args)
        {
            var teensy = HidDevices.Enumerate(0x16C0, 0x0486)    // 0x486 -> usb type raw hid
                        .Where(d => d.Capabilities.Usage==0x200) // usage 0x200 -> RawHID usage
                        .FirstOrDefault();                       // take the first one we find on the USB bus

            while (teensy != null)
            {
                var report = teensy.ReadReport();                // request a report from the teensy
                Console.WriteLine(report.Data[0]);               // and write the first byte on the console
            }
        }
    }
}
Python
import hid
import keyboard

hidInterfaces = hid.enumerate()          # get all hid interfaces
t_it = filter(lambda t:                  # filter by vid and usagepage/usage
  t['vendor_id']==0x16c0 and
  t['usage_page'] == 0xFFAB and
  t['usage'] == 0x0200, hidInterfaces)

rawHID_interface = next(t_it, None)      # 'firstOrDefault'

if rawHID_interface != None:
   teensy = hid.Device(path = rawHID_interface["path"])

   while not keyboard.is_pressed('esc'):
      report = teensy.read(64)           # wait for an incomming report...
      print(report[0])                   # ...and print first byte

Sending data from a PC to a Teensy

Sending HID reports from the PC

The following examples demonstrate sending RAWHID reports from a PC to a Teensy. Instead of sending a boring, incrementing number, we send a random advice slip from adviceslip.com to the Teensy.

HID Sender DotNet C-Sharp
using HidLibrary;
using System;
using System.Json;
using System.Linq;
using System.Net;

namespace hid
{
    class Program
    {
        static void Main(string[] args)
        {
            var teensy = HidDevices.Enumerate(0x16C0, 0x0486)    // 0x486 -> usb type raw hid
                        .Where(d => d.Capabilities.Usage==0x200) // usage 0x200 -> RawHID usage
                        .FirstOrDefault();                       // take the first one we find on the USB bus

            if (teensy == null || !teensy.IsConnected) return;

            for(int loops = 0; loops< 10; loops++)               // don't read too much data from the web page...
            {
                String slip = new WebClient().DownloadString(@"https://api.adviceslip.com/advice");  // read a slip from adviceslip.com
                String advice = JsonValue.Parse(slip)["slip"]["advice"];                             // extract the advice from the json result

                HidReport report = teensy.CreateReport();        // Generate an empty report
                for(int i = 0; i< advice.Take(63).Count(); i++ ) // and copy the characters into it.
                {                                                // limit to 63 bytes to ensure the report always has a EOS (\0) at the end
                    report.Data[i] = (byte) advice[i];
                }
                teensy.WriteReport(report);                      // send report to teensy
                Console.WriteLine(advice);                       // echo on console
            }
        }
    }
}
HID Sender Python

Python

import hid
from urllib import request
import json

hidInterfaces = hid.enumerate()          # get all hid interfaces
t_it = filter(lambda t:                  # filter by vid and usagepage/usage
  t['vendor_id']  == 0x16c0 and
  t['usage_page'] == 0xFFAB and
  t['usage']      == 0x0200, hidInterfaces)

rawHID_interface = next(t_it, None)      # 'firstOrDefault'

if rawHID_interface != None:
   teensy = hid.Device(path = rawHID_interface["path"])

   for i in range(10):
     jsonurl = request.urlopen("https://api.adviceslip.com/advice")
     slip = '\0' + json.loads(jsonurl.read())['slip']['advice']  # the sent report must always start with \0
     teensy.write(slip.encode()[:64])                            # rawHID report is 64 bytes long

Receiving HID reports on the Teensy

The receiving code on the Teensy is as simple as this:

void setup(){}

void loop()
{
    char buf[64];

    if(usb_rawhid_recv(buf, 10) > 0)  // Wait for a received raw hid report
    {
      Serial.println(buf);            // and print it on Serial (actually a SEREMU interface in this case)
    }
}

And here the output which was written by the Teensy to the serial monitor (note that we limited the text length to 64 byte in this simple example)

image

Both, firmware and software can be downloaded from here.

Additional Resources:


winhidlisten

Winhidlisten

⚠️ **GitHub.com Fallback** ⚠️