Add support for varying HID descriptors
Change-Id: I8ee01045d2b4bcc98bedb615f0af1b26ebbd66f7
diff --git a/motors/pistol_grip/drivers_station.cc b/motors/pistol_grip/drivers_station.cc
index d58d3d3..155440a 100644
--- a/motors/pistol_grip/drivers_station.cc
+++ b/motors/pistol_grip/drivers_station.cc
@@ -198,6 +198,35 @@
}
}
+// The HID report descriptor we use.
+constexpr char kReportDescriptor[] = {
+ 0x05, 0x01, // Usage Page (Generic Desktop),
+ 0x09, 0x04, // Usage (Joystick),
+ 0xA1, 0x01, // Collection (Application),
+ 0x75, 0x10, // Report Size (16),
+ 0x95, 0x06, // Report Count (6),
+ 0x15, 0x00, // Logical Minimum (0),
+ 0x26, 0xFF, 0xFF, // Logical Maximum (65535),
+ 0x35, 0x00, // Physical Minimum (0),
+ 0x46, 0xFF, 0xFF, // Physical Maximum (65535),
+ 0x09, 0x30, // Usage (X),
+ 0x09, 0x31, // Usage (Y),
+ 0x09, 0x32, // Usage (Z),
+ 0x09, 0x33, // Usage (Rz),
+ 0x09, 0x34, // Usage (?),
+ 0x09, 0x35, // Usage (?),
+ 0x81, 0x02, // Input (Variable),
+ 0x75, 0x01, // Report Size (1),
+ 0x95, 0x10, // Report Count (16),
+ 0x25, 0x01, // Logical Maximum (1),
+ 0x45, 0x01, // Physical Maximum (1),
+ 0x05, 0x09, // Usage Page (Button),
+ 0x19, 0x01, // Usage Minimum (01),
+ 0x29, 0x10, // Usage Maximum (16),
+ 0x81, 0x02, // Input (Variable),
+ 0xC0 // End Collection
+};
+
} // namespace
extern "C" {
@@ -244,7 +273,11 @@
usb_device.SetManufacturer("FRC 971 Spartan Robotics");
usb_device.SetProduct("Pistol Grip Controller interface");
teensy::HidFunction throttle_joystick(&usb_device, 14);
+ throttle_joystick.set_report_descriptor(
+ ::std::string(kReportDescriptor, sizeof(kReportDescriptor)));
teensy::HidFunction wheel_joystick(&usb_device, 14);
+ wheel_joystick.set_report_descriptor(
+ ::std::string(kReportDescriptor, sizeof(kReportDescriptor)));
teensy::AcmTty tty1(&usb_device);
teensy::AcmTty tty2(&usb_device);
teensy::InterruptOut interrupt_out(&usb_device, "JoystickForce");
diff --git a/motors/usb/hid.cc b/motors/usb/hid.cc
index f42930b..d885e75 100644
--- a/motors/usb/hid.cc
+++ b/motors/usb/hid.cc
@@ -15,48 +15,6 @@
constexpr uint8_t set_protcol() { return 0x0b; }
} // namespace hid_class_requests
-// The hard-coded HID report descriptor.
-uint8_t kReportDescriptor[] = {
- 0x05, 0x01, // Usage Page (Generic Desktop),
- 0x09, 0x04, // Usage (Joystick),
- 0xA1, 0x01, // Collection (Application),
- 0x75, 0x10, // Report Size (16),
- 0x95, 0x06, // Report Count (6),
- 0x15, 0x00, // Logical Minimum (0),
- 0x26, 0xFF, 0xFF, // Logical Maximum (65535),
- 0x35, 0x00, // Physical Minimum (0),
- 0x46, 0xFF, 0xFF, // Physical Maximum (65535),
- 0x09, 0x30, // Usage (X),
- 0x09, 0x31, // Usage (Y),
- 0x09, 0x32, // Usage (Z),
- 0x09, 0x33, // Usage (Rz),
- 0x09, 0x34, // Usage (?),
- 0x09, 0x35, // Usage (?),
- 0x81, 0x02, // Input (Variable),
- 0x75, 0x01, // Report Size (1),
- 0x95, 0x10, // Report Count (16),
- 0x25, 0x01, // Logical Maximum (1),
- 0x45, 0x01, // Physical Maximum (1),
- 0x05, 0x09, // Usage Page (Button),
- 0x19, 0x01, // Usage Minimum (01),
- 0x29, 0x10, // Usage Maximum (16),
- 0x81, 0x02, // Input (Variable),
- 0xC0 // End Collection
-};
-
-// The hard-coded HID descriptor.
-uint8_t kHidDescriptor[] = {
- 9, // bLength
- static_cast<uint8_t>(UsbClassDescriptorType::kHidHid), // bDescriptorType
- 0x10, 0x01, // bcdHID
- 0, // bCountryCode
- 1, // bNumDescriptors
- static_cast<uint8_t>(
- UsbClassDescriptorType::kHidReport), // bDescriptorType
- sizeof(kReportDescriptor), // wDescriptorLength
- 0,
-};
-
} // namespace
void HidFunction::Initialize() {
@@ -82,7 +40,17 @@
interface_descriptor->AddByte(device()->AddString("Hid")); // iInterface
}
- AddPremadeDescriptor(kHidDescriptor, sizeof(kHidDescriptor));
+ {
+ const auto hid_descriptor = hid_descriptor_list_.CreateDescriptor(
+ 9, UsbClassDescriptorType::kHidHid);
+ hid_descriptor->AddUint16(0x0110); // bcdHID
+ hid_descriptor->AddByte(0); // bCountryCode
+ hid_descriptor->AddByte(1); // bNumDescriptors
+ hid_descriptor->AddByte(static_cast<uint8_t>(
+ UsbClassDescriptorType::kHidReport)); // bDescriptorType
+ hid_descriptor->AddUint16(report_descriptor_.size()); // wDescriptorLength
+ }
+ AddPremadeDescriptor(hid_descriptor_list_);
{
const auto endpoint_descriptor = CreateDescriptor(
@@ -169,8 +137,9 @@
return SetupResponse::kStall;
}
device()->QueueEndpoint0Data(
- reinterpret_cast<const char *>(kHidDescriptor),
- ::std::min<int>(setup_packet.length, sizeof(kHidDescriptor)));
+ hid_descriptor_list_.GetData(),
+ ::std::min<int>(setup_packet.length,
+ hid_descriptor_list_.CurrentSize()));
return SetupResponse::kHandled;
case static_cast<uint8_t>(UsbClassDescriptorType::kHidReport):
@@ -178,8 +147,8 @@
return SetupResponse::kStall;
}
device()->QueueEndpoint0Data(
- reinterpret_cast<const char *>(kReportDescriptor),
- ::std::min<int>(setup_packet.length, sizeof(kReportDescriptor)));
+ report_descriptor_.data(),
+ ::std::min<int>(setup_packet.length, report_descriptor_.size()));
return SetupResponse::kHandled;
case static_cast<uint8_t>(UsbClassDescriptorType::kHidPhysical):
diff --git a/motors/usb/hid.h b/motors/usb/hid.h
index 37aa86b..019231c 100644
--- a/motors/usb/hid.h
+++ b/motors/usb/hid.h
@@ -23,6 +23,13 @@
}
~HidFunction() override = default;
+ // Sets the report descriptor. Must be called at least once.
+ //
+ // May only be called during setup.
+ void set_report_descriptor(const ::std::string &report_descriptor) {
+ report_descriptor_ = report_descriptor;
+ }
+
void UpdateReport(const void *data, int length,
const DisableInterrupts &disable_interrupts) {
memcpy(report_tx_buffer_to_fill(disable_interrupts), data, length);
@@ -82,6 +89,9 @@
int in_endpoint_;
const int report_max_size_;
+
+ ::std::string report_descriptor_;
+ UsbDescriptorList hid_descriptor_list_;
};
} // namespace teensy
diff --git a/motors/usb/usb.h b/motors/usb/usb.h
index 8fd2fb3..299df59 100644
--- a/motors/usb/usb.h
+++ b/motors/usb/usb.h
@@ -214,10 +214,22 @@
memcpy(&data_[start_index], data, length);
}
+ void AddPremadeDescriptor(const UsbDescriptorList &other_list) {
+ other_list.CheckFinished();
+ AddPremadeDescriptor(
+ reinterpret_cast<const uint8_t *>(other_list.data_.data()),
+ other_list.data_.size());
+ }
+
void CheckFinished() const { assert(open_descriptors_ == 0); }
int CurrentSize() const { return data_.size(); }
+ const char *GetData() const {
+ CheckFinished();
+ return data_.data();
+ }
+
private:
::std::unique_ptr<Descriptor> CreateDescriptor(uint8_t length,
uint8_t descriptor_type) {
@@ -504,6 +516,9 @@
void AddPremadeDescriptor(const uint8_t *data, int length) {
device_->config_descriptor_list_.AddPremadeDescriptor(data, length);
}
+ void AddPremadeDescriptor(const UsbDescriptorList &other_list) {
+ device_->config_descriptor_list_.AddPremadeDescriptor(other_list);
+ }
UsbDevice *device() const { return device_; }