Retired Document
Important: This sample code may not represent best practices for current development. The project may use deprecated symbols and illustrate technologies and techniques that are no longer recommended.
TestHIDprobe.c
/* |
File: TestHIDprobe.c |
Contains: xxx put contents here xxx |
Version: xxx put version here xxx |
Copyright: © 1998 by Apple Computer, Inc., all rights reserved. |
File Ownership: |
DRI: xxx put dri here xxx |
Other Contact: xxx put other contact here xxx |
Technology: xxx put technology here xxx |
Writers: |
(BWS) Brent Schorsch |
Change History (most recent first): |
<0*> 5/18/98 BWS stolen from USBProber |
*/ |
#include <string.h> |
#include <stdio.h> |
#include <errors.h> |
#include <USB.h> |
/* HID Constants - Spec 1.0 */ |
#define UnpackReportSize(packedByte) ((packedByte) & 0x03) |
#define UnpackReportType(packedByte) (((packedByte) & 0x0C) >> 2) |
#define UnpackReportTag(packedByte) (((packedByte) & 0xF0) >> 4) |
enum |
{ |
kReport_TypeMain = 0, |
kReport_TypeGlobal = 1, |
kReport_TypeLocal = 2, |
kReport_TypeReserved = 3, |
kReport_TagLongItem = 0x0F, |
// main items |
kReport_TagInput = 0x08, |
kReport_TagOutput = 0x09, |
kReport_TagFeature = 0x0B, |
kReport_TagCollection = 0x0A, |
kReport_TagEndCollection = 0x0C, |
// global items |
kReport_TagUsagePage = 0x00, |
kReport_TagLogicalMin = 0x01, |
kReport_TagLogicalMax = 0x02, |
kReport_TagPhysicalMin = 0x03, |
kReport_TagPhysicalMax = 0x04, |
kReport_TagUnitExponent = 0x05, |
kReport_TagUnit = 0x06, |
kReport_TagReportSize = 0x07, |
kReport_TagReportID = 0x08, |
kReport_TagReportCount = 0x09, |
kReport_TagPush = 0x0A, |
kReport_TagPop = 0x0B, |
// local items |
kReport_TagUsage = 0x00, |
kReport_TagUsageMin = 0x01, |
kReport_TagUsageMax = 0x02, |
kReport_TagDesignatorIndex = 0x03, |
kReport_TagDesignatorMin = 0x04, |
kReport_TagDesignatorMax = 0x05, |
kReport_TagStringIndex = 0x07, |
kReport_TagStringMin = 0x08, |
kReport_TagStringMax = 0x09, |
kReport_TagSetDelimiter = 0x0A |
}; |
// Collection constants |
enum |
{ |
kCollection_Physical = 0x00, |
kCollection_Application = 0x01, |
kCollection_Logical = 0x02 |
}; |
// I/O constants (used for Input/Output/Feature tags) |
enum |
{ |
kIO_Data_or_Constant = 0x0001, |
kIO_Array_or_Variable = 0x0002, |
kIO_Absolute_or_Relative = 0x0004, |
kIO_NoWrap_or_Wrap = 0x0008, |
kIO_Linear_or_NonLinear = 0x0010, |
kIO_PreferredState_or_NoPreferred = 0x0020, |
kIO_NoNullPosition_or_NullState = 0x0040, |
kIO_NonVolatile_or_Volatile = 0x0080, // reserved for Input |
kIO_BitField_or_BufferedBytes = 0x0100 |
}; |
// Usage pages from HID Usage Tables spec 1.0 |
enum |
{ |
kUsage_PageGenericDesktop = 0x01, |
kUsage_PageSimulationControls = 0x02, |
kUsage_PageVRControls = 0x03, |
kUsage_PageSportControls = 0x04, |
kUsage_PageGameControls = 0x05, |
kUsage_PageKeyboard = 0x07, |
kUsage_PageLED = 0x08, |
kUsage_PageButton = 0x09, |
kUsage_PageOrdinal = 0x0A, |
kUsage_PageTelephonyDevice = 0x0B, |
kUsage_PageConsumer = 0x0C, |
kUsage_PageDigitizers = 0x0D, |
kUsage_PageUnicode = 0x10, |
kUsage_PageAlphanumericDisplay = 0x14 |
}; |
// Usage constants for Generic Desktop page (01) from HID Usage Tables spec 1.0 |
enum |
{ |
kUsage_01_Pointer = 0x01, |
kUsage_01_Mouse = 0x02, |
kUsage_01_Joystick = 0x04, |
kUsage_01_GamePad = 0x05, |
kUsage_01_Keyboard = 0x06, |
kUsage_01_Keypad = 0x07, |
kUsage_01_X = 0x30, |
kUsage_01_Y = 0x31, |
kUsage_01_Z = 0x32, |
kUsage_01_Rx = 0x33, |
kUsage_01_Ry = 0x34, |
kUsage_01_Rz = 0x35, |
kUsage_01_Slider = 0x36, |
kUsage_01_Dial = 0x37, |
kUsage_01_Wheel = 0x38, |
kUsage_01_HatSwitch = 0x39, |
kUsage_01_CountedBuffer = 0x3A, |
kUsage_01_ByteCount = 0x3B, |
kUsage_01_MotionWakeup = 0x3C, |
kUsage_01_Vx = 0x40, |
kUsage_01_Vy = 0x41, |
kUsage_01_Vz = 0x42, |
kUsage_01_Vbrx = 0x43, |
kUsage_01_Vbry = 0x44, |
kUsage_01_Vbrz = 0x45, |
kUsage_01_Vno = 0x46, |
kUsage_01_SystemControl = 0x80, |
kUsage_01_SystemPowerDown = 0x81, |
kUsage_01_SystemSleep = 0x82, |
kUsage_01_SystemWakeup = 0x83, |
kUsage_01_SystemContextMenu = 0x84, |
kUsage_01_SystemMainMenu = 0x85, |
kUsage_01_SystemAppMenu = 0x86, |
kUsage_01_SystemMenuHelp = 0x87, |
kUsage_01_SystemMenuExit = 0x88, |
kUsage_01_SystemMenuSelect = 0x89, |
kUsage_01_SystemMenuRight = 0x8A, |
kUsage_01_SystemMenuLeft = 0x8B, |
kUsage_01_SystemMenuUp = 0x8C, |
kUsage_01_SystemMenuDown = 0x8D |
}; |
/* end HID Constants Spec 1.0 */ |
void PrintHIDReport(UInt8 * reportDesc, UInt32 length); |
void PrintHIDReport(UInt8 * reportDesc, UInt32 length) |
{ |
UInt8 * currByte; |
UInt8 * end; |
UInt8 size, type, tag; |
UInt32 usagePage = 0; |
UInt32 value; |
SInt32 svalue; |
unsigned char buf[256], tempbuf[256]; |
int i, k, indentLevel; |
Boolean datahandled; |
Boolean usagesigned; |
end = reportDesc + length; |
printf("Report Descriptor\n"); |
printf("0x%x (%d) Bytes\n", length, length); |
k= 0; |
buf[0] = 0; |
currByte = reportDesc; |
for(i=0; i < length + 3; i++) |
{ |
if (!(k%16)) |
{ |
sprintf((char *)buf, "%04X:", k); |
}; |
sprintf((char *)tempbuf, "%02X ", *(currByte++)); |
strcat((char *)buf, (char *)tempbuf); |
k++; |
if (!(k%16)) |
{ |
printf("%s\n", (char *)buf); |
}; |
}; |
if ((k%16)) |
printf("%s\n", (char *)buf); |
buf[0] = 0; |
indentLevel = 0; |
while (reportDesc < end) |
{ |
size = UnpackReportSize(*reportDesc); |
if (size == 3) size = 4; // 0 == 0 bytes, 1 == 1 bytes, 2 == 2 bytes, but 3 == 4 bytes |
type = UnpackReportType(*reportDesc); |
tag = UnpackReportTag(*reportDesc); |
reportDesc++; |
if (tag == kReport_TagLongItem) |
{ |
size = *reportDesc++; |
tag = *reportDesc++; |
} |
// if we're small enough, load the value into a register (byte swaping) |
if (size <= 4) |
{ |
value = 0; |
for (i = 0; i < size; i++) |
value += (*(reportDesc++)) << (i * 8); |
svalue = 0; |
switch (size) |
{ |
case 1: svalue = (SInt8) value; break; |
case 2: svalue = (SInt16) value; break; |
// if the top bit is set, then sign extend it and fall thru to 32bit case |
case 3: if (value & 0x00800000) value |= 0xFF000000; // no break |
case 4: svalue = (SInt32) value; break; |
} |
} |
// indent this line |
buf[0] = 0; |
for (i = 0; i < indentLevel; i++) |
strcat((char *)buf, " "); |
// get the name of this tag, and do any specific data handling |
datahandled = false; |
switch (type) |
{ |
case kReport_TypeMain: |
switch (tag) |
{ |
case kReport_TagInput: |
case kReport_TagOutput: |
case kReport_TagFeature: |
switch (tag) |
{ |
case kReport_TagInput: strcat((char *)buf, "Input "); break; |
case kReport_TagOutput: strcat((char *)buf, "Output "); break; |
case kReport_TagFeature: strcat((char *)buf, "Feature "); break; |
} |
strcat((char *)buf, (char *)"("); |
if (value & kIO_Data_or_Constant) strcat((char *)buf, "Constant"); |
else strcat((char *)buf, "Data"); |
if (value & kIO_Array_or_Variable) strcat((char *)buf, ", Variable"); |
else strcat((char *)buf, ", Array"); |
if (value & kIO_Absolute_or_Relative) strcat((char *)buf, ", Relative"); |
else strcat((char *)buf, ", Absolute"); |
if (value & kIO_NoWrap_or_Wrap) strcat((char *)buf, ", Null State"); |
if (value & kIO_Linear_or_NonLinear) strcat((char *)buf, ", Nonlinear"); |
if (value & kIO_PreferredState_or_NoPreferred) strcat((char *)buf, ", No Preferred"); |
if (value & kIO_NoNullPosition_or_NullState) strcat((char *)buf, ", Null State"); |
if (tag != kReport_TagInput) |
if (value & kIO_NonVolatile_or_Volatile) strcat((char *)buf, ", Volatile"); |
else strcat((char *)buf, ", Non-volatile"); |
if (value & kIO_BitField_or_BufferedBytes) strcat((char *)buf, ", Buffered bytes"); |
strcat((char *)buf, (char *)")"); |
tempbuf[0] = 0; // we don't want to add this again outside the switch |
datahandled = true; |
break; |
case kReport_TagCollection: |
indentLevel++; |
sprintf((char *)tempbuf, "Collection "); |
strcat((char *)buf, (char *)tempbuf); |
strcat((char *)buf, (char *)"("); |
switch (value) |
{ |
case kCollection_Physical: sprintf((char *)tempbuf, "Physical"); break; |
case kCollection_Application: sprintf((char *)tempbuf, "Application"); break; |
case kCollection_Logical: sprintf((char *)tempbuf, "Logical"); break; |
} |
strcat((char *)buf, (char *)tempbuf); |
strcat((char *)buf, (char *)")"); |
tempbuf[0] = 0; // we don't want to add this again outside the switch |
datahandled = true; |
break; |
case kReport_TagEndCollection: |
// recalc indentation, since we want this line to start earlier |
indentLevel--; |
buf[0] = 0; |
for (i = 0; i < indentLevel; i++) |
strcat((char *)buf, " "); |
sprintf((char *)tempbuf, "End Collection "); |
break; |
} |
break; |
case kReport_TypeGlobal: |
switch (tag) |
{ |
case kReport_TagUsagePage: |
sprintf((char *)tempbuf, "Usage Page "); |
strcat((char *)buf, (char *)tempbuf); |
usagesigned = true; |
usagePage = value; |
strcat((char *)buf, (char *)"("); |
switch (usagePage) |
{ |
case kUsage_PageGenericDesktop: sprintf((char *)tempbuf, "Generic Desktop"); break; |
case kUsage_PageSimulationControls: sprintf((char *)tempbuf, "Simulation Controls"); break; |
case kUsage_PageVRControls: sprintf((char *)tempbuf, "VR Controls"); break; |
case kUsage_PageSportControls: sprintf((char *)tempbuf, "Sports Controls"); break; |
case kUsage_PageGameControls: sprintf((char *)tempbuf, "Game Controls"); break; |
case kUsage_PageKeyboard: |
sprintf((char *)tempbuf, "Keyboard/Keypad"); |
usagesigned = false; |
break; |
case kUsage_PageLED: sprintf((char *)tempbuf, "LED"); break; |
case kUsage_PageButton: sprintf((char *)tempbuf, "Button"); break; |
case kUsage_PageOrdinal: sprintf((char *)tempbuf, "Ordinal"); break; |
case kUsage_PageTelephonyDevice: sprintf((char *)tempbuf, "Telephany Device"); break; |
case kUsage_PageConsumer: sprintf((char *)tempbuf, "Consumer"); break; |
case kUsage_PageDigitizers: sprintf((char *)tempbuf, "Digitizer"); break; |
case kUsage_PageUnicode: sprintf((char *)tempbuf, "Unicode"); break; |
case kUsage_PageAlphanumericDisplay: sprintf((char *)tempbuf, "Alphanumeric Display"); break; |
default: sprintf((char *)tempbuf, "%d", usagePage); break; |
} |
strcat((char *)buf, (char *)tempbuf); |
strcat((char *)buf, (char *)")"); |
tempbuf[0] = 0; // we don't want to add this again outside the switch |
datahandled = true; |
break; |
case kReport_TagLogicalMin: sprintf((char *)tempbuf, "Logical Minimum.... "); break; |
case kReport_TagLogicalMax: sprintf((char *)tempbuf, "Logical Maximum.... "); break; |
case kReport_TagPhysicalMin: sprintf((char *)tempbuf, "Physical Minimum... "); break; |
case kReport_TagPhysicalMax: sprintf((char *)tempbuf, "Physical Maximum... "); break; |
case kReport_TagUnitExponent: sprintf((char *)tempbuf, "Unit Exponent...... "); break; |
case kReport_TagUnit: sprintf((char *)tempbuf, "Unit............... "); break; |
case kReport_TagReportSize: sprintf((char *)tempbuf, "Report Size........ "); break; |
case kReport_TagReportID: sprintf((char *)tempbuf, "ReportID........... "); break; |
case kReport_TagReportCount: sprintf((char *)tempbuf, "Report Count....... "); break; |
case kReport_TagPush: sprintf((char *)tempbuf, "Push............... "); break; |
case kReport_TagPop: sprintf((char *)tempbuf, "Pop................ "); break; |
} |
break; |
case kReport_TypeLocal: |
switch (tag) |
{ |
case kReport_TagUsage: |
sprintf((char *)tempbuf, "Usage "); |
strcat((char *)buf, (char *)tempbuf); |
strcat((char *)buf, (char *)"("); |
switch (value) |
{ |
case kUsage_01_Pointer: sprintf((char *)tempbuf, "Pointer"); break; |
case kUsage_01_Mouse: sprintf((char *)tempbuf, "Mouse"); break; |
case kUsage_01_Joystick: sprintf((char *)tempbuf, "Joystick"); break; |
case kUsage_01_GamePad: sprintf((char *)tempbuf, "GamePad"); break; |
case kUsage_01_Keyboard: sprintf((char *)tempbuf, "Keyboard"); break; |
case kUsage_01_Keypad: sprintf((char *)tempbuf, "Keypad"); break; |
case kUsage_01_X: sprintf((char *)tempbuf, "X"); break; |
case kUsage_01_Y: sprintf((char *)tempbuf, "Y"); break; |
case kUsage_01_Z: sprintf((char *)tempbuf, "Z"); break; |
case kUsage_01_Rx: sprintf((char *)tempbuf, "Rx"); break; |
case kUsage_01_Ry: sprintf((char *)tempbuf, "Ry"); break; |
case kUsage_01_Rz: sprintf((char *)tempbuf, "Rz"); break; |
case kUsage_01_Slider: sprintf((char *)tempbuf, "Slider"); break; |
case kUsage_01_Dial: sprintf((char *)tempbuf, "Dial"); break; |
case kUsage_01_Wheel: sprintf((char *)tempbuf, "Wheel"); break; |
case kUsage_01_HatSwitch: sprintf((char *)tempbuf, "Hat Switch"); break; |
case kUsage_01_CountedBuffer: sprintf((char *)tempbuf, "Counted Buffer"); break; |
case kUsage_01_ByteCount: sprintf((char *)tempbuf, "Byte Count"); break; |
case kUsage_01_MotionWakeup: sprintf((char *)tempbuf, "Motion Wakeup"); break; |
case kUsage_01_Vx: sprintf((char *)tempbuf, "Vx"); break; |
case kUsage_01_Vy: sprintf((char *)tempbuf, "Vy"); break; |
case kUsage_01_Vz: sprintf((char *)tempbuf, "Vz"); break; |
case kUsage_01_Vbrx: sprintf((char *)tempbuf, "Vbrx"); break; |
case kUsage_01_Vbry: sprintf((char *)tempbuf, "Vbry"); break; |
case kUsage_01_Vbrz: sprintf((char *)tempbuf, "Vbrz"); break; |
case kUsage_01_Vno: sprintf((char *)tempbuf, "Vno"); break; |
case kUsage_01_SystemControl: sprintf((char *)tempbuf, "System Control"); break; |
case kUsage_01_SystemPowerDown: sprintf((char *)tempbuf, "System Power Down"); break; |
case kUsage_01_SystemSleep: sprintf((char *)tempbuf, "System Sleep"); break; |
case kUsage_01_SystemWakeup: sprintf((char *)tempbuf, "System Wakeup"); break; |
case kUsage_01_SystemContextMenu: sprintf((char *)tempbuf, "System Context Menu"); break; |
case kUsage_01_SystemMainMenu: sprintf((char *)tempbuf, "System Main Menu"); break; |
case kUsage_01_SystemAppMenu: sprintf((char *)tempbuf, "System App Menu"); break; |
case kUsage_01_SystemMenuHelp: sprintf((char *)tempbuf, "System Menu Help"); break; |
case kUsage_01_SystemMenuExit: sprintf((char *)tempbuf, "System Menu Exit"); break; |
case kUsage_01_SystemMenuSelect: sprintf((char *)tempbuf, "System Menu Select"); break; |
case kUsage_01_SystemMenuRight: sprintf((char *)tempbuf, "System Menu Right"); break; |
case kUsage_01_SystemMenuLeft: sprintf((char *)tempbuf, "System Menu Left"); break; |
case kUsage_01_SystemMenuUp: sprintf((char *)tempbuf, "System Menu Up"); break; |
case kUsage_01_SystemMenuDown: sprintf((char *)tempbuf, "System Menu Down"); break; |
default: sprintf((char *)tempbuf, "%d", value); break; |
} |
strcat((char *)buf, (char *)tempbuf); |
strcat((char *)buf, (char *)")"); |
tempbuf[0] = 0; // we don't want to add this again outside the switch |
datahandled = true; |
break; |
case kReport_TagUsageMin: sprintf((char *)tempbuf, "Usage Minimum...... "); break; |
case kReport_TagUsageMax: sprintf((char *)tempbuf, "Usage Maximum...... "); break; |
case kReport_TagDesignatorIndex: sprintf((char *)tempbuf, "Designator Index... "); break; |
case kReport_TagDesignatorMin: sprintf((char *)tempbuf, "Designator Minumum. "); break; |
case kReport_TagDesignatorMax: sprintf((char *)tempbuf, "Designator Maximum. "); break; |
case kReport_TagStringIndex: sprintf((char *)tempbuf, "String Index....... "); break; |
case kReport_TagStringMin: sprintf((char *)tempbuf, "String Minimum..... "); break; |
case kReport_TagStringMax: sprintf((char *)tempbuf, "String Maximum..... "); break; |
case kReport_TagSetDelimiter: sprintf((char *)tempbuf, "Set Delimiter...... "); break; |
} |
break; |
case kReport_TypeReserved: |
sprintf((char *)tempbuf, "Reserved "); break; |
break; |
} |
// actually put in the data from the switch -- why not just strcat there?? |
strcat((char *)buf, (char *)tempbuf); |
// if we didn't handle the data before, print in generic fashion |
if (!datahandled && size) |
{ |
strcat((char *)buf, (char *)"("); |
if (size <= 4) |
{ |
if (usagesigned) |
{ |
sprintf((char *)tempbuf, "%ld", (SInt32)svalue); |
} |
else |
{ |
sprintf((char *)tempbuf, "%lu", (UInt32)value); |
} |
strcat((char *)buf, (char *)tempbuf); |
} |
else |
for (i = 0; i < size; i++) |
{ |
sprintf((char *)tempbuf, "%02X ", *(reportDesc++)); |
strcat((char *)buf, (char *)tempbuf); |
} |
strcat((char *)buf, (char *)") "); |
} |
// finally add the info |
// printf("ITEM (%s)\n", (char *) tempbuf); |
printf("%s\n", (char *) buf); |
} |
} |
Copyright © 2003 Apple Computer, Inc. All Rights Reserved. Terms of Use | Privacy Policy | Updated: 2003-01-14