Skip to content

Commit 911db9a

Browse files
committed
Cleanup and tests
1 parent cbc8e82 commit 911db9a

File tree

9 files changed

+453
-245
lines changed

9 files changed

+453
-245
lines changed

main/badge_hid_drivers.c

Lines changed: 149 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,21 @@
1616

1717
static char const TAG[] = "BADGE_HID_DRIVER";
1818

19+
static mouse_field_layout_t mouse_layout = {0};
20+
static gamepad_field_layout_t gamepad_layout = {0};
21+
22+
static uint32_t extract_unsigned_bits(const uint8_t* data, int bit_offset, int bit_size) {
23+
uint32_t value = 0;
24+
for (int i = 0; i < bit_size; i++) {
25+
int byte_index = (bit_offset + i) / 8;
26+
int bit_index = (bit_offset + i) % 8;
27+
if (data[byte_index] & (1 << bit_index)) {
28+
value |= (1u << i);
29+
}
30+
}
31+
return value;
32+
}
33+
1934
static int32_t extract_signed_bits(const uint8_t* data, uint16_t bit_offset, uint8_t bit_size) {
2035
uint32_t raw = 0;
2136
for (int i = 0; i < ((bit_size + 7) / 8) + 1; ++i) {
@@ -33,6 +48,13 @@ static int32_t extract_signed_bits(const uint8_t* data, uint16_t bit_offset, uin
3348
return value;
3449
}
3550

51+
static void decode_hat_to_dpad(uint8_t hat, gamepad_report_t* rpt) {
52+
rpt->buttons.up = (hat == 0x00 || hat == 0x01 || hat == 0x07);
53+
rpt->buttons.right = (hat == 0x01 || hat == 0x02 || hat == 0x03);
54+
rpt->buttons.down = (hat == 0x03 || hat == 0x04 || hat == 0x05);
55+
rpt->buttons.left = (hat == 0x05 || hat == 0x06 || hat == 0x07);
56+
}
57+
3658
esp_err_t analyze_mouse_layout(const uint8_t* desc, int desc_len, mouse_field_layout_t* layout_out) {
3759
memset(layout_out, 0, sizeof(*layout_out));
3860

@@ -68,7 +90,11 @@ esp_err_t analyze_mouse_layout(const uint8_t* desc, int desc_len, mouse_field_la
6890
report_size = data;
6991
else if (tag == HID_TAG_REPORT_COUNT)
7092
report_count = data;
71-
break;
93+
else if (tag == HID_TAG_REPORT_ID) {
94+
layout_out->report_id = data;
95+
bit_offset += 8;
96+
}
97+
break;;
7298

7399
case HID_TYPE_LOCAL:
74100
if (tag == HID_TAG_USAGE && usage_index < 32)
@@ -144,7 +170,7 @@ esp_err_t analyze_mouse_layout(const uint8_t* desc, int desc_len, mouse_field_la
144170
return layout_out->x.present && layout_out->y.present && layout_out->buttons.present ? ESP_OK : ESP_FAIL;
145171
}
146172

147-
esp_err_t analyze_gamepad_layout(const uint8_t* desc, int desc_len, gamepad_field_layout_t* layout_out) {
173+
esp_err_t analyze_gamepad_layout(const uint8_t* desc, const int desc_len, gamepad_field_layout_t* layout_out) {
148174
memset(layout_out, 0, sizeof(*layout_out));
149175

150176
uint16_t bit_offset = 0;
@@ -282,6 +308,87 @@ esp_err_t analyze_gamepad_layout(const uint8_t* desc, int desc_len, gamepad_fiel
282308
return ESP_OK;
283309
}
284310

311+
mouse_report_t parse_mouse_event(const uint8_t* data, const int length, mouse_field_layout_t* layout) {
312+
313+
// ESP_LOG_BUFFER_HEX(TAG, data, length);
314+
315+
mouse_report_t report = {0};
316+
if (!layout) {
317+
ESP_LOGW(TAG, "No layout for mouse!");
318+
return report;
319+
}
320+
321+
if (layout->buttons.present) {
322+
report.buttons.val = extract_unsigned_bits(data, layout->buttons.offset, layout->buttons.size);
323+
}
324+
325+
if (layout->x.present) {
326+
report.x_displacement = extract_signed_bits(data, layout->x.offset, layout->x.size);
327+
}
328+
329+
if (layout->y.present) {
330+
report.y_displacement = extract_signed_bits(data, layout->y.offset, layout->y.size);
331+
}
332+
333+
if (layout->scroll.present) {
334+
report.scroll = extract_signed_bits(data, layout->scroll.offset, layout->scroll.size);
335+
}
336+
337+
if (layout->tilt.present) {
338+
report.tilt = extract_signed_bits(data, layout->tilt.offset, layout->tilt.size);
339+
}
340+
341+
return report;
342+
}
343+
344+
gamepad_report_t parse_gamepad_report(const uint8_t* data, int length, gamepad_field_layout_t* layout) {
345+
346+
ESP_LOG_BUFFER_HEX(TAG, data, length);
347+
348+
gamepad_report_t report = {0};
349+
if (!layout) {
350+
ESP_LOGW(TAG, "No layout for gamepad!");
351+
return report;
352+
}
353+
if (layout->dpad.present) {
354+
uint8_t hat = extract_unsigned_bits(data, layout->dpad.offset, layout->dpad.size);
355+
decode_hat_to_dpad(hat, &report);
356+
}
357+
358+
if (layout->buttons.present) {
359+
uint32_t btn_bits = extract_unsigned_bits(data, layout->buttons.offset, layout->buttons.size);
360+
// Preserve bits that were already set by decode_hat_to_dpad()
361+
btn_bits |= report.buttons.val;
362+
report.buttons.val = btn_bits;
363+
}
364+
365+
if (layout->lx.present) {
366+
report.lx = extract_signed_bits(data, layout->lx.offset, layout->lx.size);
367+
}
368+
369+
if (layout->ly.present) {
370+
report.ly = extract_signed_bits(data, layout->ly.offset, layout->ly.size);
371+
}
372+
373+
if (layout->rx.present) {
374+
report.rx = extract_signed_bits(data, layout->rx.offset, layout->rx.size);
375+
}
376+
377+
if (layout->ry.present) {
378+
report.ry = extract_signed_bits(data, layout->ry.offset, layout->ry.size);
379+
}
380+
381+
if (layout->lt.present) {
382+
report.lt = extract_signed_bits(data, layout->lt.offset, layout->lt.size);
383+
}
384+
385+
if (layout->rt.present) {
386+
report.rt = extract_signed_bits(data, layout->rt.offset, layout->rt.size);
387+
}
388+
389+
return report;
390+
}
391+
285392
esp_err_t decode_descriptor_register_driver(const uint8_t* const desc, const int desc_len, const uint8_t proto) {
286393
if (HID_PROTOCOL_KEYBOARD == proto) {
287394
ESP_LOGI(TAG, "Keyboard uses generic (boot) driver");
@@ -291,63 +398,69 @@ esp_err_t decode_descriptor_register_driver(const uint8_t* const desc, const int
291398
if (HID_PROTOCOL_MOUSE == proto) {
292399
ESP_LOGI(TAG, "Mouse driver analysing");
293400
ESP_LOG_BUFFER_HEX(TAG, desc, desc_len);
294-
mouse_field_layout_t layout = {0};
295-
if (ESP_OK == analyze_mouse_layout(desc, desc_len, &layout)) {
401+
if (ESP_OK == analyze_mouse_layout(desc, desc_len, &mouse_layout)) {
296402
ESP_LOGI(TAG, "Parsed mouse layout:");
297-
ESP_LOGI(TAG, " Buttons: offset %u bits, count %u", layout.buttons.offset, layout.buttons.size);
298-
if (layout.x.present) ESP_LOGI(TAG, " X: offset %u bits, size %u bits", layout.x.offset, layout.x.size);
299-
if (layout.y.offset) ESP_LOGI(TAG, " Y: offset %u bits, size %u bits", layout.y.offset, layout.y.size);
300-
if (layout.scroll.present)
301-
ESP_LOGI(TAG, " Scroll: offset %u bits, size %u bits", layout.scroll.offset, layout.scroll.size);
302-
if (layout.tilt.present)
303-
ESP_LOGI(TAG, " Tilt: offset %u bits, size %u bits", layout.tilt.offset, layout.tilt.size);
403+
ESP_LOGI(TAG, " Buttons: offset %u bits, count %u", mouse_layout.buttons.offset, mouse_layout.buttons.size);
404+
if (mouse_layout.x.present) ESP_LOGI(TAG, " X: offset %u bits, size %u bits", mouse_layout.x.offset, mouse_layout.x.size);
405+
if (mouse_layout.y.offset) ESP_LOGI(TAG, " Y: offset %u bits, size %u bits", mouse_layout.y.offset, mouse_layout.y.size);
406+
if (mouse_layout.scroll.present)
407+
ESP_LOGI(TAG, " Scroll: offset %u bits, size %u bits", mouse_layout.scroll.offset, mouse_layout.scroll.size);
408+
if (mouse_layout.tilt.present)
409+
ESP_LOGI(TAG, " Tilt: offset %u bits, size %u bits", mouse_layout.tilt.offset, mouse_layout.tilt.size);
304410
} else {
305411
ESP_LOGW(TAG, "Could not parse mouse layout");
306412
}
307413
} else {
308414
ESP_LOGI(TAG, "Gamepad driver analysing");
309415
ESP_LOG_BUFFER_HEX(TAG, desc, desc_len);
310-
gamepad_field_layout_t layout;
311-
if (ESP_OK == analyze_gamepad_layout(desc, desc_len, &layout)) {
312-
ESP_LOGI(TAG, "Parsed gamepad layout:");
313-
if (layout.dpad.present) {
314-
ESP_LOGI(TAG, " D-Pad: offset %d bits, size %d bits", layout.dpad.offset, layout.dpad.size);
416+
if (ESP_OK == analyze_gamepad_layout(desc, desc_len, &gamepad_layout)) {
417+
ESP_LOGI(TAG, "Parsed gamepad gamepad_layout:");
418+
if (gamepad_layout.dpad.present) {
419+
ESP_LOGI(TAG, " D-Pad: offset %d bits, size %d bits", gamepad_layout.dpad.offset,
420+
gamepad_layout.dpad.size);
315421
}
316422

317-
if (layout.buttons.present) {
318-
ESP_LOGI(TAG, " Buttons: offset %d bits, count %d", layout.buttons.offset, layout.buttons.size);
423+
if (gamepad_layout.buttons.present) {
424+
ESP_LOGI(TAG, " Buttons: offset %d bits, count %d", gamepad_layout.buttons.offset,
425+
gamepad_layout.buttons.size);
319426
}
320427

321-
if (layout.lx.present && layout.ly.present) {
322-
ESP_LOGI(TAG, " Left Stick: X@%dbits (%d bits), Y@%dbits (%d bits)", layout.lx.offset, layout.lx.size,
323-
layout.ly.offset, layout.ly.size);
428+
if (gamepad_layout.lx.present && gamepad_layout.ly.present) {
429+
ESP_LOGI(TAG, " Left Stick: X@%dbits (%d bits), Y@%dbits (%d bits)", gamepad_layout.lx.offset,
430+
gamepad_layout.lx.size, gamepad_layout.ly.offset, gamepad_layout.ly.size);
324431
} else {
325-
if (layout.lx.present) {
326-
ESP_LOGI(TAG, " Left Stick X: offset %d bits, size %d bits", layout.lx.offset, layout.lx.size);
432+
if (gamepad_layout.lx.present) {
433+
ESP_LOGI(TAG, " Left Stick X: offset %d bits, size %d bits", gamepad_layout.lx.offset,
434+
gamepad_layout.lx.size);
327435
}
328-
if (layout.ly.present) {
329-
ESP_LOGI(TAG, " Left Stick Y: offset %d bits, size %d bits", layout.ly.offset, layout.ly.size);
436+
if (gamepad_layout.ly.present) {
437+
ESP_LOGI(TAG, " Left Stick Y: offset %d bits, size %d bits", gamepad_layout.ly.offset,
438+
gamepad_layout.ly.size);
330439
}
331440
}
332441

333-
if (layout.rx.present && layout.ry.present) {
334-
ESP_LOGI(TAG, " Right Stick: X@%dbits (%d bits), Y@%dbits (%d bits)", layout.rx.offset, layout.rx.size,
335-
layout.ry.offset, layout.ry.size);
442+
if (gamepad_layout.rx.present && gamepad_layout.ry.present) {
443+
ESP_LOGI(TAG, " Right Stick: X@%dbits (%d bits), Y@%dbits (%d bits)", gamepad_layout.rx.offset,
444+
gamepad_layout.rx.size, gamepad_layout.ry.offset, gamepad_layout.ry.size);
336445
} else {
337-
if (layout.rx.present) {
338-
ESP_LOGI(TAG, " Right Stick X: offset %d bits, size %d bits", layout.rx.offset, layout.rx.size);
446+
if (gamepad_layout.rx.present) {
447+
ESP_LOGI(TAG, " Right Stick X: offset %d bits, size %d bits", gamepad_layout.rx.offset,
448+
gamepad_layout.rx.size);
339449
}
340-
if (layout.ry.present) {
341-
ESP_LOGI(TAG, " Right Stick Y: offset %d bits, size %d bits", layout.ry.offset, layout.ry.size);
450+
if (gamepad_layout.ry.present) {
451+
ESP_LOGI(TAG, " Right Stick Y: offset %d bits, size %d bits", gamepad_layout.ry.offset,
452+
gamepad_layout.ry.size);
342453
}
343454
}
344455

345-
if (layout.lt.present) {
346-
ESP_LOGI(TAG, " Trigger L: offset %d bits, size %d bits", layout.lt.offset, layout.lt.size);
456+
if (gamepad_layout.lt.present) {
457+
ESP_LOGI(TAG, " Trigger L: offset %d bits, size %d bits", gamepad_layout.lt.offset,
458+
gamepad_layout.lt.size);
347459
}
348460

349-
if (layout.rt.present) {
350-
ESP_LOGI(TAG, " Trigger R: offset %d bits, size %d bits", layout.rt.offset, layout.rt.size);
461+
if (gamepad_layout.rt.present) {
462+
ESP_LOGI(TAG, " Trigger R: offset %d bits, size %d bits", gamepad_layout.rt.offset,
463+
gamepad_layout.rt.size);
351464
}
352465

353466
} else {

main/badge_hid_drivers.h

Lines changed: 62 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -115,19 +115,75 @@ typedef struct {
115115
field_info_t lt, rt;
116116
} gamepad_field_layout_t;
117117

118-
// Mouse layout: X, Y, Wheel, Buttons up to 8
119-
// Buttons are bit-packed after axes
120-
121118
typedef struct {
122119
uint8_t report_id;
123120
field_info_t x;
124121
field_info_t y;
125122
field_info_t scroll;
126123
field_info_t tilt;
127-
field_info_t buttons; // count via size: number of bits
124+
field_info_t buttons;
128125
} mouse_field_layout_t;
129126

130-
esp_err_t analyze_mouse_layout(const uint8_t* desc, int desc_len, mouse_field_layout_t* layout_out);
131-
esp_err_t analyze_gamepad_layout(const uint8_t* desc, int desc_len, gamepad_field_layout_t* layout_out);
127+
typedef struct {
128+
uint8_t report_id;
129+
130+
union {
131+
struct {
132+
uint32_t a : 1;
133+
uint32_t b : 1;
134+
uint32_t x : 1;
135+
uint32_t y : 1;
136+
137+
uint32_t select : 1;
138+
uint32_t start : 1;
139+
140+
uint32_t l1 : 1;
141+
uint32_t r1 : 1;
142+
uint32_t l2 : 1;
143+
uint32_t r2 : 1;
144+
uint32_t l3 : 1;
145+
uint32_t r3 : 1;
146+
147+
uint32_t home : 1;
148+
149+
uint32_t l4 : 1;
150+
uint32_t r4 : 1;
151+
152+
uint32_t up : 1;
153+
uint32_t down : 1;
154+
uint32_t left : 1;
155+
uint32_t right : 1;
156+
157+
uint32_t _reserved : 13; // Up to 32 bits total
158+
};
159+
uint32_t val;
160+
} buttons;
161+
162+
uint8_t lx, ly;
163+
uint8_t rx, ry;
164+
uint8_t lt, rt;
165+
} gamepad_report_t;
166+
167+
typedef struct {
168+
union {
169+
struct {
170+
uint8_t button1 : 1;
171+
uint8_t button2 : 1;
172+
uint8_t button3 : 1;
173+
uint8_t reserved : 5;
174+
};
175+
uint8_t val;
176+
} buttons;
177+
int16_t x_displacement;
178+
int16_t y_displacement;
179+
int8_t scroll;
180+
int8_t tilt;
181+
} mouse_report_t;
182+
183+
mouse_report_t parse_mouse_event(const uint8_t* const data, const int length, mouse_field_layout_t* layout);
184+
gamepad_report_t parse_gamepad_report(const uint8_t* const data, const int length, gamepad_field_layout_t* layout);
185+
186+
esp_err_t analyze_mouse_layout(const uint8_t* desc, const int desc_len, mouse_field_layout_t* layout_out);
187+
esp_err_t analyze_gamepad_layout(const uint8_t* desc, const int desc_len, gamepad_field_layout_t* layout_out);
132188

133189
esp_err_t decode_descriptor_register_driver(const uint8_t* const desc, const int desc_len, const uint8_t proto);

0 commit comments

Comments
 (0)