/*
* Copyright (c) 2002 Apple Computer, Inc. All rights reserved.
*
* @APPLE_LICENSE_HEADER_START@
*
* The contents of this file constitute Original Code as defined in and
* are subject to the Apple Public Source License Version 1.2 (the
* "License"). You may not use this file except in compliance with the
* License. Please obtain a copy of the License at
* http://www.apple.com/publicsource and read it before using this file.
*
* This Original Code and all software distributed under the License are
* distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER
* EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
* INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
* Please see the License for the specific language governing rights and
* limitations under the License.
*
* @APPLE_LICENSE_HEADER_END@
*/
#import "DecodeHIDReport.h"
@implementation DecodeHIDReport
+(void)DecodeHIDReport:(UInt8 *)reportDesc forDevice:(UInt16)deviceNumber atDepth:(UInt16)depth reportLen:(UInt16)length forNode:(Node *)node
{
UInt8 * end = reportDesc + length;
UInt8 size, type, tag;
UInt32 usagePage = 0;
UInt32 value=0;
SInt32 svalue=0;
static unsigned char buf[350], tempbuf[350], bufvalue[350], tempbufvalue[350];
int i, indentLevel;
Boolean datahandled=false;
Boolean usagesigned=false;
[self PrintKeyVal:"Parsed Report Descriptor:" val:"" forDevice:deviceNumber atDepth:depth forNode:node];
indentLevel = 1;
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;
bufvalue[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 *)bufvalue, (char *)"(");
strcat((char *)bufvalue, (value & kIO_Data_or_Constant) ? "Constant, " : "Data, ");
strcat((char *)bufvalue, (value & kIO_Array_or_Variable) ? "Variable, ": "Array, ");
strcat((char *)bufvalue, (value & kIO_Absolute_or_Relative) ? "Relative" : "Absolute");
if (((tag == kReport_TagInput) && (value & kIO_Array_or_Variable)) || tag != kReport_TagInput)
{ // these are only valid for variable inputs, and feature/output tags
strcat((char *)bufvalue, (value & kIO_NoWrap_or_Wrap) ? ", Wrap, " : ", No Wrap, ");
strcat((char *)bufvalue, (value & kIO_Linear_or_NonLinear) ? "Nonlinear, " : "Linear, ");
strcat((char *)bufvalue, (value & kIO_PreferredState_or_NoPreferred) ? "No Preferred, " : "Preferred State, ");
strcat((char *)bufvalue, (value & kIO_NoNullPosition_or_NullState) ? "Null State, " : "No Null Position, ");
if (tag != kReport_TagInput)
strcat((char *)bufvalue, (value & kIO_NonVolatile_or_Volatile) ? "Volatile, " : "Nonvolatile, ");
strcat((char *)bufvalue, (value & kIO_BitField_or_BufferedBytes) ? "Buffered bytes" : "Bitfield");
}
strcat((char *)bufvalue, (char *)")");
tempbuf[0] = 0; // we don't want to add this again outside the switch
tempbufvalue[0] = 0;
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
tempbufvalue[0] = 0;
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:
strcat((char *)buf, "Usage Page ");
usagesigned = true;
usagePage = value;
strcat((char *)bufvalue, (char *)"(");
switch (usagePage)
{
case kUsage_PageGenericDesktop: sprintf((char *)tempbufvalue, "Generic Desktop"); break;
case kUsage_PageSimulationControls: sprintf((char *)tempbufvalue, "Simulation Controls"); break;
case kUsage_PageVRControls: sprintf((char *)tempbufvalue, "VR Controls"); break;
case kUsage_PageSportControls: sprintf((char *)tempbufvalue, "Sports Controls"); break;
case kUsage_PageGameControls: sprintf((char *)tempbufvalue, "Game Controls"); break;
case kUsage_PageKeyboard:
sprintf((char *)tempbufvalue, "Keyboard/Keypad");
usagesigned = false;
break;
case kUsage_PageLED: sprintf((char *)tempbufvalue, "LED"); break;
case kUsage_PageButton: sprintf((char *)tempbufvalue, "Button"); break;
case kUsage_PageOrdinal: sprintf((char *)tempbufvalue, "Ordinal"); break;
case kUsage_PageTelephonyDevice: sprintf((char *)tempbufvalue, "Telephany Device"); break;
case kUsage_PageConsumer: sprintf((char *)tempbufvalue, "Consumer"); break;
case kUsage_PageDigitizers: sprintf((char *)tempbufvalue, "Digitizer"); break;
case kUsage_PageUnicode: sprintf((char *)tempbufvalue, "Unicode"); break;
case kUsage_PageAlphanumericDisplay: sprintf((char *)tempbufvalue, "Alphanumeric Display"); break;
case kUsage_PageMonitor: sprintf((char *)tempbufvalue, "Monitor"); break;
case kUsage_PageMonitorEnumeratedValues: sprintf((char *)tempbufvalue, "Monitor Enumerated Values"); break;
case kUsage_PageMonitorVirtualControl: sprintf((char *)tempbufvalue, "VESA Virtual Controls"); break;
case kUsage_PageMonitorReserved: sprintf((char *)tempbufvalue, "Monitor Class reserved"); break;
case kUsage_PagePowerDevice: sprintf((char *)tempbufvalue, "Power Device"); break;
case kUsage_PageBatterySystem: sprintf((char *)tempbufvalue, "Battery System"); break;
case kUsage_PowerClassReserved: sprintf((char *)tempbufvalue, "Power Class reserved"); break;
case kUsage_PowerClassReserved2: sprintf((char *)tempbufvalue, "Power Class reserved"); break;
default: sprintf((char *)tempbufvalue, " }
//strcat((char *)buf, (char *)tempbuf);
strcat((char *)bufvalue, (char *)tempbufvalue);
strcat((char *)bufvalue, (char *)")");
tempbuf[0] = 0; // we don't want to add this again outside the switch
tempbufvalue[0] = 0;
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);
if (usagePage == kUsage_PageGenericDesktop)
{
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, " }
strcat((char *)tempbuf, (char *)")");
}
else
{
sprintf((char *)tempbuf, " }
strcat((char *)buf, (char *)tempbuf);
tempbuf[0] = 0; // we don't want to add this again outside the switch
tempbufvalue[0] = 0;
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 *)bufvalue, (char *)"(");
if (size <= 4)
{
if (usagesigned)
{
sprintf((char *)tempbufvalue, " }
else
{
sprintf((char *)tempbufvalue, " }
strcat((char *)bufvalue, (char *)tempbufvalue);
}
else
for (i = 0; i < size; i++)
{
sprintf((char *)tempbufvalue, " strcat((char *)bufvalue, (char *)tempbufvalue);
}
strcat((char *)bufvalue, (char *)") ");
}
// finally add the info
strcat((char *)bufvalue, " "); // in case bufvalue was empty, add a blank space
// this juggling is because the End Collection tags were not nested deep enough in the OutlineView.
if (tag == kReport_TagEndCollection) {
[self PrintKeyVal:buf val:bufvalue forDevice:deviceNumber atDepth:depth+indentLevel+1 forNode:node];
}
else
[self PrintKeyVal:buf val:bufvalue forDevice:deviceNumber atDepth:depth+indentLevel forNode:node];
}
}
@end