Get a basic USB device working
It enumerates, takes its address, gets configured, and then Linux kind
of gives up because it has no endpoints.
Change-Id: I01f75acee419b585e455f428ee45bcd37f0ce189
diff --git a/motors/usb/constants.h b/motors/usb/constants.h
new file mode 100644
index 0000000..58c9ecc
--- /dev/null
+++ b/motors/usb/constants.h
@@ -0,0 +1,114 @@
+#ifndef MOTORS_USB_CONSTANTS_H_
+#define MOTORS_USB_CONSTANTS_H_
+
+#include <stdint.h>
+
+namespace frc971 {
+namespace teensy {
+
+enum class Direction : uint32_t {
+ kTx = 1 << 1,
+ kRx = 0,
+};
+
+enum class EvenOdd : uint32_t {
+ kOdd = 1 << 0,
+ kEven = 0,
+};
+
+constexpr static inline EvenOdd EvenOddInverse(EvenOdd odd) {
+ return static_cast<EvenOdd>(static_cast<uint32_t>(odd) ^
+ static_cast<uint32_t>(EvenOdd::kOdd));
+}
+
+// Returns 0 for kEven and 1 for kOdd. This is useful for indexing into arrays
+// and similar things.
+constexpr static inline int EvenOddIndex(EvenOdd odd) {
+ static_assert(static_cast<int>(EvenOdd::kOdd) == 1, "Value changed");
+ return static_cast<int>(odd);
+}
+
+enum class EndpointBufferState : int {
+ // The values are chosen carefully so bit arithmetic can efficiently
+ // manipulate these values. This math is all encapsulated in methods
+ // immediately following.
+ // Bit 0 is even full.
+ // Bit 1 is odd full.
+ // Bit 2 is which one to fill next (1 for odd).
+ // Bit 3 is which one to empty next (1 for odd).
+
+ // Both are empty and we should fill the even one first.
+ kBothEmptyEvenFirst = 0x0,
+ kBothEmptyOddFirst = 0xC,
+ kEvenFull = 0x5,
+ kOddFull = 0xA,
+ // Both are full and we should empty the even one first.
+ kBothFullEvenFirst = 0x3,
+ kBothFullOddFirst = 0xF,
+};
+
+// kBothEmptyEvenFirst fill even kEvenFull fill odd kBothFullEvenFirst
+// empty even kOddFull empty odd kBothEmptyEvenFirst
+
+// Returns true if state has at least one empty buffer.
+constexpr static inline bool BufferStateHasEmpty(EndpointBufferState state) {
+ return (static_cast<int>(state) & 0x3) != 0x3;
+}
+
+// Returns true if state has at least one full buffer.
+constexpr static inline bool BufferStateHasFull(EndpointBufferState state) {
+ return (static_cast<int>(state) & 0x3) != 0;
+}
+
+// Returns the next buffer to fill from state.
+//
+// This won't make sense if !BufferStateHasEmpty(state).
+constexpr static inline EvenOdd BufferStateToFill(EndpointBufferState state) {
+ return (static_cast<int>(state) & 0x4) ? EvenOdd::kOdd : EvenOdd::kEven;
+}
+
+// Returns the next buffer to empty from state.
+//
+// This won't make sense if !BufferStateHasFull(state).
+constexpr static inline EvenOdd BufferStateToEmpty(EndpointBufferState state) {
+ return (static_cast<int>(state) & 0x8) ? EvenOdd::kOdd : EvenOdd::kEven;
+}
+
+// Returns the new state after filling BufferStateToFill(state).
+//
+// This won't make sense if !BufferStateHasEmpty(state).
+constexpr static inline EndpointBufferState BufferStateAfterFill(
+ EndpointBufferState state) {
+ return static_cast<EndpointBufferState>(
+ // XOR with bit 2 to toggle which is next.
+ (static_cast<int>(state) ^ 0x4) |
+ // Set the bit corresponding to the buffer which was filled.
+ (1 << EvenOddIndex(BufferStateToFill(state))));
+}
+
+// Returns the new state after emptying BufferStateToEmpty(state).
+//
+// This won't make sense if !BufferStateHasFull(state).
+constexpr static inline EndpointBufferState BufferStateAfterEmpty(
+ EndpointBufferState state) {
+ return static_cast<EndpointBufferState>(
+ // XOR with bit 3 to toggle which is next.
+ (static_cast<int>(state) ^ 0x8) &
+ // Clear the bit corresponding to the buffer which was emptied.
+ ~(1 << EvenOddIndex(BufferStateToEmpty(state))));
+}
+
+enum class Data01 : uint32_t {
+ kData1 = 1 << 6,
+ kData0 = 0,
+};
+
+constexpr static inline Data01 Data01Inverse(Data01 toggle) {
+ return static_cast<Data01>(static_cast<uint32_t>(toggle) ^
+ static_cast<uint32_t>(Data01::kData1));
+}
+
+} // namespace teensy
+} // namespace frc971
+
+#endif // MOTORS_USB_CONSTANTS_H_