diff --git a/cmake/modules/FindFreenect.cmake b/cmake/modules/FindFreenect.cmake new file mode 100644 index 0000000000..97adc4302a --- /dev/null +++ b/cmake/modules/FindFreenect.cmake @@ -0,0 +1,44 @@ +# Try to find the Freenect library to read from Kinect +# +# You must provide a FREENECT_ROOT_DIR which contains lib and include directories +# +# Once done this will define +# +# FREENECT_FOUND - system found Freenect +# FREENECT_INCLUDE_DIRS - the Freenect include directory +# FREENECT_LIBRARIES - Link this to use Freenect +# +# Created on 6/25/2013 by Andrzej Kapolka +# Copyright (c) 2013 High Fidelity +# + +if (FREENECT_LIBRARIES AND FREENECT_INCLUDE_DIRS) + # in cache already + set(FREENECT_FOUND TRUE) +else (FREENECT_LIBRARIES AND FREENECT_INCLUDE_DIRS) + find_path(FREENECT_INCLUDE_DIRS libfreenect.h ${FREENECT_ROOT_DIR}/include) + + if (APPLE) + find_library(FREENECT_LIBRARIES libfreenect.a ${FREENECT_ROOT_DIR}/lib/MacOS/) + elseif (UNIX) + find_library(FREENECT_LIBRARIES libfreenect.a ${FREENECT_ROOT_DIR}/lib/UNIX/) + endif () + + if (FREENECT_INCLUDE_DIRS AND FREENECT_LIBRARIES) + set(FREENECT_FOUND TRUE) + endif (FREENECT_INCLUDE_DIRS AND FREENECT_LIBRARIES) + + if (FREENECT_FOUND) + if (NOT FREENECT_FIND_QUIETLY) + message(STATUS "Found Freenect: ${FREENECT_LIBRARIES}") + endif (NOT FREENECT_FIND_QUIETLY) + else (FREENECT_FOUND) + if (FREENECT_FIND_REQUIRED) + message(FATAL_ERROR "Could not find Freenect") + endif (FREENECT_FIND_REQUIRED) + endif (FREENECT_FOUND) + + # show the FREENECT_INCLUDE_DIRS and FREENECT_LIBRARIES variables only in the advanced view + mark_as_advanced(FREENECT_INCLUDE_DIRS FREENECT_LIBRARIES) + +endif (FREENECT_LIBRARIES AND FREENECT_INCLUDE_DIRS) diff --git a/cmake/modules/FindLibUSB.cmake b/cmake/modules/FindLibUSB.cmake new file mode 100644 index 0000000000..f9599752a1 --- /dev/null +++ b/cmake/modules/FindLibUSB.cmake @@ -0,0 +1,44 @@ +# Try to find the LibUSB library to interact with USB devices +# +# You must provide a LIBUSB_ROOT_DIR which contains lib and include directories +# +# Once done this will define +# +# LIBUSB_FOUND - system found LibUSB +# LIBUSB_INCLUDE_DIRS - the LibUSB include directory +# LIBUSB_LIBRARIES - Link this to use LibUSB +# +# Created on 6/25/2013 by Andrzej Kapolka +# Copyright (c) 2013 High Fidelity +# + +if (LIBUSB_LIBRARIES AND LIBUSB_INCLUDE_DIRS) + # in cache already + set(LIBUSB_FOUND TRUE) +else (LIBUSB_LIBRARIES AND LIBUSB_INCLUDE_DIRS) + find_path(LIBUSB_INCLUDE_DIRS libusb.h ${LIBUSB_ROOT_DIR}/include) + + if (APPLE) + find_library(LIBUSB_LIBRARIES libusb-1.0.a ${LIBUSB_ROOT_DIR}/lib/MacOS/) + elseif (UNIX) + find_library(LIBUSB_LIBRARIES libusb-1.0.a ${LIBUSB_ROOT_DIR}/lib/UNIX/) + endif () + + if (LIBUSB_INCLUDE_DIRS AND LIBUSB_LIBRARIES) + set(LIBUSB_FOUND TRUE) + endif (LIBUSB_INCLUDE_DIRS AND LIBUSB_LIBRARIES) + + if (LIBUSB_FOUND) + if (NOT LIBUSB_FIND_QUIETLY) + message(STATUS "Found LibUSB: ${LIBUSB_LIBRARIES}") + endif (NOT LIBUSB_FIND_QUIETLY) + else (LIBUSB_FOUND) + if (LIBUSB_FIND_REQUIRED) + message(FATAL_ERROR "Could not find LibUSB") + endif (LIBUSB_FIND_REQUIRED) + endif (LIBUSB_FOUND) + + # show the LIBUSB_INCLUDE_DIRS and LIBUSB_LIBRARIES variables only in the advanced view + mark_as_advanced(LIBUSB_INCLUDE_DIRS LIBUSB_LIBRARIES) + +endif (LIBUSB_LIBRARIES AND LIBUSB_INCLUDE_DIRS) diff --git a/cmake/modules/FindSkeltrack.cmake b/cmake/modules/FindSkeltrack.cmake new file mode 100644 index 0000000000..a05e0c2990 --- /dev/null +++ b/cmake/modules/FindSkeltrack.cmake @@ -0,0 +1,44 @@ +# Try to find the Skeltrack library to perform skeleton tracking via depth camera +# +# You must provide a SKELTRACK_ROOT_DIR which contains lib and include directories +# +# Once done this will define +# +# SKELTRACK_FOUND - system found Skeltrack +# SKELTRACK_INCLUDE_DIRS - the Skeltrack include directory +# SKELTRACK_LIBRARIES - Link this to use Skeltrack +# +# Created on 6/25/2013 by Andrzej Kapolka +# Copyright (c) 2013 High Fidelity +# + +if (SKELTRACK_LIBRARIES AND SKELTRACK_INCLUDE_DIRS) + # in cache already + set(SKELTRACK_FOUND TRUE) +else (SKELTRACK_LIBRARIES AND SKELTRACK_INCLUDE_DIRS) + find_path(SKELTRACK_INCLUDE_DIRS skeltrack.h ${SKELTRACK_ROOT_DIR}/include) + + if (APPLE) + find_library(SKELTRACK_LIBRARIES libskeltrack.a ${SKELTRACK_ROOT_DIR}/lib/MacOS/) + elseif (UNIX) + find_library(SKELTRACK_LIBRARIES libskeltrack.a ${SKELTRACK_ROOT_DIR}/lib/UNIX/) + endif () + + if (SKELTRACK_INCLUDE_DIRS AND SKELTRACK_LIBRARIES) + set(SKELTRACK_FOUND TRUE) + endif (SKELTRACK_INCLUDE_DIRS AND SKELTRACK_LIBRARIES) + + if (SKELTRACK_FOUND) + if (NOT SKELTRACK_FIND_QUIETLY) + message(STATUS "Found Skeltrack: ${SKELTRACK_LIBRARIES}") + endif (NOT SKELTRACK_FIND_QUIETLY) + else (SKELTRACK_FOUND) + if (SKELTRACK_FIND_REQUIRED) + message(FATAL_ERROR "Could not find Skeltrack") + endif (SKELTRACK_FIND_REQUIRED) + endif (SKELTRACK_FOUND) + + # show the SKELTRACK_INCLUDE_DIRS and SKELTRACK_LIBRARIES variables only in the advanced view + mark_as_advanced(SKELTRACK_INCLUDE_DIRS SKELTRACK_LIBRARIES) + +endif (SKELTRACK_LIBRARIES AND SKELTRACK_INCLUDE_DIRS) diff --git a/interface/CMakeLists.txt b/interface/CMakeLists.txt index 148e6819be..234f365687 100644 --- a/interface/CMakeLists.txt +++ b/interface/CMakeLists.txt @@ -13,6 +13,9 @@ set(PORTAUDIO_ROOT_DIR ${CMAKE_CURRENT_SOURCE_DIR}/external/PortAudio) set(SPEEX_ROOT_DIR ${CMAKE_CURRENT_SOURCE_DIR}/external/Speex) set(OPENCV_ROOT_DIR ${CMAKE_CURRENT_SOURCE_DIR}/external/OpenCV) set(UVCCAMERACONTROL_ROOT_DIR ${CMAKE_CURRENT_SOURCE_DIR}/external/UVCCameraControl) +set(LIBUSB_ROOT_DIR ${CMAKE_CURRENT_SOURCE_DIR}/external/LibUSB) +set(FREENECT_ROOT_DIR ${CMAKE_CURRENT_SOURCE_DIR}/external/freenect) +set(SKELTRACK_ROOT_DIR ${CMAKE_CURRENT_SOURCE_DIR}/external/skeltrack) if (APPLE) set(GL_HEADERS "#include \n#include ") @@ -91,6 +94,9 @@ find_package(SpeexDSP REQUIRED) find_package(OpenCV) find_package(ZLIB) find_package(UVCCameraControl) +find_package(LibUSB) +find_package(Freenect) +find_package(Skeltrack) # include headers for interface and InterfaceConfig. include_directories( @@ -106,9 +112,12 @@ include_directories( ${LIBOVR_INCLUDE_DIRS} ${OPENCV_INCLUDE_DIRS} ${SPEEXDSP_INCLUDE_DIRS} + ${FREENECT_INCLUDE_DIRS} + ${SKELTRACK_INCLUDE_DIRS} ) -target_link_libraries(${TARGET_NAME} ${QT_LIBRARIES} ${OPENCV_LIBRARIES} ${ZLIB_LIBRARIES} ${SPEEXDSP_LIBRARIES}) +target_link_libraries(${TARGET_NAME} ${QT_LIBRARIES} ${OPENCV_LIBRARIES} ${ZLIB_LIBRARIES} ${SPEEXDSP_LIBRARIES} + ${FREENECT_LIBRARIES} ${SKELTRACK_LIBRARIES} ${LIBUSB_LIBRARIES}) if (APPLE) # link in required OS X frameworks and include the right GL headers diff --git a/interface/external/LibUSB/include/libusb.h b/interface/external/LibUSB/include/libusb.h new file mode 100644 index 0000000000..58b406f247 --- /dev/null +++ b/interface/external/LibUSB/include/libusb.h @@ -0,0 +1,1443 @@ +/* + * Public libusb header file + * Copyright (C) 2007-2008 Daniel Drake + * Copyright (c) 2001 Johannes Erdfelt + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#ifndef LIBUSB_H +#define LIBUSB_H + +#ifdef _MSC_VER +/* on MS environments, the inline keyword is available in C++ only */ +#define inline __inline +/* ssize_t is also not available (copy/paste from MinGW) */ +#ifndef _SSIZE_T_DEFINED +#define _SSIZE_T_DEFINED +#undef ssize_t +#ifdef _WIN64 + typedef __int64 ssize_t; +#else + typedef int ssize_t; +#endif /* _WIN64 */ +#endif /* _SSIZE_T_DEFINED */ +#endif /* _MSC_VER */ + +/* stdint.h is also not usually available on MS */ +#if defined(_MSC_VER) && (_MSC_VER < 1600) && (!defined(_STDINT)) && (!defined(_STDINT_H)) +typedef unsigned __int8 uint8_t; +typedef unsigned __int16 uint16_t; +typedef unsigned __int32 uint32_t; +#else +#include +#endif + +#include +#include +#include + +#if defined(__linux) || defined(__APPLE__) || defined(__CYGWIN__) +#include +#endif + +/* 'interface' might be defined as a macro on Windows, so we need to + * undefine it so as not to break the current libusb API, because + * libusb_config_descriptor has an 'interface' member + * As this can be problematic if you include windows.h after libusb.h + * in your sources, we force windows.h to be included first. */ +#if defined(_WIN32) || defined(__CYGWIN__) +#include +#if defined(interface) +#undef interface +#endif +#endif + +/** \def LIBUSB_CALL + * \ingroup misc + * libusb's Windows calling convention. + * + * Under Windows, the selection of available compilers and configurations + * means that, unlike other platforms, there is not one true calling + * convention (calling convention: the manner in which parameters are + * passed to funcions in the generated assembly code). + * + * Matching the Windows API itself, libusb uses the WINAPI convention (which + * translates to the stdcall convention) and guarantees that the + * library is compiled in this way. The public header file also includes + * appropriate annotations so that your own software will use the right + * convention, even if another convention is being used by default within + * your codebase. + * + * The one consideration that you must apply in your software is to mark + * all functions which you use as libusb callbacks with this LIBUSB_CALL + * annotation, so that they too get compiled for the correct calling + * convention. + * + * On non-Windows operating systems, this macro is defined as nothing. This + * means that you can apply it to your code without worrying about + * cross-platform compatibility. + */ +/* LIBUSB_CALL must be defined on both definition and declaration of libusb + * functions. You'd think that declaration would be enough, but cygwin will + * complain about conflicting types unless both are marked this way. + * The placement of this macro is important too; it must appear after the + * return type, before the function name. See internal documentation for + * API_EXPORTED. + */ +#if defined(_WIN32) || defined(__CYGWIN__) +#define LIBUSB_CALL WINAPI +#else +#define LIBUSB_CALL +#endif + +#ifdef __cplusplus +extern "C" { +#endif + +/** \def libusb_cpu_to_le16 + * \ingroup misc + * Convert a 16-bit value from host-endian to little-endian format. On + * little endian systems, this function does nothing. On big endian systems, + * the bytes are swapped. + * \param x the host-endian value to convert + * \returns the value in little-endian byte order + */ +static inline uint16_t libusb_cpu_to_le16(const uint16_t x) +{ + union { + uint8_t b8[2]; + uint16_t b16; + } _tmp; + _tmp.b8[1] = x >> 8; + _tmp.b8[0] = x & 0xff; + return _tmp.b16; +} + +/** \def libusb_le16_to_cpu + * \ingroup misc + * Convert a 16-bit value from little-endian to host-endian format. On + * little endian systems, this function does nothing. On big endian systems, + * the bytes are swapped. + * \param x the little-endian value to convert + * \returns the value in host-endian byte order + */ +#define libusb_le16_to_cpu libusb_cpu_to_le16 + +/* standard USB stuff */ + +/** \ingroup desc + * Device and/or Interface Class codes */ +enum libusb_class_code { + /** In the context of a \ref libusb_device_descriptor "device descriptor", + * this bDeviceClass value indicates that each interface specifies its + * own class information and all interfaces operate independently. + */ + LIBUSB_CLASS_PER_INTERFACE = 0, + + /** Audio class */ + LIBUSB_CLASS_AUDIO = 1, + + /** Communications class */ + LIBUSB_CLASS_COMM = 2, + + /** Human Interface Device class */ + LIBUSB_CLASS_HID = 3, + + /** Physical */ + LIBUSB_CLASS_PHYSICAL = 5, + + /** Printer class */ + LIBUSB_CLASS_PRINTER = 7, + + /** Image class */ + LIBUSB_CLASS_PTP = 6, /* legacy name from libusb-0.1 usb.h */ + LIBUSB_CLASS_IMAGE = 6, + + /** Mass storage class */ + LIBUSB_CLASS_MASS_STORAGE = 8, + + /** Hub class */ + LIBUSB_CLASS_HUB = 9, + + /** Data class */ + LIBUSB_CLASS_DATA = 10, + + /** Smart Card */ + LIBUSB_CLASS_SMART_CARD = 0x0b, + + /** Content Security */ + LIBUSB_CLASS_CONTENT_SECURITY = 0x0d, + + /** Video */ + LIBUSB_CLASS_VIDEO = 0x0e, + + /** Personal Healthcare */ + LIBUSB_CLASS_PERSONAL_HEALTHCARE = 0x0f, + + /** Diagnostic Device */ + LIBUSB_CLASS_DIAGNOSTIC_DEVICE = 0xdc, + + /** Wireless class */ + LIBUSB_CLASS_WIRELESS = 0xe0, + + /** Application class */ + LIBUSB_CLASS_APPLICATION = 0xfe, + + /** Class is vendor-specific */ + LIBUSB_CLASS_VENDOR_SPEC = 0xff +}; + +/** \ingroup desc + * Descriptor types as defined by the USB specification. */ +enum libusb_descriptor_type { + /** Device descriptor. See libusb_device_descriptor. */ + LIBUSB_DT_DEVICE = 0x01, + + /** Configuration descriptor. See libusb_config_descriptor. */ + LIBUSB_DT_CONFIG = 0x02, + + /** String descriptor */ + LIBUSB_DT_STRING = 0x03, + + /** Interface descriptor. See libusb_interface_descriptor. */ + LIBUSB_DT_INTERFACE = 0x04, + + /** Endpoint descriptor. See libusb_endpoint_descriptor. */ + LIBUSB_DT_ENDPOINT = 0x05, + + /** HID descriptor */ + LIBUSB_DT_HID = 0x21, + + /** HID report descriptor */ + LIBUSB_DT_REPORT = 0x22, + + /** Physical descriptor */ + LIBUSB_DT_PHYSICAL = 0x23, + + /** Hub descriptor */ + LIBUSB_DT_HUB = 0x29, +}; + +/* Descriptor sizes per descriptor type */ +#define LIBUSB_DT_DEVICE_SIZE 18 +#define LIBUSB_DT_CONFIG_SIZE 9 +#define LIBUSB_DT_INTERFACE_SIZE 9 +#define LIBUSB_DT_ENDPOINT_SIZE 7 +#define LIBUSB_DT_ENDPOINT_AUDIO_SIZE 9 /* Audio extension */ +#define LIBUSB_DT_HUB_NONVAR_SIZE 7 + +#define LIBUSB_ENDPOINT_ADDRESS_MASK 0x0f /* in bEndpointAddress */ +#define LIBUSB_ENDPOINT_DIR_MASK 0x80 + +/** \ingroup desc + * Endpoint direction. Values for bit 7 of the + * \ref libusb_endpoint_descriptor::bEndpointAddress "endpoint address" scheme. + */ +enum libusb_endpoint_direction { + /** In: device-to-host */ + LIBUSB_ENDPOINT_IN = 0x80, + + /** Out: host-to-device */ + LIBUSB_ENDPOINT_OUT = 0x00 +}; + +#define LIBUSB_TRANSFER_TYPE_MASK 0x03 /* in bmAttributes */ + +/** \ingroup desc + * Endpoint transfer type. Values for bits 0:1 of the + * \ref libusb_endpoint_descriptor::bmAttributes "endpoint attributes" field. + */ +enum libusb_transfer_type { + /** Control endpoint */ + LIBUSB_TRANSFER_TYPE_CONTROL = 0, + + /** Isochronous endpoint */ + LIBUSB_TRANSFER_TYPE_ISOCHRONOUS = 1, + + /** Bulk endpoint */ + LIBUSB_TRANSFER_TYPE_BULK = 2, + + /** Interrupt endpoint */ + LIBUSB_TRANSFER_TYPE_INTERRUPT = 3 +}; + +/** \ingroup misc + * Standard requests, as defined in table 9-3 of the USB2 specifications */ +enum libusb_standard_request { + /** Request status of the specific recipient */ + LIBUSB_REQUEST_GET_STATUS = 0x00, + + /** Clear or disable a specific feature */ + LIBUSB_REQUEST_CLEAR_FEATURE = 0x01, + + /* 0x02 is reserved */ + + /** Set or enable a specific feature */ + LIBUSB_REQUEST_SET_FEATURE = 0x03, + + /* 0x04 is reserved */ + + /** Set device address for all future accesses */ + LIBUSB_REQUEST_SET_ADDRESS = 0x05, + + /** Get the specified descriptor */ + LIBUSB_REQUEST_GET_DESCRIPTOR = 0x06, + + /** Used to update existing descriptors or add new descriptors */ + LIBUSB_REQUEST_SET_DESCRIPTOR = 0x07, + + /** Get the current device configuration value */ + LIBUSB_REQUEST_GET_CONFIGURATION = 0x08, + + /** Set device configuration */ + LIBUSB_REQUEST_SET_CONFIGURATION = 0x09, + + /** Return the selected alternate setting for the specified interface */ + LIBUSB_REQUEST_GET_INTERFACE = 0x0A, + + /** Select an alternate interface for the specified interface */ + LIBUSB_REQUEST_SET_INTERFACE = 0x0B, + + /** Set then report an endpoint's synchronization frame */ + LIBUSB_REQUEST_SYNCH_FRAME = 0x0C, +}; + +/** \ingroup misc + * Request type bits of the + * \ref libusb_control_setup::bmRequestType "bmRequestType" field in control + * transfers. */ +enum libusb_request_type { + /** Standard */ + LIBUSB_REQUEST_TYPE_STANDARD = (0x00 << 5), + + /** Class */ + LIBUSB_REQUEST_TYPE_CLASS = (0x01 << 5), + + /** Vendor */ + LIBUSB_REQUEST_TYPE_VENDOR = (0x02 << 5), + + /** Reserved */ + LIBUSB_REQUEST_TYPE_RESERVED = (0x03 << 5) +}; + +/** \ingroup misc + * Recipient bits of the + * \ref libusb_control_setup::bmRequestType "bmRequestType" field in control + * transfers. Values 4 through 31 are reserved. */ +enum libusb_request_recipient { + /** Device */ + LIBUSB_RECIPIENT_DEVICE = 0x00, + + /** Interface */ + LIBUSB_RECIPIENT_INTERFACE = 0x01, + + /** Endpoint */ + LIBUSB_RECIPIENT_ENDPOINT = 0x02, + + /** Other */ + LIBUSB_RECIPIENT_OTHER = 0x03, +}; + +#define LIBUSB_ISO_SYNC_TYPE_MASK 0x0C + +/** \ingroup desc + * Synchronization type for isochronous endpoints. Values for bits 2:3 of the + * \ref libusb_endpoint_descriptor::bmAttributes "bmAttributes" field in + * libusb_endpoint_descriptor. + */ +enum libusb_iso_sync_type { + /** No synchronization */ + LIBUSB_ISO_SYNC_TYPE_NONE = 0, + + /** Asynchronous */ + LIBUSB_ISO_SYNC_TYPE_ASYNC = 1, + + /** Adaptive */ + LIBUSB_ISO_SYNC_TYPE_ADAPTIVE = 2, + + /** Synchronous */ + LIBUSB_ISO_SYNC_TYPE_SYNC = 3 +}; + +#define LIBUSB_ISO_USAGE_TYPE_MASK 0x30 + +/** \ingroup desc + * Usage type for isochronous endpoints. Values for bits 4:5 of the + * \ref libusb_endpoint_descriptor::bmAttributes "bmAttributes" field in + * libusb_endpoint_descriptor. + */ +enum libusb_iso_usage_type { + /** Data endpoint */ + LIBUSB_ISO_USAGE_TYPE_DATA = 0, + + /** Feedback endpoint */ + LIBUSB_ISO_USAGE_TYPE_FEEDBACK = 1, + + /** Implicit feedback Data endpoint */ + LIBUSB_ISO_USAGE_TYPE_IMPLICIT = 2, +}; + +/** \ingroup desc + * A structure representing the standard USB device descriptor. This + * descriptor is documented in section 9.6.1 of the USB 2.0 specification. + * All multiple-byte fields are represented in host-endian format. + */ +struct libusb_device_descriptor { + /** Size of this descriptor (in bytes) */ + uint8_t bLength; + + /** Descriptor type. Will have value + * \ref libusb_descriptor_type::LIBUSB_DT_DEVICE LIBUSB_DT_DEVICE in this + * context. */ + uint8_t bDescriptorType; + + /** USB specification release number in binary-coded decimal. A value of + * 0x0200 indicates USB 2.0, 0x0110 indicates USB 1.1, etc. */ + uint16_t bcdUSB; + + /** USB-IF class code for the device. See \ref libusb_class_code. */ + uint8_t bDeviceClass; + + /** USB-IF subclass code for the device, qualified by the bDeviceClass + * value */ + uint8_t bDeviceSubClass; + + /** USB-IF protocol code for the device, qualified by the bDeviceClass and + * bDeviceSubClass values */ + uint8_t bDeviceProtocol; + + /** Maximum packet size for endpoint 0 */ + uint8_t bMaxPacketSize0; + + /** USB-IF vendor ID */ + uint16_t idVendor; + + /** USB-IF product ID */ + uint16_t idProduct; + + /** Device release number in binary-coded decimal */ + uint16_t bcdDevice; + + /** Index of string descriptor describing manufacturer */ + uint8_t iManufacturer; + + /** Index of string descriptor describing product */ + uint8_t iProduct; + + /** Index of string descriptor containing device serial number */ + uint8_t iSerialNumber; + + /** Number of possible configurations */ + uint8_t bNumConfigurations; +}; + +/** \ingroup desc + * A structure representing the standard USB endpoint descriptor. This + * descriptor is documented in section 9.6.3 of the USB 2.0 specification. + * All multiple-byte fields are represented in host-endian format. + */ +struct libusb_endpoint_descriptor { + /** Size of this descriptor (in bytes) */ + uint8_t bLength; + + /** Descriptor type. Will have value + * \ref libusb_descriptor_type::LIBUSB_DT_ENDPOINT LIBUSB_DT_ENDPOINT in + * this context. */ + uint8_t bDescriptorType; + + /** The address of the endpoint described by this descriptor. Bits 0:3 are + * the endpoint number. Bits 4:6 are reserved. Bit 7 indicates direction, + * see \ref libusb_endpoint_direction. + */ + uint8_t bEndpointAddress; + + /** Attributes which apply to the endpoint when it is configured using + * the bConfigurationValue. Bits 0:1 determine the transfer type and + * correspond to \ref libusb_transfer_type. Bits 2:3 are only used for + * isochronous endpoints and correspond to \ref libusb_iso_sync_type. + * Bits 4:5 are also only used for isochronous endpoints and correspond to + * \ref libusb_iso_usage_type. Bits 6:7 are reserved. + */ + uint8_t bmAttributes; + + /** Maximum packet size this endpoint is capable of sending/receiving. */ + uint16_t wMaxPacketSize; + + /** Interval for polling endpoint for data transfers. */ + uint8_t bInterval; + + /** For audio devices only: the rate at which synchronization feedback + * is provided. */ + uint8_t bRefresh; + + /** For audio devices only: the address if the synch endpoint */ + uint8_t bSynchAddress; + + /** Extra descriptors. If libusb encounters unknown endpoint descriptors, + * it will store them here, should you wish to parse them. */ + const unsigned char *extra; + + /** Length of the extra descriptors, in bytes. */ + int extra_length; +}; + +/** \ingroup desc + * A structure representing the standard USB interface descriptor. This + * descriptor is documented in section 9.6.5 of the USB 2.0 specification. + * All multiple-byte fields are represented in host-endian format. + */ +struct libusb_interface_descriptor { + /** Size of this descriptor (in bytes) */ + uint8_t bLength; + + /** Descriptor type. Will have value + * \ref libusb_descriptor_type::LIBUSB_DT_INTERFACE LIBUSB_DT_INTERFACE + * in this context. */ + uint8_t bDescriptorType; + + /** Number of this interface */ + uint8_t bInterfaceNumber; + + /** Value used to select this alternate setting for this interface */ + uint8_t bAlternateSetting; + + /** Number of endpoints used by this interface (excluding the control + * endpoint). */ + uint8_t bNumEndpoints; + + /** USB-IF class code for this interface. See \ref libusb_class_code. */ + uint8_t bInterfaceClass; + + /** USB-IF subclass code for this interface, qualified by the + * bInterfaceClass value */ + uint8_t bInterfaceSubClass; + + /** USB-IF protocol code for this interface, qualified by the + * bInterfaceClass and bInterfaceSubClass values */ + uint8_t bInterfaceProtocol; + + /** Index of string descriptor describing this interface */ + uint8_t iInterface; + + /** Array of endpoint descriptors. This length of this array is determined + * by the bNumEndpoints field. */ + const struct libusb_endpoint_descriptor *endpoint; + + /** Extra descriptors. If libusb encounters unknown interface descriptors, + * it will store them here, should you wish to parse them. */ + const unsigned char *extra; + + /** Length of the extra descriptors, in bytes. */ + int extra_length; +}; + +/** \ingroup desc + * A collection of alternate settings for a particular USB interface. + */ +struct libusb_interface { + /** Array of interface descriptors. The length of this array is determined + * by the num_altsetting field. */ + const struct libusb_interface_descriptor *altsetting; + + /** The number of alternate settings that belong to this interface */ + int num_altsetting; +}; + +/** \ingroup desc + * A structure representing the standard USB configuration descriptor. This + * descriptor is documented in section 9.6.3 of the USB 2.0 specification. + * All multiple-byte fields are represented in host-endian format. + */ +struct libusb_config_descriptor { + /** Size of this descriptor (in bytes) */ + uint8_t bLength; + + /** Descriptor type. Will have value + * \ref libusb_descriptor_type::LIBUSB_DT_CONFIG LIBUSB_DT_CONFIG + * in this context. */ + uint8_t bDescriptorType; + + /** Total length of data returned for this configuration */ + uint16_t wTotalLength; + + /** Number of interfaces supported by this configuration */ + uint8_t bNumInterfaces; + + /** Identifier value for this configuration */ + uint8_t bConfigurationValue; + + /** Index of string descriptor describing this configuration */ + uint8_t iConfiguration; + + /** Configuration characteristics */ + uint8_t bmAttributes; + + /** Maximum power consumption of the USB device from this bus in this + * configuration when the device is fully opreation. Expressed in units + * of 2 mA. */ + uint8_t MaxPower; + + /** Array of interfaces supported by this configuration. The length of + * this array is determined by the bNumInterfaces field. */ + const struct libusb_interface *interface; + + /** Extra descriptors. If libusb encounters unknown configuration + * descriptors, it will store them here, should you wish to parse them. */ + const unsigned char *extra; + + /** Length of the extra descriptors, in bytes. */ + int extra_length; +}; + +/** \ingroup asyncio + * Setup packet for control transfers. */ +struct libusb_control_setup { + /** Request type. Bits 0:4 determine recipient, see + * \ref libusb_request_recipient. Bits 5:6 determine type, see + * \ref libusb_request_type. Bit 7 determines data transfer direction, see + * \ref libusb_endpoint_direction. + */ + uint8_t bmRequestType; + + /** Request. If the type bits of bmRequestType are equal to + * \ref libusb_request_type::LIBUSB_REQUEST_TYPE_STANDARD + * "LIBUSB_REQUEST_TYPE_STANDARD" then this field refers to + * \ref libusb_standard_request. For other cases, use of this field is + * application-specific. */ + uint8_t bRequest; + + /** Value. Varies according to request */ + uint16_t wValue; + + /** Index. Varies according to request, typically used to pass an index + * or offset */ + uint16_t wIndex; + + /** Number of bytes to transfer */ + uint16_t wLength; +}; + +#define LIBUSB_CONTROL_SETUP_SIZE (sizeof(struct libusb_control_setup)) + +/* libusb */ + +struct libusb_context; +struct libusb_device; +struct libusb_device_handle; + +/** \ingroup lib + * Structure representing the libusb version. + */ +struct libusb_version { + /** Library major version. */ + const uint16_t major; + + /** Library minor version. */ + const uint16_t minor; + + /** Library micro version. */ + const uint16_t micro; + + /** Library nano version. This field is only nonzero on Windows. */ + const uint16_t nano; + + /** Library release candidate suffix string, e.g. "-rc4". */ + const char *rc; + + /** Output of `git describe --tags` at library build time. */ + const char *describe; +}; + +/** \ingroup lib + * Structure representing a libusb session. The concept of individual libusb + * sessions allows for your program to use two libraries (or dynamically + * load two modules) which both independently use libusb. This will prevent + * interference between the individual libusb users - for example + * libusb_set_debug() will not affect the other user of the library, and + * libusb_exit() will not destroy resources that the other user is still + * using. + * + * Sessions are created by libusb_init() and destroyed through libusb_exit(). + * If your application is guaranteed to only ever include a single libusb + * user (i.e. you), you do not have to worry about contexts: pass NULL in + * every function call where a context is required. The default context + * will be used. + * + * For more information, see \ref contexts. + */ +typedef struct libusb_context libusb_context; + +/** \ingroup dev + * Structure representing a USB device detected on the system. This is an + * opaque type for which you are only ever provided with a pointer, usually + * originating from libusb_get_device_list(). + * + * Certain operations can be performed on a device, but in order to do any + * I/O you will have to first obtain a device handle using libusb_open(). + * + * Devices are reference counted with libusb_device_ref() and + * libusb_device_unref(), and are freed when the reference count reaches 0. + * New devices presented by libusb_get_device_list() have a reference count of + * 1, and libusb_free_device_list() can optionally decrease the reference count + * on all devices in the list. libusb_open() adds another reference which is + * later destroyed by libusb_close(). + */ +typedef struct libusb_device libusb_device; + + +/** \ingroup dev + * Structure representing a handle on a USB device. This is an opaque type for + * which you are only ever provided with a pointer, usually originating from + * libusb_open(). + * + * A device handle is used to perform I/O and other operations. When finished + * with a device handle, you should call libusb_close(). + */ +typedef struct libusb_device_handle libusb_device_handle; + +/** \ingroup dev + * Speed codes. Indicates the speed at which the device is operating. + */ +enum libusb_speed { + /** The OS doesn't report or know the device speed. */ + LIBUSB_SPEED_UNKNOWN = 0, + + /** The device is operating at low speed (1.5MBit/s). */ + LIBUSB_SPEED_LOW = 1, + + /** The device is operating at full speed (12MBit/s). */ + LIBUSB_SPEED_FULL = 2, + + /** The device is operating at high speed (480MBit/s). */ + LIBUSB_SPEED_HIGH = 3, + + /** The device is operating at super speed (5000MBit/s). */ + LIBUSB_SPEED_SUPER = 4, +}; + +/** \ingroup misc + * Error codes. Most libusb functions return 0 on success or one of these + * codes on failure. + * You can call \ref libusb_error_name() to retrieve a string representation + * of an error code. + */ +enum libusb_error { + /** Success (no error) */ + LIBUSB_SUCCESS = 0, + + /** Input/output error */ + LIBUSB_ERROR_IO = -1, + + /** Invalid parameter */ + LIBUSB_ERROR_INVALID_PARAM = -2, + + /** Access denied (insufficient permissions) */ + LIBUSB_ERROR_ACCESS = -3, + + /** No such device (it may have been disconnected) */ + LIBUSB_ERROR_NO_DEVICE = -4, + + /** Entity not found */ + LIBUSB_ERROR_NOT_FOUND = -5, + + /** Resource busy */ + LIBUSB_ERROR_BUSY = -6, + + /** Operation timed out */ + LIBUSB_ERROR_TIMEOUT = -7, + + /** Overflow */ + LIBUSB_ERROR_OVERFLOW = -8, + + /** Pipe error */ + LIBUSB_ERROR_PIPE = -9, + + /** System call interrupted (perhaps due to signal) */ + LIBUSB_ERROR_INTERRUPTED = -10, + + /** Insufficient memory */ + LIBUSB_ERROR_NO_MEM = -11, + + /** Operation not supported or unimplemented on this platform */ + LIBUSB_ERROR_NOT_SUPPORTED = -12, + + /* NB! Remember to update libusb_error_name() + when adding new error codes here. */ + + /** Other error */ + LIBUSB_ERROR_OTHER = -99, +}; + +/** \ingroup asyncio + * Transfer status codes */ +enum libusb_transfer_status { + /** Transfer completed without error. Note that this does not indicate + * that the entire amount of requested data was transferred. */ + LIBUSB_TRANSFER_COMPLETED, + + /** Transfer failed */ + LIBUSB_TRANSFER_ERROR, + + /** Transfer timed out */ + LIBUSB_TRANSFER_TIMED_OUT, + + /** Transfer was cancelled */ + LIBUSB_TRANSFER_CANCELLED, + + /** For bulk/interrupt endpoints: halt condition detected (endpoint + * stalled). For control endpoints: control request not supported. */ + LIBUSB_TRANSFER_STALL, + + /** Device was disconnected */ + LIBUSB_TRANSFER_NO_DEVICE, + + /** Device sent more data than requested */ + LIBUSB_TRANSFER_OVERFLOW, +}; + +/** \ingroup asyncio + * libusb_transfer.flags values */ +enum libusb_transfer_flags { + /** Report short frames as errors */ + LIBUSB_TRANSFER_SHORT_NOT_OK = 1<<0, + + /** Automatically free() transfer buffer during libusb_free_transfer() */ + LIBUSB_TRANSFER_FREE_BUFFER = 1<<1, + + /** Automatically call libusb_free_transfer() after callback returns. + * If this flag is set, it is illegal to call libusb_free_transfer() + * from your transfer callback, as this will result in a double-free + * when this flag is acted upon. */ + LIBUSB_TRANSFER_FREE_TRANSFER = 1<<2, + + /** Terminate transfers that are a multiple of the endpoint's + * wMaxPacketSize with an extra zero length packet. This is useful + * when a device protocol mandates that each logical request is + * terminated by an incomplete packet (i.e. the logical requests are + * not separated by other means). + * + * This flag only affects host-to-device transfers to bulk and interrupt + * endpoints. In other situations, it is ignored. + * + * This flag only affects transfers with a length that is a multiple of + * the endpoint's wMaxPacketSize. On transfers of other lengths, this + * flag has no effect. Therefore, if you are working with a device that + * needs a ZLP whenever the end of the logical request falls on a packet + * boundary, then it is sensible to set this flag on every + * transfer (you do not have to worry about only setting it on transfers + * that end on the boundary). + * + * This flag is currently only supported on Linux. + * On other systems, libusb_submit_transfer() will return + * LIBUSB_ERROR_NOT_SUPPORTED for every transfer where this flag is set. + * + * Available since libusb-1.0.9. + */ + LIBUSB_TRANSFER_ADD_ZERO_PACKET = 1 << 3, +}; + +/** \ingroup asyncio + * Isochronous packet descriptor. */ +struct libusb_iso_packet_descriptor { + /** Length of data to request in this packet */ + unsigned int length; + + /** Amount of data that was actually transferred */ + unsigned int actual_length; + + /** Status code for this packet */ + enum libusb_transfer_status status; +}; + +struct libusb_transfer; + +/** \ingroup asyncio + * Asynchronous transfer callback function type. When submitting asynchronous + * transfers, you pass a pointer to a callback function of this type via the + * \ref libusb_transfer::callback "callback" member of the libusb_transfer + * structure. libusb will call this function later, when the transfer has + * completed or failed. See \ref asyncio for more information. + * \param transfer The libusb_transfer struct the callback function is being + * notified about. + */ +typedef void (LIBUSB_CALL *libusb_transfer_cb_fn)(struct libusb_transfer *transfer); + +/** \ingroup asyncio + * The generic USB transfer structure. The user populates this structure and + * then submits it in order to request a transfer. After the transfer has + * completed, the library populates the transfer with the results and passes + * it back to the user. + */ +struct libusb_transfer { + /** Handle of the device that this transfer will be submitted to */ + libusb_device_handle *dev_handle; + + /** A bitwise OR combination of \ref libusb_transfer_flags. */ + uint8_t flags; + + /** Address of the endpoint where this transfer will be sent. */ + unsigned char endpoint; + + /** Type of the endpoint from \ref libusb_transfer_type */ + unsigned char type; + + /** Timeout for this transfer in millseconds. A value of 0 indicates no + * timeout. */ + unsigned int timeout; + + /** The status of the transfer. Read-only, and only for use within + * transfer callback function. + * + * If this is an isochronous transfer, this field may read COMPLETED even + * if there were errors in the frames. Use the + * \ref libusb_iso_packet_descriptor::status "status" field in each packet + * to determine if errors occurred. */ + enum libusb_transfer_status status; + + /** Length of the data buffer */ + int length; + + /** Actual length of data that was transferred. Read-only, and only for + * use within transfer callback function. Not valid for isochronous + * endpoint transfers. */ + int actual_length; + + /** Callback function. This will be invoked when the transfer completes, + * fails, or is cancelled. */ + libusb_transfer_cb_fn callback; + + /** User context data to pass to the callback function. */ + void *user_data; + + /** Data buffer */ + unsigned char *buffer; + + /** Number of isochronous packets. Only used for I/O with isochronous + * endpoints. */ + int num_iso_packets; + + /** Isochronous packet descriptors, for isochronous transfers only. */ + struct libusb_iso_packet_descriptor iso_packet_desc +#if defined(__STDC_VERSION__) && (__STDC_VERSION__ >= 199901L) + [] /* valid C99 code */ +#else + [0] /* non-standard, but usually working code */ +#endif + ; +}; + +/** \ingroup misc + * Capabilities supported by this instance of libusb. Test if the loaded + * library supports a given capability by calling + * \ref libusb_has_capability(). + */ +enum libusb_capability { + /** The libusb_has_capability() API is available. */ + LIBUSB_CAP_HAS_CAPABILITY = 0, +}; + +int LIBUSB_CALL libusb_init(libusb_context **ctx); +void LIBUSB_CALL libusb_exit(libusb_context *ctx); +void LIBUSB_CALL libusb_set_debug(libusb_context *ctx, int level); +const struct libusb_version * LIBUSB_CALL libusb_get_version(void); +int LIBUSB_CALL libusb_has_capability(uint32_t capability); +const char * LIBUSB_CALL libusb_error_name(int errcode); + +ssize_t LIBUSB_CALL libusb_get_device_list(libusb_context *ctx, + libusb_device ***list); +void LIBUSB_CALL libusb_free_device_list(libusb_device **list, + int unref_devices); +libusb_device * LIBUSB_CALL libusb_ref_device(libusb_device *dev); +void LIBUSB_CALL libusb_unref_device(libusb_device *dev); + +int LIBUSB_CALL libusb_get_configuration(libusb_device_handle *dev, + int *config); +int LIBUSB_CALL libusb_get_device_descriptor(libusb_device *dev, + struct libusb_device_descriptor *desc); +int LIBUSB_CALL libusb_get_active_config_descriptor(libusb_device *dev, + struct libusb_config_descriptor **config); +int LIBUSB_CALL libusb_get_config_descriptor(libusb_device *dev, + uint8_t config_index, struct libusb_config_descriptor **config); +int LIBUSB_CALL libusb_get_config_descriptor_by_value(libusb_device *dev, + uint8_t bConfigurationValue, struct libusb_config_descriptor **config); +void LIBUSB_CALL libusb_free_config_descriptor( + struct libusb_config_descriptor *config); +uint8_t LIBUSB_CALL libusb_get_bus_number(libusb_device *dev); +uint8_t LIBUSB_CALL libusb_get_device_address(libusb_device *dev); +int LIBUSB_CALL libusb_get_device_speed(libusb_device *dev); +int LIBUSB_CALL libusb_get_max_packet_size(libusb_device *dev, + unsigned char endpoint); +int LIBUSB_CALL libusb_get_max_iso_packet_size(libusb_device *dev, + unsigned char endpoint); + +int LIBUSB_CALL libusb_open(libusb_device *dev, libusb_device_handle **handle); +void LIBUSB_CALL libusb_close(libusb_device_handle *dev_handle); +libusb_device * LIBUSB_CALL libusb_get_device(libusb_device_handle *dev_handle); + +int LIBUSB_CALL libusb_set_configuration(libusb_device_handle *dev, + int configuration); +int LIBUSB_CALL libusb_claim_interface(libusb_device_handle *dev, + int interface_number); +int LIBUSB_CALL libusb_release_interface(libusb_device_handle *dev, + int interface_number); + +libusb_device_handle * LIBUSB_CALL libusb_open_device_with_vid_pid( + libusb_context *ctx, uint16_t vendor_id, uint16_t product_id); + +int LIBUSB_CALL libusb_set_interface_alt_setting(libusb_device_handle *dev, + int interface_number, int alternate_setting); +int LIBUSB_CALL libusb_clear_halt(libusb_device_handle *dev, + unsigned char endpoint); +int LIBUSB_CALL libusb_reset_device(libusb_device_handle *dev); + +int LIBUSB_CALL libusb_kernel_driver_active(libusb_device_handle *dev, + int interface_number); +int LIBUSB_CALL libusb_detach_kernel_driver(libusb_device_handle *dev, + int interface_number); +int LIBUSB_CALL libusb_attach_kernel_driver(libusb_device_handle *dev, + int interface_number); + +/* async I/O */ + +/** \ingroup asyncio + * Get the data section of a control transfer. This convenience function is here + * to remind you that the data does not start until 8 bytes into the actual + * buffer, as the setup packet comes first. + * + * Calling this function only makes sense from a transfer callback function, + * or situations where you have already allocated a suitably sized buffer at + * transfer->buffer. + * + * \param transfer a transfer + * \returns pointer to the first byte of the data section + */ +static inline unsigned char *libusb_control_transfer_get_data( + struct libusb_transfer *transfer) +{ + return transfer->buffer + LIBUSB_CONTROL_SETUP_SIZE; +} + +/** \ingroup asyncio + * Get the control setup packet of a control transfer. This convenience + * function is here to remind you that the control setup occupies the first + * 8 bytes of the transfer data buffer. + * + * Calling this function only makes sense from a transfer callback function, + * or situations where you have already allocated a suitably sized buffer at + * transfer->buffer. + * + * \param transfer a transfer + * \returns a casted pointer to the start of the transfer data buffer + */ +static inline struct libusb_control_setup *libusb_control_transfer_get_setup( + struct libusb_transfer *transfer) +{ + return (struct libusb_control_setup *) transfer->buffer; +} + +/** \ingroup asyncio + * Helper function to populate the setup packet (first 8 bytes of the data + * buffer) for a control transfer. The wIndex, wValue and wLength values should + * be given in host-endian byte order. + * + * \param buffer buffer to output the setup packet into + * \param bmRequestType see the + * \ref libusb_control_setup::bmRequestType "bmRequestType" field of + * \ref libusb_control_setup + * \param bRequest see the + * \ref libusb_control_setup::bRequest "bRequest" field of + * \ref libusb_control_setup + * \param wValue see the + * \ref libusb_control_setup::wValue "wValue" field of + * \ref libusb_control_setup + * \param wIndex see the + * \ref libusb_control_setup::wIndex "wIndex" field of + * \ref libusb_control_setup + * \param wLength see the + * \ref libusb_control_setup::wLength "wLength" field of + * \ref libusb_control_setup + */ +static inline void libusb_fill_control_setup(unsigned char *buffer, + uint8_t bmRequestType, uint8_t bRequest, uint16_t wValue, uint16_t wIndex, + uint16_t wLength) +{ + struct libusb_control_setup *setup = (struct libusb_control_setup *) buffer; + setup->bmRequestType = bmRequestType; + setup->bRequest = bRequest; + setup->wValue = libusb_cpu_to_le16(wValue); + setup->wIndex = libusb_cpu_to_le16(wIndex); + setup->wLength = libusb_cpu_to_le16(wLength); +} + +struct libusb_transfer * LIBUSB_CALL libusb_alloc_transfer(int iso_packets); +int LIBUSB_CALL libusb_submit_transfer(struct libusb_transfer *transfer); +int LIBUSB_CALL libusb_cancel_transfer(struct libusb_transfer *transfer); +void LIBUSB_CALL libusb_free_transfer(struct libusb_transfer *transfer); + +/** \ingroup asyncio + * Helper function to populate the required \ref libusb_transfer fields + * for a control transfer. + * + * If you pass a transfer buffer to this function, the first 8 bytes will + * be interpreted as a control setup packet, and the wLength field will be + * used to automatically populate the \ref libusb_transfer::length "length" + * field of the transfer. Therefore the recommended approach is: + * -# Allocate a suitably sized data buffer (including space for control setup) + * -# Call libusb_fill_control_setup() + * -# If this is a host-to-device transfer with a data stage, put the data + * in place after the setup packet + * -# Call this function + * -# Call libusb_submit_transfer() + * + * It is also legal to pass a NULL buffer to this function, in which case this + * function will not attempt to populate the length field. Remember that you + * must then populate the buffer and length fields later. + * + * \param transfer the transfer to populate + * \param dev_handle handle of the device that will handle the transfer + * \param buffer data buffer. If provided, this function will interpret the + * first 8 bytes as a setup packet and infer the transfer length from that. + * \param callback callback function to be invoked on transfer completion + * \param user_data user data to pass to callback function + * \param timeout timeout for the transfer in milliseconds + */ +static inline void libusb_fill_control_transfer( + struct libusb_transfer *transfer, libusb_device_handle *dev_handle, + unsigned char *buffer, libusb_transfer_cb_fn callback, void *user_data, + unsigned int timeout) +{ + struct libusb_control_setup *setup = (struct libusb_control_setup *) buffer; + transfer->dev_handle = dev_handle; + transfer->endpoint = 0; + transfer->type = LIBUSB_TRANSFER_TYPE_CONTROL; + transfer->timeout = timeout; + transfer->buffer = buffer; + if (setup) + transfer->length = LIBUSB_CONTROL_SETUP_SIZE + + libusb_le16_to_cpu(setup->wLength); + transfer->user_data = user_data; + transfer->callback = callback; +} + +/** \ingroup asyncio + * Helper function to populate the required \ref libusb_transfer fields + * for a bulk transfer. + * + * \param transfer the transfer to populate + * \param dev_handle handle of the device that will handle the transfer + * \param endpoint address of the endpoint where this transfer will be sent + * \param buffer data buffer + * \param length length of data buffer + * \param callback callback function to be invoked on transfer completion + * \param user_data user data to pass to callback function + * \param timeout timeout for the transfer in milliseconds + */ +static inline void libusb_fill_bulk_transfer(struct libusb_transfer *transfer, + libusb_device_handle *dev_handle, unsigned char endpoint, + unsigned char *buffer, int length, libusb_transfer_cb_fn callback, + void *user_data, unsigned int timeout) +{ + transfer->dev_handle = dev_handle; + transfer->endpoint = endpoint; + transfer->type = LIBUSB_TRANSFER_TYPE_BULK; + transfer->timeout = timeout; + transfer->buffer = buffer; + transfer->length = length; + transfer->user_data = user_data; + transfer->callback = callback; +} + +/** \ingroup asyncio + * Helper function to populate the required \ref libusb_transfer fields + * for an interrupt transfer. + * + * \param transfer the transfer to populate + * \param dev_handle handle of the device that will handle the transfer + * \param endpoint address of the endpoint where this transfer will be sent + * \param buffer data buffer + * \param length length of data buffer + * \param callback callback function to be invoked on transfer completion + * \param user_data user data to pass to callback function + * \param timeout timeout for the transfer in milliseconds + */ +static inline void libusb_fill_interrupt_transfer( + struct libusb_transfer *transfer, libusb_device_handle *dev_handle, + unsigned char endpoint, unsigned char *buffer, int length, + libusb_transfer_cb_fn callback, void *user_data, unsigned int timeout) +{ + transfer->dev_handle = dev_handle; + transfer->endpoint = endpoint; + transfer->type = LIBUSB_TRANSFER_TYPE_INTERRUPT; + transfer->timeout = timeout; + transfer->buffer = buffer; + transfer->length = length; + transfer->user_data = user_data; + transfer->callback = callback; +} + +/** \ingroup asyncio + * Helper function to populate the required \ref libusb_transfer fields + * for an isochronous transfer. + * + * \param transfer the transfer to populate + * \param dev_handle handle of the device that will handle the transfer + * \param endpoint address of the endpoint where this transfer will be sent + * \param buffer data buffer + * \param length length of data buffer + * \param num_iso_packets the number of isochronous packets + * \param callback callback function to be invoked on transfer completion + * \param user_data user data to pass to callback function + * \param timeout timeout for the transfer in milliseconds + */ +static inline void libusb_fill_iso_transfer(struct libusb_transfer *transfer, + libusb_device_handle *dev_handle, unsigned char endpoint, + unsigned char *buffer, int length, int num_iso_packets, + libusb_transfer_cb_fn callback, void *user_data, unsigned int timeout) +{ + transfer->dev_handle = dev_handle; + transfer->endpoint = endpoint; + transfer->type = LIBUSB_TRANSFER_TYPE_ISOCHRONOUS; + transfer->timeout = timeout; + transfer->buffer = buffer; + transfer->length = length; + transfer->num_iso_packets = num_iso_packets; + transfer->user_data = user_data; + transfer->callback = callback; +} + +/** \ingroup asyncio + * Convenience function to set the length of all packets in an isochronous + * transfer, based on the num_iso_packets field in the transfer structure. + * + * \param transfer a transfer + * \param length the length to set in each isochronous packet descriptor + * \see libusb_get_max_packet_size() + */ +static inline void libusb_set_iso_packet_lengths( + struct libusb_transfer *transfer, unsigned int length) +{ + int i; + for (i = 0; i < transfer->num_iso_packets; i++) + transfer->iso_packet_desc[i].length = length; +} + +/** \ingroup asyncio + * Convenience function to locate the position of an isochronous packet + * within the buffer of an isochronous transfer. + * + * This is a thorough function which loops through all preceding packets, + * accumulating their lengths to find the position of the specified packet. + * Typically you will assign equal lengths to each packet in the transfer, + * and hence the above method is sub-optimal. You may wish to use + * libusb_get_iso_packet_buffer_simple() instead. + * + * \param transfer a transfer + * \param packet the packet to return the address of + * \returns the base address of the packet buffer inside the transfer buffer, + * or NULL if the packet does not exist. + * \see libusb_get_iso_packet_buffer_simple() + */ +static inline unsigned char *libusb_get_iso_packet_buffer( + struct libusb_transfer *transfer, unsigned int packet) +{ + int i; + size_t offset = 0; + int _packet; + + /* oops..slight bug in the API. packet is an unsigned int, but we use + * signed integers almost everywhere else. range-check and convert to + * signed to avoid compiler warnings. FIXME for libusb-2. */ + if (packet > INT_MAX) + return NULL; + _packet = packet; + + if (_packet >= transfer->num_iso_packets) + return NULL; + + for (i = 0; i < _packet; i++) + offset += transfer->iso_packet_desc[i].length; + + return transfer->buffer + offset; +} + +/** \ingroup asyncio + * Convenience function to locate the position of an isochronous packet + * within the buffer of an isochronous transfer, for transfers where each + * packet is of identical size. + * + * This function relies on the assumption that every packet within the transfer + * is of identical size to the first packet. Calculating the location of + * the packet buffer is then just a simple calculation: + * buffer + (packet_size * packet) + * + * Do not use this function on transfers other than those that have identical + * packet lengths for each packet. + * + * \param transfer a transfer + * \param packet the packet to return the address of + * \returns the base address of the packet buffer inside the transfer buffer, + * or NULL if the packet does not exist. + * \see libusb_get_iso_packet_buffer() + */ +static inline unsigned char *libusb_get_iso_packet_buffer_simple( + struct libusb_transfer *transfer, unsigned int packet) +{ + int _packet; + + /* oops..slight bug in the API. packet is an unsigned int, but we use + * signed integers almost everywhere else. range-check and convert to + * signed to avoid compiler warnings. FIXME for libusb-2. */ + if (packet > INT_MAX) + return NULL; + _packet = packet; + + if (_packet >= transfer->num_iso_packets) + return NULL; + + return transfer->buffer + (transfer->iso_packet_desc[0].length * _packet); +} + +/* sync I/O */ + +int LIBUSB_CALL libusb_control_transfer(libusb_device_handle *dev_handle, + uint8_t request_type, uint8_t bRequest, uint16_t wValue, uint16_t wIndex, + unsigned char *data, uint16_t wLength, unsigned int timeout); + +int LIBUSB_CALL libusb_bulk_transfer(libusb_device_handle *dev_handle, + unsigned char endpoint, unsigned char *data, int length, + int *actual_length, unsigned int timeout); + +int LIBUSB_CALL libusb_interrupt_transfer(libusb_device_handle *dev_handle, + unsigned char endpoint, unsigned char *data, int length, + int *actual_length, unsigned int timeout); + +/** \ingroup desc + * Retrieve a descriptor from the default control pipe. + * This is a convenience function which formulates the appropriate control + * message to retrieve the descriptor. + * + * \param dev a device handle + * \param desc_type the descriptor type, see \ref libusb_descriptor_type + * \param desc_index the index of the descriptor to retrieve + * \param data output buffer for descriptor + * \param length size of data buffer + * \returns number of bytes returned in data, or LIBUSB_ERROR code on failure + */ +static inline int libusb_get_descriptor(libusb_device_handle *dev, + uint8_t desc_type, uint8_t desc_index, unsigned char *data, int length) +{ + return libusb_control_transfer(dev, LIBUSB_ENDPOINT_IN, + LIBUSB_REQUEST_GET_DESCRIPTOR, (desc_type << 8) | desc_index, 0, data, + (uint16_t) length, 1000); +} + +/** \ingroup desc + * Retrieve a descriptor from a device. + * This is a convenience function which formulates the appropriate control + * message to retrieve the descriptor. The string returned is Unicode, as + * detailed in the USB specifications. + * + * \param dev a device handle + * \param desc_index the index of the descriptor to retrieve + * \param langid the language ID for the string descriptor + * \param data output buffer for descriptor + * \param length size of data buffer + * \returns number of bytes returned in data, or LIBUSB_ERROR code on failure + * \see libusb_get_string_descriptor_ascii() + */ +static inline int libusb_get_string_descriptor(libusb_device_handle *dev, + uint8_t desc_index, uint16_t langid, unsigned char *data, int length) +{ + return libusb_control_transfer(dev, LIBUSB_ENDPOINT_IN, + LIBUSB_REQUEST_GET_DESCRIPTOR, (uint16_t)((LIBUSB_DT_STRING << 8) | desc_index), + langid, data, (uint16_t) length, 1000); +} + +int LIBUSB_CALL libusb_get_string_descriptor_ascii(libusb_device_handle *dev, + uint8_t desc_index, unsigned char *data, int length); + +/* polling and timeouts */ + +int LIBUSB_CALL libusb_try_lock_events(libusb_context *ctx); +void LIBUSB_CALL libusb_lock_events(libusb_context *ctx); +void LIBUSB_CALL libusb_unlock_events(libusb_context *ctx); +int LIBUSB_CALL libusb_event_handling_ok(libusb_context *ctx); +int LIBUSB_CALL libusb_event_handler_active(libusb_context *ctx); +void LIBUSB_CALL libusb_lock_event_waiters(libusb_context *ctx); +void LIBUSB_CALL libusb_unlock_event_waiters(libusb_context *ctx); +int LIBUSB_CALL libusb_wait_for_event(libusb_context *ctx, struct timeval *tv); + +int LIBUSB_CALL libusb_handle_events_timeout(libusb_context *ctx, + struct timeval *tv); +int LIBUSB_CALL libusb_handle_events_timeout_completed(libusb_context *ctx, + struct timeval *tv, int *completed); +int LIBUSB_CALL libusb_handle_events(libusb_context *ctx); +int LIBUSB_CALL libusb_handle_events_completed(libusb_context *ctx, int *completed); +int LIBUSB_CALL libusb_handle_events_locked(libusb_context *ctx, + struct timeval *tv); +int LIBUSB_CALL libusb_pollfds_handle_timeouts(libusb_context *ctx); +int LIBUSB_CALL libusb_get_next_timeout(libusb_context *ctx, + struct timeval *tv); + +/** \ingroup poll + * File descriptor for polling + */ +struct libusb_pollfd { + /** Numeric file descriptor */ + int fd; + + /** Event flags to poll for from . POLLIN indicates that you + * should monitor this file descriptor for becoming ready to read from, + * and POLLOUT indicates that you should monitor this file descriptor for + * nonblocking write readiness. */ + short events; +}; + +/** \ingroup poll + * Callback function, invoked when a new file descriptor should be added + * to the set of file descriptors monitored for events. + * \param fd the new file descriptor + * \param events events to monitor for, see \ref libusb_pollfd for a + * description + * \param user_data User data pointer specified in + * libusb_set_pollfd_notifiers() call + * \see libusb_set_pollfd_notifiers() + */ +typedef void (LIBUSB_CALL *libusb_pollfd_added_cb)(int fd, short events, + void *user_data); + +/** \ingroup poll + * Callback function, invoked when a file descriptor should be removed from + * the set of file descriptors being monitored for events. After returning + * from this callback, do not use that file descriptor again. + * \param fd the file descriptor to stop monitoring + * \param user_data User data pointer specified in + * libusb_set_pollfd_notifiers() call + * \see libusb_set_pollfd_notifiers() + */ +typedef void (LIBUSB_CALL *libusb_pollfd_removed_cb)(int fd, void *user_data); + +const struct libusb_pollfd ** LIBUSB_CALL libusb_get_pollfds( + libusb_context *ctx); +void LIBUSB_CALL libusb_set_pollfd_notifiers(libusb_context *ctx, + libusb_pollfd_added_cb added_cb, libusb_pollfd_removed_cb removed_cb, + void *user_data); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/interface/external/LibUSB/include/libusbi.h b/interface/external/LibUSB/include/libusbi.h new file mode 100644 index 0000000000..976be0d13b --- /dev/null +++ b/interface/external/LibUSB/include/libusbi.h @@ -0,0 +1,935 @@ +/* + * Internal header for libusb + * Copyright (C) 2007-2009 Daniel Drake + * Copyright (c) 2001 Johannes Erdfelt + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#ifndef LIBUSBI_H +#define LIBUSBI_H + +#include + +#include +#include +#include +#include +#ifdef HAVE_POLL_H +#include +#endif + +#include +#include + +/* Inside the libusb code, mark all public functions as follows: + * return_type API_EXPORTED function_name(params) { ... } + * But if the function returns a pointer, mark it as follows: + * DEFAULT_VISIBILITY return_type * LIBUSB_CALL function_name(params) { ... } + * In the libusb public header, mark all declarations as: + * return_type LIBUSB_CALL function_name(params); + */ +#define API_EXPORTED LIBUSB_CALL DEFAULT_VISIBILITY + +#define DEVICE_DESC_LENGTH 18 + +#define USB_MAXENDPOINTS 32 +#define USB_MAXINTERFACES 32 +#define USB_MAXCONFIG 8 + +struct list_head { + struct list_head *prev, *next; +}; + +/* Get an entry from the list + * ptr - the address of this list_head element in "type" + * type - the data type that contains "member" + * member - the list_head element in "type" + */ +#define list_entry(ptr, type, member) \ + ((type *)((uintptr_t)(ptr) - (uintptr_t)(&((type *)0L)->member))) + +/* Get each entry from a list + * pos - A structure pointer has a "member" element + * head - list head + * member - the list_head element in "pos" + * type - the type of the first parameter + */ +#define list_for_each_entry(pos, head, member, type) \ + for (pos = list_entry((head)->next, type, member); \ + &pos->member != (head); \ + pos = list_entry(pos->member.next, type, member)) + +#define list_for_each_entry_safe(pos, n, head, member, type) \ + for (pos = list_entry((head)->next, type, member), \ + n = list_entry(pos->member.next, type, member); \ + &pos->member != (head); \ + pos = n, n = list_entry(n->member.next, type, member)) + +#define list_empty(entry) ((entry)->next == (entry)) + +static inline void list_init(struct list_head *entry) +{ + entry->prev = entry->next = entry; +} + +static inline void list_add(struct list_head *entry, struct list_head *head) +{ + entry->next = head->next; + entry->prev = head; + + head->next->prev = entry; + head->next = entry; +} + +static inline void list_add_tail(struct list_head *entry, + struct list_head *head) +{ + entry->next = head; + entry->prev = head->prev; + + head->prev->next = entry; + head->prev = entry; +} + +static inline void list_del(struct list_head *entry) +{ + entry->next->prev = entry->prev; + entry->prev->next = entry->next; +} + +#define container_of(ptr, type, member) ({ \ + const typeof( ((type *)0)->member ) *mptr = (ptr); \ + (type *)( (char *)mptr - offsetof(type,member) );}) + +#define MIN(a, b) ((a) < (b) ? (a) : (b)) +#define MAX(a, b) ((a) > (b) ? (a) : (b)) + +#define TIMESPEC_IS_SET(ts) ((ts)->tv_sec != 0 || (ts)->tv_nsec != 0) + +enum usbi_log_level { + LOG_LEVEL_DEBUG, + LOG_LEVEL_INFO, + LOG_LEVEL_WARNING, + LOG_LEVEL_ERROR, +}; + +void usbi_log(struct libusb_context *ctx, enum usbi_log_level level, + const char *function, const char *format, ...); + +void usbi_log_v(struct libusb_context *ctx, enum usbi_log_level level, + const char *function, const char *format, va_list args); + +#if !defined(_MSC_VER) || _MSC_VER >= 1400 + +#ifdef ENABLE_LOGGING +#define _usbi_log(ctx, level, ...) usbi_log(ctx, level, __FUNCTION__, __VA_ARGS__) +#else +#define _usbi_log(ctx, level, ...) do { (void)(ctx); } while(0) +#endif + +#ifdef ENABLE_DEBUG_LOGGING +#define usbi_dbg(...) _usbi_log(NULL, LOG_LEVEL_DEBUG, __VA_ARGS__) +#else +#define usbi_dbg(...) do {} while(0) +#endif + +#define usbi_info(ctx, ...) _usbi_log(ctx, LOG_LEVEL_INFO, __VA_ARGS__) +#define usbi_warn(ctx, ...) _usbi_log(ctx, LOG_LEVEL_WARNING, __VA_ARGS__) +#define usbi_err(ctx, ...) _usbi_log(ctx, LOG_LEVEL_ERROR, __VA_ARGS__) + +#else /* !defined(_MSC_VER) || _MSC_VER >= 1400 */ + +/* Old MS compilers don't support variadic macros. The code is simple, so we + * repeat it for each loglevel. Note that the debug case is special. + * + * Support for variadic macros was introduced in Visual C++ 2005. + * http://msdn.microsoft.com/en-us/library/ms177415%28v=VS.80%29.aspx + */ + +static inline void usbi_info(struct libusb_context *ctx, const char *fmt, ...) +{ +#ifdef ENABLE_LOGGING + va_list args; + va_start(args, fmt); + usbi_log_v(ctx, LOG_LEVEL_INFO, "", fmt, args); + va_end(args); +#else + (void)ctx; +#endif +} + +static inline void usbi_warn(struct libusb_context *ctx, const char *fmt, ...) +{ +#ifdef ENABLE_LOGGING + va_list args; + va_start(args, fmt); + usbi_log_v(ctx, LOG_LEVEL_WARNING, "", fmt, args); + va_end(args); +#else + (void)ctx; +#endif +} + +static inline void usbi_err(struct libusb_context *ctx, const char *fmt, ...) +{ +#ifdef ENABLE_LOGGING + va_list args; + va_start(args, fmt); + usbi_log_v(ctx, LOG_LEVEL_ERROR, "", fmt, args); + va_end(args); +#else + (void)ctx; +#endif +} + +static inline void usbi_dbg(const char *fmt, ...) +{ +#ifdef ENABLE_DEBUG_LOGGING + va_list args; + va_start(args, fmt); + usbi_log_v(NULL, LOG_LEVEL_DEBUG, "", fmt, args); + va_end(args); +#else + (void)fmt; +#endif +} + +#endif /* !defined(_MSC_VER) || _MSC_VER >= 1400 */ + +#define USBI_GET_CONTEXT(ctx) if (!(ctx)) (ctx) = usbi_default_context +#define DEVICE_CTX(dev) ((dev)->ctx) +#define HANDLE_CTX(handle) (DEVICE_CTX((handle)->dev)) +#define TRANSFER_CTX(transfer) (HANDLE_CTX((transfer)->dev_handle)) +#define ITRANSFER_CTX(transfer) \ + (TRANSFER_CTX(USBI_TRANSFER_TO_LIBUSB_TRANSFER(transfer))) + +#define IS_EPIN(ep) (0 != ((ep) & LIBUSB_ENDPOINT_IN)) +#define IS_EPOUT(ep) (!IS_EPIN(ep)) +#define IS_XFERIN(xfer) (0 != ((xfer)->endpoint & LIBUSB_ENDPOINT_IN)) +#define IS_XFEROUT(xfer) (!IS_XFERIN(xfer)) + +/* Internal abstractions for thread synchronization and poll */ +#if defined(THREADS_POSIX) +#include +#elif defined(OS_WINDOWS) +#include +#endif + +#if defined(OS_LINUX) || defined(OS_DARWIN) || defined(OS_OPENBSD) +#include +#include +#elif defined(OS_WINDOWS) +#include +#endif + +#if defined(OS_WINDOWS) && !defined(__GCC__) +#undef HAVE_GETTIMEOFDAY +int usbi_gettimeofday(struct timeval *tp, void *tzp); +#define LIBUSB_GETTIMEOFDAY_WIN32 +#define HAVE_USBI_GETTIMEOFDAY +#else +#ifdef HAVE_GETTIMEOFDAY +#define usbi_gettimeofday(tv, tz) gettimeofday((tv), (tz)) +#define HAVE_USBI_GETTIMEOFDAY +#endif +#endif + +extern struct libusb_context *usbi_default_context; + +struct libusb_context { + int debug; + int debug_fixed; + + /* internal control pipe, used for interrupting event handling when + * something needs to modify poll fds. */ + int ctrl_pipe[2]; + + struct list_head usb_devs; + usbi_mutex_t usb_devs_lock; + + /* A list of open handles. Backends are free to traverse this if required. + */ + struct list_head open_devs; + usbi_mutex_t open_devs_lock; + + /* this is a list of in-flight transfer handles, sorted by timeout + * expiration. URBs to timeout the soonest are placed at the beginning of + * the list, URBs that will time out later are placed after, and urbs with + * infinite timeout are always placed at the very end. */ + struct list_head flying_transfers; + usbi_mutex_t flying_transfers_lock; + + /* list of poll fds */ + struct list_head pollfds; + usbi_mutex_t pollfds_lock; + + /* a counter that is set when we want to interrupt event handling, in order + * to modify the poll fd set. and a lock to protect it. */ + unsigned int pollfd_modify; + usbi_mutex_t pollfd_modify_lock; + + /* user callbacks for pollfd changes */ + libusb_pollfd_added_cb fd_added_cb; + libusb_pollfd_removed_cb fd_removed_cb; + void *fd_cb_user_data; + + /* ensures that only one thread is handling events at any one time */ + usbi_mutex_t events_lock; + + /* used to see if there is an active thread doing event handling */ + int event_handler_active; + + /* used to wait for event completion in threads other than the one that is + * event handling */ + usbi_mutex_t event_waiters_lock; + usbi_cond_t event_waiters_cond; + +#ifdef USBI_TIMERFD_AVAILABLE + /* used for timeout handling, if supported by OS. + * this timerfd is maintained to trigger on the next pending timeout */ + int timerfd; +#endif +}; + +#ifdef USBI_TIMERFD_AVAILABLE +#define usbi_using_timerfd(ctx) ((ctx)->timerfd >= 0) +#else +#define usbi_using_timerfd(ctx) (0) +#endif + +struct libusb_device { + /* lock protects refcnt, everything else is finalized at initialization + * time */ + usbi_mutex_t lock; + int refcnt; + + struct libusb_context *ctx; + + uint8_t bus_number; + uint8_t device_address; + uint8_t num_configurations; + enum libusb_speed speed; + + struct list_head list; + unsigned long session_data; + unsigned char os_priv[0]; +}; + +struct libusb_device_handle { + /* lock protects claimed_interfaces */ + usbi_mutex_t lock; + unsigned long claimed_interfaces; + + struct list_head list; + struct libusb_device *dev; + unsigned char os_priv[0]; +}; + +enum { + USBI_CLOCK_MONOTONIC, + USBI_CLOCK_REALTIME +}; + +/* in-memory transfer layout: + * + * 1. struct usbi_transfer + * 2. struct libusb_transfer (which includes iso packets) [variable size] + * 3. os private data [variable size] + * + * from a libusb_transfer, you can get the usbi_transfer by rewinding the + * appropriate number of bytes. + * the usbi_transfer includes the number of allocated packets, so you can + * determine the size of the transfer and hence the start and length of the + * OS-private data. + */ + +struct usbi_transfer { + int num_iso_packets; + struct list_head list; + struct timeval timeout; + int transferred; + uint8_t flags; + + /* this lock is held during libusb_submit_transfer() and + * libusb_cancel_transfer() (allowing the OS backend to prevent duplicate + * cancellation, submission-during-cancellation, etc). the OS backend + * should also take this lock in the handle_events path, to prevent the user + * cancelling the transfer from another thread while you are processing + * its completion (presumably there would be races within your OS backend + * if this were possible). */ + usbi_mutex_t lock; +}; + +enum usbi_transfer_flags { + /* The transfer has timed out */ + USBI_TRANSFER_TIMED_OUT = 1 << 0, + + /* Set by backend submit_transfer() if the OS handles timeout */ + USBI_TRANSFER_OS_HANDLES_TIMEOUT = 1 << 1, + + /* Cancellation was requested via libusb_cancel_transfer() */ + USBI_TRANSFER_CANCELLING = 1 << 2, + + /* Operation on the transfer failed because the device disappeared */ + USBI_TRANSFER_DEVICE_DISAPPEARED = 1 << 3, +}; + +#define USBI_TRANSFER_TO_LIBUSB_TRANSFER(transfer) \ + ((struct libusb_transfer *)(((unsigned char *)(transfer)) \ + + sizeof(struct usbi_transfer))) +#define LIBUSB_TRANSFER_TO_USBI_TRANSFER(transfer) \ + ((struct usbi_transfer *)(((unsigned char *)(transfer)) \ + - sizeof(struct usbi_transfer))) + +static inline void *usbi_transfer_get_os_priv(struct usbi_transfer *transfer) +{ + return ((unsigned char *)transfer) + sizeof(struct usbi_transfer) + + sizeof(struct libusb_transfer) + + (transfer->num_iso_packets + * sizeof(struct libusb_iso_packet_descriptor)); +} + +/* bus structures */ + +/* All standard descriptors have these 2 fields in common */ +struct usb_descriptor_header { + uint8_t bLength; + uint8_t bDescriptorType; +}; + +/* shared data and functions */ + +int usbi_io_init(struct libusb_context *ctx); +void usbi_io_exit(struct libusb_context *ctx); + +struct libusb_device *usbi_alloc_device(struct libusb_context *ctx, + unsigned long session_id); +struct libusb_device *usbi_get_device_by_session_id(struct libusb_context *ctx, + unsigned long session_id); +int usbi_sanitize_device(struct libusb_device *dev); +void usbi_handle_disconnect(struct libusb_device_handle *handle); + +int usbi_handle_transfer_completion(struct usbi_transfer *itransfer, + enum libusb_transfer_status status); +int usbi_handle_transfer_cancellation(struct usbi_transfer *transfer); + +int usbi_parse_descriptor(unsigned char *source, const char *descriptor, + void *dest, int host_endian); +int usbi_get_config_index_by_value(struct libusb_device *dev, + uint8_t bConfigurationValue, int *idx); + +/* polling */ + +struct usbi_pollfd { + /* must come first */ + struct libusb_pollfd pollfd; + + struct list_head list; +}; + +int usbi_add_pollfd(struct libusb_context *ctx, int fd, short events); +void usbi_remove_pollfd(struct libusb_context *ctx, int fd); +void usbi_fd_notification(struct libusb_context *ctx); + +/* device discovery */ + +/* we traverse usbfs without knowing how many devices we are going to find. + * so we create this discovered_devs model which is similar to a linked-list + * which grows when required. it can be freed once discovery has completed, + * eliminating the need for a list node in the libusb_device structure + * itself. */ +struct discovered_devs { + size_t len; + size_t capacity; + struct libusb_device *devices[0]; +}; + +struct discovered_devs *discovered_devs_append( + struct discovered_devs *discdevs, struct libusb_device *dev); + +/* OS abstraction */ + +/* This is the interface that OS backends need to implement. + * All fields are mandatory, except ones explicitly noted as optional. */ +struct usbi_os_backend { + /* A human-readable name for your backend, e.g. "Linux usbfs" */ + const char *name; + + /* Perform initialization of your backend. You might use this function + * to determine specific capabilities of the system, allocate required + * data structures for later, etc. + * + * This function is called when a libusb user initializes the library + * prior to use. + * + * Return 0 on success, or a LIBUSB_ERROR code on failure. + */ + int (*init)(struct libusb_context *ctx); + + /* Deinitialization. Optional. This function should destroy anything + * that was set up by init. + * + * This function is called when the user deinitializes the library. + */ + void (*exit)(void); + + /* Enumerate all the USB devices on the system, returning them in a list + * of discovered devices. + * + * Your implementation should enumerate all devices on the system, + * regardless of whether they have been seen before or not. + * + * When you have found a device, compute a session ID for it. The session + * ID should uniquely represent that particular device for that particular + * connection session since boot (i.e. if you disconnect and reconnect a + * device immediately after, it should be assigned a different session ID). + * If your OS cannot provide a unique session ID as described above, + * presenting a session ID of (bus_number << 8 | device_address) should + * be sufficient. Bus numbers and device addresses wrap and get reused, + * but that is an unlikely case. + * + * After computing a session ID for a device, call + * usbi_get_device_by_session_id(). This function checks if libusb already + * knows about the device, and if so, it provides you with a libusb_device + * structure for it. + * + * If usbi_get_device_by_session_id() returns NULL, it is time to allocate + * a new device structure for the device. Call usbi_alloc_device() to + * obtain a new libusb_device structure with reference count 1. Populate + * the bus_number and device_address attributes of the new device, and + * perform any other internal backend initialization you need to do. At + * this point, you should be ready to provide device descriptors and so + * on through the get_*_descriptor functions. Finally, call + * usbi_sanitize_device() to perform some final sanity checks on the + * device. Assuming all of the above succeeded, we can now continue. + * If any of the above failed, remember to unreference the device that + * was returned by usbi_alloc_device(). + * + * At this stage we have a populated libusb_device structure (either one + * that was found earlier, or one that we have just allocated and + * populated). This can now be added to the discovered devices list + * using discovered_devs_append(). Note that discovered_devs_append() + * may reallocate the list, returning a new location for it, and also + * note that reallocation can fail. Your backend should handle these + * error conditions appropriately. + * + * This function should not generate any bus I/O and should not block. + * If I/O is required (e.g. reading the active configuration value), it is + * OK to ignore these suggestions :) + * + * This function is executed when the user wishes to retrieve a list + * of USB devices connected to the system. + * + * Return 0 on success, or a LIBUSB_ERROR code on failure. + */ + int (*get_device_list)(struct libusb_context *ctx, + struct discovered_devs **discdevs); + + /* Open a device for I/O and other USB operations. The device handle + * is preallocated for you, you can retrieve the device in question + * through handle->dev. + * + * Your backend should allocate any internal resources required for I/O + * and other operations so that those operations can happen (hopefully) + * without hiccup. This is also a good place to inform libusb that it + * should monitor certain file descriptors related to this device - + * see the usbi_add_pollfd() function. + * + * This function should not generate any bus I/O and should not block. + * + * This function is called when the user attempts to obtain a device + * handle for a device. + * + * Return: + * - 0 on success + * - LIBUSB_ERROR_ACCESS if the user has insufficient permissions + * - LIBUSB_ERROR_NO_DEVICE if the device has been disconnected since + * discovery + * - another LIBUSB_ERROR code on other failure + * + * Do not worry about freeing the handle on failed open, the upper layers + * do this for you. + */ + int (*open)(struct libusb_device_handle *handle); + + /* Close a device such that the handle cannot be used again. Your backend + * should destroy any resources that were allocated in the open path. + * This may also be a good place to call usbi_remove_pollfd() to inform + * libusb of any file descriptors associated with this device that should + * no longer be monitored. + * + * This function is called when the user closes a device handle. + */ + void (*close)(struct libusb_device_handle *handle); + + /* Retrieve the device descriptor from a device. + * + * The descriptor should be retrieved from memory, NOT via bus I/O to the + * device. This means that you may have to cache it in a private structure + * during get_device_list enumeration. Alternatively, you may be able + * to retrieve it from a kernel interface (some Linux setups can do this) + * still without generating bus I/O. + * + * This function is expected to write DEVICE_DESC_LENGTH (18) bytes into + * buffer, which is guaranteed to be big enough. + * + * This function is called when sanity-checking a device before adding + * it to the list of discovered devices, and also when the user requests + * to read the device descriptor. + * + * This function is expected to return the descriptor in bus-endian format + * (LE). If it returns the multi-byte values in host-endian format, + * set the host_endian output parameter to "1". + * + * Return 0 on success or a LIBUSB_ERROR code on failure. + */ + int (*get_device_descriptor)(struct libusb_device *device, + unsigned char *buffer, int *host_endian); + + /* Get the ACTIVE configuration descriptor for a device. + * + * The descriptor should be retrieved from memory, NOT via bus I/O to the + * device. This means that you may have to cache it in a private structure + * during get_device_list enumeration. You may also have to keep track + * of which configuration is active when the user changes it. + * + * This function is expected to write len bytes of data into buffer, which + * is guaranteed to be big enough. If you can only do a partial write, + * return an error code. + * + * This function is expected to return the descriptor in bus-endian format + * (LE). If it returns the multi-byte values in host-endian format, + * set the host_endian output parameter to "1". + * + * Return: + * - 0 on success + * - LIBUSB_ERROR_NOT_FOUND if the device is in unconfigured state + * - another LIBUSB_ERROR code on other failure + */ + int (*get_active_config_descriptor)(struct libusb_device *device, + unsigned char *buffer, size_t len, int *host_endian); + + /* Get a specific configuration descriptor for a device. + * + * The descriptor should be retrieved from memory, NOT via bus I/O to the + * device. This means that you may have to cache it in a private structure + * during get_device_list enumeration. + * + * The requested descriptor is expressed as a zero-based index (i.e. 0 + * indicates that we are requesting the first descriptor). The index does + * not (necessarily) equal the bConfigurationValue of the configuration + * being requested. + * + * This function is expected to write len bytes of data into buffer, which + * is guaranteed to be big enough. If you can only do a partial write, + * return an error code. + * + * This function is expected to return the descriptor in bus-endian format + * (LE). If it returns the multi-byte values in host-endian format, + * set the host_endian output parameter to "1". + * + * Return 0 on success or a LIBUSB_ERROR code on failure. + */ + int (*get_config_descriptor)(struct libusb_device *device, + uint8_t config_index, unsigned char *buffer, size_t len, + int *host_endian); + + /* Get the bConfigurationValue for the active configuration for a device. + * Optional. This should only be implemented if you can retrieve it from + * cache (don't generate I/O). + * + * If you cannot retrieve this from cache, either do not implement this + * function, or return LIBUSB_ERROR_NOT_SUPPORTED. This will cause + * libusb to retrieve the information through a standard control transfer. + * + * This function must be non-blocking. + * Return: + * - 0 on success + * - LIBUSB_ERROR_NO_DEVICE if the device has been disconnected since it + * was opened + * - LIBUSB_ERROR_NOT_SUPPORTED if the value cannot be retrieved without + * blocking + * - another LIBUSB_ERROR code on other failure. + */ + int (*get_configuration)(struct libusb_device_handle *handle, int *config); + + /* Set the active configuration for a device. + * + * A configuration value of -1 should put the device in unconfigured state. + * + * This function can block. + * + * Return: + * - 0 on success + * - LIBUSB_ERROR_NOT_FOUND if the configuration does not exist + * - LIBUSB_ERROR_BUSY if interfaces are currently claimed (and hence + * configuration cannot be changed) + * - LIBUSB_ERROR_NO_DEVICE if the device has been disconnected since it + * was opened + * - another LIBUSB_ERROR code on other failure. + */ + int (*set_configuration)(struct libusb_device_handle *handle, int config); + + /* Claim an interface. When claimed, the application can then perform + * I/O to an interface's endpoints. + * + * This function should not generate any bus I/O and should not block. + * Interface claiming is a logical operation that simply ensures that + * no other drivers/applications are using the interface, and after + * claiming, no other drivers/applicatiosn can use the interface because + * we now "own" it. + * + * Return: + * - 0 on success + * - LIBUSB_ERROR_NOT_FOUND if the interface does not exist + * - LIBUSB_ERROR_BUSY if the interface is in use by another driver/app + * - LIBUSB_ERROR_NO_DEVICE if the device has been disconnected since it + * was opened + * - another LIBUSB_ERROR code on other failure + */ + int (*claim_interface)(struct libusb_device_handle *handle, int interface_number); + + /* Release a previously claimed interface. + * + * This function should also generate a SET_INTERFACE control request, + * resetting the alternate setting of that interface to 0. It's OK for + * this function to block as a result. + * + * You will only ever be asked to release an interface which was + * successfully claimed earlier. + * + * Return: + * - 0 on success + * - LIBUSB_ERROR_NO_DEVICE if the device has been disconnected since it + * was opened + * - another LIBUSB_ERROR code on other failure + */ + int (*release_interface)(struct libusb_device_handle *handle, int interface_number); + + /* Set the alternate setting for an interface. + * + * You will only ever be asked to set the alternate setting for an + * interface which was successfully claimed earlier. + * + * It's OK for this function to block. + * + * Return: + * - 0 on success + * - LIBUSB_ERROR_NOT_FOUND if the alternate setting does not exist + * - LIBUSB_ERROR_NO_DEVICE if the device has been disconnected since it + * was opened + * - another LIBUSB_ERROR code on other failure + */ + int (*set_interface_altsetting)(struct libusb_device_handle *handle, + int interface_number, int altsetting); + + /* Clear a halt/stall condition on an endpoint. + * + * It's OK for this function to block. + * + * Return: + * - 0 on success + * - LIBUSB_ERROR_NOT_FOUND if the endpoint does not exist + * - LIBUSB_ERROR_NO_DEVICE if the device has been disconnected since it + * was opened + * - another LIBUSB_ERROR code on other failure + */ + int (*clear_halt)(struct libusb_device_handle *handle, + unsigned char endpoint); + + /* Perform a USB port reset to reinitialize a device. + * + * If possible, the handle should still be usable after the reset + * completes, assuming that the device descriptors did not change during + * reset and all previous interface state can be restored. + * + * If something changes, or you cannot easily locate/verify the resetted + * device, return LIBUSB_ERROR_NOT_FOUND. This prompts the application + * to close the old handle and re-enumerate the device. + * + * Return: + * - 0 on success + * - LIBUSB_ERROR_NOT_FOUND if re-enumeration is required, or if the device + * has been disconnected since it was opened + * - another LIBUSB_ERROR code on other failure + */ + int (*reset_device)(struct libusb_device_handle *handle); + + /* Determine if a kernel driver is active on an interface. Optional. + * + * The presence of a kernel driver on an interface indicates that any + * calls to claim_interface would fail with the LIBUSB_ERROR_BUSY code. + * + * Return: + * - 0 if no driver is active + * - 1 if a driver is active + * - LIBUSB_ERROR_NO_DEVICE if the device has been disconnected since it + * was opened + * - another LIBUSB_ERROR code on other failure + */ + int (*kernel_driver_active)(struct libusb_device_handle *handle, + int interface_number); + + /* Detach a kernel driver from an interface. Optional. + * + * After detaching a kernel driver, the interface should be available + * for claim. + * + * Return: + * - 0 on success + * - LIBUSB_ERROR_NOT_FOUND if no kernel driver was active + * - LIBUSB_ERROR_INVALID_PARAM if the interface does not exist + * - LIBUSB_ERROR_NO_DEVICE if the device has been disconnected since it + * was opened + * - another LIBUSB_ERROR code on other failure + */ + int (*detach_kernel_driver)(struct libusb_device_handle *handle, + int interface_number); + + /* Attach a kernel driver to an interface. Optional. + * + * Reattach a kernel driver to the device. + * + * Return: + * - 0 on success + * - LIBUSB_ERROR_NOT_FOUND if no kernel driver was active + * - LIBUSB_ERROR_INVALID_PARAM if the interface does not exist + * - LIBUSB_ERROR_NO_DEVICE if the device has been disconnected since it + * was opened + * - LIBUSB_ERROR_BUSY if a program or driver has claimed the interface, + * preventing reattachment + * - another LIBUSB_ERROR code on other failure + */ + int (*attach_kernel_driver)(struct libusb_device_handle *handle, + int interface_number); + + /* Destroy a device. Optional. + * + * This function is called when the last reference to a device is + * destroyed. It should free any resources allocated in the get_device_list + * path. + */ + void (*destroy_device)(struct libusb_device *dev); + + /* Submit a transfer. Your implementation should take the transfer, + * morph it into whatever form your platform requires, and submit it + * asynchronously. + * + * This function must not block. + * + * Return: + * - 0 on success + * - LIBUSB_ERROR_NO_DEVICE if the device has been disconnected + * - another LIBUSB_ERROR code on other failure + */ + int (*submit_transfer)(struct usbi_transfer *itransfer); + + /* Cancel a previously submitted transfer. + * + * This function must not block. The transfer cancellation must complete + * later, resulting in a call to usbi_handle_transfer_cancellation() + * from the context of handle_events. + */ + int (*cancel_transfer)(struct usbi_transfer *itransfer); + + /* Clear a transfer as if it has completed or cancelled, but do not + * report any completion/cancellation to the library. You should free + * all private data from the transfer as if you were just about to report + * completion or cancellation. + * + * This function might seem a bit out of place. It is used when libusb + * detects a disconnected device - it calls this function for all pending + * transfers before reporting completion (with the disconnect code) to + * the user. Maybe we can improve upon this internal interface in future. + */ + void (*clear_transfer_priv)(struct usbi_transfer *itransfer); + + /* Handle any pending events. This involves monitoring any active + * transfers and processing their completion or cancellation. + * + * The function is passed an array of pollfd structures (size nfds) + * as a result of the poll() system call. The num_ready parameter + * indicates the number of file descriptors that have reported events + * (i.e. the poll() return value). This should be enough information + * for you to determine which actions need to be taken on the currently + * active transfers. + * + * For any cancelled transfers, call usbi_handle_transfer_cancellation(). + * For completed transfers, call usbi_handle_transfer_completion(). + * For control/bulk/interrupt transfers, populate the "transferred" + * element of the appropriate usbi_transfer structure before calling the + * above functions. For isochronous transfers, populate the status and + * transferred fields of the iso packet descriptors of the transfer. + * + * This function should also be able to detect disconnection of the + * device, reporting that situation with usbi_handle_disconnect(). + * + * When processing an event related to a transfer, you probably want to + * take usbi_transfer.lock to prevent races. See the documentation for + * the usbi_transfer structure. + * + * Return 0 on success, or a LIBUSB_ERROR code on failure. + */ + int (*handle_events)(struct libusb_context *ctx, + struct pollfd *fds, POLL_NFDS_TYPE nfds, int num_ready); + + /* Get time from specified clock. At least two clocks must be implemented + by the backend: USBI_CLOCK_REALTIME, and USBI_CLOCK_MONOTONIC. + + Description of clocks: + USBI_CLOCK_REALTIME : clock returns time since system epoch. + USBI_CLOCK_MONOTONIC: clock returns time since unspecified start + time (usually boot). + */ + int (*clock_gettime)(int clkid, struct timespec *tp); + +#ifdef USBI_TIMERFD_AVAILABLE + /* clock ID of the clock that should be used for timerfd */ + clockid_t (*get_timerfd_clockid)(void); +#endif + + /* Number of bytes to reserve for per-device private backend data. + * This private data area is accessible through the "os_priv" field of + * struct libusb_device. */ + size_t device_priv_size; + + /* Number of bytes to reserve for per-handle private backend data. + * This private data area is accessible through the "os_priv" field of + * struct libusb_device. */ + size_t device_handle_priv_size; + + /* Number of bytes to reserve for per-transfer private backend data. + * This private data area is accessible by calling + * usbi_transfer_get_os_priv() on the appropriate usbi_transfer instance. + */ + size_t transfer_priv_size; + + /* Mumber of additional bytes for os_priv for each iso packet. + * Can your backend use this? */ + /* FIXME: linux can't use this any more. if other OS's cannot either, + * then remove this */ + size_t add_iso_packet_size; +}; + +extern const struct usbi_os_backend * const usbi_backend; + +extern const struct usbi_os_backend linux_usbfs_backend; +extern const struct usbi_os_backend darwin_backend; +extern const struct usbi_os_backend openbsd_backend; +extern const struct usbi_os_backend windows_backend; + +#endif + diff --git a/interface/external/LibUSB/include/os/darwin_usb.h b/interface/external/LibUSB/include/os/darwin_usb.h new file mode 100644 index 0000000000..59d0a694ce --- /dev/null +++ b/interface/external/LibUSB/include/os/darwin_usb.h @@ -0,0 +1,169 @@ +/* + * darwin backend for libusb 1.0 + * Copyright (C) 2008-2009 Nathan Hjelm + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#if !defined(LIBUSB_DARWIN_H) +#define LIBUSB_DARWIN_H + +#include "libusbi.h" + +#include +#include +#include +#include + +/* IOUSBInterfaceInferface */ +#if defined (kIOUSBInterfaceInterfaceID300) + +#define usb_interface_t IOUSBInterfaceInterface300 +#define InterfaceInterfaceID kIOUSBInterfaceInterfaceID300 +#define InterfaceVersion 300 + +#elif defined (kIOUSBInterfaceInterfaceID245) + +#define usb_interface_t IOUSBInterfaceInterface245 +#define InterfaceInterfaceID kIOUSBInterfaceInterfaceID245 +#define InterfaceVersion 245 + +#elif defined (kIOUSBInterfaceInterfaceID220) + +#define usb_interface_t IOUSBInterfaceInterface220 +#define InterfaceInterfaceID kIOUSBInterfaceInterfaceID220 +#define InterfaceVersion 220 + +#elif defined (kIOUSBInterfaceInterfaceID197) + +#define usb_interface_t IOUSBInterfaceInterface197 +#define InterfaceInterfaceID kIOUSBInterfaceInterfaceID197 +#define InterfaceVersion 197 + +#elif defined (kIOUSBInterfaceInterfaceID190) + +#define usb_interface_t IOUSBInterfaceInterface190 +#define InterfaceInterfaceID kIOUSBInterfaceInterfaceID190 +#define InterfaceVersion 190 + +#elif defined (kIOUSBInterfaceInterfaceID182) + +#define usb_interface_t IOUSBInterfaceInterface182 +#define InterfaceInterfaceID kIOUSBInterfaceInterfaceID182 +#define InterfaceVersion 182 + +#else + +#error "IOUSBFamily is too old. Please upgrade your OS" + +#endif + +/* IOUSBDeviceInterface */ +#if defined (kIOUSBDeviceInterfaceID320) + +#define usb_device_t IOUSBDeviceInterface320 +#define DeviceInterfaceID kIOUSBDeviceInterfaceID320 +#define DeviceVersion 320 + +#elif defined (kIOUSBDeviceInterfaceID300) + +#define usb_device_t IOUSBDeviceInterface300 +#define DeviceInterfaceID kIOUSBDeviceInterfaceID300 +#define DeviceVersion 300 + +#elif defined (kIOUSBDeviceInterfaceID245) + +#define usb_device_t IOUSBDeviceInterface245 +#define DeviceInterfaceID kIOUSBDeviceInterfaceID245 +#define DeviceVersion 245 + +#elif defined (kIOUSBDeviceInterfaceID197) + +#define usb_device_t IOUSBDeviceInterface197 +#define DeviceInterfaceID kIOUSBDeviceInterfaceID197 +#define DeviceVersion 197 + +#elif defined (kIOUSBDeviceInterfaceID187) + +#define usb_device_t IOUSBDeviceInterface187 +#define DeviceInterfaceID kIOUSBDeviceInterfaceID187 +#define DeviceVersion 187 + +#elif defined (kIOUSBDeviceInterfaceID182) + +#define usb_device_t IOUSBDeviceInterface182 +#define DeviceInterfaceID kIOUSBDeviceInterfaceID182 +#define DeviceVersion 182 + +#else + +#error "IOUSBFamily is too old. Please upgrade your OS" + +#endif + +#if !defined(IO_OBJECT_NULL) +#define IO_OBJECT_NULL ((io_object_t) 0) +#endif + +typedef IOCFPlugInInterface *io_cf_plugin_ref_t; +typedef IONotificationPortRef io_notification_port_t; + +/* private structures */ +struct darwin_device_priv { + IOUSBDeviceDescriptor dev_descriptor; + UInt32 location; + char sys_path[21]; + usb_device_t **device; + int open_count; + UInt8 first_config, active_config; +}; + +struct darwin_device_handle_priv { + int is_open; + CFRunLoopSourceRef cfSource; + int fds[2]; + + struct darwin_interface { + usb_interface_t **interface; + uint8_t num_endpoints; + CFRunLoopSourceRef cfSource; + uint64_t frames[256]; + uint8_t endpoint_addrs[USB_MAXENDPOINTS]; + } interfaces[USB_MAXINTERFACES]; +}; + +struct darwin_transfer_priv { + /* Isoc */ + IOUSBIsocFrame *isoc_framelist; + size_t num_iso_packets; + + /* Control */ +#if !defined (LIBUSB_NO_TIMEOUT_DEVICE) + IOUSBDevRequestTO req; +#else + IOUSBDevRequest req; +#endif + + /* Bulk */ +}; + +enum { + MESSAGE_DEVICE_GONE, + MESSAGE_ASYNC_IO_COMPLETE +}; + + + +#endif diff --git a/interface/external/LibUSB/include/os/linux_usbfs.h b/interface/external/LibUSB/include/os/linux_usbfs.h new file mode 100644 index 0000000000..487acb5ac2 --- /dev/null +++ b/interface/external/LibUSB/include/os/linux_usbfs.h @@ -0,0 +1,139 @@ +/* + * usbfs header structures + * Copyright (C) 2007 Daniel Drake + * Copyright (c) 2001 Johannes Erdfelt + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#ifndef LIBUSB_USBFS_H +#define LIBUSB_USBFS_H + +#define SYSFS_DEVICE_PATH "/sys/bus/usb/devices" + +struct usbfs_ctrltransfer { + /* keep in sync with usbdevice_fs.h:usbdevfs_ctrltransfer */ + uint8_t bmRequestType; + uint8_t bRequest; + uint16_t wValue; + uint16_t wIndex; + uint16_t wLength; + + uint32_t timeout; /* in milliseconds */ + + /* pointer to data */ + void *data; +}; + +struct usbfs_bulktransfer { + /* keep in sync with usbdevice_fs.h:usbdevfs_bulktransfer */ + unsigned int ep; + unsigned int len; + unsigned int timeout; /* in milliseconds */ + + /* pointer to data */ + void *data; +}; + +struct usbfs_setinterface { + /* keep in sync with usbdevice_fs.h:usbdevfs_setinterface */ + unsigned int interface; + unsigned int altsetting; +}; + +#define USBFS_MAXDRIVERNAME 255 + +struct usbfs_getdriver { + unsigned int interface; + char driver[USBFS_MAXDRIVERNAME + 1]; +}; + +#define USBFS_URB_SHORT_NOT_OK 0x01 +#define USBFS_URB_ISO_ASAP 0x02 +#define USBFS_URB_BULK_CONTINUATION 0x04 +#define USBFS_URB_QUEUE_BULK 0x10 +#define USBFS_URB_ZERO_PACKET 0x40 + +enum usbfs_urb_type { + USBFS_URB_TYPE_ISO = 0, + USBFS_URB_TYPE_INTERRUPT = 1, + USBFS_URB_TYPE_CONTROL = 2, + USBFS_URB_TYPE_BULK = 3, +}; + +struct usbfs_iso_packet_desc { + unsigned int length; + unsigned int actual_length; + unsigned int status; +}; + +#define MAX_ISO_BUFFER_LENGTH 32768 +#define MAX_BULK_BUFFER_LENGTH 16384 +#define MAX_CTRL_BUFFER_LENGTH 4096 + +struct usbfs_urb { + unsigned char type; + unsigned char endpoint; + int status; + unsigned int flags; + void *buffer; + int buffer_length; + int actual_length; + int start_frame; + int number_of_packets; + int error_count; + unsigned int signr; + void *usercontext; + struct usbfs_iso_packet_desc iso_frame_desc[0]; +}; + +struct usbfs_connectinfo { + unsigned int devnum; + unsigned char slow; +}; + +struct usbfs_ioctl { + int ifno; /* interface 0..N ; negative numbers reserved */ + int ioctl_code; /* MUST encode size + direction of data so the + * macros in give correct values */ + void *data; /* param buffer (in, or out) */ +}; + +struct usbfs_hub_portinfo { + unsigned char numports; + unsigned char port[127]; /* port to device num mapping */ +}; + +#define IOCTL_USBFS_CONTROL _IOWR('U', 0, struct usbfs_ctrltransfer) +#define IOCTL_USBFS_BULK _IOWR('U', 2, struct usbfs_bulktransfer) +#define IOCTL_USBFS_RESETEP _IOR('U', 3, unsigned int) +#define IOCTL_USBFS_SETINTF _IOR('U', 4, struct usbfs_setinterface) +#define IOCTL_USBFS_SETCONFIG _IOR('U', 5, unsigned int) +#define IOCTL_USBFS_GETDRIVER _IOW('U', 8, struct usbfs_getdriver) +#define IOCTL_USBFS_SUBMITURB _IOR('U', 10, struct usbfs_urb) +#define IOCTL_USBFS_DISCARDURB _IO('U', 11) +#define IOCTL_USBFS_REAPURB _IOW('U', 12, void *) +#define IOCTL_USBFS_REAPURBNDELAY _IOW('U', 13, void *) +#define IOCTL_USBFS_CLAIMINTF _IOR('U', 15, unsigned int) +#define IOCTL_USBFS_RELEASEINTF _IOR('U', 16, unsigned int) +#define IOCTL_USBFS_CONNECTINFO _IOW('U', 17, struct usbfs_connectinfo) +#define IOCTL_USBFS_IOCTL _IOWR('U', 18, struct usbfs_ioctl) +#define IOCTL_USBFS_HUB_PORTINFO _IOR('U', 19, struct usbfs_hub_portinfo) +#define IOCTL_USBFS_RESET _IO('U', 20) +#define IOCTL_USBFS_CLEAR_HALT _IOR('U', 21, unsigned int) +#define IOCTL_USBFS_DISCONNECT _IO('U', 22) +#define IOCTL_USBFS_CONNECT _IO('U', 23) + +#endif diff --git a/interface/external/LibUSB/include/os/poll_posix.h b/interface/external/LibUSB/include/os/poll_posix.h new file mode 100644 index 0000000000..0e5e7f5b72 --- /dev/null +++ b/interface/external/LibUSB/include/os/poll_posix.h @@ -0,0 +1,10 @@ +#ifndef LIBUSB_POLL_POSIX_H +#define LIBUSB_POLL_POSIX_H + +#define usbi_write write +#define usbi_read read +#define usbi_close close +#define usbi_pipe pipe +#define usbi_poll poll + +#endif /* LIBUSB_POLL_POSIX_H */ diff --git a/interface/external/LibUSB/include/os/poll_windows.h b/interface/external/LibUSB/include/os/poll_windows.h new file mode 100644 index 0000000000..6e5bf2bcef --- /dev/null +++ b/interface/external/LibUSB/include/os/poll_windows.h @@ -0,0 +1,115 @@ +/* + * Windows compat: POSIX compatibility wrapper + * Copyright (C) 2009-2010 Pete Batard + * With contributions from Michael Plante, Orin Eman et al. + * Parts of poll implementation from libusb-win32, by Stephan Meyer et al. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * + */ +#pragma once + +#if defined(_MSC_VER) +// disable /W4 MSVC warnings that are benign +#pragma warning(disable:4127) // conditional expression is constant +#endif + +// Handle synchronous completion through the overlapped structure +#if !defined(STATUS_REPARSE) // reuse the REPARSE status code +#define STATUS_REPARSE ((LONG)0x00000104L) +#endif +#define STATUS_COMPLETED_SYNCHRONOUSLY STATUS_REPARSE +#define HasOverlappedIoCompletedSync(lpOverlapped) (((DWORD)(lpOverlapped)->Internal) == STATUS_COMPLETED_SYNCHRONOUSLY) + +#define DUMMY_HANDLE ((HANDLE)(LONG_PTR)-2) + +enum windows_version { + WINDOWS_UNSUPPORTED, + WINDOWS_XP, + WINDOWS_2003, // also includes XP 64 + WINDOWS_VISTA_AND_LATER, +}; +extern enum windows_version windows_version; + +#define MAX_FDS 256 + +#define POLLIN 0x0001 /* There is data to read */ +#define POLLPRI 0x0002 /* There is urgent data to read */ +#define POLLOUT 0x0004 /* Writing now will not block */ +#define POLLERR 0x0008 /* Error condition */ +#define POLLHUP 0x0010 /* Hung up */ +#define POLLNVAL 0x0020 /* Invalid request: fd not open */ + +struct pollfd { + int fd; /* file descriptor */ + short events; /* requested events */ + short revents; /* returned events */ +}; + +// access modes +enum rw_type { + RW_NONE, + RW_READ, + RW_WRITE, +}; + +// fd struct that can be used for polling on Windows +struct winfd { + int fd; // what's exposed to libusb core + HANDLE handle; // what we need to attach overlapped to the I/O op, so we can poll it + OVERLAPPED* overlapped; // what will report our I/O status + enum rw_type rw; // I/O transfer direction: read *XOR* write (NOT BOTH) +}; +extern const struct winfd INVALID_WINFD; + +int usbi_pipe(int pipefd[2]); +int usbi_poll(struct pollfd *fds, unsigned int nfds, int timeout); +ssize_t usbi_write(int fd, const void *buf, size_t count); +ssize_t usbi_read(int fd, void *buf, size_t count); +int usbi_close(int fd); + +void init_polling(void); +void exit_polling(void); +struct winfd usbi_create_fd(HANDLE handle, int access_mode); +void usbi_free_fd(int fd); +struct winfd fd_to_winfd(int fd); +struct winfd handle_to_winfd(HANDLE handle); +struct winfd overlapped_to_winfd(OVERLAPPED* overlapped); + +/* + * Timeval operations + */ +#if defined(DDKBUILD) +#include // defines timeval functions on DDK +#endif + +#if !defined(TIMESPEC_TO_TIMEVAL) +#define TIMESPEC_TO_TIMEVAL(tv, ts) { \ + (tv)->tv_sec = (long)(ts)->tv_sec; \ + (tv)->tv_usec = (long)(ts)->tv_nsec / 1000; \ +} +#endif +#if !defined(timersub) +#define timersub(a, b, result) \ +do { \ + (result)->tv_sec = (a)->tv_sec - (b)->tv_sec; \ + (result)->tv_usec = (a)->tv_usec - (b)->tv_usec; \ + if ((result)->tv_usec < 0) { \ + --(result)->tv_sec; \ + (result)->tv_usec += 1000000; \ + } \ +} while (0) +#endif + diff --git a/interface/external/LibUSB/include/os/threads_posix.h b/interface/external/LibUSB/include/os/threads_posix.h new file mode 100644 index 0000000000..9752208936 --- /dev/null +++ b/interface/external/LibUSB/include/os/threads_posix.h @@ -0,0 +1,48 @@ +/* + * libusb synchronization using POSIX Threads + * + * Copyright (C) 2010 Peter Stuge + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#ifndef LIBUSB_THREADS_POSIX_H +#define LIBUSB_THREADS_POSIX_H + +#include + +#define usbi_mutex_static_t pthread_mutex_t +#define USBI_MUTEX_INITIALIZER PTHREAD_MUTEX_INITIALIZER +#define usbi_mutex_static_lock pthread_mutex_lock +#define usbi_mutex_static_unlock pthread_mutex_unlock + +#define usbi_mutex_t pthread_mutex_t +#define usbi_mutex_init pthread_mutex_init +#define usbi_mutex_lock pthread_mutex_lock +#define usbi_mutex_unlock pthread_mutex_unlock +#define usbi_mutex_trylock pthread_mutex_trylock +#define usbi_mutex_destroy pthread_mutex_destroy + +#define usbi_cond_t pthread_cond_t +#define usbi_cond_init pthread_cond_init +#define usbi_cond_wait pthread_cond_wait +#define usbi_cond_timedwait pthread_cond_timedwait +#define usbi_cond_broadcast pthread_cond_broadcast +#define usbi_cond_destroy pthread_cond_destroy +#define usbi_cond_signal pthread_cond_signal + +extern int usbi_mutex_init_recursive(pthread_mutex_t *mutex, pthread_mutexattr_t *attr); + +#endif /* LIBUSB_THREADS_POSIX_H */ diff --git a/interface/external/LibUSB/include/os/threads_windows.h b/interface/external/LibUSB/include/os/threads_windows.h new file mode 100644 index 0000000000..7bb144af58 --- /dev/null +++ b/interface/external/LibUSB/include/os/threads_windows.h @@ -0,0 +1,86 @@ +/* + * libusb synchronization on Microsoft Windows + * + * Copyright (C) 2010 Michael Plante + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#ifndef LIBUSB_THREADS_WINDOWS_H +#define LIBUSB_THREADS_WINDOWS_H + +#define usbi_mutex_static_t volatile LONG +#define USBI_MUTEX_INITIALIZER 0 + +#define usbi_mutex_t HANDLE + +struct usbi_cond_perthread { + struct list_head list; + DWORD tid; + HANDLE event; +}; +struct usbi_cond_t_ { + // Every time a thread touches the CV, it winds up in one of these lists. + // It stays there until the CV is destroyed, even if the thread + // terminates. + struct list_head waiters; + struct list_head not_waiting; +}; +typedef struct usbi_cond_t_ usbi_cond_t; + +// We *were* getting timespec from pthread.h: +#if (!defined(HAVE_STRUCT_TIMESPEC) && !defined(_TIMESPEC_DEFINED)) +#define HAVE_STRUCT_TIMESPEC 1 +#define _TIMESPEC_DEFINED 1 +struct timespec { + long tv_sec; + long tv_nsec; +}; +#endif /* HAVE_STRUCT_TIMESPEC | _TIMESPEC_DEFINED */ + +// We *were* getting ETIMEDOUT from pthread.h: +#ifndef ETIMEDOUT +# define ETIMEDOUT 10060 /* This is the value in winsock.h. */ +#endif + +#define usbi_mutexattr_t void +#define usbi_condattr_t void + +// all Windows mutexes are recursive +#define usbi_mutex_init_recursive(mutex, attr) usbi_mutex_init((mutex), (attr)) + +int usbi_mutex_static_lock(usbi_mutex_static_t *mutex); +int usbi_mutex_static_unlock(usbi_mutex_static_t *mutex); + + +int usbi_mutex_init(usbi_mutex_t *mutex, + const usbi_mutexattr_t *attr); +int usbi_mutex_lock(usbi_mutex_t *mutex); +int usbi_mutex_unlock(usbi_mutex_t *mutex); +int usbi_mutex_trylock(usbi_mutex_t *mutex); +int usbi_mutex_destroy(usbi_mutex_t *mutex); + +int usbi_cond_init(usbi_cond_t *cond, + const usbi_condattr_t *attr); +int usbi_cond_destroy(usbi_cond_t *cond); +int usbi_cond_wait(usbi_cond_t *cond, usbi_mutex_t *mutex); +int usbi_cond_timedwait(usbi_cond_t *cond, + usbi_mutex_t *mutex, + const struct timespec *abstime); +int usbi_cond_broadcast(usbi_cond_t *cond); +int usbi_cond_signal(usbi_cond_t *cond); + +#endif /* LIBUSB_THREADS_WINDOWS_H */ + diff --git a/interface/external/LibUSB/include/os/windows_usb.h b/interface/external/LibUSB/include/os/windows_usb.h new file mode 100644 index 0000000000..ddbd68075b --- /dev/null +++ b/interface/external/LibUSB/include/os/windows_usb.h @@ -0,0 +1,608 @@ +/* + * Windows backend for libusb 1.0 + * Copyright (C) 2009-2010 Pete Batard + * With contributions from Michael Plante, Orin Eman et al. + * Parts of this code adapted from libusb-win32-v1 by Stephan Meyer + * Major code testing contribution by Xiaofan Chen + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#pragma once + +#if defined(_MSC_VER) +// disable /W4 MSVC warnings that are benign +#pragma warning(disable:4127) // conditional expression is constant +#pragma warning(disable:4100) // unreferenced formal parameter +#pragma warning(disable:4214) // bit field types other than int +#pragma warning(disable:4201) // nameless struct/union +#endif + +// Windows API default is uppercase - ugh! +#if !defined(bool) +#define bool BOOL +#endif +#if !defined(true) +#define true TRUE +#endif +#if !defined(false) +#define false FALSE +#endif + +// Missing from MSVC6 setupapi.h +#if !defined(SPDRP_ADDRESS) +#define SPDRP_ADDRESS 28 +#endif +#if !defined(SPDRP_INSTALL_STATE) +#define SPDRP_INSTALL_STATE 34 +#endif + +#if defined(__CYGWIN__ ) +// cygwin produces a warning unless these prototypes are defined +extern int _snprintf(char *buffer, size_t count, const char *format, ...); +extern char *_strdup(const char *strSource); +// _beginthreadex is MSVCRT => unavailable for cygwin. Fallback to using CreateThread +#define _beginthreadex(a, b, c, d, e, f) CreateThread(a, b, (LPTHREAD_START_ROUTINE)c, d, e, f) +#endif +#define safe_free(p) do {if (p != NULL) {free((void*)p); p = NULL;}} while(0) +#define safe_closehandle(h) do {if (h != INVALID_HANDLE_VALUE) {CloseHandle(h); h = INVALID_HANDLE_VALUE;}} while(0) +#define safe_min(a, b) min((size_t)(a), (size_t)(b)) +#define safe_strcp(dst, dst_max, src, count) do {memcpy(dst, src, safe_min(count, dst_max)); \ + ((char*)dst)[safe_min(count, dst_max)-1] = 0;} while(0) +#define safe_strcpy(dst, dst_max, src) safe_strcp(dst, dst_max, src, safe_strlen(src)+1) +#define safe_strncat(dst, dst_max, src, count) strncat(dst, src, safe_min(count, dst_max - safe_strlen(dst) - 1)) +#define safe_strcat(dst, dst_max, src) safe_strncat(dst, dst_max, src, safe_strlen(src)+1) +#define safe_strcmp(str1, str2) strcmp(((str1==NULL)?"":str1), ((str2==NULL)?"":str2)) +#define safe_strncmp(str1, str2, count) strncmp(((str1==NULL)?"":str1), ((str2==NULL)?"":str2), count) +#define safe_strlen(str) ((str==NULL)?0:strlen(str)) +#define safe_sprintf _snprintf +#define safe_unref_device(dev) do {if (dev != NULL) {libusb_unref_device(dev); dev = NULL;}} while(0) +#define wchar_to_utf8_ms(wstr, str, strlen) WideCharToMultiByte(CP_UTF8, 0, wstr, -1, str, strlen, NULL, NULL) +static inline void upperize(char* str) { + size_t i; + if (str == NULL) return; + for (i=0; ios_priv; +} + +static inline void windows_device_priv_init(libusb_device* dev) { + struct windows_device_priv* p = _device_priv(dev); + int i; + p->depth = 0; + p->port = 0; + p->parent_dev = NULL; + p->path = NULL; + p->apib = &usb_api_backend[USB_API_UNSUPPORTED]; + p->composite_api_flags = 0; + p->active_config = 0; + p->config_descriptor = NULL; + memset(&(p->dev_descriptor), 0, sizeof(USB_DEVICE_DESCRIPTOR)); + for (i=0; iusb_interface[i].path = NULL; + p->usb_interface[i].apib = &usb_api_backend[USB_API_UNSUPPORTED]; + p->usb_interface[i].nb_endpoints = 0; + p->usb_interface[i].endpoint = NULL; + } +} + +static inline void windows_device_priv_release(libusb_device* dev) { + struct windows_device_priv* p = _device_priv(dev); + int i; + safe_free(p->path); + if ((dev->num_configurations > 0) && (p->config_descriptor != NULL)) { + for (i=0; i < dev->num_configurations; i++) + safe_free(p->config_descriptor[i]); + } + safe_free(p->config_descriptor); + for (i=0; iusb_interface[i].path); + safe_free(p->usb_interface[i].endpoint); + } +} + +struct interface_handle_t { + HANDLE dev_handle; // WinUSB needs an extra handle for the file + HANDLE api_handle; // used by the API to communicate with the device +}; + +struct windows_device_handle_priv { + int active_interface; + struct interface_handle_t interface_handle[USB_MAXINTERFACES]; + int autoclaim_count[USB_MAXINTERFACES]; // For auto-release +}; + +static inline struct windows_device_handle_priv *_device_handle_priv( + struct libusb_device_handle *handle) +{ + return (struct windows_device_handle_priv *) handle->os_priv; +} + +// used for async polling functions +struct windows_transfer_priv { + struct winfd pollable_fd; + uint8_t interface_number; +}; + +// used to match a device driver (including filter drivers) against a supported API +struct driver_lookup { + char list[MAX_KEY_LENGTH+1];// REG_MULTI_SZ list of services (driver) names + const DWORD reg_prop; // SPDRP registry key to use to retreive list + const char* designation; // internal designation (for debug output) +}; + +/* + * API macros - from libusb-win32 1.x + */ +#define DLL_DECLARE_PREFIXNAME(api, ret, prefixname, name, args) \ + typedef ret (api * __dll_##name##_t)args; \ + static __dll_##name##_t prefixname = NULL + +#define DLL_LOAD_PREFIXNAME(dll, prefixname, name, ret_on_failure) \ + do { \ + HMODULE h = GetModuleHandleA(#dll); \ + if (!h) \ + h = LoadLibraryA(#dll); \ + if (!h) { \ + if (ret_on_failure) { return LIBUSB_ERROR_NOT_FOUND; }\ + else { break; } \ + } \ + prefixname = (__dll_##name##_t)GetProcAddress(h, #name); \ + if (prefixname) break; \ + prefixname = (__dll_##name##_t)GetProcAddress(h, #name "A"); \ + if (prefixname) break; \ + prefixname = (__dll_##name##_t)GetProcAddress(h, #name "W"); \ + if (prefixname) break; \ + if(ret_on_failure) \ + return LIBUSB_ERROR_NOT_FOUND; \ + } while(0) + +#define DLL_DECLARE(api, ret, name, args) DLL_DECLARE_PREFIXNAME(api, ret, name, name, args) +#define DLL_LOAD(dll, name, ret_on_failure) DLL_LOAD_PREFIXNAME(dll, name, name, ret_on_failure) +#define DLL_DECLARE_PREFIXED(api, ret, prefix, name, args) DLL_DECLARE_PREFIXNAME(api, ret, prefix##name, name, args) +#define DLL_LOAD_PREFIXED(dll, prefix, name, ret_on_failure) DLL_LOAD_PREFIXNAME(dll, prefix##name, name, ret_on_failure) + +/* OLE32 dependency */ +DLL_DECLARE_PREFIXED(WINAPI, HRESULT, p, CLSIDFromString, (LPCOLESTR, LPCLSID)); + +/* SetupAPI dependencies */ +DLL_DECLARE_PREFIXED(WINAPI, HDEVINFO, p, SetupDiGetClassDevsA, (const GUID*, PCSTR, HWND, DWORD)); +DLL_DECLARE_PREFIXED(WINAPI, BOOL, p, SetupDiEnumDeviceInfo, (HDEVINFO, DWORD, PSP_DEVINFO_DATA)); +DLL_DECLARE_PREFIXED(WINAPI, BOOL, p, SetupDiEnumDeviceInterfaces, (HDEVINFO, PSP_DEVINFO_DATA, + const GUID*, DWORD, PSP_DEVICE_INTERFACE_DATA)); +DLL_DECLARE_PREFIXED(WINAPI, BOOL, p, SetupDiGetDeviceInterfaceDetailA, (HDEVINFO, PSP_DEVICE_INTERFACE_DATA, + PSP_DEVICE_INTERFACE_DETAIL_DATA_A, DWORD, PDWORD, PSP_DEVINFO_DATA)); +DLL_DECLARE_PREFIXED(WINAPI, BOOL, p, SetupDiDestroyDeviceInfoList, (HDEVINFO)); +DLL_DECLARE_PREFIXED(WINAPI, HKEY, p, SetupDiOpenDevRegKey, (HDEVINFO, PSP_DEVINFO_DATA, DWORD, DWORD, DWORD, REGSAM)); +DLL_DECLARE_PREFIXED(WINAPI, BOOL, p, SetupDiGetDeviceRegistryPropertyA, (HDEVINFO, + PSP_DEVINFO_DATA, DWORD, PDWORD, PBYTE, DWORD, PDWORD)); +DLL_DECLARE_PREFIXED(WINAPI, LONG, p, RegQueryValueExW, (HKEY, LPCWSTR, LPDWORD, LPDWORD, LPBYTE, LPDWORD)); +DLL_DECLARE_PREFIXED(WINAPI, LONG, p, RegCloseKey, (HKEY)); + +/* + * Windows DDK API definitions. Most of it copied from MinGW's includes + */ +typedef DWORD DEVNODE, DEVINST; +typedef DEVNODE *PDEVNODE, *PDEVINST; +typedef DWORD RETURN_TYPE; +typedef RETURN_TYPE CONFIGRET; + +#define CR_SUCCESS 0x00000000 +#define CR_NO_SUCH_DEVNODE 0x0000000D + +#define USB_DEVICE_DESCRIPTOR_TYPE LIBUSB_DT_DEVICE +#define USB_CONFIGURATION_DESCRIPTOR_TYPE LIBUSB_DT_CONFIG +#define USB_STRING_DESCRIPTOR_TYPE LIBUSB_DT_STRING +#define USB_INTERFACE_DESCRIPTOR_TYPE LIBUSB_DT_INTERFACE +#define USB_ENDPOINT_DESCRIPTOR_TYPE LIBUSB_DT_ENDPOINT + +#define USB_REQUEST_GET_STATUS LIBUSB_REQUEST_GET_STATUS +#define USB_REQUEST_CLEAR_FEATURE LIBUSB_REQUEST_CLEAR_FEATURE +#define USB_REQUEST_SET_FEATURE LIBUSB_REQUEST_SET_FEATURE +#define USB_REQUEST_SET_ADDRESS LIBUSB_REQUEST_SET_ADDRESS +#define USB_REQUEST_GET_DESCRIPTOR LIBUSB_REQUEST_GET_DESCRIPTOR +#define USB_REQUEST_SET_DESCRIPTOR LIBUSB_REQUEST_SET_DESCRIPTOR +#define USB_REQUEST_GET_CONFIGURATION LIBUSB_REQUEST_GET_CONFIGURATION +#define USB_REQUEST_SET_CONFIGURATION LIBUSB_REQUEST_SET_CONFIGURATION +#define USB_REQUEST_GET_INTERFACE LIBUSB_REQUEST_GET_INTERFACE +#define USB_REQUEST_SET_INTERFACE LIBUSB_REQUEST_SET_INTERFACE +#define USB_REQUEST_SYNC_FRAME LIBUSB_REQUEST_SYNCH_FRAME + +#define USB_GET_NODE_INFORMATION 258 +#define USB_GET_DESCRIPTOR_FROM_NODE_CONNECTION 260 +#define USB_GET_NODE_CONNECTION_NAME 261 +#define USB_GET_HUB_CAPABILITIES 271 +#if !defined(USB_GET_NODE_CONNECTION_INFORMATION_EX) +#define USB_GET_NODE_CONNECTION_INFORMATION_EX 274 +#endif +#if !defined(USB_GET_HUB_CAPABILITIES_EX) +#define USB_GET_HUB_CAPABILITIES_EX 276 +#endif + +#ifndef METHOD_BUFFERED +#define METHOD_BUFFERED 0 +#endif +#ifndef FILE_ANY_ACCESS +#define FILE_ANY_ACCESS 0x00000000 +#endif +#ifndef FILE_DEVICE_UNKNOWN +#define FILE_DEVICE_UNKNOWN 0x00000022 +#endif +#ifndef FILE_DEVICE_USB +#define FILE_DEVICE_USB FILE_DEVICE_UNKNOWN +#endif + +#ifndef CTL_CODE +#define CTL_CODE(DeviceType, Function, Method, Access)( \ + ((DeviceType) << 16) | ((Access) << 14) | ((Function) << 2) | (Method)) +#endif + +typedef enum USB_CONNECTION_STATUS { + NoDeviceConnected, + DeviceConnected, + DeviceFailedEnumeration, + DeviceGeneralFailure, + DeviceCausedOvercurrent, + DeviceNotEnoughPower, + DeviceNotEnoughBandwidth, + DeviceHubNestedTooDeeply, + DeviceInLegacyHub +} USB_CONNECTION_STATUS, *PUSB_CONNECTION_STATUS; + +typedef enum USB_HUB_NODE { + UsbHub, + UsbMIParent +} USB_HUB_NODE; + +/* Cfgmgr32.dll interface */ +DLL_DECLARE(WINAPI, CONFIGRET, CM_Get_Parent, (PDEVINST, DEVINST, ULONG)); +DLL_DECLARE(WINAPI, CONFIGRET, CM_Get_Child, (PDEVINST, DEVINST, ULONG)); +DLL_DECLARE(WINAPI, CONFIGRET, CM_Get_Sibling, (PDEVINST, DEVINST, ULONG)); +DLL_DECLARE(WINAPI, CONFIGRET, CM_Get_Device_IDA, (DEVINST, PCHAR, ULONG, ULONG)); + +#define IOCTL_USB_GET_HUB_CAPABILITIES_EX \ + CTL_CODE( FILE_DEVICE_USB, USB_GET_HUB_CAPABILITIES_EX, METHOD_BUFFERED, FILE_ANY_ACCESS) + +#define IOCTL_USB_GET_HUB_CAPABILITIES \ + CTL_CODE(FILE_DEVICE_USB, USB_GET_HUB_CAPABILITIES, METHOD_BUFFERED, FILE_ANY_ACCESS) + +#define IOCTL_USB_GET_DESCRIPTOR_FROM_NODE_CONNECTION \ + CTL_CODE(FILE_DEVICE_USB, USB_GET_DESCRIPTOR_FROM_NODE_CONNECTION, METHOD_BUFFERED, FILE_ANY_ACCESS) + +#define IOCTL_USB_GET_ROOT_HUB_NAME \ + CTL_CODE(FILE_DEVICE_USB, HCD_GET_ROOT_HUB_NAME, METHOD_BUFFERED, FILE_ANY_ACCESS) + +#define IOCTL_USB_GET_NODE_INFORMATION \ + CTL_CODE(FILE_DEVICE_USB, USB_GET_NODE_INFORMATION, METHOD_BUFFERED, FILE_ANY_ACCESS) + +#define IOCTL_USB_GET_NODE_CONNECTION_INFORMATION_EX \ + CTL_CODE(FILE_DEVICE_USB, USB_GET_NODE_CONNECTION_INFORMATION_EX, METHOD_BUFFERED, FILE_ANY_ACCESS) + +#define IOCTL_USB_GET_NODE_CONNECTION_ATTRIBUTES \ + CTL_CODE(FILE_DEVICE_USB, USB_GET_NODE_CONNECTION_ATTRIBUTES, METHOD_BUFFERED, FILE_ANY_ACCESS) + +#define IOCTL_USB_GET_NODE_CONNECTION_NAME \ + CTL_CODE(FILE_DEVICE_USB, USB_GET_NODE_CONNECTION_NAME, METHOD_BUFFERED, FILE_ANY_ACCESS) + +// Most of the structures below need to be packed +#pragma pack(push, 1) + +typedef struct USB_INTERFACE_DESCRIPTOR { + UCHAR bLength; + UCHAR bDescriptorType; + UCHAR bInterfaceNumber; + UCHAR bAlternateSetting; + UCHAR bNumEndpoints; + UCHAR bInterfaceClass; + UCHAR bInterfaceSubClass; + UCHAR bInterfaceProtocol; + UCHAR iInterface; +} USB_INTERFACE_DESCRIPTOR, *PUSB_INTERFACE_DESCRIPTOR; + +typedef struct USB_CONFIGURATION_DESCRIPTOR { + UCHAR bLength; + UCHAR bDescriptorType; + USHORT wTotalLength; + UCHAR bNumInterfaces; + UCHAR bConfigurationValue; + UCHAR iConfiguration; + UCHAR bmAttributes; + UCHAR MaxPower; +} USB_CONFIGURATION_DESCRIPTOR, *PUSB_CONFIGURATION_DESCRIPTOR; + +typedef struct USB_CONFIGURATION_DESCRIPTOR_SHORT { + struct { + ULONG ConnectionIndex; + struct { + UCHAR bmRequest; + UCHAR bRequest; + USHORT wValue; + USHORT wIndex; + USHORT wLength; + } SetupPacket; + } req; + USB_CONFIGURATION_DESCRIPTOR data; +} USB_CONFIGURATION_DESCRIPTOR_SHORT; + +typedef struct USB_ENDPOINT_DESCRIPTOR { + UCHAR bLength; + UCHAR bDescriptorType; + UCHAR bEndpointAddress; + UCHAR bmAttributes; + USHORT wMaxPacketSize; + UCHAR bInterval; +} USB_ENDPOINT_DESCRIPTOR, *PUSB_ENDPOINT_DESCRIPTOR; + +typedef struct USB_DESCRIPTOR_REQUEST { + ULONG ConnectionIndex; + struct { + UCHAR bmRequest; + UCHAR bRequest; + USHORT wValue; + USHORT wIndex; + USHORT wLength; + } SetupPacket; +// UCHAR Data[0]; +} USB_DESCRIPTOR_REQUEST, *PUSB_DESCRIPTOR_REQUEST; + +typedef struct USB_HUB_DESCRIPTOR { + UCHAR bDescriptorLength; + UCHAR bDescriptorType; + UCHAR bNumberOfPorts; + USHORT wHubCharacteristics; + UCHAR bPowerOnToPowerGood; + UCHAR bHubControlCurrent; + UCHAR bRemoveAndPowerMask[64]; +} USB_HUB_DESCRIPTOR, *PUSB_HUB_DESCRIPTOR; + +typedef struct USB_ROOT_HUB_NAME { + ULONG ActualLength; + WCHAR RootHubName[1]; +} USB_ROOT_HUB_NAME, *PUSB_ROOT_HUB_NAME; + +typedef struct USB_ROOT_HUB_NAME_FIXED { + ULONG ActualLength; + WCHAR RootHubName[MAX_PATH_LENGTH]; +} USB_ROOT_HUB_NAME_FIXED; + +typedef struct USB_NODE_CONNECTION_NAME { + ULONG ConnectionIndex; + ULONG ActualLength; + WCHAR NodeName[1]; +} USB_NODE_CONNECTION_NAME, *PUSB_NODE_CONNECTION_NAME; + +typedef struct USB_NODE_CONNECTION_NAME_FIXED { + ULONG ConnectionIndex; + ULONG ActualLength; + WCHAR NodeName[MAX_PATH_LENGTH]; +} USB_NODE_CONNECTION_NAME_FIXED; + +typedef struct USB_HUB_NAME_FIXED { + union { + USB_ROOT_HUB_NAME_FIXED root; + USB_NODE_CONNECTION_NAME_FIXED node; + } u; +} USB_HUB_NAME_FIXED; + +typedef struct USB_HUB_INFORMATION { + USB_HUB_DESCRIPTOR HubDescriptor; + BOOLEAN HubIsBusPowered; +} USB_HUB_INFORMATION, *PUSB_HUB_INFORMATION; + +typedef struct USB_MI_PARENT_INFORMATION { + ULONG NumberOfInterfaces; +} USB_MI_PARENT_INFORMATION, *PUSB_MI_PARENT_INFORMATION; + +typedef struct USB_NODE_INFORMATION { + USB_HUB_NODE NodeType; + union { + USB_HUB_INFORMATION HubInformation; + USB_MI_PARENT_INFORMATION MiParentInformation; + } u; +} USB_NODE_INFORMATION, *PUSB_NODE_INFORMATION; + +typedef struct USB_PIPE_INFO { + USB_ENDPOINT_DESCRIPTOR EndpointDescriptor; + ULONG ScheduleOffset; +} USB_PIPE_INFO, *PUSB_PIPE_INFO; + +typedef struct USB_NODE_CONNECTION_INFORMATION_EX { + ULONG ConnectionIndex; + USB_DEVICE_DESCRIPTOR DeviceDescriptor; + UCHAR CurrentConfigurationValue; + UCHAR Speed; + BOOLEAN DeviceIsHub; + USHORT DeviceAddress; + ULONG NumberOfOpenPipes; + USB_CONNECTION_STATUS ConnectionStatus; +// USB_PIPE_INFO PipeList[0]; +} USB_NODE_CONNECTION_INFORMATION_EX, *PUSB_NODE_CONNECTION_INFORMATION_EX; + +typedef struct USB_HUB_CAP_FLAGS { + ULONG HubIsHighSpeedCapable:1; + ULONG HubIsHighSpeed:1; + ULONG HubIsMultiTtCapable:1; + ULONG HubIsMultiTt:1; + ULONG HubIsRoot:1; + ULONG HubIsArmedWakeOnConnect:1; + ULONG ReservedMBZ:26; +} USB_HUB_CAP_FLAGS, *PUSB_HUB_CAP_FLAGS; + +typedef struct USB_HUB_CAPABILITIES { + ULONG HubIs2xCapable : 1; +} USB_HUB_CAPABILITIES, *PUSB_HUB_CAPABILITIES; + +typedef struct USB_HUB_CAPABILITIES_EX { + USB_HUB_CAP_FLAGS CapabilityFlags; +} USB_HUB_CAPABILITIES_EX, *PUSB_HUB_CAPABILITIES_EX; + +#pragma pack(pop) + +/* winusb.dll interface */ + +#define SHORT_PACKET_TERMINATE 0x01 +#define AUTO_CLEAR_STALL 0x02 +#define PIPE_TRANSFER_TIMEOUT 0x03 +#define IGNORE_SHORT_PACKETS 0x04 +#define ALLOW_PARTIAL_READS 0x05 +#define AUTO_FLUSH 0x06 +#define RAW_IO 0x07 +#define MAXIMUM_TRANSFER_SIZE 0x08 +#define AUTO_SUSPEND 0x81 +#define SUSPEND_DELAY 0x83 +#define DEVICE_SPEED 0x01 +#define LowSpeed 0x01 +#define FullSpeed 0x02 +#define HighSpeed 0x03 + +typedef enum USBD_PIPE_TYPE { + UsbdPipeTypeControl, + UsbdPipeTypeIsochronous, + UsbdPipeTypeBulk, + UsbdPipeTypeInterrupt +} USBD_PIPE_TYPE; + +typedef struct { + USBD_PIPE_TYPE PipeType; + UCHAR PipeId; + USHORT MaximumPacketSize; + UCHAR Interval; +} WINUSB_PIPE_INFORMATION, *PWINUSB_PIPE_INFORMATION; + +#pragma pack(1) +typedef struct { + UCHAR request_type; + UCHAR request; + USHORT value; + USHORT index; + USHORT length; +} WINUSB_SETUP_PACKET, *PWINUSB_SETUP_PACKET; +#pragma pack() + +typedef void *WINUSB_INTERFACE_HANDLE, *PWINUSB_INTERFACE_HANDLE; + +DLL_DECLARE(WINAPI, BOOL, WinUsb_Initialize, (HANDLE, PWINUSB_INTERFACE_HANDLE)); +DLL_DECLARE(WINAPI, BOOL, WinUsb_Free, (WINUSB_INTERFACE_HANDLE)); +DLL_DECLARE(WINAPI, BOOL, WinUsb_GetAssociatedInterface, (WINUSB_INTERFACE_HANDLE, UCHAR, PWINUSB_INTERFACE_HANDLE)); +DLL_DECLARE(WINAPI, BOOL, WinUsb_GetDescriptor, (WINUSB_INTERFACE_HANDLE, UCHAR, UCHAR, USHORT, PUCHAR, ULONG, PULONG)); +DLL_DECLARE(WINAPI, BOOL, WinUsb_QueryInterfaceSettings, (WINUSB_INTERFACE_HANDLE, UCHAR, PUSB_INTERFACE_DESCRIPTOR)); +DLL_DECLARE(WINAPI, BOOL, WinUsb_QueryDeviceInformation, (WINUSB_INTERFACE_HANDLE, ULONG, PULONG, PVOID)); +DLL_DECLARE(WINAPI, BOOL, WinUsb_SetCurrentAlternateSetting, (WINUSB_INTERFACE_HANDLE, UCHAR)); +DLL_DECLARE(WINAPI, BOOL, WinUsb_GetCurrentAlternateSetting, (WINUSB_INTERFACE_HANDLE, PUCHAR)); +DLL_DECLARE(WINAPI, BOOL, WinUsb_QueryPipe, (WINUSB_INTERFACE_HANDLE, UCHAR, UCHAR, PWINUSB_PIPE_INFORMATION)); +DLL_DECLARE(WINAPI, BOOL, WinUsb_SetPipePolicy, (WINUSB_INTERFACE_HANDLE, UCHAR, ULONG, ULONG, PVOID)); +DLL_DECLARE(WINAPI, BOOL, WinUsb_GetPipePolicy, (WINUSB_INTERFACE_HANDLE, UCHAR, ULONG, PULONG, PVOID)); +DLL_DECLARE(WINAPI, BOOL, WinUsb_ReadPipe, (WINUSB_INTERFACE_HANDLE, UCHAR, PUCHAR, ULONG, PULONG, LPOVERLAPPED)); +DLL_DECLARE(WINAPI, BOOL, WinUsb_WritePipe, (WINUSB_INTERFACE_HANDLE, UCHAR, PUCHAR, ULONG, PULONG, LPOVERLAPPED)); +DLL_DECLARE(WINAPI, BOOL, WinUsb_ControlTransfer, (WINUSB_INTERFACE_HANDLE, WINUSB_SETUP_PACKET, PUCHAR, ULONG, PULONG, LPOVERLAPPED)); +DLL_DECLARE(WINAPI, BOOL, WinUsb_ResetPipe, (WINUSB_INTERFACE_HANDLE, UCHAR)); +DLL_DECLARE(WINAPI, BOOL, WinUsb_AbortPipe, (WINUSB_INTERFACE_HANDLE, UCHAR)); +DLL_DECLARE(WINAPI, BOOL, WinUsb_FlushPipe, (WINUSB_INTERFACE_HANDLE, UCHAR)); diff --git a/interface/external/LibUSB/include/version.h b/interface/external/LibUSB/include/version.h new file mode 100644 index 0000000000..62446da871 --- /dev/null +++ b/interface/external/LibUSB/include/version.h @@ -0,0 +1,18 @@ +/* This file is parsed by m4 and windres and RC.EXE so please keep it simple. */ +#ifndef LIBUSB_MAJOR +#define LIBUSB_MAJOR 1 +#endif +#ifndef LIBUSB_MINOR +#define LIBUSB_MINOR 0 +#endif +#ifndef LIBUSB_MICRO +#define LIBUSB_MICRO 9 +#endif +/* LIBUSB_NANO may be used for Windows internal versioning. 0 means unused. */ +#ifndef LIBUSB_NANO +#define LIBUSB_NANO 0 +#endif +/* LIBUSB_RC is the release candidate suffix. Should normally be empty. */ +#ifndef LIBUSB_RC +#define LIBUSB_RC "" +#endif diff --git a/interface/external/LibUSB/lib/UNIX/libusb-1.0.a b/interface/external/LibUSB/lib/UNIX/libusb-1.0.a new file mode 100644 index 0000000000..871391de51 Binary files /dev/null and b/interface/external/LibUSB/lib/UNIX/libusb-1.0.a differ diff --git a/interface/external/LibUSB/lib/UNIX/libusb-1.0.la b/interface/external/LibUSB/lib/UNIX/libusb-1.0.la new file mode 100644 index 0000000000..384d0b2fc1 --- /dev/null +++ b/interface/external/LibUSB/lib/UNIX/libusb-1.0.la @@ -0,0 +1,41 @@ +# libusb-1.0.la - a libtool library file +# Generated by libtool (GNU libtool) 2.2.10 +# +# Please DO NOT delete this file! +# It is necessary for linking the library. + +# The name that we can dlopen(3). +dlname='libusb-1.0.so.0' + +# Names of this library. +library_names='libusb-1.0.so.0.1.0 libusb-1.0.so.0 libusb-1.0.so' + +# The name of the static archive. +old_library='libusb-1.0.a' + +# Linker flags that can not go in dependency_libs. +inherited_linker_flags=' -pthread' + +# Libraries that this one depends upon. +dependency_libs=' -lrt' + +# Names of additional weak libraries provided by this library +weak_library_names='' + +# Version information for libusb-1.0. +current=1 +age=1 +revision=0 + +# Is this an already installed library? +installed=no + +# Should we warn about portability when linking against -modules? +shouldnotlink=no + +# Files to dlopen/dlpreopen +dlopen='' +dlpreopen='' + +# Directory that this library needs to be installed in: +libdir='/usr/local/lib' diff --git a/interface/external/freenect/include/libfreenect-audio.h b/interface/external/freenect/include/libfreenect-audio.h new file mode 100644 index 0000000000..108cf38178 --- /dev/null +++ b/interface/external/freenect/include/libfreenect-audio.h @@ -0,0 +1,115 @@ +/* + * This file is part of the OpenKinect Project. http://www.openkinect.org + * + * Copyright (c) 2011 individual OpenKinect contributors. See the CONTRIB file + * for details. + * + * This code is licensed to you under the terms of the Apache License, version + * 2.0, or, at your option, the terms of the GNU General Public License, + * version 2.0. See the APACHE20 and GPL2 files for the text of the licenses, + * or the following URLs: + * http://www.apache.org/licenses/LICENSE-2.0 + * http://www.gnu.org/licenses/gpl-2.0.txt + * + * If you redistribute this file in source form, modified or unmodified, you + * may: + * 1) Leave this header intact and distribute it under the same terms, + * accompanying it with the APACHE20 and GPL20 files, or + * 2) Delete the Apache 2.0 clause and accompany it with the GPL2 file, or + * 3) Delete the GPL v2 clause and accompany it with the APACHE20 file + * In all cases you must keep the copyright notice intact and include a copy + * of the CONTRIB file. + * + * Binary distributions must follow the binary distribution requirements of + * either License. + */ + +#pragma once + +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +/// Structure to represent a single 16-bit signed little-endian PCM sample. +typedef struct { + int16_t left; + int16_t right; + int16_t center; + int16_t lfe; + int16_t surround_left; + int16_t surround_right; +} freenect_sample_51; + +/** + * Typedef for "you wanted this microphone data, here it is" event callbacks. + * TODO: Timestamp details + * The format of the unknown stream is as of yet undetermined. + * + * @param dev Device which triggered this callback + * @param num_samples Number of samples provided in each of the audio data arrays (mic[1-4] and cancelled) + * @param mic1 Microphone data for the leftmost microphone: 32-bit PCM little-endian samples at 16kHz. + * @param mic2 Microphone data for the left-middle microphone: 32-bit PCM little-endian samples at 16kHz. + * @param mic3 Microphone data for the right-middle microphone: 32-bit PCM little-endian samples at 16kHz. + * @param mic4 Microphone data for the rightmost microphone: 32-bit PCM little-endian samples at 16kHz. + * @param cancelled Noise-cancelled audio data: 16-bit PCM little-endian samples at 16kHz. + */ +typedef void (*freenect_audio_in_cb)(freenect_device *dev, int num_samples, + int32_t* mic1, int32_t* mic2, + int32_t* mic3, int32_t* mic4, + int16_t* cancelled, void *unknown/*, timestamp_t timestamp*/); + +/** + * Typedef for "you're playing audio, the library needs you to fill up the outgoing audio buffer" event callbacks + * The library will request samples at a rate of 48000Hz. + * + * @param dev Device this callback was triggered for + * @param samples Pointer to the memory where the library expects you to copy the next sample_count freenect_sample_51's to. + * @param sample_count Bidirectional. in: maximum number of samples the driver wants (don't copy in more than this, you'll clobber memory). out: actual number of samples provided to the driver. + */ +typedef void (*freenect_audio_out_cb)(freenect_device *dev, freenect_sample_51* samples, int* sample_count); + +/** + * Set the audio in callback. This is the function called when the library + * has new microphone samples. It will be called approximately 62.5 times per + * second (16kHz sample rate, expect 512 samples/callback) + * + * @param dev Device for which to set the callback + * @param callback Callback function to set + */ +FREENECTAPI void freenect_set_audio_in_callback(freenect_device *dev, freenect_audio_in_cb callback); + +/** + * Set the audio out callback. This is the "tell me what audio you're about + * to play through the speakers so the Kinect can subtract it out" callback for + * a given device. If you choose not set an audio_out_callback, the library + * will send silence to the Kinect for you - it requires data either way. + * + * @param dev Device for which to set the callback + * @param callback Callback function to set + */ +FREENECTAPI void freenect_set_audio_out_callback(freenect_device *dev, freenect_audio_out_cb callback); + +/** + * Start streaming audio for the specified device. + * + * @param dev Device for which to start audio streaming + * + * @return 0 on success, < 0 if error + */ +FREENECTAPI int freenect_start_audio(freenect_device* dev); + +/** + * Stop streaming audio for the specified device. + * + * @param dev Device for which to stop audio streaming + * + * @return 0 on success, < 0 if error + */ +FREENECTAPI int freenect_stop_audio(freenect_device* dev); + +#ifdef __cplusplus +} +#endif diff --git a/interface/external/freenect/include/libfreenect-registration.h b/interface/external/freenect/include/libfreenect-registration.h new file mode 100644 index 0000000000..7ad2b5bb80 --- /dev/null +++ b/interface/external/freenect/include/libfreenect-registration.h @@ -0,0 +1,126 @@ +/* + * This file is part of the OpenKinect Project. http://www.openkinect.org + * + * Copyright (c) 2011 individual OpenKinect contributors. See the CONTRIB file + * for details. + * + * This code is licensed to you under the terms of the Apache License, version + * 2.0, or, at your option, the terms of the GNU General Public License, + * version 2.0. See the APACHE20 and GPL2 files for the text of the licenses, + * or the following URLs: + * http://www.apache.org/licenses/LICENSE-2.0 + * http://www.gnu.org/licenses/gpl-2.0.txt + * + * If you redistribute this file in source form, modified or unmodified, you + * may: + * 1) Leave this header intact and distribute it under the same terms, + * accompanying it with the APACHE20 and GPL20 files, or + * 2) Delete the Apache 2.0 clause and accompany it with the GPL2 file, or + * 3) Delete the GPL v2 clause and accompany it with the APACHE20 file + * In all cases you must keep the copyright notice intact and include a copy + * of the CONTRIB file. + * + * Binary distributions must follow the binary distribution requirements of + * either License. + */ + +#pragma once + +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +/// Internal Kinect registration parameters. +/// Structure matches that of the line protocol +/// of the Kinect. +typedef struct { + int32_t dx_center; // not used by mapping algorithm + + int32_t ax; + int32_t bx; + int32_t cx; + int32_t dx; + + int32_t dx_start; + + int32_t ay; + int32_t by; + int32_t cy; + int32_t dy; + + int32_t dy_start; + + int32_t dx_beta_start; + int32_t dy_beta_start; + + int32_t rollout_blank; // not used by mapping algorithm + int32_t rollout_size; // not used by mapping algorithm + + int32_t dx_beta_inc; + int32_t dy_beta_inc; + + int32_t dxdx_start; + int32_t dxdy_start; + int32_t dydx_start; + int32_t dydy_start; + + int32_t dxdxdx_start; + int32_t dydxdx_start; + int32_t dxdxdy_start; + int32_t dydxdy_start; + + int32_t back_comp1; // not used by mapping algorithm + + int32_t dydydx_start; + + int32_t back_comp2; // not used by mapping algorithm + + int32_t dydydy_start; +} freenect_reg_info; + +/// registration padding info (?) +typedef struct { + uint16_t start_lines; + uint16_t end_lines; + uint16_t cropping_lines; +} freenect_reg_pad_info; + +/// internal Kinect zero plane data +typedef struct { + float dcmos_emitter_dist; // Distance between IR camera and IR emitter, in cm. + float dcmos_rcmos_dist; // Distance between IR camera and RGB camera, in cm. + float reference_distance; // The focal length of the IR camera, in mm. + float reference_pixel_size; // The size of a single pixel on the zero plane, in mm. +} freenect_zero_plane_info; + +/// all data needed for depth->RGB mapping +typedef struct { + freenect_reg_info reg_info; + freenect_reg_pad_info reg_pad_info; + freenect_zero_plane_info zero_plane_info; + + double const_shift; + + uint16_t* raw_to_mm_shift; + int32_t* depth_to_rgb_shift; + int32_t (*registration_table)[2]; // A table of 640*480 pairs of x,y values. + // Index first by pixel, then x:0 and y:1. +} freenect_registration; + + +// These allow clients to export registration parameters; proper docs will +// come later +FREENECTAPI freenect_registration freenect_copy_registration(freenect_device* dev); +FREENECTAPI int freenect_destroy_registration(freenect_registration* reg); + +// convenience function to convert a single x-y coordinate pair from camera +// to world coordinates +FREENECTAPI void freenect_camera_to_world(freenect_device* dev, + int cx, int cy, int wz, double* wx, double* wy); + +#ifdef __cplusplus +} +#endif diff --git a/interface/external/freenect/include/libfreenect.h b/interface/external/freenect/include/libfreenect.h new file mode 100644 index 0000000000..13c7c4c538 --- /dev/null +++ b/interface/external/freenect/include/libfreenect.h @@ -0,0 +1,619 @@ +/* + * This file is part of the OpenKinect Project. http://www.openkinect.org + * + * Copyright (c) 2010 individual OpenKinect contributors. See the CONTRIB file + * for details. + * + * This code is licensed to you under the terms of the Apache License, version + * 2.0, or, at your option, the terms of the GNU General Public License, + * version 2.0. See the APACHE20 and GPL2 files for the text of the licenses, + * or the following URLs: + * http://www.apache.org/licenses/LICENSE-2.0 + * http://www.gnu.org/licenses/gpl-2.0.txt + * + * If you redistribute this file in source form, modified or unmodified, you + * may: + * 1) Leave this header intact and distribute it under the same terms, + * accompanying it with the APACHE20 and GPL20 files, or + * 2) Delete the Apache 2.0 clause and accompany it with the GPL2 file, or + * 3) Delete the GPL v2 clause and accompany it with the APACHE20 file + * In all cases you must keep the copyright notice intact and include a copy + * of the CONTRIB file. + * + * Binary distributions must follow the binary distribution requirements of + * either License. + */ + +#pragma once + +#include + +/* We need struct timeval */ +#ifdef _WIN32 +#include +#else +#include +#endif + +#ifdef __cplusplus +extern "C" { +#endif + +#define FREENECT_COUNTS_PER_G 819 /**< Ticks per G for accelerometer as set per http://www.kionix.com/Product%20Sheets/KXSD9%20Product%20Brief.pdf */ + +/// Maximum value that a uint16_t pixel will take on in the buffer of any of the FREENECT_DEPTH_MM or FREENECT_DEPTH_REGISTERED frame callbacks +#define FREENECT_DEPTH_MM_MAX_VALUE 10000 +/// Value indicating that this pixel has no data, when using FREENECT_DEPTH_MM or FREENECT_DEPTH_REGISTERED depth modes +#define FREENECT_DEPTH_MM_NO_VALUE 0 +/// Maximum value that a uint16_t pixel will take on in the buffer of any of the FREENECT_DEPTH_11BIT, FREENECT_DEPTH_10BIT, FREENECT_DEPTH_11BIT_PACKED, or FREENECT_DEPTH_10BIT_PACKED frame callbacks +#define FREENECT_DEPTH_RAW_MAX_VALUE 2048 +/// Value indicating that this pixel has no data, when using FREENECT_DEPTH_11BIT, FREENECT_DEPTH_10BIT, FREENECT_DEPTH_11BIT_PACKED, or FREENECT_DEPTH_10BIT_PACKED +#define FREENECT_DEPTH_RAW_NO_VALUE 2047 + +/// Flags representing devices to open when freenect_open_device() is called. +/// In particular, this allows libfreenect to grab only a subset of the devices +/// in the Kinect, so you could (for instance) use libfreenect to handle audio +/// and motor support while letting OpenNI have access to the cameras. +/// If a device is not supported on a particular platform, its flag will be ignored. +typedef enum { + FREENECT_DEVICE_MOTOR = 0x01, + FREENECT_DEVICE_CAMERA = 0x02, + FREENECT_DEVICE_AUDIO = 0x04, +} freenect_device_flags; + +/// A struct used in enumeration to give access to serial numbers, so you can +/// open a particular device by serial rather than depending on index. This +/// is most useful if you have more than one Kinect. +struct freenect_device_attributes; +struct freenect_device_attributes { + struct freenect_device_attributes *next; /**< Next device in the linked list */ + const char* camera_serial; /**< Serial number of this device's camera subdevice */ +}; + +/// Enumeration of available resolutions. +/// Not all available resolutions are actually supported for all video formats. +/// Frame modes may not perfectly match resolutions. For instance, +/// FREENECT_RESOLUTION_MEDIUM is 640x488 for the IR camera. +typedef enum { + FREENECT_RESOLUTION_LOW = 0, /**< QVGA - 320x240 */ + FREENECT_RESOLUTION_MEDIUM = 1, /**< VGA - 640x480 */ + FREENECT_RESOLUTION_HIGH = 2, /**< SXGA - 1280x1024 */ + FREENECT_RESOLUTION_DUMMY = 2147483647, /**< Dummy value to force enum to be 32 bits wide */ +} freenect_resolution; + +/// Enumeration of video frame information states. +/// See http://openkinect.org/wiki/Protocol_Documentation#RGB_Camera for more information. +typedef enum { + FREENECT_VIDEO_RGB = 0, /**< Decompressed RGB mode (demosaicing done by libfreenect) */ + FREENECT_VIDEO_BAYER = 1, /**< Bayer compressed mode (raw information from camera) */ + FREENECT_VIDEO_IR_8BIT = 2, /**< 8-bit IR mode */ + FREENECT_VIDEO_IR_10BIT = 3, /**< 10-bit IR mode */ + FREENECT_VIDEO_IR_10BIT_PACKED = 4, /**< 10-bit packed IR mode */ + FREENECT_VIDEO_YUV_RGB = 5, /**< YUV RGB mode */ + FREENECT_VIDEO_YUV_RAW = 6, /**< YUV Raw mode */ + FREENECT_VIDEO_DUMMY = 2147483647, /**< Dummy value to force enum to be 32 bits wide */ +} freenect_video_format; + +/// Enumeration of depth frame states +/// See http://openkinect.org/wiki/Protocol_Documentation#RGB_Camera for more information. +typedef enum { + FREENECT_DEPTH_11BIT = 0, /**< 11 bit depth information in one uint16_t/pixel */ + FREENECT_DEPTH_10BIT = 1, /**< 10 bit depth information in one uint16_t/pixel */ + FREENECT_DEPTH_11BIT_PACKED = 2, /**< 11 bit packed depth information */ + FREENECT_DEPTH_10BIT_PACKED = 3, /**< 10 bit packed depth information */ + FREENECT_DEPTH_REGISTERED = 4, /**< processed depth data in mm, aligned to 640x480 RGB */ + FREENECT_DEPTH_MM = 5, /**< depth to each pixel in mm, but left unaligned to RGB image */ + FREENECT_DEPTH_DUMMY = 2147483647, /**< Dummy value to force enum to be 32 bits wide */ +} freenect_depth_format; + +/// Structure to give information about the width, height, bitrate, +/// framerate, and buffer size of a frame in a particular mode, as +/// well as the total number of bytes needed to hold a single frame. +typedef struct { + uint32_t reserved; /**< unique ID used internally. The meaning of values may change without notice. Don't touch or depend on the contents of this field. We mean it. */ + freenect_resolution resolution; /**< Resolution this freenect_frame_mode describes, should you want to find it again with freenect_find_*_frame_mode(). */ + union { + int32_t dummy; + freenect_video_format video_format; + freenect_depth_format depth_format; + }; /**< The video or depth format that this freenect_frame_mode describes. The caller should know which of video_format or depth_format to use, since they called freenect_get_*_frame_mode() */ + int32_t bytes; /**< Total buffer size in bytes to hold a single frame of data. Should be equivalent to width * height * (data_bits_per_pixel+padding_bits_per_pixel) / 8 */ + int16_t width; /**< Width of the frame, in pixels */ + int16_t height; /**< Height of the frame, in pixels */ + int8_t data_bits_per_pixel; /**< Number of bits of information needed for each pixel */ + int8_t padding_bits_per_pixel; /**< Number of bits of padding for alignment used for each pixel */ + int8_t framerate; /**< Approximate expected frame rate, in Hz */ + int8_t is_valid; /**< If 0, this freenect_frame_mode is invalid and does not describe a supported mode. Otherwise, the frame_mode is valid. */ +} freenect_frame_mode; + +/// Enumeration of LED states +/// See http://openkinect.org/wiki/Protocol_Documentation#Setting_LED for more information. +typedef enum { + LED_OFF = 0, /**< Turn LED off */ + LED_GREEN = 1, /**< Turn LED to Green */ + LED_RED = 2, /**< Turn LED to Red */ + LED_YELLOW = 3, /**< Turn LED to Yellow */ + LED_BLINK_GREEN = 4, /**< Make LED blink Green */ + // 5 is same as 4, LED blink Green + LED_BLINK_RED_YELLOW = 6, /**< Make LED blink Red/Yellow */ +} freenect_led_options; + + +/// Enumeration of tilt motor status +typedef enum { + TILT_STATUS_STOPPED = 0x00, /**< Tilt motor is stopped */ + TILT_STATUS_LIMIT = 0x01, /**< Tilt motor has reached movement limit */ + TILT_STATUS_MOVING = 0x04, /**< Tilt motor is currently moving to new position */ +} freenect_tilt_status_code; + +/// Data from the tilt motor and accelerometer +typedef struct { + int16_t accelerometer_x; /**< Raw accelerometer data for X-axis, see FREENECT_COUNTS_PER_G for conversion */ + int16_t accelerometer_y; /**< Raw accelerometer data for Y-axis, see FREENECT_COUNTS_PER_G for conversion */ + int16_t accelerometer_z; /**< Raw accelerometer data for Z-axis, see FREENECT_COUNTS_PER_G for conversion */ + int8_t tilt_angle; /**< Raw tilt motor angle encoder information */ + freenect_tilt_status_code tilt_status; /**< State of the tilt motor (stopped, moving, etc...) */ +} freenect_raw_tilt_state; + +struct _freenect_context; +typedef struct _freenect_context freenect_context; /**< Holds information about the usb context. */ + +struct _freenect_device; +typedef struct _freenect_device freenect_device; /**< Holds device information. */ + +// usb backend specific section +typedef void freenect_usb_context; /**< Holds libusb-1.0 context */ +// + +/// If Win32, export all functions for DLL usage +#ifndef _WIN32 + #define FREENECTAPI /**< DLLExport information for windows, set to nothing on other platforms */ +#else + /**< DLLExport information for windows, set to nothing on other platforms */ + #ifdef __cplusplus + #define FREENECTAPI extern "C" __declspec(dllexport) + #else + // this is required when building from a Win32 port of gcc without being + // forced to compile all of the library files (.c) with g++... + #define FREENECTAPI __declspec(dllexport) + #endif +#endif + +/// Enumeration of message logging levels +typedef enum { + FREENECT_LOG_FATAL = 0, /**< Log for crashing/non-recoverable errors */ + FREENECT_LOG_ERROR, /**< Log for major errors */ + FREENECT_LOG_WARNING, /**< Log for warning messages */ + FREENECT_LOG_NOTICE, /**< Log for important messages */ + FREENECT_LOG_INFO, /**< Log for normal messages */ + FREENECT_LOG_DEBUG, /**< Log for useful development messages */ + FREENECT_LOG_SPEW, /**< Log for slightly less useful messages */ + FREENECT_LOG_FLOOD, /**< Log EVERYTHING. May slow performance. */ +} freenect_loglevel; + +/** + * Initialize a freenect context and do any setup required for + * platform specific USB libraries. + * + * @param ctx Address of pointer to freenect context struct to allocate and initialize + * @param usb_ctx USB context to initialize. Can be NULL if not using multiple contexts. + * + * @return 0 on success, < 0 on error + */ +FREENECTAPI int freenect_init(freenect_context **ctx, freenect_usb_context *usb_ctx); + +/** + * Closes the device if it is open, and frees the context + * + * @param ctx freenect context to close/free + * + * @return 0 on success + */ +FREENECTAPI int freenect_shutdown(freenect_context *ctx); + +/// Typedef for logging callback functions +typedef void (*freenect_log_cb)(freenect_context *dev, freenect_loglevel level, const char *msg); + +/** + * Set the log level for the specified freenect context + * + * @param ctx context to set log level for + * @param level log level to use (see freenect_loglevel enum) + */ +FREENECTAPI void freenect_set_log_level(freenect_context *ctx, freenect_loglevel level); + +/** + * Callback for log messages (i.e. for rerouting to a file instead of + * stdout) + * + * @param ctx context to set log callback for + * @param cb callback function pointer + */ +FREENECTAPI void freenect_set_log_callback(freenect_context *ctx, freenect_log_cb cb); + +/** + * Calls the platform specific usb event processor + * + * @param ctx context to process events for + * + * @return 0 on success, other values on error, platform/library dependant + */ +FREENECTAPI int freenect_process_events(freenect_context *ctx); + +/** + * Calls the platform specific usb event processor until either an event occurs + * or the timeout parameter time has passed. If a zero timeval is passed, this + * function will handle any already-pending events, then return immediately. + * + * @param ctx Context to process events for + * @param timeout Pointer to a timeval containing the maximum amount of time to block waiting for events, or zero for nonblocking mode + * + * @return 0 on success, other values on error, platform/library dependant + */ +FREENECTAPI int freenect_process_events_timeout(freenect_context *ctx, struct timeval* timeout); + +/** + * Return the number of kinect devices currently connected to the + * system + * + * @param ctx Context to access device count through + * + * @return Number of devices connected, < 0 on error + */ +FREENECTAPI int freenect_num_devices(freenect_context *ctx); + +/** + * Scans for kinect devices and produces a linked list of their attributes + * (namely, serial numbers), returning the number of devices. + * + * @param ctx Context to scan for kinect devices with + * @param attribute_list Pointer to where this function will store the resultant linked list + * + * @return Number of devices connected, < 0 on error + */ +FREENECTAPI int freenect_list_device_attributes(freenect_context *ctx, struct freenect_device_attributes** attribute_list); + +/** + * Free the linked list produced by freenect_list_device_attributes(). + * + * @param attribute_list Linked list of attributes to free. + */ +FREENECTAPI void freenect_free_device_attributes(struct freenect_device_attributes* attribute_list); + +/** + * Answer which subdevices this library supports. This is most useful for + * wrappers trying to determine whether the underlying library was built with + * audio support or not, so the wrapper can avoid calling functions that do not + * exist. + * + * @return Flags representing the subdevices that the library supports opening (see freenect_device_flags) + */ +FREENECTAPI int freenect_supported_subdevices(void); + +/** + * Set which subdevices any subsequent calls to freenect_open_device() + * should open. This will not affect devices which have already been + * opened. The default behavior, should you choose not to call this + * function at all, is to open all supported subdevices - motor, cameras, + * and audio, if supported on the platform. + * + * @param ctx Context to set future subdevice selection for + * @param subdevs Flags representing the subdevices to select + */ +FREENECTAPI void freenect_select_subdevices(freenect_context *ctx, freenect_device_flags subdevs); + +/** + * Opens a kinect device via a context. Index specifies the index of + * the device on the current state of the bus. Bus resets may cause + * indexes to shift. + * + * @param ctx Context to open device through + * @param dev Device structure to assign opened device to + * @param index Index of the device on the bus + * + * @return 0 on success, < 0 on error + */ +FREENECTAPI int freenect_open_device(freenect_context *ctx, freenect_device **dev, int index); + +/** + * Opens a kinect device (via a context) associated with a particular camera + * subdevice serial number. This function will fail if no device with a + * matching serial number is found. + * + * @param ctx Context to open device through + * @param dev Device structure to assign opened device to + * @param camera_serial Null-terminated ASCII string containing the serial number of the camera subdevice in the device to open + * + * @return 0 on success, < 0 on error + */ +FREENECTAPI int freenect_open_device_by_camera_serial(freenect_context *ctx, freenect_device **dev, const char* camera_serial); + +/** + * Closes a device that is currently open + * + * @param dev Device to close + * + * @return 0 on success + */ +FREENECTAPI int freenect_close_device(freenect_device *dev); + +/** + * Set the device user data, for passing generic information into + * callbacks + * + * @param dev Device to attach user data to + * @param user User data to attach + */ +FREENECTAPI void freenect_set_user(freenect_device *dev, void *user); + +/** + * Retrieve the pointer to user data from the device struct + * + * @param dev Device from which to get user data + * + * @return Pointer to user data + */ +FREENECTAPI void *freenect_get_user(freenect_device *dev); + +/// Typedef for depth image received event callbacks +typedef void (*freenect_depth_cb)(freenect_device *dev, void *depth, uint32_t timestamp); +/// Typedef for video image received event callbacks +typedef void (*freenect_video_cb)(freenect_device *dev, void *video, uint32_t timestamp); + +/** + * Set callback for depth information received event + * + * @param dev Device to set callback for + * @param cb Function pointer for processing depth information + */ +FREENECTAPI void freenect_set_depth_callback(freenect_device *dev, freenect_depth_cb cb); + +/** + * Set callback for video information received event + * + * @param dev Device to set callback for + * @param cb Function pointer for processing video information + */ +FREENECTAPI void freenect_set_video_callback(freenect_device *dev, freenect_video_cb cb); + +/** + * Set the buffer to store depth information to. Size of buffer is + * dependant on depth format. See FREENECT_DEPTH_*_SIZE defines for + * more information. + * + * @param dev Device to set depth buffer for. + * @param buf Buffer to store depth information to. + * + * @return 0 on success, < 0 on error + */ +FREENECTAPI int freenect_set_depth_buffer(freenect_device *dev, void *buf); + +/** + * Set the buffer to store depth information to. Size of buffer is + * dependant on video format. See FREENECT_VIDEO_*_SIZE defines for + * more information. + * + * @param dev Device to set video buffer for. + * @param buf Buffer to store video information to. + * + * @return 0 on success, < 0 on error + */ +FREENECTAPI int freenect_set_video_buffer(freenect_device *dev, void *buf); + +/** + * Start the depth information stream for a device. + * + * @param dev Device to start depth information stream for. + * + * @return 0 on success, < 0 on error + */ +FREENECTAPI int freenect_start_depth(freenect_device *dev); + +/** + * Start the video information stream for a device. + * + * @param dev Device to start video information stream for. + * + * @return 0 on success, < 0 on error + */ +FREENECTAPI int freenect_start_video(freenect_device *dev); + +/** + * Stop the depth information stream for a device + * + * @param dev Device to stop depth information stream on. + * + * @return 0 on success, < 0 on error + */ +FREENECTAPI int freenect_stop_depth(freenect_device *dev); + +/** + * Stop the video information stream for a device + * + * @param dev Device to stop video information stream on. + * + * @return 0 on success, < 0 on error + */ +FREENECTAPI int freenect_stop_video(freenect_device *dev); + +/** + * Updates the accelerometer state using a blocking control message + * call. + * + * @param dev Device to get accelerometer data from + * + * @return 0 on success, < 0 on error. Accelerometer data stored to + * device struct. + */ +FREENECTAPI int freenect_update_tilt_state(freenect_device *dev); + +/** + * Retrieve the tilt state from a device + * + * @param dev Device to retrieve tilt state from + * + * @return The tilt state struct of the device + */ +FREENECTAPI freenect_raw_tilt_state* freenect_get_tilt_state(freenect_device *dev); + +/** + * Return the tilt state, in degrees with respect to the horizon + * + * @param state The tilt state struct from a device + * + * @return Current degree of tilt of the device + */ +FREENECTAPI double freenect_get_tilt_degs(freenect_raw_tilt_state *state); + +/** + * Set the tilt state of the device, in degrees with respect to the + * horizon. Uses blocking control message call to update + * device. Function return does not reflect state of device, device + * may still be moving to new position after the function returns. Use + * freenect_get_tilt_status() to find current movement state. + * + * @param dev Device to set tilt state + * @param angle Angle the device should tilt to + * + * @return 0 on success, < 0 on error. + */ +FREENECTAPI int freenect_set_tilt_degs(freenect_device *dev, double angle); + +/** + * Return the movement state of the tilt motor (moving, stopped, etc...) + * + * @param state Raw state struct to get the tilt status code from + * + * @return Status code of the tilt device. See + * freenect_tilt_status_code enum for more info. + */ +FREENECTAPI freenect_tilt_status_code freenect_get_tilt_status(freenect_raw_tilt_state *state); + +/** + * Set the state of the LED. Uses blocking control message call to + * update device. + * + * @param dev Device to set the LED state + * @param option LED state to set on device. See freenect_led_options enum. + * + * @return 0 on success, < 0 on error + */ +FREENECTAPI int freenect_set_led(freenect_device *dev, freenect_led_options option); + +/** + * Get the axis-based gravity adjusted accelerometer state, as laid + * out via the accelerometer data sheet, which is available at + * + * http://www.kionix.com/Product%20Sheets/KXSD9%20Product%20Brief.pdf + * + * @param state State to extract accelerometer data from + * @param x Stores X-axis accelerometer state + * @param y Stores Y-axis accelerometer state + * @param z Stores Z-axis accelerometer state + */ +FREENECTAPI void freenect_get_mks_accel(freenect_raw_tilt_state *state, double* x, double* y, double* z); + +/** + * Get the number of video camera modes supported by the driver. This includes both RGB and IR modes. + * + * @return Number of video modes supported by the driver + */ +FREENECTAPI int freenect_get_video_mode_count(); + +/** + * Get the frame descriptor of the nth supported video mode for the + * video camera. + * + * @param mode_num Which of the supported modes to return information about + * + * @return A freenect_frame_mode describing the nth video mode + */ +FREENECTAPI freenect_frame_mode freenect_get_video_mode(int mode_num); + +/** + * Get the frame descriptor of the current video mode for the specified + * freenect device. + * + * @param dev Which device to return the currently-set video mode for + * + * @return A freenect_frame_mode describing the current video mode of the specified device + */ +FREENECTAPI freenect_frame_mode freenect_get_current_video_mode(freenect_device *dev); + +/** + * Convenience function to return a mode descriptor matching the + * specified resolution and video camera pixel format, if one exists. + * + * @param res Resolution desired + * @param fmt Pixel format desired + * + * @return A freenect_frame_mode that matches the arguments specified, if such a valid mode exists; otherwise, an invalid freenect_frame_mode. + */ +FREENECTAPI freenect_frame_mode freenect_find_video_mode(freenect_resolution res, freenect_video_format fmt); + +/** + * Sets the current video mode for the specified device. If the + * freenect_frame_mode specified is not one provided by the driver + * e.g. from freenect_get_video_mode() or freenect_find_video_mode() + * then behavior is undefined. The current video mode cannot be + * changed while streaming is active. + * + * @param dev Device for which to set the video mode + * @param mode Frame mode to set + * + * @return 0 on success, < 0 if error + */ +FREENECTAPI int freenect_set_video_mode(freenect_device* dev, freenect_frame_mode mode); + +/** + * Get the number of depth camera modes supported by the driver. This includes both RGB and IR modes. + * + * @return Number of depth modes supported by the driver + */ +FREENECTAPI int freenect_get_depth_mode_count(); + +/** + * Get the frame descriptor of the nth supported depth mode for the + * depth camera. + * + * @param mode_num Which of the supported modes to return information about + * + * @return A freenect_frame_mode describing the nth depth mode + */ +FREENECTAPI freenect_frame_mode freenect_get_depth_mode(int mode_num); + +/** + * Get the frame descriptor of the current depth mode for the specified + * freenect device. + * + * @param dev Which device to return the currently-set depth mode for + * + * @return A freenect_frame_mode describing the current depth mode of the specified device + */ +FREENECTAPI freenect_frame_mode freenect_get_current_depth_mode(freenect_device *dev); + +/** + * Convenience function to return a mode descriptor matching the + * specified resolution and depth camera pixel format, if one exists. + * + * @param res Resolution desired + * @param fmt Pixel format desired + * + * @return A freenect_frame_mode that matches the arguments specified, if such a valid mode exists; otherwise, an invalid freenect_frame_mode. + */ +FREENECTAPI freenect_frame_mode freenect_find_depth_mode(freenect_resolution res, freenect_depth_format fmt); + +/** + * Sets the current depth mode for the specified device. The mode + * cannot be changed while streaming is active. + * + * @param dev Device for which to set the depth mode + * @param mode Frame mode to set + * + * @return 0 on success, < 0 if error + */ +FREENECTAPI int freenect_set_depth_mode(freenect_device* dev, const freenect_frame_mode mode); + +#ifdef __cplusplus +} +#endif diff --git a/interface/external/freenect/lib/UNIX/libfreenect.a b/interface/external/freenect/lib/UNIX/libfreenect.a new file mode 100644 index 0000000000..604faaee0a Binary files /dev/null and b/interface/external/freenect/lib/UNIX/libfreenect.a differ diff --git a/interface/external/freenect/lib/UNIX/libfreenect_sync.a b/interface/external/freenect/lib/UNIX/libfreenect_sync.a new file mode 100644 index 0000000000..7e509c8b38 Binary files /dev/null and b/interface/external/freenect/lib/UNIX/libfreenect_sync.a differ diff --git a/interface/external/skeltrack/AUTHORS b/interface/external/skeltrack/AUTHORS new file mode 100644 index 0000000000..751f7ed02c --- /dev/null +++ b/interface/external/skeltrack/AUTHORS @@ -0,0 +1 @@ +Joaquim Rocha - Creator diff --git a/interface/external/skeltrack/CMakeLists.txt b/interface/external/skeltrack/CMakeLists.txt new file mode 100644 index 0000000000..21ef04931b --- /dev/null +++ b/interface/external/skeltrack/CMakeLists.txt @@ -0,0 +1,14 @@ +cmake_minimum_required(VERSION 2.8) +include_directories(include) + +# grab the implementation and header files from src dirs +file(GLOB SKELTRACK_SRCS src/*.c include/*.h) + +find_package(PkgConfig REQUIRED) +pkg_check_modules(GLIB2 glib-2.0) + +string(REPLACE ";" " " CMAKE_C_FLAGS "${CMAKE_C_FLAGS} ${GLIB2_STATIC_CFLAGS} ${GLIB2_STATIC_LDFLAGS}") +message("${CMAKE_C_FLAGS}") + +add_library(skeltrack ${SKELTRACK_SRCS}) + diff --git a/interface/external/skeltrack/COPYING b/interface/external/skeltrack/COPYING new file mode 100644 index 0000000000..65c5ca88a6 --- /dev/null +++ b/interface/external/skeltrack/COPYING @@ -0,0 +1,165 @@ + GNU LESSER GENERAL PUBLIC LICENSE + Version 3, 29 June 2007 + + Copyright (C) 2007 Free Software Foundation, Inc. + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + + + This version of the GNU Lesser General Public License incorporates +the terms and conditions of version 3 of the GNU General Public +License, supplemented by the additional permissions listed below. + + 0. Additional Definitions. + + As used herein, "this License" refers to version 3 of the GNU Lesser +General Public License, and the "GNU GPL" refers to version 3 of the GNU +General Public License. + + "The Library" refers to a covered work governed by this License, +other than an Application or a Combined Work as defined below. + + An "Application" is any work that makes use of an interface provided +by the Library, but which is not otherwise based on the Library. +Defining a subclass of a class defined by the Library is deemed a mode +of using an interface provided by the Library. + + A "Combined Work" is a work produced by combining or linking an +Application with the Library. The particular version of the Library +with which the Combined Work was made is also called the "Linked +Version". + + The "Minimal Corresponding Source" for a Combined Work means the +Corresponding Source for the Combined Work, excluding any source code +for portions of the Combined Work that, considered in isolation, are +based on the Application, and not on the Linked Version. + + The "Corresponding Application Code" for a Combined Work means the +object code and/or source code for the Application, including any data +and utility programs needed for reproducing the Combined Work from the +Application, but excluding the System Libraries of the Combined Work. + + 1. Exception to Section 3 of the GNU GPL. + + You may convey a covered work under sections 3 and 4 of this License +without being bound by section 3 of the GNU GPL. + + 2. Conveying Modified Versions. + + If you modify a copy of the Library, and, in your modifications, a +facility refers to a function or data to be supplied by an Application +that uses the facility (other than as an argument passed when the +facility is invoked), then you may convey a copy of the modified +version: + + a) under this License, provided that you make a good faith effort to + ensure that, in the event an Application does not supply the + function or data, the facility still operates, and performs + whatever part of its purpose remains meaningful, or + + b) under the GNU GPL, with none of the additional permissions of + this License applicable to that copy. + + 3. Object Code Incorporating Material from Library Header Files. + + The object code form of an Application may incorporate material from +a header file that is part of the Library. You may convey such object +code under terms of your choice, provided that, if the incorporated +material is not limited to numerical parameters, data structure +layouts and accessors, or small macros, inline functions and templates +(ten or fewer lines in length), you do both of the following: + + a) Give prominent notice with each copy of the object code that the + Library is used in it and that the Library and its use are + covered by this License. + + b) Accompany the object code with a copy of the GNU GPL and this license + document. + + 4. Combined Works. + + You may convey a Combined Work under terms of your choice that, +taken together, effectively do not restrict modification of the +portions of the Library contained in the Combined Work and reverse +engineering for debugging such modifications, if you also do each of +the following: + + a) Give prominent notice with each copy of the Combined Work that + the Library is used in it and that the Library and its use are + covered by this License. + + b) Accompany the Combined Work with a copy of the GNU GPL and this license + document. + + c) For a Combined Work that displays copyright notices during + execution, include the copyright notice for the Library among + these notices, as well as a reference directing the user to the + copies of the GNU GPL and this license document. + + d) Do one of the following: + + 0) Convey the Minimal Corresponding Source under the terms of this + License, and the Corresponding Application Code in a form + suitable for, and under terms that permit, the user to + recombine or relink the Application with a modified version of + the Linked Version to produce a modified Combined Work, in the + manner specified by section 6 of the GNU GPL for conveying + Corresponding Source. + + 1) Use a suitable shared library mechanism for linking with the + Library. A suitable mechanism is one that (a) uses at run time + a copy of the Library already present on the user's computer + system, and (b) will operate properly with a modified version + of the Library that is interface-compatible with the Linked + Version. + + e) Provide Installation Information, but only if you would otherwise + be required to provide such information under section 6 of the + GNU GPL, and only to the extent that such information is + necessary to install and execute a modified version of the + Combined Work produced by recombining or relinking the + Application with a modified version of the Linked Version. (If + you use option 4d0, the Installation Information must accompany + the Minimal Corresponding Source and Corresponding Application + Code. If you use option 4d1, you must provide the Installation + Information in the manner specified by section 6 of the GNU GPL + for conveying Corresponding Source.) + + 5. Combined Libraries. + + You may place library facilities that are a work based on the +Library side by side in a single library together with other library +facilities that are not Applications and are not covered by this +License, and convey such a combined library under terms of your +choice, if you do both of the following: + + a) Accompany the combined library with a copy of the same work based + on the Library, uncombined with any other library facilities, + conveyed under the terms of this License. + + b) Give prominent notice with the combined library that part of it + is a work based on the Library, and explaining where to find the + accompanying uncombined form of the same work. + + 6. Revised Versions of the GNU Lesser General Public License. + + The Free Software Foundation may publish revised and/or new versions +of the GNU Lesser General Public License from time to time. Such new +versions will be similar in spirit to the present version, but may +differ in detail to address new problems or concerns. + + Each version is given a distinguishing version number. If the +Library as you received it specifies that a certain numbered version +of the GNU Lesser General Public License "or any later version" +applies to it, you have the option of following the terms and +conditions either of that published version or of any later version +published by the Free Software Foundation. If the Library as you +received it does not specify a version number of the GNU Lesser +General Public License, you may choose any version of the GNU Lesser +General Public License ever published by the Free Software Foundation. + + If the Library as you received it specifies that a proxy can decide +whether future versions of the GNU Lesser General Public License shall +apply, that proxy's public statement of acceptance of any version is +permanent authorization for you to choose that version for the +Library. diff --git a/interface/external/skeltrack/include/skeltrack-joint.h b/interface/external/skeltrack/include/skeltrack-joint.h new file mode 100644 index 0000000000..4a9e0ba28c --- /dev/null +++ b/interface/external/skeltrack/include/skeltrack-joint.h @@ -0,0 +1,90 @@ +/* + * skeltrak-joint.h + * + * Skeltrack - A Free Software skeleton tracking library + * Copyright (C) 2012 Igalia S.L. + * + * Authors: + * Joaquim Rocha + * Eduardo Lima Mitev + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public License + * version 3, or (at your option) any later version as published by + * the Free Software Foundation. + * + * This library is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License at http://www.gnu.org/licenses/lgpl-3.0.txt + * for more details. + */ + +#ifndef __SKELTRACK_JOINT_H__ +#define __SKELTRACK_JOINT_H__ + +#include +#include + +G_BEGIN_DECLS + +#define SKELTRACK_TYPE_JOINT (skeltrack_joint_get_type ()) +#define SKELTRACK_JOINT_MAX_JOINTS 7 + +typedef struct _SkeltrackJoint SkeltrackJoint; +typedef SkeltrackJoint **SkeltrackJointList; + +/** + * SkeltrackJointId: + * @SKELTRACK_JOINT_ID_HEAD: The head + * @SKELTRACK_JOINT_ID_LEFT_SHOULDER: The left shoulder + * @SKELTRACK_JOINT_ID_RIGHT_SHOULDER: The right shoulder + * @SKELTRACK_JOINT_ID_LEFT_ELBOW: The left elbow + * @SKELTRACK_JOINT_ID_RIGHT_ELBOW: The right elbow + * @SKELTRACK_JOINT_ID_LEFT_HAND: The left hand + * @SKELTRACK_JOINT_ID_RIGHT_HAND: The right hand + * + * Available joint ids. + **/ +typedef enum { + SKELTRACK_JOINT_ID_HEAD, + SKELTRACK_JOINT_ID_LEFT_SHOULDER, + SKELTRACK_JOINT_ID_RIGHT_SHOULDER, + SKELTRACK_JOINT_ID_LEFT_ELBOW, + SKELTRACK_JOINT_ID_RIGHT_ELBOW, + SKELTRACK_JOINT_ID_LEFT_HAND, + SKELTRACK_JOINT_ID_RIGHT_HAND +} SkeltrackJointId; + +/** + * SkeltrackJoint: + * @id: The id of the joint + * @x: The x coordinate of the joint in the space (in mm) + * @y: The y coordinate of the joint in the space (in mm) + * @z: The z coordinate of the joint in the space (in mm) + * @screen_x: The x coordinate of the joint in the screen (in pixels) + * @screen_y: The y coordinate of the joint in the screen (in pixels) + **/ +struct _SkeltrackJoint +{ + SkeltrackJointId id; + + gint x; + gint y; + gint z; + + gint screen_x; + gint screen_y; +}; + +GType skeltrack_joint_get_type (void); +gpointer skeltrack_joint_copy (SkeltrackJoint *joint); +void skeltrack_joint_free (SkeltrackJoint *joint); +void skeltrack_joint_list_free (SkeltrackJointList list); +SkeltrackJointList skeltrack_joint_list_new (void); +SkeltrackJoint * skeltrack_joint_list_get_joint (SkeltrackJointList list, + SkeltrackJointId id); + +G_END_DECLS + +#endif /* __SKELTRACK_JOINT_H__ */ diff --git a/interface/external/skeltrack/include/skeltrack-skeleton.h b/interface/external/skeltrack/include/skeltrack-skeleton.h new file mode 100644 index 0000000000..11e4344025 --- /dev/null +++ b/interface/external/skeltrack/include/skeltrack-skeleton.h @@ -0,0 +1,95 @@ +/* + * skeltrack.h + * + * Skeltrack - A Free Software skeleton tracking library + * Copyright (C) 2012 Igalia S.L. + * + * Authors: + * Joaquim Rocha + * Eduardo Lima Mitev + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public License + * version 3, or (at your option) any later version as published by + * the Free Software Foundation. + * + * This library is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License at http://www.gnu.org/licenses/lgpl-3.0.txt + * for more details. + */ + +#ifndef __SKELTRACK_SKELETON_H__ +#define __SKELTRACK_SKELETON_H__ + +#include +#include +#include +#include + +G_BEGIN_DECLS + +#define SKELTRACK_TYPE_SKELETON (skeltrack_skeleton_get_type ()) +#define SKELTRACK_SKELETON(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), SKELTRACK_TYPE_SKELETON, SkeltrackSkeleton)) +#define SKELTRACK_SKELETON_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), SKELTRACK_TYPE_SKELETON, SkeltrackSkeletonClass)) +#define SKELTRACK_IS_SKELETON(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), SKELTRACK_TYPE_SKELETON)) +#define SKELTRACK_IS_SKELETON_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), SKELTRACK_TYPE_SKELETON)) +#define SKELTRACK_SKELETON_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), SKELTRACK_TYPE_SKELETON, SkeltrackSkeletonClass)) + +typedef struct _SkeltrackSkeleton SkeltrackSkeleton; +typedef struct _SkeltrackSkeletonClass SkeltrackSkeletonClass; +typedef struct _SkeltrackSkeletonPrivate SkeltrackSkeletonPrivate; + +struct _SkeltrackSkeleton +{ + GObject parent; + + /*< private >*/ + SkeltrackSkeletonPrivate *priv; +}; + +/** + * SkeltrackSkeletonClass: + **/ +struct _SkeltrackSkeletonClass +{ + GObjectClass parent_class; +}; + +GType skeltrack_skeleton_get_type (void) G_GNUC_CONST; + +SkeltrackSkeleton * skeltrack_skeleton_new (void); + +void skeltrack_skeleton_track_joints (SkeltrackSkeleton *self, + guint16 *buffer, + guint width, + guint height, + GCancellable *cancellable, + GAsyncReadyCallback callback, + gpointer user_data); + +SkeltrackJointList skeltrack_skeleton_track_joints_finish (SkeltrackSkeleton *self, + GAsyncResult *result, + GError **error); + +SkeltrackJointList skeltrack_skeleton_track_joints_sync (SkeltrackSkeleton *self, + guint16 *buffer, + guint width, + guint height, + GCancellable *cancellable, + GError **error); + +void skeltrack_skeleton_get_focus_point (SkeltrackSkeleton *self, + gint *x, + gint *y, + gint *z); + +void skeltrack_skeleton_set_focus_point (SkeltrackSkeleton *self, + gint x, + gint y, + gint z); + +G_END_DECLS + +#endif /* __SKELTRACK_SKELETON_H__ */ diff --git a/interface/external/skeltrack/include/skeltrack-smooth.h b/interface/external/skeltrack/include/skeltrack-smooth.h new file mode 100644 index 0000000000..ea99bfc7ae --- /dev/null +++ b/interface/external/skeltrack/include/skeltrack-smooth.h @@ -0,0 +1,36 @@ +/* + * skeltrack-smooth.h + * + * Skeltrack - A Free Software skeleton tracking library + * Copyright (C) 2012 Igalia S.L. + * + * Authors: + * Joaquim Rocha + * Eduardo Lima Mitev + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 3 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License at http://www.gnu.org/licenses/lgpl-3.0.txt + * for more details. + */ + +#include "skeltrack-joint.h" + +typedef struct { + SkeltrackJointList smoothed_joints; + SkeltrackJointList trend_joints; + guint joints_persistency; + gfloat smoothing_factor; + guint joints_persistency_counter[SKELTRACK_JOINT_MAX_JOINTS]; +} SmoothData; + +void reset_joints_persistency_counter (SmoothData *smooth_data); + +void smooth_joints (SmoothData *data, + SkeltrackJointList new_joints); diff --git a/interface/external/skeltrack/include/skeltrack-util.h b/interface/external/skeltrack/include/skeltrack-util.h new file mode 100644 index 0000000000..540aee7f33 --- /dev/null +++ b/interface/external/skeltrack/include/skeltrack-util.h @@ -0,0 +1,127 @@ +/* + * skeltrack-util.h + * + * Skeltrack - A Free Software skeleton tracking library + * Copyright (C) 2012 Igalia S.L. + * + * Authors: + * Joaquim Rocha + * Eduardo Lima Mitev + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 3 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License at http://www.gnu.org/licenses/lgpl-3.0.txt + * for more details. + */ + +#include +#include "skeltrack-joint.h" + +typedef struct _Label Label; +typedef struct _Node Node; + +struct _Label { + gint index; + Label *parent; + GList *nodes; + Node *bridge_node; + Node *to_node; + gint lower_screen_y; + gint higher_z; + gint lower_z; + gdouble normalized_num_nodes; +}; + +struct _Node { + gint i; + gint j; + gint x; + gint y; + gint z; + GList *neighbors; + GList *linked_nodes; + Label *label; +}; + +Node * get_closest_node_to_joint (GList *extremas, + SkeltrackJoint *joint, + gint *distance); + +Node * get_closest_node (GList *node_list, Node *from); + +Node * get_closest_torso_node (GList *node_list, + Node *from, + Node *head); + +Label * get_main_component (GList *node_list, + Node *from, + gdouble min_normalized_nr_nodes); + +Label * label_find (Label *label); + +void label_union (Label *a, Label *b); + +gint get_distance (Node *a, Node *b); + +void free_label (Label *label); + +void clean_labels (GList *labels); + +void free_node (Node *node, + gboolean unlink_node_first); + +void clean_nodes (GList *nodes); + +GList * remove_nodes_with_label (GList *nodes, + Node **node_matrix, + gint width, + Label *label); + +Label * get_lowest_index_label (Label **neighbor_labels); + +Label * new_label (gint index); + +void join_components_to_main (GList *nodes, + Label *lowest_component_label, + guint horizontal_max_distance, + guint depth_max_distance, + guint graph_distance_threshold); + +void set_joint_from_node (SkeltrackJointList *joints, + Node *node, + SkeltrackJointId id, + gint dimension_reduction); + +gint * create_new_dist_matrix (gint matrix_size); + +gboolean dijkstra_to (GList *nodes, + Node *source, + Node *target, + gint width, + gint height, + gint *distances, + Node **previous); + +void convert_screen_coords_to_mm (guint width, + guint height, + guint dimension_reduction, + guint i, + guint j, + gint z, + gint *x, + gint *y); + +void convert_mm_to_screen_coords (guint width, + guint height, + guint dimension_reduction, + gint x, + gint y, + gint z, + guint *i, + guint *j); diff --git a/interface/external/skeltrack/include/skeltrack.h b/interface/external/skeltrack/include/skeltrack.h new file mode 100644 index 0000000000..8e1c572303 --- /dev/null +++ b/interface/external/skeltrack/include/skeltrack.h @@ -0,0 +1,28 @@ +/* + * skeltrack.h + * + * skeltrack - A GObject wrapper of the libfreenect library + * Copyright (C) 2011 Igalia S.L. + * + * Authors: + * Joaquim Manuel Pereira Rocha + * Eduardo Lima Mitev + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public License + * version 3, or (at your option) any later version as published by + * the Free Software Foundation. + * + * This library is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License at http://www.gnu.org/licenses/lgpl-3.0.txt + * for more details. + */ + +#ifndef __SKELTRACK_H__ +#define __SKELTRACK_H__ + +#include + +#endif /* __SKELTRACK_H__ */ diff --git a/interface/external/skeltrack/lib/UNIX/libskeltrack.a b/interface/external/skeltrack/lib/UNIX/libskeltrack.a new file mode 100644 index 0000000000..f34c83224b Binary files /dev/null and b/interface/external/skeltrack/lib/UNIX/libskeltrack.a differ diff --git a/interface/external/skeltrack/src/skeltrack-joint.c b/interface/external/skeltrack/src/skeltrack-joint.c new file mode 100644 index 0000000000..6310c6a789 --- /dev/null +++ b/interface/external/skeltrack/src/skeltrack-joint.c @@ -0,0 +1,159 @@ +/* + * skeltrack-joint.c + * + * Skeltrack - A Free Software skeleton tracking library + * Copyright (C) 2012 Igalia S.L. + * + * Authors: + * Joaquim Rocha + * Eduardo Lima Mitev + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 3 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License at http://www.gnu.org/licenses/lgpl-3.0.txt + * for more details. + */ + +/** + * SECTION:skeltrack-joint + * @short_description: Data structure that holds information about + * a skeleton joint. + * + * A #SkeltrackJoint is built automatically by #SkeltrackSkeleton when + * it finds a skeleton joint and can be used to get information about it. + * Each #SkeltrackJoint holds an id, given by #SkeltrackJointId that indicates + * which of the human skeleton joints it represents. + * + * Spacial information about a joint is given by the @x, @y and @z coordinates. + * To represent the joint in a 2D, the variables @screen_x and + * @screen_y will indicate the joint's position in the screen and are calculated + * taking into account the #SkeltrackSkeleton:dimension-reduction (it will + * be multiplied by this value). + * + * The tracked list of joints is represented by #SkeltrackJointList and given + * by skeltrack_skeleton_track_joints_finish(). + * To get a #SkeltrackJoint from a #SkeltrackJointList object, use the + * skeltrack_joint_list_get_joint() indicating the needed #SkeltrackJointId. + * + * A #SkeltrackJointList can be freed by using skeltrack_joint_list_free(). + * A #SkeltrackJoint can be copied by skeltrack_joint_copy() and freed by + * skeltrack_joint_free(). + **/ + +#include +#include "skeltrack-joint.h" + +/** + * skeltrack_joint_get_type: + * + * Returns: The registered #GType for #SkeltrackJoint boxed type + **/ +GType +skeltrack_joint_get_type (void) +{ + static GType type = 0; + + if (G_UNLIKELY (type == 0)) + type = g_boxed_type_register_static ("SkeltrackJoint", + (GBoxedCopyFunc) skeltrack_joint_copy, + (GBoxedFreeFunc) skeltrack_joint_free); + return type; +} + +/** + * skeltrack_joint_copy: + * @joint: The #SkeltrackJoint to copy + * + * Makes an exact copy of a #SkeltrackJoint object. + * + * Returns: (transfer full): A newly created #SkeltrackJoint. Use + * skeltrack_joint_free() to free it. + **/ +gpointer +skeltrack_joint_copy (SkeltrackJoint *joint) +{ + SkeltrackJoint *new_joint; + + if (joint == NULL) + return NULL; + + new_joint = g_slice_new0 (SkeltrackJoint); + memcpy (new_joint, joint, sizeof (SkeltrackJoint)); + + return new_joint; +} + +/** + * skeltrack_joint_free: + * @joint: The #SkeltrackJoint to free + * + * Frees a #SkeltrackJoint object. + **/ +void +skeltrack_joint_free (SkeltrackJoint *joint) +{ + g_slice_free (SkeltrackJoint, joint); +} + + +/** + * skeltrack_joint_list_free: + * @list: The #SkeltrackJointList to free + * + * Frees a #SkeltrackJointList object and each #SkeltrackJoint + * in it. + **/ +void +skeltrack_joint_list_free (SkeltrackJointList list) +{ + gint i; + + if (list == NULL) + return; + + for (i = 0; i < SKELTRACK_JOINT_MAX_JOINTS; i++) + { + g_slice_free (SkeltrackJoint, list[i]); + } + g_slice_free1 (SKELTRACK_JOINT_MAX_JOINTS * sizeof (SkeltrackJoint *), list); +} + +/** + * skeltrack_joint_list_get_joint: + * @list: The #SkeltrackJointList + * @id: The #SkeltrackJointId of the joint to get + * + * Gets a joint from a list of skeleton joints. The joint + * returned needs to be freed by using skeltrack_joint_free() or, + * alternatively, the whole list and its joints can be freed by using + * skeltrack_joint_list_free(). + * + * Returns: (transfer full): The #SkeltrackJoint that corresponds to + * the given @id or %NULL if that joint wasn't found. + **/ +SkeltrackJoint * +skeltrack_joint_list_get_joint (SkeltrackJointList list, SkeltrackJointId id) +{ + return list[id]; +} + +/** + * skeltrack_joint_list_new: + * + * Created a new list of #SkeltrackJointsList with its joints as #NULL. + * When it is no longer needed, free it with skeltrack_joint_list_free(). + * + * Returns: (transfer full): A newly allocated #SkeltrackJointList + **/ +SkeltrackJointList +skeltrack_joint_list_new (void) +{ + return (SkeltrackJointList) g_slice_alloc0 (SKELTRACK_JOINT_MAX_JOINTS * + sizeof (SkeltrackJoint *)); +} diff --git a/interface/external/skeltrack/src/skeltrack-skeleton.c b/interface/external/skeltrack/src/skeltrack-skeleton.c new file mode 100644 index 0000000000..9373af56a8 --- /dev/null +++ b/interface/external/skeltrack/src/skeltrack-skeleton.c @@ -0,0 +1,2027 @@ +/* + * skeltrack-skeleton.c + * + * Skeltrack - A Free Software skeleton tracking library + * Copyright (C) 2012 Igalia S.L. + * + * Authors: + * Joaquim Rocha + * Eduardo Lima Mitev + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 3 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License at http://www.gnu.org/licenses/lgpl-3.0.txt + * for more details. + */ + +/** + * SECTION:skeltrack-skeleton + * @short_description: Object that tracks the joints in a human skeleton + * + * This object tries to detect joints of the human skeleton. + * + * To track the joints, first create an instance of #SkeltrackSkeleton using + * skeltrack_skeleton_new() and then set a buffer from where the joints will + * be retrieved using the asynchronous function + * skeltrack_skeleton_track_joints() and get the list of joints using + * skeltrack_skeleton_track_joints_finish(). + * + * A common use case is to use this library together with a Kinect device so + * an easy way to retrieve the needed buffer is to use the GFreenect library. + * + * It currently tracks the joints identified by #SkeltrackJointId . + * + * Tracking the skeleton joints can be computational heavy so it is advised that + * the given buffer's dimension is reduced before setting it. To do it, + * simply choose the reduction factor and loop through the original buffer + * (using this factor as a step) and set the reduced buffer's values accordingly. + * The #SkeltrackSkeleton:dimension-reduction property holds this reduction + * value and should be changed to the reduction factor used (alternatively you + * can retrieve its default value and use it in the reduction, if it fits your + * needs). + * + * The skeleton tracking uses a few heuristics that proved to work well for + * tested cases but they can be tweaked by changing the following properties: + * #SkeltrackSkeleton:graph-distance-threshold , + * #SkeltrackSkeleton:graph-minimum-number-nodes , + * #SkeltrackSkeleton:hands-minimum-distance , + * #SkeltrackSkeleton:shoulders-arc-start-point , + * #SkeltrackSkeleton:shoulders-arc-length , + * #SkeltrackSkeleton:shoulders-circumference-radius , + * #SkeltrackSkeleton:shoulders-search-step . + **/ +#include +#include +#include + +#include "skeltrack-skeleton.h" +#include "skeltrack-smooth.h" +#include "skeltrack-util.h" + +#define SKELTRACK_SKELETON_GET_PRIVATE(obj) (G_TYPE_INSTANCE_GET_PRIVATE ((obj), \ + SKELTRACK_TYPE_SKELETON, \ + SkeltrackSkeletonPrivate)) + +#define DIMENSION_REDUCTION 16 +#define GRAPH_DISTANCE_THRESHOLD 150 +#define GRAPH_MINIMUM_NUMBER_OF_NODES 5 +#define HANDS_MINIMUM_DISTANCE 550 +#define SHOULDERS_CIRCUMFERENCE_RADIUS 300 +#define SHOULDERS_ARC_START_POINT 100 +#define SHOULDERS_ARC_LENGTH 250 +#define SHOULDERS_SEARCH_STEP 0.05 +#define JOINTS_PERSISTENCY_DEFAULT 3 +#define SMOOTHING_FACTOR_DEFAULT .5 +#define ENABLE_SMOOTHING_DEFAULT TRUE +#define DEFAULT_FOCUS_POINT_Z 1000 +#define TORSO_MINIMUM_NUMBER_NODES_DEFAULT 16.0 +#define EXTREMA_SPHERE_RADIUS 300 + +/* private data */ +struct _SkeltrackSkeletonPrivate +{ + guint16 *buffer; + guint buffer_width; + guint buffer_height; + + GAsyncResult *track_joints_result; + GMutex track_joints_mutex; + + GList *graph; + GList *labels; + Node **node_matrix; + gint *distances_matrix; + GList *main_component; + + guint16 dimension_reduction; + guint16 distance_threshold; + guint16 min_nr_nodes; + + guint16 hands_minimum_distance; + + guint16 shoulders_circumference_radius; + guint16 shoulders_arc_start_point; + guint16 shoulders_arc_length; + gfloat shoulders_search_step; + + guint16 extrema_sphere_radius; + + Node *focus_node; + + gboolean enable_smoothing; + SmoothData smooth_data; + + gfloat torso_minimum_number_nodes; + + SkeltrackJoint *previous_head; +}; + +/* Currently searches for head and hands */ +static const guint NR_EXTREMAS_TO_SEARCH = 3; + +/* properties */ +enum + { + PROP_0, + PROP_DIMENSION_REDUCTION, + PROP_GRAPH_DISTANCE_THRESHOLD, + PROP_GRAPH_MIN_NR_NODES, + PROP_HANDS_MINIMUM_DISTANCE, + PROP_SHOULDERS_CIRCUMFERENCE_RADIUS, + PROP_SHOULDERS_ARC_START_POINT, + PROP_SHOULDERS_ARC_LENGTH, + PROP_SHOULDERS_SEARCH_STEP, + PROP_EXTREMA_SPHERE_RADIUS, + PROP_SMOOTHING_FACTOR, + PROP_JOINTS_PERSISTENCY, + PROP_ENABLE_SMOOTHING, + PROP_TORSO_MINIMUM_NUMBER_NODES + }; + + +static void skeltrack_skeleton_class_init (SkeltrackSkeletonClass *class); +static void skeltrack_skeleton_init (SkeltrackSkeleton *self); +static void skeltrack_skeleton_finalize (GObject *obj); +static void skeltrack_skeleton_dispose (GObject *obj); + +static void skeltrack_skeleton_set_property (GObject *obj, + guint prop_id, + const GValue *value, + GParamSpec *pspec); +static void skeltrack_skeleton_get_property (GObject *obj, + guint prop_id, + GValue *value, + GParamSpec *pspec); + + +static void clean_tracking_resources (SkeltrackSkeleton *self); + +G_DEFINE_TYPE (SkeltrackSkeleton, skeltrack_skeleton, G_TYPE_OBJECT) + +static void +skeltrack_skeleton_class_init (SkeltrackSkeletonClass *class) +{ + GObjectClass *obj_class; + + obj_class = G_OBJECT_CLASS (class); + + obj_class->dispose = skeltrack_skeleton_dispose; + obj_class->finalize = skeltrack_skeleton_finalize; + obj_class->get_property = skeltrack_skeleton_get_property; + obj_class->set_property = skeltrack_skeleton_set_property; + + /* install properties */ + + /** + * SkeltrackSkeleton:dimension-reduction + * + * The value by which the dimension of the buffer was reduced + * (in case it was). + **/ + g_object_class_install_property (obj_class, + PROP_DIMENSION_REDUCTION, + g_param_spec_uint ("dimension-reduction", + "Dimension reduction", + "The dimension reduction value", + 1, + 1024, + DIMENSION_REDUCTION, + G_PARAM_READWRITE | + G_PARAM_STATIC_STRINGS)); + + /** + * SkeltrackSkeleton:graph-distance-threshold + * + * The value (in mm) for the distance threshold between each node and its + * neighbors. This means that a node in the graph will only be connected + * to another if they aren't farther apart then this value. + **/ + g_object_class_install_property (obj_class, + PROP_GRAPH_DISTANCE_THRESHOLD, + g_param_spec_uint ("graph-distance-threshold", + "Graph's distance threshold", + "The distance threshold between " + "each node.", + 1, + G_MAXUINT16, + GRAPH_DISTANCE_THRESHOLD, + G_PARAM_READWRITE | + G_PARAM_STATIC_STRINGS)); + + /** + * SkeltrackSkeleton:graph-minimum-number-nodes + * + * The minimum number of nodes each of the graph's components + * should have (when it is not fully connected). + **/ + g_object_class_install_property (obj_class, + PROP_GRAPH_MIN_NR_NODES, + g_param_spec_uint ("graph-minimum-number-nodes", + "Graph's minimum number of nodes", + "The minimum number of nodes " + "of the graph's components ", + 1, + G_MAXUINT16, + GRAPH_MINIMUM_NUMBER_OF_NODES, + G_PARAM_READWRITE | + G_PARAM_STATIC_STRINGS)); + + /** + * SkeltrackSkeleton:hands-minimum-distance + * + * The minimum distance (in mm) that each hand should be from its + * respective shoulder. + **/ + g_object_class_install_property (obj_class, + PROP_HANDS_MINIMUM_DISTANCE, + g_param_spec_uint ("hands-minimum-distance", + "Hands' minimum distance from the " + "shoulders", + "The minimum distance (in mm) that " + "each hand should be from its " + "respective shoulder.", + 300, + G_MAXUINT, + HANDS_MINIMUM_DISTANCE, + G_PARAM_READWRITE | + G_PARAM_STATIC_STRINGS)); + + /** + * SkeltrackSkeleton:shoulders-circumference-radius + * + * The radius of the circumference (in mm) from the head with which + * to look for the shoulders. + **/ + g_object_class_install_property (obj_class, + PROP_SHOULDERS_CIRCUMFERENCE_RADIUS, + g_param_spec_uint ("shoulders-circumference-radius", + "Shoulders' circumference radius", + "The radius of the circumference " + "(in mm) from the head with which " + "to look for the shoulders.", + 1, + G_MAXUINT16, + SHOULDERS_CIRCUMFERENCE_RADIUS, + G_PARAM_READWRITE | + G_PARAM_STATIC_STRINGS)); + + /** + * SkeltrackSkeleton:shoulders-arc-start-point + * + * The starting point (in mm) of the arc (from the bottom of the + * shoulders' circumference) where the shoulders will be searched for. + * This point is used together with the + * SkeltrackSkeleton::shoulders-arc-length to determine the arc + * where the shoulders' points will be looked for. + **/ + g_object_class_install_property (obj_class, + PROP_SHOULDERS_ARC_START_POINT, + g_param_spec_uint ("shoulders-arc-start-point", + "Shoulders' arc start point", + "The starting point (in mm) of the " + "arc from the bottom of the " + "shoulders' circumference where " + "the shoulders will be searched for.", + 1, + G_MAXUINT16, + SHOULDERS_ARC_START_POINT, + G_PARAM_READWRITE | + G_PARAM_STATIC_STRINGS)); + + /** + * SkeltrackSkeleton:shoulders-arc-length + * + * The length (in mm) of the arc where the shoulders will be searched. + * This length is used together with the + * SkeltrackSkeleton::shoulders-arc-start-point to determine the arc + * where the shoulders' points will be looked for. + **/ + g_object_class_install_property (obj_class, + PROP_SHOULDERS_ARC_LENGTH, + g_param_spec_uint ("shoulders-arc-length", + "Shoulders' arc length", + "The length (in mm) of the arc " + "where the shoulders will be " + "searched.", + 1, + G_MAXUINT16, + SHOULDERS_ARC_LENGTH, + G_PARAM_READWRITE | + G_PARAM_STATIC_STRINGS)); + + + /** + * SkeltrackSkeleton:shoulders-search-step + * + * The step considered for sampling the shoulders' circumference + * when searching for the shoulders. + **/ + g_object_class_install_property (obj_class, + PROP_SHOULDERS_SEARCH_STEP, + g_param_spec_float ("shoulders-search-step", + "Shoulders' search step", + "The step considered for sampling " + "the shoulders' circumference " + "when searching for the shoulders.", + .01, + M_PI, + .01, + G_PARAM_READWRITE | + G_PARAM_STATIC_STRINGS)); + + /** + * SkeltrackSkeleton:smoothing-factor + * + * The factor by which the joints should be smoothed. This refers to + * Holt's Double Exponential Smoothing and determines how the current and + * previous data and trend will be used. A value closer to 0 will produce smoother + * results but increases latency. + **/ + g_object_class_install_property (obj_class, + PROP_SMOOTHING_FACTOR, + g_param_spec_float ("smoothing-factor", + "Smoothing factor", + "The factor by which the joints values" + "should be smoothed.", + .0, + 1.0, + .5, + G_PARAM_READWRITE | + G_PARAM_STATIC_STRINGS)); + + /** + * SkeltrackSkeleton:joints-persistency + * + * The number of times that a joint can be null until its previous + * value is discarded. For example, if this property is 3, the last value for + * a joint will keep being used until the new value for this joint is null for + * 3 consecutive times. + * + **/ + g_object_class_install_property (obj_class, + PROP_JOINTS_PERSISTENCY, + g_param_spec_uint ("joints-persistency", + "Joints persistency", + "The number of times that a joint " + "can be null until its previous " + "value is discarded", + 0, + G_MAXUINT16, + JOINTS_PERSISTENCY_DEFAULT, + G_PARAM_READWRITE | + G_PARAM_STATIC_STRINGS)); + + /** + * SkeltrackSkeleton:enable-smoothing + * + * Whether smoothing the joints should be applied or not. + * + **/ + g_object_class_install_property (obj_class, + PROP_ENABLE_SMOOTHING, + g_param_spec_boolean ("enable-smoothing", + "Enable smoothing", + "Whether smoothing should be " + "applied or not", + ENABLE_SMOOTHING_DEFAULT, + G_PARAM_READWRITE | + G_PARAM_STATIC_STRINGS)); + + /** + * SkeltrackSkeleton:torso-minimum-number-nodes + * + * Minimum number of nodes for a component to be considered torso. + * + **/ + g_object_class_install_property (obj_class, + PROP_TORSO_MINIMUM_NUMBER_NODES, + g_param_spec_float ("torso-minimum-number-nodes", + "Torso minimum number of nodes", + "Minimum number of nodes for a " + "component to be considered " + "torso", + 0, + G_MAXUINT16, + TORSO_MINIMUM_NUMBER_NODES_DEFAULT, + G_PARAM_READWRITE | + G_PARAM_STATIC_STRINGS)); + + /** + * SkeltrackSkeleton:extrema-sphere-radius + * + * The radius of the sphere around the extremas (in mm). + * + * Points inside this sphere are considered for calculating the average position + * of the extrema. If the value is 0, no averaging is done. + **/ + g_object_class_install_property (obj_class, + PROP_EXTREMA_SPHERE_RADIUS, + g_param_spec_uint ("extrema-sphere-radius", + "Extrema sphere radius", + "The radius of the sphere around " + "the extremas (in mm).", + 0, + G_MAXUINT16, + EXTREMA_SPHERE_RADIUS, + G_PARAM_READWRITE | + G_PARAM_STATIC_STRINGS)); + + + /* add private structure */ + g_type_class_add_private (obj_class, sizeof (SkeltrackSkeletonPrivate)); +} + +static void +skeltrack_skeleton_init (SkeltrackSkeleton *self) +{ + guint i; + SkeltrackSkeletonPrivate *priv; + + priv = SKELTRACK_SKELETON_GET_PRIVATE (self); + self->priv = priv; + + priv->buffer = NULL; + priv->buffer_width = 0; + priv->buffer_height = 0; + + priv->graph = NULL; + priv->labels = NULL; + priv->main_component = NULL; + priv->node_matrix = NULL; + priv->distances_matrix = NULL; + + priv->dimension_reduction = DIMENSION_REDUCTION; + priv->distance_threshold = GRAPH_DISTANCE_THRESHOLD; + + priv->min_nr_nodes = GRAPH_MINIMUM_NUMBER_OF_NODES; + + priv->hands_minimum_distance = HANDS_MINIMUM_DISTANCE; + + priv->shoulders_circumference_radius = SHOULDERS_CIRCUMFERENCE_RADIUS; + priv->shoulders_arc_start_point = SHOULDERS_ARC_START_POINT; + priv->shoulders_arc_length = SHOULDERS_ARC_LENGTH; + priv->shoulders_search_step = SHOULDERS_SEARCH_STEP; + + priv->extrema_sphere_radius = EXTREMA_SPHERE_RADIUS; + + priv->focus_node = g_slice_new0 (Node); + priv->focus_node->x = 0; + priv->focus_node->y = 0; + priv->focus_node->z = DEFAULT_FOCUS_POINT_Z; + + priv->track_joints_result = NULL; + + g_mutex_init (&priv->track_joints_mutex); + + priv->enable_smoothing = ENABLE_SMOOTHING_DEFAULT; + priv->smooth_data.smoothing_factor = SMOOTHING_FACTOR_DEFAULT; + priv->smooth_data.smoothed_joints = NULL; + priv->smooth_data.trend_joints = NULL; + priv->smooth_data.joints_persistency = JOINTS_PERSISTENCY_DEFAULT; + for (i = 0; i < SKELTRACK_JOINT_MAX_JOINTS; i++) + priv->smooth_data.joints_persistency_counter[i] = JOINTS_PERSISTENCY_DEFAULT; + + priv->torso_minimum_number_nodes = TORSO_MINIMUM_NUMBER_NODES_DEFAULT; + + priv->previous_head = NULL; +} + +static void +skeltrack_skeleton_dispose (GObject *obj) +{ + /* TODO: cancel any cancellable to interrupt joints tracking operation */ + + G_OBJECT_CLASS (skeltrack_skeleton_parent_class)->dispose (obj); +} + +static void +skeltrack_skeleton_finalize (GObject *obj) +{ + SkeltrackSkeleton *self = SKELTRACK_SKELETON (obj); + + g_mutex_clear (&self->priv->track_joints_mutex); + + skeltrack_joint_list_free (self->priv->smooth_data.smoothed_joints); + skeltrack_joint_list_free (self->priv->smooth_data.trend_joints); + + skeltrack_joint_free (self->priv->previous_head); + + clean_tracking_resources (self); + + g_slice_free (Node, self->priv->focus_node); + + G_OBJECT_CLASS (skeltrack_skeleton_parent_class)->finalize (obj); +} + +static void +skeltrack_skeleton_set_property (GObject *obj, + guint prop_id, + const GValue *value, + GParamSpec *pspec) +{ + SkeltrackSkeleton *self; + + self = SKELTRACK_SKELETON (obj); + + switch (prop_id) + { + case PROP_DIMENSION_REDUCTION: + self->priv->dimension_reduction = g_value_get_uint (value); + break; + + case PROP_GRAPH_DISTANCE_THRESHOLD: + self->priv->distance_threshold = g_value_get_uint (value); + break; + + case PROP_GRAPH_MIN_NR_NODES: + self->priv->min_nr_nodes = g_value_get_uint (value); + break; + + case PROP_HANDS_MINIMUM_DISTANCE: + self->priv->hands_minimum_distance = g_value_get_uint (value); + break; + + case PROP_SHOULDERS_CIRCUMFERENCE_RADIUS: + self->priv->shoulders_circumference_radius = g_value_get_uint (value); + break; + + case PROP_SHOULDERS_ARC_START_POINT: + self->priv->shoulders_arc_start_point = g_value_get_uint (value); + break; + + case PROP_SHOULDERS_ARC_LENGTH: + self->priv->shoulders_arc_length = g_value_get_uint (value); + break; + + case PROP_SHOULDERS_SEARCH_STEP: + self->priv->shoulders_circumference_radius = g_value_get_float (value); + break; + + case PROP_EXTREMA_SPHERE_RADIUS: + self->priv->extrema_sphere_radius = g_value_get_uint (value); + break; + + case PROP_SMOOTHING_FACTOR: + self->priv->smooth_data.smoothing_factor = g_value_get_float (value); + break; + + case PROP_JOINTS_PERSISTENCY: + self->priv->smooth_data.joints_persistency = g_value_get_uint (value); + reset_joints_persistency_counter (&self->priv->smooth_data); + break; + + case PROP_ENABLE_SMOOTHING: + self->priv->enable_smoothing = g_value_get_boolean (value); + break; + + case PROP_TORSO_MINIMUM_NUMBER_NODES: + self->priv->torso_minimum_number_nodes = g_value_get_float (value); + break; + + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (obj, prop_id, pspec); + break; + } +} + +static void +skeltrack_skeleton_get_property (GObject *obj, + guint prop_id, + GValue *value, + GParamSpec *pspec) +{ + SkeltrackSkeleton *self; + + self = SKELTRACK_SKELETON (obj); + + switch (prop_id) + { + case PROP_DIMENSION_REDUCTION: + g_value_set_uint (value, self->priv->dimension_reduction); + break; + + case PROP_GRAPH_DISTANCE_THRESHOLD: + g_value_set_uint (value, self->priv->distance_threshold); + break; + + case PROP_GRAPH_MIN_NR_NODES: + g_value_set_uint (value, self->priv->min_nr_nodes); + break; + + case PROP_HANDS_MINIMUM_DISTANCE: + g_value_set_uint (value, self->priv->hands_minimum_distance); + break; + + case PROP_SHOULDERS_CIRCUMFERENCE_RADIUS: + g_value_set_uint (value, self->priv->shoulders_circumference_radius); + break; + + case PROP_SHOULDERS_ARC_START_POINT: + g_value_set_uint (value, self->priv->shoulders_arc_start_point); + break; + + case PROP_SHOULDERS_ARC_LENGTH: + g_value_set_uint (value, self->priv->shoulders_arc_length); + break; + + case PROP_SHOULDERS_SEARCH_STEP: + g_value_set_float (value, self->priv->shoulders_search_step); + break; + + case PROP_EXTREMA_SPHERE_RADIUS: + g_value_set_uint (value, self->priv->extrema_sphere_radius); + break; + + case PROP_SMOOTHING_FACTOR: + g_value_set_float (value, self->priv->smooth_data.smoothing_factor); + break; + + case PROP_JOINTS_PERSISTENCY: + g_value_set_uint (value, self->priv->smooth_data.joints_persistency); + break; + + case PROP_ENABLE_SMOOTHING: + g_value_set_boolean (value, self->priv->enable_smoothing); + break; + + case PROP_TORSO_MINIMUM_NUMBER_NODES: + g_value_set_float (value, self->priv->torso_minimum_number_nodes); + break; + + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (obj, prop_id, pspec); + break; + } +} + +static gint +join_neighbor (SkeltrackSkeleton *self, + Node *node, + Label **neighbor_labels, + gint index, + gint i, + gint j) +{ + Node *neighbor; + if (i < 0 || i >= self->priv->buffer_width || + j < 0 || j >= self->priv->buffer_height) + { + return index; + } + + neighbor = self->priv->node_matrix[self->priv->buffer_width * j + i]; + if (neighbor != NULL) + { + gint distance; + distance = get_distance (neighbor, node); + if (distance < self->priv->distance_threshold) + { + neighbor->neighbors = g_list_append (neighbor->neighbors, + node); + node->neighbors = g_list_append (node->neighbors, + neighbor); + neighbor_labels[index] = neighbor->label; + index++; + } + } + return index; +} + +GList * +make_graph (SkeltrackSkeleton *self, GList **label_list) +{ + SkeltrackSkeletonPrivate *priv; + gint i, j, n; + Node *node; + GList *nodes = NULL; + GList *labels = NULL; + GList *current_label; + Label *main_component_label = NULL; + gint index = 0; + gint next_label = -1; + guint16 value; + guint16 *buffer; + gint width, height; + + buffer = self->priv->buffer; + width = self->priv->buffer_width; + height = self->priv->buffer_height; + + priv = self->priv; + + + if (priv->node_matrix == NULL) + { + priv->node_matrix = g_slice_alloc0 (width * height * sizeof (Node *)); + } + else + { + memset (self->priv->node_matrix, + 0, + width * height * sizeof (Node *)); + } + + for (i = 0; i < width; i++) + { + for (j = 0; j < height; j++) + { + gint south, north, west; + Label *lowest_index_label = NULL; + Label *neighbor_labels[4] = {NULL, NULL, NULL, NULL}; + + value = buffer[j * width + i]; + if (value == 0) + continue; + + node = g_slice_new0 (Node); + node->i = i; + node->j = j; + node->z = value; + convert_screen_coords_to_mm (self->priv->buffer_width, + self->priv->buffer_height, + self->priv->dimension_reduction, + i, j, + node->z, + &(node->x), + &(node->y)); + node->neighbors = NULL; + node->linked_nodes = NULL; + + index = 0; + + south = j + 1; + north = j - 1; + west = i - 1; + + /* West */ + index = join_neighbor (self, + node, + neighbor_labels, + index, + west, j); + /* South West*/ + index = join_neighbor (self, + node, + neighbor_labels, + index, + west, south); + /* North */ + index = join_neighbor (self, + node, + neighbor_labels, + index, + i, north); + + /* North West */ + index = join_neighbor (self, + node, + neighbor_labels, + index, + west, north); + + lowest_index_label = get_lowest_index_label (neighbor_labels); + + /* No neighbors */ + if (lowest_index_label == NULL) + { + Label *label; + next_label++; + label = new_label (next_label); + labels = g_list_append (labels, label); + lowest_index_label = label; + } + else + { + for (index = 0; index < 4; index++) + { + if (neighbor_labels[index] != NULL) + { + label_union (neighbor_labels[index], lowest_index_label); + } + } + } + + node->label = lowest_index_label; + nodes = g_list_append(nodes, node); + priv->node_matrix[width * node->j + node->i] = node; + } + } + + for (n = 0; n < g_list_length (nodes); n++) + { + Node *node = (Node *) g_list_nth_data (nodes, n); + node->label = label_find (node->label); + node->label->nodes = g_list_append (node->label->nodes, + node); + + /* Assign lower node so we can extract the + lower graph's component */ + if (node->label->lower_screen_y == -1 || + node->j > node->label->lower_screen_y) + { + node->label->lower_screen_y = node->j; + } + + /* Assign farther to the camera node so we + can extract the main graph component */ + if (node->label->higher_z == -1 || + node->z > node->label->higher_z) + { + node->label->higher_z = node->z; + } + + /* Assign closer to the camera node so we + can extract the main graph component */ + if (node->label->lower_z == -1 || + node->z < node->label->lower_z) + { + node->label->lower_z = node->z; + } + } + + for (current_label = g_list_first (labels); + current_label != NULL; + current_label = g_list_next (current_label)) + { + Label *label; + GList *current_nodes; + + label = (Label *) current_label->data; + current_nodes = label->nodes; + + label->normalized_num_nodes = g_list_length (current_nodes) * + ((label->higher_z - label->lower_z)/2 + + label->lower_z) * + (pow (DIMENSION_REDUCTION, 2)/2) / + 1000000; + } + + main_component_label = get_main_component (nodes, + priv->focus_node, + priv->torso_minimum_number_nodes); + + current_label = g_list_first (labels); + while (current_label != NULL) + { + Label *label; + label = (Label *) current_label->data; + + /* Remove label if number of nodes is less than + the minimum required */ + if (g_list_length (label->nodes) < priv->min_nr_nodes) + { + nodes = remove_nodes_with_label (nodes, + priv->node_matrix, + priv->buffer_width, + label); + + GList *link = current_label; + current_label = g_list_next (current_label); + labels = g_list_delete_link (labels, link); + free_label (label); + continue; + } + + current_label = g_list_next (current_label); + } + + if (main_component_label) + { + join_components_to_main (labels, + main_component_label, + priv->distance_threshold, + priv->hands_minimum_distance, + priv->distance_threshold); + + current_label = g_list_first (labels); + while (current_label != NULL) + { + Label *label; + label = (Label *) current_label->data; + if (label == main_component_label) + { + current_label = g_list_next (current_label); + continue; + } + + if (label->bridge_node == NULL) + { + nodes = remove_nodes_with_label (nodes, + priv->node_matrix, + priv->buffer_width, + label); + + GList *link = current_label; + current_label = g_list_next (current_label); + labels = g_list_delete_link (labels, link); + free_label (label); + continue; + } + + label->bridge_node->neighbors = + g_list_append (label->bridge_node->neighbors, label->to_node); + label->to_node->neighbors = g_list_append (label->to_node->neighbors, + label->bridge_node); + + current_label = g_list_next (current_label); + } + + priv->main_component = main_component_label->nodes; + } + + *label_list = labels; + + return nodes; +} + +Node * +get_centroid (SkeltrackSkeleton *self) +{ + gint avg_x = 0; + gint avg_y = 0; + gint avg_z = 0; + gint length; + GList *node_list; + Node *cent = NULL; + Node *centroid = NULL; + + if (self->priv->main_component == NULL) + return NULL; + + for (node_list = g_list_first (self->priv->main_component); + node_list != NULL; + node_list = g_list_next (node_list)) + { + Node *node; + node = (Node *) node_list->data; + avg_x += node->x; + avg_y += node->y; + avg_z += node->z; + } + + length = g_list_length (self->priv->main_component); + cent = g_slice_new0 (Node); + cent->x = avg_x / length; + cent->y = avg_y / length; + cent->z = avg_z / length; + cent->linked_nodes = NULL; + + centroid = get_closest_node (self->priv->graph, cent); + + g_slice_free (Node, cent); + + return centroid; +} + +static Node * +get_lowest (SkeltrackSkeleton *self, Node *centroid) +{ + Node *lowest = NULL; + /* @TODO: Use the node_matrix instead of the lowest + component to look for the lowest node as it's faster. */ + if (self->priv->main_component != NULL) + { + GList *node_list; + for (node_list = g_list_first (self->priv->main_component); + node_list != NULL; + node_list = g_list_next (node_list)) + { + Node *node; + node = (Node *) node_list->data; + if (node->i != centroid->i) + continue; + if (lowest == NULL || + lowest->j < node->j) + { + lowest = node; + } + } + } + return lowest; +} + +static Node * +get_longer_distance (SkeltrackSkeleton *self, gint *distances) +{ + GList *current; + Node *farthest_node; + + current = g_list_first (self->priv->graph); + farthest_node = (Node *) current->data; + current = g_list_next (current); + + while (current != NULL) + { + Node *node; + node = (Node *) current->data; + if (node != NULL && + (distances[farthest_node->j * + self->priv->buffer_width + + farthest_node->i] != -1 && + distances[farthest_node->j * + self->priv->buffer_width + + farthest_node->i] < distances[node->j * + self->priv->buffer_width + + node->i])) + { + farthest_node = node; + } + current = g_list_next (current); + } + return farthest_node; +} + +static void +set_average_extremas (SkeltrackSkeletonPrivate *priv, GList *extremas) +{ + GList *current_extrema, *averaged_extremas = NULL; + + for (current_extrema = g_list_first (extremas); + current_extrema != NULL; + current_extrema = g_list_next (current_extrema)) + { + GList *current_node; + Node *extrema, *node = NULL, *cent = NULL, *node_centroid = NULL; + gint avg_x = 0, avg_y = 0, avg_z = 0, length = 0; + + extrema = (Node *) current_extrema->data; + + for (current_node = g_list_first (priv->graph); + current_node != NULL; + current_node = g_list_next (current_node)) + { + node = (Node *) current_node->data; + + if ((get_distance (extrema, node) < + priv->extrema_sphere_radius)) + { + avg_x += node->x; + avg_y += node->y; + avg_z += node->z; + + length++; + } + } + + /* if the length is 1 then it is because no other + nodes were considered for the average */ + if (length > 1) + { + cent = g_slice_new0 (Node); + cent->x = avg_x / length; + cent->y = avg_y / length; + cent->z = avg_z / length; + cent->linked_nodes = NULL; + + node_centroid = get_closest_node (priv->graph, cent); + + /* If the new averaged extrema is not already an extrema + set it for addition */ + if (g_list_find (averaged_extremas, node_centroid) == NULL && + g_list_find (extremas, node_centroid) == NULL) + { + current_extrema->data = node_centroid; + } + + g_slice_free (Node, cent); + } + } +} + +static GList * +get_extremas (SkeltrackSkeleton *self, Node *centroid) +{ + SkeltrackSkeletonPrivate *priv; + gint i, nr_nodes, matrix_size; + Node *lowest, *source, *node; + GList *extremas = NULL; + + priv = self->priv; + lowest = get_lowest (self, centroid); + source = lowest; + + matrix_size = priv->buffer_width * priv->buffer_height; + if (priv->distances_matrix == NULL) + { + priv->distances_matrix = g_slice_alloc0 (matrix_size * sizeof (gint)); + } + + for (i = 0; i < matrix_size; i++) + { + priv->distances_matrix[i] = -1; + } + + for (nr_nodes = NR_EXTREMAS_TO_SEARCH; + source != NULL && nr_nodes > 0; + nr_nodes--) + { + dijkstra_to (priv->graph, + source, + NULL, + priv->buffer_width, + priv->buffer_height, + priv->distances_matrix, + NULL); + + node = get_longer_distance (self, priv->distances_matrix); + + if (node == NULL) + continue; + + if (node != source) + { + priv->distances_matrix[node->j * priv->buffer_width + node->i] = 0; + source->linked_nodes = g_list_append (source->linked_nodes, node); + node->linked_nodes = g_list_append (node->linked_nodes, source); + source = node; + extremas = g_list_append (extremas, node); + } + } + + if (self->priv->extrema_sphere_radius != 0) + { + set_average_extremas (priv, extremas); + } + + return extremas; +} + +static Node * +get_shoulder_node (SkeltrackSkeletonPrivate *priv, + gfloat alpha, + gfloat step, + gint x_node, + gint y_node, + gint z_centroid) +{ + guint radius, arc_start_point, arc_length, current_i, current_j; + gfloat start_angle, last_node_arc, current_arc, angle, current_x, current_y; + Node *current_node = NULL; + Node *last_node = NULL; + + radius = priv->shoulders_circumference_radius; + arc_start_point = priv->shoulders_arc_start_point; + arc_length = priv->shoulders_arc_length; + + start_angle = M_PI_2; + + angle = start_angle + alpha; + current_x = x_node + radius * cos (angle); + current_y = y_node + radius * sin (angle); + current_arc = 0; + last_node_arc = 0; + current_node = NULL; + last_node = NULL; + + while (current_arc <= (arc_start_point + arc_length)) + { + convert_mm_to_screen_coords (priv->buffer_width, + priv->buffer_height, + priv->dimension_reduction, + current_x, + current_y, + z_centroid, + ¤t_i, + ¤t_j); + + if (current_i >= priv->buffer_width || current_j >= priv->buffer_height) + break; + + current_node = priv->node_matrix[current_j * priv->buffer_width + + current_i]; + + if (current_node != NULL) + { + last_node = current_node; + last_node_arc = current_arc; + } + + angle += step; + current_x = x_node + radius * cos (angle); + current_y = y_node + radius * sin (angle); + current_arc = ABS (angle - start_angle) * radius; + } + + if (last_node_arc < arc_start_point) + return NULL; + + return last_node; +} + +static gboolean +check_if_node_can_be_head (SkeltrackSkeleton *self, + Node *node, + Node *centroid, + Node **left_shoulder, + Node **right_shoulder) +{ + gfloat alpha; + Node *found_right_shoulder = NULL, *found_left_shoulder = NULL; + + SkeltrackSkeletonPrivate *priv; + + *left_shoulder = NULL; + *right_shoulder = NULL; + + priv = self->priv; + + if (node->j > centroid->j) + return FALSE; + + if ((node->y - centroid->y) != 0) + alpha = atan( ABS (node->x - centroid->x) / ABS (node->y - centroid->y)); + else + return FALSE; + + /* too much tilt, cannot be the head */ + if (alpha >= M_PI_4) + return FALSE; + + if (node->x < centroid->x) + alpha = -alpha; + + found_right_shoulder = get_shoulder_node (priv, + alpha, + priv->shoulders_search_step, + node->x, + node->y, + centroid->z); + if (found_right_shoulder == NULL) + return FALSE; + + found_left_shoulder = get_shoulder_node (priv, + alpha, + -priv->shoulders_search_step, + node->x, + node->y, + centroid->z); + + if (found_left_shoulder == NULL) + return FALSE; + + *right_shoulder = found_right_shoulder; + *left_shoulder = found_left_shoulder; + + return TRUE; +} + +static gboolean +get_head_and_shoulders (SkeltrackSkeleton *self, + GList *extremas, + Node *centroid, + Node **head, + Node **left_shoulder, + Node **right_shoulder) +{ + Node *node; + GList *current_extrema; + + for (current_extrema = g_list_first (extremas); + current_extrema != NULL; + current_extrema = g_list_next (current_extrema)) + { + node = (Node *) current_extrema->data; + + if (check_if_node_can_be_head (self, + node, + centroid, + left_shoulder, + right_shoulder)) + { + *head = node; + return TRUE; + } + } + return FALSE; +} + +static void +identify_arm_extrema (gint *distances, + Node **previous_nodes, + gint width, + gint hand_distance, + Node *extrema, + Node **elbow_extrema, + Node **hand_extrema) +{ + gint total_dist; + + if (extrema == NULL) + return; + + total_dist = distances[width * extrema->j + extrema->i]; + if (total_dist < hand_distance) + { + *elbow_extrema = extrema; + *hand_extrema = NULL; + } + else + { + Node *previous; + gint elbow_dist; + + previous = previous_nodes[extrema->j * width + extrema->i]; + elbow_dist = total_dist / 2; + while (previous && + distances[previous->j * width + previous->i] > elbow_dist) + { + previous = previous_nodes[previous->j * width + previous->i]; + } + *elbow_extrema = previous; + *hand_extrema = extrema; + } +} + +static void +set_left_and_right_from_extremas (SkeltrackSkeleton *self, + GList *extremas, + Node *head, + Node *left_shoulder, + Node *right_shoulder, + SkeltrackJointList *joints) +{ + gint *dist_left_a = NULL; + gint *dist_left_b = NULL; + gint *dist_right_a = NULL; + gint *dist_right_b = NULL; + gint total_dist_left_a = -1; + gint total_dist_right_a = -1; + gint total_dist_left_b = -1; + gint total_dist_right_b = -1; + gint *distances_left[2] = {NULL, NULL}; + gint *distances_right[2] = {NULL, NULL}; + gint index_left = -1; + gint index_right = -1; + Node *elbow_extrema, *hand_extrema; + Node **previous_left_a = NULL; + Node **previous_left_b = NULL; + Node **previous_right_a = NULL; + Node **previous_right_b = NULL; + Node **previous_left[2] = {NULL, NULL}; + Node **previous_right[2] = {NULL, NULL}; + Node *ext_a = NULL; + Node *ext_b = NULL; + Node *left_extrema[2] = {NULL, NULL}; + Node *right_extrema[2] = {NULL, NULL}; + GList *current_extrema; + gint width, height, matrix_size; + + for (current_extrema = g_list_first (extremas); + current_extrema != NULL; + current_extrema = g_list_next (current_extrema)) + { + Node *node; + node = (Node *) current_extrema->data; + if (node != head) + { + if (ext_a == NULL) + ext_a = node; + else + ext_b = node; + } + } + + if (head == NULL) + return; + + width = self->priv->buffer_width; + height = self->priv->buffer_height; + matrix_size = width * height; + + previous_left_a = g_slice_alloc0 (matrix_size * sizeof (Node *)); + previous_left_b = g_slice_alloc0 (matrix_size * sizeof (Node *)); + previous_right_a = g_slice_alloc0 (matrix_size * sizeof (Node *)); + previous_right_b = g_slice_alloc0 (matrix_size * sizeof (Node *)); + + dist_left_a = create_new_dist_matrix(matrix_size); + dijkstra_to (self->priv->graph, + left_shoulder, + ext_a, + width, + height, + dist_left_a, + previous_left_a); + + dist_left_b = create_new_dist_matrix(matrix_size); + dijkstra_to (self->priv->graph, + left_shoulder, + ext_b, + width, + height, + dist_left_b, + previous_left_b); + + dist_right_a = create_new_dist_matrix(matrix_size); + dijkstra_to (self->priv->graph, + right_shoulder, + ext_a, + width, + height, + dist_right_a, previous_right_a); + + dist_right_b = create_new_dist_matrix(matrix_size); + dijkstra_to (self->priv->graph, + right_shoulder, + ext_b, + width, + height, + dist_right_b, + previous_right_b); + + total_dist_left_a = dist_left_a[ext_a->j * width + ext_a->i]; + total_dist_right_a = dist_right_a[ext_a->j * width + ext_a->i]; + total_dist_left_b = dist_left_b[ext_b->j * width + ext_b->i]; + total_dist_right_b = dist_right_b[ext_b->j * width + ext_b->i]; + + if (total_dist_left_a < total_dist_right_a) + { + index_left++; + left_extrema[index_left] = ext_a; + distances_left[index_left] = dist_left_a; + previous_left[index_left] = previous_left_a; + } + else + { + index_right++; + right_extrema[index_right] = ext_a; + distances_right[index_right] = dist_right_a; + previous_right[index_right] = previous_right_a; + } + + if (total_dist_left_b < total_dist_right_b) + { + index_left++; + left_extrema[index_left] = ext_b; + distances_left[index_left] = dist_left_b; + previous_left[index_left] = previous_left_b; + } + else + { + index_right++; + right_extrema[index_right] = ext_b; + distances_right[index_right] = dist_right_b; + previous_right[index_right] = previous_right_b; + } + + elbow_extrema = NULL; + hand_extrema = NULL; + identify_arm_extrema (distances_left[0], + previous_left[0], + width, + self->priv->hands_minimum_distance, + left_extrema[0], + &elbow_extrema, + &hand_extrema); + + /* Two left extremas */ + if (index_left == 1) + { + if (hand_extrema == NULL) + { + hand_extrema = left_extrema[1]; + elbow_extrema = left_extrema[0]; + } + else + { + hand_extrema = left_extrema[0]; + elbow_extrema = left_extrema[1]; + } + } + + set_joint_from_node (joints, + elbow_extrema, + SKELTRACK_JOINT_ID_LEFT_ELBOW, + self->priv->dimension_reduction); + set_joint_from_node (joints, + hand_extrema, + SKELTRACK_JOINT_ID_LEFT_HAND, + self->priv->dimension_reduction); + + + elbow_extrema = NULL; + hand_extrema = NULL; + identify_arm_extrema (distances_right[0], + previous_right[0], + width, + self->priv->hands_minimum_distance, + right_extrema[0], + &elbow_extrema, + &hand_extrema); + + /* Two right extremas */ + if (index_right == 1) + { + if (hand_extrema == NULL) + { + hand_extrema = right_extrema[1]; + elbow_extrema = right_extrema[0]; + } + else + { + hand_extrema = right_extrema[0]; + elbow_extrema = right_extrema[1]; + } + } + + set_joint_from_node (joints, + elbow_extrema, + SKELTRACK_JOINT_ID_RIGHT_ELBOW, + self->priv->dimension_reduction); + set_joint_from_node (joints, + hand_extrema, + SKELTRACK_JOINT_ID_RIGHT_HAND, + self->priv->dimension_reduction); + + g_slice_free1 (matrix_size * sizeof (Node *), previous_left_a); + g_slice_free1 (matrix_size * sizeof (Node *), previous_left_b); + g_slice_free1 (matrix_size * sizeof (Node *), previous_right_a); + g_slice_free1 (matrix_size * sizeof (Node *), previous_right_b); + + g_slice_free1 (matrix_size * sizeof (gint), dist_left_a); + g_slice_free1 (matrix_size * sizeof (gint), dist_left_b); + g_slice_free1 (matrix_size * sizeof (gint), dist_right_a); + g_slice_free1 (matrix_size * sizeof (gint), dist_right_b); +} + +static Node * +get_adjusted_shoulder (guint buffer_width, + guint buffer_height, + guint dimension_reduction, + GList *graph, + Node *centroid, + Node *head, + Node *shoulder) +{ + Node *virtual_shoulder, *adjusted_shoulder = NULL; + virtual_shoulder = g_slice_new (Node); + virtual_shoulder->x = shoulder->x; + virtual_shoulder->y = shoulder->y; + virtual_shoulder->z = centroid->z; + + convert_mm_to_screen_coords (buffer_width, + buffer_height, + dimension_reduction, + virtual_shoulder->x, + virtual_shoulder->y, + virtual_shoulder->z, + (guint *) &virtual_shoulder->i, + (guint *) &virtual_shoulder->j); + + adjusted_shoulder = get_closest_torso_node (graph, + virtual_shoulder, + head); + g_slice_free (Node, virtual_shoulder); + + return adjusted_shoulder; +} + +static SkeltrackJoint ** +track_joints (SkeltrackSkeleton *self) +{ + Node * centroid; + Node *head = NULL; + Node *right_shoulder = NULL; + Node *left_shoulder = NULL; + GList *extremas; + SkeltrackJointList joints = NULL; + SkeltrackJointList smoothed = NULL; + + self->priv->graph = make_graph (self, &self->priv->labels); + centroid = get_centroid (self); + extremas = get_extremas (self, centroid); + + if (g_list_length (extremas) > 2) + { + if (self->priv->previous_head) + { + gint distance; + gboolean can_be_head = FALSE; + head = get_closest_node_to_joint (extremas, + self->priv->previous_head, + &distance); + if (head != NULL && + distance < GRAPH_DISTANCE_THRESHOLD) + { + can_be_head = check_if_node_can_be_head (self, + head, + centroid, + &left_shoulder, + &right_shoulder); + } + + if (!can_be_head) + head = NULL; + } + + if (head == NULL) + { + get_head_and_shoulders (self, + extremas, + centroid, + &head, + &left_shoulder, + &right_shoulder); + } + + if (joints == NULL) + joints = skeltrack_joint_list_new (); + + set_joint_from_node (&joints, + head, + SKELTRACK_JOINT_ID_HEAD, + self->priv->dimension_reduction); + + if (left_shoulder && head && head->z > left_shoulder->z) + { + Node *adjusted_shoulder; + adjusted_shoulder = get_adjusted_shoulder (self->priv->buffer_width, + self->priv->buffer_height, + self->priv->dimension_reduction, + self->priv->graph, + centroid, + head, + left_shoulder); + + if (adjusted_shoulder) + left_shoulder = adjusted_shoulder; + } + + set_joint_from_node (&joints, + left_shoulder, + SKELTRACK_JOINT_ID_LEFT_SHOULDER, + self->priv->dimension_reduction); + + if (right_shoulder && head && head->z > right_shoulder->z) + { + Node *adjusted_shoulder; + adjusted_shoulder = get_adjusted_shoulder (self->priv->buffer_width, + self->priv->buffer_height, + self->priv->dimension_reduction, + self->priv->graph, + centroid, + head, + right_shoulder); + + if (adjusted_shoulder) + right_shoulder = adjusted_shoulder; + } + set_joint_from_node (&joints, + right_shoulder, + SKELTRACK_JOINT_ID_RIGHT_SHOULDER, + self->priv->dimension_reduction); + + set_left_and_right_from_extremas (self, + extremas, + head, + left_shoulder, + right_shoulder, + &joints); + } + + self->priv->buffer = NULL; + + self->priv->main_component = NULL; + + clean_nodes (self->priv->graph); + g_list_free (self->priv->graph); + self->priv->graph = NULL; + + clean_labels (self->priv->labels); + g_list_free (self->priv->labels); + self->priv->labels = NULL; + + if (self->priv->enable_smoothing) + { + smooth_joints (&self->priv->smooth_data, joints); + + if (self->priv->smooth_data.smoothed_joints != NULL) + { + guint i; + smoothed = skeltrack_joint_list_new (); + for (i = 0; i < SKELTRACK_JOINT_MAX_JOINTS; i++) + { + SkeltrackJoint *smoothed_joint, *smooth, *trend; + smoothed_joint = NULL; + smooth = self->priv->smooth_data.smoothed_joints[i]; + if (smooth != NULL) + { + if (self->priv->smooth_data.trend_joints != NULL) + { + trend = self->priv->smooth_data.trend_joints[i]; + if (trend != NULL) + { + smoothed_joint = g_slice_new0 (SkeltrackJoint); + smoothed_joint->x = smooth->x + trend->x; + smoothed_joint->y = smooth->y + trend->y; + smoothed_joint->z = smooth->z + trend->z; + smoothed_joint->screen_x = smooth->screen_x + trend->screen_x; + smoothed_joint->screen_y = smooth->screen_y + trend->screen_y; + } + else + smoothed_joint = skeltrack_joint_copy (smooth); + } + else + smoothed_joint = skeltrack_joint_copy (smooth); + } + smoothed[i] = smoothed_joint; + } + } + skeltrack_joint_list_free (joints); + + joints = smoothed; + } + + if (joints) + { + SkeltrackJoint *joint = skeltrack_joint_list_get_joint (joints, + SKELTRACK_JOINT_ID_HEAD); + if (joint != NULL) + { + skeltrack_joint_free (self->priv->previous_head); + self->priv->previous_head = skeltrack_joint_copy (joint); + } + } + + g_list_free (extremas); + + return joints; +} + +static void +clean_tracking_resources (SkeltrackSkeleton *self) +{ + g_slice_free1 (self->priv->buffer_width * + self->priv->buffer_height * sizeof (gint), + self->priv->distances_matrix); + self->priv->distances_matrix = NULL; + + g_slice_free1 (self->priv->buffer_width * + self->priv->buffer_height * sizeof (Node *), + self->priv->node_matrix); + self->priv->node_matrix = NULL; +} + +static void +track_joints_in_thread (GSimpleAsyncResult *res, + GObject *object, + GCancellable *cancellable) +{ + SkeltrackSkeleton *self = SKELTRACK_SKELETON (object); + SkeltrackJointList joints; + + joints = track_joints (self); + + g_mutex_lock (&self->priv->track_joints_mutex); + self->priv->track_joints_result = NULL; + g_mutex_unlock (&self->priv->track_joints_mutex); + + g_simple_async_result_set_op_res_gpointer (res, + joints, + NULL); + + g_object_unref (res); +} + +/* public methods */ + +/** + * skeltrack_skeleton_new: + * + * Constructs and returns a new #SkeltrackSkeleton instance. + * + * Returns: (transfer full): The newly created #SkeltrackSkeleton. + */ +SkeltrackSkeleton * +skeltrack_skeleton_new (void) +{ + return g_object_new (SKELTRACK_TYPE_SKELETON, NULL); +} + +/** + * skeltrack_skeleton_set_focus_point: + * @self: The #SkeltrackSkeleton + * @x: The x coordinate of the focus point. + * @y: The y coordinate of the focus point. + * @z: The z coordinate of the focus point. + * + * Gets the focus point which is the origin from where the tracking will + * start. The coordinates will be in mm. + * + **/ +void +skeltrack_skeleton_get_focus_point (SkeltrackSkeleton *self, + gint *x, + gint *y, + gint *z) +{ + *x = self->priv->focus_node->x; + *y = self->priv->focus_node->y; + *z = self->priv->focus_node->z; +} + +/** + * skeltrack_skeleton_set_focus_point: + * @self: The #SkeltrackSkeleton + * @x: The x coordinate of the focus point. + * @y: The y coordinate of the focus point. + * @z: The z coordinate of the focus point. + * + * Sets the focus point which is the origin from where the tracking will + * start. The coordinates should be in mm. + * + * If this method is not called the default values are @x = 0, @y = 0, + * @z = 1000, that is, in the center of the screen and at 1m from the + * camera. + * + **/ +void +skeltrack_skeleton_set_focus_point (SkeltrackSkeleton *self, + gint x, + gint y, + gint z) +{ + self->priv->focus_node->x = x; + self->priv->focus_node->y = y; + self->priv->focus_node->z = z; +} + +/** + * skeltrack_skeleton_track_joints: + * @self: The #SkeltrackSkeleton + * @buffer: The buffer containing the depth information, from which + * all the information will be retrieved. + * @width: The width of the @buffer + * @height: The height of the @buffer + * @cancellable: (allow-none): A cancellable object, or %NULL (currently + * unused) + * @callback: (scope async): The function to call when the it is finished + * tracking the joints + * @user_data: (allow-none): An arbitrary user data to pass in @callback, + * or %NULL + * + * Tracks the skeleton's joints. + * + * It uses the depth information contained in the given @buffer and tries to + * track the skeleton joints. The @buffer's depth values should be in mm. + * Use skeltrack_skeleton_track_joints_finish() to get a list of the joints + * found. + * + * If this method is called while a previous attempt of tracking the joints + * is still running, a %G_IO_ERROR_PENDING error occurs. + * + **/ +void +skeltrack_skeleton_track_joints (SkeltrackSkeleton *self, + guint16 *buffer, + guint width, + guint height, + GCancellable *cancellable, + GAsyncReadyCallback callback, + gpointer user_data) +{ + GSimpleAsyncResult *result = NULL; + + g_return_if_fail (SKELTRACK_IS_SKELETON (self) && + callback != NULL && + buffer != NULL); + + result = g_simple_async_result_new (G_OBJECT (self), + callback, + user_data, + skeltrack_skeleton_track_joints); + + if (self->priv->track_joints_result != NULL) + { + g_simple_async_result_set_error (result, + G_IO_ERROR, + G_IO_ERROR_PENDING, + "Currently tracking joints"); + g_simple_async_result_complete_in_idle (result); + g_object_unref (result); + return; + } + + g_mutex_lock (&self->priv->track_joints_mutex); + + self->priv->track_joints_result = G_ASYNC_RESULT (result); + + /* @TODO: Set the cancellable */ + + self->priv->buffer = buffer; + + if (self->priv->buffer_width != width || + self->priv->buffer_height != height) + { + clean_tracking_resources (self); + + self->priv->buffer_width = width; + self->priv->buffer_height = height; + } + + g_simple_async_result_run_in_thread (result, + track_joints_in_thread, + G_PRIORITY_DEFAULT, + cancellable); + + g_mutex_unlock (&self->priv->track_joints_mutex); +} + +/** + * skeltrack_skeleton_track_joints_finish: + * @self: The #SkeltrackSkeleton + * @result: The #GAsyncResult provided in the callback + * @error: (allow-none): A pointer to a #GError, or %NULL + * + * Gets the list of joints that were retrieved by a + * skeltrack_skeleton_track_joints() operation. + * + * Use skeltrack_joint_list_get_joint() with #SkeltrackJointId + * to get the respective joints from the list. + * Joints that could not be found will appear as %NULL in the list. + * + * The list should be freed using skeltrack_joint_list_free(). + * + * Returns: (transfer full): The #SkeltrackJointList with the joints found. + */ +SkeltrackJointList +skeltrack_skeleton_track_joints_finish (SkeltrackSkeleton *self, + GAsyncResult *result, + GError **error) +{ + GSimpleAsyncResult *res; + + g_return_val_if_fail (G_IS_SIMPLE_ASYNC_RESULT (result), NULL); + + res = G_SIMPLE_ASYNC_RESULT (result); + + if (! g_simple_async_result_propagate_error (res, error)) + { + SkeltrackJointList joints = NULL; + joints = g_simple_async_result_get_op_res_gpointer (res); + return joints; + } + else + return NULL; +} + +/** + * skeltrack_skeleton_track_joints_sync: + * @self: The #SkeltrackSkeleton + * @buffer: The buffer containing the depth information, from which + * all the information will be retrieved. + * @width: The width of the @buffer + * @height: The height of the @buffer + * @cancellable: (allow-none): A cancellable object, or %NULL (currently + * unused) + * @error: (allow-none): A pointer to a #GError, or %NULL + * + * Tracks the skeleton's joints synchronously. + * + * Does the same as skeltrack_skeleton_track_joints() but synchronously + * and returns the list of joints found. + * Ideal for off-line skeleton tracking. + * + * If this method is called while a previous attempt of asynchronously + * tracking the joints is still running, a %G_IO_ERROR_PENDING error occurs. + * + * The joints list should be freed using skeltrack_joint_list_free(). + * + * Returns: (transfer full): The #SkeltrackJointList with the joints found. + **/ +SkeltrackJointList +skeltrack_skeleton_track_joints_sync (SkeltrackSkeleton *self, + guint16 *buffer, + guint width, + guint height, + GCancellable *cancellable, + GError **error) +{ + g_return_val_if_fail (SKELTRACK_IS_SKELETON (self), NULL); + + if (self->priv->track_joints_result != NULL && error != NULL) + { + *error = g_error_new (G_IO_ERROR, + G_IO_ERROR_PENDING, + "Currently tracking joints"); + return NULL; + } + + self->priv->buffer = buffer; + + if (self->priv->buffer_width != width || + self->priv->buffer_height != height) + { + clean_tracking_resources (self); + + self->priv->buffer_width = width; + self->priv->buffer_height = height; + } + + return track_joints (self); +} diff --git a/interface/external/skeltrack/src/skeltrack-smooth.c b/interface/external/skeltrack/src/skeltrack-smooth.c new file mode 100644 index 0000000000..1e6658f578 --- /dev/null +++ b/interface/external/skeltrack/src/skeltrack-smooth.c @@ -0,0 +1,226 @@ +/* + * skeltrack-smooth.c + * + * Skeltrack - A Free Software skeleton tracking library + * Copyright (C) 2012 Igalia S.L. + * + * Authors: + * Joaquim Rocha + * Eduardo Lima Mitev + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 3 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License at http://www.gnu.org/licenses/lgpl-3.0.txt + * for more details. + */ + +#include + +#include "skeltrack-smooth.h" + +static gfloat +holt_double_exp_formula_st (gfloat alpha, + gfloat previous_trend, + gfloat current_value, + gfloat previous_smoothed_value) +{ + return alpha * current_value + + (1.0 - alpha) * (previous_smoothed_value + previous_trend); +} + +static gfloat +holt_double_exp_formula_bt (gfloat beta, + gfloat previous_trend, + gfloat current_smoothed_value, + gfloat previous_smoothed_value) +{ + return beta * (current_smoothed_value - previous_smoothed_value) + + (1.0 - beta) * previous_trend; +} + +static void +holt_double_exp_joint (gfloat alpha, + gfloat beta, + SkeltrackJoint *smoothed_joint, + SkeltrackJoint *current_joint, + SkeltrackJoint *trend_joint) +{ + gfloat new_x, new_y, new_z, new_screen_x, new_screen_y; + new_x = holt_double_exp_formula_st (alpha, + trend_joint->x, + current_joint->x, + smoothed_joint->x); + new_y = holt_double_exp_formula_st (alpha, + trend_joint->y, + current_joint->y, + smoothed_joint->y); + new_z = holt_double_exp_formula_st (alpha, + trend_joint->z, + current_joint->z, + smoothed_joint->z); + new_screen_x = holt_double_exp_formula_st (alpha, + trend_joint->screen_x, + current_joint->screen_x, + smoothed_joint->screen_x); + new_screen_y = holt_double_exp_formula_st (alpha, + trend_joint->screen_y, + current_joint->screen_y, + smoothed_joint->screen_y); + trend_joint->x = holt_double_exp_formula_bt (beta, + trend_joint->x, + new_x, + smoothed_joint->x); + trend_joint->y = holt_double_exp_formula_bt (beta, + trend_joint->y, + new_y, + smoothed_joint->y); + trend_joint->z = holt_double_exp_formula_bt (beta, + trend_joint->z, + new_z, + smoothed_joint->z); + trend_joint->screen_x = holt_double_exp_formula_bt (beta, + trend_joint->screen_x, + new_screen_x, + smoothed_joint->screen_x); + trend_joint->screen_y = holt_double_exp_formula_bt (beta, + trend_joint->screen_y, + new_screen_y, + smoothed_joint->screen_y); + smoothed_joint->x = new_x; + smoothed_joint->y = new_y; + smoothed_joint->z = new_z; + smoothed_joint->screen_x = new_screen_x; + smoothed_joint->screen_y = new_screen_y; +} + +void +reset_joints_persistency_counter (SmoothData *smooth_data) +{ + guint i; + for (i = 0; i < SKELTRACK_JOINT_MAX_JOINTS; i++) + { + smooth_data->joints_persistency_counter[i] = + smooth_data->joints_persistency; + } +} + +static void +decrease_joints_persistency (SmoothData *smooth_data) +{ + guint i; + for (i = 0; i < SKELTRACK_JOINT_MAX_JOINTS; i++) + { + SkeltrackJoint *smoothed_joint = NULL; + SkeltrackJoint *trend_joint = NULL; + + if (smooth_data->smoothed_joints) + smoothed_joint = smooth_data->smoothed_joints[i]; + if (smooth_data->trend_joints) + trend_joint = smooth_data->trend_joints[i]; + + if (smoothed_joint != NULL || trend_joint != NULL) + { + if (smooth_data->joints_persistency_counter[i] > 0) + smooth_data->joints_persistency_counter[i]--; + else + { + skeltrack_joint_free (smoothed_joint); + skeltrack_joint_free (trend_joint); + if (smoothed_joint) + smooth_data->smoothed_joints[i] = NULL; + if (trend_joint) + smooth_data->trend_joints[i] = NULL; + smooth_data->joints_persistency_counter[i] = smooth_data->joints_persistency; + } + } + } +} + +void +smooth_joints (SmoothData *data, + SkeltrackJointList new_joints) +{ + guint i; + + if (new_joints == NULL) + { + decrease_joints_persistency (data); + return; + } + + if (data->smoothed_joints == NULL) + { + data->smoothed_joints = skeltrack_joint_list_new (); + for (i = 0; i < SKELTRACK_JOINT_MAX_JOINTS; i++) + { + data->smoothed_joints[i] = skeltrack_joint_copy (new_joints[i]); + } + return; + } + if (data->trend_joints == NULL) + { + data->trend_joints = skeltrack_joint_list_new (); + } + + for (i = 0; i < SKELTRACK_JOINT_MAX_JOINTS; i++) + { + SkeltrackJoint *joint, *smoothed_joint, *trend_joint; + + smoothed_joint = data->smoothed_joints[i]; + trend_joint = data->trend_joints[i]; + joint = new_joints[i]; + if (joint == NULL) + { + if (smoothed_joint != NULL) + { + if (data->joints_persistency_counter[i] > 0) + data->joints_persistency_counter[i]--; + else + { + skeltrack_joint_free (smoothed_joint); + skeltrack_joint_free (trend_joint); + data->smoothed_joints[i] = NULL; + data->trend_joints[i] = NULL; + data->joints_persistency_counter[i] = data->joints_persistency; + } + } + continue; + } + data->joints_persistency_counter[i] = data->joints_persistency; + + if (smoothed_joint == NULL) + { + data->smoothed_joints[i] = skeltrack_joint_copy (joint); + continue; + } + + if (trend_joint == NULL) + { + /* First case (when there are only initial values) */ + trend_joint = g_slice_new0 (SkeltrackJoint); + trend_joint->x = joint->x - smoothed_joint->x; + trend_joint->y = joint->y - smoothed_joint->y; + trend_joint->z = joint->z - smoothed_joint->z; + trend_joint->screen_x = joint->screen_x - smoothed_joint->screen_x; + trend_joint->screen_y = joint->screen_y - smoothed_joint->screen_y; + data->trend_joints[i] = trend_joint; + } + else + { + /* @TODO: Check if we should give the control of each factor + independently (data-smoothing-factor and trend-smoothing-factor). + */ + holt_double_exp_joint (data->smoothing_factor, + data->smoothing_factor, + smoothed_joint, + joint, + trend_joint); + } + } +} diff --git a/interface/external/skeltrack/src/skeltrack-util.c b/interface/external/skeltrack/src/skeltrack-util.c new file mode 100644 index 0000000000..482f26069a --- /dev/null +++ b/interface/external/skeltrack/src/skeltrack-util.c @@ -0,0 +1,626 @@ +/* + * skeltrack-util.c + * + * Skeltrack - A Free Software skeleton tracking library + * Copyright (C) 2012 Igalia S.L. + * + * Authors: + * Joaquim Rocha + * Eduardo Lima Mitev + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 3 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License at http://www.gnu.org/licenses/lgpl-3.0.txt + * for more details. + */ + +#include + +#include "skeltrack-util.h" + +/* @TODO: Expose these to the user */ +static const gfloat SCALE_FACTOR = .0021; +static const gint MIN_DISTANCE = -10.0; + +static SkeltrackJoint * +node_to_joint (Node *node, SkeltrackJointId id, gint dimension_reduction) +{ + SkeltrackJoint *joint; + + if (node == NULL) + return NULL; + + joint = g_slice_new0 (SkeltrackJoint); + joint->id = id; + joint->x = node->x; + joint->y = node->y; + joint->z = node->z; + joint->screen_x = node->i * dimension_reduction; + joint->screen_y = node->j * dimension_reduction; + + return joint; +} + +static guint +get_distance_from_joint (Node *node, SkeltrackJoint *joint) +{ + guint dx, dy, dz; + dx = ABS (node->x - joint->x); + dy = ABS (node->y - joint->y); + dz = ABS (node->z - joint->z); + return sqrt (dx * dx + dy * dy + dz * dz); +} + +static void +unlink_node (Node *node) +{ + Node *neighbor; + GList *current_neighbor; + + for (current_neighbor = g_list_first (node->neighbors); + current_neighbor != NULL; + current_neighbor = g_list_next (current_neighbor)) + { + neighbor = (Node *) current_neighbor->data; + neighbor->neighbors = g_list_remove (neighbor->neighbors, node); + } + + for (current_neighbor = g_list_first (node->linked_nodes); + current_neighbor != NULL; + current_neighbor = g_list_next (current_neighbor)) + { + neighbor = (Node *) current_neighbor->data; + neighbor->linked_nodes = g_list_remove (neighbor->linked_nodes, node); + } + + g_list_free (node->neighbors); + g_list_free (node->linked_nodes); + node->neighbors = NULL; + node->linked_nodes = NULL; +} + +static Node * +get_closest_node_with_distances (GList *node_list, + Node *from, + guint x_dist, + guint y_dist, + guint z_dist, + gint *closest_node_dist) +{ + Node *closest = NULL; + gint distance = -1; + GList *current_node; + + /* @TODO: Replace this and use closest pair of points + algorithm and ensure O(n log n) instead of brute-force */ + + for (current_node = g_list_first (node_list); + current_node != NULL; + current_node = g_list_next (current_node)) + { + guint dx, dy, dz; + Node *node; + gint current_distance; + node = (Node *) current_node->data; + + dx = ABS (from->x - node->x); + dy = ABS (from->y - node->y); + dz = ABS (from->z - node->z); + + if (dx > x_dist || dy > y_dist || dz > z_dist) + continue; + + current_distance = sqrt (dx * dx + dy * dy + dz * dz); + if (closest == NULL || distance > current_distance) + { + closest = node; + distance = current_distance; + } + } + + *closest_node_dist = distance; + return closest; +} + +Node * +get_closest_node_to_joint (GList *extremas, + SkeltrackJoint *joint, + gint *distance) +{ + GList *current_node; + gint dist = -1; + Node *closest_node = NULL; + + for (current_node = g_list_first (extremas); + current_node != NULL; + current_node = g_list_next (current_node)) + { + guint current_dist; + Node *node = (Node *) current_node->data; + if (node == NULL) + continue; + + current_dist = get_distance_from_joint (node, joint); + if (dist == -1 || current_dist < dist) + { + closest_node = node; + dist = current_dist; + } + } + *distance = dist; + return closest_node; +} + +gint +get_distance (Node *a, Node *b) +{ + guint dx, dy, dz; + dx = ABS (a->x - b->x); + dy = ABS (a->y - b->y); + dz = ABS (a->z - b->z); + return sqrt (dx * dx + dy * dy + dz * dz); +} + +Node * +get_closest_torso_node (GList *node_list, Node *from, Node *head) +{ + Node *closest = NULL; + gint distance = -1; + GList *current_node; + + /* @TODO: Replace this and use closest pair of points + algorithm and ensure O(n log n) instead of brute-force */ + + for (current_node = g_list_first (node_list); + current_node != NULL; + current_node = g_list_next (current_node)) + { + Node *node; + gint current_distance; + node = (Node *) current_node->data; + if (node->z >= head->z && + node->y >= from->y) + { + current_distance = get_distance (node, from); + if (closest == NULL || current_distance < distance) + { + closest = node; + distance = current_distance; + } + } + } + return closest; +} + +Node * +get_closest_node (GList *node_list, Node *from) +{ + Node *closest = NULL; + gint distance = -1; + GList *current_node; + + /* @TODO: Replace this and use closest pair of points + algorithm and ensure O(n log n) instead of brute-force */ + + for (current_node = g_list_first (node_list); + current_node != NULL; + current_node = g_list_next (current_node)) + { + Node *node; + gint current_distance; + node = (Node *) current_node->data; + if (closest == NULL) + { + closest = node; + distance = get_distance (node, from); + continue; + } + current_distance = get_distance (node, from); + if (current_distance < distance) + { + closest = node; + distance = current_distance; + } + } + return closest; +} + +Label * +get_main_component (GList *node_list, Node *from, gdouble min_normalized_nr_nodes) +{ + Label *main_component = NULL; + gint distance = -1; + GList *current_node; + + for (current_node = g_list_first (node_list); + current_node != NULL; + current_node = g_list_next (current_node)) + { + Node *node; + Label *label; + gint current_distance; + node = (Node *) current_node->data; + label = node->label; + + if (main_component == NULL && + label->normalized_num_nodes > min_normalized_nr_nodes) + { + main_component = label; + distance = get_distance (node, from); + continue; + } + + current_distance = get_distance (node, from); + if (current_distance < distance && + label->normalized_num_nodes > min_normalized_nr_nodes) + { + main_component = label; + distance = current_distance; + } + } + + return main_component; +} + +Label * +label_find (Label *label) +{ + Label *parent; + + g_return_val_if_fail (label != NULL, NULL); + + parent = label->parent; + if (parent == label) + return parent; + else + return label_find (parent); +} + +void +label_union (Label *a, Label *b) +{ + Label *root_a, *root_b; + root_a = label_find (a); + root_b = label_find (b); + if (root_a->index < root_b->index) + { + b->parent = root_a; + } + else + { + a->parent = root_b; + } +} + +void +free_label (Label *label) +{ + g_list_free (label->nodes); + label->nodes = NULL; + g_slice_free (Label, label); +} + +void +clean_labels (GList *labels) +{ + GList *current = g_list_first (labels); + while (current != NULL) + { + Label *label; + label = (Label *) current->data; + free_label (label); + current = g_list_next (current); + } +} + +void +free_node (Node *node, gboolean unlink_node_first) +{ + if (unlink_node_first) + { + unlink_node (node); + } + else + { + g_list_free (node->neighbors); + g_list_free (node->linked_nodes); + node->neighbors = NULL; + node->linked_nodes = NULL; + } + g_slice_free (Node, node); +} + +void +clean_nodes (GList *nodes) +{ + GList *current = g_list_first (nodes); + while (current != NULL) + { + Node *node; + node = (Node *) current->data; + free_node (node, FALSE); + current = g_list_next (current); + } +} + +GList * +remove_nodes_with_label (GList *nodes, + Node **node_matrix, + gint width, + Label *label) +{ + Node *node; + GList *link_to_delete, *current_node; + + current_node = g_list_first (nodes); + while (current_node != NULL) + { + node = (Node *) current_node->data; + if (node->label == label) + { + link_to_delete = current_node; + current_node = g_list_next (current_node); + nodes = g_list_delete_link (nodes, link_to_delete); + node_matrix[width * node->j + node->i] = NULL; + free_node (node, TRUE); + continue; + } + current_node = g_list_next (current_node); + } + return nodes; +} + +Label * +get_lowest_index_label (Label **neighbor_labels) +{ + guint index; + Label *lowest_index_label = NULL; + + lowest_index_label = neighbor_labels[0]; + for (index = 1; index < 4; index++) + { + if (neighbor_labels[index] == NULL) + continue; + + if (lowest_index_label == NULL || + lowest_index_label->index < neighbor_labels[index]->index) + { + lowest_index_label = neighbor_labels[index]; + } + } + + return lowest_index_label; +} + +Label * +new_label (gint index) +{ + Label *label = g_slice_new (Label); + label->index = index; + label->parent = label; + label->nodes = NULL; + label->bridge_node = NULL; + label->to_node = NULL; + label->lower_screen_y = -1; + label->higher_z = -1; + label->lower_z = -1; + label->normalized_num_nodes = -1; + + return label; +} + +void +join_components_to_main (GList *labels, + Label *main_component_label, + guint horizontal_max_distance, + guint depth_max_distance, + guint graph_distance_threshold) +{ + GList *current_label; + + for (current_label = g_list_first (labels); + current_label != NULL; + current_label = g_list_next (current_label)) + { + gint closer_distance = -1; + Label *label; + GList *current_node, *nodes; + + label = (Label *) current_label->data; + if (label == main_component_label) + continue; + + /* Skip nodes behind main component */ + if (label->higher_z > main_component_label->higher_z + + graph_distance_threshold) + continue; + + nodes = label->nodes; + for (current_node = g_list_first (nodes); + current_node != NULL; + current_node = g_list_next (current_node)) + { + Node *node; + gint current_distance; + node = (Node *) current_node->data; + /* Skip nodes that belong to the same component or + that a not in the edge of their component */ + if (g_list_length (node->neighbors) == 8) + continue; + + Node *closest_node = + get_closest_node_with_distances (main_component_label->nodes, + node, + horizontal_max_distance, + horizontal_max_distance, + depth_max_distance, + ¤t_distance); + if (closest_node && + (current_distance < closer_distance || + closer_distance == -1)) + { + node->label->bridge_node = node; + node->label->to_node = closest_node; + closer_distance = current_distance; + } + } + } +} + +void +set_joint_from_node (SkeltrackJointList *joints, + Node *node, + SkeltrackJointId id, + gint dimension_reduction) +{ + (*joints)[id] = node_to_joint (node, id, dimension_reduction); +} + +gint * +create_new_dist_matrix (gint matrix_size) +{ + guint i; + gint *distances; + + distances = g_slice_alloc0 (matrix_size * sizeof (gint)); + for (i = 0; i < matrix_size; i++) + { + distances[i] = -1; + } + + return distances; +} + +gboolean +dijkstra_to (GList *nodes, Node *source, Node *target, + gint width, gint height, + gint *distances, Node **previous) +{ + gint nr; + GList *unvisited_nodes, *current; + + for (current = g_list_first (nodes); + previous != NULL && current != NULL; + current = g_list_next (current)) + { + Node *node; + node = (Node *) current->data; + previous[node->j * width + node->i] = NULL; + } + distances[source->j * width + source->i] = 0; + + unvisited_nodes = g_list_copy (nodes); + nr = 0; + while (unvisited_nodes != NULL) + { + Node *node; + GList *current_neighbor, *shorter_dist_node, *cur_node; + + shorter_dist_node = g_list_first (unvisited_nodes); + cur_node = g_list_next (shorter_dist_node); + while (cur_node != NULL) + { + Node *value, *shorter_dist; + value = (Node *) cur_node->data; + shorter_dist = (Node *) shorter_dist_node->data; + if (distances[shorter_dist->j * width + shorter_dist->i] == -1 || + (distances[value->j * width + value->i] != -1 && + distances[value->j * width + + value->i] < distances[shorter_dist->j * width + + shorter_dist->i])) + { + shorter_dist_node = cur_node; + } + cur_node = g_list_next (cur_node); + } + + node = (Node *) shorter_dist_node->data; + if (distances[node->j * width + node->i] == -1) + { + break; + } + + current_neighbor = g_list_first (node->neighbors); + while (current_neighbor) + { + gint dist; + Node *neighbor; + + neighbor = (Node *) current_neighbor->data; + dist = get_distance (node, neighbor) + + distances[node->j * width + node->i]; + + if (distances[neighbor->j * width + neighbor->i] == -1 || + dist < distances[neighbor->j * width + neighbor->i]) + { + distances[neighbor->j * width + neighbor->i] = dist; + if (previous != NULL) + { + previous[neighbor->j * width + neighbor->i] = node; + } + nr++; + } + if (target != NULL && neighbor == target) + { + g_list_free (unvisited_nodes); + return TRUE; + } + + current_neighbor = g_list_next (current_neighbor); + } + unvisited_nodes = g_list_delete_link (unvisited_nodes, shorter_dist_node); + } + g_list_free (unvisited_nodes); + return FALSE; +} + +void +convert_screen_coords_to_mm (guint width, + guint height, + guint dimension_reduction, + guint i, + guint j, + gint z, + gint *x, + gint *y) +{ + gfloat width_height_relation = + width > height ? (gfloat) width / height : (gfloat) height / width; + /* Formula from http://openkinect.org/wiki/Imaging_Information */ + *x = round((i * dimension_reduction - width * dimension_reduction / 2.0) * + (z + MIN_DISTANCE) * SCALE_FACTOR * width_height_relation); + *y = round((j * dimension_reduction - height * dimension_reduction / 2.0) * + (z + MIN_DISTANCE) * SCALE_FACTOR); +} + +void +convert_mm_to_screen_coords (guint width, + guint height, + guint dimension_reduction, + gint x, + gint y, + gint z, + guint *i, + guint *j) +{ + gfloat width_height_relation = + width > height ? (gfloat) width / height : (gfloat) height / width; + + if (z + MIN_DISTANCE == 0) + { + *i = 0; + *j = 0; + return; + } + + *i = round (width / 2.0 + x / ((gfloat) (z + MIN_DISTANCE) * SCALE_FACTOR * + dimension_reduction * width_height_relation)); + *j = round (height / 2.0 + y / ((gfloat) (z + MIN_DISTANCE) * SCALE_FACTOR * + dimension_reduction)); +} diff --git a/interface/src/Webcam.cpp b/interface/src/Webcam.cpp index 586e806ce3..f01b9a5804 100644 --- a/interface/src/Webcam.cpp +++ b/interface/src/Webcam.cpp @@ -176,11 +176,15 @@ void Webcam::setFrame(const Mat& frame, const RotatedRect& faceRect) { QTimer::singleShot(qMax((int)remaining / 1000, 0), _grabber, SLOT(grabFrame())); } -FrameGrabber::FrameGrabber() : _capture(0), _searchWindow(0, 0, 0, 0) { +FrameGrabber::FrameGrabber() : _capture(0), _searchWindow(0, 0, 0, 0), _freenectContext(0) { } FrameGrabber::~FrameGrabber() { - if (_capture != 0) { + if (_freenectContext != 0) { + freenect_close_device(_freenectDevice); + freenect_shutdown(_freenectContext); + + } else if (_capture != 0) { cvReleaseCapture(&_capture); } } @@ -190,32 +194,14 @@ void FrameGrabber::reset() { } void FrameGrabber::grabFrame() { - if (_capture == 0) { - if ((_capture = cvCaptureFromCAM(-1)) == 0) { - printLog("Failed to open webcam.\n"); - return; - } - const int IDEAL_FRAME_WIDTH = 320; - const int IDEAL_FRAME_HEIGHT = 240; - cvSetCaptureProperty(_capture, CV_CAP_PROP_FRAME_WIDTH, IDEAL_FRAME_WIDTH); - cvSetCaptureProperty(_capture, CV_CAP_PROP_FRAME_HEIGHT, IDEAL_FRAME_HEIGHT); - -#ifdef __APPLE__ - configureCamera(0x5ac, 0x8510, false, 0.975, 0.5, 1.0, 0.5, true, 0.5); -#else - cvSetCaptureProperty(_capture, CV_CAP_PROP_EXPOSURE, 0.5); - cvSetCaptureProperty(_capture, CV_CAP_PROP_CONTRAST, 0.5); - cvSetCaptureProperty(_capture, CV_CAP_PROP_SATURATION, 0.5); - cvSetCaptureProperty(_capture, CV_CAP_PROP_BRIGHTNESS, 0.5); - cvSetCaptureProperty(_capture, CV_CAP_PROP_HUE, 0.5); - cvSetCaptureProperty(_capture, CV_CAP_PROP_GAIN, 0.5); -#endif - - switchToResourcesParentIfRequired(); - if (!_faceCascade.load("resources/haarcascades/haarcascade_frontalface_alt.xml")) { - printLog("Failed to load Haar cascade for face tracking.\n"); - } + if (_capture == 0 && _freenectContext == 0 && !init()) { + return; } + if (_freenectContext != 0) { + + return; + } + IplImage* image = cvQueryFrame(_capture); if (image == 0) { // try again later @@ -264,6 +250,47 @@ void FrameGrabber::grabFrame() { Q_ARG(cv::Mat, frame), Q_ARG(cv::RotatedRect, faceRect)); } +bool FrameGrabber::init() { + // first try for a Kinect + if (freenect_init(&_freenectContext, 0) >= 0) { + if (freenect_num_devices(_freenectContext) > 0) { + if (freenect_open_device(_freenectContext, &_freenectDevice, 0) >= 0) { + return true; + } + } + freenect_shutdown(_freenectContext); + _freenectContext = 0; + } + + // next, an ordinary webcam + if ((_capture = cvCaptureFromCAM(-1)) == 0) { + printLog("Failed to open webcam.\n"); + return false; + } + const int IDEAL_FRAME_WIDTH = 320; + const int IDEAL_FRAME_HEIGHT = 240; + cvSetCaptureProperty(_capture, CV_CAP_PROP_FRAME_WIDTH, IDEAL_FRAME_WIDTH); + cvSetCaptureProperty(_capture, CV_CAP_PROP_FRAME_HEIGHT, IDEAL_FRAME_HEIGHT); + +#ifdef __APPLE__ + configureCamera(0x5ac, 0x8510, false, 0.975, 0.5, 1.0, 0.5, true, 0.5); +#else + cvSetCaptureProperty(_capture, CV_CAP_PROP_EXPOSURE, 0.5); + cvSetCaptureProperty(_capture, CV_CAP_PROP_CONTRAST, 0.5); + cvSetCaptureProperty(_capture, CV_CAP_PROP_SATURATION, 0.5); + cvSetCaptureProperty(_capture, CV_CAP_PROP_BRIGHTNESS, 0.5); + cvSetCaptureProperty(_capture, CV_CAP_PROP_HUE, 0.5); + cvSetCaptureProperty(_capture, CV_CAP_PROP_GAIN, 0.5); +#endif + + switchToResourcesParentIfRequired(); + if (!_faceCascade.load("resources/haarcascades/haarcascade_frontalface_alt.xml")) { + printLog("Failed to load Haar cascade for face tracking.\n"); + return false; + } + return true; +} + void FrameGrabber::updateHSVFrame(const Mat& frame) { cvtColor(frame, _hsvFrame, CV_BGR2HSV); inRange(_hsvFrame, Scalar(0, 55, 65), Scalar(180, 256, 256), _mask); diff --git a/interface/src/Webcam.h b/interface/src/Webcam.h index 4bf6dea53e..59110d35a2 100644 --- a/interface/src/Webcam.h +++ b/interface/src/Webcam.h @@ -15,6 +15,8 @@ #include +#include + #include #include "InterfaceConfig.h" @@ -82,6 +84,7 @@ public slots: private: + bool init(); void updateHSVFrame(const cv::Mat& frame); CvCapture* _capture; @@ -91,6 +94,9 @@ private: cv::SparseMat _histogram; cv::Mat _backProject; cv::Rect _searchWindow; + + freenect_context* _freenectContext; + freenect_device* _freenectDevice; }; Q_DECLARE_METATYPE(cv::Mat)