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