blob: 019231c7701f341930c161424d82a4efc31fb549 [file] [log] [blame]
Brian Silvermand930f282017-11-04 23:09:12 -04001#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
11namespace frc971 {
12namespace teensy {
13
14// Implements an HID class device.
15// TODO(Brian): Make this way more generic.
16class 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 Silverman587edcc2018-01-15 12:00:22 -080026 // 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 Silvermand930f282017-11-04 23:09:12 -040033 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 Silvermand930f282017-11-04 23:09:12 -040061 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 Silverman587edcc2018-01-15 12:00:22 -080092
93 ::std::string report_descriptor_;
94 UsbDescriptorList hid_descriptor_list_;
Brian Silvermand930f282017-11-04 23:09:12 -040095};
96
97} // namespace teensy
98} // namespace frc971
99
100#endif // MOTORS_USB_HID_H_