blob: f7c7437d913441efb1048520d0b028217ab69e04 [file] [log] [blame]
Brian Silvermaneda63f32017-10-08 18:57:33 -04001#ifndef MOTORS_USB_CDC_H_
2#define MOTORS_USB_CDC_H_
3
4#include <array>
5
6#include "motors/usb/usb.h"
7#include "motors/usb/queue.h"
8#include "motors/util.h"
9
10// CDC (Communications Device Class) is a "class standard" which takes 30 pages
11// to explain that a communications device has communications and data, and they
12// can come via separate interfaces or the same ones, and the data can be in a
13// lot of formats. The only commonality across the "class" seems to be some
14// constants and a few descriptors.
15
16namespace frc971 {
17namespace teensy {
18
19struct CdcLineCoding {
20 static constexpr uint8_t stop_bits_1() { return 0; }
21 static constexpr uint8_t stop_bits_1_5() { return 1; }
22 static constexpr uint8_t stop_bits_2() { return 2; }
23
24 static constexpr uint8_t parity_none() { return 0; }
25 static constexpr uint8_t parity_odd() { return 1; }
26 static constexpr uint8_t parity_even() { return 2; }
27 static constexpr uint8_t parity_mark() { return 3; }
28 static constexpr uint8_t parity_space() { return 4; }
29
30 // The baud rate in bits/second.
31 uint32_t rate; // dwDTERate
32
33 uint8_t stop_bits; // bCharFormat
34
35 uint8_t parity; // bParityType
36
37 // 5, 6, 7, 8, or 16 according to the standard.
38 uint8_t data_bits; // bDataBits
39} __attribute__((packed));
40static_assert(sizeof(CdcLineCoding) == 7, "wrong size");
41
42// Implements a pretty dumb serial port via CDC's ACM (Abstract Control
43// Management) and Call Management functions.
44class AcmTty final : public UsbFunction {
45 public:
46 AcmTty(UsbDevice *device) : UsbFunction(device) {}
47 ~AcmTty() override = default;
48
49 size_t Read(void *buffer, size_t buffer_size);
50 size_t Write(const void *buffer, size_t buffer_size);
51
52 private:
53 enum class NextEndpoint0Out {
54 kNone,
55 kLineCoding,
56 };
57
58 // We're going with the largest allowable sizes for full speed devices for
59 // the data endpoints to maximize throughput.
60 static constexpr uint16_t kDataMaxPacketSize = 64;
61
62 // We have no information to send here, so no point allocating bus bandwidth
63 // for it.
64 static constexpr uint16_t kStatusMaxPacketSize = 1;
65
66 ::std::array<::std::array<char, kDataMaxPacketSize>, 2> tx_buffers_,
67 rx_buffers_;
68
69 void Initialize() override;
70
71 SetupResponse HandleEndpoint0SetupPacket(
72 const UsbDevice::SetupPacket &setup_packet) override;
73 SetupResponse HandleEndpoint0OutPacket(void *data, int data_length) override;
74 void HandleOutFinished(int endpoint, BdtEntry *bdt_entry) override;
75 void HandleInFinished(int endpoint, BdtEntry *bdt_entry,
76 EvenOdd odd) override;
77 void HandleConfigured(int endpoint) override;
78 void HandleReset() override {
79 // TODO(Brian): Handle data already in the buffers correctly.
80 DisableInterrupts disable_interrupts;
81 tx_state_ = EndpointBufferState::kBothEmptyEvenFirst;
82 device()->SetBdtEntry(status_endpoint_, Direction::kTx, EvenOdd::kEven,
83 {0, nullptr});
84 device()->SetBdtEntry(status_endpoint_, Direction::kTx, EvenOdd::kOdd,
85 {0, nullptr});
86 device()->SetBdtEntry(data_tx_endpoint_, Direction::kTx, EvenOdd::kEven,
87 {0, nullptr});
88 device()->SetBdtEntry(data_tx_endpoint_, Direction::kTx, EvenOdd::kOdd,
89 {0, nullptr});
90 device()->SetBdtEntry(data_rx_endpoint_, Direction::kRx, EvenOdd::kEven,
91 {0, nullptr});
92 device()->SetBdtEntry(data_rx_endpoint_, Direction::kRx, EvenOdd::kOdd,
93 {0, nullptr});
94 }
95
96 char *tx_buffer_for(EvenOdd odd) {
97 return tx_buffers_[EvenOddIndex(odd)].data();
98 }
99
100 void EnqueueTxData(const DisableInterrupts &);
101
102 // In theory, we could sent notifications over this about things like the line
103 // state, but we don't have anything to report so we pretty much just ignore
104 // this.
105 int status_interface_;
106 int data_interface_;
107 int status_endpoint_, data_tx_endpoint_, data_rx_endpoint_;
108
109 Queue tx_queue_{1024}, rx_queue_{1024};
110
111 NextEndpoint0Out next_endpoint0_out_ = NextEndpoint0Out::kNone;
112
113 // This is only manipulated with interrupts disabled.
114 EndpointBufferState tx_state_;
115 Data01 next_tx_toggle_;
116
117 // These are BdtEntries which we're holding into without releasing back to the
118 // hardware so that we won't receive any more data until we have space for it.
119 // They are only manipulated with interrupts disabled.
120 BdtEntry *first_rx_held_ = nullptr, *second_rx_held_ = nullptr;
121 Data01 next_rx_toggle_;
122
123 CdcLineCoding line_coding_{0, CdcLineCoding::stop_bits_1(),
124 CdcLineCoding::parity_none(), 8};
125 CdcLineCoding line_coding_to_send_;
126
127 uint16_t control_line_state_ = 0;
128};
129
130} // namespace teensy
131} // namespace frc971
132
133#endif // MOTORS_USB_CDC_H_