blob: bd2e665db35cac445bf049904663ea4da74958a7 [file] [log] [blame]
Brian Silverman1e869f32013-10-25 18:00:20 -07001#include <string.h>
2#include <errno.h>
3#include <inttypes.h>
4
5#include "frc971/input/usb_receiver.h"
6
7#include "aos/common/logging/logging.h"
8#include "aos/common/control_loop/ControlLoop.h"
9
10namespace frc971 {
11
12USBReceiver::USBReceiver() {
13 Reset();
14}
15
16void USBReceiver::RunIteration() {
17 if (ReceiveData()) {
18 Reset();
19 } else {
20 const ::aos::time::Time received_time = ::aos::time::Time::Now();
Brian Silverman74acd622013-10-26 14:47:14 -070021 if (phase_locker_.IsCurrentPacketGood(received_time, sequence_)) {
22 LOG(DEBUG, "processing data %" PRIu32 "\n", sequence_);
Brian Silverman1e869f32013-10-25 18:00:20 -070023 ProcessData();
24 }
25 }
26}
27
28void USBReceiver::PhaseLocker::Reset() {
29 LOG(INFO, "resetting\n");
30 last_good_packet_time_ = ::aos::time::Time(0, 0);
Brian Silverman74acd622013-10-26 14:47:14 -070031 last_good_sequence_ = 0;
Brian Silverman1e869f32013-10-25 18:00:20 -070032 good_phase_ = guess_phase_ = kUnknownPhase;
33 guess_phase_good_ = guess_phase_bad_ = 0;
34 good_phase_early_ = good_phase_late_ = 0;
35}
36
37bool USBReceiver::PhaseLocker::IsCurrentPacketGood(
38 const ::aos::time::Time &received_time,
Brian Silverman74acd622013-10-26 14:47:14 -070039 uint32_t sequence) {
Brian Silverman1e869f32013-10-25 18:00:20 -070040 if (last_good_packet_time_ != ::aos::time::Time(0, 0) &&
41 received_time - last_good_packet_time_ > kResetTime) {
42 LOG(WARNING, "no good packet received in too long\n");
43 Reset();
44 return false;
45 }
Brian Silverman74acd622013-10-26 14:47:14 -070046 if (last_good_sequence_ != 0 && sequence - last_good_sequence_ > 100) {
Brian Silverman1e869f32013-10-25 18:00:20 -070047 LOG(WARNING, "skipped too many packets\n");
48 Reset();
49 return false;
50 }
Brian Silverman74acd622013-10-26 14:47:14 -070051 if (sequence < last_good_sequence_) {
52 LOG(WARNING, "sequence went down. gyro board reset?\n");
53 Reset();
54 return false;
55 }
Brian Silverman1e869f32013-10-25 18:00:20 -070056
57 using ::aos::control_loops::kLoopFrequency;
58 // How often we (should) receive packets.
59 static const ::aos::time::Time kPacketFrequency =
60 kLoopFrequency / kPacketsPerLoopCycle;
61 static const ::aos::time::Time kPacketClose =
62 kPacketFrequency * 65 / 100;
63 static const ::aos::time::Time kSwitchOffset =
64 kPacketFrequency * 6 / 10;
65
66 // When we want to receive a packet for the next cycle of control loops.
67 ::aos::time::Time next_desired =
68 ::aos::control_loops::NextLoopTime(received_time) + kDesiredOffset;
69 // If we came up with something more than 1 packet in the past.
70 if (next_desired - received_time < -kPacketFrequency) {
71 next_desired += kLoopFrequency;
72 }
73 // How far off of when we want the next packet this one is.
74 const ::aos::time::Time offset = next_desired - received_time;
75
76 const int received_phase = sequence % kPacketsPerLoopCycle;
77
78 assert(!(good_phase_early_ != 0 && good_phase_late_ != 0));
79
80 if (good_phase_ == kUnknownPhase &&
81 guess_phase_good_ > kMinGoodGuessCycles) {
82 good_phase_ = guess_phase_;
83 if (guess_phase_offset_ < kPacketFrequency / -2) {
84 ++good_phase_;
85 } else if (guess_phase_offset_ > kPacketFrequency / 2) {
86 --good_phase_;
87 }
88 LOG(INFO, "locked on to phase %d\n", good_phase_);
89 } else if (guess_phase_bad_ > kMaxBadGuessCycles) {
90 LOG(INFO, "guessed wrong phase too many times\n");
91 Reset();
92 }
93 if (good_phase_early_ > kSwitchCycles) {
94 good_phase_early_ = 0;
95 LOG(INFO, "switching from phase %d to %d-1\n",
96 good_phase_, good_phase_);
97 --good_phase_;
98 } else if (good_phase_late_ > kSwitchCycles) {
99 good_phase_late_ = 0;
100 LOG(INFO, "switching from phase %d to %d+1\n",
101 good_phase_, good_phase_);
102 ++good_phase_;
103 }
104 if (good_phase_ == kUnknownPhase) {
105 LOG(DEBUG, "guessing which packet is good\n");
106
107 // If it's close to the right time.
108 if (offset.abs() < kPacketClose) {
109 if (guess_phase_ == kUnknownPhase) {
110 if (offset.abs() < kPacketFrequency * 55 / 100) {
111 guess_phase_ = received_phase;
112 guess_phase_offset_ = offset;
113 }
114 } else if (received_phase == guess_phase_) {
115 LOG(DEBUG, "guessed right phase %d\n", received_phase);
116 ++guess_phase_good_;
117 guess_phase_bad_ = 0;
118 guess_phase_offset_ = (guess_phase_offset_ * 9 + offset) / 10;
119 }
120 } else if (guess_phase_ != kUnknownPhase &&
121 received_phase == guess_phase_) {
122 LOG(DEBUG, "guessed wrong phase %d\n", received_phase);
123 ++guess_phase_bad_;
124 guess_phase_good_ = ::std::max(0, guess_phase_good_ -
125 (kMinGoodGuessCycles / 10));
126 }
127 return false;
128 } else { // we know what phase we're looking for
129 // Deal with it if the above logic for tweaking the phase that we're
130 // using wrapped it around.
131 if (good_phase_ == -1) {
132 good_phase_ = kPacketsPerLoopCycle;
133 } else if (good_phase_ == kPacketsPerLoopCycle) {
134 LOG(DEBUG, "dewrapping\n");
135 good_phase_ = 0;
136 }
137 assert(good_phase_ >= 0);
138 assert(good_phase_ < kPacketsPerLoopCycle);
139
140 if (received_phase == good_phase_) {
141 if (offset < -kSwitchOffset) {
142 ++good_phase_early_;
143 good_phase_late_ = 0;
144 } else if (offset > kSwitchOffset) {
145 ++good_phase_late_;
146 good_phase_early_ = 0;
147 } else {
148 good_phase_early_ = good_phase_late_ = 0;
149 }
150 last_good_packet_time_ = received_time;
151 last_good_sequence_ = sequence;
152
153 return true;
154 } else {
155 return false;
156 }
157 }
158}
159
160void USBReceiver::StaticTransferCallback(libusb::Transfer *transfer,
161 void *self) {
162 static_cast<USBReceiver *>(self)->TransferCallback(transfer);
163}
164
165void USBReceiver::TransferCallback(libusb::Transfer *transfer) {
166 if (transfer->status() == LIBUSB_TRANSFER_COMPLETED) {
167 LOG(DEBUG, "transfer %p completed\n", transfer);
168 completed_transfer_ = transfer;
169 } else if (transfer->status() == LIBUSB_TRANSFER_TIMED_OUT) {
170 LOG(WARNING, "transfer %p timed out\n", transfer);
171 completed_transfer_ = kTransferFailed;
172 } else if (transfer->status() == LIBUSB_TRANSFER_CANCELLED) {
173 LOG(DEBUG, "transfer %p cancelled\n", transfer);
174 } else {
175 LOG(FATAL, "transfer %p has status %d\n", transfer, transfer->status());
176 }
177 transfer->Submit();
178}
179
180bool USBReceiver::ReceiveData() {
181 // Loop and then return once we get a good one.
182 while (true) {
183 completed_transfer_ = NULL;
184 while (completed_transfer_ == NULL) {
185 libusb_.HandleEvents();
186 }
187 if (completed_transfer_ == kTransferFailed) {
188 LOG(WARNING, "transfer failed\n");
189 return true;
190 }
191
192 if (completed_transfer_->read_bytes() <
193 static_cast<ssize_t>(sizeof(GyroBoardData))) {
194 LOG(ERROR, "read %d bytes instead of at least %zd\n",
195 completed_transfer_->read_bytes(), sizeof(GyroBoardData));
196 continue;
197 }
198
199 memcpy(data(), completed_transfer_->data(),
200 sizeof(GyroBoardData));
201
Brian Silverman74acd622013-10-26 14:47:14 -0700202 uint32_t sequence_before = sequence_;
203 sequence_ = data()->sequence;
204 if (sequence_before == 0) {
205 LOG(INFO, "count starting at %" PRIu32 "\n", sequence_);
206 } else if (sequence_ - sequence_before != 1) {
207 LOG(WARNING, "count went from %" PRIu32" to %" PRIu32 "\n",
208 sequence_before, sequence_);
Brian Silverman1e869f32013-10-25 18:00:20 -0700209 }
210
211 return false;
212 }
213}
214
215void USBReceiver::Reset() {
216 typedef ::std::unique_ptr<libusb::IsochronousTransfer> TransferType;
217 for (TransferType &c : transfers_) {
218 c.reset();
219 }
220 dev_handle_ = ::std::unique_ptr<LibUSBDeviceHandle>(
221 libusb_.FindDeviceWithVIDPID(kVid, kPid));
222 if (!dev_handle_) {
223 LOG(ERROR, "couldn't find device. exiting\n");
224 exit(1);
225 }
226 for (TransferType &c : transfers_) {
227 c.reset(new libusb::IsochronousTransfer(kDataLength, 1,
228 StaticTransferCallback, this));
229 c->FillIsochronous(dev_handle_.get(), kEndpoint, kReadTimeout);
230 c->Submit();
231 }
232
Brian Silverman74acd622013-10-26 14:47:14 -0700233 sequence_ = 0;
Brian Silverman1e869f32013-10-25 18:00:20 -0700234 phase_locker_.Reset();
235}
236
237constexpr ::aos::time::Time USBReceiver::kReadTimeout;
238constexpr ::aos::time::Time USBReceiver::kDesiredOffset;
239constexpr ::aos::time::Time USBReceiver::kResetTime;
240
241} // namespace frc971