Brian Silverman | d930f28 | 2017-11-04 23:09:12 -0400 | [diff] [blame] | 1 | #ifndef MOTORS_USB_HID_H_ |
| 2 | #define MOTORS_USB_HID_H_ |
| 3 | |
| 4 | #include <stdint.h> |
| 5 | #include <string.h> |
Philipp Schrader | 790cb54 | 2023-07-05 21:06:52 -0700 | [diff] [blame] | 6 | |
Brian Silverman | d930f28 | 2017-11-04 23:09:12 -0400 | [diff] [blame] | 7 | #include <array> |
| 8 | |
| 9 | #include "motors/usb/usb.h" |
| 10 | #include "motors/util.h" |
| 11 | |
| 12 | namespace frc971 { |
| 13 | namespace teensy { |
| 14 | |
| 15 | // Implements an HID class device. |
| 16 | // TODO(Brian): Make this way more generic. |
| 17 | class HidFunction final : public UsbFunction { |
| 18 | public: |
| 19 | HidFunction(UsbDevice *device, int report_max_size) |
| 20 | : UsbFunction(device), report_max_size_(report_max_size) { |
| 21 | if (report_max_size_ > kMaxReportSize) { |
| 22 | __builtin_trap(); |
| 23 | } |
| 24 | } |
| 25 | ~HidFunction() override = default; |
| 26 | |
Brian Silverman | 587edcc | 2018-01-15 12:00:22 -0800 | [diff] [blame] | 27 | // Sets the report descriptor. Must be called at least once. |
| 28 | // |
| 29 | // May only be called during setup. |
| 30 | void set_report_descriptor(const ::std::string &report_descriptor) { |
| 31 | report_descriptor_ = report_descriptor; |
| 32 | } |
| 33 | |
Brian Silverman | d930f28 | 2017-11-04 23:09:12 -0400 | [diff] [blame] | 34 | void UpdateReport(const void *data, int length, |
| 35 | const DisableInterrupts &disable_interrupts) { |
| 36 | memcpy(report_tx_buffer_to_fill(disable_interrupts), data, length); |
| 37 | } |
| 38 | |
| 39 | private: |
| 40 | // Choose 64 for now so it always fits into a single packet. |
| 41 | static constexpr int kMaxReportSize = 64; |
| 42 | |
| 43 | uint8_t *report_tx_buffer_for(EvenOdd odd) { |
| 44 | return report_tx_buffers_[EvenOddIndex(odd)].data(); |
| 45 | } |
| 46 | uint8_t *report_tx_buffer_being_sent(const DisableInterrupts &) { |
| 47 | return report_tx_buffer_for(BufferStateToEmpty(tx_state_)); |
| 48 | } |
| 49 | uint8_t *report_tx_buffer_to_fill(const DisableInterrupts &) { |
| 50 | return report_tx_buffer_for(BufferStateToFill(tx_state_)); |
| 51 | } |
| 52 | |
| 53 | int in_endpoint_max_size() const { return report_max_size_; } |
| 54 | |
| 55 | void Initialize() override; |
| 56 | |
| 57 | SetupResponse HandleEndpoint0SetupPacket( |
| 58 | const UsbDevice::SetupPacket &setup_packet) override; |
| 59 | SetupResponse HandleGetDescriptor( |
| 60 | const UsbDevice::SetupPacket &setup_packet) override; |
| 61 | |
Brian Silverman | d930f28 | 2017-11-04 23:09:12 -0400 | [diff] [blame] | 62 | void HandleInFinished(int endpoint, BdtEntry *bdt_entry, |
| 63 | EvenOdd odd) override; |
| 64 | |
| 65 | void HandleConfigured(int endpoint) override; |
| 66 | void HandleReset() override { |
| 67 | tx_state_ = EndpointBufferState::kBothEmptyEvenFirst; |
| 68 | device()->SetBdtEntry(in_endpoint_, Direction::kTx, EvenOdd::kEven, |
| 69 | {0, nullptr}); |
| 70 | device()->SetBdtEntry(in_endpoint_, Direction::kTx, EvenOdd::kOdd, |
| 71 | {0, nullptr}); |
| 72 | { |
| 73 | DisableInterrupts disable_interrupts; |
| 74 | memset(report_tx_buffers_[0].data(), 0, kMaxReportSize); |
| 75 | memset(report_tx_buffers_[1].data(), 0, kMaxReportSize); |
| 76 | } |
| 77 | } |
| 78 | |
| 79 | ::std::array<::std::array<uint8_t, kMaxReportSize>, 2> report_tx_buffers_; |
| 80 | ::std::array<uint8_t, kMaxReportSize> get_report_response_buffer_; |
| 81 | |
| 82 | // This is only manipulated with interrupts disabled. |
| 83 | EndpointBufferState tx_state_; |
| 84 | Data01 next_tx_toggle_; |
| 85 | |
| 86 | // Our interface number. |
| 87 | int interface_; |
| 88 | |
| 89 | // The IN endpoint we send reports on. |
| 90 | int in_endpoint_; |
| 91 | |
| 92 | const int report_max_size_; |
Brian Silverman | 587edcc | 2018-01-15 12:00:22 -0800 | [diff] [blame] | 93 | |
| 94 | ::std::string report_descriptor_; |
| 95 | UsbDescriptorList hid_descriptor_list_; |
Brian Silverman | d930f28 | 2017-11-04 23:09:12 -0400 | [diff] [blame] | 96 | }; |
| 97 | |
| 98 | } // namespace teensy |
| 99 | } // namespace frc971 |
| 100 | |
| 101 | #endif // MOTORS_USB_HID_H_ |