1// 2// IOHIDReportDescriptorParser.c 3// IOHIDFamily 4// 5// Created by Rob Yepez on 2/23/13. 6// 7// 8 9#include <string.h> 10#include "IOHIDReportDescriptorParser.h" 11 12#define UnpackReportSize(packedByte) ((packedByte) & 0x03) 13#define UnpackReportType(packedByte) (((packedByte) & 0x0C) >> 2) 14#define UnpackReportTag(packedByte) (((packedByte) & 0xF0) >> 4) 15 16enum 17{ 18 kReport_TypeMain = 0, 19 kReport_TypeGlobal = 1, 20 kReport_TypeLocal = 2, 21 kReport_TypeReserved = 3, 22 23 kReport_TagLongItem = 0x0F, 24 25 // main items 26 kReport_TagInput = 0x08, 27 kReport_TagOutput = 0x09, 28 kReport_TagFeature = 0x0B, 29 kReport_TagCollection = 0x0A, 30 kReport_TagEndCollection = 0x0C, 31 32 // global items 33 kReport_TagUsagePage = 0x00, 34 kReport_TagLogicalMin = 0x01, 35 kReport_TagLogicalMax = 0x02, 36 kReport_TagPhysicalMin = 0x03, 37 kReport_TagPhysicalMax = 0x04, 38 kReport_TagUnitExponent = 0x05, 39 kReport_TagUnit = 0x06, 40 kReport_TagReportSize = 0x07, 41 kReport_TagReportID = 0x08, 42 kReport_TagReportCount = 0x09, 43 kReport_TagPush = 0x0A, 44 kReport_TagPop = 0x0B, 45 46 // local items 47 kReport_TagUsage = 0x00, 48 kReport_TagUsageMin = 0x01, 49 kReport_TagUsageMax = 0x02, 50 kReport_TagDesignatorIndex = 0x03, 51 kReport_TagDesignatorMin = 0x04, 52 kReport_TagDesignatorMax = 0x05, 53 kReport_TagStringIndex = 0x07, 54 kReport_TagStringMin = 0x08, 55 kReport_TagStringMax = 0x09, 56 kReport_TagSetDelimiter = 0x0A 57}; 58 59// Collection constants 60enum 61{ 62 kCollection_Physical = 0x00, 63 kCollection_Application = 0x01, 64 kCollection_Logical = 0x02 65}; 66 67// I/O constants (used for Input/Output/Feature tags) 68enum 69{ 70 kIO_Data_or_Constant = 0x0001, 71 kIO_Array_or_Variable = 0x0002, 72 kIO_Absolute_or_Relative = 0x0004, 73 kIO_NoWrap_or_Wrap = 0x0008, 74 kIO_Linear_or_NonLinear = 0x0010, 75 kIO_PreferredState_or_NoPreferred = 0x0020, 76 kIO_NoNullPosition_or_NullState = 0x0040, 77 kIO_NonVolatile_or_Volatile = 0x0080, // reserved for Input 78 kIO_BitField_or_BufferedBytes = 0x0100 79}; 80 81// Usage pages from HID Usage Tables spec 1.0 82enum 83{ 84 kUsage_PageGenericDesktop = 0x01, 85 kUsage_PageSimulationControls = 0x02, 86 kUsage_PageVRControls = 0x03, 87 kUsage_PageSportControls = 0x04, 88 kUsage_PageGameControls = 0x05, 89 kUsage_PageKeyboard = 0x07, 90 kUsage_PageLED = 0x08, 91 kUsage_PageButton = 0x09, 92 kUsage_PageOrdinal = 0x0A, 93 kUsage_PageTelephonyDevice = 0x0B, 94 kUsage_PageConsumer = 0x0C, 95 kUsage_PageDigitizers = 0x0D, 96 kUsage_PagePID = 0x0F, 97 kUsage_PageUnicode = 0x10, 98 kUsage_PageAlphanumericDisplay = 0x14, 99 kUsage_PageMonitor = 0x80, 100 kUsage_PageMonitorEnumeratedValues = 0x81, 101 kUsage_PageMonitorVirtualControl = 0x82, 102 kUsage_PageMonitorReserved = 0x83, 103 kUsage_PagePowerDevice = 0x84, 104 kUsage_PageBatterySystem = 0x85, 105 kUsage_PowerClassReserved = 0x86, 106 kUsage_PowerClassReserved2 = 0x87 107}; 108 109// Usage constants for Generic Desktop page (01) from HID Usage Tables spec 1.0 110enum 111{ 112 kUsage_01_Pointer = 0x01, 113 kUsage_01_Mouse = 0x02, 114 kUsage_01_Joystick = 0x04, 115 kUsage_01_GamePad = 0x05, 116 kUsage_01_Keyboard = 0x06, 117 kUsage_01_Keypad = 0x07, 118 119 kUsage_01_X = 0x30, 120 kUsage_01_Y = 0x31, 121 kUsage_01_Z = 0x32, 122 kUsage_01_Rx = 0x33, 123 kUsage_01_Ry = 0x34, 124 kUsage_01_Rz = 0x35, 125 kUsage_01_Slider = 0x36, 126 kUsage_01_Dial = 0x37, 127 kUsage_01_Wheel = 0x38, 128 kUsage_01_HatSwitch = 0x39, 129 kUsage_01_CountedBuffer = 0x3A, 130 kUsage_01_ByteCount = 0x3B, 131 kUsage_01_MotionWakeup = 0x3C, 132 133 kUsage_01_Vx = 0x40, 134 kUsage_01_Vy = 0x41, 135 kUsage_01_Vz = 0x42, 136 kUsage_01_Vbrx = 0x43, 137 kUsage_01_Vbry = 0x44, 138 kUsage_01_Vbrz = 0x45, 139 kUsage_01_Vno = 0x46, 140 141 kUsage_01_SystemControl = 0x80, 142 kUsage_01_SystemPowerDown = 0x81, 143 kUsage_01_SystemSleep = 0x82, 144 kUsage_01_SystemWakeup = 0x83, 145 kUsage_01_SystemContextMenu = 0x84, 146 kUsage_01_SystemMainMenu = 0x85, 147 kUsage_01_SystemAppMenu = 0x86, 148 kUsage_01_SystemMenuHelp = 0x87, 149 kUsage_01_SystemMenuExit = 0x88, 150 kUsage_01_SystemMenuSelect = 0x89, 151 kUsage_01_SystemMenuRight = 0x8A, 152 kUsage_01_SystemMenuLeft = 0x8B, 153 kUsage_01_SystemMenuUp = 0x8C, 154 kUsage_01_SystemMenuDown = 0x8D 155}; 156 157void PrintHIDReport(uint8_t *reportDesc, uint32_t length) 158{ 159 uint8_t * end = reportDesc + length; 160 uint8_t size, type, tag; 161 uint32_t usagePage = 0; 162 uint32_t value=0; 163 int32_t svalue=0; 164 static unsigned char buf[350], tempbuf[350], bufvalue[350], tempbufvalue[350]; 165 int i, indentLevel; 166 int datahandled=0; 167 int usagesigned=0; 168 169 170 indentLevel = 1; 171 172 while (reportDesc < end) 173 { 174 size = UnpackReportSize(*reportDesc); 175 if (size == 3) size = 4; // 0 == 0 bytes, 1 == 1 bytes, 2 == 2 bytes, but 3 == 4 bytes 176 177 type = UnpackReportType(*reportDesc); 178 tag = UnpackReportTag(*reportDesc); 179 reportDesc++; 180 181 if (tag == kReport_TagLongItem) 182 { 183 size = *reportDesc++; 184 tag = *reportDesc++; 185 } 186 187 188 // if we're small enough, load the value into a register (byte swaping) 189 if (size <= 4) 190 { 191 value = 0; 192 for (i = 0; i < size; i++) 193 value += (*(reportDesc++)) << (i * 8); 194 195 svalue = 0; 196 switch (size) 197 { 198 case 1: svalue = (int8_t) value; break; 199 case 2: svalue = (int16_t) value; break; 200 201 // if the top bit is set, then sign extend it and fall thru to 32bit case 202 case 3: if (value & 0x00800000) value |= 0xFF000000; // no break 203 case 4: svalue = (int32_t) value; break; 204 } 205 } 206 207 // indent this line 208 buf[0] = 0; 209 bufvalue[0] = 0; 210 for (i = 0; i < indentLevel; i++) 211 strcat((char *)buf, " "); 212 213 214 // get the name of this tag, and do any specific data handling 215 datahandled = 0; 216 switch (type) 217 { 218 case kReport_TypeMain: 219 switch (tag) 220 { 221 case kReport_TagInput: 222 case kReport_TagOutput: 223 case kReport_TagFeature: 224 switch (tag) 225 { 226 case kReport_TagInput: strcat((char *)buf, "Input..................."); break; 227 case kReport_TagOutput: strcat((char *)buf, "Output.................."); break; 228 case kReport_TagFeature: strcat((char *)buf, "Feature................."); break; 229 } 230 231 strcat((char *)bufvalue, (char *)"("); 232 233 strcat((char *)bufvalue, (value & kIO_Data_or_Constant) ? "Constant, " : "Data, "); 234 235 strcat((char *)bufvalue, (value & kIO_Array_or_Variable) ? "Variable, ": "Array, "); 236 237 strcat((char *)bufvalue, (value & kIO_Absolute_or_Relative) ? "Relative" : "Absolute"); 238 239 if (((tag == kReport_TagInput) && (value & kIO_Array_or_Variable)) || tag != kReport_TagInput) 240 { // these are only valid for variable inputs, and feature/output tags 241 strcat((char *)bufvalue, (value & kIO_NoWrap_or_Wrap) ? ", Wrap, " : ", No Wrap, "); 242 243 strcat((char *)bufvalue, (value & kIO_Linear_or_NonLinear) ? "Nonlinear, " : "Linear, "); 244 245 strcat((char *)bufvalue, (value & kIO_PreferredState_or_NoPreferred) ? "No Preferred, " : "Preferred State, "); 246 247 strcat((char *)bufvalue, (value & kIO_NoNullPosition_or_NullState) ? "Null State, " : "No Null Position, "); 248 249 if (tag != kReport_TagInput) 250 strcat((char *)bufvalue, (value & kIO_NonVolatile_or_Volatile) ? "Volatile, " : "Nonvolatile, "); 251 252 strcat((char *)bufvalue, (value & kIO_BitField_or_BufferedBytes) ? "Buffered bytes" : "Bitfield"); 253 } 254 255 strcat((char *)bufvalue, (char *)")"); 256 257 tempbuf[0] = 0; // we don't want to add this again outside the switch 258 tempbufvalue[0] = 0; 259 datahandled = 1; 260 break; 261 262 263 case kReport_TagCollection: 264 indentLevel++; 265 266 sprintf((char *)tempbuf, "Collection "); 267 268 strcat((char *)buf, (char *)tempbuf); 269 270 strcat((char *)buf, (char *)"("); 271 switch (value) 272 { 273 case kCollection_Physical: sprintf((char *)tempbuf, "Physical"); break; 274 case kCollection_Application: sprintf((char *)tempbuf, "Application"); break; 275 case kCollection_Logical: sprintf((char *)tempbuf, "Logical"); break; 276 } 277 strcat((char *)buf, (char *)tempbuf); 278 strcat((char *)buf, (char *)")"); 279 280 tempbuf[0] = 0; // we don't want to add this again outside the switch 281 tempbufvalue[0] = 0; 282 datahandled = 1; 283 break; 284 285 case kReport_TagEndCollection: 286 // recalc indentation, since we want this line to start earlier 287 indentLevel--; 288 289 buf[0] = 0; 290 for (i = 0; i < indentLevel; i++) { 291 strcat((char *)buf, " "); 292 } 293 294 sprintf((char *)tempbuf, "End Collection "); 295 296 297 break; 298 } 299 break; 300 301 case kReport_TypeGlobal: 302 switch (tag) 303 { 304 case kReport_TagUsagePage: 305 strcat((char *)buf, "Usage Page "); 306 307 usagesigned = 1; 308 usagePage = value; 309 strcat((char *)bufvalue, (char *)"("); 310 switch (usagePage) 311 { 312 case kUsage_PageGenericDesktop: sprintf((char *)tempbufvalue, "Generic Desktop"); break; 313 case kUsage_PageSimulationControls: sprintf((char *)tempbufvalue, "Simulation Controls"); break; 314 case kUsage_PageVRControls: sprintf((char *)tempbufvalue, "VR Controls"); break; 315 case kUsage_PageSportControls: sprintf((char *)tempbufvalue, "Sports Controls"); break; 316 case kUsage_PageGameControls: sprintf((char *)tempbufvalue, "Game Controls"); break; 317 case kUsage_PageKeyboard: 318 sprintf((char *)tempbufvalue, "Keyboard/Keypad"); 319 usagesigned = 0; 320 break; 321 322 case kUsage_PageLED: sprintf((char *)tempbufvalue, "LED"); break; 323 case kUsage_PageButton: sprintf((char *)tempbufvalue, "Button"); break; 324 case kUsage_PageOrdinal: sprintf((char *)tempbufvalue, "Ordinal"); break; 325 case kUsage_PageTelephonyDevice: sprintf((char *)tempbufvalue, "Telephony Device"); break; 326 case kUsage_PageConsumer: sprintf((char *)tempbufvalue, "Consumer"); break; 327 case kUsage_PageDigitizers: sprintf((char *)tempbufvalue, "Digitizer"); break; 328 case kUsage_PagePID: sprintf((char *)tempbufvalue, "PID"); break; 329 case kUsage_PageUnicode: sprintf((char *)tempbufvalue, "Unicode"); break; 330 case kUsage_PageAlphanumericDisplay: sprintf((char *)tempbufvalue, "Alphanumeric Display"); break; 331 case kUsage_PageMonitor: sprintf((char *)tempbufvalue, "Monitor"); break; 332 case kUsage_PageMonitorEnumeratedValues: sprintf((char *)tempbufvalue, "Monitor Enumerated Values"); break; 333 case kUsage_PageMonitorVirtualControl: sprintf((char *)tempbufvalue, "VESA Virtual Controls"); break; 334 case kUsage_PageMonitorReserved: sprintf((char *)tempbufvalue, "Monitor Class reserved"); break; 335 case kUsage_PagePowerDevice: sprintf((char *)tempbufvalue, "Power Device"); break; 336 case kUsage_PageBatterySystem: sprintf((char *)tempbufvalue, "Battery System"); break; 337 case kUsage_PowerClassReserved: sprintf((char *)tempbufvalue, "Power Class reserved"); break; 338 case kUsage_PowerClassReserved2: sprintf((char *)tempbufvalue, "Power Class reserved"); break; 339 case 0xff: sprintf((char *)tempbufvalue, "Vendor Defined"); break; 340 341 default: sprintf((char *)tempbufvalue, "%u", usagePage); break; 342 } 343 344 //strcat((char *)buf, (char *)tempbuf); 345 strcat((char *)bufvalue, (char *)tempbufvalue); 346 strcat((char *)bufvalue, (char *)")"); 347 tempbuf[0] = 0; // we don't want to add this again outside the switch 348 tempbufvalue[0] = 0; 349 datahandled = 1; 350 break; 351 352 case kReport_TagLogicalMin: sprintf((char *)tempbuf, "Logical Minimum......... "); break; 353 case kReport_TagLogicalMax: sprintf((char *)tempbuf, "Logical Maximum......... "); break; 354 case kReport_TagPhysicalMin: sprintf((char *)tempbuf, "Physical Minimum........ "); break; 355 case kReport_TagPhysicalMax: sprintf((char *)tempbuf, "Physical Maximum........ "); break; 356 case kReport_TagUnitExponent: sprintf((char *)tempbuf, "Unit Exponent........... "); break; 357 case kReport_TagUnit: sprintf((char *)tempbuf, "Unit.................... "); break; 358 case kReport_TagReportSize: sprintf((char *)tempbuf, "Report Size............. "); break; 359 case kReport_TagReportID: sprintf((char *)tempbuf, "ReportID................ "); break; 360 case kReport_TagReportCount: sprintf((char *)tempbuf, "Report Count............ "); break; 361 case kReport_TagPush: sprintf((char *)tempbuf, "Push.................... "); break; 362 case kReport_TagPop: sprintf((char *)tempbuf, "Pop..................... "); break; 363 } 364 break; 365 366 case kReport_TypeLocal: 367 switch (tag) 368 { 369 case kReport_TagUsage: 370 sprintf((char *)tempbuf, "Usage "); 371 strcat((char *)buf, (char *)tempbuf); 372 if (usagePage == kUsage_PageGenericDesktop) 373 { 374 strcat((char *)buf, (char *)"("); 375 switch (value) 376 { 377 case kUsage_01_Pointer: sprintf((char *)tempbuf, "Pointer"); break; 378 case kUsage_01_Mouse: sprintf((char *)tempbuf, "Mouse"); break; 379 case kUsage_01_Joystick: sprintf((char *)tempbuf, "Joystick"); break; 380 case kUsage_01_GamePad: sprintf((char *)tempbuf, "GamePad"); break; 381 case kUsage_01_Keyboard: sprintf((char *)tempbuf, "Keyboard"); break; 382 case kUsage_01_Keypad: sprintf((char *)tempbuf, "Keypad"); break; 383 384 case kUsage_01_X: sprintf((char *)tempbuf, "X"); break; 385 case kUsage_01_Y: sprintf((char *)tempbuf, "Y"); break; 386 case kUsage_01_Z: sprintf((char *)tempbuf, "Z"); break; 387 case kUsage_01_Rx: sprintf((char *)tempbuf, "Rx"); break; 388 case kUsage_01_Ry: sprintf((char *)tempbuf, "Ry"); break; 389 case kUsage_01_Rz: sprintf((char *)tempbuf, "Rz"); break; 390 case kUsage_01_Slider: sprintf((char *)tempbuf, "Slider"); break; 391 case kUsage_01_Dial: sprintf((char *)tempbuf, "Dial"); break; 392 case kUsage_01_Wheel: sprintf((char *)tempbuf, "Wheel"); break; 393 case kUsage_01_HatSwitch: sprintf((char *)tempbuf, "Hat Switch"); break; 394 case kUsage_01_CountedBuffer: sprintf((char *)tempbuf, "Counted Buffer"); break; 395 case kUsage_01_ByteCount: sprintf((char *)tempbuf, "Byte Count"); break; 396 case kUsage_01_MotionWakeup: sprintf((char *)tempbuf, "Motion Wakeup"); break; 397 398 case kUsage_01_Vx: sprintf((char *)tempbuf, "Vx"); break; 399 case kUsage_01_Vy: sprintf((char *)tempbuf, "Vy"); break; 400 case kUsage_01_Vz: sprintf((char *)tempbuf, "Vz"); break; 401 case kUsage_01_Vbrx: sprintf((char *)tempbuf, "Vbrx"); break; 402 case kUsage_01_Vbry: sprintf((char *)tempbuf, "Vbry"); break; 403 case kUsage_01_Vbrz: sprintf((char *)tempbuf, "Vbrz"); break; 404 case kUsage_01_Vno: sprintf((char *)tempbuf, "Vno"); break; 405 406 case kUsage_01_SystemControl: sprintf((char *)tempbuf, "System Control"); break; 407 case kUsage_01_SystemPowerDown: sprintf((char *)tempbuf, "System Power Down"); break; 408 case kUsage_01_SystemSleep: sprintf((char *)tempbuf, "System Sleep"); break; 409 case kUsage_01_SystemWakeup: sprintf((char *)tempbuf, "System Wakeup"); break; 410 case kUsage_01_SystemContextMenu: sprintf((char *)tempbuf, "System Context Menu"); break; 411 case kUsage_01_SystemMainMenu: sprintf((char *)tempbuf, "System Main Menu"); break; 412 case kUsage_01_SystemAppMenu: sprintf((char *)tempbuf, "System App Menu"); break; 413 case kUsage_01_SystemMenuHelp: sprintf((char *)tempbuf, "System Menu Help"); break; 414 case kUsage_01_SystemMenuExit: sprintf((char *)tempbuf, "System Menu Exit"); break; 415 case kUsage_01_SystemMenuSelect: sprintf((char *)tempbuf, "System Menu Select"); break; 416 case kUsage_01_SystemMenuRight: sprintf((char *)tempbuf, "System Menu Right"); break; 417 case kUsage_01_SystemMenuLeft: sprintf((char *)tempbuf, "System Menu Left"); break; 418 case kUsage_01_SystemMenuUp: sprintf((char *)tempbuf, "System Menu Up"); break; 419 case kUsage_01_SystemMenuDown: sprintf((char *)tempbuf, "System Menu Down"); break; 420 421 default: sprintf((char *)tempbuf, "%d (0x%x)", (int)value, (unsigned int)value); break; 422 } 423 strcat((char *)tempbuf, (char *)")"); 424 } 425 else if (usagePage == kUsage_PagePID) 426 { 427 strcat((char *)buf, (char *)"("); 428 switch (value) 429 { 430 case 1: sprintf((char *)tempbuf, "Physical Interface Device"); break; 431 case 0x20: sprintf((char *)tempbuf, "Normal"); break; 432 case 0x21: sprintf((char *)tempbuf, "Set Effect Report"); break; 433 case 0x22: sprintf((char *)tempbuf, "Effect Block Index"); break; 434 case 0x23: sprintf((char *)tempbuf, "Parameter Block Offset"); break; 435 case 0x24: sprintf((char *)tempbuf, "ROM Flag"); break; 436 case 0x25: sprintf((char *)tempbuf, "Effect Type"); break; 437 case 0x26: sprintf((char *)tempbuf, "ET Constant Force"); break; 438 case 0x27: sprintf((char *)tempbuf, "ET Ramp"); break; 439 case 0x28: sprintf((char *)tempbuf, "ET Custom Force Data"); break; 440 case 0x30: sprintf((char *)tempbuf, "ET Square"); break; 441 case 0x31: sprintf((char *)tempbuf, "ET Sine"); break; 442 case 0x32: sprintf((char *)tempbuf, "ET Triangle"); break; 443 case 0x33: sprintf((char *)tempbuf, "ET Sawtooth Up"); break; 444 case 0x34: sprintf((char *)tempbuf, "ET Sawtooth Down"); break; 445 case 0x40: sprintf((char *)tempbuf, "ET Spring"); break; 446 case 0x41: sprintf((char *)tempbuf, "ET Damper"); break; 447 case 0x42: sprintf((char *)tempbuf, "ET Inertia"); break; 448 case 0x43: sprintf((char *)tempbuf, "ET Friction"); break; 449 case 0x50: sprintf((char *)tempbuf, "Duration"); break; 450 case 0x51: sprintf((char *)tempbuf, "Sample Period"); break; 451 case 0x52: sprintf((char *)tempbuf, "Gain"); break; 452 case 0x53: sprintf((char *)tempbuf, "Trigger Button"); break; 453 case 0x54: sprintf((char *)tempbuf, "Trigger Repeat Interval"); break; 454 case 0x55: sprintf((char *)tempbuf, "Axes Enable"); break; 455 case 0x56: sprintf((char *)tempbuf, "Direction Enable"); break; 456 case 0x57: sprintf((char *)tempbuf, "Direction"); break; 457 case 0x58: sprintf((char *)tempbuf, "Type Specific Block Offset"); break; 458 case 0x59: sprintf((char *)tempbuf, "Block Type"); break; 459 case 0x5a: sprintf((char *)tempbuf, "Set Envelope Report"); break; 460 case 0x5b: sprintf((char *)tempbuf, "Attack Level"); break; 461 case 0x5c: sprintf((char *)tempbuf, "Attack Time"); break; 462 case 0x5d: sprintf((char *)tempbuf, "Fade Level"); break; 463 case 0x5e: sprintf((char *)tempbuf, "Fade Time"); break; 464 case 0x5f: sprintf((char *)tempbuf, "Set Condition Report"); break; 465 case 0x60: sprintf((char *)tempbuf, "CP Offset"); break; 466 case 0x61: sprintf((char *)tempbuf, "Positive Coefficient"); break; 467 case 0x62: sprintf((char *)tempbuf, "Negative Coefficient"); break; 468 case 0x63: sprintf((char *)tempbuf, "Positive Saturation"); break; 469 case 0x64: sprintf((char *)tempbuf, "Negative Saturation"); break; 470 case 0x65: sprintf((char *)tempbuf, "Dead Band"); break; 471 case 0x66: sprintf((char *)tempbuf, "Download Force Data Report"); break; 472 case 0x67: sprintf((char *)tempbuf, "Isoch Custom Force Enable"); break; 473 case 0x68: sprintf((char *)tempbuf, "Custom Force Data Report"); break; 474 case 0x69: sprintf((char *)tempbuf, "Custom Force Data"); break; 475 case 0x6a: sprintf((char *)tempbuf, "Custom Force Vendor Defined Data"); break; 476 case 0x6b: sprintf((char *)tempbuf, "Set Custom Force Report"); break; 477 case 0x6c: sprintf((char *)tempbuf, "Custom Force Data Offset"); break; 478 case 0x6d: sprintf((char *)tempbuf, "Sample Count"); break; 479 case 0x6e: sprintf((char *)tempbuf, "Set Periodic Report"); break; 480 case 0x6f: sprintf((char *)tempbuf, "Offset"); break; 481 case 0x70: sprintf((char *)tempbuf, "Magnitude"); break; 482 case 0x71: sprintf((char *)tempbuf, "Phase"); break; 483 case 0x72: sprintf((char *)tempbuf, "Period"); break; 484 case 0x73: sprintf((char *)tempbuf, "Set Constant Force Report"); break; 485 case 0x74: sprintf((char *)tempbuf, "Set Constant Force"); break; 486 case 0x75: sprintf((char *)tempbuf, "Ramp Start"); break; 487 case 0x76: sprintf((char *)tempbuf, "Ramp End"); break; 488 case 0x77: sprintf((char *)tempbuf, "Effect Operation Report"); break; 489 case 0x78: sprintf((char *)tempbuf, "Effect Operation"); break; 490 case 0x79: sprintf((char *)tempbuf, "Op Effect Start"); break; 491 case 0x7a: sprintf((char *)tempbuf, "Op Effect Start Solo"); break; 492 case 0x7b: sprintf((char *)tempbuf, "Op Effect Stop"); break; 493 case 0x7c: sprintf((char *)tempbuf, "Loop Count"); break; 494 case 0x7d: sprintf((char *)tempbuf, "Gain Report"); break; 495 case 0x7e: sprintf((char *)tempbuf, "Gain"); break; 496 case 0x7f: sprintf((char *)tempbuf, "PID Pool Report"); break; 497 case 0x80: sprintf((char *)tempbuf, "RAM Pool Size"); break; 498 case 0x81: sprintf((char *)tempbuf, "ROM Pool Size"); break; 499 case 0x82: sprintf((char *)tempbuf, "ROM Effect Block Count"); break; 500 case 0x83: sprintf((char *)tempbuf, "Simultaneous Effects Max"); break; 501 case 0x84: sprintf((char *)tempbuf, "Pool Alignment"); break; 502 case 0x85: sprintf((char *)tempbuf, "PID Pool Move Report"); break; 503 case 0x86: sprintf((char *)tempbuf, "Move Source"); break; 504 case 0x87: sprintf((char *)tempbuf, "Move Destination"); break; 505 case 0x88: sprintf((char *)tempbuf, "Move Length"); break; 506 case 0x89: sprintf((char *)tempbuf, "PID Block Load Report"); break; 507 case 0x8b: sprintf((char *)tempbuf, "Block Load Status"); break; 508 case 0x8c: sprintf((char *)tempbuf, "Block Load Success"); break; 509 case 0x8d: sprintf((char *)tempbuf, "Block Load Full"); break; 510 case 0x8e: sprintf((char *)tempbuf, "Block Load Error"); break; 511 case 0x8f: sprintf((char *)tempbuf, "Block Handle"); break; 512 case 0x90: sprintf((char *)tempbuf, "PID Block Free Report"); break; 513 case 0x91: sprintf((char *)tempbuf, "Type Specific Block Handle"); break; 514 case 0x92: sprintf((char *)tempbuf, "PID State Report"); break; 515 case 0x94: sprintf((char *)tempbuf, "Effect Playing"); break; 516 case 0x95: sprintf((char *)tempbuf, "PID Device Control Report"); break; 517 case 0x96: sprintf((char *)tempbuf, "PID Device Control"); break; 518 case 0x97: sprintf((char *)tempbuf, "DC Enable Actuators"); break; 519 case 0x98: sprintf((char *)tempbuf, "DC Disable Actuators"); break; 520 case 0x99: sprintf((char *)tempbuf, "DC Stoop All Effects"); break; 521 case 0x9a: sprintf((char *)tempbuf, "DC Device Reset"); break; 522 case 0x9b: sprintf((char *)tempbuf, "DC Device Pause"); break; 523 case 0x9c: sprintf((char *)tempbuf, "DC Device Continue"); break; 524 case 0x9f: sprintf((char *)tempbuf, "Device Paused"); break; 525 case 0xa0: sprintf((char *)tempbuf, "Actuators Enabled"); break; 526 case 0xa4: sprintf((char *)tempbuf, "Safety Switch"); break; 527 case 0xa5: sprintf((char *)tempbuf, "Actuator Override Switch"); break; 528 case 0xa6: sprintf((char *)tempbuf, "Actuator Power"); break; 529 case 0xa7: sprintf((char *)tempbuf, "Start Delay"); break; 530 case 0xa8: sprintf((char *)tempbuf, "Parameter Block Size"); break; 531 case 0xa9: sprintf((char *)tempbuf, "Device Managed Pool"); break; 532 case 0xaa: sprintf((char *)tempbuf, "Shared parameter blocks"); break; 533 case 0xab: sprintf((char *)tempbuf, "Create New Effect Report"); break; 534 case 0xac: sprintf((char *)tempbuf, "RAM Pool Available"); break; 535 536 537 default: sprintf((char *)tempbuf, "%d (0x%x)", (int)value, (unsigned int)value); break; 538 } 539 strcat((char *)tempbuf, (char *)")"); 540 } 541 else 542 { 543 sprintf((char *)tempbuf, "%d (0x%x)", (int)value, (unsigned int)value); 544 } 545 546 strcat((char *)buf, (char *)tempbuf); 547 tempbuf[0] = 0; // we don't want to add this again outside the switch 548 tempbufvalue[0] = 0; 549 datahandled = 1; 550 break; 551 552 case kReport_TagUsageMin: sprintf((char *)tempbuf, "Usage Minimum........... "); break; 553 case kReport_TagUsageMax: sprintf((char *)tempbuf, "Usage Maximum........... "); break; 554 case kReport_TagDesignatorIndex: sprintf((char *)tempbuf, "Designator Index........ "); break; 555 case kReport_TagDesignatorMin: sprintf((char *)tempbuf, "Designator Minumum...... "); break; 556 case kReport_TagDesignatorMax: sprintf((char *)tempbuf, "Designator Maximum...... "); break; 557 case kReport_TagStringIndex: sprintf((char *)tempbuf, "String Index............ "); break; 558 case kReport_TagStringMin: sprintf((char *)tempbuf, "String Minimum.......... "); break; 559 case kReport_TagStringMax: sprintf((char *)tempbuf, "String Maximum.......... "); break; 560 case kReport_TagSetDelimiter: sprintf((char *)tempbuf, "Set Delimiter........... "); break; 561 } 562 break; 563 564 case kReport_TypeReserved: 565 sprintf((char *)tempbuf, "Reserved "); break; 566 break; 567 } 568 569 // actually put in the data from the switch -- why not just strcat there?? 570 strcat((char *)buf, (char *)tempbuf); 571 572 // if we didn't handle the data before, print in generic fashion 573 if (!datahandled && size) 574 { 575 strcat((char *)bufvalue, (char *)"("); 576 if (size <= 4) 577 { 578 if (usagesigned) 579 { 580 sprintf((char *)tempbufvalue, "%d", (int32_t)svalue); 581 } 582 else 583 { 584 sprintf((char *)tempbufvalue, "%u", (uint32_t)value); 585 } 586 strcat((char *)bufvalue, (char *)tempbufvalue); 587 } 588 else 589 for (i = 0; i < size; i++) 590 { 591 sprintf((char *)tempbufvalue, "%02X ", *(reportDesc++)); 592 strcat((char *)bufvalue, (char *)tempbufvalue); 593 } 594 strcat((char *)bufvalue, (char *)") "); 595 } 596 597 598 // finally add the info 599 strcat((char *)bufvalue, " "); // in case bufvalue was empty, add a blank space 600 601 602 // this juggling is because the End Collection tags were not nested deep enough in the OutlineView. 603 604 /* if (tag == kReport_TagEndCollection) { 605 [self PrintKeyVal:buf val:bufvalue forDevice:deviceNumber atDepth:depth+indentLevel+1 forNode:node]; 606 } 607 else 608 [self PrintKeyVal:buf val:bufvalue forDevice:deviceNumber atDepth:depth+indentLevel forNode:node];*/ 609 610 printf("%s%s\n",buf, bufvalue); 611 } 612} 613