Skip to content

Commit da50151

Browse files
committed
usb keyboard added start for multiple report ids
1 parent a15aa92 commit da50151

1 file changed

Lines changed: 82 additions & 73 deletions

File tree

klib/usb/device/keyboard.hpp

Lines changed: 82 additions & 73 deletions
Original file line numberDiff line numberDiff line change
@@ -203,6 +203,14 @@ namespace klib::usb::device {
203203
serial = 3
204204
};
205205

206+
/**
207+
* @brief All the report ids we have in our descriptor
208+
*
209+
*/
210+
enum class report_id: uint8_t {
211+
keyboard = 1,
212+
};
213+
206214
// Push the current pack to the stack and set the pack to 1
207215
// as all these structs have specific sizes
208216
#pragma pack(push, 1)
@@ -250,28 +258,27 @@ namespace klib::usb::device {
250258

251259
// report descriptor for the hid keyboard
252260
const __attribute__((aligned(4))) static inline uint8_t report_desc[] = {
253-
0x05, 0x01, // Usage Page (generic desktop)
254-
0x09, 0x06, // Usage (keyboard)
255-
0xa1, 0x01, // Collection
256-
0x05, 0x07, // Usage Page 7 (keyboard/keypad)
257-
0x19, 0xe0, // Usage Minimum = 224
258-
0x29, 0xe7, // Usage Maximum = 231
259-
0x15, 0x00, // Logical Minimum = 0
260-
0x25, 0x01, // Logical Maximum = 1
261-
0x75, 0x01, // Report Size = 1
262-
0x95, 0x08, // Report Count = 8
263-
0x81, 0x02, // Input(Data,Variable,Absolute)
264-
0x95, 0x01, // Report Count = 1
265-
0x75, 0x08, // Report Size = 8
266-
0x81, 0x01, // Input(Constant)
267-
0x19, 0x00, // Usage Minimum = 0
268-
0x29, 0x65, // Usage Maximum = 101
269-
0x15, 0x00, // Logical Minimum = 0
270-
0x25, 0x65, // Logical Maximum = 101
271-
0x75, 0x08, // Report Size = 8
272-
0x95, 0x01, // Report Count = 1
273-
0x81, 0x00, // Input(Data,Variable,Array)
274-
0xc0 // End Collection
261+
// Keyboard report (Report ID 1)
262+
0x05, 0x01, // Usage Page (Generic Desktop)
263+
0x09, 0x06, // Usage (Keyboard)
264+
0xa1, 0x01, // Collection (Application)
265+
0x85, 0x01, // Report ID (1)
266+
0x05, 0x07, // Usage Page (Keyboard/Keypad)
267+
0x19, 0xe0, // Usage Minimum (224)
268+
0x29, 0xe7, // Usage Maximum (231)
269+
0x15, 0x00, // Logical Minimum (0)
270+
0x25, 0x01, // Logical Maximum (1)
271+
0x75, 0x01, // Report Size (1)
272+
0x95, 0x08, // Report Count (8)
273+
0x81, 0x02, // Input (Data, Variable, Absolute) ; Modifier byte
274+
0x19, 0x00, // Usage Minimum (0)
275+
0x29, 0x65, // Usage Maximum (101)
276+
0x15, 0x00, // Logical Minimum (0)
277+
0x25, 0x65, // Logical Maximum (101)
278+
0x75, 0x08, // Report Size (8)
279+
0x95, 0x01, // Report Count (1)
280+
0x81, 0x00, // Input (Data, Array) ; Keycode byte
281+
0xc0, // End Collection
275282
};
276283

277284
// configuration descriptor
@@ -329,22 +336,27 @@ namespace klib::usb::device {
329336
// flag if remote wakeup is supported
330337
static inline bool remote_wakeup = false;
331338

332-
// structure for the report
333-
struct report_data {
334-
// modifier keys (e.g. ctrl, shift)
335-
uint8_t modifier;
339+
// Push the current pack to the stack and set the pack to 1
340+
// as the following structs have specific sizes
341+
#pragma pack(push, 1)
336342

337-
// reserved value. Should be 0x00
338-
uint8_t reserved;
343+
struct keycode_report_t {
344+
// fixed report id for the keyboard
345+
const report_id id = report_id::keyboard;
339346

340-
// the current key that is pressed
347+
// key data
348+
uint8_t modifier;
341349
key_t key;
342350
};
343351

344-
static_assert(sizeof(report_data) == 3, "invalid report size");
352+
static_assert(sizeof(keycode_report_t) == 3, "invalid keyboard report size");
353+
354+
// release the old pack so the rest of the structs are not
355+
// affected by the pack(1)
356+
#pragma pack(pop)
345357

346358
// storage for the keyboard hid messages
347-
static inline report_data report = {};
359+
static inline keycode_report_t keycode_report = {};
348360

349361
// static parameters with data to write to the host
350362
static inline const char *volatile irq_data = nullptr;
@@ -374,12 +386,13 @@ namespace klib::usb::device {
374386
if ((!irq_size) && (irq_data != nullptr)) {
375387
// we have nothing more to send. Send a empty report
376388
// with no keypresses
377-
report = {};
389+
keycode_report.modifier = 0x00;
390+
keycode_report.key = key_t::key_none;
378391

379392
// send the no key pressed to the host
380393
Usb::write(
381394
hid_callback<Usb>, usb::get_endpoint(config.endpoint.bEndpointAddress),
382-
mode, {reinterpret_cast<const uint8_t*>(&report), sizeof(report)}
395+
mode, {reinterpret_cast<const uint8_t*>(&keycode_report), sizeof(keycode_report)}
383396
);
384397

385398
// clear the data to notify we are done with the string
@@ -400,12 +413,13 @@ namespace klib::usb::device {
400413
if (irq_size > 0 && irq_data[0] == irq_data[1] && repeated_key == false) {
401414
// we have detected a double character. Send a no keys
402415
// pressed in between
403-
report = {};
416+
keycode_report.modifier = 0x00;
417+
keycode_report.key = key_t::key_none;
404418

405419
// send the report to the host
406420
Usb::write(
407421
hid_callback<Usb>, usb::get_endpoint(config.endpoint.bEndpointAddress),
408-
mode, {reinterpret_cast<const uint8_t*>(&report), sizeof(report)}
422+
mode, {reinterpret_cast<const uint8_t*>(&keycode_report), sizeof(keycode_report)}
409423
);
410424

411425
// mark we have send a no keys between two repeated keys
@@ -421,25 +435,22 @@ namespace klib::usb::device {
421435
irq_data++;
422436

423437
// encode the next character
424-
encode_report(irq_data[0], report);
438+
encode_report(irq_data[0], keycode_report);
425439

426440
// clear we have transmitted a no keys in between two repeated keys
427441
repeated_key = false;
428442

429443
// send the report to the host
430444
Usb::write(
431445
hid_callback<Usb>, usb::get_endpoint(config.endpoint.bEndpointAddress),
432-
mode, {reinterpret_cast<const uint8_t*>(&report), sizeof(report)}
446+
mode, {reinterpret_cast<const uint8_t*>(&keycode_report), sizeof(keycode_report)}
433447
);
434448

435449
// return we are done
436450
return;
437451
}
438452

439-
static void encode_report(const char ch, report_data& report) {
440-
// always clear the reserved data
441-
report.reserved = 0x00;
442-
453+
static void encode_report(const char ch, keycode_report_t& report) {
443454
// check what data we have
444455
if (klib::string::is_character(ch)) {
445456
// offset between the character (in the ascii table) and in the
@@ -540,8 +551,8 @@ namespace klib::usb::device {
540551
return false;
541552
}
542553

543-
template <typename Usb, bool Async = false>
544-
static bool write_impl(const report_data& r) {
554+
template <typename Usb, bool Async = false, typename T = keycode_report_t>
555+
static bool write_impl(const T& r) {
545556
// write the first report to the endpoint
546557
if (!Usb::write(hid_callback<Usb>, usb::get_endpoint(config.endpoint.bEndpointAddress),
547558
usb::get_endpoint_mode(config.endpoint.bEndpointAddress), {reinterpret_cast<const uint8_t*>(&r), sizeof(r)}))
@@ -577,14 +588,14 @@ namespace klib::usb::device {
577588
}
578589

579590
// encode the first report
580-
encode_report(data[0], report);
591+
encode_report(data[0], keycode_report);
581592

582593
// set the data in the interrupt
583594
irq_size = size - 1;
584595
irq_data = data;
585596

586597
// write the data
587-
return write_impl<Usb, Async>(report);
598+
return write_impl<Usb, Async, true>(keycode_report);
588599
}
589600

590601
template <typename Usb, bool Async = false>
@@ -599,18 +610,15 @@ namespace klib::usb::device {
599610
}
600611

601612
// set the report
602-
report = {
603-
.modifier = 0x00,
604-
.reserved = 0x00,
605-
.key = key
606-
};
613+
keycode_report.modifier = 0x00;
614+
keycode_report.key = key;
607615

608616
// set the data in the interrupt
609617
irq_size = 0;
610618
irq_data = &dummy;
611619

612620
// write the data
613-
return write_impl<Usb, Async>(report);
621+
return write_impl<Usb, Async>(keycode_report);
614622
}
615623

616624
/**
@@ -849,7 +857,7 @@ namespace klib::usb::device {
849857
usb::get_endpoint(config.endpoint.bEndpointAddress),
850858
usb::get_endpoint_mode(config.endpoint.bEndpointAddress),
851859
usb::get_transfer_type(config.endpoint.bmAttributes),
852-
sizeof(report)
860+
sizeof(keycode_report)
853861
);
854862

855863
// store the configuration value
@@ -859,13 +867,14 @@ namespace klib::usb::device {
859867
Usb::configured(true);
860868

861869
// prepare a inital report with no keys pressed
862-
report = {};
870+
keycode_report.modifier = 0x00;
871+
keycode_report.key = key_t::key_none;
863872

864873
// write the inital report
865874
if (Usb::write(
866875
hid_callback<Usb>, usb::get_endpoint(config.endpoint.bEndpointAddress),
867876
usb::get_endpoint_mode(config.endpoint.bEndpointAddress),
868-
{reinterpret_cast<const uint8_t*>(&report), sizeof(report)}))
877+
{reinterpret_cast<const uint8_t*>(&keycode_report), sizeof(keycode_report)}))
869878
{
870879
// no issue for now ack
871880
return usb::handshake::ack;
@@ -934,11 +943,12 @@ namespace klib::usb::device {
934943
case hid::class_request::get_report:
935944
// the host should not use this as a substitute for the Interrupt EP
936945
// we simply send a "no keys" report to the host
937-
report = {};
946+
keycode_report.modifier = 0x00;
947+
keycode_report.key = key_t::key_none;
938948

939949
// write the data to the control endpoint
940950
if (Usb::write(nullptr, usb::control_endpoint,
941-
usb::endpoint_mode::in, {reinterpret_cast<const uint8_t*>(&report), sizeof(report)}))
951+
usb::endpoint_mode::in, {reinterpret_cast<const uint8_t*>(&keycode_report), sizeof(keycode_report)}))
942952
{
943953
// no issue for now ack
944954
return usb::handshake::ack;
@@ -949,24 +959,23 @@ namespace klib::usb::device {
949959
}
950960
break;
951961
case hid::class_request::get_idle:
952-
// TODO: add support for report id != 0
953-
// for now we only support report id == 0
954-
if ((packet.wValue & 0xff) != 0x00) {
955-
// not supported for now
956-
return usb::handshake::stall;
957-
}
958-
else {
959-
// write the data to the control endpoint
960-
if (Usb::write(nullptr, usb::control_endpoint, usb::endpoint_mode::in,
961-
{reinterpret_cast<const uint8_t*>(&report), sizeof(report)}))
962-
{
963-
// no issue for now ack
964-
return usb::handshake::ack;
965-
}
966-
else {
967-
// something went wrong stall for now
962+
switch (static_cast<report_id>(packet.wValue & 0xff)) {
963+
case report_id::keyboard:
964+
// write the data to the control endpoint
965+
if (Usb::write(nullptr, usb::control_endpoint, usb::endpoint_mode::in,
966+
{reinterpret_cast<const uint8_t*>(&keycode_report), sizeof(keycode_report)}))
967+
{
968+
// no issue for now ack
969+
return usb::handshake::ack;
970+
}
971+
else {
972+
// something went wrong stall for now
973+
return usb::handshake::stall;
974+
}
975+
break;
976+
default:
977+
// not supported for now
968978
return usb::handshake::stall;
969-
}
970979
}
971980
break;
972981
case hid::class_request::set_report:

0 commit comments

Comments
 (0)