mirror of
https://github.com/odriverobotics/ODrive.git
synced 2026-09-22 16:14:37 +08:00
add finishing touches to initial libfibre version
This commit is contained in:
@@ -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'}
|
||||
|
||||
@@ -0,0 +1 @@
|
||||
/third_party
|
||||
@@ -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
|
||||
|
||||
@@ -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.
@@ -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;
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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.
|
||||
|
||||
@@ -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
@@ -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
|
||||
|
||||
@@ -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.
|
||||
|
||||
@@ -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
|
||||
|
||||
BIN
Binary file not shown.
BIN
Binary file not shown.
Binary file not shown.
BIN
Binary file not shown.
@@ -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)
|
||||
|
||||
|
||||
BIN
Binary file not shown.
+1
-4
@@ -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
@@ -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)
|
||||
|
||||
Reference in New Issue
Block a user