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