blob: 20c31bf3dc7d7c50236986251962722bec8f985a [file] [log] [blame]
Brian Silvermanf4937f62013-10-16 10:32:00 -07001#include <string.h>
2
Brian Silverman2e0dcfd2013-03-30 22:44:40 -07003#include <memory>
4
5#include "aos/common/inttypes.h"
6#include "aos/atom_code/init.h"
7#include "aos/common/logging/logging.h"
8#include "aos/common/time.h"
Brian Silvermanf4937f62013-10-16 10:32:00 -07009#include "aos/common/util/wrapping_counter.h"
10#include "aos/common/control_loop/ControlLoop.h"
Brian Silverman2e0dcfd2013-03-30 22:44:40 -070011
12#include "frc971/control_loops/drivetrain/drivetrain.q.h"
13#include "frc971/control_loops/wrist/wrist_motor.q.h"
14#include "frc971/control_loops/angle_adjust/angle_adjust_motor.q.h"
15#include "frc971/control_loops/index/index_motor.q.h"
16#include "frc971/control_loops/shooter/shooter_motor.q.h"
17#include "frc971/input/gyro_board_data.h"
Brian Silverman2e0dcfd2013-03-30 22:44:40 -070018#include "frc971/queues/GyroAngle.q.h"
Brian Silverman4bde0172013-10-25 15:53:25 -070019#include "gyro_board/src/libusb-driver/libusb_wrap.h"
Brian Silverman2e0dcfd2013-03-30 22:44:40 -070020
21#ifndef M_PI
22#define M_PI 3.14159265358979323846
23#endif
24
25using ::frc971::control_loops::drivetrain;
26using ::frc971::control_loops::wrist;
27using ::frc971::control_loops::angle_adjust;
28using ::frc971::control_loops::shooter;
29using ::frc971::control_loops::index_loop;
30using ::frc971::sensors::gyro;
Brian Silvermanf4937f62013-10-16 10:32:00 -070031using ::aos::util::WrappingCounter;
Brian Silverman2e0dcfd2013-03-30 22:44:40 -070032
33namespace frc971 {
34namespace {
35
36inline double drivetrain_translate(int32_t in) {
37 return static_cast<double>(in) / (256.0 /*cpr*/ * 4.0 /*quad*/) *
38 (19.0 / 50.0) /*output reduction*/ * (64.0 / 24.0) /*encoder gears*/ *
39 (3.5 /*wheel diameter*/ * 2.54 / 100.0 * M_PI);
40}
41
42inline double wrist_translate(int32_t in) {
43 return static_cast<double>(in) / (256.0 /*cpr*/ * 4.0 /*quad*/) *
44 (14.0 / 50.0 * 20.0 / 84.0) /*gears*/ * (2 * M_PI);
45}
46
47inline double angle_adjust_translate(int32_t in) {
48 static const double kCableDiameter = 0.060;
49 return -static_cast<double>(in) / (256.0 /*cpr*/ * 4.0 /*quad*/) *
50 ((0.75 + kCableDiameter) / (16.61125 + kCableDiameter)) /*pulleys*/ *
51 (2 * M_PI);
52}
53
54inline double shooter_translate(int32_t in) {
55 return static_cast<double>(in) / (32.0 /*cpr*/ * 4.0 /*quad*/) *
56 (15.0 / 34.0) /*gears*/ * (2 * M_PI);
57}
58
59inline double index_translate(int32_t in) {
60 return -static_cast<double>(in) / (128.0 /*cpr*/ * 4.0 /*quad*/) *
61 (1.0) /*gears*/ * (2 * M_PI);
62}
63
64} // namespace
65
Brian Silvermancaeed862013-10-25 17:32:19 -070066// TODO(brians): Figure out how to deal with the kernel bunching packets up on
67// us.
Brian Silvermanf4937f62013-10-16 10:32:00 -070068class GyroSensorReceiver {
Brian Silverman2e0dcfd2013-03-30 22:44:40 -070069 public:
Brian Silvermanf4937f62013-10-16 10:32:00 -070070 GyroSensorReceiver() {
71 Reset();
Brian Silverman2e0dcfd2013-03-30 22:44:40 -070072 }
73
Brian Silvermanf4937f62013-10-16 10:32:00 -070074 void RunIteration() {
75 if (ReceiveData()) {
76 Reset();
Brian Silvermanf92396c2013-09-12 20:13:13 -070077 } else {
Brian Silvermanf4937f62013-10-16 10:32:00 -070078 const ::aos::time::Time received_time = ::aos::time::Time::Now();
79 if (phase_locker_.IsCurrentPacketGood(received_time, sequence_.count())) {
Brian Silverman7643bbb2013-10-24 15:58:37 -070080 LOG(DEBUG, "processing data\n");
Brian Silvermanf4937f62013-10-16 10:32:00 -070081 ProcessData();
82 }
Brian Silvermanf92396c2013-09-12 20:13:13 -070083 }
Brian Silverman2e0dcfd2013-03-30 22:44:40 -070084 }
85
86 private:
Brian Silverman4bde0172013-10-25 15:53:25 -070087 static const unsigned char kEndpoint = 0x83;
Brian Silverman2e0dcfd2013-03-30 22:44:40 -070088 // 0 is unlimited
Brian Silvermanf4937f62013-10-16 10:32:00 -070089 static constexpr ::aos::time::Time kReadTimeout =
90 ::aos::time::Time::InSeconds(1.5);
Brian Silverman4bde0172013-10-25 15:53:25 -070091 // vendor ID
92 static const int32_t kVid = 0x1424;
93 // product ID
94 static const int32_t kPid = 0xd243;
95
96 // A value to put into completed_transfer_ to indicate that it failed.
97 static constexpr libusb::Transfer *kTransferFailed =
98 reinterpret_cast<libusb::Transfer *>(-1);
Brian Silverman1c3cfc02013-10-25 17:02:19 -070099 // The kernel on the fitpc seems to miss ~11-15 packets in a row if it misses
100 // any with just 2, so 25 should be enough to ride over any holes.
101 static const int kNumTransfers = 25;
Brian Silverman4bde0172013-10-25 15:53:25 -0700102
103 // How big of a buffer we're going to give the usb transfer stuff.
104 static const size_t kDataLength = 128;
105 static_assert(kDataLength >= sizeof(GyroBoardData), "buffer is too small");
Brian Silverman2e0dcfd2013-03-30 22:44:40 -0700106
Brian Silvermanf4937f62013-10-16 10:32:00 -0700107 static const int kPacketsPerLoopCycle = 10;
Brian Silverman2e0dcfd2013-03-30 22:44:40 -0700108
Brian Silverman1c3cfc02013-10-25 17:02:19 -0700109 // How long "after" the control loops run we want to use a packet.
Brian Silverman7643bbb2013-10-24 15:58:37 -0700110 static constexpr ::aos::time::Time kDesiredOffset =
Brian Silvermancaeed862013-10-25 17:32:19 -0700111 ::aos::time::Time::InSeconds(-0.003);
Brian Silverman7643bbb2013-10-24 15:58:37 -0700112
Brian Silverman1c3cfc02013-10-25 17:02:19 -0700113 // How long without a good packet until we give up and Reset().
114 static constexpr ::aos::time::Time kResetTime =
Brian Silvermancaeed862013-10-25 17:32:19 -0700115 ::aos::time::Time::InSeconds(0.25);
Brian Silverman1c3cfc02013-10-25 17:02:19 -0700116
Brian Silvermanf4937f62013-10-16 10:32:00 -0700117 // Contains all of the complicated state and logic for locking onto the the
118 // correct phase.
119 class {
120 public:
121 void Reset() {
Brian Silverman7643bbb2013-10-24 15:58:37 -0700122 LOG(INFO, "resetting\n");
Brian Silverman1c3cfc02013-10-25 17:02:19 -0700123 last_good_packet_time_ = ::aos::time::Time(0, 0);
Brian Silvermancaeed862013-10-25 17:32:19 -0700124 last_good_sequence_ = -1;
Brian Silvermanf4937f62013-10-16 10:32:00 -0700125 good_phase_ = guess_phase_ = kUnknownPhase;
126 guess_phase_good_ = guess_phase_bad_ = 0;
127 good_phase_early_ = good_phase_late_ = 0;
128 }
Brian Silverman9a574d52013-03-31 00:53:53 -0700129
Brian Silvermanf4937f62013-10-16 10:32:00 -0700130 // Gets called for every packet received.
131 // Returns whether or not to process the values from this packet.
132 bool IsCurrentPacketGood(const ::aos::time::Time &received_time,
133 int32_t sequence) {
Brian Silverman1c3cfc02013-10-25 17:02:19 -0700134 if (last_good_packet_time_ != ::aos::time::Time(0, 0) &&
135 received_time - last_good_packet_time_ > kResetTime) {
136 LOG(WARNING, "no good packet received in too long\n");
137 Reset();
138 return false;
139 }
Brian Silvermancaeed862013-10-25 17:32:19 -0700140 if (last_good_sequence_ != -1 && sequence - last_good_sequence_ > 100) {
141 LOG(WARNING, "skipped too many packets\n");
142 Reset();
143 return false;
144 }
Brian Silverman1c3cfc02013-10-25 17:02:19 -0700145
146 using ::aos::control_loops::kLoopFrequency;
Brian Silvermanf4937f62013-10-16 10:32:00 -0700147 // How often we (should) receive packets.
148 static const ::aos::time::Time kPacketFrequency =
Brian Silverman1c3cfc02013-10-25 17:02:19 -0700149 kLoopFrequency / kPacketsPerLoopCycle;
Brian Silverman7643bbb2013-10-24 15:58:37 -0700150 static const ::aos::time::Time kPacketClose =
151 kPacketFrequency * 65 / 100;
152 static const ::aos::time::Time kSwitchOffset =
153 kPacketFrequency * 6 / 10;
Brian Silvermanf4937f62013-10-16 10:32:00 -0700154
155 // When we want to receive a packet for the next cycle of control loops.
Brian Silverman1c3cfc02013-10-25 17:02:19 -0700156 ::aos::time::Time next_desired =
157 ::aos::control_loops::NextLoopTime(received_time) + kDesiredOffset;
158 // If we came up with something more than 1 packet in the past.
159 if (next_desired - received_time < -kPacketFrequency) {
160 next_desired += kLoopFrequency;
161 }
Brian Silvermanf4937f62013-10-16 10:32:00 -0700162 // How far off of when we want the next packet this one is.
163 const ::aos::time::Time offset = next_desired - received_time;
164
165 const int received_phase = sequence % kPacketsPerLoopCycle;
166
167 assert(!(good_phase_early_ != 0 && good_phase_late_ != 0));
168
Brian Silverman1c3cfc02013-10-25 17:02:19 -0700169 if (good_phase_ == kUnknownPhase &&
170 guess_phase_good_ > kMinGoodGuessCycles) {
Brian Silvermanf4937f62013-10-16 10:32:00 -0700171 good_phase_ = guess_phase_;
Brian Silverman7643bbb2013-10-24 15:58:37 -0700172 if (guess_phase_offset_ < kPacketFrequency / -2) {
Brian Silvermanf4937f62013-10-16 10:32:00 -0700173 ++good_phase_;
Brian Silverman7643bbb2013-10-24 15:58:37 -0700174 } else if (guess_phase_offset_ > kPacketFrequency / 2) {
Brian Silvermanf4937f62013-10-16 10:32:00 -0700175 --good_phase_;
176 }
Brian Silverman1c3cfc02013-10-25 17:02:19 -0700177 LOG(INFO, "locked on to phase %d\n", good_phase_);
Brian Silvermanf4937f62013-10-16 10:32:00 -0700178 } else if (guess_phase_bad_ > kMaxBadGuessCycles) {
Brian Silverman4bde0172013-10-25 15:53:25 -0700179 LOG(INFO, "guessed wrong phase too many times\n");
Brian Silvermanf4937f62013-10-16 10:32:00 -0700180 Reset();
181 }
182 if (good_phase_early_ > kSwitchCycles) {
183 good_phase_early_ = 0;
Brian Silverman1c3cfc02013-10-25 17:02:19 -0700184 LOG(INFO, "switching from phase %d to %d-1\n",
185 good_phase_, good_phase_);
Brian Silvermanf4937f62013-10-16 10:32:00 -0700186 --good_phase_;
187 } else if (good_phase_late_ > kSwitchCycles) {
188 good_phase_late_ = 0;
Brian Silverman1c3cfc02013-10-25 17:02:19 -0700189 LOG(INFO, "switching from phase %d to %d+1\n",
190 good_phase_, good_phase_);
Brian Silvermanf4937f62013-10-16 10:32:00 -0700191 ++good_phase_;
192 }
193 if (good_phase_ == kUnknownPhase) {
Brian Silvermancaeed862013-10-25 17:32:19 -0700194 LOG(DEBUG, "guessing which packet is good\n");
Brian Silvermanf4937f62013-10-16 10:32:00 -0700195
Brian Silvermanf4937f62013-10-16 10:32:00 -0700196 // If it's close to the right time.
Brian Silverman7643bbb2013-10-24 15:58:37 -0700197 if (offset.abs() < kPacketClose) {
Brian Silvermanf4937f62013-10-16 10:32:00 -0700198 if (guess_phase_ == kUnknownPhase) {
Brian Silverman7643bbb2013-10-24 15:58:37 -0700199 if (offset.abs() < kPacketFrequency * 55 / 100) {
Brian Silvermanf4937f62013-10-16 10:32:00 -0700200 guess_phase_ = received_phase;
201 guess_phase_offset_ = offset;
202 }
203 } else if (received_phase == guess_phase_) {
Brian Silverman4bde0172013-10-25 15:53:25 -0700204 LOG(DEBUG, "guessed right phase %d\n", received_phase);
Brian Silvermanf4937f62013-10-16 10:32:00 -0700205 ++guess_phase_good_;
206 guess_phase_bad_ = 0;
207 guess_phase_offset_ = (guess_phase_offset_ * 9 + offset) / 10;
208 }
209 } else if (guess_phase_ != kUnknownPhase &&
210 received_phase == guess_phase_) {
Brian Silverman4bde0172013-10-25 15:53:25 -0700211 LOG(DEBUG, "guessed wrong phase %d\n", received_phase);
Brian Silvermanf4937f62013-10-16 10:32:00 -0700212 ++guess_phase_bad_;
213 guess_phase_good_ = ::std::max(0, guess_phase_good_ -
214 (kMinGoodGuessCycles / 10));
215 }
Brian Silverman1c3cfc02013-10-25 17:02:19 -0700216 return false;
Brian Silvermanf4937f62013-10-16 10:32:00 -0700217 } else { // we know what phase we're looking for
218 // Deal with it if the above logic for tweaking the phase that we're
219 // using wrapped it around.
220 if (good_phase_ == -1) {
221 good_phase_ = kPacketsPerLoopCycle;
222 } else if (good_phase_ == kPacketsPerLoopCycle) {
Brian Silverman1c3cfc02013-10-25 17:02:19 -0700223 LOG(DEBUG, "dewrapping\n");
Brian Silvermanf4937f62013-10-16 10:32:00 -0700224 good_phase_ = 0;
225 }
226 assert(good_phase_ >= 0);
227 assert(good_phase_ < kPacketsPerLoopCycle);
228
229 if (received_phase == good_phase_) {
Brian Silverman7643bbb2013-10-24 15:58:37 -0700230 if (offset < -kSwitchOffset) {
Brian Silvermanf4937f62013-10-16 10:32:00 -0700231 ++good_phase_early_;
232 good_phase_late_ = 0;
Brian Silverman7643bbb2013-10-24 15:58:37 -0700233 } else if (offset > kSwitchOffset) {
Brian Silvermanf4937f62013-10-16 10:32:00 -0700234 ++good_phase_late_;
235 good_phase_early_ = 0;
236 } else {
237 good_phase_early_ = good_phase_late_ = 0;
238 }
Brian Silverman1c3cfc02013-10-25 17:02:19 -0700239 last_good_packet_time_ = received_time;
Brian Silvermancaeed862013-10-25 17:32:19 -0700240 last_good_sequence_ = sequence;
Brian Silverman1c3cfc02013-10-25 17:02:19 -0700241
Brian Silvermanf4937f62013-10-16 10:32:00 -0700242 return true;
243 } else {
244 return false;
245 }
246 }
247 }
248
249 private:
Brian Silvermanf4937f62013-10-16 10:32:00 -0700250 // How many times the packet we guessed has to be close to right to use the
251 // guess.
252 static const int kMinGoodGuessCycles = 30;
253 // How many times in a row we have to guess the wrong packet before trying
254 // again.
255 static const int kMaxBadGuessCycles = 3;
256
257 // How many times in a row a different packet has to be better than the one
258 // that we're using befor switching to it.
259 static const int kSwitchCycles = 15;
260
Brian Silverman1c3cfc02013-10-25 17:02:19 -0700261 ::aos::time::Time last_good_packet_time_{0, 0};
Brian Silvermanf4937f62013-10-16 10:32:00 -0700262
Brian Silvermancaeed862013-10-25 17:32:19 -0700263 int32_t last_good_sequence_;
264
Brian Silvermanf4937f62013-10-16 10:32:00 -0700265 const int kUnknownPhase = -11;
266 // kUnknownPhase or the sequence number (%kPacketsPerLoopCycle) to
267 // use or think about using.
268 // If not kUnknownPhase, 0 <= these < kPacketsPerLoopCycle.
269 int good_phase_, guess_phase_;
270 int guess_phase_good_, guess_phase_bad_;
271 ::aos::time::Time guess_phase_offset_{0, 0};
272 int good_phase_early_, good_phase_late_;
273 } phase_locker_;
274
Brian Silverman4bde0172013-10-25 15:53:25 -0700275 static void StaticTransferCallback(libusb::Transfer *transfer, void *self) {
276 static_cast<GyroSensorReceiver *>(self)->TransferCallback(transfer);
277 }
278 void TransferCallback(libusb::Transfer *transfer) {
279 if (transfer->status() == LIBUSB_TRANSFER_COMPLETED) {
280 LOG(DEBUG, "transfer %p completed\n", transfer);
281 completed_transfer_ = transfer;
282 } else if (transfer->status() == LIBUSB_TRANSFER_TIMED_OUT) {
283 LOG(WARNING, "transfer %p timed out\n", transfer);
284 completed_transfer_ = kTransferFailed;
285 } else if (transfer->status() == LIBUSB_TRANSFER_CANCELLED) {
286 LOG(DEBUG, "transfer %p cancelled\n", transfer);
287 } else {
288 LOG(FATAL, "transfer %p has status %d\n", transfer, transfer->status());
289 }
290 transfer->Submit();
291 }
292
Brian Silvermanf4937f62013-10-16 10:32:00 -0700293 // Returns true if receiving failed and we should try a Reset().
294 bool ReceiveData() {
Brian Silverman2e0dcfd2013-03-30 22:44:40 -0700295 // Loop and then return once we get a good one.
296 while (true) {
Brian Silverman4bde0172013-10-25 15:53:25 -0700297 completed_transfer_ = NULL;
298 while (completed_transfer_ == NULL) {
299 libusb_.HandleEvents();
Brian Silverman2e0dcfd2013-03-30 22:44:40 -0700300 }
Brian Silverman4bde0172013-10-25 15:53:25 -0700301 if (completed_transfer_ == kTransferFailed) {
302 LOG(WARNING, "transfer failed\n");
303 return true;
304 }
305
306 if (completed_transfer_->read_bytes() <
307 static_cast<ssize_t>(sizeof(GyroBoardData))) {
308 LOG(ERROR, "read %d bytes instead of at least %zd\n",
309 completed_transfer_->read_bytes(), sizeof(GyroBoardData));
310 continue;
311 }
312
313 memcpy(data(), completed_transfer_->data(),
314 sizeof(GyroBoardData));
Brian Silverman1c3cfc02013-10-25 17:02:19 -0700315
316 int32_t count_before = sequence_.count();
Brian Silverman4bde0172013-10-25 15:53:25 -0700317 sequence_.Update(data()->sequence);
Brian Silvermancaeed862013-10-25 17:32:19 -0700318 if (count_before == 0) {
319 LOG(INFO, "count starting at %" PRId32 "\n", sequence_.count());
320 } else if (sequence_.count() - count_before != 1) {
Brian Silverman1c3cfc02013-10-25 17:02:19 -0700321 LOG(WARNING, "count went from %" PRId32" to %" PRId32 "\n",
322 count_before, sequence_.count());
323 }
324
Brian Silverman4bde0172013-10-25 15:53:25 -0700325 return false;
Brian Silverman2e0dcfd2013-03-30 22:44:40 -0700326 }
327 }
328
Brian Silvermanf4937f62013-10-16 10:32:00 -0700329 GyroBoardData *data() {
Brian Silverman4bde0172013-10-25 15:53:25 -0700330 return &data_;
Brian Silvermanf4937f62013-10-16 10:32:00 -0700331 }
332
333 void Reset() {
Brian Silverman1c3cfc02013-10-25 17:02:19 -0700334 typedef ::std::unique_ptr<libusb::IsochronousTransfer> TransferType;
335 for (TransferType &c : transfers_) {
336 c.reset();
337 }
Brian Silverman4bde0172013-10-25 15:53:25 -0700338 dev_handle_ = ::std::unique_ptr<LibUSBDeviceHandle>(
339 libusb_.FindDeviceWithVIDPID(kVid, kPid));
340 if (!dev_handle_) {
341 LOG(ERROR, "couldn't find device. exiting\n");
342 exit(1);
343 }
Brian Silverman1c3cfc02013-10-25 17:02:19 -0700344 for (TransferType &c : transfers_) {
345 c.reset(new libusb::IsochronousTransfer(kDataLength, 1,
346 StaticTransferCallback, this));
347 c->FillIsochronous(dev_handle_.get(), kEndpoint, kReadTimeout);
348 c->Submit();
349 }
Brian Silverman4bde0172013-10-25 15:53:25 -0700350
Brian Silvermanf4937f62013-10-16 10:32:00 -0700351 sequence_.Reset();
352 phase_locker_.Reset();
Brian Silverman2e0dcfd2013-03-30 22:44:40 -0700353 }
354
Brian Silvermanf4937f62013-10-16 10:32:00 -0700355 void ProcessData() {
356 if (data()->robot_id != 0) {
357 LOG(ERROR, "gyro board sent data for robot id %hhd!"
358 " dip switches are %x\n",
359 data()->robot_id, data()->base_status & 0xF);
360 return;
361 } else {
362 LOG(DEBUG, "processing a packet dip switches %x\n",
363 data()->base_status & 0xF);
364 }
365
366 static ::aos::time::Time last_time = ::aos::time::Time::Now();
367 if ((last_time - ::aos::time::Time::Now()) >
368 ::aos::time::Time::InMS(0.0011)) {
369 LOG(INFO, "missed one\n");
370 }
371
372 gyro.MakeWithBuilder()
373 .angle(data()->gyro_angle / 16.0 / 1000.0 / 180.0 * M_PI)
374 .Send();
375
376 drivetrain.position.MakeWithBuilder()
377 .right_encoder(drivetrain_translate(data()->main.right_drive))
378 .left_encoder(-drivetrain_translate(data()->main.left_drive))
379 .Send();
380
381 wrist.position.MakeWithBuilder()
382 .pos(wrist_translate(data()->main.wrist))
Brian Silvermancaeed862013-10-25 17:32:19 -0700383 .hall_effect(data()->main.wrist_hall_effect)
Brian Silvermanf4937f62013-10-16 10:32:00 -0700384 .calibration(wrist_translate(data()->main.capture_wrist_rise))
385 .Send();
386
387 angle_adjust.position.MakeWithBuilder()
388 .angle(angle_adjust_translate(data()->main.shooter_angle))
Brian Silvermancaeed862013-10-25 17:32:19 -0700389 .bottom_hall_effect(data()->main.angle_adjust_bottom_hall_effect)
Brian Silvermanf4937f62013-10-16 10:32:00 -0700390 .middle_hall_effect(false)
391 .bottom_calibration(angle_adjust_translate(
392 data()->main.capture_shooter_angle_rise))
393 .middle_calibration(angle_adjust_translate(
394 0))
395 .Send();
396
397 shooter.position.MakeWithBuilder()
398 .position(shooter_translate(data()->main.shooter))
399 .Send();
400
401 index_loop.position.MakeWithBuilder()
402 .index_position(index_translate(data()->main.indexer))
Brian Silvermancaeed862013-10-25 17:32:19 -0700403 .top_disc_detect(data()->main.top_disc)
Brian Silvermanf4937f62013-10-16 10:32:00 -0700404 .top_disc_posedge_count(top_rise_.Update(data()->main.top_rise_count))
405 .top_disc_posedge_position(
406 index_translate(data()->main.capture_top_rise))
407 .top_disc_negedge_count(top_fall_.Update(data()->main.top_fall_count))
408 .top_disc_negedge_position(
409 index_translate(data()->main.capture_top_fall))
Brian Silvermancaeed862013-10-25 17:32:19 -0700410 .bottom_disc_detect(data()->main.bottom_disc)
Brian Silvermanf4937f62013-10-16 10:32:00 -0700411 .bottom_disc_posedge_count(
412 bottom_rise_.Update(data()->main.bottom_rise_count))
413 .bottom_disc_negedge_count(
414 bottom_fall_.Update(data()->main.bottom_fall_count))
415 .bottom_disc_negedge_wait_position(index_translate(
416 data()->main.capture_bottom_fall_delay))
417 .bottom_disc_negedge_wait_count(
418 bottom_fall_delay_.Update(data()->main.bottom_fall_delay_count))
419 .loader_top(data()->main.loader_top)
420 .loader_bottom(data()->main.loader_bottom)
421 .Send();
Brian Silverman2e0dcfd2013-03-30 22:44:40 -0700422 }
423
Brian Silverman4bde0172013-10-25 15:53:25 -0700424 GyroBoardData data_;
Brian Silverman2e0dcfd2013-03-30 22:44:40 -0700425
Brian Silvermanf4937f62013-10-16 10:32:00 -0700426 WrappingCounter sequence_;
Brian Silverman2e0dcfd2013-03-30 22:44:40 -0700427
Brian Silverman4bde0172013-10-25 15:53:25 -0700428 LibUSB libusb_;
429 ::std::unique_ptr<LibUSBDeviceHandle> dev_handle_;
Brian Silverman1c3cfc02013-10-25 17:02:19 -0700430 ::std::unique_ptr<libusb::IsochronousTransfer> transfers_[kNumTransfers];
Brian Silverman4bde0172013-10-25 15:53:25 -0700431 // Temporary variable for holding a completed transfer to communicate that
432 // information from the callback to the code that wants it.
433 libusb::Transfer *completed_transfer_;
Brian Silvermanf4937f62013-10-16 10:32:00 -0700434
435 WrappingCounter top_rise_;
436 WrappingCounter top_fall_;
437 WrappingCounter bottom_rise_;
438 WrappingCounter bottom_fall_delay_;
439 WrappingCounter bottom_fall_;
Brian Silverman2e0dcfd2013-03-30 22:44:40 -0700440};
Brian Silvermanf4937f62013-10-16 10:32:00 -0700441constexpr ::aos::time::Time GyroSensorReceiver::kReadTimeout;
Brian Silverman7643bbb2013-10-24 15:58:37 -0700442constexpr ::aos::time::Time GyroSensorReceiver::kDesiredOffset;
Brian Silverman1c3cfc02013-10-25 17:02:19 -0700443constexpr ::aos::time::Time GyroSensorReceiver::kResetTime;
Brian Silverman2e0dcfd2013-03-30 22:44:40 -0700444
445} // namespace frc971
446
447int main() {
448 ::aos::Init();
Brian Silvermanf4937f62013-10-16 10:32:00 -0700449 ::frc971::GyroSensorReceiver receiver;
Brian Silverman2e0dcfd2013-03-30 22:44:40 -0700450 while (true) {
451 receiver.RunIteration();
452 }
453 ::aos::Cleanup();
454}