blob: c02873d28c5ba634a295220d99d9c9b69ab11d5d [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
Brian Silverman19ea60f2018-01-03 21:43:15 -080052 bool write_queue_empty() const { return tx_queue_.empty(); }
53
Brian Silvermaneda63f32017-10-08 18:57:33 -040054 private:
55 enum class NextEndpoint0Out {
56 kNone,
57 kLineCoding,
58 };
59
60 // We're going with the largest allowable sizes for full speed devices for
61 // the data endpoints to maximize throughput.
62 static constexpr uint16_t kDataMaxPacketSize = 64;
63
64 // We have no information to send here, so no point allocating bus bandwidth
65 // for it.
66 static constexpr uint16_t kStatusMaxPacketSize = 1;
67
Brian Silvermaneda63f32017-10-08 18:57:33 -040068 void Initialize() override;
69
70 SetupResponse HandleEndpoint0SetupPacket(
71 const UsbDevice::SetupPacket &setup_packet) override;
72 SetupResponse HandleEndpoint0OutPacket(void *data, int data_length) override;
73 void HandleOutFinished(int endpoint, BdtEntry *bdt_entry) override;
74 void HandleInFinished(int endpoint, BdtEntry *bdt_entry,
75 EvenOdd odd) override;
76 void HandleConfigured(int endpoint) override;
77 void HandleReset() override {
78 // TODO(Brian): Handle data already in the buffers correctly.
79 DisableInterrupts disable_interrupts;
80 tx_state_ = EndpointBufferState::kBothEmptyEvenFirst;
81 device()->SetBdtEntry(status_endpoint_, Direction::kTx, EvenOdd::kEven,
82 {0, nullptr});
83 device()->SetBdtEntry(status_endpoint_, Direction::kTx, EvenOdd::kOdd,
84 {0, nullptr});
85 device()->SetBdtEntry(data_tx_endpoint_, Direction::kTx, EvenOdd::kEven,
86 {0, nullptr});
87 device()->SetBdtEntry(data_tx_endpoint_, Direction::kTx, EvenOdd::kOdd,
88 {0, nullptr});
89 device()->SetBdtEntry(data_rx_endpoint_, Direction::kRx, EvenOdd::kEven,
90 {0, nullptr});
91 device()->SetBdtEntry(data_rx_endpoint_, Direction::kRx, EvenOdd::kOdd,
92 {0, nullptr});
93 }
94
95 char *tx_buffer_for(EvenOdd odd) {
96 return tx_buffers_[EvenOddIndex(odd)].data();
97 }
98
99 void EnqueueTxData(const DisableInterrupts &);
100
Brian Silvermand930f282017-11-04 23:09:12 -0400101 ::std::array<::std::array<char, kDataMaxPacketSize>, 2> tx_buffers_,
102 rx_buffers_;
103
Brian Silvermaneda63f32017-10-08 18:57:33 -0400104 // In theory, we could sent notifications over this about things like the line
105 // state, but we don't have anything to report so we pretty much just ignore
106 // this.
107 int status_interface_;
108 int data_interface_;
109 int status_endpoint_, data_tx_endpoint_, data_rx_endpoint_;
110
111 Queue tx_queue_{1024}, rx_queue_{1024};
112
113 NextEndpoint0Out next_endpoint0_out_ = NextEndpoint0Out::kNone;
114
115 // This is only manipulated with interrupts disabled.
116 EndpointBufferState tx_state_;
117 Data01 next_tx_toggle_;
118
Brian Silverman4aa83042018-01-05 12:47:31 -0800119 // These are BdtEntries which we're holding onto without releasing back to the
Brian Silvermaneda63f32017-10-08 18:57:33 -0400120 // hardware so that we won't receive any more data until we have space for it.
121 // They are only manipulated with interrupts disabled.
122 BdtEntry *first_rx_held_ = nullptr, *second_rx_held_ = nullptr;
123 Data01 next_rx_toggle_;
124
125 CdcLineCoding line_coding_{0, CdcLineCoding::stop_bits_1(),
126 CdcLineCoding::parity_none(), 8};
127 CdcLineCoding line_coding_to_send_;
128
129 uint16_t control_line_state_ = 0;
130};
131
132} // namespace teensy
133} // namespace frc971
134
135#endif // MOTORS_USB_CDC_H_