blob: 0b0dd60afb7190807b03a31f609cf2e8d83d95dc [file] [log] [blame]
Brian Silverman1e869f32013-10-25 18:00:20 -07001#ifndef FRC971_INPUT_USB_RECEIVER_H_
2#define FRC971_INPUT_USB_RECEIVER_H_
3
4#include <memory>
5
6#include "aos/common/time.h"
Brian Silverman1e869f32013-10-25 18:00:20 -07007
8#include "gyro_board/src/libusb-driver/libusb_wrap.h"
9#include "frc971/input/gyro_board_data.h"
10
11namespace frc971 {
12
13// TODO(brians): Figure out how to deal with the kernel bunching packets up on
14// us.
15class USBReceiver {
16 public:
17 USBReceiver();
18
19 void RunIteration();
20
Brian Silvermanf3cfbd72013-10-28 16:26:09 -070021 // The relative priority that tasks doing this should get run at (ie what to
22 // pass to ::aos::Init(int)).
23 static const int kRelativePriority = 5;
24
Brian Silverman1e869f32013-10-25 18:00:20 -070025 protected:
26 GyroBoardData *data() { return &data_; }
27
28 private:
29 static const unsigned char kEndpoint = 0x83;
30 // 0 is unlimited
31 static constexpr ::aos::time::Time kReadTimeout =
32 ::aos::time::Time::InSeconds(1.5);
33 // vendor ID
34 static const int32_t kVid = 0x1424;
35 // product ID
36 static const int32_t kPid = 0xd243;
37
38 // A value to put into completed_transfer_ to indicate that it failed.
39 static constexpr libusb::Transfer *kTransferFailed =
40 reinterpret_cast<libusb::Transfer *>(-1);
41 // The kernel on the fitpc seems to miss ~11-15 packets in a row if it misses
42 // any with just 2, so 25 should be enough to ride over any holes.
43 static const int kNumTransfers = 25;
44
45 // How big of a buffer we're going to give the usb transfer stuff.
46 static const size_t kDataLength = 128;
47 static_assert(kDataLength >= sizeof(GyroBoardData), "buffer is too small");
48
49 static const int kPacketsPerLoopCycle = 10;
50
51 // How long "after" the control loops run we want to use a packet.
52 static constexpr ::aos::time::Time kDesiredOffset =
53 ::aos::time::Time::InSeconds(-0.003);
54
55 // How long without a good packet until we give up and Reset().
56 static constexpr ::aos::time::Time kResetTime =
57 ::aos::time::Time::InSeconds(0.25);
58
59 // Contains all of the complicated state and logic for locking onto the the
60 // correct phase.
61 class PhaseLocker {
62 public:
63 void Reset();
64
65 // Gets called for every packet received.
66 // Returns whether or not to process the values from this packet.
67 bool IsCurrentPacketGood(const ::aos::time::Time &received_time,
Brian Silverman74acd622013-10-26 14:47:14 -070068 uint32_t sequence);
Brian Silverman1e869f32013-10-25 18:00:20 -070069
70 private:
71 // How many times the packet we guessed has to be close to right to use the
72 // guess.
73 static const int kMinGoodGuessCycles = 30;
74 // How many times in a row we have to guess the wrong packet before trying
75 // again.
76 static const int kMaxBadGuessCycles = 3;
77
78 // How many times in a row a different packet has to be better than the one
79 // that we're using befor switching to it.
80 static const int kSwitchCycles = 15;
81
82 ::aos::time::Time last_good_packet_time_{0, 0};
83
Brian Silverman74acd622013-10-26 14:47:14 -070084 uint32_t last_good_sequence_;
Brian Silverman1e869f32013-10-25 18:00:20 -070085
86 const int kUnknownPhase = -11;
87 // kUnknownPhase or the sequence number (%kPacketsPerLoopCycle) to
88 // use or think about using.
89 // If not kUnknownPhase, 0 <= these < kPacketsPerLoopCycle.
90 int good_phase_, guess_phase_;
91 int guess_phase_good_, guess_phase_bad_;
92 ::aos::time::Time guess_phase_offset_{0, 0};
93 int good_phase_early_, good_phase_late_;
94 } phase_locker_;
95
96 static void StaticTransferCallback(libusb::Transfer *transfer, void *self);
97 void TransferCallback(libusb::Transfer *transfer);
98
99 // Returns true if receiving failed and we should try a Reset().
100 bool ReceiveData();
101
102 void Reset();
103
104 virtual void ProcessData() = 0;
105
106 GyroBoardData data_;
107
Brian Silverman74acd622013-10-26 14:47:14 -0700108 uint32_t sequence_;
Brian Silverman1e869f32013-10-25 18:00:20 -0700109
110 LibUSB libusb_;
111 ::std::unique_ptr<LibUSBDeviceHandle> dev_handle_;
112 ::std::unique_ptr<libusb::IsochronousTransfer> transfers_[kNumTransfers];
113 // "Temporary" variable for holding a completed transfer to communicate that
114 // information from the callback to the code that wants it.
115 libusb::Transfer *completed_transfer_;
116};
117
118} // namespace frc971
119
120#endif // FRC971_INPUT_USB_RECEIVER_H_