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