USB pen/stylus HID

FrG

New member
Hi,

I have just started to look into creating a pen/stylus HID.
I have already looked at some documentation on usb.org, and some old posts on here:
https://forum.pjrc.com/threads/28943-NEWS-I-added-a-touch-screen-HID-device-to-Teensyduino-1-23-%28works-also-on-Linux%29?highlight=elmue+hid
https://forum.pjrc.com/threads/28661-Touchscreen-on-Linux-with-Mouse-moveTo%28%29
and of course:
https://forum.pjrc.com/threads/32331-USB-HID-Touchscreen-support-needed?highlight=TouchscreenUSB

However I do not know enough of USB descriptor protocols and such to get anywhere fast.

So far I have used USBlyzer to see the Report descriptor of an existing device, which brought me the overview as can be seen at the end of this message.
I believe the device is a composite device, containing both a description for a mouse and for a pen/stylus.

my question; how could I add support for a pen/stylus. (When succeeded I would like to continue with a dial as well)
Any pointers (no pun intended) are appreciated

Usage Page (Generic Desktop) 05*01*
Usage (Mouse) 09*02*
Collection (Application) A1*01*
****Report ID (1) 85*01*
****Usage (Pointer) 09*01*
****Collection (Physical) A1*00*
********Usage Page (Button) 05*09*
********Usage Minimum (Button 1) 19*01*
********Usage Maximum (Button 2) 29*02*
********Logical Minimum (0) 15*00*
********Logical Maximum (1) 25*01*
********Report Count (2) 95*02*
********Report Size (1) 75*01*
********Input (Data,Var,Abs,NWrp,Lin,Pref,NNul,Bit) 81*02*
********Report Count (1) 95*01*
********Report Size (6) 75*06*
********Input (Cnst,Var,Abs,NWrp,Lin,Pref,NNul,Bit) 81*03*
********Usage Page (Generic Desktop) 05*01*
********Usage (X) 09*30*
********Usage (Y) 09*31*
********Logical Minimum (-127) 15*81*
********Logical Maximum (127) 25*7F*
********Report Size (8) 75*08*
********Report Count (2) 95*02*
********Input (Data,Var,Rel,NWrp,Lin,Pref,NNul,Bit) 81*06*
****End Collection C0*
End Collection C0*
Usage Page (Digitizer) 05*0D*
Usage (Pen) 09*02*
Collection (Application) A1*01*
****Report ID (2) 85*02*
****Usage (Stylus) 09*20*
****Collection (Physical) A1*00*
********Usage (Tip Switch) 09*42*
********Usage (Barrel Switch) 09*44*
********Usage (Eraser) 09*45*
********Usage (Invert) 09*3C*
********Usage 09*5A*
********Usage (In Range) 09*32*
********Logical Minimum (0) 15*00*
********Logical Maximum (1) 25*01*
********Report Size (1) 75*01*
********Report Count (6) 95*06*
********Input (Data,Var,Abs,NWrp,Lin,Pref,NNul,Bit) 81*02*
********Report Count (2) 95*02*
********Input (Cnst,Var,Abs,NWrp,Lin,Pref,NNul,Bit) 81*03*
********Usage Page (Generic Desktop) 05*01*
********Usage (X) 09*30*
********Logical Maximum (29837) 27*8D*74*00*00*
********Physical Maximum (59674) 47*1A*E9*00*00*
********Unit (SI Lin: Length (cm)) 65*11*
********Unit Exponent (-3) 55*0D*
********Report Size (16) 75*10*
********Report Count (1) 95*01*
********Input (Data,Var,Abs,NWrp,Lin,Pref,NNul,Bit) 81*02*
********Usage (Y) 09*31*
********Logical Maximum (16783) 27*8F*41*00*00*
********Physical Maximum (33566) 47*1E*83*00*00*
********Input (Data,Var,Abs,NWrp,Lin,Pref,NNul,Bit) 81*02*
********Physical Maximum (0) 45*00*
********Unit (None) 65*00*
********Unit Exponent (0) 55*00*
********Usage Page (Digitizer) 05*0D*
********Usage (Tip Pressure) 09*30*
********Logical Maximum (4095) 26*FF*0F*
********Input (Data,Var,Abs,NWrp,Lin,Pref,NNul,Bit) 81*02*
********Usage Page (Vendor-Defined 1) 06*00*FF*
********Usage (Vendor-Defined 4) 09*04*
********Report Size (8) 75*08*
********Logical Maximum (255) 26*FF*00*
********Physical Maximum (255) 46*FF*00*
********Unit (SI Lin: Length (cm)) 65*11*
********Unit Exponent (-2) 55*0E*
********Input (Data,Var,Abs,NWrp,Lin,Pref,NNul,Bit) 81*02*
********Usage Page (Digitizer) 05*0D*
********Usage (X Tilt) 09*3D*
********Report Size (16) 75*10*
********Logical Minimum (-9000) 16*D8*DC*
********Logical Maximum (9000) 26*28*23*
********Physical Minimum (-9000) 36*D8*DC*
********Physical Maximum (9000) 46*28*23*
********Unit (Eng Rot: Degree) 65*14*
********Input (Data,Var,Abs,NWrp,Lin,Pref,NNul,Bit) 81*02*
********Usage (Y Tilt) 09*3E*
********Input (Data,Var,Abs,NWrp,Lin,Pref,NNul,Bit) 81*02*
********Unit (None) 65*00*
********Unit Exponent (0) 55*00*
********Logical Minimum (0) 15*00*
********Physical Minimum (0) 35*00*
********Physical Maximum (0) 45*00*
****End Collection C0*
****Usage (Undefined) 09*00*
****Report Size (8) 75*08*
****Logical Maximum (255) 26*FF*00*
****Feature (Data,Var,Abs,NWrp,NLin,Pref,NNul,NVol,Bit) B1*12*
End Collection C0*
Usage Page (Vendor-Defined 1) 06*00*FF*
Usage (Undefined) 09*00*
Collection (Application) A1*01*
****Report ID (17) 85*11*
****Usage Page (Digitizer) 05*0D*
****Usage (Stylus) 09*20*
****Collection (Physical) A1*00*
********Usage (Tip Switch) 09*42*
********Usage (Barrel Switch) 09*44*
********Usage (Eraser) 09*45*
********Usage (Invert) 09*3C*
********Usage 09*5A*
********Usage (In Range) 09*32*
********Logical Minimum (0) 15*00*
********Logical Maximum (1) 25*01*
********Report Size (1) 75*01*
********Report Count (6) 95*06*
********Input (Data,Var,Abs,NWrp,Lin,Pref,NNul,Bit) 81*02*
********Report Count (2) 95*02*
********Input (Cnst,Var,Abs,NWrp,Lin,Pref,NNul,Bit) 81*03*
********Usage Page (Generic Desktop) 05*01*
********Usage (X) 09*30*
********Logical Maximum (59674) 27*1A*E9*00*00*
********Physical Maximum (59674) 47*1A*E9*00*00*
********Unit (SI Lin: Length (cm)) 65*11*
********Unit Exponent (-3) 55*0D*
********Report Size (16) 75*10*
********Report Count (1) 95*01*
********Input (Data,Var,Abs,NWrp,Lin,Pref,NNul,Bit) 81*02*
********Usage (Y) 09*31*
********Logical Maximum (33566) 27*1E*83*00*00*
********Physical Maximum (33566) 47*1E*83*00*00*
********Input (Data,Var,Abs,NWrp,Lin,Pref,NNul,Bit) 81*02*
********Physical Maximum (0) 45*00*
********Unit (None) 65*00*
********Unit Exponent (0) 55*00*
********Usage Page (Digitizer) 05*0D*
********Usage (Tip Pressure) 09*30*
********Logical Maximum (4095) 26*FF*0F*
********Input (Data,Var,Abs,NWrp,Lin,Pref,NNul,Bit) 81*02*
********Usage Page (Vendor-Defined 1) 06*00*FF*
********Usage (Vendor-Defined 4) 09*04*
********Report Size (8) 75*08*
********Logical Maximum (255) 26*FF*00*
********Physical Maximum (255) 46*FF*00*
********Unit (SI Lin: Length (cm)) 65*11*
********Unit Exponent (-2) 55*0E*
********Input (Data,Var,Abs,NWrp,Lin,Pref,NNul,Bit) 81*02*
********Usage Page (Digitizer) 05*0D*
********Usage (X Tilt) 09*3D*
********Report Size (16) 75*10*
********Logical Minimum (-9000) 16*D8*DC*
********Logical Maximum (9000) 26*28*23*
********Physical Minimum (-9000) 36*D8*DC*
********Physical Maximum (9000) 46*28*23*
********Unit (Eng Rot: Degree) 65*14*
********Input (Data,Var,Abs,NWrp,Lin,Pref,NNul,Bit) 81*02*
********Usage (Y Tilt) 09*3E*
********Input (Data,Var,Abs,NWrp,Lin,Pref,NNul,Bit) 81*02*
********Unit (None) 65*00*
********Unit Exponent (0) 55*00*
********Logical Minimum (0) 15*00*
********Physical Minimum (0) 35*00*
********Physical Maximum (0) 45*00*
****End Collection C0*
****Usage (Undefined) 09*00*
****Report Size (8) 75*08*
****Logical Maximum (255) 26*FF*00*
****Report Count (3) 95*03*
****Feature (Data,Var,Abs,NWrp,NLin,Pref,NNul,NVol,Bit) B1*12*
End Collection C0*
Usage Page (Generic Desktop) 05*01*
 
After doing some reading I've created a first draft for the pen's descriptor.

In usb_desc.c I've added:

#ifdef PEN_INTERFACE
static uint8_t pen_report_desc[] = {
0x05, 0x0D, // Usage Page (Digitizer)
0x09, 0x02, // Usage (Pen)
0xA1, 0x01, // Collection (Application)
0x85, 0x01, // Report ID (1)
0x09, 0x42, // Usage (Tip Switch)
0x09, 0x44, // Usage (Barrel Switch)
0x09, 0x45, // Usage (Eraser)
0x09, 0x3C, // Usage (Invert)
0x09, 0x5A, // Usage
0x09, 0x32, // Usage (In Range)
0x15, 0x00, // Logical Minimum (0)
0x25, 0x01, // Logical Maximum (1)
0x75, 0x01, // Report Size (1)
0x95, 0x06, // Report Count (6)
0x81, 0x02, // Input (Data,Var,Abs)
0x95, 0x02, // Report Count (2)
0x81, 0x03, // Input (Cnst,Var,Abs)
0x05, 0x01, // Usage Page (Generic Desktop)
0x09, 0x30, // Usage (X)
0x09, 0x31, // Usage (Y)
0x26, 0xFF, 0x7F, // Logical Maximum (32767)
0x65, 0x00, // Unit (None) <-- does it needs real units?
0x75, 0x10, // Report Size (16)
0x95, 0x02, // Report Count (2)
0x81, 0x02, // Input (variable,absolute)
0x05, 0x0D, // Usage Page (Digitizer)
0x09, 0x30, // Usage (Tip Pressure)
0x26, 0xFF, 0x0F, // Logical Maximum (4095)
0x75, 0x10, // Report Size (16)
0x95, 0x02, // Report Count (1)
0x81, 0x02, // Input (Data,Var,Abs,NWrp,Lin,Pref,NNul,Bit)
0x05, 0x0D, // Usage Page (Digitizer)
0x09, 0x3D, // Usage (X Tilt)
0x09, 0x3E, // Usage (Y Tilt)
0x75, 0x10, // Report Size (16)
0x95, 0x02, // Report Count (2)
0x16, 0xD8, 0xDC, // Logical Minimum (-9000)
0x26, 0x28, 0x23, // Logical Maximum (9000)
0x36, 0xD8, 0xDC, // Physical Minimum (-9000)
0x46, 0x28, 0x23, // Physical Maximum (9000)
0x65, 0x14, // Unit (Eng Rot: Degree)
0x81, 0x02, // Input (Data,Var,Abs)
0xC0 // End Collection
};
#endif

and in usb_desc.h I've added:

#elif defined(USB_PEN)
#define VENDOR_ID 0x16C0
#define PRODUCT_ID 0x04D4
#define MANUFACTURER_NAME {'T','e','e','n','s','y','d','u','i','n','o'}
#define MANUFACTURER_NAME_LEN 11
#define PRODUCT_NAME {'P','e','n'}
#define PRODUCT_NAME_LEN 3
#define EP0_SIZE 64
#define NUM_ENDPOINTS 3
#define NUM_USB_BUFFERS 15
#define NUM_INTERFACE 2
#define SEREMU_INTERFACE 1 // Serial emulation
#define SEREMU_TX_ENDPOINT 1
#define SEREMU_TX_SIZE 64
#define SEREMU_TX_INTERVAL 1
#define SEREMU_RX_ENDPOINT 2
#define SEREMU_RX_SIZE 32
#define SEREMU_RX_INTERVAL 2
#define PEN_INTERFACE 2 // Touchscreen
#define PEN_ENDPOINT 3
#define PEN_SIZE 10 <-- is this correct?
#define ENDPOINT1_CONFIG ENDPOINT_TRANSIMIT_ONLY
#define ENDPOINT2_CONFIG ENDPOINT_RECEIVE_ONLY
#define ENDPOINT3_CONFIG ENDPOINT_TRANSIMIT_ONLY
 
Last edited:
Looks like you're on the right track. But this is a long journey. After you get all the USB descriptors worked out, you also need to add code to actually send the HID reports with the same data as the report descriptor claims you have.
 
Back
Top