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