blob: 924cf3796e1e2e366420b60feae9eede41e191f9 [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>
Philipp Schrader790cb542023-07-05 21:06:52 -07006
Brian Silvermand930f282017-11-04 23:09:12 -04007#include <array>
8
9#include "motors/usb/usb.h"
10#include "motors/util.h"
11
12namespace frc971 {
13namespace teensy {
14
15// Implements an HID class device.
16// TODO(Brian): Make this way more generic.
17class 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 Silverman587edcc2018-01-15 12:00:22 -080027 // 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 Silvermand930f282017-11-04 23:09:12 -040034 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 Silvermand930f282017-11-04 23:09:12 -040062 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 Silverman587edcc2018-01-15 12:00:22 -080093
94 ::std::string report_descriptor_;
95 UsbDescriptorList hid_descriptor_list_;
Brian Silvermand930f282017-11-04 23:09:12 -040096};
97
98} // namespace teensy
99} // namespace frc971
100
101#endif // MOTORS_USB_HID_H_