moved back to our custom libusb wrappers instead of glibusb
Glibusb's model is too simplified to work very well at all with
isochronous, so I had to go back to our custom wrapper (which still
needed isochronous support to be finished).
diff --git a/frc971/input/gyro_sensor_receiver.cc b/frc971/input/gyro_sensor_receiver.cc
index 0fafaeb..ed37229 100644
--- a/frc971/input/gyro_sensor_receiver.cc
+++ b/frc971/input/gyro_sensor_receiver.cc
@@ -6,8 +6,6 @@
#include "aos/atom_code/init.h"
#include "aos/common/logging/logging.h"
#include "aos/common/time.h"
-#include "aos/common/glibusb/glibusb.h"
-#include "aos/common/glibusb/gbuffer.h"
#include "aos/common/util/wrapping_counter.h"
#include "aos/common/control_loop/ControlLoop.h"
@@ -18,6 +16,7 @@
#include "frc971/control_loops/shooter/shooter_motor.q.h"
#include "frc971/input/gyro_board_data.h"
#include "frc971/queues/GyroAngle.q.h"
+#include "gyro_board/src/libusb-driver/libusb_wrap.h"
#ifndef M_PI
#define M_PI 3.14159265358979323846
@@ -78,20 +77,27 @@
if (phase_locker_.IsCurrentPacketGood(received_time, sequence_.count())) {
LOG(DEBUG, "processing data\n");
ProcessData();
- } else {
- LOG(DEBUG, "not processing\n");
}
}
}
private:
- static const unsigned char kEndpoint = 0x3;
+ static const unsigned char kEndpoint = 0x83;
// 0 is unlimited
static constexpr ::aos::time::Time kReadTimeout =
::aos::time::Time::InSeconds(1.5);
- static constexpr ::glibusb::VendorProductId kDeviceId =
- ::glibusb::VendorProductId(0x1424 /* vendor ID */,
- 0xd243 /* product ID */);
+ // vendor ID
+ static const int32_t kVid = 0x1424;
+ // product ID
+ static const int32_t kPid = 0xd243;
+
+ // A value to put into completed_transfer_ to indicate that it failed.
+ static constexpr libusb::Transfer *kTransferFailed =
+ reinterpret_cast<libusb::Transfer *>(-1);
+
+ // How big of a buffer we're going to give the usb transfer stuff.
+ static const size_t kDataLength = 128;
+ static_assert(kDataLength >= sizeof(GyroBoardData), "buffer is too small");
static const int kPacketsPerLoopCycle = 10;
@@ -141,6 +147,7 @@
--good_phase_;
}
} else if (guess_phase_bad_ > kMaxBadGuessCycles) {
+ LOG(INFO, "guessed wrong phase too many times\n");
Reset();
}
if (good_phase_early_ > kSwitchCycles) {
@@ -172,12 +179,14 @@
guess_phase_offset_ = offset;
}
} else if (received_phase == guess_phase_) {
+ LOG(DEBUG, "guessed right phase %d\n", received_phase);
++guess_phase_good_;
guess_phase_bad_ = 0;
guess_phase_offset_ = (guess_phase_offset_ * 9 + offset) / 10;
}
} else if (guess_phase_ != kUnknownPhase &&
received_phase == guess_phase_) {
+ LOG(DEBUG, "guessed wrong phase %d\n", received_phase);
++guess_phase_bad_;
guess_phase_good_ = ::std::max(0, guess_phase_good_ -
(kMinGoodGuessCycles / 10));
@@ -240,47 +249,75 @@
int good_phase_early_, good_phase_late_;
} phase_locker_;
+ static void StaticTransferCallback(libusb::Transfer *transfer, void *self) {
+ static_cast<GyroSensorReceiver *>(self)->TransferCallback(transfer);
+ }
+ void TransferCallback(libusb::Transfer *transfer) {
+ if (transfer->status() == LIBUSB_TRANSFER_COMPLETED) {
+ LOG(DEBUG, "transfer %p completed\n", transfer);
+ completed_transfer_ = transfer;
+ } else if (transfer->status() == LIBUSB_TRANSFER_TIMED_OUT) {
+ LOG(WARNING, "transfer %p timed out\n", transfer);
+ completed_transfer_ = kTransferFailed;
+ } else if (transfer->status() == LIBUSB_TRANSFER_CANCELLED) {
+ LOG(DEBUG, "transfer %p cancelled\n", transfer);
+ } else {
+ LOG(FATAL, "transfer %p has status %d\n", transfer, transfer->status());
+ }
+ transfer->Submit();
+ }
+
// Returns true if receiving failed and we should try a Reset().
bool ReceiveData() {
// Loop and then return once we get a good one.
while (true) {
- using ::glibusb::UsbEndpoint;
- UsbEndpoint::IoStatus result =
- endpoint_->ReadAtMostWithTimeout(sizeof(GyroBoardData),
- kReadTimeout.ToMSec(),
- &buffer_);
- switch (result) {
- case UsbEndpoint::kSuccess:
- sequence_.Update(data()->sequence);
- return false;
- case UsbEndpoint::kTimeout:
- LOG(WARNING, "read timed out\n");
- return true;
- case UsbEndpoint::kNoDevice:
- LOG(ERROR, "no device\n");
- return true;
- case UsbEndpoint::kUnknown:
- case UsbEndpoint::kFail:
- case UsbEndpoint::kAbort:
- LOG(ERROR, "read failed\n");
- continue;
+ completed_transfer_ = NULL;
+ while (completed_transfer_ == NULL) {
+ libusb_.HandleEvents();
}
+ if (completed_transfer_ == kTransferFailed) {
+ LOG(WARNING, "transfer failed\n");
+ return true;
+ }
+
+ if (completed_transfer_->read_bytes() <
+ static_cast<ssize_t>(sizeof(GyroBoardData))) {
+ LOG(ERROR, "read %d bytes instead of at least %zd\n",
+ completed_transfer_->read_bytes(), sizeof(GyroBoardData));
+ continue;
+ }
+
+ memcpy(data(), completed_transfer_->data(),
+ sizeof(GyroBoardData));
+ sequence_.Update(data()->sequence);
+ return false;
}
}
GyroBoardData *data() {
- return static_cast<GyroBoardData *>(
- buffer_.GetBufferPointer(sizeof(GyroBoardData)));
+ return &data_;
}
void Reset() {
- // Make sure to delete the endpoint before its device.
- endpoint_.reset();
- device_ = ::std::unique_ptr< ::glibusb::UsbDevice>(
- libusb_.FindSingleMatchingDeviceOrLose(kDeviceId));
- CHECK(device_);
- endpoint_ = ::std::unique_ptr< ::glibusb::UsbInEndpoint>(
- device_->InEndpoint(kEndpoint));
+ transfer1_.reset();
+ transfer2_.reset();
+ dev_handle_ = ::std::unique_ptr<LibUSBDeviceHandle>(
+ libusb_.FindDeviceWithVIDPID(kVid, kPid));
+ if (!dev_handle_) {
+ LOG(ERROR, "couldn't find device. exiting\n");
+ exit(1);
+ }
+ transfer1_ = ::std::unique_ptr<libusb::IsochronousTransfer>(
+ new libusb::IsochronousTransfer(kDataLength, 1,
+ StaticTransferCallback, this));
+ transfer2_ = ::std::unique_ptr<libusb::IsochronousTransfer>(
+ new libusb::IsochronousTransfer(kDataLength, 1,
+ StaticTransferCallback, this));
+ transfer1_->FillIsochronous(dev_handle_.get(), kEndpoint, kReadTimeout);
+ transfer2_->FillIsochronous(dev_handle_.get(), kEndpoint, kReadTimeout);
+ transfer1_->Submit();
+ transfer2_->Submit();
+
sequence_.Reset();
phase_locker_.Reset();
}
@@ -354,13 +391,16 @@
.Send();
}
- ::std::unique_ptr< ::glibusb::UsbDevice> device_;
- ::std::unique_ptr< ::glibusb::UsbInEndpoint> endpoint_;
- ::glibusb::Buffer buffer_;
+ GyroBoardData data_;
WrappingCounter sequence_;
- ::glibusb::Libusb libusb_;
+ LibUSB libusb_;
+ ::std::unique_ptr<LibUSBDeviceHandle> dev_handle_;
+ ::std::unique_ptr<libusb::IsochronousTransfer> transfer1_, transfer2_;
+ // Temporary variable for holding a completed transfer to communicate that
+ // information from the callback to the code that wants it.
+ libusb::Transfer *completed_transfer_;
WrappingCounter top_rise_;
WrappingCounter top_fall_;
@@ -368,7 +408,6 @@
WrappingCounter bottom_fall_delay_;
WrappingCounter bottom_fall_;
};
-constexpr ::glibusb::VendorProductId GyroSensorReceiver::kDeviceId;
constexpr ::aos::time::Time GyroSensorReceiver::kReadTimeout;
constexpr ::aos::time::Time GyroSensorReceiver::kDesiredOffset;
diff --git a/frc971/input/input.gyp b/frc971/input/input.gyp
index 8682eee..130e50f 100644
--- a/frc971/input/input.gyp
+++ b/frc971/input/input.gyp
@@ -37,10 +37,9 @@
'<(AOS)/atom_code/atom_code.gyp:init',
'<(AOS)/build/aos.gyp:logging',
'<(AOS)/common/common.gyp:time',
- '<(AOS)/common/glibusb/glibusb.gyp:glibusb',
- '<(AOS)/common/glibusb/glibusb.gyp:gbuffer',
'<(AOS)/common/util/util.gyp:wrapping_counter',
'<(AOS)/common/common.gyp:controls',
+ '<(DEPTH)/gyro_board/src/libusb-driver/libusb-driver.gyp:libusb_wrap',
],
},
{
diff --git a/gyro_board/src/libusb-driver/libusb-driver.gyp b/gyro_board/src/libusb-driver/libusb-driver.gyp
index 1c50633..ab2bf70 100644
--- a/gyro_board/src/libusb-driver/libusb-driver.gyp
+++ b/gyro_board/src/libusb-driver/libusb-driver.gyp
@@ -11,6 +11,10 @@
'<(AOS)/common/util/util.gyp:thread',
'libusb_wrap',
'<(AOS)/build/aos.gyp:logging',
+ '<(AOS)/common/common.gyp:time',
+ ],
+ 'export_dependent_settings': [
+ '<(AOS)/common/common.gyp:time',
],
},
{
diff --git a/gyro_board/src/libusb-driver/libusb_wrap.cc b/gyro_board/src/libusb-driver/libusb_wrap.cc
index 83cf245..0026ef3 100644
--- a/gyro_board/src/libusb-driver/libusb_wrap.cc
+++ b/gyro_board/src/libusb-driver/libusb_wrap.cc
@@ -1,5 +1,7 @@
#include "libusb_wrap.h"
+#include <string.h>
+
#include <iostream>
#include "aos/common/logging/logging.h"
@@ -115,8 +117,9 @@
Transfer::Transfer(size_t data_length,
void (*callback)(Transfer *, void *),
- void *user_data)
- : transfer_(libusb_alloc_transfer(0)),
+ void *user_data,
+ int num_iso_packets)
+ : transfer_(libusb_alloc_transfer(num_iso_packets)),
data_(new uint8_t[data_length]),
data_length_(data_length),
callback_(callback),
@@ -146,16 +149,16 @@
if (ret == LIBUSB_ERROR_BUSY) {
LOG(FATAL, "transfer %p already submitted\n", this);
}
- LOG(FATAL, "libusb error %d submitting transfer %p\n",
- ret, this);
+ LOG(FATAL, "libusb error %d submitting transfer %p. errno %d: %s\n",
+ ret, this, errno, strerror(errno));
}
}
void Transfer::Cancel() {
int ret = libusb_cancel_transfer(transfer_);
if (ret != 0) {
- LOG(FATAL, "libusb error %d cancelling transfer %p\n",
- ret, this);
+ LOG(FATAL, "libusb error %d cancelling transfer %p. errno %d: %s\n",
+ ret, this, errno, strerror(errno));
}
}
@@ -167,17 +170,14 @@
int num_packets,
void (*callback)(Transfer *, void *),
void *user_data)
- : Transfer(packet_length * num_packets, callback, user_data),
+ : Transfer(packet_length * num_packets, callback, user_data, num_packets),
num_packets_(num_packets) {
}
void IsochronousTransfer::FillIsochronous(LibUSBDeviceHandle *device,
unsigned char endpoint,
- unsigned int timeout) {
- (void)device;
- (void)endpoint;
- (void)timeout;
- /*libusb_fill_iso_transfer(transfer_,
+ const ::aos::time::Time &timeout) {
+ libusb_fill_iso_transfer(transfer_,
device->dev_handle_,
endpoint,
data_,
@@ -185,7 +185,8 @@
num_packets_,
StaticTransferCallback,
this,
- timeout);*/
+ timeout.ToMSec());
+ transfer_->iso_packet_desc[0].length = data_length_;
}
} // namespace libusb
diff --git a/gyro_board/src/libusb-driver/libusb_wrap.h b/gyro_board/src/libusb-driver/libusb_wrap.h
index 261cded..6056c66 100644
--- a/gyro_board/src/libusb-driver/libusb_wrap.h
+++ b/gyro_board/src/libusb-driver/libusb_wrap.h
@@ -4,6 +4,7 @@
#include <libusb-1.0/libusb.h>
#include "aos/common/macros.h"
+#include "aos/common/time.h"
class LibUSBDeviceHandle;
namespace libusb {
@@ -61,7 +62,8 @@
public:
Transfer(size_t data_length,
void (*callback)(Transfer *, void *),
- void *user_data);
+ void *user_data,
+ int num_iso_packets = 0);
~Transfer();
void FillInterrupt(LibUSBDeviceHandle *device,
@@ -72,7 +74,7 @@
void Cancel();
libusb_transfer_status status() { return transfer_->status; }
- int read_bytes() { return transfer_->actual_length; }
+ virtual int read_bytes() { return transfer_->actual_length; }
const uint8_t *data() { return data_; }
@@ -81,20 +83,22 @@
static_cast<Transfer *>(self->user_data)->TransferCallback();
}
- private:
- void TransferCallback();
-
+ protected:
libusb_transfer *const transfer_;
uint8_t *const data_;
size_t data_length_;
+ private:
+ void TransferCallback();
+
void (*const callback_)(Transfer *, void *);
void *const user_data_;
DISALLOW_COPY_AND_ASSIGN(Transfer);
};
+// TODO(brians): Make this actually work for num_packets != 1.
class IsochronousTransfer : public Transfer {
public:
IsochronousTransfer(size_t packet_length,
@@ -104,7 +108,11 @@
void FillIsochronous(LibUSBDeviceHandle *device,
unsigned char endpoint,
- unsigned int timeout);
+ const ::aos::time::Time &timeout);
+
+ virtual int read_bytes() {
+ return transfer_->iso_packet_desc[0].actual_length;
+ }
private:
const int num_packets_;