/** * @file main.cpp * @brief Main entry point for the HID Device Analyzer tool * * This tool helps identify and analyze HID devices, particularly focusing on * lighthouse devices used in VR systems. It can: * 1. Detect and connect to HID devices * 2. Read raw HID reports from these devices * 3. Analyze and display the report IDs and raw buffer data * 4. Help identify the exact offsets for accelerometer and gyroscope XYZ values */ #include "hid_device_analyzer.h" #include #include #include #include #include #include #include // Valve's Vendor ID #define VALVE_VID 0x28DE void PrintUsage() { std::cout << "HID Device Analyzer - A tool to analyze HID devices and their reports" << std::endl; std::cout << "Usage:" << std::endl; std::cout << " -h, --help Show this help message" << std::endl; std::cout << " -l, --list List all HID devices" << std::endl; std::cout << " -v, --valve List only Valve HID devices (VID: 0x28DE)" << std::endl; std::cout << " -d, --device Open a specific device by path" << std::endl; std::cout << " -r, --read Read a number of reports from the device" << std::endl; std::cout << " -i, --id Specify the report ID to read (default: 0)" << std::endl; std::cout << " -a, --analyze Analyze the read reports to identify patterns" << std::endl; std::cout << " -p, --print-descriptor Print the HID report descriptor" << std::endl; std::cout << std::endl; std::cout << "Examples:" << std::endl; std::cout << " hid_analyzer --list # List all HID devices" << std::endl; std::cout << " hid_analyzer --valve # List only Valve HID devices" << std::endl; std::cout << " hid_analyzer --device \"HID\\VID_28DE&PID_2101\\123456\" --print-descriptor # Print the report descriptor for a specific device" << std::endl; std::cout << " hid_analyzer --device \"HID\\VID_28DE&PID_2101\\123456\" --read 10 --id 1 --analyze # Read 10 reports with ID 1 and analyze them" << std::endl; } int main(int argc, char* argv[]) { std::cout << "HID Device Analyzer v1.0" << std::endl; std::cout << "=========================" << std::endl; // Parse command line arguments bool listDevices = false; bool listValveDevices = false; bool printDescriptor = false; bool analyzeReports = false; std::string devicePath; int reportCount = 0; uint8_t reportId = 0; for (int i = 1; i < argc; i++) { std::string arg = argv[i]; if (arg == "-h" || arg == "--help") { PrintUsage(); return 0; } else if (arg == "-l" || arg == "--list") { listDevices = true; } else if (arg == "-v" || arg == "--valve") { listValveDevices = true; } else if (arg == "-d" || arg == "--device") { if (i + 1 < argc) { devicePath = argv[++i]; } else { std::cerr << "Error: --device requires a path argument." << std::endl; return 1; } } else if (arg == "-r" || arg == "--read") { if (i + 1 < argc) { reportCount = std::atoi(argv[++i]); } else { std::cerr << "Error: --read requires a count argument." << std::endl; return 1; } } else if (arg == "-i" || arg == "--id") { if (i + 1 < argc) { reportId = (uint8_t)std::stoi(argv[++i], nullptr, 0); } else { std::cerr << "Error: --id requires a report ID argument." << std::endl; return 1; } } else if (arg == "-a" || arg == "--analyze") { analyzeReports = true; } else if (arg == "-p" || arg == "--print-descriptor") { printDescriptor = true; } else { std::cerr << "Error: Unknown argument: " << arg << std::endl; PrintUsage(); return 1; } } // If no arguments provided, show usage if (argc == 1) { PrintUsage(); return 0; } // Create and initialize the HID device analyzer HidDeviceAnalyzer analyzer; if (!analyzer.Initialize()) { std::cerr << "Error: Failed to initialize HID device analyzer." << std::endl; return 1; } // List devices if requested if (listDevices || listValveDevices) { std::vector devices = analyzer.EnumerateHidDevices(listValveDevices ? VALVE_VID : 0); std::cout << std::endl << "Found " << devices.size() << " HID devices:" << std::endl; for (size_t i = 0; i < devices.size(); i++) { std::cout << i + 1 << ". " << devices[i].name << std::endl; std::cout << " Path: " << devices[i].path << std::endl; if (!devices[i].serialNumber.empty()) { std::cout << " Serial: " << devices[i].serialNumber << std::endl; } std::cout << std::endl; } // If we're just listing devices, we're done if (devicePath.empty()) { analyzer.Shutdown(); return 0; } } // Open the specified device if (!devicePath.empty()) { if (!analyzer.OpenDevice(devicePath)) { std::cerr << "Error: Failed to open device: " << devicePath << std::endl; analyzer.Shutdown(); return 1; } // Print the report descriptor if requested if (printDescriptor) { analyzer.PrintReportDescriptor(); } // Read reports if requested if (reportCount > 0) { std::vector reports = analyzer.ReadReports(reportCount, reportId); // Print the reports std::cout << std::endl << "Read " << reports.size() << " reports:" << std::endl; for (size_t i = 0; i < reports.size(); i++) { std::cout << "Report " << i + 1 << ":" << std::endl; analyzer.PrintReport(reports[i]); std::cout << std::endl; } // Analyze the reports if requested if (analyzeReports && !reports.empty()) { std::cout << std::endl << "Report Analysis:" << std::endl; analyzer.AnalyzeReports(reports); } } // Close the device analyzer.CloseDevice(); } // Shutdown the analyzer analyzer.Shutdown(); return 0; } /** * Interactive mode function - not used in the main program but provided as an example * of how to use the HID device analyzer in an interactive way. */ void InteractiveMode() { HidDeviceAnalyzer analyzer; if (!analyzer.Initialize()) { std::cerr << "Error: Failed to initialize HID device analyzer." << std::endl; return; } // List all Valve devices std::vector devices = analyzer.EnumerateHidDevices(VALVE_VID); if (devices.empty()) { std::cout << "No Valve HID devices found." << std::endl; analyzer.Shutdown(); return; } // Print the devices std::cout << "Found " << devices.size() << " Valve HID devices:" << std::endl; for (size_t i = 0; i < devices.size(); i++) { std::cout << i + 1 << ". " << devices[i].name << std::endl; } // Ask the user to select a device std::cout << "Select a device (1-" << devices.size() << "): "; size_t deviceIndex; std::cin >> deviceIndex; if (deviceIndex < 1 || deviceIndex > devices.size()) { std::cout << "Invalid device selection." << std::endl; analyzer.Shutdown(); return; } // Open the selected device if (!analyzer.OpenDevice(devices[deviceIndex - 1].path)) { std::cerr << "Error: Failed to open device." << std::endl; analyzer.Shutdown(); return; } // Print the report descriptor analyzer.PrintReportDescriptor(); // Ask the user for the report ID to read std::cout << "Enter the report ID to read (0-255): "; int reportId; std::cin >> reportId; if (reportId < 0 || reportId > 255) { std::cout << "Invalid report ID." << std::endl; analyzer.CloseDevice(); analyzer.Shutdown(); return; } // Ask the user for the number of reports to read std::cout << "Enter the number of reports to read: "; int reportCount; std::cin >> reportCount; if (reportCount <= 0) { std::cout << "Invalid report count." << std::endl; analyzer.CloseDevice(); analyzer.Shutdown(); return; } // Read the reports std::vector reports = analyzer.ReadReports(reportCount, (uint8_t)reportId); // Print the reports std::cout << "Read " << reports.size() << " reports:" << std::endl; for (size_t i = 0; i < reports.size(); i++) { std::cout << "Report " << i + 1 << ":" << std::endl; analyzer.PrintReport(reports[i]); std::cout << std::endl; } // Analyze the reports if (!reports.empty()) { std::cout << "Report Analysis:" << std::endl; analyzer.AnalyzeReports(reports); } // Close the device analyzer.CloseDevice(); // Shutdown the analyzer analyzer.Shutdown(); }