blob: 019231c7701f341930c161424d82a4efc31fb549 [file] [log] [blame]
#ifndef MOTORS_USB_HID_H_
#define MOTORS_USB_HID_H_
#include <stdint.h>
#include <string.h>
#include <array>
#include "motors/usb/usb.h"
#include "motors/util.h"
namespace frc971 {
namespace teensy {
// Implements an HID class device.
// TODO(Brian): Make this way more generic.
class HidFunction final : public UsbFunction {
public:
HidFunction(UsbDevice *device, int report_max_size)
: UsbFunction(device), report_max_size_(report_max_size) {
if (report_max_size_ > kMaxReportSize) {
__builtin_trap();
}
}
~HidFunction() override = default;
// Sets the report descriptor. Must be called at least once.
//
// May only be called during setup.
void set_report_descriptor(const ::std::string &report_descriptor) {
report_descriptor_ = report_descriptor;
}
void UpdateReport(const void *data, int length,
const DisableInterrupts &disable_interrupts) {
memcpy(report_tx_buffer_to_fill(disable_interrupts), data, length);
}
private:
// Choose 64 for now so it always fits into a single packet.
static constexpr int kMaxReportSize = 64;
uint8_t *report_tx_buffer_for(EvenOdd odd) {
return report_tx_buffers_[EvenOddIndex(odd)].data();
}
uint8_t *report_tx_buffer_being_sent(const DisableInterrupts &) {
return report_tx_buffer_for(BufferStateToEmpty(tx_state_));
}
uint8_t *report_tx_buffer_to_fill(const DisableInterrupts &) {
return report_tx_buffer_for(BufferStateToFill(tx_state_));
}
int in_endpoint_max_size() const { return report_max_size_; }
void Initialize() override;
SetupResponse HandleEndpoint0SetupPacket(
const UsbDevice::SetupPacket &setup_packet) override;
SetupResponse HandleGetDescriptor(
const UsbDevice::SetupPacket &setup_packet) override;
void HandleInFinished(int endpoint, BdtEntry *bdt_entry,
EvenOdd odd) override;
void HandleConfigured(int endpoint) override;
void HandleReset() override {
tx_state_ = EndpointBufferState::kBothEmptyEvenFirst;
device()->SetBdtEntry(in_endpoint_, Direction::kTx, EvenOdd::kEven,
{0, nullptr});
device()->SetBdtEntry(in_endpoint_, Direction::kTx, EvenOdd::kOdd,
{0, nullptr});
{
DisableInterrupts disable_interrupts;
memset(report_tx_buffers_[0].data(), 0, kMaxReportSize);
memset(report_tx_buffers_[1].data(), 0, kMaxReportSize);
}
}
::std::array<::std::array<uint8_t, kMaxReportSize>, 2> report_tx_buffers_;
::std::array<uint8_t, kMaxReportSize> get_report_response_buffer_;
// This is only manipulated with interrupts disabled.
EndpointBufferState tx_state_;
Data01 next_tx_toggle_;
// Our interface number.
int interface_;
// The IN endpoint we send reports on.
int in_endpoint_;
const int report_max_size_;
::std::string report_descriptor_;
UsbDescriptorList hid_descriptor_list_;
};
} // namespace teensy
} // namespace frc971
#endif // MOTORS_USB_HID_H_