Author SHA1 Message Date
Ben Kleinheksel 6bc70b5f29 Clean up example
Add second signal set to the example
2025-06-16 15:39:32 -04:00
Ben Kleinheksel bb4176dec8 Change signal name to DAQ Enable 2025-06-16 13:54:51 -04:00
Ben Kleinheksel 0b135e29a0 Add test to example 2025-06-16 11:04:40 -04:00
Ben Kleinheksel 5bfd7e3300 Add set value to live data
Print new commands and signals
2025-06-16 11:04:38 -04:00
404 changed files with 129443 additions and 1609 deletions
-1
View File
@@ -15,4 +15,3 @@ third-party/concurrentqueue/tests
examples/csharp/bin examples/csharp/bin
examples/csharp/obj examples/csharp/obj
test/system test/system
.env
+88 -64
View File
@@ -67,7 +67,7 @@ unit_test windows/x86:
script: script:
- apt update -y - apt update -y
- apt upgrade -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 - sh ci/build-posix.sh
artifacts: artifacts:
when: always when: always
@@ -82,7 +82,7 @@ unit_test windows/x86:
script: script:
- apt update -y - apt update -y
- apt upgrade -y - apt upgrade -y
- apt install -y libpcap-dev - apt install -y libusb-1.0-0-dev libpcap-dev
- build/libicsneo-unit-tests - build/libicsneo-unit-tests
tags: tags:
- linux-build - linux-build
@@ -93,7 +93,7 @@ unit_test windows/x86:
script: script:
- apt update -y - apt update -y
- apt upgrade -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 - CC=clang CXX=clang++ LDFLAGS=-fuse-ld=lld sh ci/build-posix.sh
artifacts: artifacts:
when: always when: always
@@ -108,12 +108,36 @@ unit_test windows/x86:
script: script:
- apt update -y - apt update -y
- apt upgrade -y - apt upgrade -y
- apt install -y libpcap-dev - apt install -y libusb-1.0-0-dev libpcap-dev
- build/libicsneo-unit-tests - build/libicsneo-unit-tests
tags: tags:
- linux-build - linux-build
timeout: 5m 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/2204/amd64/gcc:
<<: *build_linux_ubuntu_gcc <<: *build_linux_ubuntu_gcc
image: ubuntu:22.04 image: ubuntu:22.04
@@ -138,30 +162,6 @@ unit_test linux/ubuntu/2204/amd64/clang:
needs: needs:
- build linux/ubuntu/2204/amd64/clang - 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 # Fedora
#------------------------------------------------------------------------------- #-------------------------------------------------------------------------------
@@ -175,7 +175,7 @@ unit_test linux/ubuntu/2404/amd64/clang:
- echo max_parallel_downloads=10 >>/etc/dnf/dnf.conf - echo max_parallel_downloads=10 >>/etc/dnf/dnf.conf
- echo fastestmirror=True >>/etc/dnf/dnf.conf - echo fastestmirror=True >>/etc/dnf/dnf.conf
- dnf upgrade -y - 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 - sh ci/build-posix.sh
artifacts: artifacts:
when: always when: always
@@ -194,7 +194,7 @@ unit_test linux/ubuntu/2404/amd64/clang:
- echo max_parallel_downloads=10 >>/etc/dnf/dnf.conf - echo max_parallel_downloads=10 >>/etc/dnf/dnf.conf
- echo fastestmirror=True >>/etc/dnf/dnf.conf - echo fastestmirror=True >>/etc/dnf/dnf.conf
- dnf upgrade -y - dnf upgrade -y
- dnf install -y libpcap-devel - dnf install -y libpcap-devel libusb1-devel
- build/libicsneo-unit-tests - build/libicsneo-unit-tests
tags: tags:
- linux-build - linux-build
@@ -209,7 +209,7 @@ unit_test linux/ubuntu/2404/amd64/clang:
- echo max_parallel_downloads=10 >>/etc/dnf/dnf.conf - echo max_parallel_downloads=10 >>/etc/dnf/dnf.conf
- echo fastestmirror=True >>/etc/dnf/dnf.conf - echo fastestmirror=True >>/etc/dnf/dnf.conf
- dnf upgrade -y - 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 - CC=clang CXX=clang++ LDFLAGS=-fuse-ld=lld sh ci/build-posix.sh
artifacts: artifacts:
when: always when: always
@@ -228,12 +228,60 @@ unit_test linux/ubuntu/2404/amd64/clang:
- echo max_parallel_downloads=10 >>/etc/dnf/dnf.conf - echo max_parallel_downloads=10 >>/etc/dnf/dnf.conf
- echo fastestmirror=True >>/etc/dnf/dnf.conf - echo fastestmirror=True >>/etc/dnf/dnf.conf
- dnf upgrade -y - dnf upgrade -y
- dnf install -y libpcap-devel - dnf install -y libpcap-devel libusb1-devel
- build/libicsneo-unit-tests - build/libicsneo-unit-tests
tags: tags:
- linux-build - linux-build
timeout: 5m 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/41/amd64/gcc:
<<: *build_linux_fedora_gcc <<: *build_linux_fedora_gcc
image: fedora:41 image: fedora:41
@@ -258,30 +306,6 @@ unit_test linux/fedora/41/amd64/clang:
needs: needs:
- build linux/fedora/41/amd64/clang - 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 # Python Module
#------------------------------------------------------------------------------- #-------------------------------------------------------------------------------
@@ -290,19 +314,19 @@ build python/linux/amd64:
stage: build stage: build
tags: tags:
- linux-build - linux-build
image: python:3.13 image: python:3.12
services: services:
- name: docker:dind - name: docker:dind
entrypoint: ["env", "-u", "DOCKER_HOST"] entrypoint: ["env", "-u", "DOCKER_HOST"]
command: ["dockerd-entrypoint.sh"] command: ["dockerd-entrypoint.sh"]
variables: 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_BUILD: "*manylinux*" # no musl
CIBW_ARCHS: x86_64 CIBW_ARCHS: x86_64
DOCKER_HOST: unix:///var/run/docker.sock DOCKER_HOST: unix:///var/run/docker.sock
DOCKER_DRIVER: overlay2 DOCKER_DRIVER: overlay2
DOCKER_TLS_CERTDIR: "" DOCKER_TLS_CERTDIR: ""
CIBW_ENVIRONMENT: CMAKE_PREFIX_PATH=/project/libpcap/install CIBW_ENVIRONMENT: CMAKE_PREFIX_PATH=/project/libpcap/install:/project/libusb/install
script: script:
- curl -sSL https://get.docker.com/ | sh - curl -sSL https://get.docker.com/ | sh
- sh ci/build-wheel-posix.sh - sh ci/build-wheel-posix.sh
@@ -315,10 +339,10 @@ build python/linux/arm64:
tags: tags:
- arm64-linux-build - arm64-linux-build
variables: 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_BUILD: "*manylinux*" # no musl
CIBW_ARCHS: aarch64 CIBW_ARCHS: aarch64
CIBW_ENVIRONMENT: CMAKE_PREFIX_PATH=/project/libpcap/install CIBW_ENVIRONMENT: CMAKE_PREFIX_PATH=/project/libpcap/install:/project/libusb/install
script: script:
- sh ci/build-wheel-posix.sh - sh ci/build-wheel-posix.sh
artifacts: artifacts:
@@ -330,9 +354,9 @@ build python/macos:
tags: tags:
- macos-arm64 - macos-arm64
variables: 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_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 MACOSX_DEPLOYMENT_TARGET: 10.14
script: script:
- sh ci/build-wheel-posix.sh - sh ci/build-wheel-posix.sh
@@ -360,7 +384,7 @@ deploy python/pypi:
TWINE_PASSWORD: $PYPI_TOKEN TWINE_PASSWORD: $PYPI_TOKEN
tags: tags:
- linux-build - linux-build
image: python:3.13 image: python:3.12
rules: rules:
- if: $CI_COMMIT_BRANCH == $CI_DEFAULT_BRANCH - if: $CI_COMMIT_BRANCH == $CI_DEFAULT_BRANCH
script: script:
+91 -25
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_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_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_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_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) option(LIBICSNEO_ENABLE_BINDINGS_PYTHON "Enable Python library" OFF)
@@ -108,6 +109,7 @@ if(LIBICSNEO_BUILD_DOCS)
endif() endif()
if(WIN32) if(WIN32)
add_definitions(-DWIN32_LEAN_AND_MEAN -DNOMINMAX -D_CRT_SECURE_NO_WARNINGS)
set(PLATFORM_SRC set(PLATFORM_SRC
platform/windows/strings.cpp platform/windows/strings.cpp
platform/windows/registry.cpp platform/windows/registry.cpp
@@ -120,9 +122,9 @@ if(WIN32)
) )
endif() endif()
if(LIBICSNEO_ENABLE_CDCACM) if(LIBICSNEO_ENABLE_CDCACM OR LIBICSNEO_ENABLE_FTDI)
list(APPEND PLATFORM_SRC list(APPEND PLATFORM_SRC
platform/windows/cdcacm.cpp platform/windows/vcp.cpp
) )
endif() endif()
else() # Darwin or Linux else() # Darwin or Linux
@@ -140,6 +142,12 @@ else() # Darwin or Linux
) )
endif() endif()
if(LIBICSNEO_ENABLE_FTDI)
list(APPEND PLATFORM_SRC
platform/posix/ftdi.cpp
)
endif()
if(LIBICSNEO_ENABLE_CDCACM) if(LIBICSNEO_ENABLE_CDCACM)
list(APPEND PLATFORM_SRC list(APPEND PLATFORM_SRC
platform/posix/cdcacm.cpp platform/posix/cdcacm.cpp
@@ -163,9 +171,51 @@ else() # Darwin or Linux
endif() endif()
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 list(APPEND PLATFORM_SRC
platform/dxx.cpp platform/ftd3xx.cpp
) )
endif() endif()
@@ -242,7 +292,6 @@ set(SRC_FILES
disk/plasiondiskreaddriver.cpp disk/plasiondiskreaddriver.cpp
disk/extextractordiskreaddriver.cpp disk/extextractordiskreaddriver.cpp
disk/fat.cpp disk/fat.cpp
disk/diskdetails.cpp
disk/vsa/vsa.cpp disk/vsa/vsa.cpp
disk/vsa/vsa02.cpp disk/vsa/vsa02.cpp
disk/vsa/vsa03.cpp disk/vsa/vsa03.cpp
@@ -334,9 +383,12 @@ endif()
if(LIBICSNEO_ENABLE_CDCACM) if(LIBICSNEO_ENABLE_CDCACM)
target_compile_definitions(icsneocpp PRIVATE ICSNEO_ENABLE_CDCACM) target_compile_definitions(icsneocpp PRIVATE ICSNEO_ENABLE_CDCACM)
endif() endif()
if(LIBICSNEO_ENABLE_DXX) if(LIBICSNEO_ENABLE_FTDI)
target_compile_definitions(icsneocpp PRIVATE ICSNEO_ENABLE_DXX) target_compile_definitions(icsneocpp PRIVATE ICSNEO_ENABLE_FTDI)
target_link_libraries(icsneocpp PRIVATE libredxx::libredxx) endif()
if(LIBICSNEO_ENABLE_FTD3XX)
target_compile_definitions(icsneocpp PRIVATE ICSNEO_ENABLE_FTD3XX)
target_link_libraries(icsneocpp PRIVATE FTD3XX::FTD3XX)
endif() 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)
@@ -350,15 +402,25 @@ add_subdirectory(third-party/fatfs)
set_property(TARGET fatfs PROPERTY POSITION_INDEPENDENT_CODE ON) set_property(TARGET fatfs PROPERTY POSITION_INDEPENDENT_CODE ON)
target_link_libraries(icsneocpp PRIVATE fatfs) target_link_libraries(icsneocpp PRIVATE fatfs)
# dxx # libftdi
if(LIBICSNEO_ENABLE_DXX) if(LIBICSNEO_ENABLE_FTDI)
include(FetchContent) if(NOT WIN32)
FetchContent_Declare(libredxx target_include_directories(icsneocpp PUBLIC third-party/libftdi/src)
GIT_REPOSITORY https://github.com/Zeranoe/libredxx.git set(LIBFTDI_DOCUMENTATION OFF CACHE INTERNAL "")
GIT_TAG 2b7932fe7f2fc006ef269c7a72595f3940178a10 set(LIBFTDI_BUILD_TESTS OFF CACHE INTERNAL "")
) set(LIBFTDI_INSTALL OFF CACHE INTERNAL "")
FetchContent_MakeAvailable(libredxx) set(LIBFTDI_PYTHON_BINDINGS OFF CACHE INTERNAL "")
endif() 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 # pcap
if(LIBICSNEO_ENABLE_RAW_ETHERNET) if(LIBICSNEO_ENABLE_RAW_ETHERNET)
@@ -444,12 +506,17 @@ add_subdirectory(bindings)
# googletest # googletest
if(LIBICSNEO_BUILD_UNIT_TESTS) if(LIBICSNEO_BUILD_UNIT_TESTS)
include(FetchContent) if(WIN32)
FetchContent_Declare(googletest set(gtest_force_shared_crt ON CACHE BOOL "" FORCE)
GIT_REPOSITORY https://github.com/google/googletest.git endif()
GIT_TAG 6986c2b575f77135401a4e1c65a7a42f20e18fef
) if (NOT TARGET gtest)
FetchContent_MakeAvailable(googletest) add_subdirectory(third-party/googletest-master)
endif()
if (CMAKE_VERSION VERSION_LESS 2.8.11)
include_directories("${gtest_SOURCE_DIR}/include")
endif()
add_executable(libicsneo-unit-tests add_executable(libicsneo-unit-tests
test/unit/main.cpp test/unit/main.cpp
@@ -465,7 +532,6 @@ if(LIBICSNEO_BUILD_UNIT_TESTS)
test/unit/ringbuffertest.cpp test/unit/ringbuffertest.cpp
test/unit/apperrordecodertest.cpp test/unit/apperrordecodertest.cpp
test/unit/windowsstrings.cpp test/unit/windowsstrings.cpp
test/unit/periodictest.cpp
) )
target_link_libraries(libicsneo-unit-tests gtest gtest_main) target_link_libraries(libicsneo-unit-tests gtest gtest_main)
-30
View File
@@ -757,33 +757,3 @@ bool icsneo_isOnlineSupported(const neodevice_t* device) {
return device->device->isOnlineSupported(); return device->device->isOnlineSupported();
} }
bool icsneo_requestTC10Wake(const neodevice_t* device, neonetid_t netid) {
if(!icsneo_isValidNeoDevice(device))
return false;
return device->device->requestTC10Wake((Network::NetID)netid);
}
bool icsneo_requestTC10Sleep(const neodevice_t* device, neonetid_t netid) {
if(!icsneo_isValidNeoDevice(device))
return false;
return device->device->requestTC10Sleep((Network::NetID)netid);
}
bool icsneo_getTC10Status(const neodevice_t* device, neonetid_t netid, neotc10status_t* status) {
if(!icsneo_isValidNeoDevice(device))
return false;
const auto statusMsg = device->device->getTC10Status((Network::NetID)netid);
if(!statusMsg)
return false;
status->wakeStatus = (neotc10wakestatus_t)statusMsg->wakeStatus;
status->sleepStatus = (neotc10sleepstatus_t)statusMsg->sleepStatus;
return true;
}
+103 -36
View File
@@ -74,9 +74,6 @@ static constexpr const char* TIMEOUT = "The timeout was reached.";
static constexpr const char* WIVI_NOT_SUPPORTED = "Wireless neoVI functions are not supported on this device."; static constexpr const char* WIVI_NOT_SUPPORTED = "Wireless neoVI functions are not supported on this device.";
static constexpr const char* RESTRICTED_ENTRY_FLAG = "Attempted to set a restricted flag in a Root Directory entry."; static constexpr const char* RESTRICTED_ENTRY_FLAG = "Attempted to set a restricted flag in a Root Directory entry.";
static constexpr const char* NOT_SUPPORTED = "The requested feature is not supported."; 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 // Device Errors
static constexpr const char* POLLING_MESSAGE_OVERFLOW = "Too many messages have been recieved for the polling message buffer, some have been lost!"; static constexpr const char* POLLING_MESSAGE_OVERFLOW = "Too many messages have been recieved for the polling message buffer, some have been lost!";
@@ -125,10 +122,6 @@ static constexpr const char* LIN_SETTINGS_NOT_AVAILABLE = "LIN settings are not
static constexpr const char* MODE_NOT_FOUND = "The mode was not found."; static constexpr const char* MODE_NOT_FOUND = "The mode was not found.";
static constexpr const char* GPTP_NOT_SUPPORTED = "GPTP clock synchronization is not supported on this device."; static constexpr const char* GPTP_NOT_SUPPORTED = "GPTP clock synchronization is not supported on this device.";
static constexpr const char* SETTING_NOT_AVAILABLE = "Requested a setting that is not available on this device"; static constexpr const char* SETTING_NOT_AVAILABLE = "Requested a setting that is not available on this device";
static constexpr const char* DISK_FORMAT_NOT_SUPPORTED = "Disk formatting is not supported on this device.";
static constexpr const char* DISK_FORMAT_INVALID_COUNT = "Disk format config disk count is mismatched with device disk count.";
// Transport Errors // Transport Errors
static constexpr const char* FAILED_TO_READ = "A read operation failed."; static constexpr const char* FAILED_TO_READ = "A read operation failed.";
@@ -147,6 +140,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.";
// VSA // VSA
static constexpr const char* VSA_BUFFER_CORRUPTED = "VSA data in record buffer is corrupted."; 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."; static constexpr const char* VSA_TIMESTAMP_NOT_FOUND = "Unable to find a VSA record with a valid timestamp.";
@@ -169,13 +197,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_NODATA_ERROR = "No data received from Servd";
static constexpr const char* SERVD_JOIN_MULTICAST_ERROR = "Error joining Servd multicast group"; 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* 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.";
@@ -219,12 +240,6 @@ const char* APIEvent::DescriptionForType(Type type) {
return RESTRICTED_ENTRY_FLAG; return RESTRICTED_ENTRY_FLAG;
case Type::NotSupported: case Type::NotSupported:
return NOT_SUPPORTED; return NOT_SUPPORTED;
case Type::FixedPointOverflow:
return FIXED_POINT_OVERFLOW;
case Type::FixedPointPrecision:
return FIXED_POINT_PRECISION;
case Type::SyscallError:
return SYSCALL_ERROR;
// Device Errors // Device Errors
case Type::PollingMessageOverflow: case Type::PollingMessageOverflow:
@@ -350,10 +365,74 @@ const char* APIEvent::DescriptionForType(Type type) {
return SEND_TO_ERROR; return SEND_TO_ERROR;
case Type::GPTPNotSupported: case Type::GPTPNotSupported:
return GPTP_NOT_SUPPORTED; return GPTP_NOT_SUPPORTED;
case Type::DiskFormatNotSupported:
return DISK_FORMAT_NOT_SUPPORTED; // FTD3XX
case Type::DiskFormatInvalidCount: case Type::FTOK:
return DISK_FORMAT_INVALID_COUNT; 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 // VSA
case Type::VSABufferCorrupted: case Type::VSABufferCorrupted:
@@ -395,18 +474,6 @@ const char* APIEvent::DescriptionForType(Type type) {
case Type::ServdJoinMulticastError: case Type::ServdJoinMulticastError:
return SERVD_JOIN_MULTICAST_ERROR; 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 // Other Errors
case Type::TooManyEvents: case Type::TooManyEvents:
return TOO_MANY_EVENTS; return TOO_MANY_EVENTS;
@@ -1,7 +1,5 @@
//FILE: icsneo40DLLAPI.H //FILE: icsneo40DLLAPI.H
#define WIN32_LEAN_AND_MEAN
#define NOMINMAX
#include <windows.h> #include <windows.h>
#include "icsneo/icsnVC40.h" #include "icsneo/icsnVC40.h"
+34 -24
View File
@@ -28,9 +28,6 @@ void init_event(pybind11::module_& m) {
.value("WiVINotSupported", APIEvent::Type::WiVINotSupported) .value("WiVINotSupported", APIEvent::Type::WiVINotSupported)
.value("RestrictedEntryFlag", APIEvent::Type::RestrictedEntryFlag) .value("RestrictedEntryFlag", APIEvent::Type::RestrictedEntryFlag)
.value("NotSupported", APIEvent::Type::NotSupported) .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("PollingMessageOverflow", APIEvent::Type::PollingMessageOverflow)
.value("NoSerialNumber", APIEvent::Type::NoSerialNumber) .value("NoSerialNumber", APIEvent::Type::NoSerialNumber)
.value("IncorrectSerialNumber", APIEvent::Type::IncorrectSerialNumber) .value("IncorrectSerialNumber", APIEvent::Type::IncorrectSerialNumber)
@@ -87,10 +84,6 @@ void init_event(pybind11::module_& m) {
.value("LINSettingsNotAvailable", APIEvent::Type::LINSettingsNotAvailable) .value("LINSettingsNotAvailable", APIEvent::Type::LINSettingsNotAvailable)
.value("ModeNotFound", APIEvent::Type::ModeNotFound) .value("ModeNotFound", APIEvent::Type::ModeNotFound)
.value("AppErrorParsingFailed", APIEvent::Type::AppErrorParsingFailed) .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("FailedToRead", APIEvent::Type::FailedToRead)
.value("FailedToWrite", APIEvent::Type::FailedToWrite) .value("FailedToWrite", APIEvent::Type::FailedToWrite)
.value("DriverFailedToOpen", APIEvent::Type::DriverFailedToOpen) .value("DriverFailedToOpen", APIEvent::Type::DriverFailedToOpen)
@@ -107,6 +100,39 @@ void init_event(pybind11::module_& m) {
.value("GetIfAddrsError", APIEvent::Type::GetIfAddrsError) .value("GetIfAddrsError", APIEvent::Type::GetIfAddrsError)
.value("SendToError", APIEvent::Type::SendToError) .value("SendToError", APIEvent::Type::SendToError)
.value("MDIOMessageExceedsMaxLength", APIEvent::Type::MDIOMessageExceedsMaxLength) .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("VSABufferCorrupted", APIEvent::Type::VSABufferCorrupted)
.value("VSATimestampNotFound", APIEvent::Type::VSATimestampNotFound) .value("VSATimestampNotFound", APIEvent::Type::VSATimestampNotFound)
.value("VSABufferFormatError", APIEvent::Type::VSABufferFormatError) .value("VSABufferFormatError", APIEvent::Type::VSABufferFormatError)
@@ -114,27 +140,11 @@ void init_event(pybind11::module_& m) {
.value("VSAByteParseFailure", APIEvent::Type::VSAByteParseFailure) .value("VSAByteParseFailure", APIEvent::Type::VSAByteParseFailure)
.value("VSAExtendedMessageError", APIEvent::Type::VSAExtendedMessageError) .value("VSAExtendedMessageError", APIEvent::Type::VSAExtendedMessageError)
.value("VSAOtherError", APIEvent::Type::VSAOtherError) .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("NoErrorFound", APIEvent::Type::NoErrorFound)
.value("TooManyEvents", APIEvent::Type::TooManyEvents) .value("TooManyEvents", APIEvent::Type::TooManyEvents)
.value("Unknown", APIEvent::Type::Unknown); .value("Unknown", APIEvent::Type::Unknown);
pybind11::enum_<APIEvent::Severity>(apiEvent, "Severity") pybind11::enum_<APIEvent::Severity>(apiEvent, "Severity")
.value("Any", APIEvent::Severity::Any) .value("Any", APIEvent::Severity::Any)
.value("EventInfo", APIEvent::Severity::EventInfo) .value("EventInfo", APIEvent::Severity::EventInfo)
.value("EventWarning", APIEvent::Severity::EventWarning) .value("EventWarning", APIEvent::Severity::EventWarning)
@@ -123,7 +123,6 @@ void init_network(pybind11::module_& m) {
.value("I2C_03", Network::NetID::I2C_03) .value("I2C_03", Network::NetID::I2C_03)
.value("I2C_04", Network::NetID::I2C_04) .value("I2C_04", Network::NetID::I2C_04)
.value("ETHERNET_02", Network::NetID::ETHERNET_02) .value("ETHERNET_02", Network::NetID::ETHERNET_02)
.value("ETHERNET_TX_WRAP", Network::NetID::ETHERNET_TX_WRAP)
.value("A2B_01", Network::NetID::A2B_01) .value("A2B_01", Network::NetID::A2B_01)
.value("A2B_02", Network::NetID::A2B_02) .value("A2B_02", Network::NetID::A2B_02)
.value("ETHERNET_03", Network::NetID::ETHERNET_03) .value("ETHERNET_03", Network::NetID::ETHERNET_03)
+1 -1
View File
@@ -17,7 +17,7 @@ void init_device(pybind11::module_& m) {
.def("close", &Device::close, pybind11::call_guard<pybind11::gil_scoped_release>()) .def("close", &Device::close, pybind11::call_guard<pybind11::gil_scoped_release>())
.def("describe", &Device::describe) .def("describe", &Device::describe)
.def("disable_message_polling", &Device::disableMessagePolling, pybind11::call_guard<pybind11::gil_scoped_release>()) .def("disable_message_polling", &Device::disableMessagePolling, pybind11::call_guard<pybind11::gil_scoped_release>())
.def("enable_message_polling", &Device::enableMessagePolling, pybind11::arg("filter") = std::nullopt, pybind11::call_guard<pybind11::gil_scoped_release>()) .def("enable_message_polling", &Device::enableMessagePolling, pybind11::call_guard<pybind11::gil_scoped_release>())
.def("get_current_message_count", &Device::getCurrentMessageCount) .def("get_current_message_count", &Device::getCurrentMessageCount)
.def("get_digital_io", &Device::getDigitalIO, pybind11::arg("type"), pybind11::arg("number"), pybind11::call_guard<pybind11::gil_scoped_release>()) .def("get_digital_io", &Device::getDigitalIO, pybind11::arg("type"), pybind11::arg("number"), pybind11::call_guard<pybind11::gil_scoped_release>())
.def("get_gptp_status", &Device::getGPTPStatus, pybind11::arg("timeout") = std::chrono::milliseconds(100), pybind11::call_guard<pybind11::gil_scoped_release>()) .def("get_gptp_status", &Device::getGPTPStatus, pybind11::arg("timeout") = std::chrono::milliseconds(100), pybind11::call_guard<pybind11::gil_scoped_release>())
+21
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
+22
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()
-11
View File
@@ -324,17 +324,6 @@ bool Decoder::decode(std::shared_ptr<Message>& result, const std::shared_ptr<Pac
result = GPTPStatus::DecodeToMessage(packet->data, report); result = GPTPStatus::DecodeToMessage(packet->data, report);
return true; return true;
} }
case ExtendedCommand::GetDiskDetails:
case ExtendedCommand::DiskFormatProgress: {
std::vector<uint8_t> responseBody(
packet->data.begin() + sizeof(ExtendedResponseMessage::ResponseHeader),
packet->data.end()
);
auto response = std::make_shared<ExtendedResponseMessage>(resp.command);
response->data = std::move(responseBody);
result = response;
return true;
}
default: default:
// No defined handler, treat this as a RawMessage // No defined handler, treat this as a RawMessage
break; break;
+4 -13
View File
@@ -35,25 +35,15 @@ bool Encoder::encode(const Packetizer& packetizer, std::vector<uint8_t>& result,
auto ethmsg = std::dynamic_pointer_cast<EthernetMessage>(message); auto ethmsg = std::dynamic_pointer_cast<EthernetMessage>(message);
if(!ethmsg) { if(!ethmsg) {
report(APIEvent::Type::MessageFormattingError, APIEvent::Severity::Error); report(APIEvent::Type::MessageFormattingError, APIEvent::Severity::Error);
return false; return false; // The message was not a properly formed EthernetMessage
} }
shortFormat = false; // Ensure long-format RED header is added
netid = static_cast<uint16_t>(Network::NetID::ETHERNET_TX_WRAP);
buffer = &result; buffer = &result;
if(!HardwareEthernetPacket::EncodeFromMessage(*ethmsg, result, report))
if(!HardwareEthernetPacket::EncodeFromMessage(*ethmsg, result, report)) {
report(APIEvent::Type::MessageFormattingError, APIEvent::Severity::Error);
return false; return false;
}
if(result.empty()) {
report(APIEvent::Type::MessageFormattingError, APIEvent::Severity::Error);
return false;
}
break; break;
} } // End of Network::Type::Ethernet
case Network::Type::CAN: case Network::Type::CAN:
case Network::Type::SWCAN: case Network::Type::SWCAN:
case Network::Type::LSFTCAN: { case Network::Type::LSFTCAN: {
@@ -240,6 +230,7 @@ bool Encoder::encode(const Packetizer& packetizer, std::vector<uint8_t>& result,
(uint8_t)(netid >> 8) (uint8_t)(netid >> 8)
}); });
} }
result = packetizer.packetWrap(*buffer, shortFormat); result = packetizer.packetWrap(*buffer, shortFormat);
return true; return true;
} }
+13 -16
View File
@@ -1,5 +1,4 @@
#include "icsneo/communication/livedata.h" #include "icsneo/communication/livedata.h"
#include <cmath>
namespace icsneo { namespace icsneo {
namespace LiveDataUtil { namespace LiveDataUtil {
@@ -19,7 +18,7 @@ double liveDataValueToDouble(const LiveDataValue& val) {
return val.value * liveDataFixedPointToDouble; return val.value * liveDataFixedPointToDouble;
} }
bool liveDataDoubleToValue(const double& dFloat, LiveDataValue& value) { int liveDataDoubleToValue(LiveDataValue& value, const double& dFloat) {
union { union {
struct struct
{ {
@@ -41,38 +40,36 @@ bool liveDataDoubleToValue(const double& dFloat, LiveDataValue& value) {
// long long (value is >= 2^63) and so the assignment ValueLarge = dBigFloat is undefined // long long (value is >= 2^63) and so the assignment ValueLarge = dBigFloat is undefined
int32_t intPart; //creating temp variable due to static analysis warning about writing and reading to different union members int32_t intPart; //creating temp variable due to static analysis warning about writing and reading to different union members
if(dFloat < 0.0) if (dFloat < 0.0)
intPart = (int32_t)std::floor(dFloat); intPart = (int32_t)floor(dFloat);
else else
intPart = (int32_t)dFloat; intPart = (int32_t)dFloat;
//using temp varialbes to avoid static analysis warning about read/write to different union members //using temp varialbes to avoid static analysis warning about read/write to different union members
double frac = dFloat - (double)(intPart); double frac = dFloat - (double)(intPart);
uint32_t fracPart = (uint32_t)std::floor((frac * CM_DOUBLEVALUE_TO_FIXED_POINT) + 0.5); uint32_t fracPart = (uint32_t)floor((frac * CM_DOUBLEVALUE_TO_FIXED_POINT) + 0.5);
//write temp vars back into the union //write temp vars back into the union
CminiFixedPt.parts.ValueInt32 = intPart; CminiFixedPt.parts.ValueInt32 = intPart;
CminiFixedPt.parts.ValueFractionPart = fracPart; CminiFixedPt.parts.ValueFractionPart = fracPart;
value.value = CminiFixedPt.ValueLarge; value.value = CminiFixedPt.ValueLarge;
if(dFloat == (double)0.0) if (dFloat == (double)0.0)
return true; return 0;
//check if double can be stored as 32.32 //check if double can be stored as 32.32
// 0x1 0000 0000 0000 0000 * CM_FIXED_POINT_TO_DOUBLEVALUE = 0x1 0000 0000 // 0x1 0000 0000 0000 0000 * CM_FIXED_POINT_TO_DOUBLEVALUE = 0x1 0000 0000
if(dFloat > INT32_MAX_DOUBLE || dFloat < INT32_MIN_DOUBLE) { if (dFloat > INT32_MAX_DOUBLE)
EventManager::GetInstance().add(APIEvent::Type::FixedPointOverflow, APIEvent::Severity::Error); return 1;
return false; if (dFloat < INT32_MIN_DOUBLE)
} return -1;
// Use absolute value for minimum fixed point check // Use absolute value for minimum fixed point check
double absFloat = (dFloat < 0.0) ? -dFloat : dFloat; double absFloat = (dFloat < 0.0) ? -dFloat : dFloat;
if(absFloat < MIN_FIXED_POINT_DOUBLE) { if (absFloat < MIN_FIXED_POINT_DOUBLE)
EventManager::GetInstance().add(APIEvent::Type::FixedPointPrecision, APIEvent::Severity::Error); return -2;
return false;
}
return true; return 0;
} }
} // namespace LiveDataUtil } // namespace LiveDataUtil
+37 -70
View File
@@ -1,5 +1,5 @@
#include "icsneo/communication/packet/ethernetpacket.h" #include "icsneo/communication/packet/ethernetpacket.h"
#include <algorithm> // for std::copy #include <cstring> // memcpy
#include <iostream> #include <iostream>
using namespace icsneo; using namespace icsneo;
@@ -7,31 +7,40 @@ using namespace icsneo;
std::shared_ptr<EthernetMessage> HardwareEthernetPacket::DecodeToMessage(const std::vector<uint8_t>& bytestream, const device_eventhandler_t& report) { std::shared_ptr<EthernetMessage> HardwareEthernetPacket::DecodeToMessage(const std::vector<uint8_t>& bytestream, const device_eventhandler_t& report) {
const HardwareEthernetPacket* packet = (const HardwareEthernetPacket*)((const void*)bytestream.data()); const HardwareEthernetPacket* packet = (const HardwareEthernetPacket*)((const void*)bytestream.data());
const uint16_t* rawWords = (const uint16_t*)bytestream.data(); const uint16_t* rawWords = (const uint16_t*)bytestream.data();
// Make sure we have enough to read the packet length first // Make sure we have enough to read the packet length first
if(bytestream.size() < sizeof(HardwareEthernetPacket)) if(bytestream.size() < sizeof(HardwareEthernetPacket))
return nullptr; return nullptr;
// packet->Length will also encompass the two uint16_t's at the end of the struct, make sure that at least they are here // packet->Length will also encompass the two uint16_t's at the end of the struct, make sure that at least they are here
if(packet->Length < 4) if(packet->Length < 4)
return nullptr; return nullptr;
const size_t fcsSize = packet->header.FCS_AVAIL ? 4 : 0; const size_t fcsSize = packet->header.FCS_AVAIL ? 4 : 0;
const size_t bytestreamExpectedSize = sizeof(HardwareEthernetPacket) + packet->Length; const size_t bytestreamExpectedSize = sizeof(HardwareEthernetPacket) + packet->Length;
const size_t bytestreamActualSize = bytestream.size(); const size_t bytestreamActualSize = bytestream.size();
if(bytestreamActualSize < bytestreamExpectedSize) if(bytestreamActualSize < bytestreamExpectedSize)
return nullptr; return nullptr;
// Check for oversized packets, noting that some devices will send an extra byte to have an even number of bytes // Check for oversized packets, noting that some devices will send an extra byte to have an even number of bytes
if(bytestreamActualSize > bytestreamExpectedSize + 1) if(bytestreamActualSize > bytestreamExpectedSize + 1)
report(APIEvent::Type::PacketDecodingError, APIEvent::Severity::EventWarning); report(APIEvent::Type::PacketDecodingError, APIEvent::Severity::EventWarning);
auto messagePtr = std::make_shared<EthernetMessage>(); auto messagePtr = std::make_shared<EthernetMessage>();
EthernetMessage& message = *messagePtr; EthernetMessage& message = *messagePtr;
message.transmitted = packet->eid.TXMSG; message.transmitted = packet->eid.TXMSG;
if(message.transmitted) if(message.transmitted)
message.description = packet->stats; message.description = packet->stats;
message.preemptionEnabled = packet->header.PREEMPTION_ENABLED; message.preemptionEnabled = packet->header.PREEMPTION_ENABLED;
if(message.preemptionEnabled) if(message.preemptionEnabled)
message.preemptionFlags = (uint8_t)((rawWords[0] & 0x03F8) >> 4); message.preemptionFlags = (uint8_t)((rawWords[0] & 0x03F8) >> 4);
message.frameTooShort = packet->header.RUNT_FRAME; message.frameTooShort = packet->header.RUNT_FRAME;
if(message.frameTooShort) if(message.frameTooShort)
message.error = true; message.error = true;
// This timestamp is raw off the device (in timestampResolution increments) // This timestamp is raw off the device (in timestampResolution increments)
// Decoder will fix as it has information about the timestampResolution increments // Decoder will fix as it has information about the timestampResolution increments
message.timestamp = packet->timestamp.TS; message.timestamp = packet->timestamp.TS;
@@ -50,83 +59,41 @@ std::shared_ptr<EthernetMessage> HardwareEthernetPacket::DecodeToMessage(const s
bool HardwareEthernetPacket::EncodeFromMessage(const EthernetMessage& message, std::vector<uint8_t>& bytestream, const device_eventhandler_t&) { bool HardwareEthernetPacket::EncodeFromMessage(const EthernetMessage& message, std::vector<uint8_t>& bytestream, const device_eventhandler_t&) {
const size_t unpaddedSize = message.data.size(); const size_t unpaddedSize = message.data.size();
if(unpaddedSize == 0) size_t paddedSize = unpaddedSize;
return false; uint16_t description = message.description;
if(!message.noPadding && unpaddedSize < 60)
paddedSize = 60; // Pad out short messages
size_t sizeWithHeader = paddedSize + 4; // DescriptionID and Padded Count
// Description ID Most Significant bit is used to identify preemption frames // Description ID Most Significant bit is used to identify preemption frames
uint16_t description = message.description;
if(description & 0x8000) if(description & 0x8000)
return false; return false;
const bool preempt = message.preemptionEnabled; if(message.preemptionEnabled) {
// full header including parent sizeWithHeader++; // Make space for the preemption flags
const size_t headerByteCount = preempt ? 15 : 14;
// local header for netID, description, and flags
const size_t localHeader = preempt ? 10 : 9;
// allocate space for fcs override
const size_t fcsSize = message.fcs ? 4 : 0;
if(preempt)
description |= 0x8000; description |= 0x8000;
size_t paddedSize = unpaddedSize;
if(!message.noPadding && unpaddedSize < 60)
paddedSize = 60;
// size of full payload including optional fcs
size_t payloadSize = paddedSize + fcsSize;
// totalBufferSize is local header + ethernet payload and option fcs
const size_t totalBufferSize = localHeader + paddedSize + fcsSize;
bytestream.clear();
bytestream.reserve(totalBufferSize);
// Header size field (little endian)
bytestream.push_back(static_cast<uint8_t>(payloadSize & 0xFF));
bytestream.push_back(static_cast<uint8_t>((payloadSize >> 8) & 0xFF));
// Description (big endian)
bytestream.push_back(static_cast<uint8_t>(description >> 8));
bytestream.push_back(static_cast<uint8_t>(description));
bytestream.push_back(0x00);
bytestream.push_back(static_cast<uint8_t>(headerByteCount));
// Network ID (little endian)
uint16_t realID = static_cast<uint16_t>(message.network.getNetID());
bytestream.push_back(static_cast<uint8_t>(realID & 0xFF));
bytestream.push_back(static_cast<uint8_t>((realID >> 8) & 0xFF));
// Flags
constexpr uint8_t FLAG_PADDING = 0x01;
constexpr uint8_t FLAG_FCS = 0x04;
constexpr uint8_t FLAG_PREEMPTION = 0x08;
uint8_t flags = 0x00;
if(!message.noPadding) flags |= FLAG_PADDING;
if(message.fcs) flags |= FLAG_FCS;
if(message.preemptionEnabled) flags |= FLAG_PREEMPTION;
bytestream.push_back(flags);
if(preempt)
bytestream.push_back(static_cast<uint8_t>(message.preemptionFlags));
bytestream.insert(bytestream.end(), message.data.begin(), message.data.end());
// Only zero-fill when we want padding
if(!message.noPadding && unpaddedSize < 60) {
size_t paddingNeeded = 60 - unpaddedSize;
bytestream.insert(bytestream.end(), paddingNeeded, 0); // Zero-fill for padding
} }
if(message.fcs) { bytestream.reserve(sizeWithHeader + 8); // Also reserve space for the bytes we'll use later on
uint32_t fcs = message.fcs.value(); bytestream.resize(sizeWithHeader);
const uint8_t* fcsBytes = reinterpret_cast<const uint8_t*>(&fcs); size_t index = 0;
bytestream.insert(bytestream.end(), fcsBytes, fcsBytes + sizeof(fcs));
} // Padded size, little endian
bytestream[index++] = uint8_t(paddedSize);
bytestream[index++] = uint8_t(paddedSize >> 8);
// Description ID, big endian
bytestream[index++] = uint8_t(description >> 8);
bytestream[index++] = uint8_t(description);
// The header is one byte larger if preemption is enabled, shifting the data
if(message.preemptionEnabled)
bytestream[index++] = message.preemptionFlags;
// We only copy in the unpadded size, the rest will be 0
memcpy(bytestream.data() + index, message.data.data(), unpaddedSize);
return true; return true;
} }
+2 -2
View File
@@ -111,14 +111,14 @@ bool HardwareLiveDataPacket::EncodeFromMessage(LiveDataMessage& message, std::ve
if(!setValMsg->handle) if(!setValMsg->handle)
setValMsg->handle = LiveDataUtil::getNewHandle(); setValMsg->handle = LiveDataUtil::getNewHandle();
out->handle = setValMsg->handle; out->handle = setValMsg->handle;
out->numSetValues = (uint32_t)numArgs; out->numArgs = static_cast<uint32_t>(setValMsg->args.size());
for(size_t i = 0; i < numArgs; ++i) { for(size_t i = 0; i < numArgs; ++i) {
out->values[i].arg.objectType = setValMsg->args[i]->objectType; out->values[i].arg.objectType = setValMsg->args[i]->objectType;
out->values[i].arg.objectIndex = setValMsg->args[i]->objectIndex; out->values[i].arg.objectIndex = setValMsg->args[i]->objectIndex;
out->values[i].arg.signalIndex = setValMsg->args[i]->signalIndex; out->values[i].arg.signalIndex = setValMsg->args[i]->signalIndex;
out->values[i].arg.valueType = setValMsg->args[i]->valueType; out->values[i].arg.valueType = setValMsg->args[i]->valueType;
out->values[i].value.value = setValMsg->values[i]->value; out->values[i].value.value = setValMsg->values[i]->value;
out->values[i].value.header.length = sizeof(LiveDataValue::value); out->values[i].value.header.length = sizeof(int64_t);
} }
} else { } else {
report(APIEvent::Type::LiveDataInvalidArgument, APIEvent::Severity::Error); report(APIEvent::Type::LiveDataInvalidArgument, APIEvent::Severity::Error);
+7 -148
View File
@@ -5,7 +5,6 @@
#include "icsneo/device/device.h" #include "icsneo/device/device.h"
#include "icsneo/device/extensions/deviceextension.h" #include "icsneo/device/extensions/deviceextension.h"
#include "icsneo/disk/fat.h" #include "icsneo/disk/fat.h"
#include "icsneo/communication/message/filter/extendedresponsefilter.h"
#ifdef _MSC_VER #ifdef _MSC_VER
#pragma warning(disable : 4996) // STL time functions #pragma warning(disable : 4996) // STL time functions
@@ -105,21 +104,15 @@ std::string Device::describe() const {
return ss.str(); return ss.str();
} }
bool Device::enableMessagePolling(std::optional<MessageFilter> filter) { bool Device::enableMessagePolling() {
if(isMessagePollingEnabled()) {// We are already polling if(isMessagePollingEnabled()) {// We are already polling
report(APIEvent::Type::DeviceCurrentlyPolling, APIEvent::Severity::Error); report(APIEvent::Type::DeviceCurrentlyPolling, APIEvent::Severity::Error);
return false; return false;
} }
if(!filter.has_value()) { messagePollingCallbackID = com->addMessageCallback(std::make_shared<MessageCallback>([this](std::shared_ptr<Message> message) {
// If no filter is provided, use a default that includes all messages
filter.emplace(MessageFilter());
filter->includeInternalInAny = true;
}
auto callback = std::make_shared<MessageCallback>(*filter, [this](std::shared_ptr<Message> message) {
pollingContainer.enqueue(message); pollingContainer.enqueue(message);
enforcePollingMessageLimit(); enforcePollingMessageLimit();
}); }));
messagePollingCallbackID = com->addMessageCallback(callback);
return true; return true;
} }
@@ -284,7 +277,7 @@ bool Device::open(OpenFlags flags, OpenStatusHandler handler) {
std::condition_variable heartbeatCV; std::condition_variable heartbeatCV;
std::mutex receivedMessageMutex; std::mutex receivedMessageMutex;
bool receivedMessage = false; bool receivedMessage = false;
auto messageReceivedCallbackID = com->addMessageCallback(std::make_shared<MessageCallback>(filter, [&](std::shared_ptr<Message>) { auto messageReceivedCallbackID = com->addMessageCallback(std::make_shared<MessageCallback>(filter, [&](std::shared_ptr<Message> message) {
{ {
std::scoped_lock<std::mutex> lk(receivedMessageMutex); std::scoped_lock<std::mutex> lk(receivedMessageMutex);
receivedMessage = true; receivedMessage = true;
@@ -421,8 +414,7 @@ bool Device::disableLogData() {
} }
bool Device::goOnline() { bool Device::goOnline() {
static constexpr uint32_t onlineTimeoutMs = 5000; if(!enableNetworkCommunication(true))
if(!enableNetworkCommunication(true, onlineTimeoutMs))
return false; return false;
auto startTime = std::chrono::system_clock::now(); auto startTime = std::chrono::system_clock::now();
@@ -451,19 +443,13 @@ bool Device::goOnline() {
return false; return false;
} }
// (re)start the keeponline
keeponline = std::make_unique<Periodic>([this] { return enableNetworkCommunication(true, onlineTimeoutMs); }, std::chrono::milliseconds(onlineTimeoutMs / 4));
online = true; online = true;
forEachExtension([](const std::shared_ptr<DeviceExtension>& ext) { ext->onGoOnline(); return true; }); forEachExtension([](const std::shared_ptr<DeviceExtension>& ext) { ext->onGoOnline(); return true; });
return true; return true;
} }
bool Device::goOffline() { bool Device::goOffline() {
keeponline.reset();
forEachExtension([](const std::shared_ptr<DeviceExtension>& ext) { ext->onGoOffline(); return true; }); forEachExtension([](const std::shared_ptr<DeviceExtension>& ext) { ext->onGoOffline(); return true; });
if(isDisconnected()) { if(isDisconnected()) {
@@ -3489,142 +3475,15 @@ bool Device::writeMACsecConfig(const MACsecMessage& message, uint16_t binaryInde
return writeBinaryFile(raw, binaryIndex); return writeBinaryFile(raw, binaryIndex);
} }
bool Device::enableNetworkCommunication(bool enable, uint32_t timeout) { bool Device::enableNetworkCommunication(bool enable) {
bool sendMsg = false; bool sendMsg = false;
if(!com->driver->enableCommunication(enable, sendMsg)) { if(!com->driver->enableCommunication(enable, sendMsg)) {
return false; return false;
} }
if(sendMsg) { if(sendMsg) {
const uint8_t* i = (uint8_t*)&timeout; if(!com->sendCommand(Command::EnableNetworkCommunication, enable)) {
if(!com->sendCommand(Command::EnableNetworkCommunication, {enable, 0, 0, 0, i[0], i[1], i[2], i[3]})) {
return false; return false;
} }
} }
return true; return true;
} }
bool Device::formatDisk(const DiskDetails& config, const DiskFormatProgress& handler, std::chrono::milliseconds interval) {
#pragma pack(push, 2)
struct DiskFormatProgressResponse {
uint16_t state;
uint64_t sectorsRemaining;
};
#pragma pack(pop)
auto diskCount = getDiskCount();
if(!diskCount) {
report(APIEvent::Type::DiskFormatNotSupported, APIEvent::Severity::Error);
return false;
}
if(config.disks.size() != diskCount) {
report(APIEvent::Type::DiskFormatInvalidCount, APIEvent::Severity::Error);
return false;
}
std::vector<uint8_t> payload = DiskDetails::Encode(config);
if(!com->sendCommand(ExtendedCommand::DiskFormatStart, payload)) {
return false;
}
uint64_t sectorsFormatted = 0;
uint64_t sectorsTotal = 0;
uint16_t lastState = 1;
do {
std::shared_ptr<Message> response = com->waitForMessageSync(
[this](){
return com->sendCommand(ExtendedCommand::DiskFormatProgress, {});
},
std::make_shared<ExtendedResponseFilter>(ExtendedCommand::DiskFormatProgress),
std::chrono::milliseconds(200)
);
if(!response) {
report(APIEvent::Type::NoDeviceResponse, APIEvent::Severity::Error);
return false;
}
auto extResponse = std::dynamic_pointer_cast<ExtendedResponseMessage>(response);
if(!extResponse) {
// Should never happen
return false;
}
if(extResponse->data.size() < sizeof(DiskFormatProgressResponse)) {
report(APIEvent::Type::BufferInsufficient, APIEvent::Severity::Error);
return false;
}
auto* progress = reinterpret_cast<DiskFormatProgressResponse*>(extResponse->data.data());
lastState = progress->state;
if(sectorsTotal == 0) {
sectorsTotal = progress->sectorsRemaining;
} else {
sectorsFormatted = sectorsTotal - progress->sectorsRemaining;
if(handler) {
auto directive = handler(sectorsFormatted, sectorsTotal);
if(directive == DiskFormatDirective::Stop) {
return com->sendCommand(ExtendedCommand::DiskFormatCancel);
}
}
}
std::this_thread::sleep_for(interval);
} while(lastState);
return true;
}
bool Device::forceDiskConfigUpdate(const DiskDetails& config) {
auto diskCount = getDiskCount();
if(!diskCount) {
report(APIEvent::Type::DiskFormatNotSupported, APIEvent::Severity::Error);
return false;
}
if(config.disks.size() != diskCount) {
report(APIEvent::Type::DiskFormatInvalidCount, APIEvent::Severity::Error);
return false;
}
return com->sendCommand(ExtendedCommand::DiskFormatUpdate, DiskDetails::Encode(config));
}
std::shared_ptr<DiskDetails> Device::getDiskDetails(std::chrono::milliseconds timeout) {
if(!supportsDiskFormatting()) {
report(APIEvent::Type::DiskFormatNotSupported, APIEvent::Severity::Error);
return nullptr;
}
if(!isOpen()) {
report(APIEvent::Type::DeviceCurrentlyClosed, APIEvent::Severity::Error);
return nullptr;
}
std::shared_ptr<Message> response = com->waitForMessageSync(
[this](){
return com->sendCommand(ExtendedCommand::GetDiskDetails, {});
},
std::make_shared<ExtendedResponseFilter>(ExtendedCommand::GetDiskDetails),
timeout
);
if(!response) {
report(APIEvent::Type::NoDeviceResponse, APIEvent::Severity::Error);
return nullptr;
}
auto extResponse = std::dynamic_pointer_cast<ExtendedResponseMessage>(response);
if(!extResponse) {
// Should never happen
return nullptr;
}
return DiskDetails::Decode(extResponse->data, getDiskCount(), report);
}
+12 -4
View File
@@ -16,8 +16,12 @@
#include "icsneo/platform/cdcacm.h" #include "icsneo/platform/cdcacm.h"
#endif #endif
#ifdef ICSNEO_ENABLE_DXX #ifdef ICSNEO_ENABLE_FTDI
#include "icsneo/platform/dxx.h" #include "icsneo/platform/ftdi.h"
#endif
#ifdef ICSNEO_ENABLE_FTD3XX
#include "icsneo/platform/ftd3xx.h"
#endif #endif
#ifdef ICSNEO_ENABLE_TCP #ifdef ICSNEO_ENABLE_TCP
@@ -79,8 +83,12 @@ std::vector<std::shared_ptr<Device>> DeviceFinder::FindAll() {
CDCACM::Find(newDriverFoundDevices); CDCACM::Find(newDriverFoundDevices);
#endif #endif
#ifdef ICSNEO_ENABLE_DXX #ifdef ICSNEO_ENABLE_FTDI
DXX::Find(newDriverFoundDevices); FTDI::Find(newDriverFoundDevices);
#endif
#ifdef ICSNEO_ENABLE_FTD3XX
FTD3XX::Find(newDriverFoundDevices);
#endif #endif
} }
-81
View File
@@ -1,81 +0,0 @@
#include <icsneo/disk/diskdetails.h>
#include <icsneo/device/idevicesettings.h>
using namespace icsneo;
#pragma pack(push, 2)
struct DISK_STATUS {
uint16_t status;
uint64_t sectors;
uint32_t bytesPerSector;
};
struct DISK_DETAILS {
DISK_SETTINGS settings;
uint16_t options;
DISK_STATUS status[12];
};
#pragma pack(pop)
static constexpr uint8_t DISK_FORMAT_FAT32 = 0x01u;
static constexpr uint8_t DISK_STATUS_PRESENT = 0x01u;
static constexpr uint8_t DISK_STATUS_INITIALIZED = 0x02u;
static constexpr uint16_t DISK_DETAILS_FULL_FORMAT = 0x01u;
std::vector<uint8_t> DiskDetails::Encode(const DiskDetails& config) {
std::vector<uint8_t> result(sizeof(DISK_DETAILS), 0);
DISK_DETAILS* details = reinterpret_cast<DISK_DETAILS*>(result.data());
details->settings.disk_layout = static_cast<uint8_t>(config.layout);
details->settings.disk_format = DISK_FORMAT_FAT32; // Always FAT32
details->options = config.fullFormat ? DISK_DETAILS_FULL_FORMAT : 0;
uint32_t& enables = details->settings.disk_enables;
enables = 0u;
for(size_t i = 0; i < config.disks.size(); i++) {
auto& disk = config.disks[i];
details->status[i].sectors = disk.sectors;
details->status[i].bytesPerSector = disk.bytesPerSector;
uint16_t& status = details->status[i].status;
status = 0u;
if(disk.initialized) {
status |= DISK_STATUS_INITIALIZED;
}
if(disk.present) {
status |= DISK_STATUS_PRESENT;
}
if(disk.formatted) {
enables |= (1u << i);
}
}
return result;
}
std::shared_ptr<DiskDetails> DiskDetails::Decode(const std::vector<uint8_t>& bytes, size_t diskCount, device_eventhandler_t report) {
if(bytes.size() < sizeof(DISK_DETAILS)) {
report(APIEvent::Type::BufferInsufficient, APIEvent::Severity::Error);
return nullptr;
}
auto result = std::make_shared<DiskDetails>();
const DISK_DETAILS* details = reinterpret_cast<const DISK_DETAILS*>(bytes.data());
result->layout = static_cast<DiskLayout>(details->settings.disk_layout);
result->fullFormat = details->options & DISK_DETAILS_FULL_FORMAT;
result->disks.reserve(diskCount);
for(size_t i = 0; i < diskCount; i++) {
auto& disk = details->status[i];
result->disks.emplace_back();
auto& info = result->disks.back();
info.present = static_cast<bool>(disk.status & DISK_STATUS_PRESENT);
info.initialized = static_cast<bool>(disk.status & DISK_STATUS_INITIALIZED);
info.formatted = static_cast<bool>(details->settings.disk_enables & (1u << i));
info.sectors = disk.sectors;
info.bytesPerSector = disk.bytesPerSector;
}
return result;
}
+1 -1
View File
@@ -32,7 +32,7 @@ std::optional<uint64_t> ExtExtractorDiskReadDriver::readLogicalDiskAligned(Commu
return ret; return ret;
} }
std::optional<uint64_t> ExtExtractorDiskReadDriver::attemptReadLogicalDiskAligned(Communication& com, device_eventhandler_t, std::optional<uint64_t> ExtExtractorDiskReadDriver::attemptReadLogicalDiskAligned(Communication& com, device_eventhandler_t report,
uint64_t pos, uint8_t* into, uint64_t amount, std::chrono::milliseconds timeout, MemoryType) { uint64_t pos, uint8_t* into, uint64_t amount, std::chrono::milliseconds timeout, MemoryType) {
static std::shared_ptr<MessageFilter> NeoMemorySDRead = std::make_shared<MessageFilter>(Network::NetID::NeoMemorySDRead); static std::shared_ptr<MessageFilter> NeoMemorySDRead = std::make_shared<MessageFilter>(Network::NetID::NeoMemorySDRead);
+1 -1
View File
@@ -58,7 +58,7 @@ std::optional<uint64_t> NeoMemoryDiskDriver::readLogicalDiskAligned(Communicatio
return SectorSize; return SectorSize;
} }
std::optional<uint64_t> NeoMemoryDiskDriver::writeLogicalDiskAligned(Communication& com, device_eventhandler_t, std::optional<uint64_t> NeoMemoryDiskDriver::writeLogicalDiskAligned(Communication& com, device_eventhandler_t report,
uint64_t pos, const uint8_t* from, uint64_t amount, std::chrono::milliseconds timeout, MemoryType memType) { uint64_t pos, const uint8_t* from, uint64_t amount, std::chrono::milliseconds timeout, MemoryType memType) {
static std::shared_ptr<MessageFilter> NeoMemoryDone = std::make_shared<MessageFilter>(Network::NetID::NeoMemoryWriteDone); static std::shared_ptr<MessageFilter> NeoMemoryDone = std::make_shared<MessageFilter>(Network::NetID::NeoMemoryWriteDone);
+1 -1
View File
@@ -6,7 +6,7 @@
using namespace icsneo; using namespace icsneo;
using namespace icsneo::Disk; using namespace icsneo::Disk;
std::optional<uint64_t> PlasionDiskReadDriver::readLogicalDiskAligned(Communication& com, device_eventhandler_t, std::optional<uint64_t> PlasionDiskReadDriver::readLogicalDiskAligned(Communication& com, device_eventhandler_t report,
uint64_t pos, uint8_t* into, uint64_t amount, std::chrono::milliseconds timeout, MemoryType) { uint64_t pos, uint8_t* into, uint64_t amount, std::chrono::milliseconds timeout, MemoryType) {
static std::shared_ptr<MessageFilter> NeoMemorySDRead = std::make_shared<MessageFilter>(Network::NetID::NeoMemorySDRead); static std::shared_ptr<MessageFilter> NeoMemorySDRead = std::make_shared<MessageFilter>(Network::NetID::NeoMemorySDRead);
+1 -1
View File
@@ -7,7 +7,7 @@ VSA08::VSA08(uint8_t* const recordBytes)
{ {
setType(VSA::Type::AA08); setType(VSA::Type::AA08);
troubleSramCount.insert(troubleSramCount.end(), recordBytes + 2, recordBytes + 6); 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; timestamp = *reinterpret_cast<uint64_t*>(recordBytes + 22) & UINT63_MAX;
checksum = *reinterpret_cast<uint16_t*>(recordBytes + 30); checksum = *reinterpret_cast<uint16_t*>(recordBytes + 30);
doChecksum(recordBytes); doChecksum(recordBytes);
+1 -1
View File
@@ -8,7 +8,7 @@ Dependencies
The minimum requirements to build libicsneo are: The minimum requirements to build libicsneo are:
- CMake version 3.12 or newer - CMake version 3.12 or newer
- A C++17 compiler - A C++17 compiler
- libpcap on Linux and macOS - libusb and libpcap on Linux and macOS
Building library & examples Building library & examples
+35 -2
View File
@@ -92,9 +92,42 @@ Monitor Ethernet Status
TC10 TC10
==== ====
:download:`Download example <../../examples/python/tc10/tc10.py>` .. code-block:: python
.. literalinclude:: ../../examples/python/tc10/tc10.py import icsneopy
import time
devices: list[icsneopy.Device] = icsneopy.find_all_devices()
device: icsneopy.Device = devices[0]
print(f"using {device} for TC10")
device.open()
netid = icsneopy.Network.NetID.AE_01
if device.supports_tc10():
# initial
status = device.get_tc10_status(netid)
print(f"initial status: wake: {status.wakeStatus}, sleep: {status.sleepStatus}")
time.sleep(1)
# sleep
device.request_tc10_sleep(netid)
print("waiting 1s for sleep to occur")
time.sleep(1)
status = device.get_tc10_status(netid)
print(f"post sleep status: wake: {status.wakeStatus}, sleep: {status.sleepStatus}")
# wake
device.request_tc10_wake(netid)
print("waiting 1s for wake to occur")
time.sleep(1)
status = device.get_tc10_status(netid)
print(f"post wake status: wake: {status.wakeStatus}, sleep: {status.sleepStatus}")
else:
print(f"{device} does not support TC10")
DoIP Ethernet Activation DoIP Ethernet Activation
======================== ========================
+1 -1
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. 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` 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` 3. Enter the build directory with `cd build`
4. Run `cmake ..` to generate your Makefile. 4. Run `cmake ..` to generate your Makefile.
+1 -1
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. 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` 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` 3. Enter the build directory with `cd build`
4. Run `cmake ..` to generate your Makefile. 4. Run `cmake ..` to generate your Makefile.
+1 -1
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. 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` 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` 3. Enter the build directory with `cd build`
4. Run `cmake ..` to generate your Makefile. 4. Run `cmake ..` to generate your Makefile.
+1 -1
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 ### 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` 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` 3. Enter the build directory with `cd build`
4. Run `cmake ..` to generate your Makefile. 4. Run `cmake ..` to generate your Makefile.
@@ -80,7 +80,8 @@ int main() {
// Run handler for three seconds to observe the signal data // Run handler for three seconds to observe the signal data
std::this_thread::sleep_for(std::chrono::seconds(3)); std::this_thread::sleep_for(std::chrono::seconds(3));
double val = 0; double val = 0;
for (unsigned int i = 0; i < 10; ++i) { for (unsigned int i = 0; i < 10; ++i)
{
// Set the values of signals we're watching so we can see them change live // Set the values of signals we're watching so we can see them change live
auto setValMsg = std::make_shared<icsneo::LiveDataSetValueMessage>(); auto setValMsg = std::make_shared<icsneo::LiveDataSetValueMessage>();
setValMsg->cmd = icsneo::LiveDataCommand::SET_VALUE; setValMsg->cmd = icsneo::LiveDataCommand::SET_VALUE;
@@ -88,8 +89,9 @@ int main() {
// Convert the value format // Convert the value format
icsneo::LiveDataValue ldValueDAQEnable; icsneo::LiveDataValue ldValueDAQEnable;
icsneo::LiveDataValue ldValueManTrig; icsneo::LiveDataValue ldValueManTrig;
if (!icsneo::LiveDataUtil::liveDataDoubleToValue(val / 3, ldValueDAQEnable) || if ((icsneo::LiveDataUtil::liveDataDoubleToValue(ldValueDAQEnable, val * 10) < 0) ||
!icsneo::LiveDataUtil::liveDataDoubleToValue(val, ldValueManTrig)) { (icsneo::LiveDataUtil::liveDataDoubleToValue(ldValueManTrig, val) < 0))
{
break; break;
} }
setValMsg->appendSetValue(icsneo::LiveDataValueType::DAQ_ENABLE, ldValueDAQEnable); setValMsg->appendSetValue(icsneo::LiveDataValueType::DAQ_ENABLE, ldValueDAQEnable);
+1 -1
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 ### 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` 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` 3. Enter the build directory with `cd build`
4. Run `cmake ..` to generate your Makefile. 4. Run `cmake ..` to generate your Makefile.
-85
View File
@@ -1,85 +0,0 @@
import icsneopy
import argparse
def main():
parser = get_parser()
args = parser.parse_args()
run_test(args)
def find_device(serial: str) -> icsneopy.Device:
devices = icsneopy.find_all_devices()
for d in devices:
if d.get_serial() == serial:
print(f"opening device {serial}")
return d
return None
def run_test(args):
# find the device
d = find_device(args.serial)
if d is None:
print(f"error: unable to find device {args.serial}")
exit(1)
# open the device
if not d.open():
print(f"error: unable to open device {args.serial}")
exit(1)
# check if TC10 is supported
if not d.supports_tc10():
print(f"error: device does not support TC10 {args.serial}")
exit(1)
# send the request on all networks
for n in args.networks:
net = getattr(icsneopy.Network.NetID, n)
if args.send_wake:
print(f"requesting TC10 wake on network {net}")
if not d.request_tc10_wake(net):
print(f"error: unable to send TC10 wake on device {args.serial}")
exit(1)
elif args.send_sleep:
print(f"requesting TC10 sleep on network {net}")
if not d.request_tc10_sleep(net):
print(f"error: unable to send TC10 sleep on device {args.serial}")
exit(1)
# close the device
print(f"closing device {args.serial}")
d.close()
def get_parser():
parser = argparse.ArgumentParser(description="TC10 wake request")
parser.add_argument(
"serial",
help="The serial number of the device",
)
parser.add_argument(
"--networks",
nargs="+",
help="List of icsneopy networks to use. Multiple networks accepted, e.g. '--networks ETHERNET_01 AE_01'",
required=True,
),
group = parser.add_mutually_exclusive_group(required=True)
group.add_argument(
"--send-wake",
help="Trigger TC10 wake on the selected networks",
action="store_true",
default=False,
)
group.add_argument(
"--send-sleep",
help="Trigger TC10 sleep on the selected networks",
action="store_true",
default=False,
)
return parser
if __name__ == "__main__":
main()
+35 -12
View File
@@ -51,9 +51,6 @@ public:
WiVINotSupported = 0x1015, WiVINotSupported = 0x1015,
RestrictedEntryFlag = 0x1016, RestrictedEntryFlag = 0x1016,
NotSupported = 0x1017, NotSupported = 0x1017,
FixedPointOverflow = 0x1018,
FixedPointPrecision = 0x1019,
SyscallError = 0x1020, // check errno/GetLastError() for details
// Device Events // Device Events
PollingMessageOverflow = 0x2000, PollingMessageOverflow = 0x2000,
@@ -114,8 +111,6 @@ public:
AppErrorParsingFailed = 0x2055, AppErrorParsingFailed = 0x2055,
GPTPNotSupported = 0x2056, GPTPNotSupported = 0x2056,
SettingNotAvaiableDevice = 0x2057, SettingNotAvaiableDevice = 0x2057,
DiskFormatNotSupported = 0x2058,
DiskFormatInvalidCount = 0x2059,
// Transport Events // Transport Events
FailedToRead = 0x3000, FailedToRead = 0x3000,
@@ -135,6 +130,41 @@ public:
SendToError = 0x3109, SendToError = 0x3109,
MDIOMessageExceedsMaxLength = 0x3110, 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 // VSA
VSABufferCorrupted = 0x5000, VSABufferCorrupted = 0x5000,
VSATimestampNotFound = VSABufferCorrupted + 1, VSATimestampNotFound = VSABufferCorrupted + 1,
@@ -157,13 +187,6 @@ public:
ServdNoDataError = ServdBindError + 9, ServdNoDataError = ServdBindError + 9,
ServdJoinMulticastError = ServdBindError + 10, ServdJoinMulticastError = ServdBindError + 10,
// DXX
DXXErrorSys = 0x6100,
DXXErrorInt = 0x6101,
DXXErrorOverflow = 0x6102,
DXXErrorIO = 0x6103,
DXXErrorArg = 0x6104,
NoErrorFound = 0xFFFFFFFD, NoErrorFound = 0xFFFFFFFD,
TooManyEvents = 0xFFFFFFFE, TooManyEvents = 0xFFFFFFFE,
Unknown = 0xFFFFFFFF Unknown = 0xFFFFFFFF
+1 -1
View File
@@ -20,7 +20,7 @@ public:
EventCallback(std::shared_ptr<EventFilter> f, fn_eventCallback cb) : callback(cb), filter(f) {} 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)) {} 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); bool ret = filter->match(*event);
if(ret) if(ret)
callback(event); callback(event);
-53
View File
@@ -1,53 +0,0 @@
#ifndef __PERIODIC_H__
#define __PERIODIC_H__
#ifdef __cplusplus
#include <condition_variable>
#include <mutex>
#include <functional>
#include <chrono>
#include <thread>
namespace icsneo {
class Periodic {
public:
using Callback = std::function<bool(void)>;
Periodic(Callback&& callback, const std::chrono::milliseconds& period) :
thread(&Periodic::loop, this, std::move(callback), period)
{}
~Periodic() {
{
std::scoped_lock lk(mutex);
stop = true;
}
cv.notify_all();
thread.join();
}
private:
void loop(Callback&& callback, const std::chrono::milliseconds& period) {
while (true) {
{
std::unique_lock lk(mutex);
cv.wait_for(lk, period, [&]{ return stop; });
if(stop) {
break;
}
}
if (!callback()) {
break;
}
}
}
bool stop = false;
std::condition_variable cv;
std::mutex mutex;
std::thread thread;
};
} // icsneo
#endif // __cplusplus
#endif // __PERIODIC_H__
+2 -3
View File
@@ -88,7 +88,6 @@ inline std::ostream& operator<<(std::ostream& os, const LiveDataValueType cmd) {
case LiveDataValueType::GPS_TIME_VALID: return os << "GPS Time Valid"; case LiveDataValueType::GPS_TIME_VALID: return os << "GPS Time Valid";
case LiveDataValueType::DAQ_ENABLE: return os << "DAQ Enable"; case LiveDataValueType::DAQ_ENABLE: return os << "DAQ Enable";
case LiveDataValueType::MANUAL_TRIGGER: return os << "Manual Trigger"; case LiveDataValueType::MANUAL_TRIGGER: return os << "Manual Trigger";
case LiveDataValueType::TIME_SINCE_MSG: return os << "Time Since Msg";
} }
return os; return os;
} }
@@ -142,7 +141,7 @@ struct LiveDataSetValueEntry
}; };
struct LiveDataSetValue : public LiveDataHeader { struct LiveDataSetValue : public LiveDataHeader {
uint32_t numSetValues; uint32_t numArgs;
LiveDataSetValueEntry values[1]; LiveDataSetValueEntry values[1];
}; };
@@ -157,7 +156,7 @@ namespace LiveDataUtil
LiveDataHandle getNewHandle(); LiveDataHandle getNewHandle();
double liveDataValueToDouble(const LiveDataValue& val); double liveDataValueToDouble(const LiveDataValue& val);
bool liveDataDoubleToValue(const double& dFloat, LiveDataValue& value); int liveDataDoubleToValue(LiveDataValue& value, const double& dFloat);
static constexpr uint32_t LiveDataVersion = 1; static constexpr uint32_t LiveDataVersion = 1;
} // namespace LiveDataUtil } // namespace LiveDataUtil
@@ -10,12 +10,11 @@ namespace icsneo {
class ExtendedResponseMessage : public Message { class ExtendedResponseMessage : public Message {
public: public:
ExtendedResponseMessage(ExtendedCommand cmd, ExtendedResponse resp = ExtendedResponse::OK) ExtendedResponseMessage(ExtendedCommand cmd, ExtendedResponse resp)
: Message(Message::Type::ExtendedResponse), command(cmd), response(resp) {} : Message(Message::Type::ExtendedResponse), command(cmd), response(resp) {}
const ExtendedCommand command; const ExtendedCommand command;
const ExtendedResponse response; const ExtendedResponse response;
std::vector<uint8_t> data;
#pragma pack(push, 2) #pragma pack(push, 2)
struct ResponseHeader { struct ResponseHeader {
@@ -15,36 +15,20 @@ namespace icsneo {
class ExtendedResponseFilter : public MessageFilter { class ExtendedResponseFilter : public MessageFilter {
public: public:
ExtendedResponseFilter(icsneo::ExtendedCommand cmd) : MessageFilter(Message::Type::ExtendedResponse), command(cmd), response(std::nullopt) {} ExtendedResponseFilter(icsneo::ExtendedResponse resp) : MessageFilter(Message::Type::ExtendedResponse), response(resp) {}
ExtendedResponseFilter(icsneo::ExtendedResponse resp) : MessageFilter(Message::Type::ExtendedResponse), command(std::nullopt), response(resp) {}
ExtendedResponseFilter(icsneo::ExtendedCommand cmd, icsneo::ExtendedResponse resp)
: MessageFilter(Message::Type::ExtendedResponse), command(cmd), response(resp) {}
bool match(const std::shared_ptr<Message>& message) const override { bool match(const std::shared_ptr<Message>& message) const override {
if(!MessageFilter::match(message)) { if(!MessageFilter::match(message)) {
return false; return false;
} }
const auto respMsg = std::static_pointer_cast<ExtendedResponseMessage>(message); const auto respMsg = std::static_pointer_cast<ExtendedResponseMessage>(message);
return respMsg && matchResponse(respMsg->command, respMsg->response); return respMsg && matchResponse(respMsg->response);
} }
private: private:
std::optional<icsneo::ExtendedCommand> command = std::nullopt; icsneo::ExtendedResponse response;
std::optional<icsneo::ExtendedResponse> response = std::nullopt; bool matchResponse(icsneo::ExtendedResponse resp) const {
return response == resp;
bool matchResponse(icsneo::ExtendedCommand cmd, icsneo::ExtendedResponse resp) const {
if(command) {
if(*command != cmd) {
return false;
}
}
if(response) {
if(*response != resp) {
return false;
}
}
return true;
} }
}; };
@@ -4,13 +4,24 @@
#ifdef __cplusplus #ifdef __cplusplus
#include "icsneo/communication/message/message.h" #include "icsneo/communication/message/message.h"
#include "icsneo/communication/tc10.h"
#include <memory> #include <memory>
namespace icsneo namespace icsneo
{ {
enum class TC10WakeStatus : uint8_t {
NoWakeReceived,
WakeReceived,
};
enum class TC10SleepStatus : uint8_t {
NoSleepReceived,
SleepReceived,
SleepFailed,
SleepAborted,
};
class TC10StatusMessage : public Message { class TC10StatusMessage : public Message {
public: public:
static std::shared_ptr<TC10StatusMessage> DecodeToMessage(const std::vector<uint8_t>& bytestream); static std::shared_ptr<TC10StatusMessage> DecodeToMessage(const std::vector<uint8_t>& bytestream);
-4
View File
@@ -143,7 +143,6 @@ public:
I2C_03 = 518, // previously I2C3 I2C_03 = 518, // previously I2C3
I2C_04 = 519, // previously I2C4 I2C_04 = 519, // previously I2C4
ETHERNET_02 = 520, // previously Ethernet2 ETHERNET_02 = 520, // previously Ethernet2
ETHERNET_TX_WRAP = 521,
A2B_01 = 522, // previously A2B1 A2B_01 = 522, // previously A2B1
A2B_02 = 523, // previously A2B2 A2B_02 = 523, // previously A2B2
ETHERNET_03 = 524, // previously Ethernet3 ETHERNET_03 = 524, // previously Ethernet3
@@ -592,7 +591,6 @@ public:
case NetID::ETHERNET_01: case NetID::ETHERNET_01:
case NetID::ETHERNET_DAQ: case NetID::ETHERNET_DAQ:
case NetID::ETHERNET_02: case NetID::ETHERNET_02:
case NetID::ETHERNET_TX_WRAP:
case NetID::ETHERNET_03: case NetID::ETHERNET_03:
case NetID::AE_01: case NetID::AE_01:
case NetID::AE_02: case NetID::AE_02:
@@ -889,8 +887,6 @@ public:
return "I2C 04"; return "I2C 04";
case NetID::ETHERNET_02: case NetID::ETHERNET_02:
return "Ethernet 02"; return "Ethernet 02";
case NetID::ETHERNET_TX_WRAP:
return "Ethernet TX Wrap";
case NetID::A2B_01: case NetID::A2B_01:
return "A2B 01"; return "A2B 01";
case NetID::A2B_02: case NetID::A2B_02:
@@ -7,9 +7,6 @@
#include "icsneo/api/eventmanager.h" #include "icsneo/api/eventmanager.h"
#include <cstdint> #include <cstdint>
#include <memory> #include <memory>
#include <iostream>
#include <iomanip>
#include <sstream>
namespace icsneo { namespace icsneo {
@@ -21,59 +18,30 @@ struct HardwareEthernetPacket {
static std::shared_ptr<EthernetMessage> DecodeToMessage(const std::vector<uint8_t>& bytestream, const device_eventhandler_t& report); static std::shared_ptr<EthernetMessage> DecodeToMessage(const std::vector<uint8_t>& bytestream, const device_eventhandler_t& report);
static bool EncodeFromMessage(const EthernetMessage& message, std::vector<uint8_t>& bytestream, const device_eventhandler_t& report); static bool EncodeFromMessage(const EthernetMessage& message, std::vector<uint8_t>& bytestream, const device_eventhandler_t& report);
// Word 0 - Header flags (offset 0)
struct { struct {
icscm_bitfield FCS_AVAIL : 1; icscm_bitfield FCS_AVAIL : 1;
icscm_bitfield RUNT_FRAME : 1; icscm_bitfield RUNT_FRAME : 1;
icscm_bitfield ENABLE_PADDING : 1; icscm_bitfield DISABLE_PADDING : 1;
icscm_bitfield PREEMPTION_ENABLED : 1; icscm_bitfield PREEMPTION_ENABLED : 1;
icscm_bitfield MPACKET_TYPE : 4; icscm_bitfield MPACKET_TYPE : 4;
icscm_bitfield MPACKET_FRAG_CNT : 2; icscm_bitfield MPACKET_FRAG_CNT : 2;
icscm_bitfield UPDATE_CHECKSUMS : 1; icscm_bitfield : 6;
icscm_bitfield FCS_OVERRIDE : 1;
icscm_bitfield CRC_ERROR : 1;
icscm_bitfield FCS_VERIFIED : 1;
icscm_bitfield DISABLE_TX_RECEIPT : 1;
icscm_bitfield T1S_ETHERNET : 1;
} header; } header;
// Word 1 - Extended ID flags
struct { struct {
icscm_bitfield txlen : 12; icscm_bitfield txlen : 12;
icscm_bitfield TXMSG : 1; icscm_bitfield TXMSG : 1;
icscm_bitfield TXAborted : 1; icscm_bitfield : 3;
icscm_bitfield T1S_SYMBOL : 1;
icscm_bitfield T1S_BURST : 1;
} eid; } eid;
icscm_bitfield reserved;
// Word 2 - T1S Status flags unsigned char data[8];
struct {
icscm_bitfield TXCollision : 1;
icscm_bitfield T1SWake : 1;
icscm_bitfield : 14;
} t1s_status;
// Word 3 - T1S Node Information
struct {
icscm_bitfield T1S_BURST_COUNT : 8;
icscm_bitfield T1S_NODE_ID : 8;
uint8_t RESERVED[6];
} t1s_node;
// Words 4-7 - Reserved/Padding
uint16_t stats; uint16_t stats;
// Words 8-11 - Timestamp (offset 14-22)
struct { struct {
uint64_t TS : 60; uint64_t TS : 60;
uint64_t : 3; uint64_t : 3; // Reserved for future status bits
uint64_t IsExtended : 1; uint64_t IsExtended : 1;
} timestamp; } timestamp;
uint16_t NetworkID; uint16_t NetworkID;
uint16_t Length; uint16_t Length;
}; };
#pragma pack(pop) #pragma pack(pop)
@@ -82,4 +50,4 @@ struct HardwareEthernetPacket {
#endif // __cplusplus #endif // __cplusplus
#endif // __ETHERNETPACKET_H__ #endif
-47
View File
@@ -1,47 +0,0 @@
#ifndef __ICSNEO_TC10_H_
#define __ICSNEO_TC10_H_
#ifdef __cplusplus
#include <cstdint>
namespace icsneo {
enum class TC10WakeStatus : uint8_t {
NoWakeReceived,
WakeReceived,
};
enum class TC10SleepStatus : uint8_t {
NoSleepReceived,
SleepReceived,
SleepFailed,
SleepAborted,
};
}
#endif // __cplusplus
#ifdef __ICSNEOC_H_
typedef enum _neotc10wakestatus_t {
ICSNEO_TC10_NO_WAKE_RECEIVED = 0,
ICSNEO_TC10_WAKE_RECEIVED = 1,
} neotc10wakestatus_t;
typedef enum _neotc10sleepstatus_t {
ICSNEO_TC10_NO_SLEEP_RECEIVED = 0,
ICSNEO_TC10_SLEEP_RECEIVED = 1,
ICSNEO_TC10_SLEEP_FAILED = 2,
ICSNEO_TC10_SLEEP_ABORTED = 3,
} neotc10sleepstatus_t;
typedef struct _neotc10status_t {
neotc10wakestatus_t wakeStatus;
neotc10sleepstatus_t sleepStatus;
} neotc10status_t;
#endif
#endif // __ICSNEO_TC10_H_
+2 -23
View File
@@ -16,7 +16,6 @@
#include <chrono> #include <chrono>
#include "icsneo/api/eventmanager.h" #include "icsneo/api/eventmanager.h"
#include "icsneo/api/lifetime.h" #include "icsneo/api/lifetime.h"
#include "icsneo/api/periodic.h"
#include "icsneo/device/neodevice.h" #include "icsneo/device/neodevice.h"
#include "icsneo/device/idevicesettings.h" #include "icsneo/device/idevicesettings.h"
#include "icsneo/device/nullsettings.h" #include "icsneo/device/nullsettings.h"
@@ -27,7 +26,6 @@
#include "icsneo/disk/diskreaddriver.h" #include "icsneo/disk/diskreaddriver.h"
#include "icsneo/disk/diskwritedriver.h" #include "icsneo/disk/diskwritedriver.h"
#include "icsneo/disk/nulldiskdriver.h" #include "icsneo/disk/nulldiskdriver.h"
#include "icsneo/disk/diskdetails.h"
#include "icsneo/communication/communication.h" #include "icsneo/communication/communication.h"
#include "icsneo/communication/packetizer.h" #include "icsneo/communication/packetizer.h"
#include "icsneo/communication/encoder.h" #include "icsneo/communication/encoder.h"
@@ -207,7 +205,7 @@ public:
// Message polling related functions // Message polling related functions
bool enableMessagePolling(std::optional<MessageFilter> filter = std::nullopt); bool enableMessagePolling();
bool disableMessagePolling(); bool disableMessagePolling();
bool isMessagePollingEnabled() { return messagePollingCallbackID != 0; }; bool isMessagePollingEnabled() { return messagePollingCallbackID != 0; };
std::pair<std::vector<std::shared_ptr<Message>>, bool> getMessages(); std::pair<std::vector<std::shared_ptr<Message>>, bool> getMessages();
@@ -640,22 +638,6 @@ public:
bool clearAllLiveData(); bool clearAllLiveData();
bool setValueLiveData(std::shared_ptr<LiveDataSetValueMessage> message); bool setValueLiveData(std::shared_ptr<LiveDataSetValueMessage> message);
enum class DiskFormatDirective : uint8_t {
Continue,
Stop
};
using DiskFormatProgress = std::function<DiskFormatDirective(uint64_t sectorsFormatted, uint64_t sectorsTotal)>;
bool formatDisk(
const DiskDetails& config,
const DiskFormatProgress& handler = {},
std::chrono::milliseconds interval = std::chrono::milliseconds(500) /** Send updates at an interval of 500ms */
);
bool forceDiskConfigUpdate(const DiskDetails& config); // Forces a disk layout and enables change without formatting
std::shared_ptr<DiskDetails> getDiskDetails(std::chrono::milliseconds timeout = std::chrono::milliseconds(100));
virtual size_t getDiskCount() const { return 0; }
bool supportsDiskFormatting() const { return getDiskCount() != 0; }
// VSA Read functions // VSA Read functions
/** /**
@@ -1038,10 +1020,7 @@ private:
*/ */
std::optional<uint64_t> getVSADiskSize(); std::optional<uint64_t> getVSADiskSize();
bool enableNetworkCommunication(bool enable, uint32_t timeout = 0); bool enableNetworkCommunication(bool enable);
// Keeponline (keepalive for online)
std::unique_ptr<Periodic> keeponline;
}; };
} }
-5
View File
@@ -13,12 +13,7 @@ struct DeviceAppVersion {
uint8_t major = 0; uint8_t major = 0;
uint8_t minor = 0; uint8_t minor = 0;
DeviceAppVersion() = default;
DeviceAppVersion(const uint8_t major, const uint8_t minor)
: major(major), minor(minor) {}
bool operator!=(const DeviceAppVersion& rhs) const { return major != rhs.major || minor != rhs.minor; } bool operator!=(const DeviceAppVersion& rhs) const { return major != rhs.major || minor != rhs.minor; }
bool operator==(const DeviceAppVersion& rhs) const { return major == rhs.major && minor == rhs.minor; }
}; };
} // namespace icsneo } // namespace icsneo
+1 -33
View File
@@ -668,37 +668,6 @@ typedef struct
} Fire3LinuxSettings; } Fire3LinuxSettings;
#define FIRE3LINUXSETTINGS_SIZE 8 #define FIRE3LINUXSETTINGS_SIZE 8
static_assert(sizeof(Fire3LinuxSettings) == FIRE3LINUXSETTINGS_SIZE, "Fire3LinuxSettings is the wrong size!"); static_assert(sizeof(Fire3LinuxSettings) == FIRE3LINUXSETTINGS_SIZE, "Fire3LinuxSettings is the wrong size!");
/* Define number of CMP streams per device*/
#define CMP_STREAMS_FIRE3 (10)
#define CMP_STREAMS_FIRE3FR (10)
#define CMP_STREAMS_RED2 (10)
#define CMP_STREAMS_A2B (3)
#define CMP_STREAMS_GIGASTAR (10)
/* CMP Network Enables */
typedef struct
{
uint8_t bStreamEnabled : 1;
uint8_t EthModule : 2;
uint8_t bControlEnabled : 1;
uint8_t spare : 4;
uint8_t streamId;
uint8_t dstMac[6];
uint64_t network_enables_1;
uint64_t network_enables_2;
} CMP_NETWORK_DATA;
/* Global CMP Data */
typedef struct
{
uint8_t cmp_enabled : 1;
uint8_t sparebits : 7;
uint8_t spare;
uint16_t cmp_device_id;
} CMP_GLOBAL_DATA;
#pragma pack(pop) #pragma pack(pop)
#ifdef __cplusplus #ifdef __cplusplus
@@ -924,8 +893,7 @@ public:
template<typename T> T getStructure() const { return *getStructurePointer<T>(); } template<typename T> T getStructure() const { return *getStructurePointer<T>(); }
template<typename T> bool applyStructure(const T& newStructure); template<typename T> bool applyStructure(const T& newStructure);
size_t getSize() const { return structSize; } const size_t& getSize() const { return structSize; }
size_t getSerialSize() const { return settings.size(); }
// if settings are disabled for this device. always false unless constructed null // if settings are disabled for this device. always false unless constructed null
bool disabled = false; bool disabled = false;
@@ -71,10 +71,6 @@ protected:
bool supportsGPTP() const override { return true; } bool supportsGPTP() const override { return true; }
size_t getDiskCount() const override {
return 2;
}
}; };
} }
@@ -11,7 +11,7 @@ namespace icsneo {
class NeoVIFIRE : public Device { class NeoVIFIRE : public Device {
public: 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); ICSNEO_FINDABLE_DEVICE_BY_PID(NeoVIFIRE, DeviceType::FIRE, 0x0701);
static const std::vector<Network>& GetSupportedNetworks() { static const std::vector<Network>& GetSupportedNetworks() {
@@ -12,7 +12,7 @@ namespace icsneo {
class NeoVIFIRE2 : public Device { class NeoVIFIRE2 : public Device {
public: public:
// Serial numbers start with CY // 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 // Ethernet MAC allocation is 0x04, standard driver is Raw
ICSNEO_FINDABLE_DEVICE(NeoVIFIRE2, DeviceType::FIRE2, "CY"); ICSNEO_FINDABLE_DEVICE(NeoVIFIRE2, DeviceType::FIRE2, "CY");
@@ -141,10 +141,6 @@ protected:
bool supportsEraseMemory() const override { bool supportsEraseMemory() const override {
return true; return true;
} }
size_t getDiskCount() const override {
return 1;
}
}; };
} }
@@ -91,10 +91,6 @@ protected:
return true; return true;
} }
size_t getDiskCount() const override {
return 2;
}
}; };
} }
@@ -75,10 +75,6 @@ protected:
bool supportsEraseMemory() const override { bool supportsEraseMemory() const override {
return true; return true;
} }
size_t getDiskCount() const override {
return 2;
}
}; };
} }
@@ -79,15 +79,7 @@ typedef struct {
uint16_t digitalIoThresholdEnable; uint16_t digitalIoThresholdEnable;
uint16_t misc_io_initial_ddr; uint16_t misc_io_initial_ddr;
uint16_t misc_io_initial_latch; uint16_t misc_io_initial_latch;
ETHERNET_SETTINGS2 ethernet2_1; ETHERNET_SETTINGS2 ethernet2;
ETHERNET_SETTINGS ethernet_2;
ETHERNET_SETTINGS2 ethernet2_2;
Fire3LinuxSettings os_settings;
RAD_GPTP_SETTINGS gPTP;
uint16_t iso_tester_pullup_enable;
CMP_GLOBAL_DATA cmp_global_data;
CMP_NETWORK_DATA cmp_stream_data[CMP_STREAMS_RED2];
uint32_t networkTimeSync;
} neovired2_settings_t; } neovired2_settings_t;
typedef struct { typedef struct {
@@ -12,7 +12,7 @@ namespace icsneo {
class NeoVIION : public Plasion { class NeoVIION : public Plasion {
public: 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); ICSNEO_FINDABLE_DEVICE_BY_PID(NeoVIION, DeviceType::ION, 0x0901);
private: private:
@@ -10,7 +10,7 @@ namespace icsneo {
class NeoVIPLASMA : public Plasion { class NeoVIPLASMA : public Plasion {
public: 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); ICSNEO_FINDABLE_DEVICE_BY_PID(NeoVIPLASMA, DeviceType::PLASMA, 0x0801);
private: private:
+1 -1
View File
@@ -15,7 +15,7 @@ namespace icsneo {
class RADA2B : public Device { class RADA2B : public Device {
public: public:
// Serial numbers start with AB // 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 // Ethernet MAC allocation is 0x18, standard driver is Raw
ICSNEO_FINDABLE_DEVICE(RADA2B, DeviceType::RAD_A2B, "AB"); ICSNEO_FINDABLE_DEVICE(RADA2B, DeviceType::RAD_A2B, "AB");
@@ -12,7 +12,7 @@ class RADComet : public RADCometBase {
public: public:
// Serial numbers start with RC // 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 // Ethernet MAC allocation is 0x1D, standard driver is Raw
ICSNEO_FINDABLE_DEVICE_BY_SERIAL_RANGE(RADComet, DeviceType::RADComet, "RC0000", "RC0299"); ICSNEO_FINDABLE_DEVICE_BY_SERIAL_RANGE(RADComet, DeviceType::RADComet, "RC0000", "RC0299");
@@ -12,7 +12,7 @@ class RADComet2 : public RADCometBase {
public: public:
// Serial numbers start with RC, Comet2 starts at RC0300 // 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 // Ethernet MAC allocation is 0x1D, standard driver is Raw
ICSNEO_FINDABLE_DEVICE_BY_SERIAL_RANGE(RADComet2, DeviceType::RADComet, "RC0300", "RCZZZZ"); ICSNEO_FINDABLE_DEVICE_BY_SERIAL_RANGE(RADComet2, DeviceType::RADComet, "RC0300", "RCZZZZ");
@@ -12,7 +12,7 @@ class RADComet3 : public Device {
public: public:
// Serial numbers start with C3 // 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 // Ethernet MAC allocation is 0x20, standard driver is Raw
ICSNEO_FINDABLE_DEVICE(RADComet3, DeviceType::RADComet3, "C3"); ICSNEO_FINDABLE_DEVICE(RADComet3, DeviceType::RADComet3, "C3");
@@ -54,10 +54,6 @@ protected:
bool supportsEraseMemory() const override { bool supportsEraseMemory() const override {
return true; return true;
} }
size_t getDiskCount() const override {
return 1;
}
}; };
} }
@@ -107,10 +107,6 @@ protected:
std::optional<MemoryAddress> getCoreminiStartAddressSD() const override { std::optional<MemoryAddress> getCoreminiStartAddressSD() const override {
return 0; return 0;
} }
size_t getDiskCount() const override {
return 1;
}
}; };
} }
@@ -14,7 +14,7 @@ namespace icsneo {
class RADGigastar : public Device { class RADGigastar : public Device {
public: public:
// Serial numbers start with GS // 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 // Ethernet MAC allocation is 0x0F, standard driver is Raw
ICSNEO_FINDABLE_DEVICE(RADGigastar, DeviceType::RADGigastar, "GS"); ICSNEO_FINDABLE_DEVICE(RADGigastar, DeviceType::RADGigastar, "GS");
@@ -120,10 +120,6 @@ protected:
std::optional<MemoryAddress> getCoreminiStartAddressSD() const override { std::optional<MemoryAddress> getCoreminiStartAddressSD() const override {
return 0; return 0;
} }
size_t getDiskCount() const override {
return 1;
}
}; };
} }
@@ -16,7 +16,7 @@ namespace icsneo
{ {
public: public:
// Serial numbers start with GT // 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 // Ethernet MAC allocation is 0x22, standard driver is Raw
ICSNEO_FINDABLE_DEVICE(RADGigastar2, DeviceType::RADGigastar2, "GT"); ICSNEO_FINDABLE_DEVICE(RADGigastar2, DeviceType::RADGigastar2, "GT");
@@ -137,11 +137,6 @@ namespace icsneo
{ {
return 0; return 0;
} }
size_t getDiskCount() const override
{
return 1;
}
}; };
} }
+1 -1
View File
@@ -14,7 +14,7 @@ namespace icsneo {
class RADMars : public Device { class RADMars : public Device {
public: public:
// Serial numbers start with GL (previously, RAD-Gigalog) // 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 // Ethernet MAC allocation is 0x0A, standard driver is Raw
ICSNEO_FINDABLE_DEVICE(RADMars, DeviceType::RADMars, "GL"); ICSNEO_FINDABLE_DEVICE(RADMars, DeviceType::RADMars, "GL");
@@ -11,7 +11,7 @@ namespace icsneo {
class RADMoon2 : public RADMoon2Base { class RADMoon2 : public RADMoon2Base {
public: public:
// Serial numbers start with RM // 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"); ICSNEO_FINDABLE_DEVICE(RADMoon2, DeviceType::RADMoon2, "RM");
uint8_t getPhyAddrOrPort() const override { return 6; }; uint8_t getPhyAddrOrPort() const override { return 6; };
@@ -12,7 +12,7 @@ class RADMoonT1S : public Device {
public: public:
// Serial numbers start with MS // 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 // Ethernet MAC allocation is 0x21, standard driver is Raw
ICSNEO_FINDABLE_DEVICE(RADMoonT1S, DeviceType::RADMoonT1S, "MS"); ICSNEO_FINDABLE_DEVICE(RADMoonT1S, DeviceType::RADMoonT1S, "MS");
@@ -12,7 +12,7 @@ namespace icsneo {
class RADStar2 : public Device { class RADStar2 : public Device {
public: public:
// Serial numbers start with RS // 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 // Ethernet MAC allocation is 0x05, standard driver is Raw
ICSNEO_FINDABLE_DEVICE(RADStar2, DeviceType::RADStar2, "RS"); ICSNEO_FINDABLE_DEVICE(RADStar2, DeviceType::RADStar2, "RS");
@@ -12,7 +12,7 @@ namespace icsneo {
class RADSupermoon : public Device { class RADSupermoon : public Device {
public: public:
// Serial numbers start with SM // 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"); ICSNEO_FINDABLE_DEVICE(RADSupermoon, DeviceType::RADSupermoon, "SM");
enum class SKU { enum class SKU {
@@ -11,7 +11,7 @@ namespace icsneo {
class ValueCAN3 : public Device { class ValueCAN3 : public Device {
public: 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); ICSNEO_FINDABLE_DEVICE_BY_PID(ValueCAN3, DeviceType::VCAN3, 0x0601);
static const std::vector<Network>& GetSupportedNetworks() { static const std::vector<Network>& GetSupportedNetworks() {
-44
View File
@@ -1,44 +0,0 @@
#ifndef __DISKDETAILS_H__
#define __DISKDETAILS_H__
#ifdef __cplusplus
#include <cstdint>
#include <vector>
#include <icsneo/api/eventmanager.h>
namespace icsneo {
enum class DiskLayout : uint8_t {
Spanned = 0,
RAID0 = 1
};
struct DiskInfo {
bool present; // Disk is connected
bool initialized; // Disk is initialized
bool formatted; // Disk is formatted
uint64_t sectors;
uint32_t bytesPerSector;
uint64_t size() const {
return sectors * bytesPerSector;
}
};
struct DiskDetails {
DiskLayout layout;
bool fullFormat;
std::vector<DiskInfo> disks;
static std::vector<uint8_t> Encode(const DiskDetails& config);
static std::shared_ptr<DiskDetails> Decode(const std::vector<uint8_t>& bytes, size_t diskCount, device_eventhandler_t report);
};
} // namespace icsneo
#endif // __cplusplus
#endif
-41
View File
@@ -9,7 +9,6 @@
#include "icsneo/platform/dynamiclib.h" // Dynamic library loading and exporting #include "icsneo/platform/dynamiclib.h" // Dynamic library loading and exporting
#include "icsneo/communication/network.h" // Network type and netID defines #include "icsneo/communication/network.h" // Network type and netID defines
#include "icsneo/communication/io.h" // IO enum defines #include "icsneo/communication/io.h" // IO enum defines
#include "icsneo/communication/tc10.h"
#include "icsneo/api/version.h" // For version info #include "icsneo/api/version.h" // For version info
#include "icsneo/api/event.h" // For event and error info #include "icsneo/api/event.h" // For event and error info
@@ -846,34 +845,6 @@ extern bool DLLExport icsneo_setRTC(const neodevice_t* device, uint64_t input);
*/ */
extern bool DLLExport icsneo_isOnlineSupported(const neodevice_t* device); extern bool DLLExport icsneo_isOnlineSupported(const neodevice_t* device);
/**
* \brief Request TC10 wake
* \param[in] device A pointer to the neodevice_t structure specifying the device to operate on.
* \param[in] netid The interface to request the TC10 wake on.
* \returns True if the device successfully sent the TC10 wake request.
*/
extern bool DLLExport icsneo_requestTC10Wake(const neodevice_t* device, neonetid_t netid);
/**
* \brief Request TC10 sleep
* \param[in] device A pointer to the neodevice_t structure specifying the device to operate on.
* \param[in] netid The interface to request the TC10 sleep on.
* \returns True if the device successfully sent the TC10 sleep request.
*/
extern bool DLLExport icsneo_requestTC10Sleep(const neodevice_t* device, neonetid_t netid);
/**
* \brief Query TC10 status
* \param[in] device A pointer to the neodevice_t structure specifying the device to operate on.
* \param[in] netid The interface to request the TC10 status for.
* \param[out] status The TC10 status for the given interface
* \returns True if the device successfully retreieved the TC10 status.
*/
extern bool DLLExport icsneo_getTC10Status(const neodevice_t* device, neonetid_t netid, neotc10status_t* status);
#ifdef __cplusplus #ifdef __cplusplus
} // extern "C" } // extern "C"
#endif #endif
@@ -1057,15 +1028,6 @@ fn_icsneo_setRTC icsneo_setRTC;
typedef bool(*fn_icsneo_isOnlineSupported)(const neodevice_t* device); typedef bool(*fn_icsneo_isOnlineSupported)(const neodevice_t* device);
fn_icsneo_isOnlineSupported icsneo_isOnlineSupported; fn_icsneo_isOnlineSupported icsneo_isOnlineSupported;
typedef bool(*fn_icsneo_requestTC10Wake)(const neodevice_t* device, neonetid_t netid);
fn_icsneo_requestTC10Wake icsneo_requestTC10Wake;
typedef bool(*fn_icsneo_requestTC10Sleep)(const neodevice_t* device, neonetid_t netid);
fn_icsneo_requestTC10Sleep icsneo_requestTC10Sleep;
typedef bool(*fn_icsneo_getTC10Status)(const neodevice_t* device, neonetid_t netid, neotc10status_t* status);
fn_icsneo_getTC10Status icsneo_getTC10Status;
#define ICSNEO_IMPORT(func) func = (fn_##func)icsneo_dynamicLibraryGetFunction(icsneo_libraryHandle, #func) #define ICSNEO_IMPORT(func) func = (fn_##func)icsneo_dynamicLibraryGetFunction(icsneo_libraryHandle, #func)
#define ICSNEO_IMPORTASSERT(func) if((ICSNEO_IMPORT(func)) == NULL) return 3 #define ICSNEO_IMPORTASSERT(func) if((ICSNEO_IMPORT(func)) == NULL) return 3
void* icsneo_libraryHandle = NULL; void* icsneo_libraryHandle = NULL;
@@ -1139,9 +1101,6 @@ int icsneo_init() {
ICSNEO_IMPORTASSERT(icsneo_getRTC); ICSNEO_IMPORTASSERT(icsneo_getRTC);
ICSNEO_IMPORTASSERT(icsneo_setRTC); ICSNEO_IMPORTASSERT(icsneo_setRTC);
ICSNEO_IMPORTASSERT(icsneo_isOnlineSupported); ICSNEO_IMPORTASSERT(icsneo_isOnlineSupported);
ICSNEO_IMPORTASSERT(icsneo_requestTC10Wake);
ICSNEO_IMPORTASSERT(icsneo_requestTC10Sleep);
ICSNEO_IMPORTASSERT(icsneo_getTC10Status);
icsneo_initialized = true; icsneo_initialized = true;
return 0; return 0;
-39
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_
+35
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
+14
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
+74
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
-2
View File
@@ -4,8 +4,6 @@
#ifdef __cplusplus #ifdef __cplusplus
#ifdef _WIN32 #ifdef _WIN32
#define WIN32_LEAN_AND_MEAN
#define NOMINMAX
#include <windows.h> #include <windows.h>
#include <winsock2.h> #include <winsock2.h>
#include <ws2tcpip.h> #include <ws2tcpip.h>
+4 -24
View File
@@ -3,34 +3,14 @@
#ifdef __cplusplus #ifdef __cplusplus
#include "icsneo/communication/driver.h" #include "icsneo/platform/windows/vcp.h"
#include "icsneo/device/founddevice.h"
#define WIN32_LEAN_AND_MEAN
#define NOMINMAX
#include <windows.h>
#include <string>
namespace icsneo { namespace icsneo {
class CDCACM : public Driver { class CDCACM : public VCP {
public: public:
CDCACM(const device_eventhandler_t& err, const std::wstring& path); CDCACM(const device_eventhandler_t& err, neodevice_t& forDevice) : VCP(err, forDevice) {}
static void Find(std::vector<FoundDevice>& found); static void Find(std::vector<FoundDevice>& found) { return VCP::Find(found, { L"usbser" }); }
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 = {};
}; };
} }
@@ -1,8 +1,6 @@
#ifndef __DYNAMICLIB_WINDOWS_H_ #ifndef __DYNAMICLIB_WINDOWS_H_
#define __DYNAMICLIB_WINDOWS_H_ #define __DYNAMICLIB_WINDOWS_H_
#define WIN32_LEAN_AND_MEAN
#define NOMINMAX
#include <windows.h> #include <windows.h>
#ifndef ICSNEOC_BUILD_STATIC #ifndef ICSNEOC_BUILD_STATIC
+20
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
@@ -3,8 +3,6 @@
#ifdef __cplusplus #ifdef __cplusplus
#define WIN32_LEAN_AND_MEAN
#define NOMINMAX
#include <windows.h> #include <windows.h>
#include <pcap.h> #include <pcap.h>
#include <memory> #include <memory>
+49
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
-194
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
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;
}
}
}
+242
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;
}
}
}
+7 -20
View File
@@ -1,9 +1,5 @@
#include "icsneo/platform/servd.h" #include "icsneo/platform/servd.h"
#include <string_view>
#include <cstdlib>
using namespace icsneo; using namespace icsneo;
#define SERVD_VERSION 1 #define SERVD_VERSION 1
@@ -12,25 +8,17 @@ static const Address SERVD_ADDRESS = Address("127.0.0.1", 26741);
static const std::string SERVD_VERSION_STR = std::to_string(SERVD_VERSION); static const std::string SERVD_VERSION_STR = std::to_string(SERVD_VERSION);
bool Servd::Enabled() { bool Servd::Enabled() {
#ifdef _MSC_VER
#pragma warning(push)
#pragma warning(disable : 4996)
#endif
char* enabled = std::getenv("LIBICSNEO_USE_SERVD"); char* enabled = std::getenv("LIBICSNEO_USE_SERVD");
#ifdef _MSC_VER
#pragma warning(pop)
#endif
return enabled ? enabled[0] == '1' : false; return enabled ? enabled[0] == '1' : false;
} }
std::vector<std::string> split(const std::string_view& str, char delim = ' ') { std::vector<std::string_view> split(const std::string_view& str, char delim = ' ')
if(str.empty()) {
return {}; std::vector<std::string_view> ret;
std::vector<std::string> ret;
size_t tail = 0; size_t tail = 0;
size_t head = 0; size_t head = 0;
while(head < str.size()) { while (head < str.size()) {
if(str[head] == delim) { if (str[head] == delim) {
ret.emplace_back(&str[tail], head - tail); ret.emplace_back(&str[tail], head - tail);
tail = head + 1; tail = head + 1;
} }
@@ -126,8 +114,8 @@ bool Servd::open() {
return false; return false;
} }
aliveThread = std::thread(&Servd::alive, this); aliveThread = std::thread(&Servd::alive, this);
readThread = std::thread(&Servd::read, this, Address{tokens[2].c_str(), (uint16_t)std::stol(tokens[3].c_str())}); readThread = std::thread(&Servd::read, this, Address{tokens[2].data(), (uint16_t)std::stol(tokens[3].data())});
writeThread = std::thread(&Servd::write, this, Address{tokens[0].c_str(), (uint16_t)std::stol(tokens[1].c_str())}); writeThread = std::thread(&Servd::write, this, Address{tokens[0].data(), (uint16_t)std::stol(tokens[1].data())});
opened = true; opened = true;
return true; return true;
} }
@@ -152,7 +140,6 @@ bool Servd::close() {
messageSocket.sendto(request.data(), request.size(), SERVD_ADDRESS); messageSocket.sendto(request.data(), request.size(), SERVD_ADDRESS);
} }
opened = false; opened = false;
setIsClosing(false);
return true; return true;
} }
-233
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));
}
}
-2
View File
@@ -1,5 +1,3 @@
#define WIN32_LEAN_AND_MEAN
#define NOMINMAX
#include <windows.h> #include <windows.h>
#include <winsock2.h> #include <winsock2.h>
-2
View File
@@ -1,8 +1,6 @@
#include "icsneo/platform/windows/registry.h" #include "icsneo/platform/windows/registry.h"
#include "icsneo/platform/windows/strings.h" #include "icsneo/platform/windows/strings.h"
#define WIN32_LEAN_AND_MEAN
#define NOMINMAX
#include <windows.h> #include <windows.h>
#include <codecvt> #include <codecvt>
#include <vector> #include <vector>
-3
View File
@@ -1,7 +1,4 @@
#include <string> #include <string>
#define WIN32_LEAN_AND_MEAN
#define NOMINMAX
#include <Windows.h> #include <Windows.h>
#include <icsneo/platform/windows/strings.h> #include <icsneo/platform/windows/strings.h>
+471
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;
}
}
}
}
}
-62
View File
@@ -1,62 +0,0 @@
#include "icsneo/api/periodic.h"
#include "gtest/gtest.h"
#include <condition_variable>
using namespace icsneo;
// no wait, make sure stop works
TEST(PeriodicTest, StartStop)
{
const auto start = std::chrono::steady_clock::now();
Periodic p([] { return true; }, std::chrono::milliseconds(1000));
const auto delta = std::chrono::duration_cast<std::chrono::milliseconds>(std::chrono::steady_clock::now() - start);
EXPECT_LT(delta.count(), 100); // hopefully enough
}
// time single cycle
TEST(PeriodicTest, OneCycle)
{
std::condition_variable cv;
std::mutex mutex;
uint8_t cycles = 0;
const auto start = std::chrono::steady_clock::now();
{
Periodic p([&] {
{
std::scoped_lock lk(mutex);
++cycles;
}
cv.notify_one();
return true;
}, std::chrono::seconds(1));
std::unique_lock<std::mutex> lk(mutex);
cv.wait_for(lk, std::chrono::seconds(2), [&]{ return cycles > 0; });
}
const auto delta = std::chrono::duration_cast<std::chrono::seconds>(std::chrono::steady_clock::now() - start);
EXPECT_EQ(delta.count(), 1);
EXPECT_EQ(cycles, 1);
}
TEST(PeriodicTest, TenCycles)
{
std::condition_variable cv;
std::mutex mutex;
uint8_t cycles = 0;
const auto start = std::chrono::steady_clock::now();
{
Periodic p([&] {
{
std::scoped_lock lk(mutex);
++cycles;
}
cv.notify_one();
return true;
}, std::chrono::milliseconds(100));
std::unique_lock<std::mutex> lk(mutex);
cv.wait_for(lk, std::chrono::seconds(2), [&]{ return cycles >= 10; });
}
const auto delta = std::chrono::duration_cast<std::chrono::seconds>(std::chrono::steady_clock::now() - start);
EXPECT_EQ(delta.count(), 1);
EXPECT_EQ(cycles, 10);
}
+4
View File
@@ -0,0 +1,4 @@
# Run manually to reformat a file:
# clang-format -i --style=file <file>
Language: Cpp
BasedOnStyle: Google
+84
View File
@@ -0,0 +1,84 @@
# Ignore CI build directory
build/
xcuserdata
cmake-build-debug/
.idea/
bazel-bin
bazel-genfiles
bazel-googletest
bazel-out
bazel-testlogs
# python
*.pyc
# Visual Studio files
.vs
*.sdf
*.opensdf
*.VC.opendb
*.suo
*.user
_ReSharper.Caches/
Win32-Debug/
Win32-Release/
x64-Debug/
x64-Release/
# Ignore autoconf / automake files
Makefile.in
aclocal.m4
configure
build-aux/
autom4te.cache/
googletest/m4/libtool.m4
googletest/m4/ltoptions.m4
googletest/m4/ltsugar.m4
googletest/m4/ltversion.m4
googletest/m4/lt~obsolete.m4
googlemock/m4
# Ignore generated directories.
googlemock/fused-src/
googletest/fused-src/
# macOS files
.DS_Store
googletest/.DS_Store
googletest/xcode/.DS_Store
# Ignore cmake generated directories and files.
CMakeFiles
CTestTestfile.cmake
Makefile
cmake_install.cmake
googlemock/CMakeFiles
googlemock/CTestTestfile.cmake
googlemock/Makefile
googlemock/cmake_install.cmake
googlemock/gtest
/bin
/googlemock/gmock.dir
/googlemock/gmock_main.dir
/googlemock/RUN_TESTS.vcxproj.filters
/googlemock/RUN_TESTS.vcxproj
/googlemock/INSTALL.vcxproj.filters
/googlemock/INSTALL.vcxproj
/googlemock/gmock_main.vcxproj.filters
/googlemock/gmock_main.vcxproj
/googlemock/gmock.vcxproj.filters
/googlemock/gmock.vcxproj
/googlemock/gmock.sln
/googlemock/ALL_BUILD.vcxproj.filters
/googlemock/ALL_BUILD.vcxproj
/lib
/Win32
/ZERO_CHECK.vcxproj.filters
/ZERO_CHECK.vcxproj
/RUN_TESTS.vcxproj.filters
/RUN_TESTS.vcxproj
/INSTALL.vcxproj.filters
/INSTALL.vcxproj
/googletest-distribution.sln
/CMakeCache.txt
/ALL_BUILD.vcxproj.filters
/ALL_BUILD.vcxproj
+77
View File
@@ -0,0 +1,77 @@
# Build matrix / environment variable are explained on:
# https://docs.travis-ci.com/user/customizing-the-build/
# This file can be validated on:
# http://lint.travis-ci.org/
sudo: false
language: cpp
# Define the matrix explicitly, manually expanding the combinations of (os, compiler, env).
# It is more tedious, but grants us far more flexibility.
matrix:
include:
- os: linux
sudo: required
before_install: chmod -R +x ./ci/*platformio.sh
install: ./ci/install-platformio.sh
script: ./ci/build-platformio.sh
- os: linux
dist: xenial
compiler: gcc
sudo : true
install: ./ci/install-linux.sh && ./ci/log-config.sh
script: ./ci/build-linux-bazel.sh
- os: linux
dist: xenial
compiler: clang
sudo : true
install: ./ci/install-linux.sh && ./ci/log-config.sh
script: ./ci/build-linux-bazel.sh
- os: linux
compiler: gcc
env: BUILD_TYPE=Debug VERBOSE=1 CXX_FLAGS=-std=c++11
- os: linux
compiler: clang
env: BUILD_TYPE=Release VERBOSE=1 CXX_FLAGS=-std=c++11 -Wgnu-zero-variadic-macro-arguments
- os: linux
compiler: clang
env: BUILD_TYPE=Release VERBOSE=1 CXX_FLAGS=-std=c++11 NO_EXCEPTION=ON NO_RTTI=ON COMPILER_IS_GNUCXX=ON
- os: osx
compiler: gcc
env: BUILD_TYPE=Release VERBOSE=1 CXX_FLAGS=-std=c++11 HOMEBREW_LOGS=~/homebrew-logs HOMEBREW_TEMP=~/homebrew-temp
- os: osx
compiler: clang
env: BUILD_TYPE=Release VERBOSE=1 CXX_FLAGS=-std=c++11 HOMEBREW_LOGS=~/homebrew-logs HOMEBREW_TEMP=~/homebrew-temp
# These are the install and build (script) phases for the most common entries in the matrix. They could be included
# in each entry in the matrix, but that is just repetitive.
install:
- ./ci/install-${TRAVIS_OS_NAME}.sh
- . ./ci/env-${TRAVIS_OS_NAME}.sh
- ./ci/log-config.sh
script: ./ci/travis.sh
# For sudo=false builds this section installs the necessary dependencies.
addons:
apt:
# List of whitelisted in travis packages for ubuntu-precise can be found here:
# https://github.com/travis-ci/apt-package-whitelist/blob/master/ubuntu-precise
# List of whitelisted in travis apt-sources:
# https://github.com/travis-ci/apt-source-whitelist/blob/master/ubuntu.json
sources:
- ubuntu-toolchain-r-test
- llvm-toolchain-precise-3.9
packages:
- g++-4.9
- clang-3.9
update: true
homebrew:
packages:
- ccache
- gcc@4.9
- llvm@3.9
update: true
notifications:
email: false
+190
View File
@@ -0,0 +1,190 @@
# Copyright 2017 Google Inc.
# All Rights Reserved.
#
#
# Redistribution and use in source and binary forms, with or without
# modification, are permitted provided that the following conditions are
# met:
#
# * Redistributions of source code must retain the above copyright
# notice, this list of conditions and the following disclaimer.
# * 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.
# * Neither the name of Google Inc. nor the names of its
# contributors may be used to endorse or promote products derived from
# this software without specific prior written permission.
#
# 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.
#
# Bazel Build for Google C++ Testing Framework(Google Test)
load("@rules_cc//cc:defs.bzl", "cc_library", "cc_test")
package(default_visibility = ["//visibility:public"])
licenses(["notice"])
exports_files(["LICENSE"])
config_setting(
name = "windows",
constraint_values = ["@platforms//os:windows"],
)
config_setting(
name = "msvc_compiler",
flag_values = {
"@bazel_tools//tools/cpp:compiler": "msvc-cl",
},
visibility = [":__subpackages__"],
)
config_setting(
name = "has_absl",
values = {"define": "absl=1"},
)
# Library that defines the FRIEND_TEST macro.
cc_library(
name = "gtest_prod",
hdrs = ["googletest/include/gtest/gtest_prod.h"],
includes = ["googletest/include"],
)
# Google Test including Google Mock
cc_library(
name = "gtest",
srcs = glob(
include = [
"googletest/src/*.cc",
"googletest/src/*.h",
"googletest/include/gtest/**/*.h",
"googlemock/src/*.cc",
"googlemock/include/gmock/**/*.h",
],
exclude = [
"googletest/src/gtest-all.cc",
"googletest/src/gtest_main.cc",
"googlemock/src/gmock-all.cc",
"googlemock/src/gmock_main.cc",
],
),
hdrs = glob([
"googletest/include/gtest/*.h",
"googlemock/include/gmock/*.h",
]),
copts = select({
":windows": [],
"//conditions:default": ["-pthread"],
}),
defines = select({
":has_absl": ["GTEST_HAS_ABSL=1"],
"//conditions:default": [],
}),
features = select({
":windows": ["windows_export_all_symbols"],
"//conditions:default": [],
}),
includes = [
"googlemock",
"googlemock/include",
"googletest",
"googletest/include",
],
linkopts = select({
":windows": [],
"//conditions:default": ["-pthread"],
}),
deps = select({
":has_absl": [
"@com_google_absl//absl/debugging:failure_signal_handler",
"@com_google_absl//absl/debugging:stacktrace",
"@com_google_absl//absl/debugging:symbolize",
"@com_google_absl//absl/strings",
"@com_google_absl//absl/types:any",
"@com_google_absl//absl/types:optional",
"@com_google_absl//absl/types:variant",
],
"//conditions:default": [],
}),
)
cc_library(
name = "gtest_main",
srcs = ["googlemock/src/gmock_main.cc"],
features = select({
":windows": ["windows_export_all_symbols"],
"//conditions:default": [],
}),
deps = [":gtest"],
)
# The following rules build samples of how to use gTest.
cc_library(
name = "gtest_sample_lib",
srcs = [
"googletest/samples/sample1.cc",
"googletest/samples/sample2.cc",
"googletest/samples/sample4.cc",
],
hdrs = [
"googletest/samples/prime_tables.h",
"googletest/samples/sample1.h",
"googletest/samples/sample2.h",
"googletest/samples/sample3-inl.h",
"googletest/samples/sample4.h",
],
features = select({
":windows": ["windows_export_all_symbols"],
"//conditions:default": [],
}),
)
cc_test(
name = "gtest_samples",
size = "small",
# All Samples except:
# sample9 (main)
# sample10 (main and takes a command line option and needs to be separate)
srcs = [
"googletest/samples/sample1_unittest.cc",
"googletest/samples/sample2_unittest.cc",
"googletest/samples/sample3_unittest.cc",
"googletest/samples/sample4_unittest.cc",
"googletest/samples/sample5_unittest.cc",
"googletest/samples/sample6_unittest.cc",
"googletest/samples/sample7_unittest.cc",
"googletest/samples/sample8_unittest.cc",
],
linkstatic = 0,
deps = [
"gtest_sample_lib",
":gtest_main",
],
)
cc_test(
name = "sample9_unittest",
size = "small",
srcs = ["googletest/samples/sample9_unittest.cc"],
deps = [":gtest"],
)
cc_test(
name = "sample10_unittest",
size = "small",
srcs = ["googletest/samples/sample10_unittest.cc"],
deps = [":gtest"],
)
+32
View File
@@ -0,0 +1,32 @@
# Note: CMake support is community-based. The maintainers do not use CMake
# internally.
cmake_minimum_required(VERSION 2.8.12)
if (POLICY CMP0048)
cmake_policy(SET CMP0048 NEW)
endif (POLICY CMP0048)
project(googletest-distribution)
set(GOOGLETEST_VERSION 1.11.0)
if (CMAKE_VERSION VERSION_GREATER "3.0.2")
if(NOT CYGWIN AND NOT MSYS AND NOT ${CMAKE_SYSTEM_NAME} STREQUAL QNX)
set(CMAKE_CXX_EXTENSIONS OFF)
endif()
endif()
enable_testing()
include(CMakeDependentOption)
include(GNUInstallDirs)
#Note that googlemock target already builds googletest
option(BUILD_GMOCK "Builds the googlemock subproject" ON)
option(INSTALL_GTEST "Enable installation of googletest. (Projects embedding googletest may want to turn this OFF.)" ON)
if(BUILD_GMOCK)
add_subdirectory( googlemock )
else()
add_subdirectory( googletest )
endif()
+130
View File
@@ -0,0 +1,130 @@
# How to become a contributor and submit your own code
## Contributor License Agreements
We'd love to accept your patches! Before we can take them, we have to jump a
couple of legal hurdles.
Please fill out either the individual or corporate Contributor License Agreement
(CLA).
* If you are an individual writing original source code and you're sure you
own the intellectual property, then you'll need to sign an
[individual CLA](https://developers.google.com/open-source/cla/individual).
* If you work for a company that wants to allow you to contribute your work,
then you'll need to sign a
[corporate CLA](https://developers.google.com/open-source/cla/corporate).
Follow either of the two links above to access the appropriate CLA and
instructions for how to sign and return it. Once we receive it, we'll be able to
accept your pull requests.
## Are you a Googler?
If you are a Googler, please make an attempt to submit an internal change rather
than a GitHub Pull Request. If you are not able to submit an internal change a
PR is acceptable as an alternative.
## Contributing A Patch
1. Submit an issue describing your proposed change to the
[issue tracker](https://github.com/google/googletest/issues).
2. Please don't mix more than one logical change per submittal, because it
makes the history hard to follow. If you want to make a change that doesn't
have a corresponding issue in the issue tracker, please create one.
3. Also, coordinate with team members that are listed on the issue in question.
This ensures that work isn't being duplicated and communicating your plan
early also generally leads to better patches.
4. If your proposed change is accepted, and you haven't already done so, sign a
Contributor License Agreement (see details above).
5. Fork the desired repo, develop and test your code changes.
6. Ensure that your code adheres to the existing style in the sample to which
you are contributing.
7. Ensure that your code has an appropriate set of unit tests which all pass.
8. Submit a pull request.
## The Google Test and Google Mock Communities
The Google Test community exists primarily through the
[discussion group](http://groups.google.com/group/googletestframework) and the
GitHub repository. Likewise, the Google Mock community exists primarily through
their own [discussion group](http://groups.google.com/group/googlemock). You are
definitely encouraged to contribute to the discussion and you can also help us
to keep the effectiveness of the group high by following and promoting the
guidelines listed here.
### Please Be Friendly
Showing courtesy and respect to others is a vital part of the Google culture,
and we strongly encourage everyone participating in Google Test development to
join us in accepting nothing less. Of course, being courteous is not the same as
failing to constructively disagree with each other, but it does mean that we
should be respectful of each other when enumerating the 42 technical reasons
that a particular proposal may not be the best choice. There's never a reason to
be antagonistic or dismissive toward anyone who is sincerely trying to
contribute to a discussion.
Sure, C++ testing is serious business and all that, but it's also a lot of fun.
Let's keep it that way. Let's strive to be one of the friendliest communities in
all of open source.
As always, discuss Google Test in the official GoogleTest discussion group. You
don't have to actually submit code in order to sign up. Your participation
itself is a valuable contribution.
## Style
To keep the source consistent, readable, diffable and easy to merge, we use a
fairly rigid coding style, as defined by the
[google-styleguide](https://github.com/google/styleguide) project. All patches
will be expected to conform to the style outlined
[here](https://google.github.io/styleguide/cppguide.html). Use
[.clang-format](https://github.com/google/googletest/blob/master/.clang-format)
to check your formatting.
## Requirements for Contributors
If you plan to contribute a patch, you need to build Google Test, Google Mock,
and their own tests from a git checkout, which has further requirements:
* [Python](https://www.python.org/) v2.3 or newer (for running some of the
tests and re-generating certain source files from templates)
* [CMake](https://cmake.org/) v2.8.12 or newer
## Developing Google Test and Google Mock
This section discusses how to make your own changes to the Google Test project.
### Testing Google Test and Google Mock Themselves
To make sure your changes work as intended and don't break existing
functionality, you'll want to compile and run Google Test and GoogleMock's own
tests. For that you can use CMake:
mkdir mybuild
cd mybuild
cmake -Dgtest_build_tests=ON -Dgmock_build_tests=ON ${GTEST_REPO_DIR}
To choose between building only Google Test or Google Mock, you may modify your
cmake command to be one of each
cmake -Dgtest_build_tests=ON ${GTEST_DIR} # sets up Google Test tests
cmake -Dgmock_build_tests=ON ${GMOCK_DIR} # sets up Google Mock tests
Make sure you have Python installed, as some of Google Test's tests are written
in Python. If the cmake command complains about not being able to find Python
(`Could NOT find PythonInterp (missing: PYTHON_EXECUTABLE)`), try telling it
explicitly where your Python executable can be found:
cmake -DPYTHON_EXECUTABLE=path/to/python ...
Next, you can build Google Test and / or Google Mock and all desired tests. On
\*nix, this is usually done by
make
To run the tests, do
make test
All tests should pass.
+63
View File
@@ -0,0 +1,63 @@
# This file contains a list of people who've made non-trivial
# contribution to the Google C++ Testing Framework project. People
# who commit code to the project are encouraged to add their names
# here. Please keep the list sorted by first names.
Ajay Joshi <jaj@google.com>
Balázs Dán <balazs.dan@gmail.com>
Benoit Sigoure <tsuna@google.com>
Bharat Mediratta <bharat@menalto.com>
Bogdan Piloca <boo@google.com>
Chandler Carruth <chandlerc@google.com>
Chris Prince <cprince@google.com>
Chris Taylor <taylorc@google.com>
Dan Egnor <egnor@google.com>
Dave MacLachlan <dmaclach@gmail.com>
David Anderson <danderson@google.com>
Dean Sturtevant
Eric Roman <eroman@chromium.org>
Gene Volovich <gv@cite.com>
Hady Zalek <hady.zalek@gmail.com>
Hal Burch <gmock@hburch.com>
Jeffrey Yasskin <jyasskin@google.com>
Jim Keller <jimkeller@google.com>
Joe Walnes <joe@truemesh.com>
Jon Wray <jwray@google.com>
Jói Sigurðsson <joi@google.com>
Keir Mierle <mierle@gmail.com>
Keith Ray <keith.ray@gmail.com>
Kenton Varda <kenton@google.com>
Kostya Serebryany <kcc@google.com>
Krystian Kuzniarek <krystian.kuzniarek@gmail.com>
Lev Makhlis
Manuel Klimek <klimek@google.com>
Mario Tanev <radix@google.com>
Mark Paskin
Markus Heule <markus.heule@gmail.com>
Matthew Simmons <simmonmt@acm.org>
Mika Raento <mikie@iki.fi>
Mike Bland <mbland@google.com>
Miklós Fazekas <mfazekas@szemafor.com>
Neal Norwitz <nnorwitz@gmail.com>
Nermin Ozkiranartli <nermin@google.com>
Owen Carlsen <ocarlsen@google.com>
Paneendra Ba <paneendra@google.com>
Pasi Valminen <pasi.valminen@gmail.com>
Patrick Hanna <phanna@google.com>
Patrick Riley <pfr@google.com>
Paul Menage <menage@google.com>
Peter Kaminski <piotrk@google.com>
Piotr Kaminski <piotrk@google.com>
Preston Jackson <preston.a.jackson@gmail.com>
Rainer Klaffenboeck <rainer.klaffenboeck@dynatrace.com>
Russ Cox <rsc@google.com>
Russ Rufer <russ@pentad.com>
Sean Mcafee <eefacm@gmail.com>
Sigurður Ásgeirsson <siggi@google.com>
Sverre Sundsdal <sundsdal@gmail.com>
Takeshi Yoshino <tyoshino@google.com>
Tracy Bialik <tracy@pentad.com>
Vadim Berman <vadimb@google.com>
Vlad Losev <vladl@google.com>
Wolfgang Klier <wklier@google.com>
Zhanyong Wan <wan@google.com>
+28
View File
@@ -0,0 +1,28 @@
Copyright 2008, Google Inc.
All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are
met:
* Redistributions of source code must retain the above copyright
notice, this list of conditions and the following disclaimer.
* 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.
* Neither the name of Google Inc. nor the names of its
contributors may be used to endorse or promote products derived from
this software without specific prior written permission.
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.
+140
View File
@@ -0,0 +1,140 @@
# GoogleTest
### Announcements
#### Live at Head
GoogleTest now follows the
[Abseil Live at Head philosophy](https://abseil.io/about/philosophy#upgrade-support).
We recommend using the latest commit in the `master` branch in your projects.
#### Documentation Updates
Our documentation is now live on GitHub Pages at
https://google.github.io/googletest/. We recommend browsing the documentation on
GitHub Pages rather than directly in the repository.
#### Release 1.10.x
[Release 1.10.x](https://github.com/google/googletest/releases/tag/release-1.10.0)
is now available.
#### Coming Soon
* We are planning to take a dependency on
[Abseil](https://github.com/abseil/abseil-cpp).
* More documentation improvements are planned.
## Welcome to **GoogleTest**, Google's C++ test framework!
This repository is a merger of the formerly separate GoogleTest and GoogleMock
projects. These were so closely related that it makes sense to maintain and
release them together.
### Getting Started
See the [GoogleTest User's Guide](https://google.github.io/googletest/) for
documentation. We recommend starting with the
[GoogleTest Primer](https://google.github.io/googletest/primer.html).
More information about building GoogleTest can be found at
[googletest/README.md](googletest/README.md).
## Features
* An [xUnit](https://en.wikipedia.org/wiki/XUnit) test framework.
* Test discovery.
* A rich set of assertions.
* User-defined assertions.
* Death tests.
* Fatal and non-fatal failures.
* Value-parameterized tests.
* Type-parameterized tests.
* Various options for running the tests.
* XML test report generation.
## Supported Platforms
GoogleTest requires a codebase and compiler compliant with the C++11 standard or
newer.
The GoogleTest code is officially supported on the following platforms.
Operating systems or tools not listed below are community-supported. For
community-supported platforms, patches that do not complicate the code may be
considered.
If you notice any problems on your platform, please file an issue on the
[GoogleTest GitHub Issue Tracker](https://github.com/google/googletest/issues).
Pull requests containing fixes are welcome!
### Operating Systems
* Linux
* macOS
* Windows
### Compilers
* gcc 5.0+
* clang 5.0+
* MSVC 2015+
**macOS users:** Xcode 9.3+ provides clang 5.0+.
### Build Systems
* [Bazel](https://bazel.build/)
* [CMake](https://cmake.org/)
**Note:** Bazel is the build system used by the team internally and in tests.
CMake is supported on a best-effort basis and by the community.
## Who Is Using GoogleTest?
In addition to many internal projects at Google, GoogleTest is also used by the
following notable projects:
* The [Chromium projects](http://www.chromium.org/) (behind the Chrome browser
and Chrome OS).
* The [LLVM](http://llvm.org/) compiler.
* [Protocol Buffers](https://github.com/google/protobuf), Google's data
interchange format.
* The [OpenCV](http://opencv.org/) computer vision library.
## Related Open Source Projects
[GTest Runner](https://github.com/nholthaus/gtest-runner) is a Qt5 based
automated test-runner and Graphical User Interface with powerful features for
Windows and Linux platforms.
[GoogleTest UI](https://github.com/ospector/gtest-gbar) is a test runner that
runs your test binary, allows you to track its progress via a progress bar, and
displays a list of test failures. Clicking on one shows failure text. Google
Test UI is written in C#.
[GTest TAP Listener](https://github.com/kinow/gtest-tap-listener) is an event
listener for GoogleTest that implements the
[TAP protocol](https://en.wikipedia.org/wiki/Test_Anything_Protocol) for test
result output. If your test runner understands TAP, you may find it useful.
[gtest-parallel](https://github.com/google/gtest-parallel) is a test runner that
runs tests from your binary in parallel to provide significant speed-up.
[GoogleTest Adapter](https://marketplace.visualstudio.com/items?itemName=DavidSchuldenfrei.gtest-adapter)
is a VS Code extension allowing to view GoogleTest in a tree view, and run/debug
your tests.
[C++ TestMate](https://github.com/matepek/vscode-catch2-test-adapter) is a VS
Code extension allowing to view GoogleTest in a tree view, and run/debug your
tests.
[Cornichon](https://pypi.org/project/cornichon/) is a small Gherkin DSL parser
that generates stub code for GoogleTest.
## Contributing Changes
Please read
[`CONTRIBUTING.md`](https://github.com/google/googletest/blob/master/CONTRIBUTING.md)
for details on how to contribute to this project.
Happy testing!
+24
View File
@@ -0,0 +1,24 @@
workspace(name = "com_google_googletest")
load("@bazel_tools//tools/build_defs/repo:http.bzl", "http_archive")
http_archive(
name = "com_google_absl",
urls = ["https://github.com/abseil/abseil-cpp/archive/7971fb358ae376e016d2d4fc9327aad95659b25e.zip"], # 2021-05-20T02:59:16Z
strip_prefix = "abseil-cpp-7971fb358ae376e016d2d4fc9327aad95659b25e",
sha256 = "aeba534f7307e36fe084b452299e49b97420667a8d28102cf9a0daeed340b859",
)
http_archive(
name = "rules_cc",
urls = ["https://github.com/bazelbuild/rules_cc/archive/68cb652a71e7e7e2858c50593e5a9e3b94e5b9a9.zip"], # 2021-05-14T14:51:14Z
strip_prefix = "rules_cc-68cb652a71e7e7e2858c50593e5a9e3b94e5b9a9",
sha256 = "1e19e9a3bc3d4ee91d7fcad00653485ee6c798efbbf9588d40b34cbfbded143d",
)
http_archive(
name = "rules_python",
urls = ["https://github.com/bazelbuild/rules_python/archive/ed6cc8f2c3692a6a7f013ff8bc185ba77eb9b4d2.zip"], # 2021-05-17T00:24:16Z
strip_prefix = "rules_python-ed6cc8f2c3692a6a7f013ff8bc185ba77eb9b4d2",
sha256 = "98b3c592faea9636ac8444bfd9de7f3fb4c60590932d6e6ac5946e3f8dbd5ff6",
)
+126
View File
@@ -0,0 +1,126 @@
#!/bin/bash
#
# Copyright 2020, Google Inc.
# All rights reserved.
#
# Redistribution and use in source and binary forms, with or without
# modification, are permitted provided that the following conditions are
# met:
#
# * Redistributions of source code must retain the above copyright
# notice, this list of conditions and the following disclaimer.
# * 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.
# * Neither the name of Google Inc. nor the names of its
# contributors may be used to endorse or promote products derived from
# this software without specific prior written permission.
#
# 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.
set -euox pipefail
readonly LINUX_LATEST_CONTAINER="gcr.io/google.com/absl-177019/linux_hybrid-latest:20210525"
readonly LINUX_GCC_FLOOR_CONTAINER="gcr.io/google.com/absl-177019/linux_gcc-floor:20201015"
if [[ -z ${GTEST_ROOT:-} ]]; then
GTEST_ROOT="$(realpath $(dirname ${0})/..)"
fi
if [[ -z ${STD:-} ]]; then
STD="c++11 c++14 c++17 c++20"
fi
# Test the CMake build
for cc in /usr/local/bin/gcc /opt/llvm/clang/bin/clang; do
for cmake_off_on in OFF ON; do
time docker run \
--volume="${GTEST_ROOT}:/src:ro" \
--tmpfs="/build:exec" \
--workdir="/build" \
--rm \
--env="CC=${cc}" \
--env="CXX_FLAGS=\"-Werror -Wdeprecated\"" \
${LINUX_LATEST_CONTAINER} \
/bin/bash -c "
cmake /src \
-DCMAKE_CXX_STANDARD=11 \
-Dgtest_build_samples=ON \
-Dgtest_build_tests=ON \
-Dgmock_build_tests=ON \
-Dcxx_no_exception=${cmake_off_on} \
-Dcxx_no_rtti=${cmake_off_on} && \
make -j$(nproc) && \
ctest -j$(nproc) --output-on-failure"
done
done
# Do one test with an older version of GCC
time docker run \
--volume="${GTEST_ROOT}:/src:ro" \
--workdir="/src" \
--rm \
--env="CC=/usr/local/bin/gcc" \
${LINUX_GCC_FLOOR_CONTAINER} \
/usr/local/bin/bazel test ... \
--copt="-Wall" \
--copt="-Werror" \
--copt="-Wno-error=pragmas" \
--keep_going \
--show_timestamps \
--test_output=errors
# Test GCC
for std in ${STD}; do
for absl in 0 1; do
time docker run \
--volume="${GTEST_ROOT}:/src:ro" \
--workdir="/src" \
--rm \
--env="CC=/usr/local/bin/gcc" \
--env="BAZEL_CXXOPTS=-std=${std}" \
${LINUX_LATEST_CONTAINER} \
/usr/local/bin/bazel test ... \
--copt="-Wall" \
--copt="-Werror" \
--define="absl=${absl}" \
--distdir="/bazel-distdir" \
--keep_going \
--show_timestamps \
--test_output=errors
done
done
# Test Clang
for std in ${STD}; do
for absl in 0 1; do
time docker run \
--volume="${GTEST_ROOT}:/src:ro" \
--workdir="/src" \
--rm \
--env="CC=/opt/llvm/clang/bin/clang" \
--env="BAZEL_CXXOPTS=-std=${std}" \
${LINUX_LATEST_CONTAINER} \
/usr/local/bin/bazel test ... \
--copt="--gcc-toolchain=/usr/local" \
--copt="-Wall" \
--copt="-Werror" \
--define="absl=${absl}" \
--distdir="/bazel-distdir" \
--keep_going \
--linkopt="--gcc-toolchain=/usr/local" \
--show_timestamps \
--test_output=errors
done
done

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