USB I/O API
From SpinetiX Support Wiki
Contents
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.
- To effectively use this API, you must be familiar with the USB HID class definition and HID usage tables.
- When an HID device is plugged into or removed from the HMP USB port, an HID event is generated. Hot-plugging is supported only on the HMP and it is not supported on Elementi.
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 >
- Peripherals > USB page for HMP400, HMP400W, HMP350, and HMP300
- I/O Automation > USB Settings page for HMP200, HMP130, HMP100
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
andserialNumber
are provided by the USB device to identify the hardware. They are shared by all functions of a multi-function device. -
usagePage
andusage
identify the functionality of an I/O interface according to USB HID usage tables. - The
inputReports
,outputReports
andfeatureReports
are arrays ofHIDReportFields
objects that enumerate the available reports for this device by category.
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 a 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 && 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 && 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, nevertheless 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.