blob: 37aa86b1c87daeefdaec3eabc78c1bbbbadffb55 [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
26 void UpdateReport(const void *data, int length,
27 const DisableInterrupts &disable_interrupts) {
28 memcpy(report_tx_buffer_to_fill(disable_interrupts), data, length);
29 }
30
31 private:
32 // Choose 64 for now so it always fits into a single packet.
33 static constexpr int kMaxReportSize = 64;
34
35 uint8_t *report_tx_buffer_for(EvenOdd odd) {
36 return report_tx_buffers_[EvenOddIndex(odd)].data();
37 }
38 uint8_t *report_tx_buffer_being_sent(const DisableInterrupts &) {
39 return report_tx_buffer_for(BufferStateToEmpty(tx_state_));
40 }
41 uint8_t *report_tx_buffer_to_fill(const DisableInterrupts &) {
42 return report_tx_buffer_for(BufferStateToFill(tx_state_));
43 }
44
45 int in_endpoint_max_size() const { return report_max_size_; }
46
47 void Initialize() override;
48
49 SetupResponse HandleEndpoint0SetupPacket(
50 const UsbDevice::SetupPacket &setup_packet) override;
51 SetupResponse HandleGetDescriptor(
52 const UsbDevice::SetupPacket &setup_packet) override;
53
Brian Silvermand930f282017-11-04 23:09:12 -040054 void HandleInFinished(int endpoint, BdtEntry *bdt_entry,
55 EvenOdd odd) override;
56
57 void HandleConfigured(int endpoint) override;
58 void HandleReset() override {
59 tx_state_ = EndpointBufferState::kBothEmptyEvenFirst;
60 device()->SetBdtEntry(in_endpoint_, Direction::kTx, EvenOdd::kEven,
61 {0, nullptr});
62 device()->SetBdtEntry(in_endpoint_, Direction::kTx, EvenOdd::kOdd,
63 {0, nullptr});
64 {
65 DisableInterrupts disable_interrupts;
66 memset(report_tx_buffers_[0].data(), 0, kMaxReportSize);
67 memset(report_tx_buffers_[1].data(), 0, kMaxReportSize);
68 }
69 }
70
71 ::std::array<::std::array<uint8_t, kMaxReportSize>, 2> report_tx_buffers_;
72 ::std::array<uint8_t, kMaxReportSize> get_report_response_buffer_;
73
74 // This is only manipulated with interrupts disabled.
75 EndpointBufferState tx_state_;
76 Data01 next_tx_toggle_;
77
78 // Our interface number.
79 int interface_;
80
81 // The IN endpoint we send reports on.
82 int in_endpoint_;
83
84 const int report_max_size_;
85};
86
87} // namespace teensy
88} // namespace frc971
89
90#endif // MOTORS_USB_HID_H_