Compare commits

..

No commits in common. "6926ca81991a9f3c7f8d614631934fdf0d929ec8" and "17285389e35ae02b1de6785a6912c45ac93081cf" have entirely different histories.

111 changed files with 15242 additions and 684 deletions

View File

@ -67,7 +67,7 @@ unit_test windows/x86:
script:
- apt update -y
- apt upgrade -y
- apt install -y g++ ninja-build cmake libpcap-dev git
- apt install -y g++ ninja-build cmake libusb-1.0-0-dev libpcap-dev git
- sh ci/build-posix.sh
artifacts:
when: always
@ -82,7 +82,7 @@ unit_test windows/x86:
script:
- apt update -y
- apt upgrade -y
- apt install -y libpcap-dev
- apt install -y libusb-1.0-0-dev libpcap-dev
- build/libicsneo-unit-tests
tags:
- linux-build
@ -93,7 +93,7 @@ unit_test windows/x86:
script:
- apt update -y
- apt upgrade -y
- apt install -y clang lld ninja-build cmake libpcap-dev git
- apt install -y clang lld ninja-build cmake libusb-1.0-0-dev libpcap-dev git
- CC=clang CXX=clang++ LDFLAGS=-fuse-ld=lld sh ci/build-posix.sh
artifacts:
when: always
@ -108,12 +108,36 @@ unit_test windows/x86:
script:
- apt update -y
- apt upgrade -y
- apt install -y libpcap-dev
- apt install -y libusb-1.0-0-dev libpcap-dev
- build/libicsneo-unit-tests
tags:
- linux-build
timeout: 5m
build linux/ubuntu/2004/amd64/gcc:
<<: *build_linux_ubuntu_gcc
image: ubuntu:20.04
unit_test linux/ubuntu/2004/amd64/gcc:
<<: *test_linux_ubuntu_gcc
image: ubuntu:20.04
dependencies:
- build linux/ubuntu/2004/amd64/gcc
needs:
- build linux/ubuntu/2004/amd64/gcc
build linux/ubuntu/2004/amd64/clang:
<<: *build_linux_ubuntu_clang
image: ubuntu:20.04
unit_test linux/ubuntu/2004/amd64/clang:
<<: *test_linux_ubuntu_clang
image: ubuntu:20.04
dependencies:
- build linux/ubuntu/2004/amd64/clang
needs:
- build linux/ubuntu/2004/amd64/clang
build linux/ubuntu/2204/amd64/gcc:
<<: *build_linux_ubuntu_gcc
image: ubuntu:22.04
@ -138,30 +162,6 @@ unit_test linux/ubuntu/2204/amd64/clang:
needs:
- build linux/ubuntu/2204/amd64/clang
build linux/ubuntu/2404/amd64/gcc:
<<: *build_linux_ubuntu_gcc
image: ubuntu:24.04
unit_test linux/ubuntu/2404/amd64/gcc:
<<: *test_linux_ubuntu_gcc
image: ubuntu:24.04
dependencies:
- build linux/ubuntu/2404/amd64/gcc
needs:
- build linux/ubuntu/2404/amd64/gcc
build linux/ubuntu/2404/amd64/clang:
<<: *build_linux_ubuntu_clang
image: ubuntu:24.04
unit_test linux/ubuntu/2404/amd64/clang:
<<: *test_linux_ubuntu_clang
image: ubuntu:24.04
dependencies:
- build linux/ubuntu/2404/amd64/clang
needs:
- build linux/ubuntu/2404/amd64/clang
#-------------------------------------------------------------------------------
# Fedora
#-------------------------------------------------------------------------------
@ -175,7 +175,7 @@ unit_test linux/ubuntu/2404/amd64/clang:
- echo max_parallel_downloads=10 >>/etc/dnf/dnf.conf
- echo fastestmirror=True >>/etc/dnf/dnf.conf
- dnf upgrade -y
- dnf install -y g++ libpcap-devel cmake ninja-build git
- dnf install -y g++ libpcap-devel cmake ninja-build libusb1-devel git
- sh ci/build-posix.sh
artifacts:
when: always
@ -194,7 +194,7 @@ unit_test linux/ubuntu/2404/amd64/clang:
- echo max_parallel_downloads=10 >>/etc/dnf/dnf.conf
- echo fastestmirror=True >>/etc/dnf/dnf.conf
- dnf upgrade -y
- dnf install -y libpcap-devel
- dnf install -y libpcap-devel libusb1-devel
- build/libicsneo-unit-tests
tags:
- linux-build
@ -209,7 +209,7 @@ unit_test linux/ubuntu/2404/amd64/clang:
- echo max_parallel_downloads=10 >>/etc/dnf/dnf.conf
- echo fastestmirror=True >>/etc/dnf/dnf.conf
- dnf upgrade -y
- dnf install -y clang lld libpcap-devel cmake ninja-build git
- dnf install -y clang lld libpcap-devel cmake ninja-build libusb1-devel git
- CC=clang CXX=clang++ LDFLAGS=-fuse-ld=lld sh ci/build-posix.sh
artifacts:
when: always
@ -228,12 +228,60 @@ unit_test linux/ubuntu/2404/amd64/clang:
- echo max_parallel_downloads=10 >>/etc/dnf/dnf.conf
- echo fastestmirror=True >>/etc/dnf/dnf.conf
- dnf upgrade -y
- dnf install -y libpcap-devel
- dnf install -y libpcap-devel libusb1-devel
- build/libicsneo-unit-tests
tags:
- linux-build
timeout: 5m
build linux/fedora/39/amd64/gcc:
<<: *build_linux_fedora_gcc
image: fedora:39
unit_test linux/fedora/39/amd64/gcc:
<<: *test_linux_fedora_gcc
image: fedora:39
dependencies:
- build linux/fedora/39/amd64/gcc
needs:
- build linux/fedora/39/amd64/gcc
build linux/fedora/39/amd64/clang:
<<: *build_linux_fedora_clang
image: fedora:39
unit_test linux/fedora/39/amd64/clang:
<<: *test_linux_fedora_clang
image: fedora:39
dependencies:
- build linux/fedora/39/amd64/clang
needs:
- build linux/fedora/39/amd64/clang
build linux/fedora/40/amd64/gcc:
<<: *build_linux_fedora_gcc
image: fedora:40
unit_test linux/fedora/40/amd64/gcc:
<<: *test_linux_fedora_gcc
image: fedora:40
dependencies:
- build linux/fedora/40/amd64/gcc
needs:
- build linux/fedora/40/amd64/gcc
build linux/fedora/40/amd64/clang:
<<: *build_linux_fedora_clang
image: fedora:40
unit_test linux/fedora/40/amd64/clang:
<<: *test_linux_fedora_clang
image: fedora:40
dependencies:
- build linux/fedora/40/amd64/clang
needs:
- build linux/fedora/40/amd64/clang
build linux/fedora/41/amd64/gcc:
<<: *build_linux_fedora_gcc
image: fedora:41
@ -258,30 +306,6 @@ unit_test linux/fedora/41/amd64/clang:
needs:
- build linux/fedora/41/amd64/clang
build linux/fedora/42/amd64/gcc:
<<: *build_linux_fedora_gcc
image: fedora:42
unit_test linux/fedora/42/amd64/gcc:
<<: *test_linux_fedora_gcc
image: fedora:42
dependencies:
- build linux/fedora/42/amd64/gcc
needs:
- build linux/fedora/42/amd64/gcc
build linux/fedora/42/amd64/clang:
<<: *build_linux_fedora_clang
image: fedora:42
unit_test linux/fedora/42/amd64/clang:
<<: *test_linux_fedora_clang
image: fedora:42
dependencies:
- build linux/fedora/42/amd64/clang
needs:
- build linux/fedora/42/amd64/clang
#-------------------------------------------------------------------------------
# Python Module
#-------------------------------------------------------------------------------
@ -290,19 +314,19 @@ build python/linux/amd64:
stage: build
tags:
- linux-build
image: python:3.13
image: python:3.12
services:
- name: docker:dind
entrypoint: ["env", "-u", "DOCKER_HOST"]
command: ["dockerd-entrypoint.sh"]
variables:
CIBW_BEFORE_ALL: yum install -y flex && sh ci/bootstrap-libpcap.sh
CIBW_BEFORE_ALL: yum install -y flex && sh ci/bootstrap-libpcap.sh && sh ci/bootstrap-libusb.sh
CIBW_BUILD: "*manylinux*" # no musl
CIBW_ARCHS: x86_64
DOCKER_HOST: unix:///var/run/docker.sock
DOCKER_DRIVER: overlay2
DOCKER_TLS_CERTDIR: ""
CIBW_ENVIRONMENT: CMAKE_PREFIX_PATH=/project/libpcap/install
CIBW_ENVIRONMENT: CMAKE_PREFIX_PATH=/project/libpcap/install:/project/libusb/install
script:
- curl -sSL https://get.docker.com/ | sh
- sh ci/build-wheel-posix.sh
@ -315,10 +339,10 @@ build python/linux/arm64:
tags:
- arm64-linux-build
variables:
CIBW_BEFORE_ALL: yum install -y flex && sh ci/bootstrap-libpcap.sh
CIBW_BEFORE_ALL: yum install -y flex && sh ci/bootstrap-libpcap.sh && sh ci/bootstrap-libusb.sh
CIBW_BUILD: "*manylinux*" # no musl
CIBW_ARCHS: aarch64
CIBW_ENVIRONMENT: CMAKE_PREFIX_PATH=/project/libpcap/install
CIBW_ENVIRONMENT: CMAKE_PREFIX_PATH=/project/libpcap/install:/project/libusb/install
script:
- sh ci/build-wheel-posix.sh
artifacts:
@ -330,9 +354,9 @@ build python/macos:
tags:
- macos-arm64
variables:
CIBW_BEFORE_ALL: sh ci/bootstrap-libpcap.sh
CIBW_BEFORE_ALL: sh ci/bootstrap-libpcap.sh && sh ci/bootstrap-libusb.sh
CIBW_ARCHS: arm64
CIBW_ENVIRONMENT: CMAKE_PREFIX_PATH=$CI_PROJECT_DIR/libpcap/install
CIBW_ENVIRONMENT: CMAKE_PREFIX_PATH=$CI_PROJECT_DIR/libpcap/install:$CI_PROJECT_DIR/libusb/install
MACOSX_DEPLOYMENT_TARGET: 10.14
script:
- sh ci/build-wheel-posix.sh
@ -360,7 +384,7 @@ deploy python/pypi:
TWINE_PASSWORD: $PYPI_TOKEN
tags:
- linux-build
image: python:3.13
image: python:3.12
rules:
- if: $CI_COMMIT_BRANCH == $CI_DEFAULT_BRANCH
script:

View File

@ -22,8 +22,9 @@ set(LIBICSNEO_NPCAP_INCLUDE_DIR "" CACHE STRING "Npcap include directory; set to
option(LIBICSNEO_ENABLE_FIRMIO "Enable communication between Linux and CoreMini within the same device" OFF)
option(LIBICSNEO_ENABLE_RAW_ETHERNET "Enable devices which communicate over raw ethernet" ON)
option(LIBICSNEO_ENABLE_CDCACM "Enable devices which communicate over USB CDC ACM" ON)
option(LIBICSNEO_ENABLE_FTDI "Enable devices which communicate over USB FTDI2XX" ON)
option(LIBICSNEO_ENABLE_TCP "Enable devices which communicate over TCP" OFF)
option(LIBICSNEO_ENABLE_DXX "Enable devices which communicate over D2XX/D3XX via libredxx" ON)
option(LIBICSNEO_ENABLE_FTD3XX "Enable devices which communicate over USB FTD3XX" ON)
option(LIBICSNEO_ENABLE_BINDINGS_PYTHON "Enable Python library" OFF)
@ -108,6 +109,7 @@ if(LIBICSNEO_BUILD_DOCS)
endif()
if(WIN32)
add_definitions(-DWIN32_LEAN_AND_MEAN -DNOMINMAX -D_CRT_SECURE_NO_WARNINGS)
set(PLATFORM_SRC
platform/windows/strings.cpp
platform/windows/registry.cpp
@ -120,9 +122,9 @@ if(WIN32)
)
endif()
if(LIBICSNEO_ENABLE_CDCACM)
if(LIBICSNEO_ENABLE_CDCACM OR LIBICSNEO_ENABLE_FTDI)
list(APPEND PLATFORM_SRC
platform/windows/cdcacm.cpp
platform/windows/vcp.cpp
)
endif()
else() # Darwin or Linux
@ -140,6 +142,12 @@ else() # Darwin or Linux
)
endif()
if(LIBICSNEO_ENABLE_FTDI)
list(APPEND PLATFORM_SRC
platform/posix/ftdi.cpp
)
endif()
if(LIBICSNEO_ENABLE_CDCACM)
list(APPEND PLATFORM_SRC
platform/posix/cdcacm.cpp
@ -163,9 +171,51 @@ else() # Darwin or Linux
endif()
endif()
if(LIBICSNEO_ENABLE_DXX)
if(LIBICSNEO_ENABLE_FTD3XX)
if(NOT FTD3XX_ROOT) # allow system override
include(FetchContent)
if(WIN32 AND CMAKE_SIZEOF_VOID_P EQUAL 8)
set(LIBICSNEO_FTD3XX_URL "https://github.com/intrepidcs/libftd3xx-repack/releases/download/24.34.0/libftd3xx-1.3.0.10-win-x64.zip")
set(LIBICSNEO_FTD3XX_URL_HASH "SHA256=459e635496ab47d6069c9d3515fdd6d82cba3d95e7ae34f794d66ffdf336e9d1")
elseif(WIN32 AND CMAKE_SIZEOF_VOID_P EQUAL 4)
set(LIBICSNEO_FTD3XX_URL "https://github.com/intrepidcs/libftd3xx-repack/releases/download/24.34.0/libftd3xx-1.3.0.10-win-i686.zip")
set(LIBICSNEO_FTD3XX_URL_HASH "SHA256=ce4259ae11772d6ede7d217172156fa392f329b29d9455131f4126a2fb89dad1")
elseif(APPLE AND CMAKE_SIZEOF_VOID_P EQUAL 8)
set(LIBICSNEO_FTD3XX_URL "https://github.com/intrepidcs/libftd3xx-repack/releases/download/24.34.0/libftd3xx-1.0.16-macos-universal2.zip")
set(LIBICSNEO_FTD3XX_URL_HASH "SHA256=0904ac5eda8e1dc4b5aac3714383bcc7792b42dfeb585dce6cbfb8b67b8c0c51")
elseif(UNIX)
if(CMAKE_SYSTEM_PROCESSOR MATCHES "x86_64|amd64|AMD64")
if(CMAKE_SIZEOF_VOID_P EQUAL 8)
set(LIBICSNEO_FTD3XX_URL "https://github.com/intrepidcs/libftd3xx-repack/releases/download/24.34.0/libftd3xx-1.0.16-linux-x64.zip")
set(LIBICSNEO_FTD3XX_URL_HASH "SHA256=cf66bf299fc722f050cdd3c36998a670f1df69f7c0df18afa73707277067114b")
endif()
elseif(CMAKE_SYSTEM_PROCESSOR MATCHES "arm.*|aarch64")
if(CMAKE_SIZEOF_VOID_P EQUAL 8)
set(LIBICSNEO_FTD3XX_URL "https://github.com/intrepidcs/libftd3xx-repack/releases/download/24.34.0/libftd3xx-1.0.16-linux-aarch64.zip")
set(LIBICSNEO_FTD3XX_URL_HASH "SHA256=66341b5112b9841e959e81400b51711be96fec91894477c5cbfc29b10a0c00a6")
elseif(CMAKE_SIZEOF_VOID_P EQUAL 4)
set(LIBICSNEO_FTD3XX_URL "https://github.com/intrepidcs/libftd3xx-repack/releases/download/24.34.0/libftd3xx-1.0.16-linux-armhf.zip")
set(LIBICSNEO_FTD3XX_URL_HASH "SHA256=cec1f959b48a11eb6b829ed43c81b6ba1c0bcf3e797bafcc84a6376e5ffc3c47")
endif()
endif()
endif()
if(NOT LIBICSNEO_FTD3XX_URL)
message(FATAL_ERROR "Unsupported platform for FTD3XX driver")
endif()
FetchContent_Declare(
ftdi3xx
URL ${LIBICSNEO_FTD3XX_URL}
URL_HASH ${LIBICSNEO_FTD3XX_URL_HASH}
)
FetchContent_GetProperties(ftdi3xx)
if(NOT ftdi3xx_POPULATED)
FetchContent_Populate(ftdi3xx)
endif()
set(FTD3XX_ROOT "${ftdi3xx_SOURCE_DIR}")
endif()
find_package(FTD3XX REQUIRED)
list(APPEND PLATFORM_SRC
platform/dxx.cpp
platform/ftd3xx.cpp
)
endif()
@ -334,9 +384,12 @@ endif()
if(LIBICSNEO_ENABLE_CDCACM)
target_compile_definitions(icsneocpp PRIVATE ICSNEO_ENABLE_CDCACM)
endif()
if(LIBICSNEO_ENABLE_DXX)
target_compile_definitions(icsneocpp PRIVATE ICSNEO_ENABLE_DXX)
target_link_libraries(icsneocpp PRIVATE libredxx::libredxx)
if(LIBICSNEO_ENABLE_FTDI)
target_compile_definitions(icsneocpp PRIVATE ICSNEO_ENABLE_FTDI)
endif()
if(LIBICSNEO_ENABLE_FTD3XX)
target_compile_definitions(icsneocpp PRIVATE ICSNEO_ENABLE_FTD3XX)
target_link_libraries(icsneocpp PRIVATE FTD3XX::FTD3XX)
endif()
if(LIBICSNEO_ENABLE_TCP)
target_compile_definitions(icsneocpp PRIVATE ICSNEO_ENABLE_TCP)
@ -350,15 +403,25 @@ add_subdirectory(third-party/fatfs)
set_property(TARGET fatfs PROPERTY POSITION_INDEPENDENT_CODE ON)
target_link_libraries(icsneocpp PRIVATE fatfs)
# dxx
if(LIBICSNEO_ENABLE_DXX)
include(FetchContent)
FetchContent_Declare(libredxx
GIT_REPOSITORY https://github.com/Zeranoe/libredxx.git
GIT_TAG 2b7932fe7f2fc006ef269c7a72595f3940178a10
)
FetchContent_MakeAvailable(libredxx)
endif()
# libftdi
if(LIBICSNEO_ENABLE_FTDI)
if(NOT WIN32)
target_include_directories(icsneocpp PUBLIC third-party/libftdi/src)
set(LIBFTDI_DOCUMENTATION OFF CACHE INTERNAL "")
set(LIBFTDI_BUILD_TESTS OFF CACHE INTERNAL "")
set(LIBFTDI_INSTALL OFF CACHE INTERNAL "")
set(LIBFTDI_PYTHON_BINDINGS OFF CACHE INTERNAL "")
set(LIBFTDI_LINK_PYTHON_LIBRARY OFF CACHE INTERNAL "")
set(FTDIPP OFF CACHE INTERNAL "")
set(FTDI_EEPROM OFF CACHE INTERNAL "")
add_subdirectory(third-party/libftdi)
target_include_directories(icsneocpp PRIVATE ${LIBUSB_INCLUDE_DIR})
set_property(TARGET ftdi1-static PROPERTY POSITION_INDEPENDENT_CODE ON)
target_link_libraries(icsneocpp PUBLIC ftdi1-static)
target_link_libraries(icsneocpp PUBLIC ${CMAKE_THREAD_LIBS_INIT})
endif(NOT WIN32)
endif(LIBICSNEO_ENABLE_FTDI)
# pcap
if(LIBICSNEO_ENABLE_RAW_ETHERNET)

View File

@ -28,7 +28,7 @@ std::string APIEvent::describe() const noexcept {
ss << *device; // Makes use of device.describe()
else
ss << "API";
Severity severity = getSeverity();
if(severity == Severity::EventInfo) {
ss << " Info: ";
@ -76,7 +76,6 @@ static constexpr const char* RESTRICTED_ENTRY_FLAG = "Attempted to set a restric
static constexpr const char* NOT_SUPPORTED = "The requested feature is not supported.";
static constexpr const char* FIXED_POINT_OVERFLOW = "Value is too large to convert to fixed point.";
static constexpr const char* FIXED_POINT_PRECISION = "Value is too small for fixed point precision.";
static constexpr const char* SYSCALL_ERROR = "Error returned from syscall, check errno/GetLastError().";
// Device Errors
static constexpr const char* POLLING_MESSAGE_OVERFLOW = "Too many messages have been recieved for the polling message buffer, some have been lost!";
@ -117,7 +116,7 @@ static constexpr const char* ATOMIC_OPERATION_RETRIED = "An operation failed to
static constexpr const char* ATOMIC_OPERATION_COMPLETED_NONATOMICALLY = "An ideally-atomic operation was completed nonatomically.";
static constexpr const char* WIVI_STACK_REFRESH_FAILED = "The Wireless neoVI stack encountered a communication error.";
static constexpr const char* WIVI_UPLOAD_STACK_OVERFLOW = "The Wireless neoVI upload stack has encountered an overflow condition.";
static constexpr const char* A2B_MESSAGE_INCOMPLETE_FRAME = "At least one of the frames of the A2B message does not contain samples for each channel and stream.";
static constexpr const char* A2B_MESSAGE_INCOMPLETE_FRAME = "At least one of the frames of the A2B message does not contain samples for each channel and stream.";
static constexpr const char* COREMINI_UPLOAD_VERSION_MISMATCH = "The version of the coremini engine on the device and the script uploaded are not the same.";
static constexpr const char* DISK_NOT_CONNECTED = "The program tried to access a disk that is not connected.";
static constexpr const char* UNEXPECTED_RESPONSE = "Received an unexpected or invalid response from the device.";
@ -147,6 +146,41 @@ static constexpr const char* ERROR_SETTING_SOCKET_OPTION = "A call to setsockopt
static constexpr const char* GETIFADDRS_ERROR = "A call to getifaddrs() failed.";
static constexpr const char* SEND_TO_ERROR = "A call to sendto() failed.";
// FTD3XX
static constexpr const char* FT_OK = "FTD3XX success.";
static constexpr const char* FT_INVALID_HANDLE = "Invalid FTD3XX handle.";
static constexpr const char* FT_DEVICE_NOT_FOUND = "FTD3XX device not found.";
static constexpr const char* FT_DEVICE_NOT_OPENED = "FTD3XX device not opened.";
static constexpr const char* FT_IO_ERROR = "FTD3XX IO error.";
static constexpr const char* FT_INSUFFICIENT_RESOURCES = "Insufficient resources for FTD3XX.";
static constexpr const char* FT_INVALID_PARAMETER = "Invalid FTD3XX parameter.";
static constexpr const char* FT_INVALID_BAUD_RATE = "Invalid FTD3XX baud rate.";
static constexpr const char* FT_DEVICE_NOT_OPENED_FOR_ERASE = "FTD3XX device not opened for erase.";
static constexpr const char* FT_DEVICE_NOT_OPENED_FOR_WRITE = "FTD3XX not opened for write.";
static constexpr const char* FT_FAILED_TO_WRITE_DEVICE = "FTD3XX failed to write device.";
static constexpr const char* FT_EEPROM_READ_FAILED = "FTD3XX EEPROM read failed.";
static constexpr const char* FT_EEPROM_WRITE_FAILED = "FTD3XX EEPROM write failed.";
static constexpr const char* FT_EEPROM_ERASE_FAILED = "FTD3XX EEPROM erase failed.";
static constexpr const char* FT_EEPROM_NOT_PRESENT = "FTD3XX EEPROM not present.";
static constexpr const char* FT_EEPROM_NOT_PROGRAMMED = "FTD3XX EEPROM not programmed.";
static constexpr const char* FT_INVALID_ARGS = "Invalid FTD3XX arguments.";
static constexpr const char* FT_NOT_SUPPORTED = "FTD3XX not supported.";
static constexpr const char* FT_NO_MORE_ITEMS = "No more FTD3XX items.";
static constexpr const char* FT_TIMEOUT = "FTD3XX timeout.";
static constexpr const char* FT_OPERATION_ABORTED = "FTD3XX operation aborted.";
static constexpr const char* FT_RESERVED_PIPE = "Reserved FTD3XX pipe.";
static constexpr const char* FT_INVALID_CONTROL_REQUEST_DIRECTION = "Invalid FTD3XX control request direction.";
static constexpr const char* FT_INVALID_CONTROL_REQUEST_TYPE = "Invalid FTD3XX control request type.";
static constexpr const char* FT_IO_PENDING = "FTD3XX IO pending.";
static constexpr const char* FT_IO_INCOMPLETE = "FTD3XX IO incomplete.";
static constexpr const char* FT_HANDLE_EOF = "Handle FTD3XX EOF.";
static constexpr const char* FT_BUSY = "FTD3XX busy.";
static constexpr const char* FT_NO_SYSTEM_RESOURCES = "No FTD3XX system resources.";
static constexpr const char* FT_DEVICE_LIST_NOT_READY = "FTD3XX device list not ready.";
static constexpr const char* FT_DEVICE_NOT_CONNECTED = "FTD3XX device not connected.";
static constexpr const char* FT_INCORRECT_DEVICE_PATH = "Incorrect FTD3XX device path.";
static constexpr const char* FT_OTHER_ERROR = "Other FTD3XX error.";
// VSA
static constexpr const char* VSA_BUFFER_CORRUPTED = "VSA data in record buffer is corrupted.";
static constexpr const char* VSA_TIMESTAMP_NOT_FOUND = "Unable to find a VSA record with a valid timestamp.";
@ -169,13 +203,6 @@ static constexpr const char* SERVD_POLL_ERROR = "Error polling on Servd socket";
static constexpr const char* SERVD_NODATA_ERROR = "No data received from Servd";
static constexpr const char* SERVD_JOIN_MULTICAST_ERROR = "Error joining Servd multicast group";
// DXX
static constexpr const char* DXX_ERROR_SYS = "System error, check errno/GetLastError()";
static constexpr const char* DXX_ERROR_INT = "DXX interrupt called";
static constexpr const char* DXX_ERROR_OVERFLOW = "Overflow in DXX";
static constexpr const char* DXX_ERROR_IO = "I/O failure in DXX";
static constexpr const char* DXX_ERROR_ARG = "Invalid arg passed to DXX";
static constexpr const char* TOO_MANY_EVENTS = "Too many events have occurred. The list has been truncated.";
static constexpr const char* UNKNOWN = "An unknown internal error occurred.";
static constexpr const char* INVALID = "An invalid internal error occurred.";
@ -223,8 +250,6 @@ const char* APIEvent::DescriptionForType(Type type) {
return FIXED_POINT_OVERFLOW;
case Type::FixedPointPrecision:
return FIXED_POINT_PRECISION;
case Type::SyscallError:
return SYSCALL_ERROR;
// Device Errors
case Type::PollingMessageOverflow:
@ -354,6 +379,74 @@ const char* APIEvent::DescriptionForType(Type type) {
return DISK_FORMAT_NOT_SUPPORTED;
case Type::DiskFormatInvalidCount:
return DISK_FORMAT_INVALID_COUNT;
// FTD3XX
case Type::FTOK:
return FT_OK;
case Type::FTInvalidHandle:
return FT_INVALID_HANDLE;
case Type::FTDeviceNotFound:
return FT_DEVICE_NOT_FOUND;
case Type::FTDeviceNotOpened:
return FT_DEVICE_NOT_OPENED;
case Type::FTIOError:
return FT_IO_ERROR;
case Type::FTInsufficientResources:
return FT_INSUFFICIENT_RESOURCES;
case Type::FTInvalidParameter:
return FT_INVALID_PARAMETER;
case Type::FTInvalidBaudRate:
return FT_INVALID_BAUD_RATE;
case Type::FTDeviceNotOpenedForErase:
return FT_DEVICE_NOT_OPENED_FOR_ERASE;
case Type::FTDeviceNotOpenedForWrite:
return FT_DEVICE_NOT_OPENED_FOR_WRITE;
case Type::FTFailedToWriteDevice:
return FT_FAILED_TO_WRITE_DEVICE;
case Type::FTEEPROMReadFailed:
return FT_EEPROM_READ_FAILED;
case Type::FTEEPROMWriteFailed:
return FT_EEPROM_WRITE_FAILED;
case Type::FTEEPROMEraseFailed:
return FT_EEPROM_ERASE_FAILED;
case Type::FTEEPROMNotPresent:
return FT_EEPROM_NOT_PRESENT;
case Type::FTEEPROMNotProgrammed:
return FT_EEPROM_NOT_PROGRAMMED;
case Type::FTInvalidArgs:
return FT_INVALID_ARGS;
case Type::FTNotSupported:
return FT_NOT_SUPPORTED;
case Type::FTNoMoreItems:
return FT_NO_MORE_ITEMS;
case Type::FTTimeout:
return FT_TIMEOUT;
case Type::FTOperationAborted:
return FT_OPERATION_ABORTED;
case Type::FTReservedPipe:
return FT_RESERVED_PIPE;
case Type::FTInvalidControlRequestDirection:
return FT_INVALID_CONTROL_REQUEST_DIRECTION;
case Type::FTInvalidControlRequestType:
return FT_INVALID_CONTROL_REQUEST_TYPE;
case Type::FTIOPending:
return FT_IO_PENDING;
case Type::FTIOIncomplete:
return FT_IO_INCOMPLETE;
case Type::FTHandleEOF:
return FT_HANDLE_EOF;
case Type::FTBusy:
return FT_BUSY;
case Type::FTNoSystemResources:
return FT_NO_SYSTEM_RESOURCES;
case Type::FTDeviceListNotReady:
return FT_DEVICE_LIST_NOT_READY;
case Type::FTDeviceNotConnected:
return FT_DEVICE_NOT_CONNECTED;
case Type::FTIncorrectDevicePath:
return FT_INCORRECT_DEVICE_PATH;
case Type::FTOtherError:
return FT_OTHER_ERROR;
// VSA
case Type::VSABufferCorrupted:
@ -395,18 +488,6 @@ const char* APIEvent::DescriptionForType(Type type) {
case Type::ServdJoinMulticastError:
return SERVD_JOIN_MULTICAST_ERROR;
// DXX
case Type::DXXErrorSys:
return DXX_ERROR_SYS;
case Type::DXXErrorInt:
return DXX_ERROR_INT;
case Type::DXXErrorOverflow:
return DXX_ERROR_OVERFLOW;
case Type::DXXErrorIO:
return DXX_ERROR_IO;
case Type::DXXErrorArg:
return DXX_ERROR_ARG;
// Other Errors
case Type::TooManyEvents:
return TOO_MANY_EVENTS;
@ -420,7 +501,7 @@ const char* APIEvent::DescriptionForType(Type type) {
bool EventFilter::match(const APIEvent& event) const noexcept {
if(type != APIEvent::Type::Any && type != event.getType())
return false;
if(matchOnDevicePtr && !event.isForDevice(device))
return false;

View File

@ -1,7 +1,5 @@
//FILE: icsneo40DLLAPI.H
#define WIN32_LEAN_AND_MEAN
#define NOMINMAX
#include <windows.h>
#include "icsneo/icsnVC40.h"

View File

@ -28,9 +28,6 @@ void init_event(pybind11::module_& m) {
.value("WiVINotSupported", APIEvent::Type::WiVINotSupported)
.value("RestrictedEntryFlag", APIEvent::Type::RestrictedEntryFlag)
.value("NotSupported", APIEvent::Type::NotSupported)
.value("FixedPointOverflow", APIEvent::Type::FixedPointOverflow)
.value("FixedPointPrecision", APIEvent::Type::FixedPointPrecision)
.value("SyscallError", APIEvent::Type::SyscallError)
.value("PollingMessageOverflow", APIEvent::Type::PollingMessageOverflow)
.value("NoSerialNumber", APIEvent::Type::NoSerialNumber)
.value("IncorrectSerialNumber", APIEvent::Type::IncorrectSerialNumber)
@ -39,6 +36,8 @@ void init_event(pybind11::module_& m) {
.value("SettingsLengthError", APIEvent::Type::SettingsLengthError)
.value("SettingsChecksumError", APIEvent::Type::SettingsChecksumError)
.value("SettingsNotAvailable", APIEvent::Type::SettingsNotAvailable)
.value("DiskFormatNotSupported", APIEvent::Type::DiskFormatNotSupported)
.value("DiskFormatInvalidCount", APIEvent::Type::DiskFormatInvalidCount)
.value("SettingsReadOnly", APIEvent::Type::SettingsReadOnly)
.value("CANSettingsNotAvailable", APIEvent::Type::CANSettingsNotAvailable)
.value("CANFDSettingsNotAvailable", APIEvent::Type::CANFDSettingsNotAvailable)
@ -87,10 +86,6 @@ void init_event(pybind11::module_& m) {
.value("LINSettingsNotAvailable", APIEvent::Type::LINSettingsNotAvailable)
.value("ModeNotFound", APIEvent::Type::ModeNotFound)
.value("AppErrorParsingFailed", APIEvent::Type::AppErrorParsingFailed)
.value("GPTPNotSupported", APIEvent::Type::GPTPNotSupported)
.value("SettingNotAvaiableDevice", APIEvent::Type::SettingNotAvaiableDevice)
.value("DiskFormatNotSupported", APIEvent::Type::DiskFormatNotSupported)
.value("DiskFormatInvalidCount", APIEvent::Type::DiskFormatInvalidCount)
.value("FailedToRead", APIEvent::Type::FailedToRead)
.value("FailedToWrite", APIEvent::Type::FailedToWrite)
.value("DriverFailedToOpen", APIEvent::Type::DriverFailedToOpen)
@ -107,6 +102,39 @@ void init_event(pybind11::module_& m) {
.value("GetIfAddrsError", APIEvent::Type::GetIfAddrsError)
.value("SendToError", APIEvent::Type::SendToError)
.value("MDIOMessageExceedsMaxLength", APIEvent::Type::MDIOMessageExceedsMaxLength)
.value("FTOK", APIEvent::Type::FTOK)
.value("FTInvalidHandle", APIEvent::Type::FTInvalidHandle)
.value("FTDeviceNotFound", APIEvent::Type::FTDeviceNotFound)
.value("FTDeviceNotOpened", APIEvent::Type::FTDeviceNotOpened)
.value("FTIOError", APIEvent::Type::FTIOError)
.value("FTInsufficientResources", APIEvent::Type::FTInsufficientResources)
.value("FTInvalidParameter", APIEvent::Type::FTInvalidParameter)
.value("FTInvalidBaudRate", APIEvent::Type::FTInvalidBaudRate)
.value("FTDeviceNotOpenedForErase", APIEvent::Type::FTDeviceNotOpenedForErase)
.value("FTDeviceNotOpenedForWrite", APIEvent::Type::FTDeviceNotOpenedForWrite)
.value("FTFailedToWriteDevice", APIEvent::Type::FTFailedToWriteDevice)
.value("FTEEPROMReadFailed", APIEvent::Type::FTEEPROMReadFailed)
.value("FTEEPROMWriteFailed", APIEvent::Type::FTEEPROMWriteFailed)
.value("FTEEPROMEraseFailed", APIEvent::Type::FTEEPROMEraseFailed)
.value("FTEEPROMNotPresent", APIEvent::Type::FTEEPROMNotPresent)
.value("FTEEPROMNotProgrammed", APIEvent::Type::FTEEPROMNotProgrammed)
.value("FTInvalidArgs", APIEvent::Type::FTInvalidArgs)
.value("FTNotSupported", APIEvent::Type::FTNotSupported)
.value("FTNoMoreItems", APIEvent::Type::FTNoMoreItems)
.value("FTTimeout", APIEvent::Type::FTTimeout)
.value("FTOperationAborted", APIEvent::Type::FTOperationAborted)
.value("FTReservedPipe", APIEvent::Type::FTReservedPipe)
.value("FTInvalidControlRequestDirection", APIEvent::Type::FTInvalidControlRequestDirection)
.value("FTInvalidControlRequestType", APIEvent::Type::FTInvalidControlRequestType)
.value("FTIOPending", APIEvent::Type::FTIOPending)
.value("FTIOIncomplete", APIEvent::Type::FTIOIncomplete)
.value("FTHandleEOF", APIEvent::Type::FTHandleEOF)
.value("FTBusy", APIEvent::Type::FTBusy)
.value("FTNoSystemResources", APIEvent::Type::FTNoSystemResources)
.value("FTDeviceListNotReady", APIEvent::Type::FTDeviceListNotReady)
.value("FTDeviceNotConnected", APIEvent::Type::FTDeviceNotConnected)
.value("FTIncorrectDevicePath", APIEvent::Type::FTIncorrectDevicePath)
.value("FTOtherError", APIEvent::Type::FTOtherError)
.value("VSABufferCorrupted", APIEvent::Type::VSABufferCorrupted)
.value("VSATimestampNotFound", APIEvent::Type::VSATimestampNotFound)
.value("VSABufferFormatError", APIEvent::Type::VSABufferFormatError)
@ -114,32 +142,18 @@ void init_event(pybind11::module_& m) {
.value("VSAByteParseFailure", APIEvent::Type::VSAByteParseFailure)
.value("VSAExtendedMessageError", APIEvent::Type::VSAExtendedMessageError)
.value("VSAOtherError", APIEvent::Type::VSAOtherError)
.value("ServdBindError", APIEvent::Type::ServdBindError)
.value("ServdNonblockError", APIEvent::Type::ServdNonblockError)
.value("ServdTransceiveError", APIEvent::Type::ServdTransceiveError)
.value("ServdOutdatedError", APIEvent::Type::ServdOutdatedError)
.value("ServdInvalidResponseError", APIEvent::Type::ServdInvalidResponseError)
.value("ServdLockError", APIEvent::Type::ServdLockError)
.value("ServdSendError", APIEvent::Type::ServdSendError)
.value("ServdRecvError", APIEvent::Type::ServdRecvError)
.value("ServdPollError", APIEvent::Type::ServdPollError)
.value("ServdNoDataError", APIEvent::Type::ServdNoDataError)
.value("ServdJoinMulticastError", APIEvent::Type::ServdJoinMulticastError)
.value("DXXErrorSys", APIEvent::Type::DXXErrorSys)
.value("DXXErrorInt", APIEvent::Type::DXXErrorInt)
.value("DXXErrorOverflow", APIEvent::Type::DXXErrorOverflow)
.value("DXXErrorIO", APIEvent::Type::DXXErrorIO)
.value("DXXErrorArg", APIEvent::Type::DXXErrorArg)
.value("NoErrorFound", APIEvent::Type::NoErrorFound)
.value("TooManyEvents", APIEvent::Type::TooManyEvents)
.value("Unknown", APIEvent::Type::Unknown);
pybind11::enum_<APIEvent::Severity>(apiEvent, "Severity")
.value("Unknown", APIEvent::Type::Unknown)
.value("FixedPointOverflow", APIEvent::Type::FixedPointOverflow)
.value("FixedPointPrecision", APIEvent::Type::FixedPointPrecision);
pybind11::enum_<APIEvent::Severity>(apiEvent, "Severity")
.value("Any", APIEvent::Severity::Any)
.value("EventInfo", APIEvent::Severity::EventInfo)
.value("EventWarning", APIEvent::Severity::EventWarning)
.value("Error", APIEvent::Severity::Error);
apiEvent
.def("get_type", &APIEvent::getType)
.def("get_severity", &APIEvent::getSeverity)
@ -156,5 +170,5 @@ void init_event(pybind11::module_& m) {
.def_readwrite("serial", &EventFilter::serial);
}
} // namespace icsneo
} // namespace icsneo

View File

@ -0,0 +1,21 @@
#!/bin/sh
VERSION="1.0.27"
ROOT="$PWD/libusb"
SOURCE="$ROOT/source"
BUILD="$ROOT/build"
INSTALL="$ROOT/install"
mkdir -p "$ROOT"
cd "$ROOT" || exit 1
curl -LO "https://github.com/libusb/libusb/releases/download/v$VERSION/libusb-$VERSION.tar.bz2" || exit 1
tar -xf "libusb-$VERSION.tar.bz2" || exit 1
mv "libusb-$VERSION" "$SOURCE" || exit 1
mkdir "$BUILD" || exit 1
cd "$BUILD" || exit 1
"$SOURCE/configure" --prefix="$INSTALL" --disable-shared --disable-udev --disable-eventfd --disable-timerfd --with-pic || exit 1
make || exit 1
make install || exit 1

View File

@ -0,0 +1,22 @@
find_path(FTD3XX_INCLUDE_DIR
NAMES ftd3xx.h FTD3XX.h
)
find_library(FTD3XX_LIBRARY
NAMES libftd3xx.a libftd3xx-static.a FTD3XX.lib
PATH_SUFFIXES x64/Static
)
mark_as_advanced(FTD3XX_FOUND FTD3XX_INCLUDE_DIR FTD3XX_LIBRARY)
include(FindPackageHandleStandardArgs)
find_package_handle_standard_args(FTD3XX
REQUIRED_VARS FTD3XX_INCLUDE_DIR FTD3XX_LIBRARY
)
if(FTD3XX_FOUND AND NOT TARGET D3XX::D3XX)
add_library(FTD3XX::FTD3XX INTERFACE IMPORTED)
set_target_properties(FTD3XX::FTD3XX PROPERTIES
INTERFACE_INCLUDE_DIRECTORIES "${FTD3XX_INCLUDE_DIR}"
INTERFACE_LINK_LIBRARIES "${FTD3XX_LIBRARY}"
)
endif()

View File

@ -16,8 +16,12 @@
#include "icsneo/platform/cdcacm.h"
#endif
#ifdef ICSNEO_ENABLE_DXX
#include "icsneo/platform/dxx.h"
#ifdef ICSNEO_ENABLE_FTDI
#include "icsneo/platform/ftdi.h"
#endif
#ifdef ICSNEO_ENABLE_FTD3XX
#include "icsneo/platform/ftd3xx.h"
#endif
#ifdef ICSNEO_ENABLE_TCP
@ -79,8 +83,12 @@ std::vector<std::shared_ptr<Device>> DeviceFinder::FindAll() {
CDCACM::Find(newDriverFoundDevices);
#endif
#ifdef ICSNEO_ENABLE_DXX
DXX::Find(newDriverFoundDevices);
#ifdef ICSNEO_ENABLE_FTDI
FTDI::Find(newDriverFoundDevices);
#endif
#ifdef ICSNEO_ENABLE_FTD3XX
FTD3XX::Find(newDriverFoundDevices);
#endif
}

View File

@ -7,7 +7,7 @@ VSA08::VSA08(uint8_t* const recordBytes)
{
setType(VSA::Type::AA08);
troubleSramCount.insert(troubleSramCount.end(), recordBytes + 2, recordBytes + 6);
troubleSectors.insert(troubleSectors.end(), reinterpret_cast<uint32_t*>(recordBytes + 6), reinterpret_cast<uint32_t*>(recordBytes + 22));
troubleSectors.insert(troubleSectors.end(), reinterpret_cast<uint32_t*>(recordBytes + 6), reinterpret_cast<uint32_t*>(recordBytes + 20));
timestamp = *reinterpret_cast<uint64_t*>(recordBytes + 22) & UINT63_MAX;
checksum = *reinterpret_cast<uint16_t*>(recordBytes + 30);
doChecksum(recordBytes);

View File

@ -8,7 +8,7 @@ Dependencies
The minimum requirements to build libicsneo are:
- CMake version 3.12 or newer
- A C++17 compiler
- libpcap on Linux and macOS
- libusb and libpcap on Linux and macOS
Building library & examples

View File

@ -52,7 +52,7 @@ Although the example program will build without successfully completing the step
First, we are going to build the icsneoc library into a .so file that we can later use in order to access the library functions.
1. Install dependencies with `sudo apt update` then `sudo apt install build-essential cmake libpcap0.8-dev`
1. Install dependencies with `sudo apt update` then `sudo apt install build-essential cmake libusb-1.0-0-dev libpcap0.8-dev`
2. Change directories to `libicsneo-examples/third-party/libicsneo` and create a build directory by running `mkdir -p build`
3. Enter the build directory with `cd build`
4. Run `cmake ..` to generate your Makefile.

View File

@ -52,7 +52,7 @@ Although the example program will build without successfully completing the step
First, we are going to build the icsneoc library into a .so file that we can later use in order to access the library functions.
1. Install dependencies with `sudo apt update` then `sudo apt install build-essential cmake libpcap0.8-dev`
1. Install dependencies with `sudo apt update` then `sudo apt install build-essential cmake libusb-1.0-0-dev libpcap0.8-dev`
2. Change directories to `libicsneo-examples/third-party/libicsneo` and create a build directory by running `mkdir -p build`
3. Enter the build directory with `cd build`
4. Run `cmake ..` to generate your Makefile.

View File

@ -52,7 +52,7 @@ Although the example program will build without successfully completing the step
First, we are going to build the icsneoc library into a .so file that we can later use in order to access the library functions.
1. Install dependencies with `sudo apt update` then `sudo apt install build-essential cmake libpcap0.8-dev`
1. Install dependencies with `sudo apt update` then `sudo apt install build-essential cmake libusb-1.0-0-dev libpcap0.8-dev`
2. Change directories to `libicsneo-examples/third-party/libicsneo` and create a build directory by running `mkdir -p build`
3. Enter the build directory with `cd build`
4. Run `cmake ..` to generate your Makefile.

View File

@ -32,7 +32,7 @@ If you haven't done this, `third-party/libicsneo` will be empty and you won't be
### Ubuntu 18.04 LTS
1. Install dependencies with `sudo apt update` then `sudo apt install build-essential cmake libpcap0.8-dev`
1. Install dependencies with `sudo apt update` then `sudo apt install build-essential cmake libusb-1.0-0-dev libpcap0.8-dev`
2. Change directories to your `libicsneo-examples/libicsneocpp-example` folder and create a build directory by running `mkdir -p build`
3. Enter the build directory with `cd build`
4. Run `cmake ..` to generate your Makefile.

View File

@ -32,7 +32,7 @@ If you haven't done this, `third-party/libicsneo` will be empty and you won't be
### Ubuntu 18.04 LTS
1. Install dependencies with `sudo apt update` then `sudo apt install build-essential cmake libpcap0.8-dev`
1. Install dependencies with `sudo apt update` then `sudo apt install build-essential cmake libusb-1.0-0-dev libpcap0.8-dev`
2. Change directories to your `libicsneo-examples/libicsneocpp-example` folder and create a build directory by running `mkdir -p build`
3. Enter the build directory with `cd build`
4. Run `cmake ..` to generate your Makefile.

View File

@ -53,7 +53,6 @@ public:
NotSupported = 0x1017,
FixedPointOverflow = 0x1018,
FixedPointPrecision = 0x1019,
SyscallError = 0x1020, // check errno/GetLastError() for details
// Device Events
PollingMessageOverflow = 0x2000,
@ -135,6 +134,41 @@ public:
SendToError = 0x3109,
MDIOMessageExceedsMaxLength = 0x3110,
// FTD3XX
FTOK = 0x4000, // placeholder
FTInvalidHandle = FTOK + 1,
FTDeviceNotFound = FTOK + 2,
FTDeviceNotOpened = FTOK + 3,
FTIOError = FTOK + 4,
FTInsufficientResources = FTOK + 5,
FTInvalidParameter = FTOK + 6,
FTInvalidBaudRate = FTOK + 7,
FTDeviceNotOpenedForErase = FTOK + 8,
FTDeviceNotOpenedForWrite = FTOK + 9,
FTFailedToWriteDevice = FTOK + 10,
FTEEPROMReadFailed = FTOK + 11,
FTEEPROMWriteFailed = FTOK + 12,
FTEEPROMEraseFailed = FTOK + 13,
FTEEPROMNotPresent = FTOK + 14,
FTEEPROMNotProgrammed = FTOK + 15,
FTInvalidArgs = FTOK + 16,
FTNotSupported = FTOK + 17,
FTNoMoreItems = FTOK + 18,
FTTimeout = FTOK + 19,
FTOperationAborted = FTOK + 20,
FTReservedPipe = FTOK + 21,
FTInvalidControlRequestDirection = FTOK + 22,
FTInvalidControlRequestType = FTOK + 23,
FTIOPending = FTOK + 24,
FTIOIncomplete = FTOK + 25,
FTHandleEOF = FTOK + 26,
FTBusy = FTOK + 27,
FTNoSystemResources = FTOK + 28,
FTDeviceListNotReady = FTOK + 29,
FTDeviceNotConnected = FTOK + 30,
FTIncorrectDevicePath = FTOK + 31,
FTOtherError = FTOK + 32,
// VSA
VSABufferCorrupted = 0x5000,
VSATimestampNotFound = VSABufferCorrupted + 1,
@ -157,13 +191,6 @@ public:
ServdNoDataError = ServdBindError + 9,
ServdJoinMulticastError = ServdBindError + 10,
// DXX
DXXErrorSys = 0x6100,
DXXErrorInt = 0x6101,
DXXErrorOverflow = 0x6102,
DXXErrorIO = 0x6103,
DXXErrorArg = 0x6104,
NoErrorFound = 0xFFFFFFFD,
TooManyEvents = 0xFFFFFFFE,
Unknown = 0xFFFFFFFF

View File

@ -20,7 +20,7 @@ public:
EventCallback(std::shared_ptr<EventFilter> f, fn_eventCallback cb) : callback(cb), filter(f) {}
EventCallback(EventFilter f, fn_eventCallback cb) : callback(cb), filter(std::make_shared<EventFilter>(f)) {}
bool callIfMatch(const std::shared_ptr<APIEvent>& event) const {
virtual bool callIfMatch(const std::shared_ptr<APIEvent>& event) const {
bool ret = filter->match(*event);
if(ret)
callback(event);

View File

@ -11,7 +11,7 @@ namespace icsneo {
class NeoVIFIRE : public Device {
public:
// USB PID is 0x0701, standard driver is DXX
// USB PID is 0x0701, standard driver is FTDI
ICSNEO_FINDABLE_DEVICE_BY_PID(NeoVIFIRE, DeviceType::FIRE, 0x0701);
static const std::vector<Network>& GetSupportedNetworks() {

View File

@ -12,7 +12,7 @@ namespace icsneo {
class NeoVIFIRE2 : public Device {
public:
// Serial numbers start with CY
// USB PID is 0x1000, standard driver is DXX
// USB PID is 0x1000, standard driver is FTDI
// Ethernet MAC allocation is 0x04, standard driver is Raw
ICSNEO_FINDABLE_DEVICE(NeoVIFIRE2, DeviceType::FIRE2, "CY");

View File

@ -12,7 +12,7 @@ namespace icsneo {
class NeoVIION : public Plasion {
public:
// USB PID is 0x0901, standard driver is DXX
// USB PID is 0x0901, standard driver is FTDI
ICSNEO_FINDABLE_DEVICE_BY_PID(NeoVIION, DeviceType::ION, 0x0901);
private:

View File

@ -10,7 +10,7 @@ namespace icsneo {
class NeoVIPLASMA : public Plasion {
public:
// USB PID is 0x0801, standard driver is DXX
// USB PID is 0x0801, standard driver is FTDI
ICSNEO_FINDABLE_DEVICE_BY_PID(NeoVIPLASMA, DeviceType::PLASMA, 0x0801);
private:

View File

@ -15,7 +15,7 @@ namespace icsneo {
class RADA2B : public Device {
public:
// Serial numbers start with AB
// USB PID is 0x0006, standard driver is DXX
// USB PID is 0x0006, standard driver is FTDI
// Ethernet MAC allocation is 0x18, standard driver is Raw
ICSNEO_FINDABLE_DEVICE(RADA2B, DeviceType::RAD_A2B, "AB");

View File

@ -12,7 +12,7 @@ class RADComet : public RADCometBase {
public:
// Serial numbers start with RC
// USB PID is 0x1207, standard driver is DXX
// USB PID is 0x1207, standard driver is FTDI3
// Ethernet MAC allocation is 0x1D, standard driver is Raw
ICSNEO_FINDABLE_DEVICE_BY_SERIAL_RANGE(RADComet, DeviceType::RADComet, "RC0000", "RC0299");

View File

@ -12,7 +12,7 @@ class RADComet2 : public RADCometBase {
public:
// Serial numbers start with RC, Comet2 starts at RC0300
// USB PID is 0x1207, standard driver is DXX
// USB PID is 0x1207, standard driver is FTDI3
// Ethernet MAC allocation is 0x1D, standard driver is Raw
ICSNEO_FINDABLE_DEVICE_BY_SERIAL_RANGE(RADComet2, DeviceType::RADComet, "RC0300", "RCZZZZ");

View File

@ -12,7 +12,7 @@ class RADComet3 : public Device {
public:
// Serial numbers start with C3
// USB PID is 0x1208, standard driver is DXX
// USB PID is 0x1208, standard driver is FTDI3
// Ethernet MAC allocation is 0x20, standard driver is Raw
ICSNEO_FINDABLE_DEVICE(RADComet3, DeviceType::RADComet3, "C3");

View File

@ -14,7 +14,7 @@ namespace icsneo {
class RADGigastar : public Device {
public:
// Serial numbers start with GS
// USB PID is 0x1204, standard driver is DXX
// USB PID is 0x1204, standard driver is FTDI3
// Ethernet MAC allocation is 0x0F, standard driver is Raw
ICSNEO_FINDABLE_DEVICE(RADGigastar, DeviceType::RADGigastar, "GS");

View File

@ -16,7 +16,7 @@ namespace icsneo
{
public:
// Serial numbers start with GT
// USB PID is 0x1210, standard driver is DXX
// USB PID is 0x1210, standard driver is FTDI3
// Ethernet MAC allocation is 0x22, standard driver is Raw
ICSNEO_FINDABLE_DEVICE(RADGigastar2, DeviceType::RADGigastar2, "GT");

View File

@ -14,7 +14,7 @@ namespace icsneo {
class RADMars : public Device {
public:
// Serial numbers start with GL (previously, RAD-Gigalog)
// USB PID is 0x1203, standard driver is DXX
// USB PID is 0x1203, standard driver is FTDI3
// Ethernet MAC allocation is 0x0A, standard driver is Raw
ICSNEO_FINDABLE_DEVICE(RADMars, DeviceType::RADMars, "GL");

View File

@ -11,7 +11,7 @@ namespace icsneo {
class RADMoon2 : public RADMoon2Base {
public:
// Serial numbers start with RM
// USB PID is 0x1202, standard driver is DXX
// USB PID is 0x1202, standard driver is FTDI3
ICSNEO_FINDABLE_DEVICE(RADMoon2, DeviceType::RADMoon2, "RM");
uint8_t getPhyAddrOrPort() const override { return 6; };

View File

@ -12,7 +12,7 @@ class RADMoonT1S : public Device {
public:
// Serial numbers start with MS
// USB PID is 0x1209, standard driver is DXX
// USB PID is 0x1209, standard driver is FTDI3
// Ethernet MAC allocation is 0x21, standard driver is Raw
ICSNEO_FINDABLE_DEVICE(RADMoonT1S, DeviceType::RADMoonT1S, "MS");

View File

@ -12,7 +12,7 @@ namespace icsneo {
class RADStar2 : public Device {
public:
// Serial numbers start with RS
// USB PID is 0x0005, standard driver is DXX
// USB PID is 0x0005, standard driver is FTDI
// Ethernet MAC allocation is 0x05, standard driver is Raw
ICSNEO_FINDABLE_DEVICE(RADStar2, DeviceType::RADStar2, "RS");

View File

@ -12,7 +12,7 @@ namespace icsneo {
class RADSupermoon : public Device {
public:
// Serial numbers start with SM
// USB PID is 0x1201, standard driver is DXX
// USB PID is 0x1201, standard driver is FTDI3
ICSNEO_FINDABLE_DEVICE(RADSupermoon, DeviceType::RADSupermoon, "SM");
enum class SKU {

View File

@ -11,7 +11,7 @@ namespace icsneo {
class ValueCAN3 : public Device {
public:
// USB PID is 0x0601, standard driver is DXX
// USB PID is 0x0601, standard driver is FTDI
ICSNEO_FINDABLE_DEVICE_BY_PID(ValueCAN3, DeviceType::VCAN3, 0x0601);
static const std::vector<Network>& GetSupportedNetworks() {

View File

@ -1,39 +0,0 @@
#ifndef __DXX_H_
#define __DXX_H_
#ifdef __cplusplus
#include "icsneo/communication/driver.h"
#include "icsneo/device/founddevice.h"
#include "libredxx/libredxx.h"
namespace icsneo {
class DXX : public Driver {
public:
static void Find(std::vector<FoundDevice>& found);
DXX(const device_eventhandler_t& err, neodevice_t& forDevice, uint16_t pid, libredxx_device_type type);
bool open() override;
bool isOpen() override;
bool close() override;
private:
void read();
void write();
neodevice_t neodevice;
uint16_t pid;
libredxx_device_type type;
libredxx_opened_device* device = nullptr;
std::thread readThread;
std::thread writeThread;
};
}
#endif // __cplusplus
#endif // __DXX_H_

View File

@ -0,0 +1,35 @@
#ifndef __FTD3XX_H_
#define __FTD3XX_H_
#ifdef __cplusplus
#include <optional>
#include "icsneo/communication/driver.h"
#include "icsneo/device/founddevice.h"
namespace icsneo {
class FTD3XX : public Driver {
public:
static void Find(std::vector<FoundDevice>& foundDevices);
FTD3XX(const device_eventhandler_t& err, neodevice_t& forDevice);
~FTD3XX() override { if(isOpen()) close(); }
bool open() override;
bool isOpen() override;
bool close() override;
bool isEthernet() const override { return false; }
private:
neodevice_t& device;
std::optional<void*> handle;
std::thread readThread, writeThread;
void readTask();
void writeTask();
};
}
#endif // __cplusplus
#endif

View File

@ -0,0 +1,14 @@
#ifndef __FTDI_H_
#define __FTDI_H_
#define INTREPID_USB_VENDOR_ID (0x093c)
#if defined _WIN32
#include "icsneo/platform/windows/ftdi.h"
#elif defined (__unix__) || (defined (__APPLE__) && defined (__MACH__))
#include "icsneo/platform/posix/ftdi.h"
#else
#warning "This platform is not supported by the FTDI driver"
#endif
#endif

View File

@ -0,0 +1,74 @@
#ifndef __FTDI_POSIX_H_
#define __FTDI_POSIX_H_
#ifdef __cplusplus
#include <vector>
#include <memory>
#include <string>
#include <ftdi.h>
#include "icsneo/device/neodevice.h"
#include "icsneo/communication/driver.h"
#include "icsneo/third-party/concurrentqueue/blockingconcurrentqueue.h"
#include "icsneo/api/eventmanager.h"
namespace icsneo {
class FTDI : public Driver {
public:
static void Find(std::vector<FoundDevice>& found);
FTDI(const device_eventhandler_t& err, neodevice_t& forDevice);
~FTDI() { if(isOpen()) close(); }
bool open();
bool close();
bool isOpen() { return ftdi.isOpen(); }
private:
class FTDIContext {
public:
FTDIContext() : context(ftdi_new()) {}
~FTDIContext() {
if(context)
ftdi_free(context); // calls ftdi_deinit and ftdi_close if required
context = nullptr;
}
// A PID of 0 disables filtering by PID
std::pair<int, std::vector< std::pair<std::string, uint16_t> > > findDevices(int pid = 0);
int openDevice(int pid, const char* serial);
bool closeDevice();
bool isOpen() const { return deviceOpen; }
int flush() { return ftdi_usb_purge_buffers(context); }
int reset() { return ftdi_usb_reset(context); }
int read(uint8_t* data, size_t size) { return ftdi_read_data(context, data, (int)size); }
int write(const uint8_t* data, size_t size) { return ftdi_write_data(context, data, (int)size); }
int setBaudrate(int baudrate) { return ftdi_set_baudrate(context, baudrate); }
int setLatencyTimer(uint8_t latency) { return ftdi_set_latency_timer(context, latency); }
bool setReadTimeout(int timeout) { if(context == nullptr) return false; context->usb_read_timeout = timeout; return true; }
bool setWriteTimeout(int timeout) { if(context == nullptr) return false; context->usb_write_timeout = timeout; return true; }
private:
struct ftdi_context* context;
bool deviceOpen = false;
};
FTDIContext ftdi;
static std::vector<std::string> handles;
static bool ErrorIsDisconnection(int errorCode);
std::thread readThread, writeThread;
void readTask();
void writeTask();
bool openable; // Set to false in the constructor if the object has not been found in searchResultDevices
neodevice_t& device;
};
}
#endif // __cplusplus
#endif

View File

@ -4,8 +4,6 @@
#ifdef __cplusplus
#ifdef _WIN32
#define WIN32_LEAN_AND_MEAN
#define NOMINMAX
#include <windows.h>
#include <winsock2.h>
#include <ws2tcpip.h>

View File

@ -3,34 +3,14 @@
#ifdef __cplusplus
#include "icsneo/communication/driver.h"
#include "icsneo/device/founddevice.h"
#define WIN32_LEAN_AND_MEAN
#define NOMINMAX
#include <windows.h>
#include <string>
#include "icsneo/platform/windows/vcp.h"
namespace icsneo {
class CDCACM : public Driver {
class CDCACM : public VCP {
public:
CDCACM(const device_eventhandler_t& err, const std::wstring& path);
static void Find(std::vector<FoundDevice>& found);
bool open() override;
bool isOpen() override;
bool close() override;
private:
void read();
void write();
std::wstring path;
HANDLE handle = INVALID_HANDLE_VALUE;
std::thread readThread;
std::thread writeThread;
OVERLAPPED readOverlapped = {};
OVERLAPPED writeOverlapped = {};
CDCACM(const device_eventhandler_t& err, neodevice_t& forDevice) : VCP(err, forDevice) {}
static void Find(std::vector<FoundDevice>& found) { return VCP::Find(found, { L"usbser" }); }
};
}

View File

@ -1,8 +1,6 @@
#ifndef __DYNAMICLIB_WINDOWS_H_
#define __DYNAMICLIB_WINDOWS_H_
#define WIN32_LEAN_AND_MEAN
#define NOMINMAX
#include <windows.h>
#ifndef ICSNEOC_BUILD_STATIC

View File

@ -0,0 +1,20 @@
#ifndef __FTDI_WINDOWS_H_
#define __FTDI_WINDOWS_H_
#ifdef __cplusplus
#include "icsneo/platform/windows/vcp.h"
namespace icsneo {
class FTDI : public VCP {
public:
FTDI(const device_eventhandler_t& err, neodevice_t& forDevice) : VCP(err, forDevice) {}
static void Find(std::vector<FoundDevice>& found) { return VCP::Find(found, { L"serenum" /*, L"ftdibus" */ }); }
};
}
#endif // __cplusplus
#endif

View File

@ -3,8 +3,6 @@
#ifdef __cplusplus
#define WIN32_LEAN_AND_MEAN
#define NOMINMAX
#include <windows.h>
#include <pcap.h>
#include <memory>

View File

@ -0,0 +1,49 @@
#ifndef __VCP_WINDOWS_H_
#define __VCP_WINDOWS_H_
#ifdef __cplusplus
#include <vector>
#include <string>
#include <thread>
#include <atomic>
#include <chrono>
#include "icsneo/device/neodevice.h"
#include "icsneo/communication/driver.h"
#include "icsneo/api/eventmanager.h"
namespace icsneo {
// Virtual COM Port Communication
class VCP : public Driver {
public:
static void Find(std::vector<FoundDevice>& found, std::vector<std::wstring> driverName);
static bool IsHandleValid(neodevice_handle_t handle);
typedef void(*fn_boolCallback)(bool success);
VCP(const device_eventhandler_t& err, neodevice_t& forDevice);
virtual ~VCP();
bool open() { return open(false); }
void openAsync(fn_boolCallback callback);
bool close();
bool isOpen();
private:
bool open(bool fromAsync);
bool opening = false;
neodevice_t& device;
struct Detail;
std::shared_ptr<Detail> detail;
std::vector<std::shared_ptr<std::thread>> threads;
std::thread readThread, writeThread;
void readTask();
void writeTask();
};
}
#endif // __cplusplus
#endif

View File

@ -1,194 +0,0 @@
#include "icsneo/platform/dxx.h"
#define ICS_USB_VID 0x093C
using namespace icsneo;
static APIEvent::Type eventError(libredxx_status status) {
switch (status) {
case LIBREDXX_STATUS_ERROR_SYS: return APIEvent::Type::DXXErrorSys;
case LIBREDXX_STATUS_ERROR_INTERRUPTED: return APIEvent::Type::DXXErrorSys;
case LIBREDXX_STATUS_ERROR_OVERFLOW: return APIEvent::Type::DXXErrorSys;
case LIBREDXX_STATUS_ERROR_IO: return APIEvent::Type::DXXErrorSys;
case LIBREDXX_STATUS_ERROR_INVALID_ARGUMENT: return APIEvent::Type::DXXErrorSys;
default: return APIEvent::Type::Unknown;
}
}
void DXX::Find(std::vector<FoundDevice>& found) {
libredxx_status status;
static libredxx_find_filter filters[] = {
{ LIBREDXX_DEVICE_TYPE_D2XX, { ICS_USB_VID, 0x0005 } }, // RAD-Star 2
{ LIBREDXX_DEVICE_TYPE_D2XX, { ICS_USB_VID, 0x0006 } }, // RAD-A2B Rev A
{ LIBREDXX_DEVICE_TYPE_D2XX, { ICS_USB_VID, 0x1000 } }, // neoVI FIRE2
{ LIBREDXX_DEVICE_TYPE_D3XX, { ICS_USB_VID, 0x1201 } }, // RAD-SuperMoon
{ LIBREDXX_DEVICE_TYPE_D3XX, { ICS_USB_VID, 0x1202 } }, // RAD-Moon2
{ LIBREDXX_DEVICE_TYPE_D3XX, { ICS_USB_VID, 0x1203 } }, // RAD-Gigalog
{ LIBREDXX_DEVICE_TYPE_D3XX, { ICS_USB_VID, 0x1204 } }, // RAD-Gigastar
{ LIBREDXX_DEVICE_TYPE_D3XX, { ICS_USB_VID, 0x1206 } }, // RAD-A2B Rev B
{ LIBREDXX_DEVICE_TYPE_D3XX, { ICS_USB_VID, 0x1207 } }, // RAD-Comet
{ LIBREDXX_DEVICE_TYPE_D3XX, { ICS_USB_VID, 0x1208 } }, // RAD-Comet3
{ LIBREDXX_DEVICE_TYPE_D3XX, { ICS_USB_VID, 0x1209 } }, // RAD-MoonT1S
{ LIBREDXX_DEVICE_TYPE_D3XX, { ICS_USB_VID, 0x1210 } }, // RAD-Gigastar 2
};
static size_t filterCount = sizeof(filters) / sizeof(filters[0]);
libredxx_found_device** foundDevices = nullptr;
size_t foundDevicesCount;
status = libredxx_find_devices(filters, filterCount, &foundDevices, &foundDevicesCount);
if(status != LIBREDXX_STATUS_SUCCESS) {
EventManager::GetInstance().add(eventError(status), APIEvent::Severity::Error);
return;
}
if(foundDevicesCount == 0) {
return;
}
for(size_t i = 0; i < foundDevicesCount; ++i) {
libredxx_found_device* foundDevice = foundDevices[i];
libredxx_serial serial = {};
status = libredxx_get_serial(foundDevice, &serial);
if(status != LIBREDXX_STATUS_SUCCESS) {
EventManager::GetInstance().add(eventError(status), APIEvent::Severity::Error);
continue;
}
libredxx_device_id id;
status = libredxx_get_device_id(foundDevice, &id);
if(status != LIBREDXX_STATUS_SUCCESS) {
EventManager::GetInstance().add(eventError(status), APIEvent::Severity::Error);
continue;
}
libredxx_device_type type;
status = libredxx_get_device_type(foundDevice, &type);
if(status != LIBREDXX_STATUS_SUCCESS) {
EventManager::GetInstance().add(eventError(status), APIEvent::Severity::Error);
continue;
}
auto& device = found.emplace_back();
std::copy(serial.serial, serial.serial + sizeof(device.serial), device.serial);
device.makeDriver = [id, type](device_eventhandler_t err, neodevice_t& forDevice) {
return std::make_unique<DXX>(err, forDevice, id.pid, type);
};
}
libredxx_free_found(foundDevices);
}
DXX::DXX(const device_eventhandler_t& err, neodevice_t& forDevice, uint16_t pid, libredxx_device_type type) :
Driver(err), neodevice(forDevice), pid(pid), type(type) {
}
bool DXX::open() {
libredxx_status status;
libredxx_find_filter filters[] = {
{ (libredxx_device_type)type, { ICS_USB_VID, pid } }
};
libredxx_found_device** foundDevices = nullptr;
size_t foundDevicesCount;
status = libredxx_find_devices(filters, 1, &foundDevices, &foundDevicesCount);
if(status != LIBREDXX_STATUS_SUCCESS) {
EventManager::GetInstance().add(eventError(status), APIEvent::Severity::Error);
return false;
}
if(foundDevicesCount == 0) {
EventManager::GetInstance().add(APIEvent::Type::DeviceDisconnected, APIEvent::Severity::Error);
return false;
}
libredxx_found_device* foundDevice = nullptr;
for(size_t i = 0; i < foundDevicesCount; ++i) {
libredxx_serial serial = {};
status = libredxx_get_serial(foundDevices[i], &serial);
if(status != LIBREDXX_STATUS_SUCCESS) {
EventManager::GetInstance().add(eventError(status), APIEvent::Severity::EventWarning);
continue;
}
if(strcmp(serial.serial, neodevice.serial) == 0) {
foundDevice = foundDevices[i];
break;
}
}
if(foundDevice == nullptr) {
EventManager::GetInstance().add(APIEvent::Type::DeviceDisconnected, APIEvent::Severity::Error);
libredxx_free_found(foundDevices);
return false;
}
status = libredxx_open_device(foundDevice, &device);
if(status != LIBREDXX_STATUS_SUCCESS) {
EventManager::GetInstance().add(eventError(status), APIEvent::Severity::Error);
libredxx_free_found(foundDevices);
return false;
}
libredxx_free_found(foundDevices);
setIsDisconnected(false);
readThread = std::thread(&DXX::read, this);
writeThread = std::thread(&DXX::write, this);
return true;
}
bool DXX::isOpen() {
return device != nullptr;
}
bool DXX::close() {
setIsClosing(true);
libredxx_close_device(device); // unblock read thread & close
writeQueue.enqueue(WriteOperation{}); // unblock write thread
readThread.join();
writeThread.join();
device = nullptr;
setIsClosing(false);
return true;
}
void DXX::read() {
EventManager::GetInstance().downgradeErrorsOnCurrentThread();
std::vector<uint8_t> buffer(ICSNEO_DRIVER_RINGBUFFER_SIZE);
while(!isDisconnected() && !isClosing()) {
size_t received = buffer.size();
const auto status = libredxx_read(device, buffer.data(), &received);
if(isDisconnected() || isClosing()) {
return;
}
if(status != LIBREDXX_STATUS_SUCCESS) {
EventManager::GetInstance().add(eventError(status), APIEvent::Severity::Error);
setIsDisconnected(true);
return;
}
while(!isDisconnected() && !isClosing()) {
if(pushRx(buffer.data(), received))
break;
}
}
}
void DXX::write() {
EventManager::GetInstance().downgradeErrorsOnCurrentThread();
WriteOperation writeOp;
while(!isDisconnected() && !isClosing()) {
writeQueue.wait_dequeue(writeOp);
if(isDisconnected() || isClosing()) {
return;
}
for(size_t totalWritten = 0; totalWritten < writeOp.bytes.size();) {
size_t size = writeOp.bytes.size() - totalWritten;
const auto status = libredxx_write(device, &writeOp.bytes[totalWritten], &size);
if(isDisconnected() || isClosing()) {
return;
}
if(status != LIBREDXX_STATUS_SUCCESS) {
EventManager::GetInstance().add(eventError(status), APIEvent::Severity::Error);
setIsDisconnected(true);
return;
}
totalWritten += size;
}
}
}

182
platform/ftd3xx.cpp 100644
View File

@ -0,0 +1,182 @@
#include <vector>
#include "icsneo/api/eventmanager.h"
#ifdef _MSC_VER
#pragma warning(push)
#pragma warning(disable : 4091)
#endif
#define FTD3XX_STATIC
#include <ftd3xx.h>
#ifdef _MSC_VER
#pragma warning(pop)
#endif
#include "icsneo/platform/ftd3xx.h"
static constexpr auto READ_PIPE_ID = 0x82;
static constexpr auto WRITE_PIPE_ID = 0x02;
using namespace icsneo;
static void addEvent(FT_STATUS status, APIEvent::Severity severity) {
const auto internalEvent = static_cast<uint32_t>(APIEvent::Type::FTOK) + status;
EventManager::GetInstance().add(APIEvent((APIEvent::Type)internalEvent, severity));
}
void FTD3XX::Find(std::vector<FoundDevice>& found) {
DWORD count;
if(const auto ret = FT_CreateDeviceInfoList(&count); ret != FT_OK) {
addEvent(ret, APIEvent::Severity::EventWarning);
return;
}
if(count == 0) {
return;
}
std::vector<FT_DEVICE_LIST_INFO_NODE> devices(count);
if(const auto ret = FT_GetDeviceInfoList(devices.data(), &count); ret != FT_OK) {
addEvent(ret, APIEvent::Severity::EventWarning);
return;
}
for(const auto& dev : devices) {
FoundDevice foundDevice = {};
std::copy(dev.SerialNumber, dev.SerialNumber + sizeof(foundDevice.serial), foundDevice.serial);
foundDevice.makeDriver = [](const device_eventhandler_t& eh, neodevice_t& forDevice) {
return std::unique_ptr<Driver>(new FTD3XX(eh, forDevice));
};
found.push_back(std::move(foundDevice));
}
}
FTD3XX::FTD3XX(const device_eventhandler_t& err, neodevice_t& forDevice) : Driver(err), device(forDevice) {
}
bool FTD3XX::open() {
if(isOpen()) {
report(APIEvent::Type::DeviceCurrentlyOpen, APIEvent::Severity::Error);
return false;
}
void* tmpHandle;
if(const auto ret = FT_Create(device.serial, FT_OPEN_BY_SERIAL_NUMBER, &tmpHandle); ret != FT_OK) {
addEvent(ret, APIEvent::Severity::Error);
return false;
}
handle.emplace(tmpHandle);
setIsClosing(false);
setIsDisconnected(false);
readThread = std::thread(&FTD3XX::readTask, this);
writeThread = std::thread(&FTD3XX::writeTask, this);
return true;
}
bool FTD3XX::isOpen() {
return handle.has_value();
}
bool FTD3XX::close() {
if(!isOpen() && !isDisconnected()) {
report(APIEvent::Type::DeviceCurrentlyClosed, APIEvent::Severity::Error);
return false;
}
setIsClosing(true);
// unblock the read thread
FT_AbortPipe(*handle, READ_PIPE_ID);
if(readThread.joinable())
readThread.join();
if(writeThread.joinable())
writeThread.join();
clearBuffers();
if(const auto ret = FT_Close(*handle); ret != FT_OK) {
addEvent(ret, APIEvent::Severity::EventWarning);
}
handle.reset();
setIsClosing(false);
return true;
}
void FTD3XX::readTask() {
EventManager::GetInstance().downgradeErrorsOnCurrentThread();
std::vector<uint8_t> buffer(2 * 1024 * 1024);
FT_SetStreamPipe(*handle, false, false, READ_PIPE_ID, (ULONG)buffer.size());
// disable timeouts, we will interupt the read thread with AbortPipe
FT_SetPipeTimeout(*handle, READ_PIPE_ID, 0);
OVERLAPPED overlapped = {};
FT_InitializeOverlapped(*handle, &overlapped);
FT_STATUS status;
ULONG received = 0;
while(!isClosing() && !isDisconnected()) {
received = 0;
#ifdef _WIN32
status = FT_ReadPipe(*handle, READ_PIPE_ID, buffer.data(), (ULONG)buffer.size(), &received, &overlapped);
#else
status = FT_ReadPipeAsync(*handle, 0, buffer.data(), buffer.size(), &received, &overlapped);
#endif
if(FT_FAILED(status)) {
if(status != FT_IO_PENDING) {
addEvent(status, APIEvent::Severity::Error);
setIsDisconnected(true);
break;
}
status = FT_GetOverlappedResult(*handle, &overlapped, &received, true);
if(FT_FAILED(status)) {
addEvent(status, APIEvent::Severity::Error);
setIsDisconnected(true);
break;
}
if(received > 0) {
pushRx(buffer.data(), received);
}
}
}
FT_ReleaseOverlapped(*handle, &overlapped);
}
void FTD3XX::writeTask() {
EventManager::GetInstance().downgradeErrorsOnCurrentThread();
FT_SetPipeTimeout(*handle, WRITE_PIPE_ID, 0);
WriteOperation writeOp;
ULONG sent;
FT_STATUS status;
while(!isClosing() && !isDisconnected()) {
if(!writeQueue.wait_dequeue_timed(writeOp, std::chrono::milliseconds(100)))
continue;
const auto size = static_cast<ULONG>(writeOp.bytes.size());
sent = 0;
#ifdef _WIN32
status = FT_WritePipe(*handle, WRITE_PIPE_ID, writeOp.bytes.data(), size, &sent, nullptr);
#else
status = FT_WritePipe(*handle, WRITE_PIPE_ID, writeOp.bytes.data(), size, &sent, 100);
#endif
if(FT_FAILED(status)) {
addEvent(status, APIEvent::Severity::Error);
setIsDisconnected(true);
break;
}
if(sent != size) {
report(APIEvent::Type::DeviceDisconnected, APIEvent::Severity::Error);
setIsDisconnected(true);
break;
}
}
}

View File

@ -0,0 +1,242 @@
#include "icsneo/platform/ftdi.h"
#include "icsneo/device/founddevice.h"
#include <iostream>
#include <stdio.h>
#include <cstring>
#include <memory>
#include <utility>
#include <cctype>
#include <algorithm>
#include <libusb.h>
using namespace icsneo;
std::vector<std::string> FTDI::handles;
void FTDI::Find(std::vector<FoundDevice>& found) {
constexpr size_t deviceSerialBufferLength = sizeof(device.serial);
static FTDIContext context;
const auto result = context.findDevices();
if(result.first < 0)
return; // TODO Flag an error for the client application, there was an issue with FTDI
for(const auto& [serial, pid] : result.second) {
FoundDevice d;
strncpy(d.serial, serial.c_str(), deviceSerialBufferLength - 1);
d.serial[deviceSerialBufferLength - 1] = '\0'; // strncpy does not write a null terminator if serial is too long
for(size_t i = 0; i < deviceSerialBufferLength - 1; i++)
d.serial[i] = toupper(serial[i]);
std::string devHandle = serial;
auto it = std::find(handles.begin(), handles.end(), devHandle);
size_t foundHandle = SIZE_MAX;
if(it != handles.end()) {
foundHandle = it - handles.begin();
} else {
foundHandle = handles.size();
handles.push_back(devHandle);
}
d.handle = foundHandle;
d.productId = pid;
d.makeDriver = [](const device_eventhandler_t& report, neodevice_t& device) {
return std::unique_ptr<Driver>(new FTDI(report, device));
};
found.push_back(d);
}
}
FTDI::FTDI(const device_eventhandler_t& err, neodevice_t& forDevice) : Driver(err), device(forDevice) {
openable = strlen(forDevice.serial) > 0 && device.handle >= 0 && device.handle < (neodevice_handle_t)handles.size();
}
bool FTDI::open() {
if(isOpen()) {
report(APIEvent::Type::DeviceCurrentlyOpen, APIEvent::Severity::Error);
return false;
}
if(!openable) {
report(APIEvent::Type::InvalidNeoDevice, APIEvent::Severity::Error);
return false;
}
// At this point the handle has been checked to be within the bounds of the handles array
auto& handle = handles[device.handle];
const int openError = ftdi.openDevice(0, handle.c_str());
if(openError == -5) { // Unable to claim device
report(APIEvent::Type::DeviceInUse, APIEvent::Severity::Error);
return false;
} else if(openError != 0) {
report(APIEvent::Type::DriverFailedToOpen, APIEvent::Severity::Error);
return false;
}
ftdi.setReadTimeout(100);
ftdi.setWriteTimeout(1000);
ftdi.reset();
ftdi.setBaudrate(500000);
ftdi.setLatencyTimer(1);
ftdi.flush();
// Create threads
setIsClosing(false);
readThread = std::thread(&FTDI::readTask, this);
writeThread = std::thread(&FTDI::writeTask, this);
return true;
}
bool FTDI::close() {
if(!isOpen() && !isDisconnected()) {
report(APIEvent::Type::DeviceCurrentlyClosed, APIEvent::Severity::Error);
return false;
}
setIsClosing(true);
if(readThread.joinable())
readThread.join();
if(writeThread.joinable())
writeThread.join();
bool ret = true;
if(!isDisconnected()) {
ret = ftdi.closeDevice();
if(!ret)
report(APIEvent::Type::DriverFailedToClose, APIEvent::Severity::Error);
}
clearBuffers();
setIsClosing(false);
setIsDisconnected(false);
return ret;
}
std::pair<int, std::vector< std::pair<std::string, uint16_t> > > FTDI::FTDIContext::findDevices(int pid) {
std::pair<int, std::vector< std::pair<std::string, uint16_t> > > ret;
if(context == nullptr) {
ret.first = -1;
return ret;
}
struct ftdi_device_list* devlist = nullptr;
ret.first = ftdi_usb_find_all(context, &devlist, INTREPID_USB_VENDOR_ID, pid);
if(ret.first < 1) {
// Didn't find anything, maybe got an error
if(devlist != nullptr)
ftdi_list_free(&devlist);
return ret;
}
if(devlist == nullptr) {
ret.first = -4;
return ret;
}
for(struct ftdi_device_list* curdev = devlist; curdev != nullptr; curdev = curdev->next) {
struct libusb_device_descriptor descriptor = {};
// Check against bDeviceClass here as it will be 0 for FTDI devices
// It will be 2 for CDC ACM devices, which we don't want to handle here
if(libusb_get_device_descriptor(curdev->dev, &descriptor) != 0 || descriptor.bDeviceClass != 0)
continue;
char serial[16] = {};
if(ftdi_usb_get_strings(context, curdev->dev, nullptr, 0, nullptr, 0, serial, sizeof(serial)) < 0)
continue;
const auto len = strnlen(serial, sizeof(serial));
if(len > 4 && len < 10)
ret.second.emplace_back(serial, descriptor.idProduct);
}
ret.first = static_cast<int>(ret.second.size());
ftdi_list_free(&devlist);
return ret;
}
int FTDI::FTDIContext::openDevice(int pid, const char* serial) {
if(context == nullptr)
return 1;
if(serial == nullptr)
return 2;
if(serial[0] == '\0')
return 3;
if(deviceOpen)
return 4;
int ret = ftdi_usb_open_desc(context, INTREPID_USB_VENDOR_ID, pid, nullptr, serial);
if(ret == 0 /* all ok */)
deviceOpen = true;
return ret;
}
bool FTDI::FTDIContext::closeDevice() {
if(context == nullptr)
return false;
if(!deviceOpen)
return true;
int ret = ftdi_usb_close(context);
if(ret != 0)
return false;
deviceOpen = false;
return true;
}
bool FTDI::ErrorIsDisconnection(int errorCode) {
return errorCode == LIBUSB_ERROR_NO_DEVICE ||
errorCode == LIBUSB_ERROR_PIPE ||
errorCode == LIBUSB_ERROR_IO;
}
void FTDI::readTask() {
constexpr size_t READ_BUFFER_SIZE = 8;
uint8_t readbuf[READ_BUFFER_SIZE];
EventManager::GetInstance().downgradeErrorsOnCurrentThread();
while(!isClosing() && !isDisconnected()) {
auto readBytes = ftdi.read(readbuf, READ_BUFFER_SIZE);
if(readBytes < 0) {
if(ErrorIsDisconnection(readBytes)) {
if(!isDisconnected()) {
setIsDisconnected(true);
report(APIEvent::Type::DeviceDisconnected, APIEvent::Severity::Error);
}
} else
report(APIEvent::Type::FailedToRead, APIEvent::Severity::EventWarning);
} else
pushRx(readbuf, readBytes);
}
}
void FTDI::writeTask() {
WriteOperation writeOp;
EventManager::GetInstance().downgradeErrorsOnCurrentThread();
while(!isClosing() && !isDisconnected()) {
if(!writeQueue.wait_dequeue_timed(writeOp, std::chrono::milliseconds(100)))
continue;
size_t offset = 0;
while(offset < writeOp.bytes.size()) {
auto writeBytes = ftdi.write(writeOp.bytes.data() + offset, (int)writeOp.bytes.size() - offset);
if(writeBytes < 0) {
if(ErrorIsDisconnection(writeBytes)) {
if(!isDisconnected()) {
setIsDisconnected(true);
report(APIEvent::Type::DeviceDisconnected, APIEvent::Severity::Error);
}
break;
} else
report(APIEvent::Type::FailedToWrite, APIEvent::Severity::EventWarning);
} else
offset += writeBytes;
}
}
}

View File

@ -2,8 +2,6 @@
#include <string_view>
#include <cstdlib>
using namespace icsneo;
#define SERVD_VERSION 1
@ -12,14 +10,7 @@ static const Address SERVD_ADDRESS = Address("127.0.0.1", 26741);
static const std::string SERVD_VERSION_STR = std::to_string(SERVD_VERSION);
bool Servd::Enabled() {
#ifdef _MSC_VER
#pragma warning(push)
#pragma warning(disable : 4996)
#endif
char* enabled = std::getenv("LIBICSNEO_USE_SERVD");
#ifdef _MSC_VER
#pragma warning(pop)
#endif
return enabled ? enabled[0] == '1' : false;
}

View File

@ -1,233 +0,0 @@
#include "icsneo/platform/windows/cdcacm.h"
#include <setupapi.h>
#include <initguid.h>
#include <usbiodef.h>
#include <devpkey.h>
using namespace icsneo;
CDCACM::CDCACM(const device_eventhandler_t& err, const std::wstring& path) : Driver(err), path(path) {
}
bool CDCACM::open() {
handle = CreateFileW(path.c_str(), GENERIC_READ | GENERIC_WRITE, 0, nullptr, OPEN_EXISTING, FILE_FLAG_OVERLAPPED, nullptr);
if(handle == INVALID_HANDLE_VALUE) {
EventManager::GetInstance().add(APIEvent::Type::SyscallError, APIEvent::Severity::Error);
return false;
}
COMMTIMEOUTS timeouts;
timeouts.ReadIntervalTimeout = MAXDWORD;
timeouts.ReadTotalTimeoutMultiplier = MAXDWORD;
timeouts.ReadTotalTimeoutConstant = MAXDWORD - 1;
timeouts.WriteTotalTimeoutMultiplier = 0;
timeouts.WriteTotalTimeoutConstant = 0;
if(!SetCommTimeouts(handle, &timeouts)) {
EventManager::GetInstance().add(APIEvent::Type::SyscallError, APIEvent::Severity::Error);
CloseHandle(handle);
handle = INVALID_HANDLE_VALUE;
return false;
}
DCB comstate;
if(!GetCommState(handle, &comstate)) {
EventManager::GetInstance().add(APIEvent::Type::SyscallError, APIEvent::Severity::Error);
CloseHandle(handle);
handle = INVALID_HANDLE_VALUE;
return false;
}
comstate.BaudRate = 115200;
comstate.ByteSize = 8;
comstate.fRtsControl = RTS_CONTROL_DISABLE;
if(!SetCommState(handle, &comstate)) {
EventManager::GetInstance().add(APIEvent::Type::SyscallError, APIEvent::Severity::Error);
CloseHandle(handle);
handle = INVALID_HANDLE_VALUE;
return false;
}
PurgeComm(handle, PURGE_RXCLEAR);
readOverlapped.hEvent = CreateEventA(nullptr, false, false, nullptr);
writeOverlapped.hEvent = CreateEventA(nullptr, false, false, nullptr);
setIsDisconnected(false);
readThread = std::thread(&CDCACM::read, this);
writeThread = std::thread(&CDCACM::write, this);
return true;
}
bool CDCACM::isOpen() {
return handle != INVALID_HANDLE_VALUE;
}
bool CDCACM::close() {
setIsClosing(true);
SetEvent(readOverlapped.hEvent); // unblock read thread
SetEvent(writeOverlapped.hEvent); // unblock write thread if waiting on COM write
writeQueue.enqueue(WriteOperation{}); // unblock write thread if waiting on write queue pop
readThread.join();
writeThread.join();
CloseHandle(readOverlapped.hEvent);
CloseHandle(writeOverlapped.hEvent);
CloseHandle(handle);
handle = INVALID_HANDLE_VALUE;
setIsClosing(false);
return true;
}
void CDCACM::read() {
EventManager::GetInstance().downgradeErrorsOnCurrentThread();
std::vector<uint8_t> buffer(ICSNEO_DRIVER_RINGBUFFER_SIZE);
while(!isDisconnected() && !isClosing()) {
if(!ReadFile(handle, buffer.data(), (DWORD)buffer.size(), nullptr, &readOverlapped)) {
if(GetLastError() != ERROR_IO_PENDING) {
EventManager::GetInstance().add(APIEvent::Type::SyscallError, APIEvent::Severity::Error);
setIsDisconnected(true);
return;
}
}
DWORD read = 0;
if(!GetOverlappedResult(handle, &readOverlapped, &read, true)) {
EventManager::GetInstance().add(APIEvent::Type::SyscallError, APIEvent::Severity::Error);
setIsDisconnected(true);
return;
}
if(read == 0) {
continue;
}
while(!isDisconnected() && !isClosing()) {
if(pushRx(buffer.data(), read))
break;
}
}
}
void CDCACM::write() {
EventManager::GetInstance().downgradeErrorsOnCurrentThread();
WriteOperation writeOp;
while(!isDisconnected() && !isClosing()) {
writeQueue.wait_dequeue(writeOp);
if(isDisconnected() || isClosing()) {
return;
}
if(!WriteFile(handle, writeOp.bytes.data(), (DWORD)writeOp.bytes.size(), nullptr, &writeOverlapped)) {
if(GetLastError() != ERROR_IO_PENDING) {
EventManager::GetInstance().add(APIEvent::Type::SyscallError, APIEvent::Severity::Error);
setIsDisconnected(true);
return;
}
}
DWORD written;
if(!GetOverlappedResult(handle, &writeOverlapped, &written, true)) {
EventManager::GetInstance().add(APIEvent::Type::SyscallError, APIEvent::Severity::Error);
setIsDisconnected(true);
return;
}
if(written != writeOp.bytes.size()) {
EventManager::GetInstance().add(APIEvent::Type::FailedToWrite, APIEvent::Severity::Error);
setIsDisconnected(true);
return;
}
}
}
class DeviceInfo {
public:
DeviceInfo() {
mDeviceInfo = SetupDiGetClassDevsW(&GUID_DEVINTERFACE_USB_DEVICE, NULL, NULL, DIGCF_PRESENT | DIGCF_DEVICEINTERFACE);
}
~DeviceInfo() {
SetupDiDestroyDeviceInfoList(mDeviceInfo);
}
operator HDEVINFO() const {
return mDeviceInfo;
}
operator bool() const {
return mDeviceInfo != INVALID_HANDLE_VALUE;
}
private:
HDEVINFO mDeviceInfo;
};
class DeviceInfoData {
public:
DeviceInfoData() {
mDeviceInfoData.cbSize = sizeof(SP_DEVINFO_DATA);
}
operator SP_DEVINFO_DATA*() {
return &mDeviceInfoData;
}
private:
SP_DEVINFO_DATA mDeviceInfoData;
};
static constexpr size_t WSTRING_ELEMENT_SIZE = sizeof(std::wstring::value_type);
void CDCACM::Find(std::vector<FoundDevice>& found) {
DeviceInfoData deviceInfoData;
const std::wstring intrepidUSB(L"USB\\VID_093C");
DeviceInfo deviceInfoSet;
if(!deviceInfoSet) {
EventManager::GetInstance().add(APIEvent::Type::SyscallError, APIEvent::Severity::Error);
return;
}
for(DWORD i = 0; SetupDiEnumDeviceInfo(deviceInfoSet, i, deviceInfoData); ++i) {
DWORD DataT;
DWORD buffersize = 0;
std::wstring wclass;
while(!SetupDiGetDevicePropertyW(deviceInfoSet, deviceInfoData, &DEVPKEY_Device_Class, &DataT, reinterpret_cast<PBYTE>(wclass.data()), static_cast<DWORD>((wclass.size() + 1) * WSTRING_ELEMENT_SIZE), &buffersize, 0)) {
wclass.resize((buffersize - 1) / WSTRING_ELEMENT_SIZE);
}
if(wclass != L"Ports") {
continue;
}
// TODO: is this a bug in Windows? why is this returned size different/wrong? It's like it's not a wstring at all
std::wstring deviceInstanceId;
while(!SetupDiGetDeviceInstanceIdW(deviceInfoSet, deviceInfoData, deviceInstanceId.data(), static_cast<DWORD>(deviceInstanceId.size() + 1), &buffersize)) {
deviceInstanceId.resize(buffersize - 1);
}
if(deviceInstanceId.find(intrepidUSB) != 0) {
continue;
}
std::wstring wserial;
while(!SetupDiGetDevicePropertyW(deviceInfoSet, deviceInfoData, &DEVPKEY_Device_BusReportedDeviceDesc, &DataT, reinterpret_cast<PBYTE>(wserial.data()), static_cast<DWORD>((wserial.size() + 1) * WSTRING_ELEMENT_SIZE), &buffersize, 0)) {
wserial.resize((buffersize - 1) / WSTRING_ELEMENT_SIZE);
}
FoundDevice device;
if(WideCharToMultiByte(CP_ACP, 0, wserial.c_str(), (int)wserial.size(), device.serial, sizeof(device.serial), NULL, NULL) == 0) {
EventManager::GetInstance().add(APIEvent::Type::SyscallError, APIEvent::Severity::Error);
continue;
}
std::wstring wport;
while(!SetupDiGetCustomDevicePropertyW(deviceInfoSet, deviceInfoData, L"PortName", 0, &DataT, reinterpret_cast<PBYTE>(wport.data()), static_cast<DWORD>((wport.size() + 1) * WSTRING_ELEMENT_SIZE), &buffersize)) {
wport.resize((buffersize - 1) / WSTRING_ELEMENT_SIZE);
}
const std::wstring path(L"\\\\.\\" + wport);
device.makeDriver = [path](device_eventhandler_t err, neodevice_t&) {
return std::make_unique<CDCACM>(err, path);
};
found.emplace_back(std::move(device));
}
}

View File

@ -1,5 +1,3 @@
#define WIN32_LEAN_AND_MEAN
#define NOMINMAX
#include <windows.h>
#include <winsock2.h>

View File

@ -1,8 +1,6 @@
#include "icsneo/platform/windows/registry.h"
#include "icsneo/platform/windows/strings.h"
#define WIN32_LEAN_AND_MEAN
#define NOMINMAX
#include <windows.h>
#include <codecvt>
#include <vector>

View File

@ -1,7 +1,4 @@
#include <string>
#define WIN32_LEAN_AND_MEAN
#define NOMINMAX
#include <Windows.h>
#include <icsneo/platform/windows/strings.h>

View File

@ -0,0 +1,471 @@
#include "icsneo/platform/windows/ftdi.h"
#include "icsneo/platform/windows/strings.h"
#include "icsneo/platform/ftdi.h"
#include "icsneo/platform/registry.h"
#include "icsneo/device/founddevice.h"
#include <windows.h>
#include <iostream>
#include <iomanip>
#include <sstream>
#include <cwctype>
#include <algorithm>
#include <codecvt>
#include <cctype>
#include <limits>
#include <stdio.h>
using namespace icsneo;
static const std::wstring DRIVER_SERVICES_REG_KEY = L"SYSTEM\\CurrentControlSet\\services\\";
static const std::wstring ALL_ENUM_REG_KEY = L"SYSTEM\\CurrentControlSet\\Enum\\";
static constexpr unsigned int RETRY_TIMES = 5;
static constexpr unsigned int RETRY_DELAY = 50;
struct VCP::Detail {
Detail() {
overlappedRead.hEvent = INVALID_HANDLE_VALUE;
overlappedWrite.hEvent = INVALID_HANDLE_VALUE;
overlappedWait.hEvent = INVALID_HANDLE_VALUE;
}
HANDLE handle = INVALID_HANDLE_VALUE;
OVERLAPPED overlappedRead = {};
OVERLAPPED overlappedWrite = {};
OVERLAPPED overlappedWait = {};
};
void VCP::Find(std::vector<FoundDevice>& found, std::vector<std::wstring> driverNames) {
for(auto& driverName : driverNames) {
std::wstringstream regss;
regss << DRIVER_SERVICES_REG_KEY << driverName << L"\\Enum\\";
std::wstring driverEnumRegKey = regss.str();
uint32_t deviceCount = 0;
if(!Registry::Get(driverEnumRegKey, L"Count", deviceCount))
continue;
for(uint32_t i = 0; i < deviceCount; i++) {
FoundDevice device;
device.makeDriver = [](const device_eventhandler_t& reportFn, neodevice_t& device) {
return std::unique_ptr<Driver>(new VCP(reportFn, device));
};
// First we want to look at what devices FTDI is enumerating (inside driverEnumRegKey)
// The entry for a ValueCAN 3 with SN 138635 looks like "FTDIBUS\VID_093C+PID_0601+138635A\0000"
// The entry for a ValueCAN 4 with SN V20227 looks like "USB\VID_093C&PID_1101\V20227"
std::wstringstream ss;
ss << i;
std::wstring entry;
if(!Registry::Get(driverEnumRegKey, ss.str(), entry))
continue;
std::transform(entry.begin(), entry.end(), entry.begin(), std::towupper);
std::wstringstream vss;
vss << "VID_" << std::setfill(L'0') << std::setw(4) << std::uppercase << std::hex << INTREPID_USB_VENDOR_ID; // Intrepid Vendor ID
if(entry.find(vss.str()) == std::wstring::npos)
continue;
auto pidpos = entry.find(L"PID_");
if(pidpos == std::wstring::npos)
continue;
// We will later use this and startchar to parse the PID
// Okay, this is a device we want
// Get the serial number
auto startchar = entry.find(L"+", pidpos + 1);
if(startchar == std::wstring::npos)
startchar = entry.find(L"\\", pidpos + 1);
bool conversionError = false;
int sn = 0;
try {
sn = std::stoi(entry.substr(startchar + 1));
}
catch(...) {
conversionError = true;
}
std::wstringstream oss;
if(!sn || conversionError)
oss << entry.substr(startchar + 1, 6); // This is a device with characters in the serial number
else
oss << sn;
device.productId = uint16_t(std::wcstol(entry.c_str() + pidpos + 4, nullptr, 16));
if(!device.productId)
continue;
std::string serial = convertWideString(oss.str());
// The serial number should not have a path slash in it. If it does, that means we don't have the real serial.
if(serial.find_first_of('\\') != std::string::npos) {
// The serial number was not in the first serenum key where we expected it.
// We can try to match the ContainerID with the one in ALL_ENUM\USB and get a serial that way
std::wstringstream uess;
uess << ALL_ENUM_REG_KEY << L"\\USB\\" << vss.str() << L"&PID_" << std::setfill(L'0') << std::setw(4)
<< std::uppercase << std::hex << device.productId << L'\\';
std::wstringstream ciss;
ciss << ALL_ENUM_REG_KEY << entry;
std::wstring containerIDFromEntry, containerIDFromEnum;
if(!Registry::Get(ciss.str(), L"ContainerID", containerIDFromEntry))
continue; // We did not get a container ID. This can happen on Windows XP and before.
if(containerIDFromEntry.empty())
continue; // The container ID was empty?
std::vector<std::wstring> subkeys;
if(!Registry::EnumerateSubkeys(uess.str(), subkeys))
continue; // VID/PID combo was not present at all.
if(subkeys.empty())
continue; // No devices for VID/PID.
std::wstring correctSerial;
for(auto& subkey : subkeys) {
std::wstringstream skss;
skss << uess.str() << L'\\' << subkey;
if(!Registry::Get(skss.str(), L"ContainerID", containerIDFromEnum))
continue;
if(containerIDFromEntry != containerIDFromEnum)
continue;
correctSerial = subkey;
break;
}
if(correctSerial.empty())
continue; // Didn't find the device within the subkeys of the enumeration
sn = 0;
conversionError = false;
try {
sn = std::stoi(correctSerial);
}
catch(...) {
conversionError = true;
}
if(!sn || conversionError) {
// This is a device with characters in the serial number
if(correctSerial.size() != 6)
continue;
serial = convertWideString(correctSerial);
}
else {
std::wstringstream soss;
soss << sn;
serial = convertWideString(soss.str());
}
if(serial.find_first_of('\\') != std::string::npos)
continue;
}
for(char& c : serial)
c = static_cast<char>(toupper(c));
strcpy_s(device.serial, sizeof(device.serial), serial.c_str());
// Serial number is saved, we want the COM port number now
// This will be stored under ALL_ENUM_REG_KEY\entry\Device Parameters\PortName (entry from the FTDI_ENUM)
std::wstringstream dpss;
dpss << ALL_ENUM_REG_KEY << entry << L"\\Device Parameters";
std::wstring port;
Registry::Get(dpss.str(), L"PortName", port); // TODO If error do something else (Plasma maybe?)
std::transform(port.begin(), port.end(), port.begin(), std::towupper);
auto compos = port.find(L"COM");
device.handle = 0;
if(compos != std::wstring::npos) {
try {
device.handle = std::stoi(port.substr(compos + 3));
}
catch(...) {} // In case of this, or any other error, handle has already been initialized to 0
}
bool alreadyFound = false;
FoundDevice* shouldReplace = nullptr;
for(auto& foundDev : found) {
if((foundDev.handle == device.handle || foundDev.handle == 0 || device.handle == 0) && serial == foundDev.serial) {
alreadyFound = true;
if(foundDev.handle == 0)
shouldReplace = &foundDev;
break;
}
}
if(!alreadyFound)
found.push_back(device);
else if(shouldReplace != nullptr)
*shouldReplace = device;
}
}
}
VCP::VCP(const device_eventhandler_t& err, neodevice_t& forDevice) : Driver(err), device(forDevice) {
detail = std::make_shared<Detail>();
}
VCP::~VCP() {
if(isOpen())
close();
}
bool VCP::IsHandleValid(neodevice_handle_t handle) {
if(handle < 1)
return false;
if(handle > 256) // Windows default max COM port is COM256
return false; // TODO Enumerate subkeys of HKLM\HARDWARE\DEVICEMAP\SERIALCOMM as a user might have more serial ports somehow
return true;
}
bool VCP::open(bool fromAsync) {
if(isOpen() || (!fromAsync && opening)) {
report(APIEvent::Type::DeviceCurrentlyOpen, APIEvent::Severity::Error);
return false;
}
if(!IsHandleValid(device.handle)) {
report(APIEvent::Type::DriverFailedToOpen, APIEvent::Severity::Error);
return false;
}
opening = true;
std::wstringstream comss;
comss << L"\\\\.\\COM" << device.handle;
// We're going to attempt to open 5 (RETRY_TIMES) times in a row
for(int i = 0; !isOpen() && i < RETRY_TIMES; i++) {
detail->handle = CreateFileW(comss.str().c_str(), GENERIC_READ | GENERIC_WRITE, 0, nullptr,
OPEN_EXISTING, FILE_FLAG_OVERLAPPED, nullptr);
if(GetLastError() == ERROR_SUCCESS)
break; // We have the file handle
std::this_thread::sleep_for(std::chrono::milliseconds(RETRY_DELAY));
}
opening = false;
if(!isOpen()) {
report(APIEvent::Type::DriverFailedToOpen, APIEvent::Severity::Error);
return false;
}
// Set the timeouts
COMMTIMEOUTS timeouts;
if(!GetCommTimeouts(detail->handle, &timeouts)) {
close();
report(APIEvent::Type::DriverFailedToOpen, APIEvent::Severity::Error);
return false;
}
// See https://docs.microsoft.com/en-us/windows/desktop/api/winbase/ns-winbase-_commtimeouts#remarks
timeouts.ReadIntervalTimeout = MAXDWORD;
timeouts.ReadTotalTimeoutMultiplier = MAXDWORD;
timeouts.ReadTotalTimeoutConstant = 100;
timeouts.WriteTotalTimeoutConstant = 10000;
timeouts.WriteTotalTimeoutMultiplier = 0;
if(!SetCommTimeouts(detail->handle, &timeouts)) {
close();
report(APIEvent::Type::DriverFailedToOpen, APIEvent::Severity::Error);
return false;
}
// Set the COM state
DCB comstate;
if(!GetCommState(detail->handle, &comstate)) {
close();
report(APIEvent::Type::DriverFailedToOpen, APIEvent::Severity::Error);
return false;
}
comstate.BaudRate = 115200;
comstate.ByteSize = 8;
comstate.Parity = NOPARITY;
comstate.StopBits = 0;
comstate.fDtrControl = DTR_CONTROL_ENABLE;
comstate.fRtsControl = RTS_CONTROL_ENABLE;
if(!SetCommState(detail->handle, &comstate)) {
close();
report(APIEvent::Type::DriverFailedToOpen, APIEvent::Severity::Error);
return false;
}
PurgeComm(detail->handle, PURGE_RXCLEAR);
// Set up events so that overlapped IO can work with them
detail->overlappedRead.hEvent = CreateEvent(nullptr, false, false, nullptr);
detail->overlappedWrite.hEvent = CreateEvent(nullptr, false, false, nullptr);
detail->overlappedWait.hEvent = CreateEvent(nullptr, true, false, nullptr);
if (detail->overlappedRead.hEvent == nullptr || detail->overlappedWrite.hEvent == nullptr || detail->overlappedWait.hEvent == nullptr) {
close();
report(APIEvent::Type::DriverFailedToOpen, APIEvent::Severity::Error);
return false;
}
// Set up event so that we will satisfy overlappedWait when a character comes in
if(!SetCommMask(detail->handle, EV_RXCHAR)) {
close();
report(APIEvent::Type::DriverFailedToOpen, APIEvent::Severity::Error);
return false;
}
// TODO Set up some sort of shared memory, save which COM port we have open so we don't try to open it again
// Create threads
readThread = std::thread(&VCP::readTask, this);
writeThread = std::thread(&VCP::writeTask, this);
return true;
}
void VCP::openAsync(fn_boolCallback callback) {
threads.push_back(std::make_shared<std::thread>([&]() {
callback(open(true));
}));
}
bool VCP::close() {
if(!isOpen()) {
report(APIEvent::Type::DeviceCurrentlyClosed, APIEvent::Severity::Error);
return false;
}
setIsClosing(true); // Signal the threads that we are closing
for(auto& t : threads)
t->join(); // Wait for the threads to close
readThread.join();
writeThread.join();
setIsClosing(false);
if(!CloseHandle(detail->handle)) {
report(APIEvent::Type::DriverFailedToClose, APIEvent::Severity::Error);
return false;
}
detail->handle = INVALID_HANDLE_VALUE;
bool ret = true; // If one of the events fails closing, we probably still want to try and close the others
if(detail->overlappedRead.hEvent != INVALID_HANDLE_VALUE) {
if(!CloseHandle(detail->overlappedRead.hEvent))
ret = false;
detail->overlappedRead.hEvent = INVALID_HANDLE_VALUE;
}
if(detail->overlappedWrite.hEvent != INVALID_HANDLE_VALUE) {
if(!CloseHandle(detail->overlappedWrite.hEvent))
ret = false;
detail->overlappedWrite.hEvent = INVALID_HANDLE_VALUE;
}
if(detail->overlappedWait.hEvent != INVALID_HANDLE_VALUE) {
if(!CloseHandle(detail->overlappedWait.hEvent))
ret = false;
detail->overlappedWait.hEvent = INVALID_HANDLE_VALUE;
}
clearBuffers();
if(!ret)
report(APIEvent::Type::DriverFailedToClose, APIEvent::Severity::Error);
// TODO Set up some sort of shared memory, free which COM port we had open so we can try to open it again
return ret;
}
bool VCP::isOpen() {
return detail->handle != INVALID_HANDLE_VALUE;
}
void VCP::readTask() {
constexpr size_t READ_BUFFER_SIZE = 10240;
uint8_t readbuf[READ_BUFFER_SIZE];
IOTaskState state = LAUNCH;
DWORD bytesRead = 0;
EventManager::GetInstance().downgradeErrorsOnCurrentThread();
while(!isClosing() && !isDisconnected()) {
switch(state) {
case LAUNCH: {
COMSTAT comStatus;
unsigned long errorCodes;
ClearCommError(detail->handle, &errorCodes, &comStatus);
bytesRead = 0;
if(ReadFile(detail->handle, readbuf, READ_BUFFER_SIZE, nullptr, &detail->overlappedRead)) {
if(GetOverlappedResult(detail->handle, &detail->overlappedRead, &bytesRead, FALSE)) {
if(bytesRead)
pushRx(readbuf, bytesRead);
}
continue;
}
auto lastError = GetLastError();
if(lastError == ERROR_IO_PENDING)
state = WAIT;
else if(lastError != ERROR_SUCCESS) {
if(lastError == ERROR_ACCESS_DENIED) {
if(!isDisconnected()) {
setIsDisconnected(true);
report(APIEvent::Type::DeviceDisconnected, APIEvent::Severity::Error);
}
} else
report(APIEvent::Type::FailedToRead, APIEvent::Severity::Error);
}
}
break;
case WAIT: {
auto ret = WaitForSingleObject(detail->overlappedRead.hEvent, 100);
if(ret == WAIT_OBJECT_0) {
if(GetOverlappedResult(detail->handle, &detail->overlappedRead, &bytesRead, FALSE)) {
pushRx(readbuf, bytesRead);
state = LAUNCH;
} else
report(APIEvent::Type::FailedToRead, APIEvent::Severity::Error);
}
if(ret == WAIT_ABANDONED || ret == WAIT_FAILED) {
state = LAUNCH;
report(APIEvent::Type::FailedToRead, APIEvent::Severity::Error);
}
}
}
}
}
void VCP::writeTask() {
IOTaskState state = LAUNCH;
VCP::WriteOperation writeOp;
DWORD bytesWritten = 0;
EventManager::GetInstance().downgradeErrorsOnCurrentThread();
while(!isClosing() && !isDisconnected()) {
switch(state) {
case LAUNCH: {
if(!writeQueue.wait_dequeue_timed(writeOp, std::chrono::milliseconds(100)))
continue;
bytesWritten = 0;
if(WriteFile(detail->handle, writeOp.bytes.data(), (DWORD)writeOp.bytes.size(), nullptr, &detail->overlappedWrite))
continue;
auto winerr = GetLastError();
if(winerr == ERROR_IO_PENDING) {
state = WAIT;
}
else if(winerr == ERROR_ACCESS_DENIED) {
if(!isDisconnected()) {
setIsDisconnected(true);
report(APIEvent::Type::DeviceDisconnected, APIEvent::Severity::Error);
}
} else
report(APIEvent::Type::FailedToWrite, APIEvent::Severity::Error);
}
break;
case WAIT: {
auto ret = WaitForSingleObject(detail->overlappedWrite.hEvent, 50);
if(ret == WAIT_OBJECT_0) {
if(!GetOverlappedResult(detail->handle, &detail->overlappedWrite, &bytesWritten, FALSE))
report(APIEvent::Type::FailedToWrite, APIEvent::Severity::Error);
state = LAUNCH;
}
if(ret == WAIT_ABANDONED) {
report(APIEvent::Type::FailedToWrite, APIEvent::Severity::Error);
state = LAUNCH;
}
}
}
}
}

53
third-party/libftdi/.gitignore vendored 100644
View File

@ -0,0 +1,53 @@
# Normal stuff
*.o
*.a
*.so
*.lo
*.la
*.pc
.deps/
.libs/
.kdev4/
build/
# kdevelop
*.kdevelop.pcs
*.kdevses
# Doxygen documentation
Doxyfile
Doxyfile.xml
doc/Doxyfile
doc/html
doc/man
doc/xml
# examples
examples/baud_test
examples/bitbang
examples/bitbang2
examples/bitbang_cbus
examples/bitbang_ft2232
examples/find_all
examples/find_all_pp
examples/serial_test
examples/simple
# Backup files and stuff from patches
*.orig
*.rej
*~
.*.swp
# libftdi specific
libftdi1-config
libftdi1.spec
# CMake
CMakeCache.txt
cmake_install.cmake
CMakeFiles
# Misc. binaries
*.dylib
opt

79
third-party/libftdi/AUTHORS vendored 100644
View File

@ -0,0 +1,79 @@
Main developers:
Intra2net AG <opensource@intra2net.com>
Contributors in alphabetical order,
see Changelog for full details:
Adam Malinowski <amalinowski75@gmail.com>
Alain Abbas <aa@libertech.fr>
Alexander Lehmann <lehmanna@in.tum.de>
Alex Harford <harford@gmail.com>
Anders Larsen <al@alarsen.net>
Andrei Errapart <a.errapart@trenz-electronic.de>
Andrew John Rogers <andrew@rogerstech.co.uk>
Arnim Läuger <arnim.laeuger@gmx.net>
Aurelien Jarno <aurelien@aurel32.net>
Benjamin Vanheuverzwijn <bvanheu@gmail.com>
Chris Morgan <chmorgan@gmail.com>
Chris Zeh <chris.w.zeh@gmail.com>
Clifford Wolf <clifford@clifford.at>
Daniel Kirkham <dk2@kirkham.id.au>
David Challis <dchallis@qsimaging.com>
Davide Michelizza <dmichelizza@gmail.com>
Denis Sirotkin <reg.libftdi@demitel.ru>
Emil <emil@datel.co.uk>
Eric Schott <eric@morningjoy.com>
Eugene Hutorny <eugene@hutorny.in.ua>
Evan Nemerson <evan@coeus-group.com>
Evgeny Sinelnikov <sin@geoft.ru>
Fahrzin Hemmati <fahhem@gmail.com>
Flynn Marquardt <ftdi@flynnux.de>
Forest Crossman <cyrozap@gmail.com>
Ian Abbott <abbotti@mev.co.uk>
Jared Boone <jared@sharebrained.com>
Jarkko Sonninen <kasper@iki.fi>
Jean-Daniel Merkli <jdmerkli@computerscience.ch>
Jochen Sprickerhof <jochen@sprickerhof.de>
Joe Zbiciak <intvnut@gmail.com>
Jon Beniston <jon@beniston.com>
Juergen Beisert <juergen.beisert@weihenstephan.org>
Lorenz Moesenlechner <lorenz@hcilab.org>
Marek Vavruša <marek@vavrusa.com>
Marius Kintel <kintel@sim.no>
Mark Hämmerling <mail@markh.de>
Matthias Janke <janke@physi.uni-heidelberg.de>
Matthias Kranz <matthias@hcilab.org>
Matthias Richter <mail.to.mr@gmx.de>
Matthijs ten Berge <m.h.tenberge@alumnus.utwente.nl>
Max <max@koeln.ccc.de>
Maxwell Dreytser <admin@mdtech.us>
Michel Zou <xantares09@hotmail.com>
Mike Frysinger <vapier.adi@gmail.com>
Nathael Pajani <nathael.pajani@ed3l.fr>
Nathan Fraser <ndf@undershorts.org>
Oleg Seiljus <oseiljus@xverve.com>
Paul Fertser <fercerpav@gmail.com>
Peter Holik <peter@holik.at>
Raphael Assenat <raph@8d.com>
Robert Cox <Robert.cox@novatechweb.com>
Robin Haberkorn <haberkorn@metratec.com>
Rodney Sinclair <rodney@sinclairrf.com>
Rogier Wolff <R.E.Wolff@harddisk-recovery.nl>
Rolf Fiedler <derRolf@gmx-topmail.de>
Salvador Eduardo Tropea <salvador@inti.gob.ar>
Stephan Linz <linz@li-pro.net>
Steven Turner <steven.turner@ftdichip.com>
Tarek Heiland <tarek@illimitable.com>
Thilo Schulz <thilo@tjps.eu>
Thimo Eichstaedt <abc@digithi.de>
Thomas Fischl <fischl@fundf.net>
Thomas Klose <thomas.klose@hiperscan.com>
Tim Ansell <mithro@mithis.com>
Tom Saunders <trsaunders@gmail.com>
Uwe Bonnes <bon@elektron.ikp.physik.tu-darmstadt.de>
Vladimir Yakovlev <nagos@inbox.ru>
Wilfried Holzke <libftdi@holzke.net>
Xiaofan Chen <xiaofanc@gmail.com>
Yegor Yefremov <yegorslists@googlemail.com>
Yi-Shin Li <ysli@araisrobo.com>

View File

@ -0,0 +1,250 @@
# Project
project(libftdi1)
set(MAJOR_VERSION 1)
set(MINOR_VERSION 4)
set(PACKAGE libftdi1)
set(VERSION_STRING ${MAJOR_VERSION}.${MINOR_VERSION})
set(VERSION ${VERSION_STRING})
set(CMAKE_MODULE_PATH ${PROJECT_SOURCE_DIR}/cmake)
# CMake
if("${CMAKE_BUILD_TYPE}" STREQUAL "")
set(CMAKE_BUILD_TYPE RelWithDebInfo)
endif("${CMAKE_BUILD_TYPE}" STREQUAL "")
set(CMAKE_COLOR_MAKEFILE ON)
cmake_minimum_required(VERSION 3.16 FATAL_ERROR)
add_definitions(-Wall)
# Debug build
message("-- Build type: ${CMAKE_BUILD_TYPE}")
if(${CMAKE_BUILD_TYPE} STREQUAL Debug)
add_definitions(-DDEBUG)
endif(${CMAKE_BUILD_TYPE} STREQUAL Debug)
# find libusb
find_package ( USB1 REQUIRED )
include_directories ( ${LIBUSB_INCLUDE_DIR} )
# Find Boost (optional package)
find_package(Boost)
# Set components
set(CPACK_COMPONENTS_ALL sharedlibs staticlibs headers)
set(CPACK_COMPONENT_SHAREDLIBS_DISPLAY_NAME "Shared libraries")
set(CPACK_COMPONENT_STATICLIBS_DISPLAY_NAME "Static libraries")
set(CPACK_COMPONENT_HEADERS_DISPLAY_NAME "C++ Headers")
set(CPACK_COMPONENT_SHAREDLIBS_DESCRIPTION
"Shared library for general use.")
set(CPACK_COMPONENT_STATICLIBS_DESCRIPTION
"Static library, good if you want to embed libftdi1 in your application.")
set(CPACK_COMPONENT_HEADERS_DESCRIPTION
"C/C++ header files.")
set(CPACK_COMPONENT_SHAREDLIBS_GROUP "Development")
set(CPACK_COMPONENT_STATICLIBS_GROUP "Development")
set(CPACK_COMPONENT_HEADERS_GROUP "Development")
option ( LIBFTDI_INSTALL "Generate install step" ON )
option ( LIBFTDI_STATICLIBS "Build static libraries" ON )
# guess LIB_SUFFIX, don't take debian multiarch into account
if ( NOT DEFINED LIB_SUFFIX )
if( CMAKE_SYSTEM_NAME MATCHES "Linux"
AND NOT CMAKE_CROSSCOMPILING
AND NOT EXISTS "/etc/debian_version"
AND NOT EXISTS "/etc/arch-release" )
if ( "${CMAKE_SIZEOF_VOID_P}" EQUAL "8" )
set ( LIB_SUFFIX 64 )
endif ()
endif ()
endif ()
if(NOT APPLE)
if(CMAKE_SIZEOF_VOID_P EQUAL 4)
SET(PACK_ARCH "")
else(CMAKE_SIZEOF_VOID_P EQUAL 8)
SET(PACK_ARCH .x86_64)
endif(CMAKE_SIZEOF_VOID_P EQUAL 4)
else(NOT APPLE)
SET(PACK_ARCH "")
endif(NOT APPLE)
# Package information
set(CPACK_PACKAGE_VERSION ${VERSION_STRING})
set(CPACK_PACKAGE_CONTACT "Intra2net AG <libftdi@developer.intra2net.com>")
set(CPACK_PACKAGE_DESCRIPTION "libftdi1 library.")
set(CPACK_PACKAGE_DESCRIPTION_SUMMARY ${CPACK_PACKAGE_DESCRIPTION}
)
# Package settings
if ( UNIX )
set(CPACK_GENERATOR "DEB;RPM")
set(CPACK_CMAKE_GENERATOR "Unix Makefiles")
set(CPACK_PACKAGE_NAME ${PROJECT_NAME})
set(CPACK_PACKAGE_FILE_NAME ${CPACK_PACKAGE_NAME}-${CPACK_PACKAGE_VERSION}${PACK_ARCH})
endif ()
if ( WIN32 )
set ( CPACK_GENERATOR "NSIS" )
set ( CPACK_CMAKE_GENERATOR "MinGW Makefiles" )
set ( CPACK_PACKAGE_NAME "${PROJECT_NAME}" )
set ( CPACK_PACKAGE_VENDOR "" )
set ( CPACK_PACKAGE_INSTALL_DIRECTORY "libftdi1" )
set ( CPACK_PACKAGE_FILE_NAME "${PROJECT_NAME}-${VERSION_STRING}-win32")
set ( CPACK_NSIS_DISPLAY_NAME "libftdi1" )
set ( CPACK_NSIS_MODIFY_PATH ON )
endif ()
set(CPACK_RESOURCE_FILE_LICENSE ${PROJECT_SOURCE_DIR}/LICENSE)
set(CPACK_SOURCE_GENERATOR TGZ)
set(CPACK_SOURCE_IGNORE_FILES "\\\\.git;~$;build/")
set(CPACK_SOURCE_PACKAGE_FILE_NAME ${CPACK_PACKAGE_NAME}-${CPACK_PACKAGE_VERSION})
# Subdirectories
if ( UNIX )
set ( CPACK_SET_DESTDIR ON )
endif ()
# "make dist" target
set(ARCHIVE_NAME ${CMAKE_PROJECT_NAME}-${VERSION_STRING})
add_custom_target(dist
COMMAND git archive --prefix=${ARCHIVE_NAME}/ HEAD
| bzip2 > ${CMAKE_BINARY_DIR}/${ARCHIVE_NAME}.tar.bz2
WORKING_DIRECTORY ${PROJECT_SOURCE_DIR})
# Tests
option ( LIBFTDI_BUILD_TESTS "Build unit tests with Boost Unit Test framework" ON )
# Documentation
option ( LIBFTDI_DOCUMENTATION "Generate API documentation with Doxygen" ON )
find_package ( Doxygen )
if ( LIBFTDI_DOCUMENTATION AND DOXYGEN_FOUND )
# Find doxy config
message(STATUS "Doxygen found.")
# Copy doxy.config.in
set(top_srcdir ${PROJECT_SOURCE_DIR})
configure_file(${PROJECT_SOURCE_DIR}/doc/Doxyfile.in ${CMAKE_BINARY_DIR}/Doxyfile )
configure_file(${PROJECT_SOURCE_DIR}/doc/Doxyfile.xml.in ${CMAKE_BINARY_DIR}/Doxyfile.xml )
# Run doxygen
add_custom_command(
OUTPUT ${CMAKE_BINARY_DIR}/doc/html/index.html
COMMAND ${CMAKE_COMMAND} -E make_directory ${CMAKE_BINARY_DIR}/doc
COMMAND ${DOXYGEN_EXECUTABLE} ${CMAKE_BINARY_DIR}/Doxyfile
DEPENDS ${c_headers};${c_sources};${cpp_sources};${cpp_headers}
)
add_custom_target(docs ALL DEPENDS ${CMAKE_BINARY_DIR}/doc/html/index.html)
message(STATUS "Generating API documentation with Doxygen")
else(LIBFTDI_DOCUMENTATION AND DOXYGEN_FOUND)
message(STATUS "Not generating API documentation")
endif(LIBFTDI_DOCUMENTATION AND DOXYGEN_FOUND)
add_subdirectory(src)
add_subdirectory(ftdipp)
add_subdirectory(python)
add_subdirectory(ftdi_eeprom)
add_subdirectory(packages)
add_subdirectory(test)
# PkgConfig
set(prefix ${CMAKE_INSTALL_PREFIX})
set(exec_prefix ${CMAKE_INSTALL_PREFIX}/bin)
set(includedir ${CMAKE_INSTALL_PREFIX}/include/${PROJECT_NAME})
if(${UNIX})
set(libdir ${CMAKE_INSTALL_PREFIX}/lib${LIB_SUFFIX})
endif(${UNIX})
if(${WIN32})
set(libdir ${CMAKE_INSTALL_PREFIX}/bin)
endif(${WIN32})
configure_file(${PROJECT_SOURCE_DIR}/libftdi1.spec.in ${CMAKE_BINARY_DIR}/libftdi1.spec @ONLY)
configure_file(${PROJECT_SOURCE_DIR}/libftdi1.pc.in ${CMAKE_BINARY_DIR}/libftdi1.pc @ONLY)
configure_file(${PROJECT_SOURCE_DIR}/libftdipp1.pc.in ${CMAKE_BINARY_DIR}/libftdipp1.pc @ONLY)
if (LIBFTDI_INSTALL)
install(FILES ${CMAKE_BINARY_DIR}/libftdi1.pc ${CMAKE_BINARY_DIR}/libftdipp1.pc
DESTINATION lib${LIB_SUFFIX}/pkgconfig)
endif()
if (UNIX OR MINGW)
configure_file ( libftdi1-config.in ${CMAKE_CURRENT_BINARY_DIR}/libftdi1-config @ONLY )
if (LIBFTDI_INSTALL)
install ( PROGRAMS ${CMAKE_CURRENT_BINARY_DIR}/libftdi1-config
DESTINATION bin )
endif()
endif ()
# config script install path
if ( NOT DEFINED LIBFTDI_CMAKE_CONFIG_DIR )
set ( LIBFTDI_CMAKE_CONFIG_DIR lib${LIB_SUFFIX}/cmake/libftdi1 )
endif ()
set ( LIBFTDI_INCLUDE_DIR ${includedir} )
set ( LIBFTDI_INCLUDE_DIRS ${LIBFTDI_INCLUDE_DIR} )
set ( LIBFTDI_LIBRARY ftdi1 )
set ( LIBFTDI_LIBRARIES ${LIBFTDI_LIBRARY} )
list ( APPEND LIBFTDI_LIBRARIES ${LIBUSB_LIBRARIES} )
set ( LIBFTDI_STATIC_LIBRARY ftdi1.a )
set ( LIBFTDI_STATIC_LIBRARIES ${LIBFTDI_STATIC_LIBRARY} )
list ( APPEND LIBFTDI_STATIC_LIBRARIES ${LIBUSB_LIBRARIES} )
if (FTDI_BUILD_CPP)
set ( LIBFTDIPP_LIBRARY ftdipp1 )
set ( LIBFTDIPP_LIBRARIES ${LIBFTDIPP_LIBRARY} )
list ( APPEND LIBFTDIPP_LIBRARIES ${LIBUSB_LIBRARIES} )
endif ()
set ( LIBFTDI_LIBRARY_DIRS ${libdir} )
set ( LIBFTDI_ROOT_DIR ${prefix} )
set ( LIBFTDI_VERSION_STRING ${VERSION_STRING} )
set ( LIBFTDI_VERSION_MAJOR ${MAJOR_VERSION} )
set ( LIBFTDI_VERSION_MINOR ${MINOR_VERSION} )
set ( LIBFTDI_USE_FILE ${CMAKE_INSTALL_PREFIX}/${LIBFTDI_CMAKE_CONFIG_DIR}/UseLibFTDI1.cmake )
if(CMAKE_VERSION VERSION_LESS 2.8.8)
configure_file ( cmake/LibFTDI1Config.cmake.in ${CMAKE_CURRENT_BINARY_DIR}/LibFTDI1Config.cmake @ONLY )
configure_file ( cmake/LibFTDI1ConfigVersion.cmake.in ${CMAKE_CURRENT_BINARY_DIR}/LibFTDI1ConfigVersion.cmake @ONLY )
else ()
include(CMakePackageConfigHelpers)
configure_package_config_file (
cmake/LibFTDI1Config.cmake.in
${CMAKE_CURRENT_BINARY_DIR}/LibFTDI1Config.cmake
INSTALL_DESTINATION ${LIBFTDI_CMAKE_CONFIG_DIR}
PATH_VARS
LIBFTDI_USE_FILE
LIBFTDI_ROOT_DIR
LIBFTDI_INCLUDE_DIR
LIBFTDI_INCLUDE_DIRS
LIBFTDI_LIBRARY_DIRS
NO_CHECK_REQUIRED_COMPONENTS_MACRO
)
write_basic_package_version_file (
LibFTDI1ConfigVersion.cmake
VERSION ${LIBFTDI_VERSION_STRING}
COMPATIBILITY AnyNewerVersion
)
endif ()
if (LIBFTDI_INSTALL)
install ( FILES
${CMAKE_CURRENT_BINARY_DIR}/LibFTDI1Config.cmake
${CMAKE_CURRENT_BINARY_DIR}/LibFTDI1ConfigVersion.cmake
cmake/UseLibFTDI1.cmake
DESTINATION ${LIBFTDI_CMAKE_CONFIG_DIR}
)
endif (LIBFTDI_INSTALL)
include(CPack)

View File

@ -0,0 +1,22 @@
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions
are met:
1. Redistributions of source code must retain the copyright
notice, this list of conditions and the following disclaimer.
2. Redistributions in binary form must reproduce the copyright
notice, this list of conditions and the following disclaimer in the
documentation and/or other materials provided with the distribution.
3. The name of the author may not be used to endorse or promote products
derived from this software without specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

339
third-party/libftdi/COPYING.GPL vendored 100644
View File

@ -0,0 +1,339 @@
GNU GENERAL PUBLIC LICENSE
Version 2, June 1991
Copyright (C) 1989, 1991 Free Software Foundation, Inc.,
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
Everyone is permitted to copy and distribute verbatim copies
of this license document, but changing it is not allowed.
Preamble
The licenses for most software are designed to take away your
freedom to share and change it. By contrast, the GNU General Public
License is intended to guarantee your freedom to share and change free
software--to make sure the software is free for all its users. This
General Public License applies to most of the Free Software
Foundation's software and to any other program whose authors commit to
using it. (Some other Free Software Foundation software is covered by
the GNU Lesser General Public License instead.) You can apply it to
your programs, too.
When we speak of free software, we are referring to freedom, not
price. Our General Public Licenses are designed to make sure that you
have the freedom to distribute copies of free software (and charge for
this service if you wish), that you receive source code or can get it
if you want it, that you can change the software or use pieces of it
in new free programs; and that you know you can do these things.
To protect your rights, we need to make restrictions that forbid
anyone to deny you these rights or to ask you to surrender the rights.
These restrictions translate to certain responsibilities for you if you
distribute copies of the software, or if you modify it.
For example, if you distribute copies of such a program, whether
gratis or for a fee, you must give the recipients all the rights that
you have. You must make sure that they, too, receive or can get the
source code. And you must show them these terms so they know their
rights.
We protect your rights with two steps: (1) copyright the software, and
(2) offer you this license which gives you legal permission to copy,
distribute and/or modify the software.
Also, for each author's protection and ours, we want to make certain
that everyone understands that there is no warranty for this free
software. If the software is modified by someone else and passed on, we
want its recipients to know that what they have is not the original, so
that any problems introduced by others will not reflect on the original
authors' reputations.
Finally, any free program is threatened constantly by software
patents. We wish to avoid the danger that redistributors of a free
program will individually obtain patent licenses, in effect making the
program proprietary. To prevent this, we have made it clear that any
patent must be licensed for everyone's free use or not licensed at all.
The precise terms and conditions for copying, distribution and
modification follow.
GNU GENERAL PUBLIC LICENSE
TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
0. This License applies to any program or other work which contains
a notice placed by the copyright holder saying it may be distributed
under the terms of this General Public License. The "Program", below,
refers to any such program or work, and a "work based on the Program"
means either the Program or any derivative work under copyright law:
that is to say, a work containing the Program or a portion of it,
either verbatim or with modifications and/or translated into another
language. (Hereinafter, translation is included without limitation in
the term "modification".) Each licensee is addressed as "you".
Activities other than copying, distribution and modification are not
covered by this License; they are outside its scope. The act of
running the Program is not restricted, and the output from the Program
is covered only if its contents constitute a work based on the
Program (independent of having been made by running the Program).
Whether that is true depends on what the Program does.
1. You may copy and distribute verbatim copies of the Program's
source code as you receive it, in any medium, provided that you
conspicuously and appropriately publish on each copy an appropriate
copyright notice and disclaimer of warranty; keep intact all the
notices that refer to this License and to the absence of any warranty;
and give any other recipients of the Program a copy of this License
along with the Program.
You may charge a fee for the physical act of transferring a copy, and
you may at your option offer warranty protection in exchange for a fee.
2. You may modify your copy or copies of the Program or any portion
of it, thus forming a work based on the Program, and copy and
distribute such modifications or work under the terms of Section 1
above, provided that you also meet all of these conditions:
a) You must cause the modified files to carry prominent notices
stating that you changed the files and the date of any change.
b) You must cause any work that you distribute or publish, that in
whole or in part contains or is derived from the Program or any
part thereof, to be licensed as a whole at no charge to all third
parties under the terms of this License.
c) If the modified program normally reads commands interactively
when run, you must cause it, when started running for such
interactive use in the most ordinary way, to print or display an
announcement including an appropriate copyright notice and a
notice that there is no warranty (or else, saying that you provide
a warranty) and that users may redistribute the program under
these conditions, and telling the user how to view a copy of this
License. (Exception: if the Program itself is interactive but
does not normally print such an announcement, your work based on
the Program is not required to print an announcement.)
These requirements apply to the modified work as a whole. If
identifiable sections of that work are not derived from the Program,
and can be reasonably considered independent and separate works in
themselves, then this License, and its terms, do not apply to those
sections when you distribute them as separate works. But when you
distribute the same sections as part of a whole which is a work based
on the Program, the distribution of the whole must be on the terms of
this License, whose permissions for other licensees extend to the
entire whole, and thus to each and every part regardless of who wrote it.
Thus, it is not the intent of this section to claim rights or contest
your rights to work written entirely by you; rather, the intent is to
exercise the right to control the distribution of derivative or
collective works based on the Program.
In addition, mere aggregation of another work not based on the Program
with the Program (or with a work based on the Program) on a volume of
a storage or distribution medium does not bring the other work under
the scope of this License.
3. You may copy and distribute the Program (or a work based on it,
under Section 2) in object code or executable form under the terms of
Sections 1 and 2 above provided that you also do one of the following:
a) Accompany it with the complete corresponding machine-readable
source code, which must be distributed under the terms of Sections
1 and 2 above on a medium customarily used for software interchange; or,
b) Accompany it with a written offer, valid for at least three
years, to give any third party, for a charge no more than your
cost of physically performing source distribution, a complete
machine-readable copy of the corresponding source code, to be
distributed under the terms of Sections 1 and 2 above on a medium
customarily used for software interchange; or,
c) Accompany it with the information you received as to the offer
to distribute corresponding source code. (This alternative is
allowed only for noncommercial distribution and only if you
received the program in object code or executable form with such
an offer, in accord with Subsection b above.)
The source code for a work means the preferred form of the work for
making modifications to it. For an executable work, complete source
code means all the source code for all modules it contains, plus any
associated interface definition files, plus the scripts used to
control compilation and installation of the executable. However, as a
special exception, the source code distributed need not include
anything that is normally distributed (in either source or binary
form) with the major components (compiler, kernel, and so on) of the
operating system on which the executable runs, unless that component
itself accompanies the executable.
If distribution of executable or object code is made by offering
access to copy from a designated place, then offering equivalent
access to copy the source code from the same place counts as
distribution of the source code, even though third parties are not
compelled to copy the source along with the object code.
4. You may not copy, modify, sublicense, or distribute the Program
except as expressly provided under this License. Any attempt
otherwise to copy, modify, sublicense or distribute the Program is
void, and will automatically terminate your rights under this License.
However, parties who have received copies, or rights, from you under
this License will not have their licenses terminated so long as such
parties remain in full compliance.
5. You are not required to accept this License, since you have not
signed it. However, nothing else grants you permission to modify or
distribute the Program or its derivative works. These actions are
prohibited by law if you do not accept this License. Therefore, by
modifying or distributing the Program (or any work based on the
Program), you indicate your acceptance of this License to do so, and
all its terms and conditions for copying, distributing or modifying
the Program or works based on it.
6. Each time you redistribute the Program (or any work based on the
Program), the recipient automatically receives a license from the
original licensor to copy, distribute or modify the Program subject to
these terms and conditions. You may not impose any further
restrictions on the recipients' exercise of the rights granted herein.
You are not responsible for enforcing compliance by third parties to
this License.
7. If, as a consequence of a court judgment or allegation of patent
infringement or for any other reason (not limited to patent issues),
conditions are imposed on you (whether by court order, agreement or
otherwise) that contradict the conditions of this License, they do not
excuse you from the conditions of this License. If you cannot
distribute so as to satisfy simultaneously your obligations under this
License and any other pertinent obligations, then as a consequence you
may not distribute the Program at all. For example, if a patent
license would not permit royalty-free redistribution of the Program by
all those who receive copies directly or indirectly through you, then
the only way you could satisfy both it and this License would be to
refrain entirely from distribution of the Program.
If any portion of this section is held invalid or unenforceable under
any particular circumstance, the balance of the section is intended to
apply and the section as a whole is intended to apply in other
circumstances.
It is not the purpose of this section to induce you to infringe any
patents or other property right claims or to contest validity of any
such claims; this section has the sole purpose of protecting the
integrity of the free software distribution system, which is
implemented by public license practices. Many people have made
generous contributions to the wide range of software distributed
through that system in reliance on consistent application of that
system; it is up to the author/donor to decide if he or she is willing
to distribute software through any other system and a licensee cannot
impose that choice.
This section is intended to make thoroughly clear what is believed to
be a consequence of the rest of this License.
8. If the distribution and/or use of the Program is restricted in
certain countries either by patents or by copyrighted interfaces, the
original copyright holder who places the Program under this License
may add an explicit geographical distribution limitation excluding
those countries, so that distribution is permitted only in or among
countries not thus excluded. In such case, this License incorporates
the limitation as if written in the body of this License.
9. The Free Software Foundation may publish revised and/or new versions
of the 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 Program
specifies a version number of this License which applies to it and "any
later version", you have the option of following the terms and conditions
either of that version or of any later version published by the Free
Software Foundation. If the Program does not specify a version number of
this License, you may choose any version ever published by the Free Software
Foundation.
10. If you wish to incorporate parts of the Program into other free
programs whose distribution conditions are different, write to the author
to ask for permission. For software which is copyrighted by the Free
Software Foundation, write to the Free Software Foundation; we sometimes
make exceptions for this. Our decision will be guided by the two goals
of preserving the free status of all derivatives of our free software and
of promoting the sharing and reuse of software generally.
NO WARRANTY
11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY
FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN
OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES
PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED
OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS
TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE
PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING,
REPAIR OR CORRECTION.
12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR
REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES,
INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING
OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED
TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY
YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER
PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE
POSSIBILITY OF SUCH DAMAGES.
END OF TERMS AND CONDITIONS
How to Apply These Terms to Your New Programs
If you develop a new program, and you want it to be of the greatest
possible use to the public, the best way to achieve this is to make it
free software which everyone can redistribute and change under these terms.
To do so, attach the following notices to the program. It is safest
to attach them to the start of each source file to most effectively
convey the exclusion of warranty; and each file should have at least
the "copyright" line and a pointer to where the full notice is found.
<one line to give the program's name and a brief idea of what it does.>
Copyright (C) <year> <name of author>
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program 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 General Public License for more details.
You should have received a copy of the GNU General Public License along
with this program; if not, write to the Free Software Foundation, Inc.,
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
Also add information on how to contact you by electronic and paper mail.
If the program is interactive, make it output a short notice like this
when it starts in an interactive mode:
Gnomovision version 69, Copyright (C) year name of author
Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
This is free software, and you are welcome to redistribute it
under certain conditions; type `show c' for details.
The hypothetical commands `show w' and `show c' should show the appropriate
parts of the General Public License. Of course, the commands you use may
be called something other than `show w' and `show c'; they could even be
mouse-clicks or menu items--whatever suits your program.
You should also get your employer (if you work as a programmer) or your
school, if any, to sign a "copyright disclaimer" for the program, if
necessary. Here is a sample; alter the names:
Yoyodyne, Inc., hereby disclaims all copyright interest in the program
`Gnomovision' (which makes passes at compilers) written by James Hacker.
<signature of Ty Coon>, 1 April 1989
Ty Coon, President of Vice
This General Public License does not permit incorporating your program into
proprietary programs. If your program is a subroutine library, you may
consider it more useful to permit linking proprietary applications with the
library. If this is what you want to do, use the GNU Lesser General
Public License instead of this License.

481
third-party/libftdi/COPYING.LIB vendored 100644
View File

@ -0,0 +1,481 @@
GNU LIBRARY GENERAL PUBLIC LICENSE
Version 2, June 1991
Copyright (C) 1991 Free Software Foundation, Inc.
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
Everyone is permitted to copy and distribute verbatim copies
of this license document, but changing it is not allowed.
[This is the first released version of the library GPL. It is
numbered 2 because it goes with version 2 of the ordinary GPL.]
Preamble
The licenses for most software are designed to take away your
freedom to share and change it. By contrast, the GNU General Public
Licenses are intended to guarantee your freedom to share and change
free software--to make sure the software is free for all its users.
This license, the Library General Public License, applies to some
specially designated Free Software Foundation software, and to any
other libraries whose authors decide to use it. You can use it for
your libraries, too.
When we speak of free software, we are referring to freedom, not
price. Our General Public Licenses are designed to make sure that you
have the freedom to distribute copies of free software (and charge for
this service if you wish), that you receive source code or can get it
if you want it, that you can change the software or use pieces of it
in new free programs; and that you know you can do these things.
To protect your rights, we need to make restrictions that forbid
anyone to deny you these rights or to ask you to surrender the rights.
These restrictions translate to certain responsibilities for you if
you distribute copies of the library, or if you modify it.
For example, if you distribute copies of the library, whether gratis
or for a fee, you must give the recipients all the rights that we gave
you. You must make sure that they, too, receive or can get the source
code. If you link a program with the library, you must provide
complete object files to the recipients so that they can relink them
with the library, after making changes to the library and recompiling
it. And you must show them these terms so they know their rights.
Our method of protecting your rights has two steps: (1) copyright
the library, and (2) offer you this license which gives you legal
permission to copy, distribute and/or modify the library.
Also, for each distributor's protection, we want to make certain
that everyone understands that there is no warranty for this free
library. If the library is modified by someone else and passed on, we
want its recipients to know that what they have is not the original
version, so that any problems introduced by others will not reflect on
the original authors' reputations.
Finally, any free program is threatened constantly by software
patents. We wish to avoid the danger that companies distributing free
software will individually obtain patent licenses, thus in effect
transforming the program into proprietary software. To prevent this,
we have made it clear that any patent must be licensed for everyone's
free use or not licensed at all.
Most GNU software, including some libraries, is covered by the ordinary
GNU General Public License, which was designed for utility programs. This
license, the GNU Library General Public License, applies to certain
designated libraries. This license is quite different from the ordinary
one; be sure to read it in full, and don't assume that anything in it is
the same as in the ordinary license.
The reason we have a separate public license for some libraries is that
they blur the distinction we usually make between modifying or adding to a
program and simply using it. Linking a program with a library, without
changing the library, is in some sense simply using the library, and is
analogous to running a utility program or application program. However, in
a textual and legal sense, the linked executable is a combined work, a
derivative of the original library, and the ordinary General Public License
treats it as such.
Because of this blurred distinction, using the ordinary General
Public License for libraries did not effectively promote software
sharing, because most developers did not use the libraries. We
concluded that weaker conditions might promote sharing better.
However, unrestricted linking of non-free programs would deprive the
users of those programs of all benefit from the free status of the
libraries themselves. This Library General Public License is intended to
permit developers of non-free programs to use free libraries, while
preserving your freedom as a user of such programs to change the free
libraries that are incorporated in them. (We have not seen how to achieve
this as regards changes in header files, but we have achieved it as regards
changes in the actual functions of the Library.) The hope is that this
will lead to faster development of free libraries.
The precise terms and conditions for copying, distribution and
modification follow. Pay close attention to the difference between a
"work based on the library" and a "work that uses the library". The
former contains code derived from the library, while the latter only
works together with the library.
Note that it is possible for a library to be covered by the ordinary
General Public License rather than by this special one.
GNU LIBRARY GENERAL PUBLIC LICENSE
TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
0. This License Agreement applies to any software library which
contains a notice placed by the copyright holder or other authorized
party saying it may be distributed under the terms of this Library
General Public License (also called "this License"). Each licensee is
addressed as "you".
A "library" means a collection of software functions and/or data
prepared so as to be conveniently linked with application programs
(which use some of those functions and data) to form executables.
The "Library", below, refers to any such software library or work
which has been distributed under these terms. A "work based on the
Library" means either the Library or any derivative work under
copyright law: that is to say, a work containing the Library or a
portion of it, either verbatim or with modifications and/or translated
straightforwardly into another language. (Hereinafter, translation is
included without limitation in the term "modification".)
"Source code" for a work means the preferred form of the work for
making modifications to it. For a library, complete source code means
all the source code for all modules it contains, plus any associated
interface definition files, plus the scripts used to control compilation
and installation of the library.
Activities other than copying, distribution and modification are not
covered by this License; they are outside its scope. The act of
running a program using the Library is not restricted, and output from
such a program is covered only if its contents constitute a work based
on the Library (independent of the use of the Library in a tool for
writing it). Whether that is true depends on what the Library does
and what the program that uses the Library does.
1. You may copy and distribute verbatim copies of the Library's
complete source code as you receive it, in any medium, provided that
you conspicuously and appropriately publish on each copy an
appropriate copyright notice and disclaimer of warranty; keep intact
all the notices that refer to this License and to the absence of any
warranty; and distribute a copy of this License along with the
Library.
You may charge a fee for the physical act of transferring a copy,
and you may at your option offer warranty protection in exchange for a
fee.
2. You may modify your copy or copies of the Library or any portion
of it, thus forming a work based on the Library, and copy and
distribute such modifications or work under the terms of Section 1
above, provided that you also meet all of these conditions:
a) The modified work must itself be a software library.
b) You must cause the files modified to carry prominent notices
stating that you changed the files and the date of any change.
c) You must cause the whole of the work to be licensed at no
charge to all third parties under the terms of this License.
d) If a facility in the modified Library refers to a function or a
table of data to be supplied by an application program that uses
the facility, other than as an argument passed when the facility
is invoked, then you must make a good faith effort to ensure that,
in the event an application does not supply such function or
table, the facility still operates, and performs whatever part of
its purpose remains meaningful.
(For example, a function in a library to compute square roots has
a purpose that is entirely well-defined independent of the
application. Therefore, Subsection 2d requires that any
application-supplied function or table used by this function must
be optional: if the application does not supply it, the square
root function must still compute square roots.)
These requirements apply to the modified work as a whole. If
identifiable sections of that work are not derived from the Library,
and can be reasonably considered independent and separate works in
themselves, then this License, and its terms, do not apply to those
sections when you distribute them as separate works. But when you
distribute the same sections as part of a whole which is a work based
on the Library, the distribution of the whole must be on the terms of
this License, whose permissions for other licensees extend to the
entire whole, and thus to each and every part regardless of who wrote
it.
Thus, it is not the intent of this section to claim rights or contest
your rights to work written entirely by you; rather, the intent is to
exercise the right to control the distribution of derivative or
collective works based on the Library.
In addition, mere aggregation of another work not based on the Library
with the Library (or with a work based on the Library) on a volume of
a storage or distribution medium does not bring the other work under
the scope of this License.
3. You may opt to apply the terms of the ordinary GNU General Public
License instead of this License to a given copy of the Library. To do
this, you must alter all the notices that refer to this License, so
that they refer to the ordinary GNU General Public License, version 2,
instead of to this License. (If a newer version than version 2 of the
ordinary GNU General Public License has appeared, then you can specify
that version instead if you wish.) Do not make any other change in
these notices.
Once this change is made in a given copy, it is irreversible for
that copy, so the ordinary GNU General Public License applies to all
subsequent copies and derivative works made from that copy.
This option is useful when you wish to copy part of the code of
the Library into a program that is not a library.
4. You may copy and distribute the Library (or a portion or
derivative of it, under Section 2) in object code or executable form
under the terms of Sections 1 and 2 above provided that you accompany
it with the complete corresponding machine-readable source code, which
must be distributed under the terms of Sections 1 and 2 above on a
medium customarily used for software interchange.
If distribution of object code is made by offering access to copy
from a designated place, then offering equivalent access to copy the
source code from the same place satisfies the requirement to
distribute the source code, even though third parties are not
compelled to copy the source along with the object code.
5. A program that contains no derivative of any portion of the
Library, but is designed to work with the Library by being compiled or
linked with it, is called a "work that uses the Library". Such a
work, in isolation, is not a derivative work of the Library, and
therefore falls outside the scope of this License.
However, linking a "work that uses the Library" with the Library
creates an executable that is a derivative of the Library (because it
contains portions of the Library), rather than a "work that uses the
library". The executable is therefore covered by this License.
Section 6 states terms for distribution of such executables.
When a "work that uses the Library" uses material from a header file
that is part of the Library, the object code for the work may be a
derivative work of the Library even though the source code is not.
Whether this is true is especially significant if the work can be
linked without the Library, or if the work is itself a library. The
threshold for this to be true is not precisely defined by law.
If such an object file uses only numerical parameters, data
structure layouts and accessors, and small macros and small inline
functions (ten lines or less in length), then the use of the object
file is unrestricted, regardless of whether it is legally a derivative
work. (Executables containing this object code plus portions of the
Library will still fall under Section 6.)
Otherwise, if the work is a derivative of the Library, you may
distribute the object code for the work under the terms of Section 6.
Any executables containing that work also fall under Section 6,
whether or not they are linked directly with the Library itself.
6. As an exception to the Sections above, you may also compile or
link a "work that uses the Library" with the Library to produce a
work containing portions of the Library, and distribute that work
under terms of your choice, provided that the terms permit
modification of the work for the customer's own use and reverse
engineering for debugging such modifications.
You must give prominent notice with each copy of the work that the
Library is used in it and that the Library and its use are covered by
this License. You must supply a copy of this License. If the work
during execution displays copyright notices, you must include the
copyright notice for the Library among them, as well as a reference
directing the user to the copy of this License. Also, you must do one
of these things:
a) Accompany the work with the complete corresponding
machine-readable source code for the Library including whatever
changes were used in the work (which must be distributed under
Sections 1 and 2 above); and, if the work is an executable linked
with the Library, with the complete machine-readable "work that
uses the Library", as object code and/or source code, so that the
user can modify the Library and then relink to produce a modified
executable containing the modified Library. (It is understood
that the user who changes the contents of definitions files in the
Library will not necessarily be able to recompile the application
to use the modified definitions.)
b) Accompany the work with a written offer, valid for at
least three years, to give the same user the materials
specified in Subsection 6a, above, for a charge no more
than the cost of performing this distribution.
c) If distribution of the work is made by offering access to copy
from a designated place, offer equivalent access to copy the above
specified materials from the same place.
d) Verify that the user has already received a copy of these
materials or that you have already sent this user a copy.
For an executable, the required form of the "work that uses the
Library" must include any data and utility programs needed for
reproducing the executable from it. However, as a special exception,
the source code distributed need not include anything that is normally
distributed (in either source or binary form) with the major
components (compiler, kernel, and so on) of the operating system on
which the executable runs, unless that component itself accompanies
the executable.
It may happen that this requirement contradicts the license
restrictions of other proprietary libraries that do not normally
accompany the operating system. Such a contradiction means you cannot
use both them and the Library together in an executable that you
distribute.
7. 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 not covered by this License, and distribute such a combined
library, provided that the separate distribution of the work based on
the Library and of the other library facilities is otherwise
permitted, and provided that you do these two things:
a) Accompany the combined library with a copy of the same work
based on the Library, uncombined with any other library
facilities. This must be distributed under the terms of the
Sections above.
b) Give prominent notice with the combined library of the fact
that part of it is a work based on the Library, and explaining
where to find the accompanying uncombined form of the same work.
8. You may not copy, modify, sublicense, link with, or distribute
the Library except as expressly provided under this License. Any
attempt otherwise to copy, modify, sublicense, link with, or
distribute the Library is void, and will automatically terminate your
rights under this License. However, parties who have received copies,
or rights, from you under this License will not have their licenses
terminated so long as such parties remain in full compliance.
9. You are not required to accept this License, since you have not
signed it. However, nothing else grants you permission to modify or
distribute the Library or its derivative works. These actions are
prohibited by law if you do not accept this License. Therefore, by
modifying or distributing the Library (or any work based on the
Library), you indicate your acceptance of this License to do so, and
all its terms and conditions for copying, distributing or modifying
the Library or works based on it.
10. Each time you redistribute the Library (or any work based on the
Library), the recipient automatically receives a license from the
original licensor to copy, distribute, link with or modify the Library
subject to these terms and conditions. You may not impose any further
restrictions on the recipients' exercise of the rights granted herein.
You are not responsible for enforcing compliance by third parties to
this License.
11. If, as a consequence of a court judgment or allegation of patent
infringement or for any other reason (not limited to patent issues),
conditions are imposed on you (whether by court order, agreement or
otherwise) that contradict the conditions of this License, they do not
excuse you from the conditions of this License. If you cannot
distribute so as to satisfy simultaneously your obligations under this
License and any other pertinent obligations, then as a consequence you
may not distribute the Library at all. For example, if a patent
license would not permit royalty-free redistribution of the Library by
all those who receive copies directly or indirectly through you, then
the only way you could satisfy both it and this License would be to
refrain entirely from distribution of the Library.
If any portion of this section is held invalid or unenforceable under any
particular circumstance, the balance of the section is intended to apply,
and the section as a whole is intended to apply in other circumstances.
It is not the purpose of this section to induce you to infringe any
patents or other property right claims or to contest validity of any
such claims; this section has the sole purpose of protecting the
integrity of the free software distribution system which is
implemented by public license practices. Many people have made
generous contributions to the wide range of software distributed
through that system in reliance on consistent application of that
system; it is up to the author/donor to decide if he or she is willing
to distribute software through any other system and a licensee cannot
impose that choice.
This section is intended to make thoroughly clear what is believed to
be a consequence of the rest of this License.
12. If the distribution and/or use of the Library is restricted in
certain countries either by patents or by copyrighted interfaces, the
original copyright holder who places the Library under this License may add
an explicit geographical distribution limitation excluding those countries,
so that distribution is permitted only in or among countries not thus
excluded. In such case, this License incorporates the limitation as if
written in the body of this License.
13. The Free Software Foundation may publish revised and/or new
versions of the Library 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
specifies a version number of this License which applies to it and
"any later version", you have the option of following the terms and
conditions either of that version or of any later version published by
the Free Software Foundation. If the Library does not specify a
license version number, you may choose any version ever published by
the Free Software Foundation.
14. If you wish to incorporate parts of the Library into other free
programs whose distribution conditions are incompatible with these,
write to the author to ask for permission. For software which is
copyrighted by the Free Software Foundation, write to the Free
Software Foundation; we sometimes make exceptions for this. Our
decision will be guided by the two goals of preserving the free status
of all derivatives of our free software and of promoting the sharing
and reuse of software generally.
NO WARRANTY
15. BECAUSE THE LIBRARY IS LICENSED FREE OF CHARGE, THERE IS NO
WARRANTY FOR THE LIBRARY, TO THE EXTENT PERMITTED BY APPLICABLE LAW.
EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR
OTHER PARTIES PROVIDE THE LIBRARY "AS IS" WITHOUT WARRANTY OF ANY
KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE
LIBRARY IS WITH YOU. SHOULD THE LIBRARY PROVE DEFECTIVE, YOU ASSUME
THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION.
16. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN
WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY
AND/OR REDISTRIBUTE THE LIBRARY AS PERMITTED ABOVE, BE LIABLE TO YOU
FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR
CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE
LIBRARY (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING
RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A
FAILURE OF THE LIBRARY TO OPERATE WITH ANY OTHER SOFTWARE), EVEN IF
SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
DAMAGES.
END OF TERMS AND CONDITIONS
How to Apply These Terms to Your New Libraries
If you develop a new library, and you want it to be of the greatest
possible use to the public, we recommend making it free software that
everyone can redistribute and change. You can do so by permitting
redistribution under these terms (or, alternatively, under the terms of the
ordinary General Public License).
To apply these terms, attach the following notices to the library. It is
safest to attach them to the start of each source file to most effectively
convey the exclusion of warranty; and each file should have at least the
"copyright" line and a pointer to where the full notice is found.
<one line to give the library's name and a brief idea of what it does.>
Copyright (C) <year> <name of author>
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Library General Public
License as published by the Free Software Foundation; either
version 2 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
Library General Public License for more details.
You should have received a copy of the GNU Library 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
Also add information on how to contact you by electronic and paper mail.
You should also get your employer (if you work as a programmer) or your
school, if any, to sign a "copyright disclaimer" for the library, if
necessary. Here is a sample; alter the names:
Yoyodyne, Inc., hereby disclaims all copyright interest in the
library `Frob' (a library for tweaking knobs) written by James Random Hacker.
<signature of Ty Coon>, 1 April 1990
Ty Coon, President of Vice
That's all there is to it!

251
third-party/libftdi/ChangeLog vendored 100644
View File

@ -0,0 +1,251 @@
New in 1.4 - 2017-08-07
-----------------------
* New ftdi_usb_open_bus_addr() open function
* Use BM/R series baud rate computation for FT230X
* ftdi_get_error_string() now returns const char*
* C++ API: Ability to open devices with empty descriptor strings
* C++ API: Fix enumerations for buffer purge and modem controls
* small build fixes and improvements in the python examples
* ftdi_eeprom / eeprom handling:
* New API function: ftdi_eeprom_get_strings()
* Fix USE_SERIAL handling for 230X type chips
* Make ftdi_read_eeprom_location() endianness independent
* Fix flashing of FT245R
New in 1.3 - 2016-05-20
-----------------------
* Added ftdi_usb_get_strings2() to prevent automatic device close (Fahrzin Hemmati)
* Added ftdi_transfer_data_cancel() for cancellation of a submitted transfer,
avoided resubmittion of a canceled transfer in the callbacks,
replaced calls to libusb_handle_events with
libusb_handle_events_timeout_completed (Eugene Hutorny)
* ftdi_eeprom / eeprom handling:
* Add support for arbitrary user data (Salvador Eduardo Tropea)
* Add --build-eeprom support (Salvador Eduardo Tropea)
* Fix use_usb_version config file option (Thilo Schulz)
* Ability to include other config files in EEPROM config file (Thilo Schulz)
* Add external oscillator enable bit (Raphael Assenat)
* Support channel configuration (Stephan Linz)
* Added --device option to ftdi_eeprom to specify FTDI device (Robin Haberkorn)
* Fixed EEPROM user-area space checks for FT232R and FT245R chips (Robin Haberkorn)
* Various improvements to CBUS handling, including the EEPROM (Robin Haberkorn)
* swig wrapper: Fix handling of binary strings in ftdi_write_data()
for python 3 (xantares09)
* cbus python example code (Rodney Sinclair)
* ftdi_stream: fix timeout setting (Ларионов Даниил)
* Fixed typo in CBUS defines: CBUSG_DRIVE1 -> CBUSH_DRIVE1
New in 1.2 - 2014-11-21
-----------------------
* Support for FT230X devices (Uwe Bonnes)
* ftdi_usb_get_strings(): Don't try to open an already open device (Denis Sirotkin)
* Support for finding devices bricked by the Windows driver (Forest Crossman)
* cmake build system: New LibFTDI1ConfigVersion.cmake file (xantares09)
* Fix a typo in the MPSSE command CLK_BYTES_OR_LOW (Benjamin Vanheuverzwijn)
* Minor fixes for MSVC++ (Andrei Errapart)
* Various small code improvements (Florian Preinstorfer, Jochen Sprickerhof, xantares09)
New in 1.1 - 2014-02-05
-----------------------
* Fix FT232H eeprom suspend pulldown setting (Davide Michelizza)
* Fix FT232H eeprom user area size (Davide Michelizza)
* Improved mingw build (Paul Fertser and Michel Zou)
* C++ wrapper: Get/set functions for USB timeouts (Jochen Sprickerhof)
* Partial support for FT230X (Nathael Pajani)
* New API function: ftdi_eeprom_set_strings() (Nathael Pajani)
* Prevent possible segfault in ftdi_eeprom_decode() (Nathael Pajani)
* Save device release number in eeprom (Jarkko Sonninen)
* Fix "self powered" eeprom flag (Jarkko Sonninen)
* Improved python wrapper (Michel Zou)
* Many buildsystem improvements (Michel Zou and Mike Frysinger)
* See the git history for more changes and fixes
New in 1.0 - 2013-01-29
-----------------------
* Ported to libusb 1.x (initial work by Jie Zhang)
* Many eeprom handling improvements (Uwe Bonnes, Anders Larsen)
* Renamed pkconfig, library .so etc. files to "libftdi1" (Intra2net)
* ftdi_eeprom is part of libftdi now (Intra2net)
* New baudrate calculation code + unit tests (Uwe Bonnes and Intra2net)
* Improved python bindings including python3 support (Michel Zou)
* Switched completely to cmake build system (Intra2net)
* cmake: Easy libftdi discovery via find_package() (Michel Zou)
* eeprom handling now done via get()/set() functions (Uwe Bonnes)
* C++ wrapper: Fixed use-after-free in List::find_all() (Intra2net)
* Documentation updates (Xiaofan Chen)
* See the git history for more changes and fixes
New in 0.20 - 2012-03-19
------------------------
* Support for FT232H (Uwe Bonnes)
* Fixed install location of header files (Uwe Bonnes and Intra2net)
* Backported serial_test tool from libftdi 1.x (Uwe Bonnes)
New in 0.19 - 2011-05-23
------------------------
* Make kernel driver detach configurable (Thomas Klose)
* Correct ftdi_poll_modem_status() result code (Tom Saunders)
* cmake build system improvements (Evgeny Sinelnikov)
* Fix uninitialized memory access in async mode (Intra2net)
* Support for FT232R eeprom features (Hermann Kraus)
* Fix size returned by ftdi_read_data (Hermann Kraus)
* C++ wrapper: Fix infinite recursion in set_bitmode (Intra2net)
* Improvements to the python wrapper (Flynn Marquardt and Chris Zeh)
New in 0.18 - 2010-06-25
------------------------
* Add ftdi_eeprom_free() to free allocated memory in eeprom (Wilfried Holzke)
* More generic error message for the FTDI kernel driver (Intra2net)
* Honor CPPFLAGS in python wrapper build (Alexander Lehmann)
* cmake: Fix package creation on 32-bit machines (Uwe Bonnes)
* Fix swig argument constraints (Intra2net)
* Don't segfault if device is closed or ftdi context is invalid (Intra2net)
* Ability to disable build of examples / documentation (Mike Frysinger and Intra2net)
* Fix typo in python wrapper build (Mike Frysinger)
* Autoconf build system improvements (Mike Frysinger)
New in 0.17 - 2009-12-19
------------------------
* C++ wrapper: Reduced code duplication and small other changes (Intra2net)
* Deprecated old ftdi_enable_bitbang() function (Intra2net)
* New ftdi_usb_open_desc_index() function (Intra2net)
* Added baud rate test example code (Intra2net)
* New serial input example code (Jim Paris)
* Fix modem status byte filtering for USB high speed chips (Intra2net and Jim Paris)
* Add bitmode for synchronous fifo in FT2232H (Uwe Bonnes)
* Fix usb_set_configuration() call on Windows 64 (NIL)
* Fix usb index in ftdi_convert_baudrate() for FT2232H/FT4232H chips (Thimo Eichstaedt)
* Set initial baudrate on correct interface instead of always the first one (Thimo Eichstaedt)
* Call usb_set_configuration() on Windows only (Uwe Bonnes)
* 64 bit and other buildsystem fixes (Uwe Bonnes)
* Don't build --with-async-mode w/ libusb-compat-0.1 (Clifford Wolf)
* Functions for read/write of a single eeprom location (Oleg Seiljus)
* Protect against double close of usb device (Nathan Fraser)
* Fix out-of-tree-build in python wrapper (Aurelien Jarno)
* Autoconf and doxygen cleanup (Jim Paris)
New in 0.16 - 2009-05-08
------------------------
* C++ wrapper: Reopen the device after calling get_strings() in Context::open() (Marek Vavruša and Intra2net)
* C++ wrapper: Fixed an inheritance problem (Marek Vavruša and Intra2net)
* C++ wrapper: Relicensed under GPLv2 + linking exception (Marek Vavruša and Intra2net)
* Support for FT2232H and FT4232H (David Challis, Alex Harford and Intra2net)
* Support for mingw cross compile (Uwe Bonnes)
* Python bindings and minor autoconf cleanup (Tarek Heiland)
* Code cleanup in various places (Intra2net)
* Fixed ftdi_read_chipid in some cases (Matthias Richter)
* eeprom decode function and small cleanups (Marius Kintel)
* cmake system improvements (Marius Kintel and Intra2net)
* Fix compilation in -ansi -pedantic mode (Matthias Janke)
New in 0.15 - 2008-12-19
------------------------
* Full C++ wrapper. Needs boost (Marek Vavruša and Intra2net)
* cmake rules (Marek Vavruša)
New in 0.14 - 2008-09-09
------------------------
* Fixed flow control code for second FT2232 interface (Marek Vavruša)
* Ability to set flow control via one USB call (Marek Vavruša)
* 64 bit build support in the RPM spec file (Uwe Bonnes)
* Small fix to the RPM spec file (Uwe Bonnes)
* Ability to set RS232 break type (Intra2net)
* Grouped flow control and modem status code together (Intra2net)
New in 0.13 - 2008-06-13
------------------------
* Build .spec file via configure.in (Intra2net)
* Fixed "libusb-config --cflags" call (Mike Frysinger and Intra2net)
* Always set usb configuration (Mike Frysinger and Intra2net)
* Improved libusb-win32 support (Mike Frysinger)
New in 0.12 - 2008-04-16
------------------------
* Fix build of documentation for "out of tree" builds
* Fix USB config descriptor in the eeprom (Juergen Beisert)
* Ability to purge RX/TX buffers separately (Arnim Läuger)
* Setting of event and error character (Arnim Läuger)
* Poll modem status function (Arnim Läuger and Intra2net)
* Updated documentation and created AUTHORS file
New in 0.11 - 2008-03-01
------------------------
* Vala bindings helper functions (ftdi_new, ftdi_free, ftdi_list_free2) (Even Nermerson)
* Support for different EEPROM sizes (Andrew John Rogers, andrew@rogerstech.co.uk)
* Async write support. Linux only and no error handling.
You have to enable it via --with-async-mode.
* Detection of R-type chips
* FTDIChip-ID read support (Peter Holik)
New in 0.10 - 2007-05-08
------------------------
* Examples for libftdi_usb_find_all and CBUS mode
* Fixed ftdi_list_free
* Small cosmetic changes
New in 0.9 - 2007-02-09
-----------------------
* Fixed build without doxygen
* Correct .so file library version
New in 0.8 - 2007-02-08
-----------------------
* Complete doxygen documentation and examples
* Extended FT2232C bitbang mode example code (Max)
* ftdi_usb_get_strings function to get device ID strings (Matthijs ten Berge)
* Fix ftdi_read_pins on PowerPC systems (Thomas Fischl)
* Automatically detach ftdi_sio kernel driver (Uwe Bonnes and Intra2net)
* Configurable flow control (Lorenz Moesenlechner and Matthias Kranz)
New in 0.7 - 2005-10-11
-----------------------
* Baudrate calculation fix for FT2232C (Steven Turner/FTDI)
* Find all devices by vendor/product id (Tim Ansell and Intra2net)
* Documentation updates (Tim Ansell)
New in 0.6 - 2005-04-24
-----------------------
* Set library version on .so file again
* Configurable serial line parameters (Alain Abbas)
* Improved filtering of status bytes (Evgeny Sinelnikov)
* Extended FT2232C support (Uwe Bonnes)
* Small improvement to the baudrate calculation code (Emil)
* Error handling cleanup (Rogier Wolff and Intra2net)
New in 0.5 - 2004-09-24
-----------------------
* New autoconf suite
* pkgconfig support
* Status byte filtering now works for "big" readbuffer sizes (Thanks Evgeny!)
* Open device by description and/or serial (Evgeny Sinelnikov)
* Improved error handling (Evgeny Sinelnikov)
New in 0.4 - 2004-06-15
-----------------------
* Fixed filtering of status bytes (Readbuffer size is now 64 bytes)
* FT2232C support (Steven Turner/FTDI)
* New baudrate calculation code (Ian Abbott)
* Automatic detection of chip type
* Important: ftdi_write_data now returns the bytes written
* Fixed defaults values in ftdi_eeprom_initdefaults (Jean-Daniel Merkli)
* Reset internal readbuffer offsets for reset()/purge_buffers()
* Small typo fixes (Mark Haemmerling)
New in 0.3 - 2004-03-25
-----------------------
* Improved read function which takes arbitrary input buffer sizes
Attention: Call ftdi_deinit() on exit to free used memory
* Vastly increased read/write performance (configurable chunksize, default is 4096)
* Set/get latency timer function working (Thanks Steven Turner/FTDI)
* Increased library version because the changes require recompilation
New in 0.2 - 2004-01-03
-----------------------
* EEPROM build fix by Daniel Kirkham (Melbourne, Australia)
* Implemented basic ftdi_read_data() function
* EEPROM write fixes
New in 0.1 - 2003-06-10
-----------------------
* First public release

View File

@ -0,0 +1,38 @@
# - Try to find the freetype library
# Once done this defines
#
# LIBUSB_FOUND - system has libusb
# LIBUSB_INCLUDE_DIR - the libusb include directory
# LIBUSB_LIBRARIES - Link these to use libusb
# Copyright (c) 2006, 2008 Laurent Montel, <montel@kde.org>
#
# Redistribution and use is allowed according to the terms of the BSD license.
# For details see the accompanying COPYING-CMAKE-SCRIPTS file.
if (LIBUSB_INCLUDE_DIR AND LIBUSB_LIBRARIES)
# in cache already
set(LIBUSB_FOUND TRUE)
else (LIBUSB_INCLUDE_DIR AND LIBUSB_LIBRARIES)
IF (NOT WIN32)
# use pkg-config to get the directories and then use these values
# in the FIND_PATH() and FIND_LIBRARY() calls
find_package(PkgConfig)
pkg_check_modules(PC_LIBUSB libusb-1.0)
ENDIF(NOT WIN32)
FIND_PATH(LIBUSB_INCLUDE_DIR libusb.h
PATHS ${PC_LIBUSB_INCLUDEDIR} ${PC_LIBUSB_INCLUDE_DIRS})
FIND_LIBRARY(LIBUSB_LIBRARIES NAMES usb-1.0
PATHS ${PC_LIBUSB_LIBDIR} ${PC_LIBUSB_LIBRARY_DIRS})
include(FindPackageHandleStandardArgs)
FIND_PACKAGE_HANDLE_STANDARD_ARGS(LIBUSB DEFAULT_MSG LIBUSB_LIBRARIES LIBUSB_INCLUDE_DIR)
MARK_AS_ADVANCED(LIBUSB_INCLUDE_DIR LIBUSB_LIBRARIES)
endif (LIBUSB_INCLUDE_DIR AND LIBUSB_LIBRARIES)

25
third-party/libftdi/LICENSE vendored 100644
View File

@ -0,0 +1,25 @@
The C library "libftdi1" is distributed under the
GNU Library General Public License version 2.
A copy of the GNU Library General Public License (LGPL) is included
in this distribution, in the file COPYING.LIB.
----------------------------------------------------------------------
The C++ wrapper "ftdipp1" is distributed under the GNU General
Public License version 2 (with a special exception described below).
A copy of the GNU General Public License (GPL) is included
in this distribution, in the file COPYING.GPL.
As a special exception, if other files instantiate templates or use macros
or inline functions from this file, or you compile this file and link it
with other works to produce a work based on this file, this file
does not by itself cause the resulting work to be covered
by the GNU General Public License.
However the source code for this file must still be made available
in accordance with section (3) of the GNU General Public License.
This exception does not invalidate any other reasons why a work based
on this file might be covered by the GNU General Public License.

52
third-party/libftdi/README vendored 100644
View File

@ -0,0 +1,52 @@
--------------------------------------------------------------------
libftdi version 1.4
--------------------------------------------------------------------
libftdi - A library (using libusb) to talk to FTDI's UART/FIFO chips
including the popular bitbang mode.
The following chips are supported:
* FT230X
- FT4232H / FT2232H
- FT232R / FT245R
- FT2232L / FT2232D / FT2232C
- FT232BM / FT245BM (and the BL/BQ variants)
- FT8U232AM / FT8U245AM
libftdi requires libusb 1.x.
The AUTHORS file contains a list of all the people
that made libftdi possible what it is today.
Changes
-------
* New ftdi_usb_open_bus_addr() open function
* Use BM/R series baud rate computation for FT230X
* ftdi_get_error_string() now returns const char*
* C++ API: Ability to open devices with empty descriptor strings
* C++ API: Fix enumerations for buffer purge and modem controls
* small build fixes and improvements in the python examples
* ftdi_eeprom / eeprom handling:
* New API function: ftdi_eeprom_get_strings()
* Fix USE_SERIAL handling for 230X type chips
* Make ftdi_read_eeprom_location() endianness independent
* Fix flashing of FT245R
You'll find the newest version of libftdi at:
https://www.intra2net.com/en/developer/libftdi
Quick start
-----------
mkdir build
cd build
cmake -DCMAKE_INSTALL_PREFIX="/usr" ../
make
make install
More verbose build instructions are in "README.build"
--------------------------------------------------------------------
www.intra2net.com 2003-2017 Intra2net AG
--------------------------------------------------------------------

View File

@ -0,0 +1,96 @@
Here is a short tutorial on how to build libftdi git under
Ubuntu 12.10, But it is similar on other Linux distros.
1) Install the build tools
sudo apt-get install build-essential (yum install make automake gcc gcc-c++ kernel-devel)
sudo apt-get install git-core (yum install git)
sudo apt-get install cmake (yum install cmake)
sudo apt-get install doxygen (for building documentations) (yum install doxygen)
2) Install dependencies
sudo apt-get install libusb-1.0-devel (yum install libusb-devel)
(if the system comes with older version like 1.0.8 or
earlier, it is recommended you build libusbx-1.0.14 or later).
sudo apt-get install libconfuse-dev (for ftdi-eeprom) (yum install libconfuse-devel)
sudo apt-get install swig python-dev (for python bindings) (yum install swig python-devel)
sudo apt-get install libboost-all-dev (for C++ binding and unit test) (yum install boost-devel)
3) Clone the git repository
mkdir libftdi
cd libftdi
git clone git://developer.intra2net.com/libftdi
If you are building the release tar ball, just extract the source
tar ball.
4) Build the git source and install
cd libftdi
mkdir build
cd build
cmake -DCMAKE_INSTALL_PREFIX="/usr" ../
make
sudo make install
5) carry out some tests
cd examples
mcuee@Ubuntu1210VM:~/Desktop/build/libftdi/libftdi/build/examples$
./find_all_pp -v 0x0403 -p 0x6001
Found devices ( VID: 0x403, PID: 0x6001 )
------------------------------------------------
FTDI (0x8730800): ftdi, usb serial converter, ftDEH51S (Open OK)
FTDI (0x8730918): FTDI, FT232R USB UART, A8007Ub5 (Open OK)
mcuee@Ubuntu1210VM:~/Desktop/build/libftdi/libftdi/build/examples$ ./eeprom
2 FTDI devices found: Only Readout on EEPROM done. Use
VID/PID/desc/serial to select device
Decoded values of device 1:
Chip type 1 ftdi_eeprom_size: 128
0x000: 00 00 03 04 01 60 00 04 a0 16 08 00 10 01 94 0a .....`.. ........
0x010: 9e 2a c8 12 0a 03 66 00 74 00 64 00 69 00 2a 03 .*....f. t.d.i.*.
0x020: 75 00 73 00 62 00 20 00 73 00 65 00 72 00 69 00 u.s.b. . s.e.r.i.
0x030: 61 00 6c 00 20 00 63 00 6f 00 6e 00 76 00 65 00 a.l. .c. o.n.v.e.
0x040: 72 00 74 00 65 00 72 00 12 03 66 00 74 00 44 00 r.t.e.r. ..f.t.D.
0x050: 45 00 48 00 35 00 31 00 53 00 02 03 00 00 00 00 E.H.5.1. S.......
0x060: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ........ ........
0x070: 00 00 00 00 00 00 00 00 00 00 00 00 01 00 16 02 ........ ........
VID: 0x0403
PID: 0x6001
Release: 0x0400
Bus Powered: 44 mA USB Remote Wake Up
Manufacturer: ftdi
Product: usb serial converter
Serial: ftDEH51S
Checksum : 0216
Enable Remote Wake Up
PNP: 1
Decoded values of device 2:
Chip type 3 ftdi_eeprom_size: 128
0x000: 00 40 03 04 01 60 00 00 a0 2d 08 00 00 00 98 0a .@...`.. .-......
0x010: a2 20 c2 12 23 10 05 00 0a 03 46 00 54 00 44 00 . ..#... ..F.T.D.
0x020: 49 00 20 03 46 00 54 00 32 00 33 00 32 00 52 00 I. .F.T. 2.3.2.R.
0x030: 20 00 55 00 53 00 42 00 20 00 55 00 41 00 52 00 .U.S.B. .U.A.R.
0x040: 54 00 12 03 41 00 38 00 30 00 30 00 37 00 55 00 T...A.8. 0.0.7.U.
0x050: 62 00 35 00 c9 bf 1c 80 00 00 00 00 00 00 00 00 b.5..... ........
0x060: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ........ ........
0x070: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 0f 23 ........ .......#
0x080: 2c 04 d3 fb 00 00 c9 bf 1c 80 42 00 00 00 00 00 ,....... ..B.....
0x090: 00 00 00 00 00 00 00 00 38 41 32 52 4a 33 47 4f ........ 8A2RJ3GO
VID: 0x0403
PID: 0x6001
Release: 0x0000
Bus Powered: 90 mA USB Remote Wake Up
Manufacturer: FTDI
Product: FT232R USB UART
Serial: A8007Ub5
Checksum : 230f
Internal EEPROM
Enable Remote Wake Up
PNP: 1
Channel A has Mode UART VCP
C0 Function: TXLED
C1 Function: RXLED
C2 Function: TXDEN
C3 Function: PWREN
C4 Function: SLEEP

View File

@ -0,0 +1,38 @@
* How to cross compile libftdi-1.x for Windows? *
1 - Prepare a pkg-config wrapper according to
https://www.flameeyes.eu/autotools-mythbuster/pkgconfig/cross-compiling.html ,
additionally export PKG_CONFIG_ALLOW_SYSTEM_CFLAGS and
PKG_CONFIG_ALLOW_SYSTEM_LIBS.
2 - Write a CMake toolchain file according to
http://www.vtk.org/Wiki/CmakeMingw . Change the path to your future sysroot.
3 - Get libusb sources (either by cloning the git repo or by downloading a
tarball). Unpack, autogen.sh (when building from git), and configure like this:
./configure --build=`./config.guess` --host=i686-w64-mingw32 \
--prefix=/usr --with-sysroot=$HOME/i686-w64-mingw32-root/
4 - run
make install DESTDIR=$HOME/i686-w64-mingw32-root/
5 - go to libftdi-1.x source directory and run
cmake -DCMAKE_TOOLCHAIN_FILE=~/Toolchain-mingw.cmake \
-DCMAKE_INSTALL_PREFIX="/usr" \
-DPKG_CONFIG_EXECUTABLE=`which i686-w64-mingw32-pkg-config`
6 - run
make install DESTDIR=$HOME/i686-w64-mingw32-root/
* How to run libftdi 1.x under Windows *
On 26-Jan-2014, libusbx and libusb project were merged with the release
of libusb-1.0.18 and now the project is called libusb.
libusb Windows backend will need to rely on a proper driver to run.
Please refer to the following wiki page for proper driver installation.
https://github.com/libusb/libusb/wiki/Windows#wiki-How_to_use_libusb_on_Windows
As of 26-Jan-2014, libusb Windows backend supports WinUSB,
libusb0.sys and libusbk.sys driver. However, libusb's support of
libusb0.sys and libusbk.sys is considered to be less mature than
WinUSB. Therefore, WinUSB driver installation using Zadig
is recommended.
Take note once you replace the original FTDI driver with WinUSB driver,
you can no longer use the functionality the original FTDI driver provides
(eg. Virtual Serial Port or D2XX).

3
third-party/libftdi/TODO vendored 100644
View File

@ -0,0 +1,3 @@
*** TODO for 1.0 release ***
Documentation:
- Document the new EEPROM function

View File

@ -0,0 +1,74 @@
# libConfuse is a configuration file parser library
# available at http://www.nongnu.org/confuse/
#
# The module defines the following variables:
# CONFUSE_FOUND - the system has Confuse
# CONFUSE_INCLUDE_DIR - where to find confuse.h
# CONFUSE_INCLUDE_DIRS - confuse includes
# CONFUSE_LIBRARY - where to find the Confuse library
# CONFUSE_LIBRARIES - aditional libraries
# CONFUSE_ROOT_DIR - root dir (ex. /usr/local)
#=============================================================================
# Copyright 2010-2013, Julien Schueller
# All rights reserved.
#
# Redistribution and use in source and binary forms, with or without
# modification, are permitted provided that the following conditions are met:
#
# 1. Redistributions of source code must retain the above copyright notice, this
# list of conditions and the following disclaimer.
# 2. Redistributions in binary form must reproduce the above copyright notice,
# this list of conditions and the following disclaimer in the documentation
# and/or other materials provided with the distribution.
#
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
# WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
# DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
# ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
# (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
# ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
# SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
# The views and conclusions contained in the software and documentation are those
# of the authors and should not be interpreted as representing official policies,
# either expressed or implied, of the FreeBSD Project.
#=============================================================================
find_path ( CONFUSE_INCLUDE_DIR
NAMES confuse.h
)
set ( CONFUSE_INCLUDE_DIRS ${CONFUSE_INCLUDE_DIR} )
find_library ( CONFUSE_LIBRARY
NAMES confuse
)
set ( CONFUSE_LIBRARIES ${CONFUSE_LIBRARY} )
# try to guess root dir from include dir
if ( CONFUSE_INCLUDE_DIR )
string ( REGEX REPLACE "(.*)/include.*" "\\1" CONFUSE_ROOT_DIR ${CONFUSE_INCLUDE_DIR} )
# try to guess root dir from library dir
elseif ( CONFUSE_LIBRARY )
string ( REGEX REPLACE "(.*)/lib[/|32|64].*" "\\1" CONFUSE_ROOT_DIR ${CONFUSE_LIBRARY} )
endif ()
# handle the QUIETLY and REQUIRED arguments
include ( FindPackageHandleStandardArgs )
find_package_handle_standard_args( Confuse DEFAULT_MSG CONFUSE_LIBRARY CONFUSE_INCLUDE_DIR )
mark_as_advanced (
CONFUSE_LIBRARY
CONFUSE_LIBRARIES
CONFUSE_INCLUDE_DIR
CONFUSE_INCLUDE_DIRS
CONFUSE_ROOT_DIR
)

View File

@ -0,0 +1,47 @@
# Try to find Libintl functionality
# Once done this will define
#
# LIBINTL_FOUND - system has Libintl
# LIBINTL_INCLUDE_DIR - Libintl include directory
# LIBINTL_LIBRARIES - Libraries needed to use Libintl
#
# TODO: This will enable translations only if Gettext functionality is
# present in libc. Must have more robust system for release, where Gettext
# functionality can also reside in standalone Gettext library, or the one
# embedded within kdelibs (cf. gettext.m4 from Gettext source).
# Copyright (c) 2006, Chusslove Illich, <caslav.ilic@gmx.net>
# Copyright (c) 2007, Alexander Neundorf, <neundorf@kde.org>
#
# Redistribution and use is allowed according to the terms of the BSD license.
# For details see the accompanying COPYING-CMAKE-SCRIPTS file.
if(LIBINTL_INCLUDE_DIR AND LIBINTL_LIB_FOUND)
set(Libintl_FIND_QUIETLY TRUE)
endif(LIBINTL_INCLUDE_DIR AND LIBINTL_LIB_FOUND)
find_path(LIBINTL_INCLUDE_DIR libintl.h)
set(LIBINTL_LIB_FOUND FALSE)
if(LIBINTL_INCLUDE_DIR)
include(CheckFunctionExists)
check_function_exists(dgettext LIBINTL_LIBC_HAS_DGETTEXT)
if (LIBINTL_LIBC_HAS_DGETTEXT)
set(LIBINTL_LIBRARIES)
set(LIBINTL_LIB_FOUND TRUE)
else (LIBINTL_LIBC_HAS_DGETTEXT)
find_library(LIBINTL_LIBRARIES NAMES intl libintl )
if(LIBINTL_LIBRARIES)
set(LIBINTL_LIB_FOUND TRUE)
endif(LIBINTL_LIBRARIES)
endif (LIBINTL_LIBC_HAS_DGETTEXT)
endif(LIBINTL_INCLUDE_DIR)
include(FindPackageHandleStandardArgs)
find_package_handle_standard_args(Libintl DEFAULT_MSG LIBINTL_INCLUDE_DIR LIBINTL_LIB_FOUND)
mark_as_advanced(LIBINTL_INCLUDE_DIR LIBINTL_LIBRARIES LIBINTL_LIBC_HAS_DGETTEXT LIBINTL_LIB_FOUND)

View File

@ -0,0 +1,43 @@
# - Try to find the freetype library
# Once done this defines
#
# LIBUSB_FOUND - system has libusb
# LIBUSB_INCLUDE_DIR - the libusb include directory
# LIBUSB_LIBRARIES - Link these to use libusb
# Copyright (c) 2006, 2008 Laurent Montel, <montel@kde.org>
#
# Redistribution and use is allowed according to the terms of the BSD license.
# For details see the accompanying COPYING-CMAKE-SCRIPTS file.
if (LIBUSB_INCLUDE_DIR AND LIBUSB_LIBRARIES)
# in cache already
set(LIBUSB_FOUND TRUE)
else (LIBUSB_INCLUDE_DIR AND LIBUSB_LIBRARIES)
# use pkg-config to get the directories and then use these values
# in the FIND_PATH() and FIND_LIBRARY() calls
find_package(PkgConfig)
pkg_check_modules(PC_LIBUSB libusb-1.0)
FIND_PATH(LIBUSB_INCLUDE_DIR libusb.h
PATH_SUFFIXES libusb-1.0
PATHS ${PC_LIBUSB_INCLUDEDIR} ${PC_LIBUSB_INCLUDE_DIRS})
FIND_LIBRARY(LIBUSB_LIBRARY NAMES usb-1.0
PATHS ${PC_LIBUSB_LIBDIR} ${PC_LIBUSB_LIBRARY_DIRS})
if (APPLE)
set(LIBUSB_LIBRARIES "${LIBUSB_LIBRARY};-lobjc;-Wl,-framework,IOKit;-Wl,-framework,CoreFoundation;-Wl,-framework,Security")
else()
set(LIBUSB_LIBRARIES "${LIBUSB_LIBRARY}")
endif (APPLE)
include(FindPackageHandleStandardArgs)
FIND_PACKAGE_HANDLE_STANDARD_ARGS(LIBUSB DEFAULT_MSG LIBUSB_LIBRARIES LIBUSB_INCLUDE_DIR)
MARK_AS_ADVANCED(LIBUSB_INCLUDE_DIR LIBUSB_LIBRARIES)
endif (LIBUSB_INCLUDE_DIR AND LIBUSB_LIBRARIES)

View File

@ -0,0 +1,53 @@
# -*- cmake -*-
#
# LibFTDI1Config.cmake(.in)
#
# Copyright (C) 2013 Intra2net AG and the libftdi developers
#
# This file is part of LibFTDI.
#
# LibFTDI is free software; you can redistribute it and/or modify
# it under the terms of the GNU Lesser General Public License
# version 2.1 as published by the Free Software Foundation;
#
# Use the following variables to compile and link against LibFTDI:
# LIBFTDI_FOUND - True if LibFTDI was found on your system
# LIBFTDI_USE_FILE - The file making LibFTDI usable
# LIBFTDI_DEFINITIONS - Definitions needed to build with LibFTDI
# LIBFTDI_INCLUDE_DIRS - Directory where ftdi.h can be found
# LIBFTDI_INCLUDE_DIRS - List of directories of LibFTDI and it's dependencies
# LIBFTDI_LIBRARY - LibFTDI library location
# LIBFTDI_LIBRARIES - List of libraries to link against LibFTDI library
# LIBFTDIPP_LIBRARY - LibFTDI C++ wrapper library location
# LIBFTDIPP_LIBRARIES - List of libraries to link against LibFTDI C++ wrapper
# LIBFTDI_LIBRARY_DIRS - List of directories containing LibFTDI' libraries
# LIBFTDI_ROOT_DIR - The base directory of LibFTDI
# LIBFTDI_VERSION_STRING - A human-readable string containing the version
# LIBFTDI_VERSION_MAJOR - The major version of LibFTDI
# LIBFTDI_VERSION_MINOR - The minor version of LibFTDI
# LIBFTDI_VERSION_PATCH - The patch version of LibFTDI
# LIBFTDI_PYTHON_MODULE_PATH - Path to the python module
set ( LIBFTDI_FOUND 1 )
set ( LIBFTDI_USE_FILE "@LIBFTDI_USE_FILE@" )
set ( LIBFTDI_DEFINITIONS "@LIBFTDI_DEFINITIONS@" )
set ( LIBFTDI_INCLUDE_DIR "@LIBFTDI_INCLUDE_DIR@" )
set ( LIBFTDI_INCLUDE_DIRS "@LIBFTDI_INCLUDE_DIRS@" )
set ( LIBFTDI_LIBRARY "@LIBFTDI_LIBRARY@" )
set ( LIBFTDI_LIBRARIES "@LIBFTDI_LIBRARIES@" )
set ( LIBFTDI_STATIC_LIBRARY "@LIBFTDI_STATIC_LIBRARY@" )
set ( LIBFTDI_STATIC_LIBRARIES "@LIBFTDI_STATIC_LIBRARIES@" )
set ( LIBFTDIPP_LIBRARY "@LIBFTDIPP_LIBRARY@" )
set ( LIBFTDIPP_LIBRARIES "@LIBFTDIPP_LIBRARIES@" )
set ( LIBFTDI_LIBRARY_DIRS "@LIBFTDI_LIBRARY_DIRS@" )
set ( LIBFTDI_ROOT_DIR "@LIBFTDI_ROOT_DIR@" )
set ( LIBFTDI_VERSION_STRING "@LIBFTDI_VERSION_STRING@" )
set ( LIBFTDI_VERSION_MAJOR "@LIBFTDI_VERSION_MAJOR@" )
set ( LIBFTDI_VERSION_MINOR "@LIBFTDI_VERSION_MINOR@" )
set ( LIBFTDI_VERSION_PATCH "@LIBFTDI_VERSION_PATCH@" )
set ( LIBFTDI_PYTHON_MODULE_PATH "@LIBFTDI_PYTHON_MODULE_PATH@" )

View File

@ -0,0 +1,31 @@
# This is a basic version file for the Config-mode of find_package().
# It is used by write_basic_package_version_file() as input file for configure_file()
# to create a version-file which can be installed along a config.cmake file.
#
# The created file sets PACKAGE_VERSION_EXACT if the current version string and
# the requested version string are exactly the same and it sets
# PACKAGE_VERSION_COMPATIBLE if the current version is >= requested version.
# The variable CVF_VERSION must be set before calling configure_file().
set(PACKAGE_VERSION "@LIBFTDI_VERSION_STRING@")
if("${PACKAGE_VERSION}" VERSION_LESS "${PACKAGE_FIND_VERSION}" )
set(PACKAGE_VERSION_COMPATIBLE FALSE)
else()
set(PACKAGE_VERSION_COMPATIBLE TRUE)
if( "${PACKAGE_FIND_VERSION}" STREQUAL "${PACKAGE_VERSION}")
set(PACKAGE_VERSION_EXACT TRUE)
endif()
endif()
# if the installed or the using project don't have CMAKE_SIZEOF_VOID_P set, ignore it:
if("${CMAKE_SIZEOF_VOID_P}" STREQUAL "" OR "8" STREQUAL "")
return()
endif()
# check that the installed version has the same 32/64bit-ness as the one which is currently searching:
if(NOT "${CMAKE_SIZEOF_VOID_P}" STREQUAL "8")
math(EXPR installedBits "8 * 8")
set(PACKAGE_VERSION "${PACKAGE_VERSION} (${installedBits}bit)")
set(PACKAGE_VERSION_UNSUITABLE TRUE)
endif()

View File

@ -0,0 +1,4 @@
set(CMAKE_SYSTEM_NAME Linux)
set(CMAKE_C_COMPILER gcc -m32)
set(CMAKE_CXX_COMPILER g++ -m32)
set(CMAKE_FIND_ROOT_PATH /usr/lib)

View File

@ -0,0 +1,17 @@
# the name of the target operating system
SET(CMAKE_SYSTEM_NAME Windows)
# which compilers to use for C and C++
SET(CMAKE_C_COMPILER i686-w64-mingw32-gcc)
SET(CMAKE_CXX_COMPILER i686-w64-mingw32-g++)
# here is the target environment located
SET(CMAKE_FIND_ROOT_PATH /usr/i686-w64-mingw32 )
# adjust the default behaviour of the FIND_XXX() commands:
# search headers and libraries in the target environment, search
# programs in the host environment
set(CMAKE_FIND_ROOT_PATH_MODE_PROGRAM NEVER)
set(CMAKE_FIND_ROOT_PATH_MODE_LIBRARY ONLY)
set(CMAKE_FIND_ROOT_PATH_MODE_INCLUDE ONLY)
set (CMAKE_RC_COMPILER i686-w64-mingw32-windres)

View File

@ -0,0 +1,16 @@
# the name of the target operating system
SET(CMAKE_SYSTEM_NAME Windows)
# which compilers to use for C and C++
SET(CMAKE_C_COMPILER i386-mingw32msvc-gcc)
SET(CMAKE_CXX_COMPILER i386-mingw32msvc-g++)
# here is the target environment located
SET(CMAKE_FIND_ROOT_PATH /opt/cross/i386-mingw32msvc )
# adjust the default behaviour of the FIND_XXX() commands:
# search headers and libraries in the target environment, search
# programs in the host environment
set(CMAKE_FIND_ROOT_PATH_MODE_PROGRAM NEVER)
set(CMAKE_FIND_ROOT_PATH_MODE_LIBRARY ONLY)
set(CMAKE_FIND_ROOT_PATH_MODE_INCLUDE ONLY)

View File

@ -0,0 +1,17 @@
# the name of the target operating system
SET(CMAKE_SYSTEM_NAME Windows)
# which compilers to use for C and C++
SET(CMAKE_C_COMPILER x86_64-w64-mingw32-gcc)
SET(CMAKE_CXX_COMPILER x86_64-w64-mingw32-g++)
# here is the target environment located
SET(CMAKE_FIND_ROOT_PATH /usr/x86_64-w64-mingw32 )
# adjust the default behaviour of the FIND_XXX() commands:
# search headers and libraries in the target environment, search
# programs in the host environment
set(CMAKE_FIND_ROOT_PATH_MODE_PROGRAM NEVER)
set(CMAKE_FIND_ROOT_PATH_MODE_LIBRARY ONLY)
set(CMAKE_FIND_ROOT_PATH_MODE_INCLUDE ONLY)
set (CMAKE_RC_COMPILER x86_64-w64-mingw32-windres)

View File

@ -0,0 +1,18 @@
# -*- cmake -*-
#
# UseLibFTDI.cmake
#
# Copyright (C) 2013 Intra2net AG and the libftdi developers
#
# This file is part of LibFTDI.
#
# LibFTDI is free software; you can redistribute it and/or modify
# it under the terms of the GNU Lesser General Public License
# version 2.1 as published by the Free Software Foundation;
#
add_definitions ( ${LIBFTDI_DEFINITIONS} )
include_directories ( ${LIBFTDI_INCLUDE_DIRS} )
link_directories ( ${LIBFTDI_LIBRARY_DIRS} )

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,26 @@
# Doxyfile 1.7.4
# xml generation only
# keep settings but shut off all other generation
@INCLUDE = Doxyfile
GENERATE_TODOLIST = NO
GENERATE_TESTLIST = NO
GENERATE_BUGLIST = NO
GENERATE_DEPRECATEDLIST= NO
GENERATE_HTML = NO
GENERATE_DOCSET = NO
GENERATE_HTMLHELP = NO
GENERATE_CHI = NO
GENERATE_QHP = NO
GENERATE_ECLIPSEHELP = NO
GENERATE_TREEVIEW = NO
GENERATE_LATEX = NO
GENERATE_RTF = NO
GENERATE_MAN = NO
GENERATE_AUTOGEN_DEF = NO
GENERATE_PERLMOD = NO
GENERATE_TAGFILE =
GENERATE_LEGEND = NO
GENERATE_XML = YES

View File

@ -0,0 +1,110 @@
Here we try to document what we know about the EEPROM Structure.
Even with a 93xx66 EEPROM, at maximum 256 Bytes are used
All important things happen in the first
0x14(FT232/245), 0x16(FT2232CD), 0x18(FT232/245R) or 0x1a (FT2232H/4432H) bytes
Type | Use extra EEPROM space
FT2XXB | No
Byte.BIT| TYPE_AM TYPE_BM TYPE_2232C TYPE_R TYPE_2232H TYPE_4232H
00.0 | 0 0 channel_a_type 232R/245R channel_a_type 0
00.1 | 0 0 channel_a_type channel_a_type 0
00.2 | 0 0 channel_a_type high_current channel_a_type 0
00.3 | 0 0 channel_a_driver channel_a_driver channel_a_driver channel_a_driver
00.4 | 0 0 high_current_a 0 0 0
00.5 | 0 0 0 0 0 0
00.6 | 0 0 0 0 0 0
00.7 | 0 0 0 0 SUSPEND_DBUS7 channel_c_driver
On TYPE_R 00.0 is set for the FT245R and cleared for the FT232R
On TYPE_R 00.3 set mean D2XX, on other devices VCP
01.0 | 0 0 channel_b_type channel_b_type 0
01.1 | 0 0 channel_b_type channel_b_type 0
01.2 | 0 0 channel_b_type 0 channel_b_type 0
01.3 | 0 0 channel_b_driver 0 channel_b_driver channel_b_driver
01.4 | 0 0 high_current_b 0 0 0
01.5 | 0 0 0 0 0 0
01.6 | 0 0 0 0 0
01.7 | 0 0 0 0 0 channel_d_driver
Fixme: Missing 4232H validation
02 | Vendor ID (VID) LSB (all)
03 | Vendor ID (VID) MSB (all)
04 | Product ID (PID) LSB (all)
05 | Product ID (PID) MSB (all)
06 | Device release number LSB (not tested on TYPE_4232H)
07 | Device release number MSB (not tested on TYPE_4232H)
|
08.4 | Battery powered
08.5 | Remote wakeup
08.6 | Self powered: 1, bus powered: 0
08.7 | Always 1
|
09 | Max power (mA/2)
|
Byte.BIT| TYPE_AM TYPE_BM TYPE_2232C TYPE_R TYPE_2232H TYPE_4232H
0a.0 | 0 IsoIn IsoIn part A 0 0 0
0a.1 | 0 IsoOut IsoOut part A 0 0 0
0a.2 | 0 suspend_pull_down suspend_pull_down suspend_pull_down suspend_pull_down
0a.3 | 0 use_serial use_serial use_serial
0a.4 | 0 change_usb_version change_usb_version
0a.5 | 0 0 IsoIn part B 0 0 0
0a.6 | 0 0 IsoOut part B 0 0 0
0a.7 | 0 - reserved
0b | TYPE_R Bitmask Invert, 0 else
Byte.BIT| TYPE_4232H
0b.4 | channel_a_rs485enable
0b.5 | channel_b_rs485enable
0b.6 | channel_c_rs485enable
0b.7 | channel_d_rs485enable
Byte | TYPE_AM TYPE_BM TYPE_2232C TYPE_R TYPE_2232H TYPE_4232H
0c | 0 USB-VER-LSB USB-VER-LSB 0 ? ?
0d | 0 USB-VER-MSB USB-VER-MSB 0 ? ?
(On several FT2232H different values were observed -> The value is unused
if change USB version is not set, so it might contain garbage)
0e | OFFSET Vendor
0f | Len VENDOR
10 | Offset Product
11 | Length Product
12 | Offset Serial
13 | Length Serial
Byte.BIT| TYPE_AM TYPE_BM TYPE_2232C TYPE_R TYPE_2232H TYPE_4232H
14.3:0 | UA UA CHIP CBUS[0] AL A
14.7:0 | UA UA CHIP CBUS[1] AH B
15.3:0 | UA UA 0 CBUS[2] BL C
15.7:0 | UA UA 0 CBUS[3] BH D
16.3:0 | UA UA UA CBUS[4] 0 0
16.7:0 | UA UA UA 0 0 0
CHIP values:
0x46: EEPROM is a 93xx46
0x56: EEPROM is a 93xx56
0x66: EEPROM is a 93xx66
17 UA UA UA 0 0 0
18 UA UA UA VENDOR CHIP CHIP
19 UA UA UA VENDOR 0 0
1a UA (all)
Additional fields after the serial string:
0x00, 0x00 - reserved for "legacy port name prefix"
0x00, 0x00 - reserved for plug and play options
(Observed values with PnP == 0:
0x02 0x03 0x01 0x00)
Note: The additional fields after the serial number string
collide with the official FTDI formula from AN_121 regarding
the start of the user area:
"Start Address = the address following the last byte of SerialNumber string."

View File

@ -0,0 +1,5 @@
#!/bin/sh
# Astyle settings used to format our source code
/usr/bin/astyle --indent=spaces=4 --indent-switches --brackets=break \
--convert-tabs --keep-one-line-statements --keep-one-line-blocks \
$*

View File

@ -0,0 +1,29 @@
*** Checklist for a new libftdi release ***
- Update ChangeLog and AUTHORS via git history
(git log --oneline latest_release..HEAD)
- Update version number in the following files:
- CMakeLists.txt
- README
- Run "make dist"
- Diff tarball to previous version, check if all
important changes are in the ChangeLog
- Ensure all modifications are checked in
- Sign tarball, build .src.rpm and sign it, too
- Create git tag:
- git tag -s -u 24F006F5 v1.XX
- git tag -d latest_release ; git tag latest_release
- git push --tags
- Website
- Upload tarball and .src.rpm
- Add ChangeLog to main page
- Update URLs in download section
- Generate API documentation and upload it
- Announce on mailinglist

View File

@ -0,0 +1,57 @@
# determine docdir
include(GNUInstallDirs)
if(NOT CMAKE_INSTALL_DOCDIR)
if(WIN32)
set(CMAKE_INSTALL_DOCDIR .)
else(WIN32)
set(CMAKE_INSTALL_DOCDIR ${CMAKE_INSTALL_DATAROOTDIR}/doc/${PROJECT_NAME})
endif(WIN32)
endif(NOT CMAKE_INSTALL_DOCDIR)
option(FTDI_EEPROM "Build ftdi_eeprom" ON)
if ( FTDI_EEPROM )
find_package ( Confuse )
find_package ( Libintl )
else(FTDI_EEPROM)
message(STATUS "ftdi_eeprom build is disabled")
endif ()
if ( CONFUSE_FOUND )
message(STATUS "Building ftdi_eeprom")
include_directories ( ${CONFUSE_INCLUDE_DIRS} )
list ( APPEND libs ${CONFUSE_LIBRARIES} )
if ( LIBINTL_FOUND )
include_directories ( ${LIBINTL_INCLUDE_DIR} )
list ( APPEND libs ${LIBINTL_LIBRARIES} )
endif ()
# Version defines
set ( EEPROM_MAJOR_VERSION 0 )
set ( EEPROM_MINOR_VERSION 17 )
set ( EEPROM_VERSION_STRING ${EEPROM_MAJOR_VERSION}.${EEPROM_MINOR_VERSION} )
include_directories ( BEFORE ${CMAKE_SOURCE_DIR}/src )
include_directories ( BEFORE ${CMAKE_CURRENT_BINARY_DIR} )
configure_file(
ftdi_eeprom_version.h.in
${CMAKE_CURRENT_BINARY_DIR}/ftdi_eeprom_version.h
)
add_executable ( ftdi_eeprom main.c )
target_link_libraries ( ftdi_eeprom ftdi1 ${CONFUSE_LIBRARIES} )
if ( LIBINTL_FOUND )
target_link_libraries ( ftdi_eeprom ${LIBINTL_LIBRARIES} )
endif ()
if ( LIBFTDI_INSTALL )
install ( TARGETS ftdi_eeprom DESTINATION bin )
install ( FILES example.conf DESTINATION ${CMAKE_INSTALL_DOCDIR} )
endif()
else ()
message ( STATUS "libConfuse not found, won't build ftdi_eeprom" )
endif ()

View File

@ -0,0 +1,59 @@
vendor_id=0x0403 # Vendor ID
product_id=0x6001 # Product ID
max_power=0 # Max. power consumption: value * 2 mA. Use 0 if self_powered = true.
###########
# Strings #
###########
manufacturer="ACME Inc" # Manufacturer
product="USB Serial Converter" # Product
serial="08-15" # Serial
###########
# Options #
###########
self_powered=true # Turn this off for bus powered
remote_wakeup=false # Turn this on for remote wakeup feature
use_serial=true # Use the serial number string
# Normally out don't have to change one of these flags
in_is_isochronous=false # In Endpoint is Isochronous
out_is_isochronous=false # Out Endpoint is Isochronous
suspend_pull_downs=false # Enable suspend pull downs for lower power
change_usb_version=false # Change USB Version
usb_version=0x0200 # Only used when change_usb_version is enabled
# Only used on FT-R chips (when omitted, use chip defaults)
# Possible values correspond to enum ftdi_cbus_func.
cbus0=TXLED
cbus1=RXLED
cbus2=TXDEN
cbus3=PWREN
cbus4=SLEEP
# Only used on FT232H chips (when omitted, use chip defaults)
# Possible values correspond to enum ftdi_cbush_func.
cbush0=TRISTATE
cbush1=TRISTATE
cbush2=TRISTATE
cbush3=TRISTATE
cbush4=TRISTATE
cbush5=TRISTATE
cbush6=TRISTATE
cbush7=TRISTATE
cbush8=TRISTATE
cbush9=TRISTATE
# Only used on FT230X chips (when omitted, use chip defaults)
# Possible values correspond to enum ftdi_cbusx_func.
cbusx0=TXDEN
cbusx1=RXLED
cbusx2=TXLED
cbusx3=SLEEP
########
# Misc #
########
filename="eeprom.new" # Filename, leave empty to skip file writing

View File

@ -0,0 +1,8 @@
#ifndef _FTDI_EEPROM_VERSION_H
#define _FTDI_EEPROM_VERSION_H
#define EEPROM_MAJOR_VERSION @EEPROM_MAJOR_VERSION@
#define EEPROM_MINOR_VERSION @EEPROM_MINOR_VERSION@
#define EEPROM_VERSION_STRING "@EEPROM_VERSION_STRING@"
#endif

View File

@ -0,0 +1,666 @@
/***************************************************************************
main.c - description
-------------------
begin : Mon Apr 7 12:05:22 CEST 2003
copyright : (C) 2003-2014 by Intra2net AG and the libftdi developers
email : opensource@intra2net.com
***************************************************************************/
/***************************************************************************
* *
* This program is free software; you can redistribute it and/or modify *
* it under the terms of the GNU General Public License version 2 as *
* published by the Free Software Foundation. *
* *
***************************************************************************/
/*
TODO:
- Merge Uwe's eeprom tool. Current features:
- Init eeprom defaults based upon eeprom type
- Read -> Already there
- Write -> Already there
- Erase -> Already there
- Decode on stdout
- Ability to find device by PID/VID, product name or serial
TODO nice-to-have:
- Out-of-the-box compatibility with FTDI's eeprom tool configuration files
*/
#ifdef HAVE_CONFIG_H
#include <config.h>
#endif
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <errno.h>
#include <sys/stat.h>
#include <confuse.h>
#include <libusb.h>
#include <ftdi.h>
#include <ftdi_eeprom_version.h>
static int parse_cbus(cfg_t *cfg, cfg_opt_t *opt, const char *value, void *result)
{
static const char* options[] =
{
"TXDEN", "PWREN", "RXLED", "TXLED", "TXRXLED", "SLEEP", "CLK48",
"CLK24", "CLK12", "CLK6", "IOMODE", "BB_WR", "BB_RD"
};
int i;
for (i=0; i<sizeof(options)/sizeof(*options); i++)
{
if (!(strcmp(options[i], value)))
{
*(int *)result = i;
return 0;
}
}
cfg_error(cfg, "Invalid %s option '%s'", cfg_opt_name(opt), value);
return -1;
}
static int parse_cbush(cfg_t *cfg, cfg_opt_t *opt, const char *value, void *result)
{
static const char* options[] =
{
"TRISTATE", "TXLED", "RXLED", "TXRXLED", "PWREN", "SLEEP",
"DRIVE_0", "DRIVE1", "IOMODE", "TXDEN", "CLK30", "CLK15", "CLK7_5"
};
int i;
for (i=0; i<sizeof(options)/sizeof(*options); i++)
{
if (!(strcmp(options[i], value)))
{
*(int *)result = i;
return 0;
}
}
cfg_error(cfg, "Invalid %s option '%s'", cfg_opt_name(opt), value);
return -1;
}
static int parse_cbusx(cfg_t *cfg, cfg_opt_t *opt, const char *value, void *result)
{
static const char* options[] =
{
"TRISTATE", "TXLED", "RXLED", "TXRXLED", "PWREN", "SLEEP",
"DRIVE_0", "DRIVE1", "IOMODE", "TXDEN", "CLK24", "CLK12",
"CLK6", "BAT_DETECT", "BAT_DETECT_NEG", "I2C_TXE", "I2C_RXF", "VBUS_SENSE",
"BB_WR", "BB_RD", "TIME_STAMP", "AWAKE"
};
int i;
for (i=0; i<sizeof(options)/sizeof(*options); i++)
{
if (!(strcmp(options[i], value)))
{
*(int *)result = i;
return 0;
}
}
cfg_error(cfg, "Invalid %s option '%s'", cfg_opt_name(opt), value);
return -1;
}
static int parse_chtype(cfg_t *cfg, cfg_opt_t *opt, const char *value, void *result)
{
static const struct
{
char* key;
int opt;
} options[] =
{
{ "UART", CHANNEL_IS_UART },
{ "FIFO", CHANNEL_IS_FIFO },
{ "OPTO", CHANNEL_IS_OPTO },
{ "CPU", CHANNEL_IS_CPU },
{ "FT1284", CHANNEL_IS_FT1284}
};
int i;
for (i=0; i<sizeof(options)/sizeof(*options); i++)
{
if (!(strcmp(options[i].key, value)))
{
*(int *)result = options[i].opt;
return 0;
}
}
cfg_error(cfg, "Invalid %s option '%s'", cfg_opt_name(opt), value);
return -1;
}
/**
* @brief Set eeprom value
*
* \param ftdi pointer to ftdi_context
* \param value_name Enum of the value to set
* \param value Value to set
*
* Function will abort the program on error
**/
static void eeprom_set_value(struct ftdi_context *ftdi, enum ftdi_eeprom_value value_name, int value)
{
if (ftdi_set_eeprom_value(ftdi, value_name, value) < 0)
{
printf("Unable to set eeprom value %d: %s. Aborting\n", value_name, ftdi_get_error_string(ftdi));
exit (-1);
}
}
/**
* @brief Get eeprom value
*
* \param ftdi pointer to ftdi_context
* \param value_name Enum of the value to get
* \param value Value to get
*
* Function will abort the program on error
**/
static void eeprom_get_value(struct ftdi_context *ftdi, enum ftdi_eeprom_value value_name, int *value)
{
if (ftdi_get_eeprom_value(ftdi, value_name, value) < 0)
{
printf("Unable to get eeprom value %d: %s. Aborting\n", value_name, ftdi_get_error_string(ftdi));
exit (-1);
}
}
static void usage(const char *program)
{
fprintf(stderr, "Syntax: %s [...options...] <config-file>\n", program);
fprintf(stderr, "Valid Options:\n");
fprintf(stderr, "--device <description> Specify device to open by description string. One of:\n");
fprintf(stderr, " d:<devicenode>\n");
fprintf(stderr, " i:<vendor>:<product>\n");
fprintf(stderr, " i:<vendor>:<product>:<index>\n");
fprintf(stderr, " s:<vendor>:<product>:<serial>\n");
fprintf(stderr, "--read-eeprom Read eeprom and write to -filename- from config-file\n");
fprintf(stderr, "--build-eeprom Build eeprom image\n");
fprintf(stderr, "--erase-eeprom Erase eeprom\n");
fprintf(stderr, "--flash-eeprom Flash eeprom\n");
}
int main(int argc, char *argv[])
{
/*
configuration options
*/
cfg_opt_t opts[] =
{
CFG_INT("vendor_id", 0, 0),
CFG_INT("product_id", 0, 0),
CFG_BOOL("self_powered", cfg_true, 0),
CFG_BOOL("remote_wakeup", cfg_true, 0),
CFG_BOOL("in_is_isochronous", cfg_false, 0),
CFG_BOOL("out_is_isochronous", cfg_false, 0),
CFG_BOOL("suspend_pull_downs", cfg_false, 0),
CFG_BOOL("use_serial", cfg_false, 0),
CFG_BOOL("change_usb_version", cfg_false, 0),
CFG_INT("usb_version", 0, 0),
CFG_INT("default_pid", 0x6001, 0),
CFG_INT("max_power", 0, 0),
CFG_STR("manufacturer", "Acme Inc.", 0),
CFG_STR("product", "USB Serial Converter", 0),
CFG_STR("serial", "08-15", 0),
CFG_INT("eeprom_type", 0x00, 0),
CFG_STR("filename", "", 0),
CFG_BOOL("flash_raw", cfg_false, 0),
CFG_BOOL("high_current", cfg_false, 0),
CFG_INT_CB("cbus0", -1, 0, parse_cbus),
CFG_INT_CB("cbus1", -1, 0, parse_cbus),
CFG_INT_CB("cbus2", -1, 0, parse_cbus),
CFG_INT_CB("cbus3", -1, 0, parse_cbus),
CFG_INT_CB("cbus4", -1, 0, parse_cbus),
CFG_INT_CB("cbush0", -1, 0, parse_cbush),
CFG_INT_CB("cbush1", -1, 0, parse_cbush),
CFG_INT_CB("cbush2", -1, 0, parse_cbush),
CFG_INT_CB("cbush3", -1, 0, parse_cbush),
CFG_INT_CB("cbush4", -1, 0, parse_cbush),
CFG_INT_CB("cbush5", -1, 0, parse_cbush),
CFG_INT_CB("cbush6", -1, 0, parse_cbush),
CFG_INT_CB("cbush7", -1, 0, parse_cbush),
CFG_INT_CB("cbush8", -1, 0, parse_cbush),
CFG_INT_CB("cbush9", -1, 0, parse_cbush),
CFG_INT_CB("cbusx0", -1, 0, parse_cbusx),
CFG_INT_CB("cbusx1", -1, 0, parse_cbusx),
CFG_INT_CB("cbusx2", -1, 0, parse_cbusx),
CFG_INT_CB("cbusx3", -1, 0, parse_cbusx),
CFG_BOOL("invert_txd", cfg_false, 0),
CFG_BOOL("invert_rxd", cfg_false, 0),
CFG_BOOL("invert_rts", cfg_false, 0),
CFG_BOOL("invert_cts", cfg_false, 0),
CFG_BOOL("invert_dtr", cfg_false, 0),
CFG_BOOL("invert_dsr", cfg_false, 0),
CFG_BOOL("invert_dcd", cfg_false, 0),
CFG_BOOL("invert_ri", cfg_false, 0),
CFG_INT_CB("cha_type", -1, 0, parse_chtype),
CFG_INT_CB("chb_type", -1, 0, parse_chtype),
CFG_BOOL("cha_vcp", cfg_true, 0),
CFG_BOOL("chb_vcp", cfg_true, 0),
CFG_BOOL("chc_vcp", cfg_true, 0),
CFG_BOOL("chd_vcp", cfg_true, 0),
CFG_BOOL("cha_rs485", cfg_false, 0),
CFG_BOOL("chb_rs485", cfg_false, 0),
CFG_BOOL("chc_rs485", cfg_false, 0),
CFG_BOOL("chd_rs485", cfg_false, 0),
CFG_FUNC("include", &cfg_include),
CFG_INT("user_data_addr", 0x18, 0),
CFG_STR("user_data_file", "", 0),
CFG_END()
};
cfg_t *cfg;
/*
normal variables
*/
enum {
COMMAND_READ = 1,
COMMAND_ERASE,
COMMAND_FLASH,
COMMAND_BUILD
} command = 0;
const char *cfg_filename = NULL;
const char *device_description = NULL;
const char *user_data_file = NULL;
char *user_data_buffer = NULL;
const int max_eeprom_size = 256;
int my_eeprom_size = 0;
unsigned char *eeprom_buf = NULL;
char *filename;
int size_check;
int i;
FILE *fp;
struct ftdi_context *ftdi = NULL;
printf("\nFTDI eeprom generator v%s\n", EEPROM_VERSION_STRING);
printf ("(c) Intra2net AG and the libftdi developers <opensource@intra2net.com>\n");
for (i = 1; i < argc; i++) {
if (*argv[i] != '-')
{
cfg_filename = argv[i];
}
else if (!strcmp(argv[i], "--device"))
{
if (i+1 >= argc)
{
usage(argv[0]);
exit(-1);
}
device_description = argv[++i];
}
else if (!strcmp(argv[i], "--read-eeprom"))
{
command = COMMAND_READ;
}
else if (!strcmp(argv[i], "--erase-eeprom"))
{
command = COMMAND_ERASE;
}
else if (!strcmp(argv[i], "--flash-eeprom"))
{
command = COMMAND_FLASH;
}
else if (!strcmp(argv[i], "--build-eeprom"))
{
command = COMMAND_BUILD;
}
else
{
usage(argv[0]);
exit(-1);
}
}
if (!cfg_filename)
{
usage(argv[0]);
exit(-1);
}
if ((fp = fopen(cfg_filename, "r")) == NULL)
{
printf ("Can't open configuration file\n");
exit (-1);
}
fclose (fp);
cfg = cfg_init(opts, 0);
cfg_parse(cfg, cfg_filename);
filename = cfg_getstr(cfg, "filename");
if (cfg_getbool(cfg, "self_powered") && cfg_getint(cfg, "max_power") > 0)
printf("Hint: Self powered devices should have a max_power setting of 0.\n");
if ((ftdi = ftdi_new()) == 0)
{
fprintf(stderr, "Failed to allocate ftdi structure :%s \n",
ftdi_get_error_string(ftdi));
return EXIT_FAILURE;
}
if (device_description != NULL)
{
i = ftdi_usb_open_string(ftdi, device_description);
if (i != 0)
{
printf("Unable to find FTDI device with description: %s\n",
device_description);
printf("Error code: %d (%s)\n", i, ftdi_get_error_string(ftdi));
exit (-1);
}
}
else if (command > 0)
{
int vendor_id = cfg_getint(cfg, "vendor_id");
int product_id = cfg_getint(cfg, "product_id");
i = ftdi_usb_open(ftdi, vendor_id, product_id);
if (i != 0)
{
int default_pid = cfg_getint(cfg, "default_pid");
printf("Unable to find FTDI devices under given vendor/product id: 0x%X/0x%X\n", vendor_id, product_id);
printf("Error code: %d (%s)\n", i, ftdi_get_error_string(ftdi));
printf("Retrying with default FTDI pid=%#04x.\n", default_pid);
i = ftdi_usb_open(ftdi, 0x0403, default_pid);
if (i != 0)
{
printf("Error: %s\n", ftdi->error_str);
exit (-1);
}
}
}
ftdi_eeprom_initdefaults (ftdi, cfg_getstr(cfg, "manufacturer"),
cfg_getstr(cfg, "product"),
cfg_getstr(cfg, "serial"));
printf("FTDI read eeprom: %d\n", ftdi_read_eeprom(ftdi));
eeprom_get_value(ftdi, CHIP_SIZE, &my_eeprom_size);
printf("EEPROM size: %d\n", my_eeprom_size);
if (command == COMMAND_READ)
{
ftdi_eeprom_decode(ftdi, 0 /* debug: 1 */);
eeprom_buf = malloc(my_eeprom_size);
ftdi_get_eeprom_buf(ftdi, eeprom_buf, my_eeprom_size);
if (eeprom_buf == NULL)
{
fprintf(stderr, "Malloc failed, aborting\n");
goto cleanup;
}
if (filename != NULL && strlen(filename) > 0)
{
FILE *fp = fopen (filename, "wb");
if(fp)
{
fwrite(eeprom_buf, 1, my_eeprom_size, fp);
fclose(fp);
}
else
fprintf(stderr, "Could not open output file %s: %s\n", filename, strerror(errno));
}
else
{
printf("Warning: Not writing eeprom, you must supply a valid filename\n");
}
goto cleanup;
}
eeprom_set_value(ftdi, VENDOR_ID, cfg_getint(cfg, "vendor_id"));
eeprom_set_value(ftdi, PRODUCT_ID, cfg_getint(cfg, "product_id"));
eeprom_set_value(ftdi, SELF_POWERED, cfg_getbool(cfg, "self_powered"));
eeprom_set_value(ftdi, REMOTE_WAKEUP, cfg_getbool(cfg, "remote_wakeup"));
eeprom_set_value(ftdi, MAX_POWER, cfg_getint(cfg, "max_power"));
eeprom_set_value(ftdi, IN_IS_ISOCHRONOUS, cfg_getbool(cfg, "in_is_isochronous"));
eeprom_set_value(ftdi, OUT_IS_ISOCHRONOUS, cfg_getbool(cfg, "out_is_isochronous"));
eeprom_set_value(ftdi, SUSPEND_PULL_DOWNS, cfg_getbool(cfg, "suspend_pull_downs"));
eeprom_set_value(ftdi, USE_SERIAL, cfg_getbool(cfg, "use_serial"));
eeprom_set_value(ftdi, USE_USB_VERSION, cfg_getbool(cfg, "change_usb_version"));
eeprom_set_value(ftdi, USB_VERSION, cfg_getint(cfg, "usb_version"));
eeprom_set_value(ftdi, CHIP_TYPE, cfg_getint(cfg, "eeprom_type"));
eeprom_set_value(ftdi, HIGH_CURRENT, cfg_getbool(cfg, "high_current"));
if (ftdi->type == TYPE_R)
{
if (cfg_getint(cfg, "cbus0") != -1)
eeprom_set_value(ftdi, CBUS_FUNCTION_0, cfg_getint(cfg, "cbus0"));
if (cfg_getint(cfg, "cbus1") != -1)
eeprom_set_value(ftdi, CBUS_FUNCTION_1, cfg_getint(cfg, "cbus1"));
if (cfg_getint(cfg, "cbus2") != -1)
eeprom_set_value(ftdi, CBUS_FUNCTION_2, cfg_getint(cfg, "cbus2"));
if (cfg_getint(cfg, "cbus3") != -1)
eeprom_set_value(ftdi, CBUS_FUNCTION_3, cfg_getint(cfg, "cbus3"));
if (cfg_getint(cfg, "cbus4") != -1)
eeprom_set_value(ftdi, CBUS_FUNCTION_4, cfg_getint(cfg, "cbus4"));
}
else if (ftdi->type == TYPE_232H)
{
if (cfg_getint(cfg, "cbush0") != -1)
eeprom_set_value(ftdi, CBUS_FUNCTION_0, cfg_getint(cfg, "cbush0"));
if (cfg_getint(cfg, "cbush1") != -1)
eeprom_set_value(ftdi, CBUS_FUNCTION_1, cfg_getint(cfg, "cbush1"));
if (cfg_getint(cfg, "cbush2") != -1)
eeprom_set_value(ftdi, CBUS_FUNCTION_2, cfg_getint(cfg, "cbush2"));
if (cfg_getint(cfg, "cbush3") != -1)
eeprom_set_value(ftdi, CBUS_FUNCTION_3, cfg_getint(cfg, "cbush3"));
if (cfg_getint(cfg, "cbush4") != -1)
eeprom_set_value(ftdi, CBUS_FUNCTION_4, cfg_getint(cfg, "cbush4"));
if (cfg_getint(cfg, "cbush5") != -1)
eeprom_set_value(ftdi, CBUS_FUNCTION_5, cfg_getint(cfg, "cbush5"));
if (cfg_getint(cfg, "cbush6") != -1)
eeprom_set_value(ftdi, CBUS_FUNCTION_6, cfg_getint(cfg, "cbush6"));
if (cfg_getint(cfg, "cbush7") != -1)
eeprom_set_value(ftdi, CBUS_FUNCTION_7, cfg_getint(cfg, "cbush7"));
if (cfg_getint(cfg, "cbush8") != -1)
eeprom_set_value(ftdi, CBUS_FUNCTION_8, cfg_getint(cfg, "cbush8"));
if (cfg_getint(cfg, "cbush9") != -1)
eeprom_set_value(ftdi, CBUS_FUNCTION_9, cfg_getint(cfg, "cbush9"));
}
else if (ftdi->type == TYPE_230X)
{
if (cfg_getint(cfg, "cbusx0") != -1)
eeprom_set_value(ftdi, CBUS_FUNCTION_0, cfg_getint(cfg, "cbusx0"));
if (cfg_getint(cfg, "cbusx1") != -1)
eeprom_set_value(ftdi, CBUS_FUNCTION_1, cfg_getint(cfg, "cbusx1"));
if (cfg_getint(cfg, "cbusx2") != -1)
eeprom_set_value(ftdi, CBUS_FUNCTION_2, cfg_getint(cfg, "cbusx2"));
if (cfg_getint(cfg, "cbusx3") != -1)
eeprom_set_value(ftdi, CBUS_FUNCTION_3, cfg_getint(cfg, "cbusx3"));
}
int invert = 0;
if (cfg_getbool(cfg, "invert_rxd")) invert |= INVERT_RXD;
if (cfg_getbool(cfg, "invert_txd")) invert |= INVERT_TXD;
if (cfg_getbool(cfg, "invert_rts")) invert |= INVERT_RTS;
if (cfg_getbool(cfg, "invert_cts")) invert |= INVERT_CTS;
if (cfg_getbool(cfg, "invert_dtr")) invert |= INVERT_DTR;
if (cfg_getbool(cfg, "invert_dsr")) invert |= INVERT_DSR;
if (cfg_getbool(cfg, "invert_dcd")) invert |= INVERT_DCD;
if (cfg_getbool(cfg, "invert_ri")) invert |= INVERT_RI;
eeprom_set_value(ftdi, INVERT, invert);
if (cfg_getint(cfg, "cha_type") != -1)
eeprom_set_value(ftdi, CHANNEL_A_TYPE, cfg_getint(cfg, "cha_type"));
if (cfg_getint(cfg, "chb_type") != -1)
eeprom_set_value(ftdi, CHANNEL_B_TYPE, cfg_getint(cfg, "chb_type"));
eeprom_set_value(ftdi, CHANNEL_A_DRIVER,
cfg_getbool(cfg, "cha_vcp") ? DRIVER_VCP : 0);
eeprom_set_value(ftdi, CHANNEL_B_DRIVER,
cfg_getbool(cfg, "chb_vcp") ? DRIVER_VCP : 0);
eeprom_set_value(ftdi, CHANNEL_C_DRIVER,
cfg_getbool(cfg, "chc_vcp") ? DRIVER_VCP : 0);
eeprom_set_value(ftdi, CHANNEL_D_DRIVER,
cfg_getbool(cfg, "chd_vcp") ? DRIVER_VCP : 0);
eeprom_set_value(ftdi, CHANNEL_A_RS485, cfg_getbool(cfg, "cha_rs485"));
eeprom_set_value(ftdi, CHANNEL_B_RS485, cfg_getbool(cfg, "chb_rs485"));
eeprom_set_value(ftdi, CHANNEL_C_RS485, cfg_getbool(cfg, "chc_rs485"));
eeprom_set_value(ftdi, CHANNEL_D_RS485, cfg_getbool(cfg, "chd_rs485"));
/* Arbitrary user data */
eeprom_set_value(ftdi, USER_DATA_ADDR, cfg_getint(cfg, "user_data_addr"));
user_data_file = cfg_getstr(cfg, "user_data_file");
if (user_data_file && strlen(user_data_file) > 0)
{
int data_size;
struct stat st;
printf("User data file: %s\n", user_data_file);
/* Allocate a buffer for the user data */
user_data_buffer = (char *)malloc(max_eeprom_size);
if (user_data_buffer == NULL)
{
fprintf(stderr, "Malloc failed, aborting\n");
goto cleanup;
}
if (stat(user_data_file, &st))
{
printf ("Can't stat user data file %s.\n", user_data_file);
exit (-1);
}
if (st.st_size > max_eeprom_size)
printf("Warning: %s is too big, only reading %d bytes\n",
user_data_file, max_eeprom_size);
/* Read the user data file, no more than max_eeprom_size bytes */
FILE *fp = fopen(user_data_file, "rb");
if (fp == NULL)
{
printf ("Can't open user data file %s.\n", user_data_file);
exit (-1);
}
data_size = fread(user_data_buffer, 1, max_eeprom_size, fp);
fclose(fp);
if (data_size < 1)
{
printf ("Can't read user data file %s.\n", user_data_file);
exit (-1);
}
printf("User data size: %d\n", data_size);
ftdi_set_eeprom_user_data(ftdi, user_data_buffer, data_size);
}
if (command == COMMAND_ERASE)
{
printf("FTDI erase eeprom: %d\n", ftdi_erase_eeprom(ftdi));
}
size_check = ftdi_eeprom_build(ftdi);
eeprom_get_value(ftdi, CHIP_SIZE, &my_eeprom_size);
if (size_check == -1)
{
printf ("Sorry, the eeprom can only contain %d bytes.\n", my_eeprom_size);
goto cleanup;
}
else if (size_check < 0)
{
printf ("ftdi_eeprom_build(): error: %d\n", size_check);
goto cleanup;
}
else
{
printf ("Used eeprom space: %d bytes\n", my_eeprom_size-size_check);
}
if (command == COMMAND_FLASH)
{
if (cfg_getbool(cfg, "flash_raw"))
{
if (filename != NULL && strlen(filename) > 0)
{
eeprom_buf = malloc(max_eeprom_size);
FILE *fp = fopen(filename, "rb");
if (fp == NULL)
{
printf ("Can't open eeprom file %s.\n", filename);
exit (-1);
}
my_eeprom_size = fread(eeprom_buf, 1, max_eeprom_size, fp);
fclose(fp);
if (my_eeprom_size < 128)
{
printf ("Can't read eeprom file %s.\n", filename);
exit (-1);
}
printf("Flashing raw eeprom from file %s (%d bytes)\n",
filename, my_eeprom_size);
ftdi_set_eeprom_buf(ftdi, eeprom_buf, my_eeprom_size);
} else
{
printf ("ERROR: flash_raw mode enabled, but no eeprom filename "
"given in config file.\n");
exit (-1);
}
}
printf ("FTDI write eeprom: %d\n", ftdi_write_eeprom(ftdi));
libusb_reset_device(ftdi->usb_dev);
}
// Write to file?
if (filename != NULL && strlen(filename) > 0 && !cfg_getbool(cfg, "flash_raw"))
{
fp = fopen(filename, "w");
if (fp == NULL)
{
printf ("Can't write eeprom file.\n");
exit (-1);
}
else
printf ("Writing to file: %s\n", filename);
if (eeprom_buf == NULL)
eeprom_buf = malloc(my_eeprom_size);
ftdi_get_eeprom_buf(ftdi, eeprom_buf, my_eeprom_size);
fwrite(eeprom_buf, my_eeprom_size, 1, fp);
fclose(fp);
}
cleanup:
if (eeprom_buf)
free(eeprom_buf);
if (user_data_buffer)
free(user_data_buffer);
if (command > 0)
{
printf("FTDI close: %d\n", ftdi_usb_close(ftdi));
}
ftdi_deinit (ftdi);
ftdi_free (ftdi);
cfg_free(cfg);
printf("\n");
return 0;
}

View File

@ -0,0 +1,72 @@
# Check
set(FTDI_BUILD_CPP False PARENT_SCOPE)
option ( FTDIPP "Build C++ binding library libftdi1++" ON )
# Targets
set(cpp_sources ${CMAKE_CURRENT_SOURCE_DIR}/ftdi.cpp CACHE INTERNAL "List of cpp sources" )
set(cpp_headers ${CMAKE_CURRENT_SOURCE_DIR}/ftdi.hpp CACHE INTERNAL "List of cpp headers" )
if (FTDIPP)
if(Boost_FOUND)
set(FTDI_BUILD_CPP True PARENT_SCOPE)
message(STATUS "Building libftdi1++")
# Shared library
add_library(ftdipp1 SHARED ${cpp_sources})
target_include_directories(ftdipp1 BEFORE PUBLIC ${CMAKE_CURRENT_BINARY_DIR}
${CMAKE_CURRENT_SOURCE_DIR}
${CMAKE_CURRENT_SOURCE_DIR}/../src)
target_include_directories(ftdipp1 PUBLIC ${Boost_INCLUDE_DIRS})
math(EXPR VERSION_FIXUP "${MAJOR_VERSION} + 1") # Compatiblity with previous releases
set_target_properties(ftdipp1 PROPERTIES VERSION ${VERSION_FIXUP}.${MINOR_VERSION}.0 SOVERSION 3)
# Prevent clobbering each other during the build
set_target_properties(ftdipp1 PROPERTIES CLEAN_DIRECT_OUTPUT 1)
# Dependencies
target_link_libraries(ftdipp1 PUBLIC ftdi1 ${LIBUSB_LIBRARIES} ${BOOST_LIBRARIES})
if ( LIBFTDI_INSTALL )
install ( TARGETS ftdipp1
RUNTIME DESTINATION bin
LIBRARY DESTINATION lib${LIB_SUFFIX}
ARCHIVE DESTINATION lib${LIB_SUFFIX}
)
endif()
# Static library
if ( LIBFTDI_STATICLIBS )
add_library(ftdipp1-static STATIC ${cpp_sources})
target_include_directories(ftdipp1-static BEFORE PUBLIC ${CMAKE_CURRENT_BINARY_DIR}
${CMAKE_CURRENT_SOURCE_DIR}
${CMAKE_CURRENT_SOURCE_DIR}/../src)
target_include_directories(ftdipp1-static PUBLIC ${Boost_INCLUDE_DIRS})
target_link_libraries(ftdipp1-static PUBLIC ftdi1 ${LIBUSB_LIBRARIES} ${BOOST_LIBRARIES})
set_target_properties(ftdipp1-static PROPERTIES OUTPUT_NAME "ftdipp1")
set_target_properties(ftdipp1-static PROPERTIES CLEAN_DIRECT_OUTPUT 1)
if ( LIBFTDI_INSTALL )
install ( TARGETS ftdipp1-static
ARCHIVE DESTINATION lib${LIB_SUFFIX}
COMPONENT staticlibs
)
endif()
endif ()
install ( FILES ${cpp_headers}
DESTINATION include/${PROJECT_NAME}
COMPONENT headers
)
else ()
message(STATUS "Boost not found, won't build libftdi1++")
endif ()
else ()
message(STATUS "Not building libftdi1++")
endif ()

View File

@ -0,0 +1,675 @@
/***************************************************************************
ftdi.cpp - C++ wraper for libftdi
-------------------
begin : Mon Oct 13 2008
copyright : (C) 2008-2017 by Marek Vavruša / libftdi developers
email : opensource@intra2net.com and marek@vavrusa.com
***************************************************************************/
/*
Copyright (C) 2008-2017 by Marek Vavruša / libftdi developers
The software in this package is distributed under the GNU General
Public License version 2 (with a special exception described below).
A copy of GNU General Public License (GPL) is included in this distribution,
in the file COPYING.GPL.
As a special exception, if other files instantiate templates or use macros
or inline functions from this file, or you compile this file and link it
with other works to produce a work based on this file, this file
does not by itself cause the resulting work to be covered
by the GNU General Public License.
However the source code for this file must still be made available
in accordance with section (3) of the GNU General Public License.
This exception does not invalidate any other reasons why a work based
on this file might be covered by the GNU General Public License.
*/
#include <libusb.h>
#include "ftdi.hpp"
#include "ftdi_i.h"
#include "ftdi.h"
namespace Ftdi
{
class Context::Private
{
public:
Private()
: open(false), ftdi(0), dev(0)
{
ftdi = ftdi_new();
}
~Private()
{
if (open)
ftdi_usb_close(ftdi);
ftdi_free(ftdi);
}
bool open;
struct ftdi_context* ftdi;
struct libusb_device* dev;
std::string vendor;
std::string description;
std::string serial;
};
/*! \brief Constructor.
*/
Context::Context()
: d( new Private() )
{
}
/*! \brief Destructor.
*/
Context::~Context()
{
}
bool Context::is_open()
{
return d->open;
}
int Context::open(int vendor, int product)
{
// Open device
int ret = ftdi_usb_open(d->ftdi, vendor, product);
if (ret < 0)
return ret;
return get_strings_and_reopen(false,false,false);
}
int Context::open(int vendor, int product, const std::string& description, const std::string& serial, unsigned int index)
{
// translate empty strings to NULL
// -> do not use them to find the device (vs. require an empty string to be set in the EEPROM)
const char* c_description=NULL;
const char* c_serial=NULL;
if (!description.empty())
c_description=description.c_str();
if (!serial.empty())
c_serial=serial.c_str();
int ret = ftdi_usb_open_desc_index(d->ftdi, vendor, product, c_description, c_serial, index);
if (ret < 0)
return ret;
return get_strings_and_reopen(false,!description.empty(),!serial.empty());
}
int Context::open(const std::string& description)
{
int ret = ftdi_usb_open_string(d->ftdi, description.c_str());
if (ret < 0)
return ret;
return get_strings_and_reopen(false,true,false);
}
int Context::open(struct libusb_device *dev)
{
if (dev != 0)
d->dev = dev;
if (d->dev == 0)
return -1;
return get_strings_and_reopen();
}
int Context::close()
{
d->open = false;
d->dev = 0;
return ftdi_usb_close(d->ftdi);
}
int Context::reset()
{
return ftdi_usb_reset(d->ftdi);
}
int Context::flush(int mask)
{
int ret;
switch (mask & (Input | Output)) {
case Input:
ret = ftdi_usb_purge_rx_buffer(d->ftdi);
break;
case Output:
ret = ftdi_usb_purge_tx_buffer(d->ftdi);
break;
case Input | Output:
ret = ftdi_usb_purge_buffers(d->ftdi);
break;
default:
// Emulate behavior of previous version.
ret = 1;
break;
}
return ret;
}
int Context::set_interface(enum ftdi_interface interface)
{
return ftdi_set_interface(d->ftdi, interface);
}
void Context::set_usb_device(struct libusb_device_handle *dev)
{
ftdi_set_usbdev(d->ftdi, dev);
d->dev = libusb_get_device(dev);
}
int Context::set_baud_rate(int baudrate)
{
return ftdi_set_baudrate(d->ftdi, baudrate);
}
int Context::set_line_property(enum ftdi_bits_type bits, enum ftdi_stopbits_type sbit, enum ftdi_parity_type parity)
{
return ftdi_set_line_property(d->ftdi, bits, sbit, parity);
}
int Context::set_line_property(enum ftdi_bits_type bits, enum ftdi_stopbits_type sbit, enum ftdi_parity_type parity, enum ftdi_break_type break_type)
{
return ftdi_set_line_property2(d->ftdi, bits, sbit, parity, break_type);
}
int Context::get_usb_read_timeout() const
{
return d->ftdi->usb_read_timeout;
}
void Context::set_usb_read_timeout(int usb_read_timeout)
{
d->ftdi->usb_read_timeout = usb_read_timeout;
}
int Context::get_usb_write_timeout() const
{
return d->ftdi->usb_write_timeout;
}
void Context::set_usb_write_timeout(int usb_write_timeout)
{
d->ftdi->usb_write_timeout = usb_write_timeout;
}
int Context::read(unsigned char *buf, int size)
{
return ftdi_read_data(d->ftdi, buf, size);
}
int Context::set_read_chunk_size(unsigned int chunksize)
{
return ftdi_read_data_set_chunksize(d->ftdi, chunksize);
}
int Context::read_chunk_size()
{
unsigned chunk = -1;
if (ftdi_read_data_get_chunksize(d->ftdi, &chunk) < 0)
return -1;
return chunk;
}
int Context::write(const unsigned char *buf, int size)
{
return ftdi_write_data(d->ftdi, buf, size);
}
int Context::set_write_chunk_size(unsigned int chunksize)
{
return ftdi_write_data_set_chunksize(d->ftdi, chunksize);
}
int Context::write_chunk_size()
{
unsigned chunk = -1;
if (ftdi_write_data_get_chunksize(d->ftdi, &chunk) < 0)
return -1;
return chunk;
}
int Context::set_flow_control(int flowctrl)
{
return ftdi_setflowctrl(d->ftdi, flowctrl);
}
int Context::set_modem_control(int mask)
{
int dtr = 0, rts = 0;
if (mask & Dtr)
dtr = 1;
if (mask & Rts)
rts = 1;
return ftdi_setdtr_rts(d->ftdi, dtr, rts);
}
int Context::set_dtr(bool state)
{
return ftdi_setdtr(d->ftdi, state);
}
int Context::set_rts(bool state)
{
return ftdi_setrts(d->ftdi, state);
}
int Context::set_latency(unsigned char latency)
{
return ftdi_set_latency_timer(d->ftdi, latency);
}
unsigned Context::latency()
{
unsigned char latency = 0;
ftdi_get_latency_timer(d->ftdi, &latency);
return latency;
}
unsigned short Context::poll_modem_status()
{
unsigned short status = 0;
ftdi_poll_modem_status(d->ftdi, &status);
return status;
}
int Context::set_event_char(unsigned char eventch, unsigned char enable)
{
return ftdi_set_event_char(d->ftdi, eventch, enable);
}
int Context::set_error_char(unsigned char errorch, unsigned char enable)
{
return ftdi_set_error_char(d->ftdi, errorch, enable);
}
int Context::set_bitmode(unsigned char bitmask, unsigned char mode)
{
return ftdi_set_bitmode(d->ftdi, bitmask, mode);
}
int Context::set_bitmode(unsigned char bitmask, enum ftdi_mpsse_mode mode)
{
return ftdi_set_bitmode(d->ftdi, bitmask, mode);
}
int Context::bitbang_disable()
{
return ftdi_disable_bitbang(d->ftdi);
}
int Context::read_pins(unsigned char *pins)
{
return ftdi_read_pins(d->ftdi, pins);
}
const char* Context::error_string()
{
return ftdi_get_error_string(d->ftdi);
}
int Context::get_strings(bool vendor, bool description, bool serial)
{
// Prepare buffers
char ivendor[512], idesc[512], iserial[512];
int ret = ftdi_usb_get_strings(d->ftdi, d->dev, vendor?ivendor:NULL, 512, description?idesc:NULL, 512, serial?iserial:NULL, 512);
if (ret < 0)
return -1;
d->vendor = ivendor;
d->description = idesc;
d->serial = iserial;
return 1;
}
int Context::get_strings_and_reopen(bool vendor, bool description, bool serial)
{
int ret = 0;
if(vendor || description || serial)
{
if (d->dev == 0)
{
d->dev = libusb_get_device(d->ftdi->usb_dev);
}
// Get device strings (closes device)
ret=get_strings(vendor, description, serial);
if (ret < 0)
{
d->open = 0;
return ret;
}
// Reattach device
ret = ftdi_usb_open_dev(d->ftdi, d->dev);
d->open = (ret >= 0);
}
return ret;
}
/*! \brief Device strings properties.
*/
const std::string& Context::vendor()
{
if(d->vendor.empty())
get_strings_and_reopen(true,false,false);
return d->vendor;
}
/*! \brief Device strings properties.
*/
const std::string& Context::description()
{
if(d->description.empty())
get_strings_and_reopen(false,true,false);
return d->description;
}
/*! \brief Device strings properties.
*/
const std::string& Context::serial()
{
if(d->serial.empty())
get_strings_and_reopen(false,false,true);
return d->serial;
}
void Context::set_context(struct ftdi_context* context)
{
ftdi_free(d->ftdi);
d->ftdi = context;
}
void Context::set_usb_device(struct libusb_device *dev)
{
d->dev = dev;
}
struct ftdi_context* Context::context()
{
return d->ftdi;
}
class Eeprom::Private
{
public:
Private()
: context(0)
{}
struct ftdi_eeprom eeprom;
struct ftdi_context* context;
};
Eeprom::Eeprom(Context* parent)
: d ( new Private() )
{
d->context = parent->context();
}
Eeprom::~Eeprom()
{
}
int Eeprom::init_defaults(char* manufacturer, char *product, char * serial)
{
return ftdi_eeprom_initdefaults(d->context, manufacturer, product, serial);
}
int Eeprom::chip_id(unsigned int *chipid)
{
return ftdi_read_chipid(d->context, chipid);
}
int Eeprom::build(unsigned char *output)
{
return ftdi_eeprom_build(d->context);
}
int Eeprom::read(unsigned char *eeprom)
{
return ftdi_read_eeprom(d->context);
}
int Eeprom::write(unsigned char *eeprom)
{
return ftdi_write_eeprom(d->context);
}
int Eeprom::read_location(int eeprom_addr, unsigned short *eeprom_val)
{
return ftdi_read_eeprom_location(d->context, eeprom_addr, eeprom_val);
}
int Eeprom::write_location(int eeprom_addr, unsigned short eeprom_val)
{
return ftdi_write_eeprom_location(d->context, eeprom_addr, eeprom_val);
}
int Eeprom::erase()
{
return ftdi_erase_eeprom(d->context);
}
class List::Private
{
public:
Private(struct ftdi_device_list* _devlist)
: devlist(_devlist)
{}
~Private()
{
if(devlist)
ftdi_list_free(&devlist);
}
std::list<Context> list;
struct ftdi_device_list* devlist;
};
List::List(struct ftdi_device_list* devlist)
: d( new Private(devlist) )
{
if (devlist != 0)
{
// Iterate list
for (; devlist != 0; devlist = devlist->next)
{
Context c;
c.set_usb_device(devlist->dev);
c.get_strings();
d->list.push_back(c);
}
}
}
List::~List()
{
}
/**
* Return begin iterator for accessing the contained list elements
* @return Iterator
*/
List::iterator List::begin()
{
return d->list.begin();
}
/**
* Return end iterator for accessing the contained list elements
* @return Iterator
*/
List::iterator List::end()
{
return d->list.end();
}
/**
* Return begin iterator for accessing the contained list elements
* @return Const iterator
*/
List::const_iterator List::begin() const
{
return d->list.begin();
}
/**
* Return end iterator for accessing the contained list elements
* @return Const iterator
*/
List::const_iterator List::end() const
{
return d->list.end();
}
/**
* Return begin reverse iterator for accessing the contained list elements
* @return Reverse iterator
*/
List::reverse_iterator List::rbegin()
{
return d->list.rbegin();
}
/**
* Return end reverse iterator for accessing the contained list elements
* @return Reverse iterator
*/
List::reverse_iterator List::rend()
{
return d->list.rend();
}
/**
* Return begin reverse iterator for accessing the contained list elements
* @return Const reverse iterator
*/
List::const_reverse_iterator List::rbegin() const
{
return d->list.rbegin();
}
/**
* Return end reverse iterator for accessing the contained list elements
* @return Const reverse iterator
*/
List::const_reverse_iterator List::rend() const
{
return d->list.rend();
}
/**
* Get number of elements stored in the list
* @return Number of elements
*/
List::ListType::size_type List::size() const
{
return d->list.size();
}
/**
* Check if list is empty
* @return True if empty, false otherwise
*/
bool List::empty() const
{
return d->list.empty();
}
/**
* Removes all elements. Invalidates all iterators.
* Do it in a non-throwing way and also make
* sure we really free the allocated memory.
*/
void List::clear()
{
ListType().swap(d->list);
// Free device list
if (d->devlist)
{
ftdi_list_free(&d->devlist);
d->devlist = 0;
}
}
/**
* Appends a copy of the element as the new last element.
* @param element Value to copy and append
*/
void List::push_back(const Context& element)
{
d->list.push_back(element);
}
/**
* Adds a copy of the element as the new first element.
* @param element Value to copy and add
*/
void List::push_front(const Context& element)
{
d->list.push_front(element);
}
/**
* Erase one element pointed by iterator
* @param pos Element to erase
* @return Position of the following element (or end())
*/
List::iterator List::erase(iterator pos)
{
return d->list.erase(pos);
}
/**
* Erase a range of elements
* @param beg Begin of range
* @param end End of range
* @return Position of the element after the erased range (or end())
*/
List::iterator List::erase(iterator beg, iterator end)
{
return d->list.erase(beg, end);
}
List* List::find_all(Context &context, int vendor, int product)
{
struct ftdi_device_list* dlist = 0;
ftdi_usb_find_all(context.context(), &dlist, vendor, product);
return new List(dlist);
}
}

View File

@ -0,0 +1,221 @@
/***************************************************************************
ftdi.hpp - C++ wrapper for libftdi
-------------------
begin : Mon Oct 13 2008
copyright : (C) 2008-2017 by Marek Vavruša and libftdi developers
email : opensource@intra2net.com and marek@vavrusa.com
***************************************************************************/
/*
Copyright (C) 2008-2017 by Marek Vavruša and libftdi developers
The software in this package is distributed under the GNU General
Public License version 2 (with a special exception described below).
A copy of GNU General Public License (GPL) is included in this distribution,
in the file COPYING.GPL.
As a special exception, if other files instantiate templates or use macros
or inline functions from this file, or you compile this file and link it
with other works to produce a work based on this file, this file
does not by itself cause the resulting work to be covered
by the GNU General Public License.
However the source code for this file must still be made available
in accordance with section (3) of the GNU General Public License.
This exception does not invalidate any other reasons why a work based
on this file might be covered by the GNU General Public License.
*/
#ifndef __libftdi_hpp__
#define __libftdi_hpp__
#include <list>
#include <string>
#include <boost/shared_ptr.hpp>
#include <ftdi.h>
namespace Ftdi
{
/* Forward declarations*/
class List;
class Eeprom;
/*! \brief FTDI device context.
* Represents single FTDI device context.
*/
class Context
{
/* Friends */
friend class Eeprom;
friend class List;
public:
/*! \brief Direction flags for flush().
*/
enum Direction
{
Input = 0x2,
Output = 0x1,
};
/*! \brief Modem control flags.
*/
enum ModemCtl
{
Dtr = 0x2,
Rts = 0x1,
};
/* Constructor, Destructor */
Context();
~Context();
/* Properties */
Eeprom* eeprom();
const std::string& vendor();
const std::string& description();
const std::string& serial();
/* Device manipulators */
bool is_open();
int open(struct libusb_device *dev = 0);
int open(int vendor, int product);
int open(int vendor, int product, const std::string& description, const std::string& serial = std::string(), unsigned int index=0);
int open(const std::string& description);
int close();
int reset();
int flush(int mask = Input|Output);
int set_interface(enum ftdi_interface interface);
void set_usb_device(struct libusb_device_handle *dev);
/* Line manipulators */
int set_baud_rate(int baudrate);
int set_line_property(enum ftdi_bits_type bits, enum ftdi_stopbits_type sbit, enum ftdi_parity_type parity);
int set_line_property(enum ftdi_bits_type bits, enum ftdi_stopbits_type sbit, enum ftdi_parity_type parity, enum ftdi_break_type break_type);
int get_usb_read_timeout() const;
void set_usb_read_timeout(int usb_read_timeout);
int get_usb_write_timeout() const;
void set_usb_write_timeout(int usb_write_timeout);
/* I/O */
int read(unsigned char *buf, int size);
int write(const unsigned char *buf, int size);
int set_read_chunk_size(unsigned int chunksize);
int set_write_chunk_size(unsigned int chunksize);
int read_chunk_size();
int write_chunk_size();
/* Async IO
TODO: should wrap?
int writeAsync(const unsigned char *buf, int size);
void asyncComplete(int wait_for_more);
*/
/* Flow control */
int set_event_char(unsigned char eventch, unsigned char enable);
int set_error_char(unsigned char errorch, unsigned char enable);
int set_flow_control(int flowctrl);
int set_modem_control(int mask = Dtr|Rts);
int set_latency(unsigned char latency);
int set_dtr(bool state);
int set_rts(bool state);
unsigned short poll_modem_status();
unsigned latency();
/* BitBang mode */
int set_bitmode(unsigned char bitmask, unsigned char mode);
int set_bitmode(unsigned char bitmask, enum ftdi_mpsse_mode mode);
int bitbang_disable();
int read_pins(unsigned char *pins);
/* Misc */
const char* error_string();
protected:
int get_strings(bool vendor=true, bool description=true, bool serial=true);
int get_strings_and_reopen(bool vendor=true, bool description=true, bool serial=true);
/* Properties */
struct ftdi_context* context();
void set_context(struct ftdi_context* context);
void set_usb_device(struct libusb_device *dev);
private:
class Private;
boost::shared_ptr<Private> d;
};
/*! \brief Device EEPROM.
*/
class Eeprom
{
public:
Eeprom(Context* parent);
~Eeprom();
int init_defaults(char *manufacturer, char* product, char * serial);
int chip_id(unsigned int *chipid);
int build(unsigned char *output);
int read(unsigned char *eeprom);
int write(unsigned char *eeprom);
int read_location(int eeprom_addr, unsigned short *eeprom_val);
int write_location(int eeprom_addr, unsigned short eeprom_val);
int erase();
private:
class Private;
boost::shared_ptr<Private> d;
};
/*! \brief Device list.
*/
class List
{
public:
List(struct ftdi_device_list* devlist = 0);
~List();
static List* find_all(Context &context, int vendor, int product);
/// List type storing "Context" objects
typedef std::list<Context> ListType;
/// Iterator type for the container
typedef ListType::iterator iterator;
/// Const iterator type for the container
typedef ListType::const_iterator const_iterator;
/// Reverse iterator type for the container
typedef ListType::reverse_iterator reverse_iterator;
/// Const reverse iterator type for the container
typedef ListType::const_reverse_iterator const_reverse_iterator;
iterator begin();
iterator end();
const_iterator begin() const;
const_iterator end() const;
reverse_iterator rbegin();
reverse_iterator rend();
const_reverse_iterator rbegin() const;
const_reverse_iterator rend() const;
ListType::size_type size() const;
bool empty() const;
void clear();
void push_back(const Context& element);
void push_front(const Context& element);
iterator erase(iterator pos);
iterator erase(iterator beg, iterator end);
private:
class Private;
boost::shared_ptr<Private> d;
};
}
#endif

View File

@ -0,0 +1,3 @@
[Project]
Manager=KDevCMakeManager
Name=libftdi-1.0

28
third-party/libftdi/libftdi.lnt vendored 100644
View File

@ -0,0 +1,28 @@
// PC-Lint 9.00 settings
--iz:\usr\include\libusb-1.0
--i../src
--i../ftdipp
-emacro(527, ftdi_error_return) // ignore "unreachable code"
-emacro(717, ftdi_error_return)
-epu // Pointer to unsigned/signed of the same type is ok
+fie // Allow enum to int conversion
-ecall(534, usb_close) // silence ignored return value from usb_close
// Disable bogus BOOST warnings
-emacro(58,BOOST_ASSERT)
-emacro(506, BOOST_FOREACH)
-emacro(666, BOOST_FOREACH)
-esym(666, BOOST_FOREACH)
-emacro(1023, BOOST_FOREACH)
-emacro(1793, BOOST_FOREACH)
-esym(665, BOOST_FOREACH)
-e123
// Don't complain we are running with -wlib(0)
// as the boost headers can't be parsed properly
-estring(686, -wlib(0))
-wlib(0)

View File

@ -0,0 +1,79 @@
#!/bin/sh
prefix=@prefix@
exec_prefix=@exec_prefix@
exec_prefix_set=no
usage()
{
cat <<EOF
Usage: libftdi1-config [OPTIONS] [LIBRARIES]
Options:
[--prefix[=DIR]]
[--exec-prefix[=DIR]]
[--version]
[--libs]
[--cflags]
EOF
exit $1
}
if test $# -eq 0; then
usage 1 1>&2
fi
while test $# -gt 0; do
case "$1" in
-*=*) optarg=`echo "$1" | sed 's/[-_a-zA-Z0-9]*=//'` ;;
*) optarg= ;;
esac
case $1 in
--prefix=*)
prefix=$optarg
if test $exec_prefix_set = no ; then
exec_prefix=$optarg
fi
;;
--prefix)
echo_prefix=yes
;;
--exec-prefix=*)
exec_prefix=$optarg
exec_prefix_set=yes
;;
--exec-prefix)
echo_exec_prefix=yes
;;
--version)
echo @VERSION@
exit 0
;;
--cflags)
if test "@includedir@" != /usr/include ; then
includes="-I@includedir@"
fi
echo_cflags=yes
;;
--libs)
echo_libs=yes
;;
*)
usage 1 1>&2
;;
esac
shift
done
if test "$echo_prefix" = "yes"; then
echo $prefix
fi
if test "$echo_exec_prefix" = "yes"; then
echo $exec_prefix
fi
if test "$echo_cflags" = "yes"; then
echo $includes
fi
if test "$echo_libs" = "yes"; then
echo -L@libdir@ -lftdi1 @LIBS@
fi

View File

@ -0,0 +1,11 @@
prefix=@prefix@
exec_prefix=@exec_prefix@
libdir=@libdir@
includedir=@includedir@
Name: libftdi1
Description: Library to program and control the FTDI USB controller
Requires: libusb-1.0
Version: @VERSION@
Libs: -L${libdir} -lftdi1
Cflags: -I${includedir}

View File

@ -0,0 +1,100 @@
%{!?python_sitearch: %define python_sitearch %(%{__python} -c "from distutils.sysconfig import get_python_lib; print get_python_lib(1)")}
Summary: Library to program and control the FTDI USB controller
Name: libftdi1
Version: @VERSION@
Release: 1
License: LGPL for libftdi and GPLv2+linking exception for the C++ wrapper
Group: System Environment/Libraries
Vendor: Intra2net AG
Source: https://www.intra2net.com/en/developer/libftdi/download/%{name}-%{version}.tar.bz2
Buildroot: /tmp/%{name}-%{version}-root
Requires: libusb1
BuildRequires: libusb1, libusb1-devel, pkgconfig, doxygen
BuildRequires: swig python-devel
Prefix: /usr
URL: https://www.intra2net.com/en/developer/libftdi
%package devel
Summary: Header files and static libraries for libftdi1
Group: Development/Libraries
Requires: libftdi1 = %{version}, libusb1-devel
%package python
Summary: Python bindings for libftdi
License: LGPL
Group: Development/Libraries
Requires: %{name} = %{version}-%{release}
%description
Library to program and control the FTDI USB controller
%description devel
Header files and static libraries for libftdi1
%description python
Python bindings for libftdi1 generated by SWIG
%prep
%setup -q
%build
mkdir build
cd build
export CFLAGS="$RPM_OPT_FLAGS"
export CXXFLAGS="$RPM_OPT_FLAGS"
cmake -DCMAKE_INSTALL_PREFIX="%{prefix}" ../
make %{?_smp_mflags}
%install
cd build
make DESTDIR=$RPM_BUILD_ROOT install
# Remove example programs
rm -f $RPM_BUILD_ROOT/usr/bin/simple
rm -f $RPM_BUILD_ROOT/usr/bin/bitbang
rm -f $RPM_BUILD_ROOT/usr/bin/bitbang2
rm -f $RPM_BUILD_ROOT/usr/bin/bitbang_ft2232
rm -f $RPM_BUILD_ROOT/usr/bin/bitbang_cbus
rm -f $RPM_BUILD_ROOT/usr/bin/find_all
rm -f $RPM_BUILD_ROOT/usr/bin/find_all_pp
rm -f $RPM_BUILD_ROOT/usr/bin/serial_test
rm -f $RPM_BUILD_ROOT/usr/bin/baud_test
# Clean python compiled files in examples dir
find $RPM_BUILD_ROOT%{prefix}/share/libftdi/examples -name "*.pyc" -or -name "*.pyo" -exec rm -f \{\} \;
# move documentation to version specific directory
# Is there an easy way in cmake to set the DOCDIR?
mkdir -p $RPM_BUILD_ROOT%{prefix}/share/doc/%{name}-%{version}
mv $RPM_BUILD_ROOT%{prefix}/share/doc/%{name}/* $RPM_BUILD_ROOT%{prefix}/share/doc/%{name}-%{version}
%clean
rm -fr $RPM_BUILD_ROOT
%files
%defattr(-,root,root)
%doc COPYING.LIB COPYING.GPL LICENSE
%{_libdir}/libftdi1*.so*
%{_libdir}/libftdipp1*.so*
%files devel
%defattr(-,root,root)
%doc build/doc/html build/doc/man
%{_bindir}/ftdi_eeprom
%{_bindir}/libftdi1-config
%{prefix}/include/libftdi1/*.h
%{prefix}/include/libftdi1/*.hpp
%{prefix}/share/libftdi/examples/*
%{_libdir}/libftdi1*.*a
%{_libdir}/libftdipp1*.*a
%{_libdir}/pkgconfig/*.pc
%{_libdir}/cmake/libftdi1/*
%files python
%defattr(-,root,root,-)
%attr(755,root,root) %{python_sitearch}/_ftdi1.so
%{python_sitearch}/ftdi1.py*

View File

@ -0,0 +1,11 @@
prefix=@prefix@
exec_prefix=@exec_prefix@
libdir=@libdir@
includedir=@includedir@
Name: libftdipp1
Description: C++ wrapper for libftdi1
Requires: libftdi1
Version: @VERSION@
Libs: -L${libdir} -lftdipp1
Cflags: -I${includedir}

View File

@ -0,0 +1,14 @@
# FTDI Devices: FT232BM/L/Q, FT245BM/L/Q, FT232RL/Q, FT245RL/Q, VNC1L with VDPS Firmware
SUBSYSTEM=="usb", ENV{DEVTYPE}=="usb_device", ATTRS{idVendor}=="0403", ATTRS{idProduct}=="6001", MODE="0664", GROUP="plugdev"
# FTDI Devices: FT2232C/D/L, FT2232HL/Q
SUBSYSTEM=="usb", ENV{DEVTYPE}=="usb_device", ATTRS{idVendor}=="0403", ATTRS{idProduct}=="6010", MODE="0664", GROUP="plugdev"
# FTDI Devices: FT4232HL/Q
SUBSYSTEM=="usb", ENV{DEVTYPE}=="usb_device", ATTRS{idVendor}=="0403", ATTRS{idProduct}=="6011", MODE="0664", GROUP="plugdev"
# FTDI Devices: FT232H
SUBSYSTEM=="usb", ENV{DEVTYPE}=="usb_device", ATTRS{idVendor}=="0403", ATTRS{idProduct}=="6014", MODE="0664", GROUP="plugdev"
# FTDI Devices: FT230X
SUBSYSTEM=="usb", ENV{DEVTYPE}=="usb_device", ATTRS{idVendor}=="0403", ATTRS{idProduct}=="6015", MODE="0664", GROUP="plugdev"

View File

@ -0,0 +1,21 @@
# Debian
if("${PACKAGE}" STREQUAL "Debian")
# Settings
set(REVISION 0)
set(CPACK_GENERATOR "DEB" PARENT_SCOPE)
set(CPACK_PACKAGE_VERSION ${CPACK_PACKAGE_VERSION}-${REVISION} PARENT_SCOPE)
# Dependencies
set(CPACK_DEBIAN_PACKAGE_DEPENDS "libusb-1.0-0" PARENT_SCOPE)
set(DEBIAN_PACKAGE_BUILDS_DEPENDS "cmake, libusb2-dev" PARENT_SCOPE)
# Bundles
message("-- Installing udev rules to /etc/udev/rules.d")
install(FILES 99-libftdi.rules
DESTINATION /etc/udev/rules.d)
endif("${PACKAGE}" STREQUAL "Debian")
# General RPM rules
set(CPACK_RPM_PACKAGE_DEPENDS "libusb1" PARENT_SCOPE)

View File

@ -0,0 +1,81 @@
option ( LIBFTDI_PYTHON_BINDINGS "Build python bindings via swig" ON )
option ( LIBFTDI_LINK_PYTHON_LIBRARY "Link against python libraries" ON )
if ( LIBFTDI_PYTHON_BINDINGS )
# workaround for cmake bug #0013449
if ( NOT DEFINED CMAKE_FIND_ROOT_PATH )
find_package ( SWIG )
else ()
find_program ( SWIG_EXECUTABLE NAMES swig2.0 swig )
if ( SWIG_EXECUTABLE )
set ( SWIG_USE_FILE ${CMAKE_ROOT}/Modules/UseSWIG.cmake )
set ( SWIG_FOUND TRUE )
endif ()
endif ()
find_package ( PythonLibs )
find_package ( PythonInterp )
endif ()
if ( SWIG_FOUND AND PYTHONLIBS_FOUND AND PYTHONINTERP_FOUND )
include ( UseSWIG )
include_directories ( BEFORE ${CMAKE_SOURCE_DIR}/src )
include_directories ( ${PYTHON_INCLUDE_DIRS} )
link_directories ( ${CMAKE_CURRENT_BINARY_DIR}/../src )
if ( DOCUMENTATION AND DOXYGEN_FOUND )
set(CMAKE_SWIG_FLAGS -DDOXYGEN=${DOXYGEN_FOUND})
endif()
swig_add_module ( ftdi1 python ftdi1.i )
swig_link_libraries ( ftdi1 ftdi1 )
if ( LIBFTDI_LINK_PYTHON_LIBRARY )
swig_link_libraries ( ftdi1 ${PYTHON_LIBRARIES} )
elseif( APPLE )
set_target_properties ( ${SWIG_MODULE_ftdi1_REAL_NAME} PROPERTIES LINK_FLAGS "-undefined dynamic_lookup" )
endif ()
set_target_properties ( ${SWIG_MODULE_ftdi1_REAL_NAME} PROPERTIES NO_SONAME ON )
execute_process ( COMMAND ${PYTHON_EXECUTABLE} -c "from distutils import sysconfig; print( sysconfig.get_python_lib( plat_specific=True, prefix='${CMAKE_INSTALL_PREFIX}' ) )"
OUTPUT_VARIABLE _ABS_PYTHON_MODULE_PATH
OUTPUT_STRIP_TRAILING_WHITESPACE )
get_filename_component ( _ABS_PYTHON_MODULE_PATH ${_ABS_PYTHON_MODULE_PATH} ABSOLUTE )
file ( RELATIVE_PATH _REL_PYTHON_MODULE_PATH ${CMAKE_INSTALL_PREFIX} ${_ABS_PYTHON_MODULE_PATH} )
set ( PYTHON_MODULE_PATH
${_REL_PYTHON_MODULE_PATH}
)
install ( FILES ${CMAKE_CURRENT_BINARY_DIR}/ftdi1.py DESTINATION ${PYTHON_MODULE_PATH} )
install ( TARGETS ${SWIG_MODULE_ftdi1_REAL_NAME} LIBRARY DESTINATION ${PYTHON_MODULE_PATH} )
if ( DOCUMENTATION AND DOXYGEN_FOUND )
# Run doxygen to only generate the xml
add_custom_command ( OUTPUT ${CMAKE_BINARY_DIR}/doc/xml/ftdi_8c.xml
COMMAND ${CMAKE_COMMAND} -E make_directory ${CMAKE_BINARY_DIR}/doc
COMMAND ${DOXYGEN_EXECUTABLE} ${CMAKE_BINARY_DIR}/Doxyfile.xml
WORKING_DIRECTORY ${CMAKE_BINARY_DIR}
DEPENDS ${c_headers};${c_sources};${cpp_sources};${cpp_headers}
)
# generate .i from doxygen .xml
add_custom_command ( OUTPUT ${CMAKE_CURRENT_BINARY_DIR}/ftdi1_doc.i
COMMAND ${PYTHON_EXECUTABLE} ${CMAKE_CURRENT_SOURCE_DIR}/doxy2swig.py -n
${CMAKE_BINARY_DIR}/doc/xml/ftdi_8c.xml
${CMAKE_CURRENT_BINARY_DIR}/ftdi1_doc.i
DEPENDS ${CMAKE_BINARY_DIR}/doc/xml/ftdi_8c.xml
)
add_custom_target ( doc_i DEPENDS ${CMAKE_CURRENT_BINARY_DIR}/ftdi1_doc.i )
add_dependencies( ${SWIG_MODULE_ftdi1_REAL_NAME} doc_i )
endif ()
set ( LIBFTDI_PYTHON_MODULE_PATH ${CMAKE_INSTALL_PREFIX}/${PYTHON_MODULE_PATH} )
set ( LIBFTDI_PYTHON_MODULE_PATH ${LIBFTDI_PYTHON_MODULE_PATH} PARENT_SCOPE ) # for ftdiconfig.cmake
message(STATUS "Building python bindings via swig. Will be installed under ${LIBFTDI_PYTHON_MODULE_PATH}")
add_subdirectory ( examples )
else ()
message(STATUS "Not building python bindings")
endif ()

View File

@ -0,0 +1,457 @@
#!/usr/bin/env python
"""Doxygen XML to SWIG docstring converter.
Usage:
doxy2swig.py [options] input.xml output.i
Converts Doxygen generated XML files into a file containing docstrings
that can be used by SWIG-1.3.x. Note that you need to get SWIG
version > 1.3.23 or use Robin Dunn's docstring patch to be able to use
the resulting output.
input.xml is your doxygen generated XML file and output.i is where the
output will be written (the file will be clobbered).
"""
#
#
# This code is implemented using Mark Pilgrim's code as a guideline:
# http://www.faqs.org/docs/diveintopython/kgp_divein.html
#
# Author: Prabhu Ramachandran
# License: BSD style
#
# Thanks:
# Johan Hake: the include_function_definition feature
# Bill Spotz: bug reports and testing.
# Sebastian Henschel: Misc. enhancements.
#
#
from xml.dom import minidom
import re
import textwrap
import sys
import os.path
import optparse
def my_open_read(source):
if hasattr(source, "read"):
return source
else:
return open(source)
def my_open_write(dest):
if hasattr(dest, "write"):
return dest
else:
return open(dest, 'w')
class Doxy2SWIG:
"""Converts Doxygen generated XML files into a file containing
docstrings that can be used by SWIG-1.3.x that have support for
feature("docstring"). Once the data is parsed it is stored in
self.pieces.
"""
def __init__(self, src, include_function_definition=True, quiet=False):
"""Initialize the instance given a source object. `src` can
be a file or filename. If you do not want to include function
definitions from doxygen then set
`include_function_definition` to `False`. This is handy since
this allows you to use the swig generated function definition
using %feature("autodoc", [0,1]).
"""
f = my_open_read(src)
self.my_dir = os.path.dirname(f.name)
self.xmldoc = minidom.parse(f).documentElement
f.close()
self.pieces = []
self.pieces.append('\n// File: %s\n' %
os.path.basename(f.name))
self.space_re = re.compile(r'\s+')
self.lead_spc = re.compile(r'^(%feature\S+\s+\S+\s*?)"\s+(\S)')
self.multi = 0
self.ignores = ['inheritancegraph', 'param', 'listofallmembers',
'innerclass', 'name', 'declname', 'incdepgraph',
'invincdepgraph', 'programlisting', 'type',
'references', 'referencedby', 'location',
'collaborationgraph', 'reimplements',
'reimplementedby', 'derivedcompoundref',
'basecompoundref']
#self.generics = []
self.include_function_definition = include_function_definition
if not include_function_definition:
self.ignores.append('argsstring')
self.quiet = quiet
def generate(self):
"""Parses the file set in the initialization. The resulting
data is stored in `self.pieces`.
"""
self.parse(self.xmldoc)
def parse(self, node):
"""Parse a given node. This function in turn calls the
`parse_<nodeType>` functions which handle the respective
nodes.
"""
pm = getattr(self, "parse_%s" % node.__class__.__name__)
pm(node)
def parse_Document(self, node):
self.parse(node.documentElement)
def parse_Text(self, node):
txt = node.data
txt = txt.replace('\\', r'\\\\')
txt = txt.replace('"', r'\"')
# ignore pure whitespace
m = self.space_re.match(txt)
if m and len(m.group()) == len(txt):
pass
else:
self.add_text(textwrap.fill(txt, break_long_words=False))
def parse_Element(self, node):
"""Parse an `ELEMENT_NODE`. This calls specific
`do_<tagName>` handers for different elements. If no handler
is available the `generic_parse` method is called. All
tagNames specified in `self.ignores` are simply ignored.
"""
name = node.tagName
ignores = self.ignores
if name in ignores:
return
attr = "do_%s" % name
if hasattr(self, attr):
handlerMethod = getattr(self, attr)
handlerMethod(node)
else:
self.generic_parse(node)
#if name not in self.generics: self.generics.append(name)
def parse_Comment(self, node):
"""Parse a `COMMENT_NODE`. This does nothing for now."""
return
def add_text(self, value):
"""Adds text corresponding to `value` into `self.pieces`."""
if isinstance(value, (list, tuple)):
self.pieces.extend(value)
else:
self.pieces.append(value)
def get_specific_nodes(self, node, names):
"""Given a node and a sequence of strings in `names`, return a
dictionary containing the names as keys and child
`ELEMENT_NODEs`, that have a `tagName` equal to the name.
"""
nodes = [(x.tagName, x) for x in node.childNodes
if x.nodeType == x.ELEMENT_NODE and
x.tagName in names]
return dict(nodes)
def generic_parse(self, node, pad=0):
"""A Generic parser for arbitrary tags in a node.
Parameters:
- node: A node in the DOM.
- pad: `int` (default: 0)
If 0 the node data is not padded with newlines. If 1 it
appends a newline after parsing the childNodes. If 2 it
pads before and after the nodes are processed. Defaults to
0.
"""
npiece = 0
if pad:
npiece = len(self.pieces)
if pad == 2:
self.add_text('\n')
for n in node.childNodes:
self.parse(n)
if pad:
if len(self.pieces) > npiece:
self.add_text('\n')
def space_parse(self, node):
self.add_text(' ')
self.generic_parse(node)
do_ref = space_parse
do_emphasis = space_parse
do_bold = space_parse
do_computeroutput = space_parse
do_formula = space_parse
def do_compoundname(self, node):
self.add_text('\n\n')
data = node.firstChild.data
self.add_text('%%feature("docstring") %s "\n' % data)
def do_compounddef(self, node):
kind = node.attributes['kind'].value
if kind in ('class', 'struct'):
prot = node.attributes['prot'].value
if prot != 'public':
return
names = ('compoundname', 'briefdescription',
'detaileddescription', 'includes')
first = self.get_specific_nodes(node, names)
for n in names:
if first.has_key(n):
self.parse(first[n])
self.add_text(['";', '\n'])
for n in node.childNodes:
if n not in first.values():
self.parse(n)
elif kind in ('file', 'namespace'):
nodes = node.getElementsByTagName('sectiondef')
for n in nodes:
self.parse(n)
def do_includes(self, node):
self.add_text('C++ includes: ')
self.generic_parse(node, pad=1)
def do_parameterlist(self, node):
text = 'unknown'
for key, val in node.attributes.items():
if key == 'kind':
if val == 'param':
text = 'Parameters'
elif val == 'exception':
text = 'Exceptions'
elif val == 'retval':
text = 'Returns'
else:
text = val
break
self.add_text(['\n', '\n', text, ':', '\n'])
self.generic_parse(node, pad=1)
def do_para(self, node):
self.add_text('\n')
self.generic_parse(node, pad=1)
def do_parametername(self, node):
self.add_text('\n')
try:
data = node.firstChild.data
except AttributeError: # perhaps a <ref> tag in it
data = node.firstChild.firstChild.data
if data.find('Exception') != -1:
self.add_text(data)
else:
self.add_text("%s: " % data)
def do_parameterdefinition(self, node):
self.generic_parse(node, pad=1)
def do_detaileddescription(self, node):
self.generic_parse(node, pad=1)
def do_briefdescription(self, node):
self.generic_parse(node, pad=1)
def do_memberdef(self, node):
prot = node.attributes['prot'].value
id = node.attributes['id'].value
kind = node.attributes['kind'].value
tmp = node.parentNode.parentNode.parentNode
compdef = tmp.getElementsByTagName('compounddef')[0]
cdef_kind = compdef.attributes['kind'].value
if prot == 'public':
first = self.get_specific_nodes(node, ('definition', 'name'))
name = first['name'].firstChild.data
if name[:8] == 'operator': # Don't handle operators yet.
return
if not 'definition' in first or \
kind in ['variable', 'typedef']:
return
if self.include_function_definition:
defn = first['definition'].firstChild.data
else:
defn = ""
self.add_text('\n')
self.add_text('%feature("docstring") ')
anc = node.parentNode.parentNode
if cdef_kind in ('file', 'namespace'):
ns_node = anc.getElementsByTagName('innernamespace')
if not ns_node and cdef_kind == 'namespace':
ns_node = anc.getElementsByTagName('compoundname')
if ns_node:
ns = ns_node[0].firstChild.data
self.add_text(' %s::%s "\n%s' % (ns, name, defn))
else:
self.add_text(' %s "\n%s' % (name, defn))
elif cdef_kind in ('class', 'struct'):
# Get the full function name.
anc_node = anc.getElementsByTagName('compoundname')
cname = anc_node[0].firstChild.data
self.add_text(' %s::%s "\n%s' % (cname, name, defn))
for n in node.childNodes:
if n not in first.values():
self.parse(n)
self.add_text(['";', '\n'])
def do_definition(self, node):
data = node.firstChild.data
self.add_text('%s "\n%s' % (data, data))
def do_sectiondef(self, node):
kind = node.attributes['kind'].value
if kind in ('public-func', 'func', 'user-defined', ''):
self.generic_parse(node)
def do_header(self, node):
"""For a user defined section def a header field is present
which should not be printed as such, so we comment it in the
output."""
data = node.firstChild.data
self.add_text('\n/*\n %s \n*/\n' % data)
# If our immediate sibling is a 'description' node then we
# should comment that out also and remove it from the parent
# node's children.
parent = node.parentNode
idx = parent.childNodes.index(node)
if len(parent.childNodes) >= idx + 2:
nd = parent.childNodes[idx + 2]
if nd.nodeName == 'description':
nd = parent.removeChild(nd)
self.add_text('\n/*')
self.generic_parse(nd)
self.add_text('\n*/\n')
def do_simplesect(self, node):
kind = node.attributes['kind'].value
if kind in ('date', 'rcs', 'version'):
pass
elif kind == 'warning':
self.add_text(['\n', 'WARNING: '])
self.generic_parse(node)
elif kind == 'see':
self.add_text('\n')
self.add_text('See: ')
self.generic_parse(node)
else:
self.generic_parse(node)
def do_argsstring(self, node):
self.generic_parse(node, pad=1)
def do_member(self, node):
kind = node.attributes['kind'].value
refid = node.attributes['refid'].value
if kind == 'function' and refid[:9] == 'namespace':
self.generic_parse(node)
def do_doxygenindex(self, node):
self.multi = 1
comps = node.getElementsByTagName('compound')
for c in comps:
refid = c.attributes['refid'].value
fname = refid + '.xml'
if not os.path.exists(fname):
fname = os.path.join(self.my_dir, fname)
if not self.quiet:
print("parsing file: %s" % fname)
p = Doxy2SWIG(fname, self.include_function_definition, self.quiet)
p.generate()
self.pieces.extend(self.clean_pieces(p.pieces))
def write(self, fname):
o = my_open_write(fname)
if self.multi:
o.write("".join(self.pieces))
else:
o.write("".join(self.clean_pieces(self.pieces)))
o.close()
def clean_pieces(self, pieces):
"""Cleans the list of strings given as `pieces`. It replaces
multiple newlines by a maximum of 2 and returns a new list.
It also wraps the paragraphs nicely.
"""
ret = []
count = 0
for i in pieces:
if i == '\n':
count = count + 1
else:
if i == '";':
if count:
ret.append('\n')
elif count > 2:
ret.append('\n\n')
elif count:
ret.append('\n' * count)
count = 0
ret.append(i)
_data = "".join(ret)
ret = []
for i in _data.split('\n\n'):
if i == 'Parameters:' or i == 'Exceptions:' or i == 'Returns:':
ret.extend([i, '\n' + '-' * len(i), '\n\n'])
elif i.find('// File:') > -1: # leave comments alone.
ret.extend([i, '\n'])
else:
_tmp = textwrap.fill(i.strip(), break_long_words=False)
_tmp = self.lead_spc.sub(r'\1"\2', _tmp)
ret.extend([_tmp, '\n\n'])
return ret
def convert(input, output, include_function_definition=True, quiet=False):
p = Doxy2SWIG(input, include_function_definition, quiet)
p.generate()
p.write(output)
def main():
usage = __doc__
parser = optparse.OptionParser(usage)
parser.add_option("-n", '--no-function-definition',
action='store_true',
default=False,
dest='func_def',
help='do not include doxygen function definitions')
parser.add_option("-q", '--quiet',
action='store_true',
default=False,
dest='quiet',
help='be quiet and minimize output')
options, args = parser.parse_args()
if len(args) != 2:
parser.error("error: no input and output specified")
convert(args[0], args[1], not options.func_def, options.quiet)
if __name__ == '__main__':
main()

View File

@ -0,0 +1,5 @@
install ( FILES simple.py complete.py cbus.py
DESTINATION share/libftdi/examples
PERMISSIONS OWNER_READ GROUP_READ WORLD_READ
)

View File

@ -0,0 +1,173 @@
#!/usr/bin/python2
"""
Copyright 2015, Sinclair R.F., Inc.
This program is distributed under the GPL, version 2.
Demonstrate how to configure the FT230X USB UART bridge as follows:
max_power 500 mA
CBUS3 Drive 1 (accomodate PCB error)
"""
import sys
# Need to install libftdi for the following to work (see README.txt)
import ftdi1 as ftdi
# Define class for displaying errors.
class ErrorMsg(Exception):
def __init__(self,message):
self.message = message
def __str__(self):
return self.message
# Function to convert CBUSX values to human-readable strings
def cbush_string(value):
if value == ftdi.CBUSX_AWAKE:
return 'AWAKE'
if value == ftdi.CBUSX_BAT_DETECT:
return 'BAT_DETECT'
if value == ftdi.CBUSX_BAT_DETECT_NEG:
return 'BAT_DETECT_NEG'
if value == ftdi.CBUSX_BB_RD:
return 'BB_RD'
if value == ftdi.CBUSX_BB_WR:
return 'BB_WR'
if value == ftdi.CBUSX_CLK24:
return 'CLK24'
if value == ftdi.CBUSX_CLK12:
return 'CLK12'
if value == ftdi.CBUSX_CLK6:
return 'CLK6'
if value == ftdi.CBUSX_DRIVE_0:
return 'DRIVE_0'
if value == ftdi.CBUSX_DRIVE1:
return 'DRIVE_1'
if value == ftdi.CBUSX_I2C_RXF:
return 'I2C_RXF'
if value == ftdi.CBUSX_I2C_TXE:
return 'I2C_TXE'
if value == ftdi.CBUSX_IOMODE:
return 'IOMODE'
if value == ftdi.CBUSX_PWREN:
return 'PWREN'
if value == ftdi.CBUSX_RXLED:
return 'RXLED'
if value == ftdi.CBUSX_SLEEP:
return 'SLEEP'
if value == ftdi.CBUSX_TIME_STAMP:
return 'TIME_STAMP'
if value == ftdi.CBUSX_TRISTATE:
return 'TRISTATE'
if value == ftdi.CBUSX_TXDEN:
return 'TXDEN'
if value == ftdi.CBUSX_TXLED:
return 'TXLED'
if value == ftdi.CBUSX_TXRXLED:
return 'TXRXLED'
if value == ftdi.CBUSX_VBUS_SENSE:
return 'VBUS_SENSE'
return 'UNKNOWN'
# Surround the program with a try ... except clause.
try:
# Allocate and inialize an ftdi context.
ftdic = ftdi.new()
if ftdic == 0:
raise ErrorMsg('ftdi.new() failed')
# List all the FT230X devices.
nDevices, devlist = ftdi.usb_find_all(ftdic, 0x0403, 0x6015)
if nDevices < 0:
raise ErrorMsg('ftdi.usb_find_all error = %s' % ftdi.get_error_string(ftdic))
elif nDevices == 0:
raise ErrorMsg('No FT230X devices found')
elif nDevices != 1:
raise ErrorMsg('More than one FT230X device found')
# Display the identified single FT230X device.
ret, manufacturer, description, serial = ftdi.usb_get_strings(ftdic, devlist.dev)
if ret < 0:
raise ErrorMsg('ftdi.usb_get_strings error = %s' % ftdi.get_error_string(ftdic))
print 'manufacturer="%s" description="%s" serial="%s"' % (manufacturer, description, serial)
# Open the identified single FT230X device.
ret = ftdi.usb_open_desc(ftdic, 0x0403, 0x6015, description, serial)
if ret < 0:
raise ErrorMsg('ftdi.usb_open_desc error = %s' % ftdi.get_error_string(ftdic))
# Read the chip id.
ret, chipid = ftdi.read_chipid(ftdic)
if ret < 0:
raise ErrorMsg('ftdi.read_chipid error = %s' % ftdi.get_error_string(ftdic))
print 'chip id=0x%08X' % (chipid % 2**32)
# Read the EEPROM
ret = ftdi.read_eeprom(ftdic)
if ret < 0:
raise ErrorMsg('ftdi.read_eeprom error = %s' % ftdi.get_error_string(ftdic))
# Get a read-only copy of the EEPROM
if True:
eeprom_size = ftdic.eeprom.size
ret, eeprom_buf = ftdi.get_eeprom_buf(ftdic, eeprom_size)
if ret < 0:
raise ErrorMsg('ftdi.get_eeprom_buf error = %s' % ftdi.get_error_string(ftdic))
for i in range(0,eeprom_size,16):
sys.stdout.write('%04x: ' % i)
for j in range(16):
sys.stdout.write('%02x ' % ord(eeprom_buf[i+j]))
if j in (7,15,):
sys.stdout.write(' ')
for j in range(16):
x = eeprom_buf[i+j]
if 32 <= ord(x) <= 0x7E:
sys.stdout.write(x)
else:
sys.stdout.write('.')
sys.stdout.write('\n')
# Read and display the EEPROM (in human readable format)
ret = ftdi.eeprom_decode(ftdic, 1)
if ret < 0:
raise ErrorMsg('ftdi.eeprom_decode error = %s' % ftdi.get_error_string(ftdic))
# Set the maximum power to 500mA.
print 'initial max_power = %dmA' % ftdic.eeprom.max_power
ftdic.eeprom.max_power = 500
print 'new max_power = %dmA' % ftdic.eeprom.max_power
# Set CBUS3 to DRIVE_1 (the board needs to be reworked to use PWREN# and BCD#)
ret, value = ftdi.get_eeprom_value(ftdic,ftdi.CBUS_FUNCTION_3)
if ret < 0:
raise ErrorMsg('ftdi.get_eeprom_value error = %s' % ftdi.get_error_string(ftdic))
print 'initial CBUS3 = %d (%s)' % (value,cbush_string(value),)
ret = ftdi.set_eeprom_value(ftdic,ftdi.CBUS_FUNCTION_3,ftdi.CBUSX_DRIVE1)
if ret < 0:
raise ErrorMsg('ftdi.set_eeprom_value error = %s' % ftdi.get_error_string(ftdic))
ret, value = ftdi.get_eeprom_value(ftdic,ftdi.CBUS_FUNCTION_3)
if ret < 0:
raise ErrorMsg('ftdi.get_eeprom_value error = %s' % ftdi.get_error_string(ftdic))
print 'new CBUS3 = %d (%s)' % (value,cbush_string(value),)
# Write the new EEPROM settings.
if False:
ret = ftdi.eeprom_build(ftdic)
if ret < 0:
raise ErrorMsg('ftdi.eeprom_build error = %s' % ftdi.get_error_string(ftdic))
ret = ftdi.write_eeprom(ftdic)
if ret < 0:
raise ErrorMsg('ftdi.write_eeprom error = %s' % ftdi.get_error_string(ftdic))
print 'EEPROM write succeeded'
else:
print 'EEPROM write not attempted'
# Close the ftdi context.
ret = ftdi.usb_close(ftdic)
if ret < 0:
raise ErrorMsg('ftdi.usb_close error = %s' % ftdi.get_error_string(ftdic))
except ErrorMsg, msg:
print >> sys.stderr, 'FATAL ERROR: ' + str(msg)
exit(1)

View File

@ -0,0 +1,121 @@
#!/usr/bin/env python
# -*- coding: utf-8 -*-
"""Python example program.
Complete program to demonstrate the usage
of the swig generated python wrapper
You need to build and install the wrapper first"""
import os
import sys
import ftdi1 as ftdi
import time
# version
print ('version: %s\n' % ftdi.__version__)
# initialize
ftdic = ftdi.new()
if ftdic == 0:
print('new failed: %d' % ret)
os._exit(1)
# try to list ftdi devices 0x6010 or 0x6001
ret, devlist = ftdi.usb_find_all(ftdic, 0x0403, 0x6010)
if ret <= 0:
ret, devlist = ftdi.usb_find_all(ftdic, 0x0403, 0x6001)
if ret < 0:
print('ftdi_usb_find_all failed: %d (%s)' %
(ret, ftdi.get_error_string(ftdic)))
os._exit(1)
print('devices: %d' % ret)
curnode = devlist
i = 0
while(curnode != None):
ret, manufacturer, description, serial = ftdi.usb_get_strings(
ftdic, curnode.dev)
if ret < 0:
print('ftdi_usb_get_strings failed: %d (%s)' %
(ret, ftdi.get_error_string(ftdic)))
os._exit(1)
print('#%d: manufacturer="%s" description="%s" serial="%s"\n' %
(i, manufacturer, description, serial))
curnode = curnode.next
i += 1
# open usb
ret = ftdi.usb_open(ftdic, 0x0403, 0x6001)
if ret < 0:
print('unable to open ftdi device: %d (%s)' %
(ret, ftdi.get_error_string(ftdic)))
os._exit(1)
# bitbang
ret = ftdi.set_bitmode(ftdic, 0xff, ftdi.BITMODE_BITBANG)
if ret < 0:
print('Cannot enable bitbang')
os._exit(1)
print('turning everything on')
ftdi.write_data(ftdic, chr(0xff), 1)
time.sleep(1)
print('turning everything off\n')
ftdi.write_data(ftdic, chr(0x00), 1)
time.sleep(1)
for i in range(8):
val = 2 ** i
print('enabling bit #%d (0x%02x)' % (i, val))
ftdi.write_data(ftdic, chr(val), 1)
time.sleep(1)
ftdi.disable_bitbang(ftdic)
print('')
# read pins
ret, pins = ftdi.read_pins(ftdic)
if (ret == 0):
if sys.version_info[0] < 3: # python 2
pins = ord(pins)
else:
pins = pins[0]
print('pins: 0x%x' % pins)
# read chip id
ret, chipid = ftdi.read_chipid(ftdic)
if (ret == 0):
print('chip id: %x\n' % chipid)
# read eeprom
eeprom_addr = 1
ret, eeprom_val = ftdi.read_eeprom_location(ftdic, eeprom_addr)
if (ret == 0):
print('eeprom @ %d: 0x%04x\n' % (eeprom_addr, eeprom_val))
print('eeprom:')
ret = ftdi.read_eeprom(ftdic)
size = 128
ret, eeprom = ftdi.get_eeprom_buf(ftdic, size)
if (ret == 0):
for i in range(size):
octet = eeprom[i]
if sys.version_info[0] < 3: # python 2
octet = ord(octet)
sys.stdout.write('%02x ' % octet)
if (i % 8 == 7):
print('')
print('')
# close usb
ret = ftdi.usb_close(ftdic)
if ret < 0:
print('unable to close ftdi device: %d (%s)' %
(ret, ftdi.get_error_string(ftdic)))
os._exit(1)
print ('device closed')
ftdi.free(ftdic)

Some files were not shown because too many files have changed in this diff Show More