Driver: Add FTD3XX
parent
b3bbf91e8c
commit
6b0c588a46
|
|
@ -1,6 +1,8 @@
|
||||||
cmake_minimum_required(VERSION 3.2)
|
cmake_minimum_required(VERSION 3.2)
|
||||||
project(libicsneo VERSION 0.3.0)
|
project(libicsneo VERSION 0.3.0)
|
||||||
|
|
||||||
|
cmake_policy(SET CMP0074 OLD)
|
||||||
|
|
||||||
option(LIBICSNEO_BUILD_TESTS "Build all tests." OFF)
|
option(LIBICSNEO_BUILD_TESTS "Build all tests." OFF)
|
||||||
option(LIBICSNEO_BUILD_DOCS "Build documentation. Don't use in Visual Studio." OFF)
|
option(LIBICSNEO_BUILD_DOCS "Build documentation. Don't use in Visual Studio." OFF)
|
||||||
option(LIBICSNEO_BUILD_EXAMPLES "Build examples." ON)
|
option(LIBICSNEO_BUILD_EXAMPLES "Build examples." ON)
|
||||||
|
|
@ -158,6 +160,14 @@ else() # Darwin or Linux
|
||||||
endif()
|
endif()
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
|
find_package(FTD3XX)
|
||||||
|
if(FTD3XX_FOUND)
|
||||||
|
set(LIBICSNEO_ENABLE_FTD3XX 1)
|
||||||
|
list(APPEND PLATFORM_SRC
|
||||||
|
platform/ftd3xx.cpp
|
||||||
|
)
|
||||||
|
endif()
|
||||||
|
|
||||||
if(LIBICSNEO_ENABLE_TCP)
|
if(LIBICSNEO_ENABLE_TCP)
|
||||||
list(APPEND PLATFORM_SRC
|
list(APPEND PLATFORM_SRC
|
||||||
platform/tcp.cpp
|
platform/tcp.cpp
|
||||||
|
|
@ -291,6 +301,10 @@ endif()
|
||||||
if(LIBICSNEO_ENABLE_FTDI)
|
if(LIBICSNEO_ENABLE_FTDI)
|
||||||
target_compile_definitions(icsneocpp PRIVATE ICSNEO_ENABLE_FTDI)
|
target_compile_definitions(icsneocpp PRIVATE ICSNEO_ENABLE_FTDI)
|
||||||
endif()
|
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)
|
if(LIBICSNEO_ENABLE_TCP)
|
||||||
target_compile_definitions(icsneocpp PRIVATE ICSNEO_ENABLE_TCP)
|
target_compile_definitions(icsneocpp PRIVATE ICSNEO_ENABLE_TCP)
|
||||||
if(WIN32)
|
if(WIN32)
|
||||||
|
|
|
||||||
|
|
@ -111,6 +111,12 @@ icsneo_closeDevice(myDevice);
|
||||||
```
|
```
|
||||||
|
|
||||||
## Building from Source
|
## Building from Source
|
||||||
|
### FTD3XX
|
||||||
|
Some devices require FTD3XX for USB communication:
|
||||||
|
1. Download the archive for the target platform from [FTDI's website](https://ftdichip.com/drivers/d3xx-drivers/)
|
||||||
|
- Windows users should download the "Application Library (DLL)" package
|
||||||
|
2. Extract the archive
|
||||||
|
3. Configure libicsneo with the CMake option `FTD3XX_ROOT` set to the path containing `f3d3xx.h` (`-DFTD3XX_ROOT=<path to directory containing ftd3xx.h>`)
|
||||||
### Windows
|
### Windows
|
||||||
Building will require MSVC 2017 version 15.7 or newer and CMake to be installed.
|
Building will require MSVC 2017 version 15.7 or newer and CMake to be installed.
|
||||||
### macOS
|
### macOS
|
||||||
|
|
|
||||||
|
|
@ -133,6 +133,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* GETIFADDRS_ERROR = "A call to getifaddrs() failed.";
|
||||||
static constexpr const char* SEND_TO_ERROR = "A call to sendto() 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.";
|
||||||
|
|
||||||
static constexpr const char* TOO_MANY_EVENTS = "Too many events have occurred. The list has been truncated.";
|
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* UNKNOWN = "An unknown internal error occurred.";
|
||||||
static constexpr const char* INVALID = "An invalid internal error occurred.";
|
static constexpr const char* INVALID = "An invalid internal error occurred.";
|
||||||
|
|
@ -286,7 +321,75 @@ const char* APIEvent::DescriptionForType(Type type) {
|
||||||
return GETIFADDRS_ERROR;
|
return GETIFADDRS_ERROR;
|
||||||
case Type::SendToError:
|
case Type::SendToError:
|
||||||
return SEND_TO_ERROR;
|
return SEND_TO_ERROR;
|
||||||
|
|
||||||
|
// 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;
|
||||||
|
|
||||||
// Other Errors
|
// Other Errors
|
||||||
case Type::TooManyEvents:
|
case Type::TooManyEvents:
|
||||||
return TOO_MANY_EVENTS;
|
return TOO_MANY_EVENTS;
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,24 @@
|
||||||
|
find_path(FTD3XX_INCLUDE_DIR
|
||||||
|
NAMES ftd3xx.h FTD3XX.h
|
||||||
|
HINTS "${FTD3XX_ROOT}"
|
||||||
|
)
|
||||||
|
|
||||||
|
find_library(FTD3XX_LIBRARY
|
||||||
|
NAMES libftd3xx-static.a FTD3XX.lib
|
||||||
|
PATH_SUFFIXES x64/Static
|
||||||
|
HINTS "${FTD3XX_ROOT}"
|
||||||
|
)
|
||||||
|
|
||||||
|
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()
|
||||||
|
|
@ -19,6 +19,10 @@
|
||||||
#include "icsneo/platform/ftdi.h"
|
#include "icsneo/platform/ftdi.h"
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#ifdef ICSNEO_ENABLE_FTD3XX
|
||||||
|
#include "icsneo/platform/ftd3xx.h"
|
||||||
|
#endif
|
||||||
|
|
||||||
#ifdef ICSNEO_ENABLE_TCP
|
#ifdef ICSNEO_ENABLE_TCP
|
||||||
#include "icsneo/platform/tcp.h"
|
#include "icsneo/platform/tcp.h"
|
||||||
#endif
|
#endif
|
||||||
|
|
@ -67,6 +71,10 @@ std::vector<std::shared_ptr<Device>> DeviceFinder::FindAll() {
|
||||||
FTDI::Find(newDriverFoundDevices);
|
FTDI::Find(newDriverFoundDevices);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#ifdef ICSNEO_ENABLE_FTD3XX
|
||||||
|
FTD3XX::Find(newDriverFoundDevices);
|
||||||
|
#endif
|
||||||
|
|
||||||
// Weak because we don't want to keep devices open if they go out of scope elsewhere
|
// Weak because we don't want to keep devices open if they go out of scope elsewhere
|
||||||
static std::vector<std::weak_ptr<Device>> foundDevices;
|
static std::vector<std::weak_ptr<Device>> foundDevices;
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -110,7 +110,42 @@ public:
|
||||||
ErrorSettingSocketOption = 0x3107,
|
ErrorSettingSocketOption = 0x3107,
|
||||||
GetIfAddrsError = 0x3108,
|
GetIfAddrsError = 0x3108,
|
||||||
SendToError = 0x3109,
|
SendToError = 0x3109,
|
||||||
|
|
||||||
|
// 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,
|
||||||
|
|
||||||
NoErrorFound = 0xFFFFFFFD,
|
NoErrorFound = 0xFFFFFFFD,
|
||||||
TooManyEvents = 0xFFFFFFFE,
|
TooManyEvents = 0xFFFFFFFE,
|
||||||
Unknown = 0xFFFFFFFF
|
Unknown = 0xFFFFFFFF
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,33 @@
|
||||||
|
#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;
|
||||||
|
void readTask() override;
|
||||||
|
void writeTask() override;
|
||||||
|
};
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif // __cplusplus
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
@ -1,19 +0,0 @@
|
||||||
#ifndef __FTDI3_H_
|
|
||||||
#define __FTDI3_H_
|
|
||||||
|
|
||||||
#define INTREPID_USB_VENDOR_ID (0x093c)
|
|
||||||
|
|
||||||
// This is currently a stub for the FTDI3 driver,
|
|
||||||
// it uses the FTDI driver to find devices but will
|
|
||||||
// not allow them to connect!
|
|
||||||
#define FTDI3 FTDI
|
|
||||||
|
|
||||||
#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
|
|
||||||
|
|
@ -0,0 +1,174 @@
|
||||||
|
#include <vector>
|
||||||
|
#include "icsneo/api/eventmanager.h"
|
||||||
|
|
||||||
|
#define FTD3XX_STATIC
|
||||||
|
#include <ftd3xx.h>
|
||||||
|
|
||||||
|
#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);
|
||||||
|
|
||||||
|
closing = 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;
|
||||||
|
}
|
||||||
|
|
||||||
|
closing = true;
|
||||||
|
disconnected = false;
|
||||||
|
|
||||||
|
if(readThread.joinable())
|
||||||
|
readThread.join();
|
||||||
|
if(writeThread.joinable())
|
||||||
|
writeThread.join();
|
||||||
|
|
||||||
|
uint8_t flush;
|
||||||
|
WriteOperation flushop;
|
||||||
|
while(readQueue.try_dequeue(flush)) {}
|
||||||
|
while(writeQueue.try_dequeue(flushop)) {}
|
||||||
|
|
||||||
|
if(const auto ret = FT_Close(*handle); ret != FT_OK) {
|
||||||
|
addEvent(ret, APIEvent::Severity::EventWarning);
|
||||||
|
}
|
||||||
|
|
||||||
|
closing = false;
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
void FTD3XX::readTask() {
|
||||||
|
EventManager::GetInstance().downgradeErrorsOnCurrentThread();
|
||||||
|
|
||||||
|
static constexpr auto bufferSize = 2048;
|
||||||
|
uint8_t buffer[bufferSize] = {};
|
||||||
|
|
||||||
|
FT_SetStreamPipe(*handle, false, false, READ_PIPE_ID, bufferSize);
|
||||||
|
FT_SetPipeTimeout(*handle, READ_PIPE_ID, 1);
|
||||||
|
while(!closing && !isDisconnected()) {
|
||||||
|
ULONG received = 0;
|
||||||
|
OVERLAPPED overlap = {};
|
||||||
|
FT_InitializeOverlapped(*handle, &overlap);
|
||||||
|
#ifdef _WIN32
|
||||||
|
FT_ReadPipe(*handle, READ_PIPE_ID, buffer, bufferSize, &received, &overlap);
|
||||||
|
#else
|
||||||
|
FT_ReadPipeAsync(*handle, 0, buffer, bufferSize, &received, &overlap);
|
||||||
|
#endif
|
||||||
|
while(!closing) {
|
||||||
|
const auto ret = FT_GetOverlappedResult(*handle, &overlap, &received, true);
|
||||||
|
if(ret == FT_IO_PENDING)
|
||||||
|
continue;
|
||||||
|
if(ret != FT_OK) {
|
||||||
|
if(ret == FT_IO_ERROR) {
|
||||||
|
disconnected = true;
|
||||||
|
report(APIEvent::Type::DeviceDisconnected, APIEvent::Severity::Error);
|
||||||
|
} else {
|
||||||
|
addEvent(ret, APIEvent::Severity::Error);
|
||||||
|
}
|
||||||
|
FT_AbortPipe(*handle, READ_PIPE_ID);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
FT_ReleaseOverlapped(*handle, &overlap);
|
||||||
|
if(received > 0) {
|
||||||
|
readQueue.enqueue_bulk(buffer, received);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void FTD3XX::writeTask() {
|
||||||
|
EventManager::GetInstance().downgradeErrorsOnCurrentThread();
|
||||||
|
|
||||||
|
FT_SetPipeTimeout(*handle, WRITE_PIPE_ID, 100);
|
||||||
|
WriteOperation writeOp;
|
||||||
|
while(!closing && !isDisconnected()) {
|
||||||
|
if(!writeQueue.wait_dequeue_timed(writeOp, std::chrono::milliseconds(100)))
|
||||||
|
continue;
|
||||||
|
|
||||||
|
const auto size = static_cast<ULONG>(writeOp.bytes.size());
|
||||||
|
ULONG sent = 0;
|
||||||
|
OVERLAPPED overlap = {};
|
||||||
|
FT_InitializeOverlapped(*handle, &overlap);
|
||||||
|
FT_SetStreamPipe(*handle, false, false, WRITE_PIPE_ID, size);
|
||||||
|
#ifdef _WIN32
|
||||||
|
FT_WritePipe(*handle, WRITE_PIPE_ID, writeOp.bytes.data(), size, &sent, &overlap);
|
||||||
|
#else
|
||||||
|
FT_WritePipeAsync(*handle, 0, writeOp.bytes.data(), size, &sent, &overlap);
|
||||||
|
#endif
|
||||||
|
while(!closing) {
|
||||||
|
const auto ret = FT_GetOverlappedResult(*handle, &overlap, &sent, true);
|
||||||
|
if(ret == FT_IO_PENDING)
|
||||||
|
continue;
|
||||||
|
if(ret != FT_OK) {
|
||||||
|
if(ret == FT_IO_ERROR) {
|
||||||
|
disconnected = true;
|
||||||
|
report(APIEvent::Type::DeviceDisconnected, APIEvent::Severity::Error);
|
||||||
|
} else {
|
||||||
|
addEvent(ret, APIEvent::Severity::Error);
|
||||||
|
}
|
||||||
|
FT_AbortPipe(*handle, WRITE_PIPE_ID);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
FT_ReleaseOverlapped(*handle, &overlap);
|
||||||
|
}
|
||||||
|
}
|
||||||
Loading…
Reference in New Issue