USB I/O API

From SpinetiX Support Wiki

Jump to: navigation, search

This page is related to Interactivity via USB and JavaScript. Applies to all HMP models.

Introduction

In computing, the USB human interface device class (USB HID class) is a part of the USB specification for computer peripherals: it specifies a device class (a type of computer hardware) for human interface devices.

Simple USB HID devices like keyboards, mice and touch screens, are automatically bounded to regular SVG input events and are accessible through interactive widgets and jSignage interactive functions.

But a myriad of other devices can be specified under the USB HID class - for instance general purpose I/O devices, thermometers, relays, sensors, modern game controllers and joysticks, exercise machines, telephony devices, audio controls, medical instrumentation etc. - for all these USB devices, you have the USB I/O API supporting device enumeration, as well as sending and receiving input, output and feature reports, directly from the JavaScript code.


Note Notes:

Player configuration

The API was experimentally introduced within firmware 3.0.0 and enabled by default. It got stabilized within firmware 3.1.0 when it got switched to being disabled by default.

To USB I/O API can be enabled and disabled from Control Center from

Definition

The IDL definition of the USB I/O API is the following:

 interface HumanInterfaceDevice {
   attribute unsigned short deviceID;
   attribute unsigned short vendorID;
   attribute unsigned short productID;
   attribute unsigned short revisionID;
   attribute DOMString vendorName;
   attribute DOMString productName;
   attribute DOMString serialNumber;
   attribute unsigned short usagePage;
   attribute unsigned short usage;
   attribute Array inputReports;
   attribute Array outputReports;
   attribute Array featureReports;

   sendOutputReport( [in unsigned short reportID,] in Array values );
   sendFeatureReport( [in unsigned short reportID,] in Array values );
   getFeatureReport( in unsigned short reportID );
 };

where

  • deviceID is a number used to identify the device in the system, it is attributed during enumeration.
  • vendorID, productID, revisionID, vendorName, productName and serialNumber are provided by the USB device to identify the hardware. They are shared by all functions of a multi-function device.
  • usagePage and usage identify the functionality of an I/O interface according to USB HID usage tables.
  • The inputReports, outputReports and featureReports are arrays of HIDReportFields objects that enumerate the available reports for this device by category.


Note Note:
Multifunction devices are allowed to expose more then one I/O interface per physical device; these will have different "usage" codes.

HID Reports description

 interface HIDReportFields : Array of HIDReportField {
   attribute unsigned short reportID;
 };

reportID is the unique identifier for this report, as defined in the HID report descriptor. The reserved value 0 is used for devices with a single report which do not define a report ID in the descriptor.

Each field of each main item in the HID report descriptor is described by a HIDReportField object, the attributes of which define the function of the field according to USB HID usage tables. All fields of all main items are described in a flat array.

 interface HIDReportField {
   attribute short index;
   attribute unsigned short usagePage;
   attribute unsigned short usage;
   attribute unsigned short collectionUsagePage;
   attribute unsigned short collectionUsage;
 };

index represents the assigned position of the field and uniquely identifies it within the report, the same indices are used to report or set field values when receiving and sending reports. Note, however, that the assignment of indices is not the same in Elementi and HMP due to limitations in the Windows HID API.

The collectionUsagePage and collectionUsage provide the application collection within which the main item is defined.

HID events

 interface HIDEvent : Event {
   unsigned short HID_DEVICE_PLUGGED = 0;
   unsigned short HID_DEVICE_REMOVED = 1;
   unsigned short HID_REPORT_IN      = 2;
   unsigned short HID_REPORT_FEATURE = 3;   

   attribute unsigned short action;
   attribute HumanInterfaceDevice device;
   attribute HIDReport report;
 }

The HIDEvent object contains these attributes in additiong to those common to all Event objects:

  • action
    One of the four possible action codes: HID_DEVICE_PLUGGED, HID_DEVICE_REMOVED, HID_REPORT_IN or HID_REPORT_FEATURE.
  • device
    HumanInterfaceDevice object describing the device that sent a report.
  • report
    HIDReport object, only present for report in and report feature events.

HID Report fields

 interface HIDReport : Array of long {
   unsigned short reportID;

   long getUsage( unsigned short usagePage, unsigned short usage );
 }

The HIDReport is an array of integer values for each field in the report, with two additions:

  • reportID
    Identifies the type of report
  • getUsage
    The function allows getting a field from the report by looking up its usage code rather than directly using the field index.

HID global variable

The HID global JavaScript object contains an array of HumanInterfaceDevice objects representing the interfaces exposed by all connected USB HID devices.

How to

Enumerate available USB devices

Here is an example to show all USB devices:

var listOfDevices = HID;
for ( var i = 0; i < listOfDevices.length; i++ ) {
  var device = listOfDevices[i];
  alert( 'Found: ' + device.vendorID.toString(16) + ':' + device.productID.toString(16) + '(' + device.vendorName + ' ' + device.productName + ')' );
}

In most cases you will use the HID array to find the device you want to control by comparing the vendorID and productID attributes.

Send output reports

To set an output on the device you need to send an output report to it. Output reports contain a group of values that are changed together. It is possible to provide a new value for each field in the report or only for some, the other one being unchanged.

  • To set all fields of the report at once, call sendOutputReport with an javascript array containing all the values.
  • To set selected fields, call sendOutputReport with a javascript object with only the selected fields defined.

In the example below we assume our device has a single output report consisting of 6 fields with 8-bit values:

// our device is 0x1234:0x4567
var dev = null;
for ( var i = 0; i < HID.length; i++ ) {
  if ( HID[i].vendorID==0x1234 and HID[i].productID==0x4567 ) {
    dev = HID[i];
    break;
  }
}

if ( dev ) {
  dev.sendOutputReport( [ 0xBA, 0xDC, 0xAF, 0xFE, 0xFE, 0xED ] );  // Initialize all output values with one report
  dev.sendOutputReport( { 0: 0xFA, 5: 0xCE } );   // Change only the first and the last value
}

Receive input reports

In the example below, we assume the same device using in the preceding example will also send input reports with 6 values, but we are interested in only the first one and the last one:

// our device is 0x1234:0x4567
var dev = null;
for ( var i = 0; i < HID.length; i++ ) {
  if ( HID[i].vendorID==0x1234 and HID[i].productID==0x4567 ) {
    dev = HID[i];
    break;
  }
}

window.addEventListener( "hid", function( ev ) {
  if ( ev.action == HIDEvent.HID_REPORT_IN && ev.device == dev ) {
    for (var n = 0; n < ev.report.length; n++) {
      if (ev.report[n] !== null) {
        alert('Got ev.report[' + n + '] = ' + ev.report[n]);
      }
    }
  }
});

Get and send feature reports

Feature reports are seldom used with USB HID devices, nevertherless it is possible to send a feature report with the sendFeatureReport method, which works exactly like sendOutputReport.

To receive a feature report you must use the getFeatureReport method, which will ask the device to send a feature report and will trigger an hid event when the report is eventually received.

See also

This page was last modified on 13 July 2018, at 18:18.