add finishing touches to initial libfibre version

This commit is contained in:
Samuel Sadok
2020-09-15 21:40:49 +02:00
parent 8a120ed4b6
commit 84e1eb8f0d
23 changed files with 225 additions and 183 deletions
+7 -7
View File
@@ -16,10 +16,10 @@ end
python_command = find_python3()
print('Using python command "'..python_command..'"')
tup.frule{inputs={'fibre/cpp/interfaces_template.j2'}, command=python_command..' interface_generator_stub.py --definitions odrive-interface.yaml --template %f --output %o', outputs='autogen/interfaces.hpp'}
tup.frule{inputs={'fibre/cpp/function_stubs_template.j2'}, command=python_command..' interface_generator_stub.py --definitions odrive-interface.yaml --template %f --output %o', outputs='autogen/function_stubs.hpp'}
tup.frule{inputs={'fibre/cpp/endpoints_template.j2'}, command=python_command..' interface_generator_stub.py --definitions odrive-interface.yaml --generate-endpoints ODrive --template %f --output %o', outputs='autogen/endpoints.hpp'}
tup.frule{inputs={'fibre/cpp/type_info_template.j2'}, command=python_command..' interface_generator_stub.py --definitions odrive-interface.yaml --template %f --output %o', outputs='autogen/type_info.hpp'}
tup.frule{inputs={'fibre-cpp/interfaces_template.j2'}, command=python_command..' interface_generator_stub.py --definitions odrive-interface.yaml --template %f --output %o', outputs='autogen/interfaces.hpp'}
tup.frule{inputs={'fibre-cpp/function_stubs_template.j2'}, command=python_command..' interface_generator_stub.py --definitions odrive-interface.yaml --template %f --output %o', outputs='autogen/function_stubs.hpp'}
tup.frule{inputs={'fibre-cpp/endpoints_template.j2'}, command=python_command..' interface_generator_stub.py --definitions odrive-interface.yaml --generate-endpoints ODrive --template %f --output %o', outputs='autogen/endpoints.hpp'}
tup.frule{inputs={'fibre-cpp/type_info_template.j2'}, command=python_command..' interface_generator_stub.py --definitions odrive-interface.yaml --template %f --output %o', outputs='autogen/type_info.hpp'}
-- Note: we currently check this file into source control for two reasons:
-- - Don't require tup to run in order to use odrivetool from the repo
@@ -192,7 +192,7 @@ sources = {
'communication/interface_usb.cpp',
'communication/interface_can.cpp',
'communication/interface_i2c.cpp',
'fibre/cpp/legacy_protocol.cpp',
'fibre-cpp/legacy_protocol.cpp',
'FreeRTOS-openocd.c',
'autogen/version.c'
}
@@ -207,14 +207,14 @@ build{
includes={
'Drivers/DRV8301',
'MotorControl',
'fibre/cpp/include',
'fibre-cpp/include',
'.',
"doctest"
}
}
if tup.getconfig('DOCTEST') == 'true' then
TEST_INCLUDES = '-I. -I./MotorControl -I./fibre/cpp/include -I./Drivers/DRV8301 -I./doctest'
TEST_INCLUDES = '-I. -I./MotorControl -I./fibre-cpp/include -I./Drivers/DRV8301 -I./doctest'
tup.foreach_rule('Tests/*.cpp', 'g++ -O3 -std=c++17 '..TEST_INCLUDES..' -c %f -o %o', 'Tests/bin/%B.o')
tup.frule{inputs='Tests/bin/*.o', command='g++ %f -o %o', outputs='Tests/test_runner.exe'}
tup.frule{inputs='Tests/test_runner.exe', command='%f'}
+1
View File
@@ -0,0 +1 @@
/third_party
+5 -14
View File
@@ -1,16 +1,12 @@
# pkgconf --cflags libusb
# pkgconf --libs libusb
# Prerequisites:
# Ubuntu: libusb-dev
ifeq ($(OS),Windows_NT)
target = windows
ifeq ($(PROCESSOR_ARCHITEW6432),AMD64)
outname = libfibre-windows-amd64.dll
else ifeq ($(PROCESSOR_ARCHITECTURE),AMD64)
outname = libfibre-windows-amd64.dll
else
$(error unsupported platform)
$(error unsupported platform ${PROCESSOR_ARCHITECTURE})
endif
else ifeq ($(shell uname -s),Linux)
target = linux
@@ -41,15 +37,10 @@ linux:
g++ -shared -o $(outname) -fPIC -std=c++11 -I/usr/include/libusb-1.0 -I./include -DFIBRE_COMPILE -DFIBRE_ENABLE_CLIENT \
$(FILES) \
-lusb-1.0
linux-cross:
arm-linux-gnueabihf-g++ -march=armv7 -shared -o libfibre.so -fPIC -std=c++11 -I/usr/include/libusb-1.0 -I./include -DFIBRE_COMPILE -DFIBRE_ENABLE_CLIENT \
$(FILES) \
-lusb
windows:
g++ -shared -o $(outname) -fPIC -std=c++11 -I./third_party/libusb-windows/libusb-1.0.23/include/libusb-1.0 -I./include -DFIBRE_COMPILE -DFIBRE_ENABLE_CLIENT \
$(FILES) \
-static-libgcc -Wl,-Bstatic -lstdc++ ./third_party/libusb-windows/libusb-1.0.23/MinGW64/static/libusb-1.0.a -Wl,-Bdynamic
# nm -D libfibre.so | grep T
# To check exported symbols run:
# nm -D libfibre.so | grep T
+59 -74
View File
@@ -13,6 +13,7 @@ set -euo pipefail
mkdir -p third_party
# Usage: download_deb_pkg destination-dir url
function download_deb_pkg() {
dir="$1"
url="$2"
@@ -30,6 +31,7 @@ function download_deb_pkg() {
popd > /dev/null
}
# Usage: compile_libusb arch-name arch
function compile_libusb() {
arch_name="$1"
arch="$2"
@@ -58,6 +60,25 @@ function compile_libusb() {
popd > /dev/null
}
FILES=('libfibre.cpp'
'platform_support/libusb_transport.cpp'
'legacy_protocol.cpp'
'legacy_object_client.cpp'
'logging.cpp')
function build_for_linux() {
arch_name="$1"
"${CXX}" -shared -o libfibre-"$arch_name".so -fPIC -std=c++11 -I./include -DFIBRE_COMPILE -DFIBRE_ENABLE_CLIENT \
${CFLAGS} \
"${FILES[@]}" \
${LIBS} \
-lpthread \
-Wl,--unresolved-symbols=ignore-in-shared-libs -static-libstdc++
}
### Download/compile prerequisites
download_deb_pkg libusb-dev-amd64 "http://mirrors.kernel.org/ubuntu/pool/main/libu/libusb-1.0/libusb-1.0-0-dev_1.0.23-2build1_amd64.deb"
download_deb_pkg libusb-amd64 "http://mirrors.kernel.org/ubuntu/pool/main/libu/libusb-1.0/libusb-1.0-0_1.0.23-2build1_amd64.deb"
download_deb_pkg libusb-i386 "http://mirrors.kernel.org/ubuntu/pool/main/libu/libusb-1.0/libusb-1.0-0_1.0.23-2build1_i386.deb"
@@ -65,35 +86,6 @@ download_deb_pkg libusb-dev-i386 "http://mirrors.kernel.org/ubuntu/pool/main/lib
download_deb_pkg libusb-armhf "http://mirrordirector.raspbian.org/raspbian/pool/main/libu/libusb-1.0/libusb-1.0-0_1.0.23-2_armhf.deb"
download_deb_pkg libusb-dev-armhf "http://mirrordirector.raspbian.org/raspbian/pool/main/libu/libusb-1.0/libusb-1.0-0-dev_1.0.23-2_armhf.deb"
download_deb_pkg libstdc++-linux-armhf "http://mirrors.kernel.org/ubuntu/pool/universe/g/gcc-10-cross/libstdc++-10-dev-armhf-cross_10-20200411-0ubuntu1cross1_all.deb"
#compile_libusb 'x86_64-apple-darwin' # fails with "sys/sysctl.h: No such file or directory"
_architectures=(
#'arm-linux-gnueabihf'
#'x86_64-apple-darwin'
#'x86_64-pc-linux-gnu'
#'i686-w64-mingw32'
#'x86_64-w64-mingw32'
)
FILES=('libfibre.cpp'
'platform_support/libusb_transport.cpp'
'legacy_protocol.cpp'
'legacy_object_client.cpp'
'logging.cpp')
### Raspberry Pi
#arm-linux-gnueabihf-g++ -shared -o libfibre-linux-armhf.so -fPIC -std=c++11 -I./include -DFIBRE_COMPILE -DFIBRE_ENABLE_CLIENT \
# -I./third_party/libusb-dev-armhf/usr/include/libusb-1.0 \
# "${FILES[@]}" \
# ./third_party/libusb-armhf/lib/arm-linux-gnueabihf/libusb-1.0.so.0.2.0 \
# -lpthread \
# -L./third_party/libstdc++-linux-armhf/usr/lib/gcc-cross/arm-linux-gnueabihf/10 \
# -Wl,--unresolved-symbols=ignore-in-shared-libs -static-libstdc++
### Windows
mkdir -p "third_party/libusb-windows"
pushd "third_party/libusb-windows" > /dev/null
@@ -105,14 +97,43 @@ if [ ! -f "libusb-1.0.23/libusb-1.0.def" ]; then
fi
popd > /dev/null
#x86_64-w64-mingw32-g++ -shared -o libfibre-windows-amd64.dll -fPIC -std=c++11 -I./include -DFIBRE_COMPILE -DFIBRE_ENABLE_CLIENT \
# -I./third_party/libusb-windows/libusb-1.0.23/include/libusb-1.0 \
# "${FILES[@]}" \
# -static-libgcc \
# -Wl,-Bstatic \
# -lstdc++ \
# ./third_party/libusb-windows/libusb-1.0.23/MinGW64/static/libusb-1.0.a \
# -Wl,-Bdynamic
### Compile libfibre
echo "building libfibre for Linux (AMD64)..."
CFLAGS="-I./third_party/libusb-dev-amd64/usr/include/libusb-1.0" \
LIBS="third_party/libusb-amd64/lib/x86_64-linux-gnu/libusb-1.0.so.0.2.0" \
CXX="x86_64-pc-linux-gnu-g++" \
build_for_linux 'linux-amd64'
echo "building libfibre for Linux (ARM)..."
CFLAGS="-I./third_party/libusb-dev-armhf/usr/include/libusb-1.0 -L./third_party/libstdc++-linux-armhf/usr/lib/gcc-cross/arm-linux-gnueabihf/10" \
LIBS="third_party/libusb-armhf/lib/arm-linux-gnueabihf/libusb-1.0.so.0.2.0" \
CXX="arm-linux-gnueabihf-g++" \
build_for_linux 'linux-armhf'
### Windows
echo "building libfibre for Windows (AMD64)..."
x86_64-w64-mingw32-g++ -shared -o libfibre-windows-amd64.dll -fPIC -std=c++11 -I./include -DFIBRE_COMPILE -DFIBRE_ENABLE_CLIENT \
-I./third_party/libusb-windows/libusb-1.0.23/include/libusb-1.0 \
"${FILES[@]}" \
-static-libgcc \
-Wl,-Bstatic \
-lstdc++ \
./third_party/libusb-windows/libusb-1.0.23/MinGW64/static/libusb-1.0.a \
-Wl,-Bdynamic
cp /usr/x86_64-w64-mingw32/bin/libwinpthread-1.dll .
### macOS
# Link are broken:
# …ions/Current/Headers $ ls -l IOReturn.h
# lrwxrwxrwx 1 root root 189 Dec 26 2019 IOReturn.h -> Users/phracker/Documents/Xcode-beta.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX.sdk/System/Library/Frameworks/Kernel.framework/Versions/A/Headers/IOKit/IOReturn.h
# Fix with:
# sudo ln -sf /opt/osxcross/SDK/MacOSX10.13.sdk/System/Library/Frameworks/Kernel.framework/Versions/A/Headers/IOKit/IOReturn.h IOReturn.h
oldprefix="Users/phracker/Documents/Xcode-beta.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX.sdk"
newprefix="/opt/osxcross/SDK/MacOSX10.13.sdk"
@@ -124,12 +145,6 @@ while IFS= read -r link; do
fi
done <<< "$(find /opt/osxcross/SDK/MacOSX10.13.sdk/System/Library/Frameworks/IOKit.framework -xtype l)"
# Link are broken:
# …ions/Current/Headers $ ls -l IOReturn.h
# lrwxrwxrwx 1 root root 189 Dec 26 2019 IOReturn.h -> Users/phracker/Documents/Xcode-beta.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX.sdk/System/Library/Frameworks/Kernel.framework/Versions/A/Headers/IOKit/IOReturn.h
# Fix with:
# sudo ln -sf /opt/osxcross/SDK/MacOSX10.13.sdk/System/Library/Frameworks/Kernel.framework/Versions/A/Headers/IOKit/IOReturn.h IOReturn.h
export PATH="/opt/osxcross/bin:$PATH"
export LD_LIBRARY_PATH="/opt/osxcross/lib"
export CFLAGS='-I/opt/osxcross/SDK/MacOSX10.13.sdk/usr/include -arch i386 -arch x86_64'
@@ -137,21 +152,7 @@ export MACOSX_DEPLOYMENT_TARGET='10.9'
CC='o64-clang' \
compile_libusb 'macos-amd64' 'x86_64-apple-darwin17'
#mkdir -p "third_party/libusb-src"
#pushd "third_party/libusb-src" > /dev/null
#if [ ! -f v1.0.23.tar.gz ]; then
# wget "https://github.com/libusb/libusb/archive/v1.0.23.tar.gz"
#fi
#if [ ! -f "libusb-1.0.23/README.md" ]; then
# tar -xvf "v1.0.23.tar.gz"
#fi
#export CC=o64-clang++
#mkdir -p "third_party/libusb-src/build-macos-amd64"
#../configure
#pushd "third_party/libusb-src" > /dev/null
#./configure
#popd > /dev/null
echo "building libfibre for macOS"
o64-clang++ -shared -o libfibre-macos-x86.dylib -fPIC -std=c++11 -I./include -DFIBRE_COMPILE -DFIBRE_ENABLE_CLIENT \
-I./third_party/libusb-windows/libusb-1.0.23/include/libusb-1.0 \
@@ -160,19 +161,3 @@ o64-clang++ -shared -o libfibre-macos-x86.dylib -fPIC -std=c++11 -I./include -DF
-static-libstdc++ \
./third_party/libusb-1.0.23/build-macos-amd64/libusb/.libs/libusb-1.0.a \
-framework CoreFoundation -framework IOKit
#"${FILES[@]}" \
#-arch i386 \
#-Wl,-Bstatic \
#./third_party/libusb-1.0.23/build-macos-amd64/libusb/libusb-1.0.la \
#-Wl,-Bdynamic
# \
#-Wl,-Bstatic \
#-lgcc \
#-lstdc++ \
#./third_party/libusb-windows/libusb-1.0.23/MinGW64/static/libusb-1.0.a \
#-Wl,-Bdynamic
@@ -191,7 +191,7 @@ struct FibrePropertyTypeInfo<Property<T>> : FloatSettableTypeInfo, StringConvert
}
bool set_string(const Introspectable& obj, char* buffer, size_t length) const override {
maybe_underlying_type_t<T> value;
maybe_underlying_type_t<T> value{};
if (!from_string(buffer, length, &value, 0)) {
return false;
}
@@ -200,7 +200,7 @@ struct FibrePropertyTypeInfo<Property<T>> : FloatSettableTypeInfo, StringConvert
}
bool set_float(const Introspectable& obj, float val) const override {
maybe_underlying_type_t<T> value;
maybe_underlying_type_t<T> value{};
if (!conversion::set_from_float(val, &value)) {
return false;
}
Binary file not shown.
+1 -2
View File
@@ -425,9 +425,8 @@ struct FIBRE_PRIVATE LibFibreCallContext : fibre::Completer<fibre::LegacyObjectC
transcode(obj->client, rx_vec, func->outputs, false);
size_t len = std::min(rx_vec.size(), rx_buf.size());
FIBRE_LOG(D) << "copying " << rx_vec.size() << " or " << rx_buf.size() << " bytes to output";
std::copy(rx_vec.begin(), rx_vec.begin() + len, rx_buf.begin());
FIBRE_LOG(D) << "result is " << as_hex(rx_buf);
FIBRE_LOG(D) << "result is [" << as_hex(rx_buf) << "]";
if (on_completed) {
(*on_completed)(ctx, output.status, rx_buf.begin() + len);
@@ -15,8 +15,13 @@ using namespace fibre;
DEFINE_LOG_TOPIC(USB);
USE_LOG_TOPIC(USB);
// This probably has no noteworthy effect since we automatically restart
// timed out operations anyway.
constexpr unsigned int kBulkTimeoutMs = 2000;
// Only relevant for platforms don't support hotplug detection and thus
// need polling.
constexpr unsigned int kPollingIntervalMs = 1000;
/* LibusbDiscoverer ----------------------------------------------------------*/
@@ -352,16 +357,16 @@ int LibusbDiscoverer::on_hotplug(struct libusb_device *dev,
if (LIBUSB_HOTPLUG_EVENT_DEVICE_ARRIVED == event) {
FIBRE_LOG(D) << "device arrived: bus " << (int)bus_number << ", " << (int)dev_number;
for (auto& subscription: subscriptions_) {
consider_device(dev, subscription);
}
// add empty placeholder to the list of known devices
known_devices_[bus_number << 8 | dev_number] = {
.dev = libusb_ref_device(dev),
.handle = nullptr
};
for (auto& subscription: subscriptions_) {
consider_device(dev, subscription);
}
} else if (LIBUSB_HOTPLUG_EVENT_DEVICE_LEFT == event) {
FIBRE_LOG(D) << "device left: bus " << (int)bus_number << ", " << (int)dev_number;
@@ -412,6 +417,17 @@ void LibusbDiscoverer::poll_devices_now() {
for (auto& dev: current_devices) {
if (known_devices_.find(dev.first) == known_devices_.end()) {
on_hotplug(dev.second, LIBUSB_HOTPLUG_EVENT_DEVICE_ARRIVED);
// Immediately forget about the devices that weren't opened on plugin.
// The reason is this: On Windows the device address and even the
// device pointer can remain equal across device reset. Since we don't
// poll at infinite frequency This means we could miss a device reset.
// To avoid this, we reinspect the all unopened devices on
// every polling iteration.
auto it = known_devices_.find(dev.first);
if (it->second.handle == nullptr) {
known_devices_.erase(it);
}
}
}
@@ -434,7 +450,7 @@ void LibusbDiscoverer::poll_devices_now() {
// It's possible that the discoverer was deinited during this function.
if (event_loop_) {
device_polling_timer_ = event_loop_->call_later(1.0, [](void* ctx) {
device_polling_timer_ = event_loop_->call_later(kPollingIntervalMs * 0.001f, [](void* ctx) {
((LibusbDiscoverer*)ctx)->poll_devices_now();
}, this);
}
@@ -516,10 +532,8 @@ void LibusbDiscoverer::consider_device(struct libusb_device *device, ChannelDisc
continue;
}
EventLoop* event_loop = using_sparate_libusb_thread_ ? event_loop_ : nullptr;
LibusbBulkInEndpoint* ep_in = new LibusbBulkInEndpoint();
if (libusb_ep_in && ep_in->init(event_loop, my_dev.handle, libusb_ep_in->bEndpointAddress)) {
if (libusb_ep_in && ep_in->init(this, my_dev.handle, libusb_ep_in->bEndpointAddress)) {
my_dev.ep_in.push_back(ep_in);
} else {
delete ep_in;
@@ -527,7 +541,7 @@ void LibusbDiscoverer::consider_device(struct libusb_device *device, ChannelDisc
}
LibusbBulkOutEndpoint* ep_out = new LibusbBulkOutEndpoint();
if (libusb_ep_out && ep_out->init(event_loop, my_dev.handle, libusb_ep_out->bEndpointAddress)) {
if (libusb_ep_out && ep_out->init(this, my_dev.handle, libusb_ep_out->bEndpointAddress)) {
my_dev.ep_out.push_back(ep_out);
} else {
delete ep_out;
@@ -549,8 +563,8 @@ void LibusbDiscoverer::consider_device(struct libusb_device *device, ChannelDisc
/* LibusbBulkEndpoint --------------------------------------------------------*/
template<typename TRes>
bool LibusbBulkEndpoint<TRes>::init(EventLoop* event_loop, libusb_device_handle* handle, uint8_t endpoint_id) {
event_loop_ = event_loop;
bool LibusbBulkEndpoint<TRes>::init(LibusbDiscoverer* parent, libusb_device_handle* handle, uint8_t endpoint_id) {
parent_ = parent;
handle_ = handle;
transfer_ = libusb_alloc_transfer(0);
endpoint_id_ = endpoint_id;
@@ -560,7 +574,7 @@ bool LibusbBulkEndpoint<TRes>::init(EventLoop* event_loop, libusb_device_handle*
template<typename TRes>
bool LibusbBulkEndpoint<TRes>::deinit() {
if (completer_) {
FIBRE_LOG(E) << "Transfer still in progress. This is gonna be messy.";
FIBRE_LOG(E) << "Transfer on EP " << as_hex(endpoint_id_) << " still in progress. This is gonna be messy.";
}
libusb_free_transfer(transfer_);
@@ -593,7 +607,7 @@ void LibusbBulkEndpoint<TRes>::start_transfer(bufptr_t buffer, TransferHandle* h
// This callback is used if we start our own libusb thread
// separate from the application's event loop thread
auto indirect_callback = [](struct libusb_transfer* transfer){
((LibusbBulkEndpoint<TRes>*)transfer->user_data)->event_loop_->post(
((LibusbBulkEndpoint<TRes>*)transfer->user_data)->parent_->event_loop_->post(
[](void* ctx) {
((LibusbBulkEndpoint<TRes>*)ctx)->on_transfer_finished();
}, transfer->user_data
@@ -603,7 +617,7 @@ void LibusbBulkEndpoint<TRes>::start_transfer(bufptr_t buffer, TransferHandle* h
//FIBRE_LOG(D) << "transfer of size " << buffer.size();
libusb_fill_bulk_transfer(transfer_, handle_, endpoint_id_,
buffer.begin(), buffer.size(),
event_loop_ ? indirect_callback : direct_callback,
parent_->using_sparate_libusb_thread_ ? indirect_callback : direct_callback,
this, kBulkTimeoutMs);
completer_ = &completer;
@@ -643,18 +657,59 @@ void LibusbBulkEndpoint<TRes>::on_transfer_finished() {
submit_transfer();
return;
}
libusb_device* dev = libusb_get_device(handle_);
// On linux we get LIBUSB_TRANSFER_STALL on the RX pipe when the cable is plugged out
StreamStatus status = LIBUSB_TRANSFER_COMPLETED == transfer_->status ? kStreamOk :
LIBUSB_TRANSFER_CANCELLED == transfer_->status ? kStreamCancelled :
LIBUSB_TRANSFER_STALL == transfer_->status ? kStreamClosed :
LIBUSB_TRANSFER_NO_DEVICE == transfer_->status ? kStreamClosed :
kStreamError;
StreamStatus status;
if (transfer_->status == LIBUSB_TRANSFER_COMPLETED) {
status = kStreamOk;
} else if (transfer_->status == LIBUSB_TRANSFER_CANCELLED) {
status = kStreamCancelled;
} else {
// The error that we get on device removal tends to be inaccurate.
// Sometimes it's LIBUSB_TRANSFER_STALL, sometimes
// LIBUSB_TRANSFER_ERROR. Therefore we just check if the device
// is still present to determine which error code to return.
bool found = false;
libusb_device** list;
ssize_t n_devices = libusb_get_device_list(parent_->libusb_ctx_, &list);
if (n_devices >= 0) {
for (size_t i = 0; i < n_devices; ++i) {
if (list[i] == dev) {
break;
}
}
libusb_free_device_list(list, 1);
}
if (found) {
status = kStreamError;
} else {
FIBRE_LOG(D) << "device removed during transfer";
status = kStreamClosed;
}
}
(status == kStreamError ? FIBRE_LOG(W) : FIBRE_LOG(T))
<< "USB transfer on EP " << as_hex(endpoint_id_) << " finished with " << libusb_error_name(transfer_->status);
uint8_t* end = std::max(transfer_->buffer + transfer_->actual_length, transfer_->buffer);
if (status == kStreamClosed) {
handle_ = nullptr; // Ensure that no new transfer is started
}
uint8_t* end = std::max(transfer_->buffer + transfer_->actual_length, transfer_->buffer);
safe_complete(completer_, {status, end});
// If libusb does hotplug detection itself then we don't need to handle
// device removal here. Libusb will call the corresponding hotplug callback.
if (status == kStreamClosed && !parent_->hotplug_callback_handle_) {
if (!parent_->using_sparate_libusb_thread_) {
FIBRE_LOG(E) << "It's not a good idea to unref the device from within this callback. This will probably hang.";
}
parent_->on_hotplug(dev, LIBUSB_HOTPLUG_EVENT_DEVICE_LEFT);
}
}
@@ -21,6 +21,8 @@ struct ChannelDiscoveryResult {
AsyncStreamSink* tx_channel;
};
template<typename TRes> class FIBRE_PRIVATE LibusbBulkEndpoint;
class FIBRE_PRIVATE LibusbDiscoverer {
public:
@@ -45,6 +47,9 @@ public:
int stop_channel_discovery(ChannelDiscoveryContext* handle);
private:
friend class LibusbBulkEndpoint<ReadResult>;
friend class LibusbBulkEndpoint<WriteResult>;
struct Device {
struct libusb_device* dev;
struct libusb_device_handle* handle;
@@ -76,7 +81,7 @@ private:
template<typename TRes>
class FIBRE_PRIVATE LibusbBulkEndpoint {
public:
bool init(EventLoop* event_loop, struct libusb_device_handle* handle, uint8_t endpoint_id);
bool init(LibusbDiscoverer* parent, struct libusb_device_handle* handle, uint8_t endpoint_id);
bool deinit();
protected:
@@ -87,7 +92,7 @@ private:
void submit_transfer();
void on_transfer_finished();
EventLoop* event_loop_ = nullptr; // only non-null on Windows where we use a separate libusb thread
LibusbDiscoverer* parent_ = nullptr;
struct libusb_device_handle* handle_ = nullptr;
uint8_t endpoint_id_ = 0;
struct libusb_transfer* transfer_ = nullptr;
+1 -1
View File
@@ -4,7 +4,7 @@ import sys
import os
try:
exec(open(os.path.join(os.path.dirname(os.path.realpath(__file__)), 'fibre', 'tools', 'interface_generator.py')).read())
exec(open(os.path.join(os.path.dirname(os.path.dirname(os.path.realpath(__file__))), 'tools', 'fibre-tools', 'interface_generator.py')).read())
except ImportError as ex:
print(str(ex), file=sys.stderr)
print("Note that there are new compile-time dependencies since around v0.5.1.", file=sys.stderr)
+1 -1
View File
@@ -4,7 +4,7 @@
## How to send commands
* **Via USB:**
* **Windows:** Use the Zadig utility to set the ODrive's driver to "usbser". Windows will then make the device available as COM port. You can use [PuTTY](https://www.chiark.greenend.org.uk/~sgtatham/putty/) to manually send commands or open the COM port using your favorite programming language
* **Windows:** Use [PuTTY](https://www.chiark.greenend.org.uk/~sgtatham/putty/) to manually send commands or open the COM port using your favorite programming language
* **Linux/macOS:** Run `/dev/tty*` to list all serial ports. The ODrive will show up as `/dev/ttyACM0` (or similar) on Linux and `/dev/tty.usbmodem[...]` on macOS. Once you know the name, you can use `screen /dev/ttyACM0` (with the correct name) to send commands manually or open the device using your favorite programming language. Serial ports on Unix can be opened, written to and read from like a normal file.
* **Via UART:** Connect the ODrive's TX (GPIO1) to your host's RX. Connect your ODrive's RX (GPIO2) to your host's TX. The logic level of the ODrive is 3.3V.
* **Arduino:** You can use the [ODrive Arduino library](https://github.com/madcowswe/ODrive/tree/master/Arduino/ODriveArduino) to talk to the ODrive.
+3 -2
View File
@@ -263,8 +263,9 @@ We use GitHub Releases to provide firmware releases.
1. Cut off the changelog to reflect the new release
2. Merge the release candidate into master.
3. Push a (lightweight) tag to the master branch. Follow the existing naming convention.
4. Push the python tools to PyPI.
5. Edit the release on GitHub to add a title and description (copy&paste from changelog).
4. If you changed something in libfibre, regenerate the binaries using `Firmware/fibre-cpp/compile_for_all_platforms.sh` and then copy all resulting `*.so`, `*.dll` and `*.dylib` files to `tools/odrive/pyfibre/fibre/`.
5. Push the python tools to PyPI (see setup.py for details).
6. Edit the release on GitHub to add a title and description (copy&paste from changelog).
## Other code maintenance notes
The cortex M4F processor has hardware single precision float unit. However double precision operations are not accelerated, and hence should be avoided. The following regex is helpful for cleaning out double constants:
+14 -11
View File
@@ -82,9 +82,6 @@ Most instructions in this guide refer to a utility called `odrivetool`, so you s
* __Anaconda__: In the start menu, type `Anaconda Prompt` <kbd>Enter</kbd>
* __Standalone Python__: In the start menu, type `cmd` <kbd>Enter</kbd>
3. Install the ODrive tools by typing `pip install odrive` <kbd>Enter</kbd>
4. Plug in a USB cable into the microUSB connector on ODrive, and connect it to your PC.
5. Use the [Zadig](http://zadig.akeo.ie/) utility to set ODrive driver to libusb-win32.
* Check 'List All Devices' from the options menu, and select 'ODrive 3.x Native Interface (Interface 2)'. With that selected in the device list choose 'libusb-win32' from the target driver list and then press the large 'install driver' button.
### OSX
@@ -112,16 +109,22 @@ pip3 install odrive
__Troubleshooting__
1. Permission Errors: Just run the previous command in sudo
```bash
sudo pip3 install odrive
```
```bash
sudo pip3 install odrive
```
2. Dependency Errors: If the installer doesn't complete and you get a dependency
error (Ex. "No module..." or "module_name not found")
```bash
sudo pip3 install module_name
```
Try step 5 again
```bash
sudo pip3 install module_name
```
Try step 5 again
3. Other Install Errors: If the installer fails at installing dependencies, try
```bash
sudo pip3 install odrive --no-deps
```
If you do this, brace yourself for runtime errors when you run `odrivetool` (the basic functionality should work though).
### Linux
@@ -143,7 +146,7 @@ Your board should come preflashed with firmware. If you run into problems, follo
Your board does **not** come preflashed with any firmware. Follow the instructions [here](odrivetool.md#device-firmware-update) on the ST Link procedure before you continue.
## Start `odrivetool`
To launch the main interactive ODrive tool, type `odrivetool` <kbd>Enter</kbd>. Connect your ODrive and wait for the tool to find it. Now you can, for instance type `odrv0.vbus_voltage` <kbd>Enter</kbd> to inpect the boards main supply voltage.
To launch the main interactive ODrive tool, type `odrivetool` <kbd>Enter</kbd>. Connect your ODrive and wait for the tool to find it. If it doesn't connect after a few seconds refer to the [troubleshooting page](troubleshooting.md#usb-connectivity-issues). Now you can, for instance type `odrv0.vbus_voltage` <kbd>Enter</kbd> to inpect the boards main supply voltage.
It should look something like this:
```text
+1 -1
View File
@@ -27,7 +27,7 @@ With this information you can look up the API documentation for your error(s):
* **Linux**: Type `lsusb` to list all USB devices. Verify that your ODrive is listed.
* **Linux**: Make sure you [set up your udev rules](getting-started#downloading-and-installing-tools) correctly.
* **Windows**: Right-click on the start menu and open "Device Manager". Verify that your ODrive is listed.
* **Windows**: Use the [Zadig utility](http://zadig.akeo.ie/) to verify the driver is set to `libusb-win32`. Note that there are two options listed in Zadig for Odrive: `ODrive 3.x Native Interface (Interface 2)` and `ODrive 3.x CDC Interface (Interface 0)`. Only the native interface should have `libusb-win32` while the CDC interface should use `WinUSB`.
* **Windows**: Use the [Zadig utility](http://zadig.akeo.ie/) to verify the driver is set to `WinUSB` or `libusb-win32`. Note that there are two options listed in Zadig for ODrive: `ODrive 3.x Native Interface (Interface 2)` and `ODrive 3.x CDC Interface (Interface 0)`. Only the driver setting of the native interface is important to `odrivetool`.
* Ensure that no other ODrive program is running
* Run `odrivetools` with the `--verbose` option.
* Run `PYUSB_DEBUG=debug odrivetools` to get even more log output.
+8 -11
View File
@@ -1,18 +1,15 @@
import os
import sys
sys.path.insert(0, os.path.join(os.path.dirname(os.path.dirname(
os.path.dirname(os.path.realpath(__file__)))),
"Firmware", "fibre", "python"))
# Syntactic sugar to make usage more intuative.
# Try/pass used to break install-time dep issues
try:
import fibre
find_any = fibre.find_any
find_all = fibre.find_all
except:
pass
# We want to use the fibre package that is included with the odrive package
# in order to avoid any version mismatch issues,
sys.path.insert(0, os.path.join(os.path.dirname(os.path.realpath(__file__)), "pyfibre"))
# Syntactic sugar to make usage more intuitive.
import fibre
find_any = fibre.find_any
find_all = fibre.find_all
# Standard convention is to add a __version__ attribute to the package
from .version import get_version_str
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
+31 -11
View File
@@ -9,8 +9,8 @@ from types import MethodType
import concurrent
import threading
import time
from fibre.utils import Logger, Event
import platform
from .utils import Logger, Event
lib_names = {
('Linux', 'x86_64'): 'libfibre-linux-amd64.so',
@@ -21,20 +21,40 @@ lib_names = {
system_desc = (platform.system(), platform.machine())
lib_dir = os.path.join(
os.path.dirname(os.path.dirname(os.path.dirname(os.path.realpath(__file__)))),
'cpp')
script_dir = os.path.dirname(os.path.realpath(__file__))
fibre_cpp_paths = [
os.path.join(os.path.dirname(os.path.dirname(script_dir)), "cpp"),
os.path.join(os.path.dirname(os.path.dirname(os.path.dirname(os.path.dirname(script_dir)))), "Firmware", "fibre-cpp")
]
def test_path(path):
return path if os.path.isfile(path) else None
def get_first(lst, predicate, default):
for item in lst:
if predicate(item):
return item
return default
lib_path = (test_path(os.path.join(lib_dir, 'libfibre.so')) or
test_path(os.path.join(lib_dir, 'libfibre.dll')) or
(test_path(os.path.join(lib_dir, lib_names[system_desc])) if (system_desc in lib_names) else None))
if not system_desc in lib_names:
fibre_cpp_path = get_first(fibre_cpp_paths, os.path.isdir, None)
if fibre_cpp_path is None:
instructions = ("Go to https://github.com/samuelsadok/fibre-cpp for "
"instructions on how to compile libfibre. Once you have compiled it, "
"add it to this folder.")
else:
instructions = ("Go to {} and run `make`. Then edit this file (libfibre.py) "
"to include the name of the binary that was generated by `make`.".format(fibre_cpp_path))
raise ModuleNotFoundError("libfibre is not supported on your platform ({} {}). {}".format(*system_desc, instructions))
lib_name = lib_names[system_desc]
search_paths = fibre_cpp_paths + [script_dir]
lib_path = get_first(
(os.path.join(p, lib_name) for p in search_paths),
os.path.isfile, None)
if lib_path is None:
raise ModuleNotFoundError("This package has no precompiled libfibre for your platform ({} {}). "
"Go to fibre/cpp/ and run `make` to compile libfibre for your platform.".format(*system_desc))
raise ModuleNotFoundError("{} was not found in {}".format(lib_name, search_paths))
lib = windll.LoadLibrary(lib_path) if os.name == 'nt' else cdll.LoadLibrary(lib_path)
Binary file not shown.
+1 -4
View File
@@ -19,13 +19,10 @@ import argparse
import time
import math
sys.path.insert(0, os.path.join(os.path.dirname(os.path.dirname(
os.path.realpath(__file__))),
"Firmware", "fibre", "python"))
from fibre import Logger, Event
import odrive
from odrive.utils import OperationAbortedException
from odrive.configuration import *
from fibre import Logger, Event
# Flush stdout by default
# Source:
+7 -16
View File
@@ -73,19 +73,6 @@ if creating_package:
version_file_path = os.path.join(os.path.dirname(os.path.realpath(__file__)), 'odrive', 'version.txt')
with open(version_file_path, mode='w') as version_file:
version_file.write(version)
# Temporarily link fibre into the python tools directory
# TODO: distribute a fibre package separately
fibre_src = os.path.join(os.path.dirname(os.path.dirname(
os.path.realpath(__file__))),
"Firmware", "fibre", "python", "fibre")
fibre_link = os.path.join(os.path.dirname(
os.path.realpath(__file__)), "fibre")
if not os.path.exists(fibre_link):
if sys.version_info > (3, 3):
os.symlink(fibre_src, fibre_link, target_is_directory=True)
else:
os.symlink(fibre_src, fibre_link)
# TODO: find a better place for this
if not creating_package:
@@ -99,7 +86,7 @@ if not creating_package:
try:
setup(
name = 'odrive',
packages = ['odrive', 'odrive.dfuse', 'fibre'],
packages = ['odrive', 'odrive.dfuse', 'odrive.pyfibre.fibre'],
scripts = ['odrivetool', 'odrivetool.bat', 'odrive_demo.py'],
version = version,
description = 'Control utilities for the ODrive high performance motor controller',
@@ -117,7 +104,12 @@ try:
'monotonic', # For compatibility with older python versions
'pywin32 >= 222; platform_system == "Windows"' # Required for fancy terminal features on Windows
],
package_data={'': ['version.txt']},
package_data={'': [
'version.txt',
'pyfibre/fibre/*.so',
'pyfibre/fibre/*.dll',
'pyfibre/fibre/*.dylib'
]},
classifiers = [],
)
@@ -127,4 +119,3 @@ finally:
# clean up
if creating_package:
os.remove(version_file_path)
os.remove(fibre_link)