From 8f1c6f384ff190c09337035ae0ef8f2b724e9d58 Mon Sep 17 00:00:00 2001 From: Philip Kunz Date: Wed, 1 Apr 2026 14:50:32 -0500 Subject: [PATCH 1/3] add HidDevice(path) constructor --- apps/decoder/decoder.cpp | 2 +- include/idf/GenericJoystick.hh | 26 ++++++ include/idf/HidDecoder.hh | 17 ++-- include/idf/HidDevice.hh | 31 ++++++-- include/idf/HidGenericJoystick.hh | 16 +++- include/idf/UsbDevice.hh | 18 ++--- source/idf/GenericJoystick.cpp | 3 + source/idf/HidDecoder.cpp | 6 +- source/idf/HidDevice.cpp | 107 ++++++++++++++++++++++--- source/idf/HidGenericJoystick.cpp | 127 ++++++++++++++++++++++-------- 10 files changed, 278 insertions(+), 75 deletions(-) diff --git a/apps/decoder/decoder.cpp b/apps/decoder/decoder.cpp index d9829bf..782eb8f 100644 --- a/apps/decoder/decoder.cpp +++ b/apps/decoder/decoder.cpp @@ -103,7 +103,7 @@ int main(int argc, char **args) { printHidDescriptor(descriptor); idf::HidDecoder decoder; - idf::HidDecoded devDecoded = *decoder.parseDescriptor(descriptor); + idf::HidDescriptor devDecoded = *decoder.parseDescriptor(descriptor); unsigned char readTest[devDecoded.maxReportLength]; unsigned char data[devDecoded.maxReportLength]; diff --git a/include/idf/GenericJoystick.hh b/include/idf/GenericJoystick.hh index d4362e6..070accc 100644 --- a/include/idf/GenericJoystick.hh +++ b/include/idf/GenericJoystick.hh @@ -40,6 +40,12 @@ public: // left-right pivoting SingleInput leftRightPivot; + // forward-backward Translation + SingleInput forwardBackwardTranslation; + + // left-right transation + SingleInput leftRightTranslation; + // twisting SingleInput twist; @@ -52,6 +58,9 @@ public: // the slider SingleInput slider; + // scroll wheel + SingleInput wheel; + // Hat Directions SingleInput HatNorth; SingleInput HatNorthEast; @@ -62,6 +71,23 @@ public: SingleInput HatWest; SingleInput HatNorthWest; + /** + * @brief Indicates whether an Rx axis exists, which may be used + * for a forwardBackwardTranslation + */ + bool rxExists = false; // TODO: make use of this + + /** + * @brief Indicates whether an Ry axis exists, which may be used + * for a LeftRightTranslation + */ + bool ryExists = false; + + /** + * @brief Indicates whether a Scroll Wheel exists + */ + bool wheelExists = false; + /** * @brief Get the Nth Button object * diff --git a/include/idf/HidDecoder.hh b/include/idf/HidDecoder.hh index 4673a27..caa6844 100644 --- a/include/idf/HidDecoder.hh +++ b/include/idf/HidDecoder.hh @@ -46,8 +46,11 @@ struct HidReport bool has_report_byte; }; -struct HidDecoded +struct HidDescriptor { + unsigned short vendor; + unsigned short product; + unsigned short interface; std::string type; std::vector reports; int maxReportLength; @@ -120,18 +123,18 @@ public: * Report Descriptor. Only @a Input items are kept. @a Output and * @a feature items are discarded * - * @param descriptor binary HID report descriptor. - * @return HidDecoded struct with a list of HidReports and some metadata + * @param descriptor binary HID Report Descriptor. + * @return HidDescriptor struct with a list of HidReports and some metadata */ - HidDecoded* parseDescriptor(const std::vector& descriptor); + HidDescriptor* parseDescriptor(const std::vector& descriptor); /** - * @brief Print out decoded information to stdout + * @brief Print out decoded descriptor information to stdout * - * @param decoded an @a HidDecoded struct + * @param describer an @a HidDescriptor struct */ - static void printDecodedInfo(const HidDecoded decoded); + static void printDecodedInfo(const HidDescriptor describer); /** diff --git a/include/idf/HidDevice.hh b/include/idf/HidDevice.hh index 3055f19..43235da 100644 --- a/include/idf/HidDevice.hh +++ b/include/idf/HidDevice.hh @@ -26,7 +26,7 @@ public: /** * @brief Find the specified device, read and decode its HID Report * Descriptor, then instantiate an HidDevice based on the decoded - * input information + * descriptor information * * @param vendor HID Vendor ID to find the connected device * @param product HID product ID to find the connected device @@ -36,7 +36,16 @@ public: */ HidDevice(const int vendor, const int product, const int interface); - HidDevice(const HidDecoded* decoded_in); + /** + * @brief Open device at @path, read and decode its HID Report + * Descriptor, then instantiate an HidDevice based on the decoded + * descriptor information + * + * @param devPath path to device + */ + HidDevice(const std::string& devPath); + + HidDevice(const HidDescriptor* descriptor); virtual ~HidDevice() {}; @@ -58,20 +67,32 @@ public: * * @param vendor USB Vendor ID * @param product USB Product ID - * @return HIDDecodedDevice struct enumerating the available reports + * @param interface HID interface # (use HidScanner to help find this info) + * @return HidDescriptor struct enumerating the available reports */ - static HidDecoded* decodeDevice(const int vendor, const int product); + static HidDescriptor* decodeDevice(const int vendor, const int product, const int interface); + /** + * @brief open device at @a path, and parse the HID + * report descriptor. This method exists mainly to ease instantiation + * + * @param path path to device + * @return HidDescriptor struct enumerating the available reports + */ + static HidDescriptor* decodeDevice(const std::string& targetPath); protected: HidDecoder decoder; - HidDecoded decoded; + HidDescriptor descriptor; std::vector hidReportDescriptor; virtual std::vector getHidReportDescriptor(); +private: + static std::string resolvePath(const std::string& path); + }; } // namespace idf diff --git a/include/idf/HidGenericJoystick.hh b/include/idf/HidGenericJoystick.hh index c7d8773..8e4ea98 100644 --- a/include/idf/HidGenericJoystick.hh +++ b/include/idf/HidGenericJoystick.hh @@ -2,7 +2,6 @@ PURPOSE: LIBRARY DEPENDENCIES: ( (idf/HidGenericJoystick.cpp) - ) */ @@ -44,9 +43,18 @@ class HidGenericJoystick : public HidDevice, public virtual GenericJoystick { */ HidGenericJoystick(const int vendor, const int product, const int interface); + /** + * @brief Construct a Generic Joystick derived from HID Report Descriptor + * of the given device + * + * @param path path to the device + */ + HidGenericJoystick(const std::string& path); + + void decode(const std::vector& data); - protected: +protected: /** * @brief Flag indicating whether the report descriptor contained a Z axis. If so @@ -57,6 +65,10 @@ class HidGenericJoystick : public HidDevice, public virtual GenericJoystick { */ bool useZForTwist; +private: + + void init(); + }; } // namespace idf diff --git a/include/idf/UsbDevice.hh b/include/idf/UsbDevice.hh index bf9520f..34f284a 100644 --- a/include/idf/UsbDevice.hh +++ b/include/idf/UsbDevice.hh @@ -126,6 +126,15 @@ class UsbDevice : public InputDevice { virtual std::vector > read(); + /** + * returns an absolute path to @a path, resolving '.', '..', and symbolic links + * + * @return the resolved path + */ + std::string resolvePath(const std::string& path) const; + + std::string getDeviceName(const Identification& info); + private: /** number of instances in existance */ @@ -184,15 +193,6 @@ class UsbDevice : public InputDevice { */ UsbDevice* getInstanceAtPath(const std::string& path) const; - /** - * returns an absolute path to @a path, resolving '.', '..', and symbolic links - * - * @return the resolved path - */ - std::string resolvePath(const std::string& path) const; - - std::string getDeviceName(const Identification& info); - void operator=(const UsbDevice&); }; diff --git a/source/idf/GenericJoystick.cpp b/source/idf/GenericJoystick.cpp index a2387de..6681eaf 100644 --- a/source/idf/GenericJoystick.cpp +++ b/source/idf/GenericJoystick.cpp @@ -7,9 +7,12 @@ namespace idf { GenericJoystick::GenericJoystick() : forwardBackwardPivot(0, 1023, 512), leftRightPivot(0, 1023, 512), + forwardBackwardTranslation(0, 1023, 512), + leftRightTranslation(0, 1024, 512), twist(0, 1023, 512), trigger(0,1), slider(0, 1023, 512), + wheel(0, 127, 64), HatNorth(0,1), HatNorthEast(0,1), HatEast(0,1), diff --git a/source/idf/HidDecoder.cpp b/source/idf/HidDecoder.cpp index 7d41748..035cf18 100644 --- a/source/idf/HidDecoder.cpp +++ b/source/idf/HidDecoder.cpp @@ -39,7 +39,7 @@ void HidDecoder::init() } -HidDecoded* HidDecoder::parseDescriptor(const std::vector &descriptor) +HidDescriptor* HidDecoder::parseDescriptor(const std::vector &descriptor) { init(); uint i = 0; @@ -93,7 +93,7 @@ HidDecoded* HidDecoder::parseDescriptor(const std::vector &descri } } - HidDecoded* decoded = new HidDecoded(); + HidDescriptor* decoded = new HidDescriptor(); decoded->type = device_type; decoded->reports = reports; @@ -344,7 +344,7 @@ int HidDecoder::convertDataToInt(const std::vector &data, const b } -void HidDecoder::printDecodedInfo(const HidDecoded decoded) +void HidDecoder::printDecodedInfo(const HidDescriptor decoded) { std::ostringstream ss; ss << "Device Type: " << decoded.type << "\n"; diff --git a/source/idf/HidDevice.cpp b/source/idf/HidDevice.cpp index 5e95a60..98597a8 100644 --- a/source/idf/HidDevice.cpp +++ b/source/idf/HidDevice.cpp @@ -1,6 +1,7 @@ #include "idf/HidDevice.hh" #include "idf/IOException.hh" #include +#include #include #include #include @@ -8,19 +9,24 @@ namespace idf { - HidDevice::HidDevice(const int vendor, const int product, const int interface) : - HidDevice(HidDevice::decodeDevice(vendor, product)) { - addIdentification(Identification(vendor, product, interface)); - } - + HidDevice(HidDevice::decodeDevice(vendor, product, interface)) {} -HidDevice::HidDevice(const HidDecoded* decoded_in) : - UsbDevice("Generic " + decoded_in->type, decoded_in->maxReportLength), - decoded(*decoded_in) {} +HidDevice::HidDevice(const std::string& devPath) : + HidDevice(HidDevice::decodeDevice(devPath)) { + setPath(devPath); + } +HidDevice::HidDevice(const HidDescriptor* descriptor_in) : + UsbDevice("Generic " + descriptor_in->type, descriptor_in->maxReportLength), + descriptor(*descriptor_in) { + std::cout << "[IDF] add device ID: " + << std::hex << descriptor.vendor << ":" << descriptor.product + << ":" << std::dec << descriptor.interface; + addIdentification(Identification(descriptor.vendor, descriptor.product, descriptor.interface)); + } -HidDecoded* HidDevice::decodeDevice(const int vendor, const int product) { +HidDescriptor* HidDevice::decodeDevice(const int vendor, const int product, const int interface) { std::ostringstream ss; hid_device* hidDevice; unsigned char buffer[HID_API_MAX_REPORT_DESCRIPTOR_SIZE]; @@ -42,12 +48,77 @@ HidDecoded* HidDevice::decodeDevice(const int vendor, const int product) { } std::vector descriptor(buffer, buffer + descSize); - HidDecoded* decDevice = decoder.parseDescriptor(descriptor); + HidDescriptor* decDevice = decoder.parseDescriptor(descriptor); + decDevice->vendor = vendor; + decDevice->product = product; + decDevice->interface = interface; hid_close(hidDevice); return decDevice; } +HidDescriptor* HidDevice::decodeDevice(const std::string& targetPath) { + hid_device* hidDevice; + unsigned char buffer[HID_API_MAX_REPORT_DESCRIPTOR_SIZE]; + HidDecoder decoder; + + std::string resolvedPath = resolvePath(targetPath); + std::ostringstream ss; + ss << "Failed to open HID device at " << targetPath; + if (resolvedPath != targetPath) { + ss << " (which resolves to " << resolvedPath << ")"; + } + ss << ": "; + + struct hid_device_info *enumerationHead = hid_enumerate(0, 0); + for (struct hid_device_info *deviceInfo = enumerationHead; deviceInfo; deviceInfo = deviceInfo->next) { + + // if the path matches + if (!strcmp(resolvedPath.c_str(), deviceInfo->path)) { + std::cout << "resolved device at " << resolvedPath << " is a "; + std::wcout << deviceInfo->manufacturer_string << " " + << deviceInfo->product_string << " "; + + std::cout << std::hex << std::setw(4) << std::setfill('0') << deviceInfo->vendor_id << ":" << deviceInfo->product_id + << std::endl; + + // TODO: check that the device isn't already open + + // Open device to read Report Descriptor + if (!(hidDevice = hid_open_path(resolvedPath.c_str()))) { + ss << strerror(errno) << ". See the https://github.com/nasa/IDF/wiki for troubleshooting."; + throw IOException(ss.str()); + } + + // decode the RD + int descSize = hid_get_report_descriptor(hidDevice, buffer, sizeof(buffer)); + + if (descSize < 0) { + ss << "unable to get HID report descriptor from " + << targetPath << strerror(errno) << std::endl; + hid_close(hidDevice); + throw IOException(ss.str()); + } + + std::vector descriptor(buffer, buffer + descSize); + HidDescriptor* decDevice = decoder.parseDescriptor(descriptor); + decDevice->vendor = deviceInfo->vendor_id; + decDevice->product = deviceInfo->product_id; + decDevice->interface = deviceInfo->interface_number; + + // release the enumeration + hid_free_enumeration(enumerationHead); + + hid_close(hidDevice); + return decDevice; + } + } + + // path not found + hid_free_enumeration(enumerationHead); + ss << "There is no device at this path."; + throw IOException(ss.str()); +} std::vector HidDevice::getHidReportDescriptor() { unsigned char buffer[HID_API_MAX_REPORT_DESCRIPTOR_SIZE]; @@ -63,7 +134,6 @@ std::vector HidDevice::getHidReportDescriptor() { return report; } - void HidDevice::printHidDescriptor() { std::vector report = getHidReportDescriptor(); @@ -75,9 +145,20 @@ void HidDevice::printHidDescriptor() { } } - void HidDevice::printDecodedHidInfo() { - decoder.printDecodedInfo(decoded); + decoder.printDecodedInfo(descriptor); +} + +std::string HidDevice::resolvePath(const std::string& unresolvedPath) { + #ifdef __APPLE__ + return unresolvedPath; + #else + char resolvedPath[PATH_MAX]; + if (!realpath(unresolvedPath.c_str(), resolvedPath)) { + throw IOException("Failed to resolve " + unresolvedPath + ": " + strerror(errno)); + } + return resolvedPath; + #endif } } //namespace idf diff --git a/source/idf/HidGenericJoystick.cpp b/source/idf/HidGenericJoystick.cpp index 35474d5..16cddcb 100644 --- a/source/idf/HidGenericJoystick.cpp +++ b/source/idf/HidGenericJoystick.cpp @@ -2,47 +2,89 @@ namespace idf { - HidGenericJoystick::HidGenericJoystick(const int vendor, const int product, const int interface) : - HidDevice(vendor, product, interface) { - // configure inputs and instantiate list of buttons - for( HidReport report : decoded.reports) { - for (HidInput input : report.inputs) { - switch(input.usage) { - case USAGE_BUTTON: - if (input.button_num == 1) - buttons.push_back(&trigger); - else - buttons.push_back(new SingleInput(0,1)); - break; + HidDevice(vendor, product, interface) + { + init(); + } - case USAGE_X: - // legacy dictates that X is a pivot even though it is a liner axis - leftRightPivot.configure(input.logical_min, input.logical_max); - break; +HidGenericJoystick::HidGenericJoystick(const std::string& devPath) : + HidDevice(devPath) + { + init(); + } - case USAGE_Y: - // legacy dictates that Y is a pivot even though it is a liner axis - forwardBackwardPivot.configure(input.logical_min, input.logical_max); - break; +/** + * @brief Initialize the joystick based on the decoded HID Report Descriptor + */ +void HidGenericJoystick::init() +{ + for( HidReport report : descriptor.reports) { + for (HidInput input : report.inputs) { + switch(input.usage) { + case USAGE_BUTTON: + if (input.button_num == 1) + { + buttons.push_back(&trigger); + } + else + { + buttons.push_back(new SingleInput(0,1)); + } + break; - case USAGE_Z: - // Up to the manufacturer whether twist is Z or RZ, but the - // norm seems to be that if Z exists it is the twist axis - useZForTwist = true; - twist.configure(input.logical_min, input.logical_max); - break; - } + case USAGE_X: + // legacy dictates that X is a pivot even though it is a liner axis + leftRightPivot.configure(input.logical_min, input.logical_max); + break; + + case USAGE_Y: + // legacy dictates that Y is a pivot even though it is a liner axis + forwardBackwardPivot.configure(input.logical_min, input.logical_max); + break; + + case USAGE_Z: + // Up to the manufacturer whether twist is Z or RZ, but the + // norm seems to be that if Z exists it is the twist axis + useZForTwist = true; + twist.configure(input.logical_min, input.logical_max); + break; + + case USAGE_RX: + rxExists = true; + leftRightTranslation.configure(input.logical_min, input.logical_max); + break; + + case USAGE_RY: + ryExists = true; + forwardBackwardTranslation.configure(input.logical_min, input.logical_max); + break; + + case USAGE_WHEEL: + wheelExists = true; + wheel.configure(input.logical_min, input.logical_max); + break; + + default: + break; } } } +} - -void HidGenericJoystick::decode(const std::vector& data) { - for (HidReport r : decoded.reports) { +/** + * @brief decode data that was read from device using the decoded Report Descriptor + * + * @param data HID Report data read from device + */ +void HidGenericJoystick::decode(const std::vector& data) +{ + for (HidReport r : descriptor.reports) { if (!r.has_report_byte || (r.has_report_byte && static_cast(data[0]) == r.id)) { - for( HidInput input : r.inputs) { + for(HidInput input : r.inputs) { + u_int64_t value = decoder.extractValue(input, data); + switch (input.usage) { case USAGE_BUTTON: try { @@ -63,6 +105,14 @@ void HidGenericJoystick::decode(const std::vector& data) { twist.setValue(value); break; + case USAGE_RX: + leftRightTranslation.setValue(value); + break; + + case USAGE_RY: + forwardBackwardTranslation.setValue(value); + break; + case USAGE_RZ: if (!useZForTwist) twist.setValue(value); break; @@ -71,6 +121,10 @@ void HidGenericJoystick::decode(const std::vector& data) { slider.setValue(value); break; + case USAGE_WHEEL: + wheel.setValue(value); + break; + case USAGE_HAT: int hat = value - input.logical_min; HatNorth.setValue(hat == 0); @@ -82,10 +136,13 @@ void HidGenericJoystick::decode(const std::vector& data) { HatWest.setValue(hat == 6); HatNorthWest.setValue(hat == 7); break; - } - } - } - } + + default: + break; + } // switch + } // for input + } // if correct report + } // for report } } // namespace idf From 3a0f945d8df22d85a40cc3a11a5e7fecb977203a Mon Sep 17 00:00:00 2001 From: Philip Kunz Date: Wed, 1 Apr 2026 15:58:04 -0500 Subject: [PATCH 2/3] remove unused variables --- include/idf/HidDecoder.hh | 3 --- source/idf/HidDecoder.cpp | 14 +++++++------- source/idf/HidGenericJoystick.cpp | 4 ---- 3 files changed, 7 insertions(+), 14 deletions(-) diff --git a/include/idf/HidDecoder.hh b/include/idf/HidDecoder.hh index caa6844..e435515 100644 --- a/include/idf/HidDecoder.hh +++ b/include/idf/HidDecoder.hh @@ -172,9 +172,6 @@ private: int units_exp; }; - int vendorId; - int productId; - std::string device_type = "Unknown"; std::vector reports; std::vector inputs; diff --git a/source/idf/HidDecoder.cpp b/source/idf/HidDecoder.cpp index 035cf18..6db5e48 100644 --- a/source/idf/HidDecoder.cpp +++ b/source/idf/HidDecoder.cpp @@ -347,18 +347,18 @@ int HidDecoder::convertDataToInt(const std::vector &data, const b void HidDecoder::printDecodedInfo(const HidDescriptor decoded) { std::ostringstream ss; - ss << "Device Type: " << decoded.type << "\n"; + ss << "Device Type: " << decoded.type << std::endl; for (HidReport report : decoded.reports) { - ss << "Report: " << report.id << " (" << report.bytes_count << " bytes)\n"; + ss << "Report: " << report.id << " (" << report.bytes_count << " bytes)" << std::endl; if (report.id != 0) { - ss << " Report ID bits 0:7 value: " << report.id << "\n"; + ss << " Report ID bits 0:7 value: " << report.id << std::endl; } for(HidInput input : report.inputs) { ss << " " << std::setfill(' ') << std::setw(15) << std::left << input.name; if (input.start_bit == input.end_bit) { ss << " bit " << std::setw(5) << std::right << input.start_bit << " range: "; ss << std::setw(5) << std::right << input.logical_min << ":"; - ss << std::left << input.logical_max << "\n"; + ss << std::left << input.logical_max << std::endl; } else { ss << " bits " << std::setw(5) << std::right << input.start_bit << ":"; @@ -367,12 +367,12 @@ void HidDecoder::printDecodedInfo(const HidDescriptor decoded) ss << std::setw(5) << std::right << input.logical_min << ":"; ss << std::setw(5) << std::left << input.logical_max << " "; ss << std::setw(5) << std::right << input.physical_min << ":"; - ss << std::setw(5) << std::left << input.physical_max << "\n"; + ss << std::setw(5) << std::left << input.physical_max << std::endl; } } - ss << "\n"; + ss << std::endl; } - printf(ss.str().c_str()); + std::cout << ss.str(); } diff --git a/source/idf/HidGenericJoystick.cpp b/source/idf/HidGenericJoystick.cpp index 16cddcb..adf594b 100644 --- a/source/idf/HidGenericJoystick.cpp +++ b/source/idf/HidGenericJoystick.cpp @@ -65,8 +65,6 @@ void HidGenericJoystick::init() wheel.configure(input.logical_min, input.logical_max); break; - default: - break; } } } @@ -137,8 +135,6 @@ void HidGenericJoystick::decode(const std::vector& data) HatNorthWest.setValue(hat == 7); break; - default: - break; } // switch } // for input } // if correct report From 8520ccc4babbc7a61033efe0bca53a2c9dce2f8f Mon Sep 17 00:00:00 2001 From: Philip Kunz Date: Thu, 2 Apr 2026 12:50:49 -0500 Subject: [PATCH 3/3] read vendor and product IDs when getting report descriptor --- include/idf/HidDecoder.hh | 2 ++ include/idf/HidDevice.hh | 2 ++ source/idf/HidDevice.cpp | 63 +++++++++++++++++++++++++++++++-------- 3 files changed, 55 insertions(+), 12 deletions(-) diff --git a/include/idf/HidDecoder.hh b/include/idf/HidDecoder.hh index e435515..1cd8c52 100644 --- a/include/idf/HidDecoder.hh +++ b/include/idf/HidDecoder.hh @@ -51,6 +51,8 @@ struct HidDescriptor unsigned short vendor; unsigned short product; unsigned short interface; + std::wstring vendor_string; + std::wstring product_string; std::string type; std::vector reports; int maxReportLength; diff --git a/include/idf/HidDevice.hh b/include/idf/HidDevice.hh index 43235da..7b45b00 100644 --- a/include/idf/HidDevice.hh +++ b/include/idf/HidDevice.hh @@ -82,6 +82,7 @@ public: static HidDescriptor* decodeDevice(const std::string& targetPath); protected: + HidDecoder decoder; HidDescriptor descriptor; @@ -91,6 +92,7 @@ protected: virtual std::vector getHidReportDescriptor(); private: + static std::string resolvePath(const std::string& path); }; diff --git a/source/idf/HidDevice.cpp b/source/idf/HidDevice.cpp index 98597a8..bce408c 100644 --- a/source/idf/HidDevice.cpp +++ b/source/idf/HidDevice.cpp @@ -10,23 +10,27 @@ namespace idf { HidDevice::HidDevice(const int vendor, const int product, const int interface) : - HidDevice(HidDevice::decodeDevice(vendor, product, interface)) {} + HidDevice(HidDevice::decodeDevice(vendor, product, interface)) + {} HidDevice::HidDevice(const std::string& devPath) : - HidDevice(HidDevice::decodeDevice(devPath)) { + HidDevice(HidDevice::decodeDevice(devPath)) + { setPath(devPath); } HidDevice::HidDevice(const HidDescriptor* descriptor_in) : UsbDevice("Generic " + descriptor_in->type, descriptor_in->maxReportLength), - descriptor(*descriptor_in) { - std::cout << "[IDF] add device ID: " - << std::hex << descriptor.vendor << ":" << descriptor.product - << ":" << std::dec << descriptor.interface; + descriptor(*descriptor_in) + { + std::wcout << "Added device to IDF: " << descriptor.vendor_string << " " << descriptor.product_string + << " (" << std::hex << descriptor.vendor << ":" << descriptor.product + << ":" << std::dec << descriptor.interface << ")" << std::endl; addIdentification(Identification(descriptor.vendor, descriptor.product, descriptor.interface)); } -HidDescriptor* HidDevice::decodeDevice(const int vendor, const int product, const int interface) { +HidDescriptor* HidDevice::decodeDevice(const int vendor, const int product, const int interface) +{ std::ostringstream ss; hid_device* hidDevice; unsigned char buffer[HID_API_MAX_REPORT_DESCRIPTOR_SIZE]; @@ -47,17 +51,34 @@ HidDescriptor* HidDevice::decodeDevice(const int vendor, const int product, cons throw IOException(ss.str()); } + wchar_t vendStr[255]; + wchar_t prodStr[255]; + if (hid_get_manufacturer_string(hidDevice, vendStr, 255) != 0) { + ss << "unable to read manufacturer string from device: " << strerror(errno) << hid_error(hidDevice) << std::endl; + throw IOException(ss.str()); + } + + if (hid_get_product_string(hidDevice, prodStr, 255) != 0) { + ss << "unable to read manufacturer string from device: " << strerror(errno) << hid_error(hidDevice) << std::endl; + throw IOException(ss.str()); + } + + std::wcout << "device = " << vendStr << " " << prodStr << std::endl; + std::vector descriptor(buffer, buffer + descSize); HidDescriptor* decDevice = decoder.parseDescriptor(descriptor); decDevice->vendor = vendor; decDevice->product = product; decDevice->interface = interface; + decDevice->vendor_string = vendStr; + decDevice->product_string = prodStr; hid_close(hidDevice); return decDevice; } -HidDescriptor* HidDevice::decodeDevice(const std::string& targetPath) { +HidDescriptor* HidDevice::decodeDevice(const std::string& targetPath) +{ hid_device* hidDevice; unsigned char buffer[HID_API_MAX_REPORT_DESCRIPTOR_SIZE]; HidDecoder decoder; @@ -100,11 +121,25 @@ HidDescriptor* HidDevice::decodeDevice(const std::string& targetPath) { throw IOException(ss.str()); } + wchar_t vendStr[255]; + wchar_t prodStr[255]; + if (hid_get_manufacturer_string(hidDevice, vendStr, 255) != 0) { + ss << "unable to read manufacturer string from device: " << strerror(errno) << hid_error(hidDevice) << std::endl; + throw IOException(ss.str()); + } + + if (hid_get_product_string(hidDevice, prodStr, 255) != 0) { + ss << "unable to read manufacturer string from device: " << strerror(errno) << hid_error(hidDevice) << std::endl; + throw IOException(ss.str()); + } + std::vector descriptor(buffer, buffer + descSize); HidDescriptor* decDevice = decoder.parseDescriptor(descriptor); decDevice->vendor = deviceInfo->vendor_id; decDevice->product = deviceInfo->product_id; decDevice->interface = deviceInfo->interface_number; + decDevice->vendor_string = vendStr; + decDevice->product_string = prodStr; // release the enumeration hid_free_enumeration(enumerationHead); @@ -120,7 +155,8 @@ HidDescriptor* HidDevice::decodeDevice(const std::string& targetPath) { throw IOException(ss.str()); } -std::vector HidDevice::getHidReportDescriptor() { +std::vector HidDevice::getHidReportDescriptor() +{ unsigned char buffer[HID_API_MAX_REPORT_DESCRIPTOR_SIZE]; int size = hid_get_report_descriptor(hidDevice, buffer, sizeof(buffer)); @@ -134,7 +170,8 @@ std::vector HidDevice::getHidReportDescriptor() { return report; } -void HidDevice::printHidDescriptor() { +void HidDevice::printHidDescriptor() +{ std::vector report = getHidReportDescriptor(); printf("\nHID Report Descriptor (%lu bytes):\n ", report.size()); @@ -145,11 +182,13 @@ void HidDevice::printHidDescriptor() { } } -void HidDevice::printDecodedHidInfo() { +void HidDevice::printDecodedHidInfo() +{ decoder.printDecodedInfo(descriptor); } -std::string HidDevice::resolvePath(const std::string& unresolvedPath) { +std::string HidDevice::resolvePath(const std::string& unresolvedPath) +{ #ifdef __APPLE__ return unresolvedPath; #else