From 76237c0a35823d4afaf6d29a86b02678175730dd Mon Sep 17 00:00:00 2001 From: Werner Sembach Date: Mon, 2 Jun 2025 16:38:31 +0200 Subject: [PATCH] Dynamically parse report IDs --- .../HIDLampArrayController.cpp | 79 ++++++++++++- Controllers/HIDLampArrayController/hid_util.h | 107 ++++++++++++++++++ 2 files changed, 180 insertions(+), 6 deletions(-) create mode 100644 Controllers/HIDLampArrayController/hid_util.h diff --git a/Controllers/HIDLampArrayController/HIDLampArrayController.cpp b/Controllers/HIDLampArrayController/HIDLampArrayController.cpp index 9b9b30113..6931e9c77 100644 --- a/Controllers/HIDLampArrayController/HIDLampArrayController.cpp +++ b/Controllers/HIDLampArrayController/HIDLampArrayController.cpp @@ -9,7 +9,9 @@ | SPDX-License-Identifier: GPL-2.0-only | \*---------------------------------------------------------*/ +#include #include +#include "hid_util.h" #include "HIDLampArrayController.h" HIDLampArrayController::HIDLampArrayController(hid_device *dev_handle, const char *path, std::string dev_name) @@ -19,13 +21,78 @@ HIDLampArrayController::HIDLampArrayController(hid_device *dev_handle, const cha name = dev_name; /*-----------------------------------------------------*\ - | Get LampArrayAttributesReport | + | Parse report IDs from descriptor | \*-----------------------------------------------------*/ - ids.LampArrayAttributesReportID = 0x01; - ids.LampAttributesRequestReportID = 0x02; - ids.LampAttributesResponseReportID = 0x03; - ids.LampMultiUpdateReportID = 0x04; - ids.LampArrayControlReportID = 0x06; + unsigned char data_len = 0; + unsigned char key = 0; + unsigned char key_cmd = 0; + unsigned char key_size = 0; + unsigned int pos = 0; + unsigned char report_descriptor[HID_API_MAX_REPORT_DESCRIPTOR_SIZE]; + unsigned char report_id = 0; + unsigned int size = hid_get_report_descriptor(dev, report_descriptor, sizeof(report_descriptor)); + unsigned int usage = 0; + unsigned char usage_page = 0; + + while(pos < size) + { + get_hid_item_size(report_descriptor, size, pos, &data_len, &key_size); + + key = report_descriptor[pos]; + key_cmd = key & 0xFC; + + switch(key_cmd) + { + case 0x4: + usage_page = get_hid_report_bytes(report_descriptor, size, data_len, pos); + break; + + case 0x8: + usage = get_hid_report_bytes(report_descriptor, size, data_len, pos); + + if(data_len == 4) + { + usage_page = usage >> 16; + usage &= 0x0000FFFF; + } + if(usage_page == 0x59 && report_id) + { + switch(usage) + { + case 0x02: + ids.LampArrayAttributesReportID = report_id; + break; + + case 0x20: + ids.LampAttributesRequestReportID = report_id; + break; + + case 0x22: + ids.LampAttributesResponseReportID = report_id; + break; + + case 0x50: + ids.LampMultiUpdateReportID = report_id; + break; + + case 0x60: + ids.LampRangeUpdateReportID = report_id; + break; + + case 0x70: + ids.LampArrayControlReportID = report_id; + break; + } + report_id = 0; + } + break; + + case 0x84: + report_id = get_hid_report_bytes(report_descriptor, size, data_len, pos); + break; + } + pos += data_len + key_size; + } /*-----------------------------------------------------*\ | Get LampArrayAttributesReport | diff --git a/Controllers/HIDLampArrayController/hid_util.h b/Controllers/HIDLampArrayController/hid_util.h new file mode 100644 index 000000000..784a792bc --- /dev/null +++ b/Controllers/HIDLampArrayController/hid_util.h @@ -0,0 +1,107 @@ +/******************************************************* + Utility functions taken from: + + HIDAPI - Multi-Platform library for + communication with HID devices. + + Alan Ott + Signal 11 Software + + libusb/hidapi Team + + Copyright 2022, All Rights Reserved. + + At the discretion of the user of this library, + this software may be licensed under the terms of the + GNU General Public License v3, a BSD-Style license, or the + original HIDAPI license as outlined in the LICENSE.txt, + LICENSE-gpl3.txt, LICENSE-bsd.txt, and LICENSE-orig.txt + files located at the root of the source distribution. + These files may also be found in the public source + code repository located at: + https://github.com/libusb/hidapi . +********************************************************/ + +/* + * Gets the size of the HID item at the given position + * Returns 1 if successful, 0 if an invalid key + * Sets data_len and key_size when successful + */ +static int get_hid_item_size(const unsigned char *report_descriptor, unsigned size, unsigned pos, unsigned char *data_len, unsigned char *key_size) +{ + int key = report_descriptor[pos]; + int size_code; + + /* + * This is a Long Item. The next byte contains the + * length of the data section (value) for this key. + * See the HID specification, version 1.11, section + * 6.2.2.3, titled "Long Items." + */ + if ((key & 0xf0) == 0xf0) { + if (pos + 1 < size) + { + *data_len = report_descriptor[pos + 1]; + *key_size = 3; + return 1; + } + *data_len = 0; /* malformed report */ + *key_size = 0; + } + + /* + * This is a Short Item. The bottom two bits of the + * key contain the size code for the data section + * (value) for this key. Refer to the HID + * specification, version 1.11, section 6.2.2.2, + * titled "Short Items." + */ + size_code = key & 0x3; + switch (size_code) { + case 0: + case 1: + case 2: + *data_len = size_code; + *key_size = 1; + return 1; + case 3: + *data_len = 4; + *key_size = 1; + return 1; + default: + /* Can't ever happen since size_code is & 0x3 */ + *data_len = 0; + *key_size = 0; + break; + }; + + /* malformed report */ + return 0; +} + +/* + * Get bytes from a HID Report Descriptor. + * Only call with a num_bytes of 0, 1, 2, or 4. + */ +static unsigned get_hid_report_bytes(unsigned char *rpt, size_t len, size_t num_bytes, size_t cur) +{ + /* Return if there aren't enough bytes. */ + if (cur + num_bytes >= len) + return 0; + + if (num_bytes == 0) + return 0; + else if (num_bytes == 1) + return rpt[cur + 1]; + else if (num_bytes == 2) + return (rpt[cur + 2] * 256 + rpt[cur + 1]); + else if (num_bytes == 4) + return ( + rpt[cur + 4] * 0x01000000 + + rpt[cur + 3] * 0x00010000 + + rpt[cur + 2] * 0x00000100 + + rpt[cur + 1] * 0x00000001 + ); + else + return 0; +}