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