Skip to content

Commit 0ea682f

Browse files
authored
Merge pull request #18 from jfedor2/descriptor-parser-improvements
Improve report descriptor parsing
2 parents 561d2a3 + 3943af1 commit 0ea682f

File tree

3 files changed

+79
-195
lines changed

3 files changed

+79
-195
lines changed

src/gfx_main.c

Lines changed: 5 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -303,15 +303,13 @@ static void new_theme_init_and_set(void)
303303
void gfx_set_byte_offsets_text(void)
304304
{
305305
char text[100];
306-
hid_data_location_t * button = xlat_get_button_location();
307-
hid_data_location_t * x = xlat_get_x_location();
308-
hid_data_location_t * y = xlat_get_y_location();
306+
uint16_t button_bits = xlat_get_button_bits();
307+
uint16_t motion_bits = xlat_get_motion_bits();
309308

310-
if (button->found && x->found && y->found) {
311-
sprintf(text, "Data: click@%d motion@%d,%d", button->byte_offset, x->byte_offset, y->byte_offset);
309+
if (button_bits || motion_bits) {
310+
sprintf(text, "Data (%u): %u button, %u motion bits", xlat_get_report_id(), button_bits, motion_bits);
312311
} else {
313-
// offsets not found
314-
sprintf(text, "Data: offsets not found");
312+
sprintf(text, "Data: locations not found");
315313
}
316314

317315
lv_checkbox_set_text(hid_offsets_label, text);

src/xlat.c

Lines changed: 71 additions & 174 deletions
Original file line numberDiff line numberDiff line change
@@ -45,7 +45,6 @@ static volatile uint_fast8_t gpio_irq_consumer = 0;
4545
// SETTINGS
4646
volatile bool xlat_initialized = false;
4747
static xlat_mode_t xlat_mode = XLAT_MODE_CLICK;
48-
static bool hid_using_reportid = false;
4948
static bool auto_trigger_level_high = false;
5049

5150
// The Razer optical switches will constantly trigger the GPIO interrupt, while pressed
@@ -66,9 +65,13 @@ static TimerHandle_t xlat_timer_handle;
6665
///////////////////////
6766

6867
// Locations of the clicks and X Y motion bytes in the HID report
69-
hid_data_location_t button_location;
70-
hid_data_location_t x_location;
71-
hid_data_location_t y_location;
68+
#define REPORT_LEN 64
69+
uint8_t prev_report[REPORT_LEN];
70+
uint8_t button_mask[REPORT_LEN];
71+
uint8_t motion_mask[REPORT_LEN];
72+
uint16_t button_bits;
73+
uint16_t motion_bits;
74+
uint8_t report_id;
7275

7376
static inline void hidreport_print_item(HID_ReportItem_t *item)
7477
{
@@ -157,39 +160,39 @@ static inline void hidreport_print_item(HID_ReportItem_t *item)
157160

158161
static void hidreport_check_item(HID_ReportItem_t *item)
159162
{
160-
switch (item->Attributes.Usage.Page) {
161-
case 0x01:
162-
switch (item->Attributes.Usage.Usage) {
163-
case 0x30:
164-
printf(" Usage.Usage: X (0x0030)\n");
165-
if (!x_location.found) {
166-
x_location.found = true;
167-
x_location.bit_index = item->BitOffset;
168-
x_location.bit_size = item->Attributes.BitSize;
169-
}
170-
break;
163+
if (item->ItemType != HID_REPORT_ITEM_In) {
164+
return;
165+
}
171166

172-
case 0x31:
173-
printf(" Usage.Usage: Y (0x0031)\n");
174-
if (!y_location.found) {
175-
y_location.found = true;
176-
y_location.bit_index = item->BitOffset;
177-
y_location.bit_size = item->Attributes.BitSize;
178-
}
179-
break;
180-
}
181-
break;
167+
uint8_t* mask = NULL;
168+
uint16_t* bits = NULL;
182169

183-
case 0x09:
184-
printf(" Usage.Page: Button (0x0009)\n");
185-
if (!button_location.found) {
186-
button_location.found = true;
187-
button_location.bit_index = item->BitOffset;
188-
}
189-
break;
170+
if (item->Attributes.Usage.Page == 0x0009) {
171+
mask = button_mask;
172+
bits = &button_bits;
173+
}
174+
if ((item->Attributes.Usage.Page == 0x0001) &&
175+
((item->Attributes.Usage.Usage == 0x0030) || (item->Attributes.Usage.Usage == 0x0031))) {
176+
mask = motion_mask;
177+
bits = &motion_bits;
178+
}
190179

191-
default:
192-
break;
180+
if (mask != NULL) {
181+
if (report_id == 0) {
182+
report_id = item->ReportID;
183+
}
184+
if (report_id != item->ReportID) {
185+
return;
186+
}
187+
for (uint8_t i = 0; i < item->Attributes.BitSize; i++) {
188+
int byte_no = (item->BitOffset + i) / 8;
189+
int bit_no = (item->BitOffset + i) % 8;
190+
byte_no += (report_id ? 1 : 0);
191+
if (byte_no < sizeof(button_mask)) {
192+
mask[byte_no] |= (1 << bit_no);
193+
(*bits)++;
194+
}
195+
}
193196
}
194197
}
195198

@@ -253,68 +256,6 @@ static int calculate_gpio_to_usb_time(void)
253256
}
254257

255258

256-
static void check_offsets(void)
257-
{
258-
printf("\n");
259-
260-
if (hid_using_reportid) {
261-
printf("[*] Using reportId, so actual report data is starting at index [1]\n");
262-
}
263-
264-
if (button_location.found) {
265-
if (button_location.bit_index % 8) {
266-
printf("[!] Button found at bit index %d, which is not a multiple of 8. Currently not supported by XLAT.\n", button_location.bit_index);
267-
button_location.found = false;
268-
} else {
269-
button_location.byte_offset = button_location.bit_index / 8 + (size_t)hid_using_reportid;
270-
printf("[*] Button found at bit index %d, which is byte %d\n", button_location.bit_index, button_location.bit_index / 8);
271-
printf(" Button byte offset: %d\n", button_location.byte_offset);
272-
}
273-
} else {
274-
button_location.found = false;
275-
printf("[x] Button not found\n");
276-
}
277-
278-
// X offset has to start at a byte boundary
279-
if (x_location.found) {
280-
if (x_location.bit_index % 8) {
281-
printf("[!] X found at bit index %d, which is not a multiple of 8. Currently not supported by XLAT.\n", x_location.bit_index);
282-
x_location.found = false;
283-
} else {
284-
x_location.byte_offset = x_location.bit_index / 8 + (size_t)hid_using_reportid;
285-
printf("[*] X found at bit index %d, which is byte %d\n", x_location.bit_index, x_location.bit_index / 8);
286-
printf(" X size: %d bits, %d bytes\n", x_location.bit_size, x_location.bit_size / 8);
287-
printf(" X byte offset: %d\n", x_location.byte_offset);
288-
}
289-
} else {
290-
x_location.found = false;
291-
printf("[x] X not found\n");
292-
}
293-
294-
// Y offset does NOT have to start at a byte boundary,
295-
// but it has to be contiguous to X
296-
// and their total size has to be a multiple of 8
297-
if (y_location.found) {
298-
if ((y_location.bit_index % 8) &&
299-
((y_location.bit_index - x_location.bit_index) != x_location.bit_size)) {
300-
printf("[!] Y found at bit index %d, which is not a multiple of 8, and not contiguous to X. Currently not supported by XLAT.\n",
301-
y_location.bit_index);
302-
y_location.found = false;
303-
} else {
304-
y_location.byte_offset = y_location.bit_index / 8 + (size_t)hid_using_reportid;
305-
printf("[*] Y found at bit index %d, which is byte %d\n", y_location.bit_index, y_location.bit_index / 8);
306-
printf(" Y size: %d bits, %d bytes\n", y_location.bit_size, y_location.bit_size / 8);
307-
printf(" Y byte offset: %d\n", y_location.byte_offset);
308-
}
309-
} else {
310-
y_location.found = false;
311-
printf("[x] Y not found\n");
312-
}
313-
314-
printf("\n");
315-
}
316-
317-
318259
//////////////////////
319260
// PUBLIC FUNCTIONS //
320261
//////////////////////
@@ -352,11 +293,10 @@ void xlat_usb_hid_event(void)
352293

353294
if (USBH_HID_GetDeviceType(phost) == HID_MOUSE)
354295
{ // if the HID is Mouse
355-
uint8_t hid_raw_data[64];
296+
uint8_t hid_raw_data[REPORT_LEN];
356297

357298
if (USBH_HID_GetRawData(phost, hid_raw_data) == USBH_OK) {
358-
// check reportId for ULX
359-
if (hid_using_reportid && (hid_raw_data[0] != 0x01)) {
299+
if ((report_id != 0) && (hid_raw_data[0] != report_id)) {
360300
// ignore
361301
goto out;
362302
}
@@ -368,68 +308,24 @@ void xlat_usb_hid_event(void)
368308
printf("\n");
369309
#endif
370310
if (xlat_mode == XLAT_MODE_CLICK) {
371-
// FOR BUTTONS/CLICKS:
372-
// The correct location of button data is determined by parsing the HID descriptor
373-
// This information is available in the button_location struct
374-
375-
// First, check if the location was found
376-
if (!button_location.found) {
377-
return;
378-
}
379-
380-
static uint8_t prev_button = 0;
381-
uint8_t button = hid_raw_data[button_location.byte_offset];
382-
383-
// Check if the button state has changed
384-
if (button != prev_button) {
385-
// Only measure on button PRESS, not on RELEASE
386-
if (button > prev_button) {
387-
// Save the captured USB event timestamp
311+
for (uint8_t i = (report_id ? 1 : 0); i < REPORT_LEN; i++) {
312+
if (((hid_raw_data[i] ^ prev_report[i]) & hid_raw_data[i] & button_mask[i])) {
388313
last_usb_timestamp_us = hevt->timestamp;
389-
390-
printf("[%5lu] hid@%lu: ", xTaskGetTickCount(), hevt->timestamp);
391-
printf("Button: B=0x%02x @ %lu\n", button, hevt->timestamp);
392-
393314
calculate_gpio_to_usb_time();
315+
break;
394316
}
395317
}
396-
397-
// Save previous state
398-
prev_button = button;
399318
}
400319
else if (xlat_mode == XLAT_MODE_MOTION) {
401-
// FOR MOTION:
402-
// The correct location of button data is determined by parsing the HID descriptor
403-
// This information is available in the [x|y]_location structs
404-
405-
// First, check if the locations were found
406-
if ((!x_location.found) || (!y_location.found)) {
407-
return;
408-
}
409-
410-
// Check X and Y data is contiguous
411-
if ((x_location.byte_offset + x_location.bit_size / 8) != y_location.byte_offset) {
412-
return;
413-
}
414-
415-
size_t start_idx = x_location.byte_offset;
416-
size_t length = (x_location.bit_size + y_location.bit_size) / 8;
417-
418-
// Loop over the data and check for non-zero values
419-
// In case there is non-zero data, call calculate_gpio_to_usb_tine();
420-
for (size_t idx = start_idx; idx < start_idx + length; idx++) {
421-
if (hid_raw_data[idx]) {
422-
// Save the captured USB event timestamp
320+
for (uint8_t i = (report_id ? 1 : 0); i < REPORT_LEN; i++) {
321+
if (hid_raw_data[i] & motion_mask[i]) {
423322
last_usb_timestamp_us = hevt->timestamp;
424-
425-
printf("[%5lu] hid@%lu: ", xTaskGetTickCount(), hevt->timestamp);
426-
printf("Motion: X=0x%02x, Y=0x%02x @ %lu\n", hid_raw_data[x_location.byte_offset], hid_raw_data[y_location.byte_offset], hevt->timestamp);
427-
428323
calculate_gpio_to_usb_time();
429-
break; // stop at the first bit of motion in this report
324+
break;
430325
}
431326
}
432327
}
328+
memcpy(prev_report, hid_raw_data, sizeof(prev_report));
433329
}
434330
}
435331

@@ -569,16 +465,6 @@ void xlat_reset_latency(void)
569465
}
570466
}
571467

572-
void xlat_set_using_reportid(bool use_reportid)
573-
{
574-
hid_using_reportid = use_reportid;
575-
}
576-
577-
bool xlat_get_using_reportid(void)
578-
{
579-
return hid_using_reportid;
580-
}
581-
582468
static void xlat_timer_callback(TimerHandle_t xTimer)
583469
{
584470
// re-enable GPIO interrupts
@@ -651,12 +537,19 @@ void xlat_parse_hid_descriptor(uint8_t *desc, size_t desc_size)
651537
return;
652538
}
653539

654-
// Check if using reportIDs:
655-
hid_using_reportid = report_info.UsingReportIDs;
656-
printf("Using reportIDs: %d\n", hid_using_reportid);
540+
printf("Button mask: ");
541+
for (int i = 0; i < REPORT_LEN; i++) {
542+
printf("%02x", button_mask[i]);
543+
}
544+
printf("\n");
545+
printf("Motion mask: ");
546+
for (int i = 0; i < REPORT_LEN; i++) {
547+
printf("%02x", motion_mask[i]);
548+
}
549+
printf("\n");
657550

658-
// Find click and motion data offsets
659-
check_offsets();
551+
// Check if using reportIDs:
552+
printf("Using report ID: %d\n", report_id);
660553

661554
// Send a message to the gfx thread, to refresh the device info
662555
struct gfx_event *evt;
@@ -666,33 +559,37 @@ void xlat_parse_hid_descriptor(uint8_t *desc, size_t desc_size)
666559
osMessagePut(msgQGfxTask, (uint32_t)evt, 0U);
667560
}
668561

669-
hid_data_location_t * xlat_get_button_location(void)
562+
uint16_t xlat_get_button_bits(void)
670563
{
671-
return &button_location;
564+
return button_bits;
672565
}
673566

674-
hid_data_location_t * xlat_get_x_location(void)
567+
uint16_t xlat_get_motion_bits(void)
675568
{
676-
return &x_location;
569+
return motion_bits;
677570
}
678571

679-
hid_data_location_t * xlat_get_y_location(void)
572+
uint16_t xlat_get_report_id(void)
680573
{
681-
return &y_location;
574+
return report_id;
682575
}
683576

684577
void xlat_clear_locations(void)
685578
{
686579
printf("Clearing locations\n");
687-
button_location.found = false;
688-
x_location.found = false;
689-
y_location.found = false;
580+
memset(prev_report, 0, sizeof(prev_report));
581+
memset(button_mask, 0, sizeof(button_mask));
582+
memset(motion_mask, 0, sizeof(motion_mask));
583+
button_bits = 0;
584+
motion_bits = 0;
585+
report_id = 0;
690586
}
691587

692588
void xlat_init(void)
693589
{
694590
// create timer
695591
xlat_timer_handle = xTimerCreate("xlat_timer", pdMS_TO_TICKS(1000), pdFALSE, NULL, xlat_timer_callback);
592+
xlat_clear_locations();
696593
hw_exti_interrupts_enable();
697594
xlat_initialized = true;
698595
printf("XLAT initialized\n");

src/xlat.h

Lines changed: 3 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -30,13 +30,6 @@ typedef struct hid_event {
3030
uint32_t timestamp;
3131
} hid_event_t;
3232

33-
typedef struct hid_data_location {
34-
bool found;
35-
size_t bit_index;
36-
size_t bit_size;
37-
size_t byte_offset;
38-
} hid_data_location_t;
39-
4033
typedef enum latency_type {
4134
LATENCY_GPIO_TO_USB = 0,
4235
LATENCY_AUDIO_TO_USB,
@@ -72,18 +65,14 @@ uint32_t xlat_counter_1mhz_get(void);
7265
uint32_t xlat_get_last_usb_timestamp_us(void);
7366
uint32_t xlat_get_last_button_timestamp_us(void);
7467

75-
76-
void xlat_set_using_reportid(bool use_reportid);
77-
bool xlat_get_using_reportid(void);
78-
7968
void xlat_parse_hid_descriptor(uint8_t *desc, size_t desc_size);
8069

8170
void xlat_set_mode(enum xlat_mode mode);
8271
enum xlat_mode xlat_get_mode(void);
8372

84-
hid_data_location_t * xlat_get_button_location(void);
85-
hid_data_location_t * xlat_get_x_location(void);
86-
hid_data_location_t * xlat_get_y_location(void);
73+
uint16_t xlat_get_button_bits(void);
74+
uint16_t xlat_get_motion_bits(void);
75+
uint16_t xlat_get_report_id(void);
8776
void xlat_clear_locations(void);
8877

8978
void xlat_auto_trigger_action(void);

0 commit comments

Comments
 (0)