57 Commits
Author SHA1 Message Date
David Rebbe 6dd4456f9a API: Added icsneoc2.
Signed-off-by: David Rebbe <drebbe@intrepidcs.com>
2025-02-04 13:48:43 -05:00
Jonathan SchwartzandKyle Schwarz c5ba2d8d32 Communication: Add missing CAN error types 2025-02-04 15:15:44 +00:00
Kyle Schwarz a22791c9e0 CI: Move Windows jobs 2025-02-03 17:16:30 -05:00
Kyle Schwarz dc2a364afb Bindings: Python: Fix API docs since adding stubs 2025-01-29 14:53:18 -05:00
Kyle Schwarz 114b664d78 All: Welcome to 2025 2025-01-15 16:46:07 -05:00
Kyle Schwarz 2acf248583 Bindings: Python: Add stubs 2025-01-09 00:14:46 -05:00
Kyle Schwarz f18aa00322 Communication: Add EthernetStatusMessage 2025-01-06 14:12:19 -05:00
Jonathan SchwartzandKyle Schwarz 87baa97c3f Device: Fix ComponentVersion retrieval 2025-01-06 19:06:11 +00:00
Jonathan SchwartzandKyle Schwarz 8dcbbe0d72 NeoVIConnect: Add ComponentVersions support 2025-01-06 14:51:42 +00:00
Kyle Schwarz b624d06ca0 Driver: FTD3XX: Fix close() 2024-12-30 14:14:23 -05:00
Kyle Schwarz c249df8756 Bindings: Python: Add CANErrorCountMessage 2024-12-23 10:28:19 -05:00
Kyle Schwarz b2161211c5 Bindings: Python: Add Message::Type MessageFilter 2024-12-20 18:28:41 -05:00
Kyle Schwarz 0ee8a990a7 Bindings: Python: Fix get_gptp_status default arg 2024-12-20 18:28:22 -05:00
Yasser YassineandKyle Schwarz dc0f16b1d2 Communication: Add GPTPStatus 2024-12-20 23:22:25 +00:00
Kyle Schwarz c4ce803d62 LINMessage: Fix timestamp scaling 2024-12-19 15:54:27 -05:00
Kyle Schwarz 34cacf4cf2 EthernetMessage: Fix TX receipts
Fixes
- HardwareEthernetPacket packing
- EthernetMessage::fcs
2024-12-13 12:55:57 -05:00
Kyle Schwarz 4157558e84 Bindings: Python: Drop GIL for Device calls
Avoids an ABBA deadlock with the GIL and messageCallbacksLock
2024-12-12 11:12:55 -05:00
Kyle Schwarz 40b85488dc TCP: Add LIBICSNEO_DISABLE_TCP env option 2024-12-11 17:25:36 -05:00
Kyle Schwarz 7584563002 Bindings: Python: Add default MessageFilter constructor 2024-12-11 17:22:09 -05:00
Kyle Schwarz 4f83614037 Bindings: Python: Fix Device RTC functions 2024-12-04 12:31:06 -05:00
Kyle Schwarz 38a4af8062 Device: Fix getRTC response size
Some devices pad to 16-bit.
2024-12-04 12:11:01 -05:00
Kyle Schwarz 3b95b41be4 Bindings: Python: Add LINMessage 2024-12-03 23:41:51 -05:00
Kyle Schwarz 3da31a29b4 Bindings: Python: Add more Network members 2024-12-03 22:35:40 -05:00
Kyle Schwarz d0f3e593df Device: Add RAD-Galaxy 2 2024-12-02 20:02:06 -05:00
Kyle Schwarz 90268a4f04 CI: Update DOCKER_HOST 2024-12-02 19:44:21 -05:00
Kyle Schwarz dbe19a5616 Bindings: Python: Add MDIOMessage 2024-11-08 15:06:45 -05:00
Kyle Schwarz e5d7a38160 CI: Fix push command 2024-11-05 16:00:30 -05:00
Kyle Schwarz d714b620c4 CI: Add GitHub auto-push 2024-11-05 14:58:54 -05:00
Kyle Schwarz 10d2625cb6 Bindings: Python: Add get_tc10_status 2024-11-05 14:30:53 -05:00
Kyle Schwarz b9cfa85009 Docs: Add GitHub link 2024-11-05 12:56:27 -05:00
Kyle Schwarz 776d14bb3e Docs: Fix RTD requirements path 2024-11-04 18:05:24 -05:00
Kyle Schwarz 648fb2502f Docs: Refactor 2024-11-04 18:01:28 -05:00
Kyle Schwarz 008a0e4057 CI: Add needs section 2024-11-01 21:26:45 -04:00
Kyle Schwarz 3787bc27a2 Add Python bindings and the icsneopy package 2024-11-02 01:14:15 +00:00
Bryant JonesandKyle Schwarz e73f61bfcc Device: Add RADGigastar2 2024-10-21 20:00:29 +00:00
Yaroslav StetsykandKyle Schwarz f552df372b Device: Add RADMoonT1S 2024-10-18 18:23:58 +00:00
Vedant NaikandKyle Schwarz 80904dd84c Device: Gigastar: Add TC10 2024-10-03 19:14:33 +00:00
Kyle Schwarz e2bd0b5a3e Device: Fix getHardwareInfo() timeout 2024-10-02 22:19:54 +00:00
Bryant JonesandKyle Schwarz 24f291dc83 Device: Comet: Update settings 2024-09-26 20:42:41 +00:00
Bryant Jones ee7b66625a Network: Add support for new networks on LIN, SPI, and OP Eth 2024-09-25 14:09:38 -04:00
Bryant Jones 99183a89f9 Communication: Add new app errors 2024-08-29 12:28:01 -04:00
Kyle Schwarz 7f30179cc4 Build: Update D3XX libraries 2024-08-29 15:13:38 +00:00
Kyle Johannes 39bcef0230 Communication: warning fix 2024-08-29 15:01:34 +00:00
Bryant JonesandKyle Schwarz ca370a1310 Device: Comet2: Enable TC10 2024-08-22 16:06:13 +00:00
Kyle Schwarz 564933cb41 Device: Add readCoreminiHeader()
- Fixes NeoMemoryDiskDriver::readLogicalDiskAligned() for flash
- Adds FlashMemoryMessage
2024-08-21 10:42:04 -04:00
Kyle JohannesandKyle Schwarz cac8d760b0 Communication: Add AppErrorMessage support
App errors are responses from the device indicating internal runtime errors.
2024-08-15 16:47:35 +00:00
Kurt WachowskiandKyle Schwarz 75af3220b0 Driver: Block between read attempts
Driver:

* Refactored to limit accessibility of member fields;

Communication:

* readTask() now calls for a blocking wait;
2024-08-13 13:55:12 +00:00
Kyle Schwarz f25a0a4a81 Device: Remove const from bool return type 2024-08-02 11:10:20 -04:00
Kyle Schwarz 387c39d3a0 Platform: TCP: Guard against negative duration 2024-07-29 22:50:16 -04:00
Kyle Schwarz 4476bd8b71 Platform: TCP: Add poll function to Socket 2024-07-30 02:09:24 +00:00
Bryant JonesandKyle Schwarz 14588591e5 Device: Comet2/Comet3: Add support for TC10 API 2024-07-08 14:00:24 +00:00
Kyle Johannes cbcbcbdc5d System Test: FIRE 3 and VCAN 4-2EL 2024-06-11 22:04:09 +00:00
Kyle Schwarz cf1b4778a1 Device: RADMoon2ZL: Add TC10 commands 2024-06-03 08:31:17 -04:00
Yasser Yassine 77928dc93d Driver: Add general predicate parameter for waitForRx 2024-05-28 18:21:22 +00:00
Yasser Yassine 659fcf633c Communication: Add pause feature
Removed redirect read
2024-05-23 21:23:45 +00:00
Yasser Yassine 9a1cd1124d Device: Add device hardware info retrieval support 2024-05-14 19:52:00 +00:00
Jonathan SchwartzandKyle Schwarz 3782e12ef6 Device: Add neoVI Connect support 2024-04-30 12:48:31 +00:00
196 changed files with 15282 additions and 1697 deletions
+1 -1
View File
@@ -14,4 +14,4 @@ third-party/concurrentqueue/tests
*.orig *.orig
examples/csharp/bin examples/csharp/bin
examples/csharp/obj examples/csharp/obj
test/system test/system
+182 -25
View File
@@ -5,6 +5,7 @@ stages:
- build - build
- unit_test - unit_test
- hardware_test - hardware_test
- deploy
#------------------------------------------------------------------------------- #-------------------------------------------------------------------------------
# Windows # Windows
@@ -20,7 +21,7 @@ build windows/x64:
- build - build
expire_in: 3 days expire_in: 3 days
tags: tags:
- icsneo-windows - libicsneo-win-x64
unit_test windows/x64: unit_test windows/x64:
stage: unit_test stage: unit_test
@@ -31,7 +32,7 @@ unit_test windows/x64:
needs: needs:
- build windows/x64 - build windows/x64
tags: tags:
- icsneo-windows - libicsneo-win-x64
timeout: 5m timeout: 5m
build windows/x86: build windows/x86:
@@ -44,7 +45,7 @@ build windows/x86:
- build - build
expire_in: 3 days expire_in: 3 days
tags: tags:
- icsneo-windows - libicsneo-win-x64
unit_test windows/x86: unit_test windows/x86:
stage: unit_test stage: unit_test
@@ -55,7 +56,7 @@ unit_test windows/x86:
needs: needs:
- build windows/x86 - build windows/x86
tags: tags:
- icsneo-windows - libicsneo-win-x64
timeout: 5m timeout: 5m
#------------------------------------------------------------------------------- #-------------------------------------------------------------------------------
@@ -318,57 +319,213 @@ unit_test linux/fedora/39/amd64/clang:
- /opt/libvirt-driver/run.sh - /opt/libvirt-driver/run.sh
after_script: after_script:
- /opt/libvirt-driver/cleanup.sh - /opt/libvirt-driver/cleanup.sh
allow_failure: true
hardware_test system-test-fedora38-red2: .fedora38_needs: &fedora38_needs
<<: *hw_test
variables:
GUEST_OS_TAG: fedora38
DEVICE_PORT: ETH_A
needs: needs:
- job: build linux/fedora/38/amd64/clang - job: build linux/fedora/38/amd64/clang
artifacts: true artifacts: true
hardware_test system-test-fedora38-vcan42: hardware_test fedora38-red2:
<<: *hw_test <<: *hw_test
<<: *fedora38_needs
variables:
GUEST_OS_TAG: fedora38
DEVICE_PORT: ETH_A
hardware_test fedora38-vcan42:
<<: *hw_test
<<: *fedora38_needs
variables: variables:
GUEST_OS_TAG: fedora38 GUEST_OS_TAG: fedora38
DEVICE_PORT: USB_D DEVICE_PORT: USB_D
needs:
- job: build linux/fedora/38/amd64/clang
artifacts: true
hardware_test system-test-ubuntu2204-red2: hardware_test fedora38-fire3:
<<: *hw_test <<: *hw_test
<<: *fedora38_needs
variables: variables:
GUEST_OS_TAG: ubuntu22.04 GUEST_OS_TAG: fedora38
DEVICE_PORT: ETH_A DEVICE_PORT: ETH_B
hardware_test fedora38-vcan42-EL:
<<: *hw_test
<<: *fedora38_needs
variables:
GUEST_OS_TAG: fedora38
DEVICE_PORT: USB_C
.ubuntu2204_needs: &ubuntu2204_needs
needs: needs:
- job: build linux/ubuntu/2204/amd64/clang - job: build linux/ubuntu/2204/amd64/clang
artifacts: true artifacts: true
hardware_test system-test-ubuntu2204-vcan42: hardware_test ubuntu2204-red2:
<<: *hw_test <<: *hw_test
<<: *ubuntu2204_needs
variables:
GUEST_OS_TAG: ubuntu22.04
DEVICE_PORT: ETH_A
hardware_test ubuntu2204-vcan42:
<<: *hw_test
<<: *ubuntu2204_needs
variables: variables:
GUEST_OS_TAG: ubuntu22.04 GUEST_OS_TAG: ubuntu22.04
DEVICE_PORT: USB_D DEVICE_PORT: USB_D
hardware_test ubuntu2204-fire3:
<<: *hw_test
<<: *ubuntu2204_needs
variables:
GUEST_OS_TAG: ubuntu22.04
DEVICE_PORT: ETH_B
hardware_test ubuntu2204-vcan42-EL:
<<: *hw_test
<<: *ubuntu2204_needs
variables:
GUEST_OS_TAG: ubuntu22.04
DEVICE_PORT: USB_C
.win10_needs: &win10_needs
needs: needs:
- job: build linux/ubuntu/2204/amd64/clang - job: build windows/x64
artifacts: true artifacts: true
hardware_test system-test-win10-red2: hardware_test win10-red2:
<<: *hw_test <<: *hw_test
<<: *win10_needs
variables: variables:
GUEST_OS_TAG: win10 GUEST_OS_TAG: win10
DEVICE_PORT: ETH_A DEVICE_PORT: ETH_A
needs:
- job: build windows/x64
artifacts: true
hardware_test system-test-win10-vcan42: hardware_test win10-vcan42:
<<: *hw_test <<: *hw_test
<<: *win10_needs
variables: variables:
GUEST_OS_TAG: win10 GUEST_OS_TAG: win10
DEVICE_PORT: USB_D DEVICE_PORT: USB_D
hardware_test win10-fire3:
<<: *hw_test
<<: *win10_needs
variables:
GUEST_OS_TAG: win10
DEVICE_PORT: ETH_B
hardware_test win10-vcan42-EL:
<<: *hw_test
<<: *win10_needs
variables:
GUEST_OS_TAG: win10
DEVICE_PORT: USB_C
#-------------------------------------------------------------------------------
# Python Module
#-------------------------------------------------------------------------------
build python/linux/amd64:
stage: build
tags:
- linux-build
image: python:3.12
services:
- name: docker:dind
entrypoint: ["env", "-u", "DOCKER_HOST"]
command: ["dockerd-entrypoint.sh"]
variables:
CIBW_BEFORE_ALL: yum install -y flex && sh ci/bootstrap-libpcap.sh && sh ci/bootstrap-libusb.sh
CIBW_BUILD: "*manylinux*" # no musl
CIBW_ARCHS: x86_64
DOCKER_HOST: unix:///var/run/docker.sock
DOCKER_DRIVER: overlay2
DOCKER_TLS_CERTDIR: ""
CIBW_ENVIRONMENT: CMAKE_PREFIX_PATH=/project/libpcap/install:/project/libusb/install
script:
- curl -sSL https://get.docker.com/ | sh
- sh ci/build-wheel-posix.sh
artifacts:
paths:
- wheelhouse
build python/linux/arm64:
stage: build
tags:
- arm64-linux-build
variables:
CIBW_BEFORE_ALL: yum install -y flex && sh ci/bootstrap-libpcap.sh && sh ci/bootstrap-libusb.sh
CIBW_BUILD: "*manylinux*" # no musl
CIBW_ARCHS: aarch64
CIBW_ENVIRONMENT: CMAKE_PREFIX_PATH=/project/libpcap/install:/project/libusb/install
script:
- sh ci/build-wheel-posix.sh
artifacts:
paths:
- wheelhouse
build python/macos:
stage: build
tags:
- macos-arm64
variables:
CIBW_BEFORE_ALL: sh ci/bootstrap-libpcap.sh && sh ci/bootstrap-libusb.sh
CIBW_ARCHS: arm64
CIBW_ENVIRONMENT: CMAKE_PREFIX_PATH=$CI_PROJECT_DIR/libpcap/install:$CI_PROJECT_DIR/libusb/install
MACOSX_DEPLOYMENT_TARGET: 10.14
script:
- sh ci/build-wheel-posix.sh
artifacts:
paths:
- wheelhouse
build python/windows:
stage: build
tags:
- libicsneo-win-x64
variables:
CIBW_ARCHS: AMD64
CIBW_ENVIRONMENT: CMAKE_GENERATOR=Ninja
script:
- cmd /c ci\build-wheel-windows.bat
artifacts:
paths:
- wheelhouse
deploy python/pypi:
stage: deploy
variables:
TWINE_USERNAME: __token__
TWINE_PASSWORD: $PYPI_TOKEN
tags:
- linux-build
image: python:3.12
rules:
- if: $CI_COMMIT_BRANCH == $CI_DEFAULT_BRANCH
script:
- python3 -m pip install -U twine
- twine upload wheelhouse/*
dependencies:
- build python/linux/amd64
- build python/linux/arm64
- build python/macos
- build python/windows
needs: needs:
- job: build windows/x64 - build python/linux/amd64
artifacts: true - build python/linux/arm64
- build python/macos
- build python/windows
push github:
stage: deploy
tags:
- linux-build
image: alpine:latest
rules:
- if: $CI_COMMIT_BRANCH == $CI_DEFAULT_BRANCH
dependencies:
- deploy python/pypi
needs:
- deploy python/pypi
script:
- apk add git
- git push https://$LIBICSNEO_GITHUB_USERNAME:$LIBICSNEO_GITHUB_TOKEN@github.com/intrepidcs/libicsneo.git HEAD:master
+15
View File
@@ -0,0 +1,15 @@
version: 2
build:
os: "ubuntu-24.04"
tools:
python: "3.12"
apt_packages:
- doxygen
python:
install:
- requirements: docs/requirements.txt
sphinx:
configuration: docs/conf.py
+64 -12
View File
@@ -12,6 +12,8 @@ option(LIBICSNEO_BUILD_DOCS "Build documentation. Don't use in Visual Studio." O
option(LIBICSNEO_BUILD_EXAMPLES "Build examples." ON) option(LIBICSNEO_BUILD_EXAMPLES "Build examples." ON)
option(LIBICSNEO_BUILD_ICSNEOC "Build dynamic C library" ON) option(LIBICSNEO_BUILD_ICSNEOC "Build dynamic C library" ON)
option(LIBICSNEO_BUILD_ICSNEOC_STATIC "Build static C library" ON) option(LIBICSNEO_BUILD_ICSNEOC_STATIC "Build static C library" ON)
option(LIBICSNEO_BUILD_ICSNEOC2 "Build dynamic C2 library" ON)
option(LIBICSNEO_BUILD_ICSNEOC2_STATIC "Build static C2 library" ON)
option(LIBICSNEO_BUILD_ICSNEOLEGACY "Build icsnVC40 compatibility library" ON) option(LIBICSNEO_BUILD_ICSNEOLEGACY "Build icsnVC40 compatibility library" ON)
option(LIBICSNEO_BUILD_ICSNEOLEGACY_STATIC "Build static icsnVC40 compatibility library" ON) option(LIBICSNEO_BUILD_ICSNEOLEGACY_STATIC "Build static icsnVC40 compatibility library" ON)
set(LIBICSNEO_NPCAP_INCLUDE_DIR "" CACHE STRING "Npcap include directory; set to build with Npcap") set(LIBICSNEO_NPCAP_INCLUDE_DIR "" CACHE STRING "Npcap include directory; set to build with Npcap")
@@ -27,6 +29,9 @@ option(LIBICSNEO_ENABLE_FTDI "Enable devices which communicate over USB FTDI2XX"
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_FTD3XX "Enable devices which communicate over USB FTD3XX" 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_RUST "Enable Rust library" OFF)
if(NOT CMAKE_CXX_STANDARD) if(NOT CMAKE_CXX_STANDARD)
set(CMAKE_CXX_STANDARD 17) set(CMAKE_CXX_STANDARD 17)
endif() endif()
@@ -172,27 +177,27 @@ if(LIBICSNEO_ENABLE_FTD3XX)
if(NOT FTD3XX_ROOT) # allow system override if(NOT FTD3XX_ROOT) # allow system override
include(FetchContent) include(FetchContent)
if(WIN32 AND CMAKE_SIZEOF_VOID_P EQUAL 8) if(WIN32 AND CMAKE_SIZEOF_VOID_P EQUAL 8)
set(LIBICSNEO_FTD3XX_URL "https://github.com/intrepidcs/libftd3xx-repack/releases/download/23.28.0/libftd3xx-1.3.0.4-win-x64.zip") 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=ee1289cdd5023de67275aaa1712e8e32e73e825a8392efb0a76f161e357fbdc9") set(LIBICSNEO_FTD3XX_URL_HASH "SHA256=459e635496ab47d6069c9d3515fdd6d82cba3d95e7ae34f794d66ffdf336e9d1")
elseif(WIN32 AND CMAKE_SIZEOF_VOID_P EQUAL 4) elseif(WIN32 AND CMAKE_SIZEOF_VOID_P EQUAL 4)
set(LIBICSNEO_FTD3XX_URL "https://github.com/intrepidcs/libftd3xx-repack/releases/download/23.28.0/libftd3xx-1.3.0.4-win-i686.zip") 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=bcd31f5c3cb39ecb9b09db5ce722bd79de6e0f813130e7b8f2c86879a60d8ff0") set(LIBICSNEO_FTD3XX_URL_HASH "SHA256=ce4259ae11772d6ede7d217172156fa392f329b29d9455131f4126a2fb89dad1")
elseif(APPLE AND CMAKE_SIZEOF_VOID_P EQUAL 8) elseif(APPLE AND CMAKE_SIZEOF_VOID_P EQUAL 8)
set(LIBICSNEO_FTD3XX_URL "https://github.com/intrepidcs/libftd3xx-repack/releases/download/23.28.0/libftd3xx-1.0.14-macos-universal2.zip") 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=74c0d35f04242d0841532c6325eb2932b8f627e3c395382a15d9f39974d27a90") set(LIBICSNEO_FTD3XX_URL_HASH "SHA256=0904ac5eda8e1dc4b5aac3714383bcc7792b42dfeb585dce6cbfb8b67b8c0c51")
elseif(UNIX) elseif(UNIX)
if(CMAKE_SYSTEM_PROCESSOR MATCHES "x86_64|amd64|AMD64") if(CMAKE_SYSTEM_PROCESSOR MATCHES "x86_64|amd64|AMD64")
if(CMAKE_SIZEOF_VOID_P EQUAL 8) if(CMAKE_SIZEOF_VOID_P EQUAL 8)
set(LIBICSNEO_FTD3XX_URL "https://github.com/intrepidcs/libftd3xx-repack/releases/download/23.28.0/libftd3xx-1.0.14-linux-x64.zip") 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=a9dc7eb6948c8977fbd79f6700bec6f882d3da5667aea8f2175b8d1f6f08e456") set(LIBICSNEO_FTD3XX_URL_HASH "SHA256=cf66bf299fc722f050cdd3c36998a670f1df69f7c0df18afa73707277067114b")
endif() endif()
elseif(CMAKE_SYSTEM_PROCESSOR MATCHES "arm.*|aarch64") elseif(CMAKE_SYSTEM_PROCESSOR MATCHES "arm.*|aarch64")
if(CMAKE_SIZEOF_VOID_P EQUAL 8) if(CMAKE_SIZEOF_VOID_P EQUAL 8)
set(LIBICSNEO_FTD3XX_URL "https://github.com/intrepidcs/libftd3xx-repack/releases/download/23.28.0/libftd3xx-1.0.14-linux-aarch64.zip") 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=da4b90ea1cbb905874cd159ad2ab8c1bdde65cc22b3aa55bf2b5fd85ca6efd22") set(LIBICSNEO_FTD3XX_URL_HASH "SHA256=66341b5112b9841e959e81400b51711be96fec91894477c5cbfc29b10a0c00a6")
elseif(CMAKE_SIZEOF_VOID_P EQUAL 4) elseif(CMAKE_SIZEOF_VOID_P EQUAL 4)
set(LIBICSNEO_FTD3XX_URL "https://github.com/intrepidcs/libftd3xx-repack/releases/download/23.28.0/libftd3xx-1.0.14-linux-armhf.zip") 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=d813008117422cae958f7c71a065cdac0d31dca3b24809d3ab5e13604a9c3fb1") set(LIBICSNEO_FTD3XX_URL_HASH "SHA256=cec1f959b48a11eb6b829ed43c81b6ba1c0bcf3e797bafcc84a6376e5ffc3c47")
endif() endif()
endif() endif()
endif() endif()
@@ -238,10 +243,14 @@ set(SRC_FILES
communication/message/flexray/control/flexraycontrolmessage.cpp communication/message/flexray/control/flexraycontrolmessage.cpp
communication/message/callback/streamoutput/a2bwavoutput.cpp communication/message/callback/streamoutput/a2bwavoutput.cpp
communication/message/a2bmessage.cpp communication/message/a2bmessage.cpp
communication/message/apperrormessage.cpp
communication/message/neomessage.cpp communication/message/neomessage.cpp
communication/message/ethphymessage.cpp communication/message/ethphymessage.cpp
communication/message/linmessage.cpp communication/message/linmessage.cpp
communication/message/livedatamessage.cpp communication/message/livedatamessage.cpp
communication/message/tc10statusmessage.cpp
communication/message/gptpstatusmessage.cpp
communication/message/ethernetstatusmessage.cpp
communication/packet/flexraypacket.cpp communication/packet/flexraypacket.cpp
communication/packet/canpacket.cpp communication/packet/canpacket.cpp
communication/packet/a2bpacket.cpp communication/packet/a2bpacket.cpp
@@ -259,6 +268,7 @@ set(SRC_FILES
communication/packet/componentversionpacket.cpp communication/packet/componentversionpacket.cpp
communication/packet/supportedfeaturespacket.cpp communication/packet/supportedfeaturespacket.cpp
communication/packet/genericbinarystatuspacket.cpp communication/packet/genericbinarystatuspacket.cpp
communication/packet/hardwareinfopacket.cpp
communication/decoder.cpp communication/decoder.cpp
communication/encoder.cpp communication/encoder.cpp
communication/ethernetpacketizer.cpp communication/ethernetpacketizer.cpp
@@ -327,6 +337,7 @@ endif()
configure_file(api/icsneocpp/buildinfo.h.template ${CMAKE_CURRENT_BINARY_DIR}/generated/buildinfo.h) configure_file(api/icsneocpp/buildinfo.h.template ${CMAKE_CURRENT_BINARY_DIR}/generated/buildinfo.h)
configure_file(api/icsneoc/version.rc.template ${CMAKE_CURRENT_BINARY_DIR}/generated/icsneoc/version.rc) configure_file(api/icsneoc/version.rc.template ${CMAKE_CURRENT_BINARY_DIR}/generated/icsneoc/version.rc)
configure_file(api/icsneoc2/version.rc.template ${CMAKE_CURRENT_BINARY_DIR}/generated/icsneoc2/version.rc)
foreach(EXTINC ${LIBICSNEO_EXTENSION_INCLUDES}) foreach(EXTINC ${LIBICSNEO_EXTENSION_INCLUDES})
message("Including " ${EXTINC}) message("Including " ${EXTINC})
@@ -454,6 +465,42 @@ if(LIBICSNEO_BUILD_ICSNEOC_STATIC)
target_compile_definitions(icsneoc-static PUBLIC ICSNEOC_BUILD_STATIC) target_compile_definitions(icsneoc-static PUBLIC ICSNEOC_BUILD_STATIC)
endif() endif()
if(LIBICSNEO_BUILD_ICSNEOC2)
add_library(icsneoc2 SHARED api/icsneoc2/icsneoc2.cpp ${CMAKE_CURRENT_BINARY_DIR}/generated/icsneoc2/version.rc)
target_include_directories(icsneoc2
PUBLIC
$<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}/include>
$<INSTALL_INTERFACE:>
PRIVATE
${CMAKE_CURRENT_SOURCE_DIR}/include
)
target_link_libraries(icsneoc2 PRIVATE icsneocpp)
target_compile_definitions(icsneoc2
PRIVATE
ICSNEO_EXPORTS _CRT_SECURE_NO_WARNINGS
PUBLIC
ICSNEO_IMPORTS _CRT_SECURE_NO_WARNINGS
INTERFACE
ICSNEO_IMPORTS _CRT_SECURE_NO_WARNINGS
)
target_compile_features(icsneoc2 PRIVATE cxx_auto_type cxx_constexpr cxx_lambdas cxx_nullptr cxx_range_for cxx_rvalue_references cxx_sizeof_member cxx_strong_enums)
target_compile_definitions(icsneoc2 PUBLIC ICSNEOC2_BUILD_DYNAMIC)
endif()
if(LIBICSNEO_BUILD_ICSNEOC2_STATIC)
add_library(icsneoc2-static STATIC api/icsneoc2/icsneoc2.cpp)
target_include_directories(icsneoc2-static
PUBLIC
$<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}/include>
$<INSTALL_INTERFACE:>
PRIVATE
${CMAKE_CURRENT_SOURCE_DIR}/include
)
target_link_libraries(icsneoc2-static PUBLIC icsneocpp)
target_compile_features(icsneoc2-static PUBLIC cxx_auto_type cxx_constexpr cxx_lambdas cxx_nullptr cxx_range_for cxx_rvalue_references cxx_sizeof_member cxx_strong_enums)
target_compile_definitions(icsneoc2-static PUBLIC ICSNEOC2_BUILD_STATIC)
endif()
if(LIBICSNEO_BUILD_ICSNEOLEGACY) if(LIBICSNEO_BUILD_ICSNEOLEGACY)
add_library(icsneolegacy SHARED add_library(icsneolegacy SHARED
api/icsneolegacy/icsneolegacy.cpp api/icsneolegacy/icsneolegacy.cpp
@@ -491,6 +538,8 @@ if(LIBICSNEO_BUILD_ICSNEOLEGACY_STATIC)
target_compile_definitions(icsneolegacy-static PUBLIC ICSNEOC_BUILD_STATIC) target_compile_definitions(icsneolegacy-static PUBLIC ICSNEOC_BUILD_STATIC)
endif() endif()
add_subdirectory(bindings)
# googletest # googletest
if(LIBICSNEO_BUILD_UNIT_TESTS) if(LIBICSNEO_BUILD_UNIT_TESTS)
if(WIN32) if(WIN32)
@@ -517,10 +566,13 @@ if(LIBICSNEO_BUILD_UNIT_TESTS)
test/unit/mdioencoderdecodertest.cpp test/unit/mdioencoderdecodertest.cpp
test/unit/livedataencoderdecodertest.cpp test/unit/livedataencoderdecodertest.cpp
test/unit/ringbuffertest.cpp test/unit/ringbuffertest.cpp
test/unit/apperrordecodertest.cpp
test/unit/icsneoc2.cpp
) )
target_link_libraries(libicsneo-unit-tests gtest gtest_main) target_link_libraries(libicsneo-unit-tests gtest gtest_main)
target_link_libraries(libicsneo-unit-tests icsneocpp) target_link_libraries(libicsneo-unit-tests icsneocpp)
target_link_libraries(libicsneo-unit-tests icsneoc2-static)
target_include_directories(libicsneo-unit-tests PUBLIC ${gtest_SOURCE_DIR}/include ${gtest_SOURCE_DIR}) target_include_directories(libicsneo-unit-tests PUBLIC ${gtest_SOURCE_DIR}/include ${gtest_SOURCE_DIR})
-56
View File
@@ -1,56 +0,0 @@
# Hardware Support
- Connecting over Ethernet
- neoVI FIRE 2
- CAN works
- CAN FD works
- ValueCAN 4-2EL
- CAN works
- CAN FD works
- Ethernet works
- RADGalaxy
- CAN works
- Ethernet works
- RADStar 2
- CAN works
- Ethernet works
- RADA2B
- CAN works
- Ethernet works
- RADComet
- CAN works
- CAN FD works
- Ethernet works
- RADComet3
- CAN works
- Ethernet works
- Connecting over USB
- ValueCAN 4 series
- CAN works
- CAN FD works
- Ethernet works (on 4-2EL)
- neoOBD2 PRO
- CAN works
- neoVI FIRE
- CAN works
- neoVI FIRE 2
- CAN works
- CAN FD works
- Ethernet works
- ValueCAN 3
- CAN works
- RADStar 2
- CAN works
- Ethernet works
- neoVI PLASMA
- CAN works
- neoVI ION
- CAN works
- RADA2B
- CAN works
- Ethernet works
- RADMoon3
- RADComet3
- CAN works
- Ethernet works
+23 -7
View File
@@ -1,13 +1,29 @@
Copyright 2018-2024 Intrepid Control Systems, Inc. Copyright (c) 2018-2025 Intrepid Control Systems, Inc.
Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: Redistribution and use in source and binary forms, with or without modification,
are permitted provided that the following conditions are met:
1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. 1. Redistributions of source code must retain the above copyright notice, this
list of conditions and the following disclaimer.
2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. 2. Redistributions in binary form must reproduce the above copyright notice,
this list of conditions and the following disclaimer in the documentation
and/or other materials provided with the distribution.
3. Neither the name of the copyright holder nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. 3. Neither the name of the copyright holder nor the names of its contributors
may be used to endorse or promote products derived from this software without
specific prior written permission.
4. It is forbidden to use this library or derivatives to interface with vehicle networking hardware not produced by Intrepid Control Systems, Inc. 4. It is forbidden to use this library or derivatives to interface with vehicle
networking hardware not produced by Intrepid Control Systems, Inc.
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 HOLDER 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. 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 HOLDER 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.
+35 -168
View File
@@ -1,176 +1,43 @@
# libicsneo # libicsneo
### The Intrepid Control Systems Open Source Cross-Platform Device Communication API
An open source solution to integrate Intrepid Control Systems vehicle networking hardware with your application. libicsneo is the [Intrepid Control Systems](https://intrepidcs.com/) device
communication library. Installation and usage documentation can be found within
each of the respective APIs.
[Read the Full Documentation](https://libicsneo.readthedocs.io/) ## Documentation
## Getting Started - [C++](https://libicsneo.readthedocs.io/en/latest/icsneocpp/)
There are two major ways to write a new application using libicsneo. You can use the C++ interface, which will be compiled with your project and statically linked, or you can use the C interface, which can be either statically or dynamically linked. - [Python](https://libicsneo.readthedocs.io/en/latest/icsneopy/)
### Integration with CMake (Static Linking) - [C](https://libicsneo.readthedocs.io/en/latest/icsneoc/)
Integrating the library with your current CMake project is extremely easy.
1. Checkout the library (or add as a submodule) into a subdirectory of your project.
2. Within your `CMakeLists.txt` you can add the line `add_subdirectory("third-party/libicsneo")` to bring in the libicsneo targets. Replace `third-party` with any subdirectory you choose.
3. The libicsneo library include paths should automatically be added to your include path.
4. Link the library with your target by adding `target_link_libraries(libicsneocpp-example icsneocpp)` after your target, substituting `libicsneocpp-example` with your target application.
You can now include either the C++ API with `#include <icsneo/icsneocpp.h>` or the C API with `#include <icsneo/icsneoc.h>` ## Hardware Support
### DLL / SO / DYLIB Releases (Dynamic Linking) - EtherBADGE
It is also possible to use the precompiled binaries with runtime linking. It is not recommended or supported to attempt to use the C++ interface with dynamic linking due to the complexities of C++ compilers. - neoVI Connect
1. Add this repository's `/include` to your include path - neoVI FIRE
2. Add `#define ICSNEOC_DYNAMICLOAD` to the top of your source file - neoVI FIRE 2
2. Add `#import <icsneo/icsneoc.h>` below that line - neoVI FIRE 3
3. Call `icsneo_init();` to import the library before using any other libicsneo functions. - neoVI ION
4. Use the library as normal. - neoVI PLASMA
5. Call `icsneo_close();` to unload the library. - neoVI RED 2
- RAD-A2B
- RAD-Comet 2
- RAD-Comet 3
- RAD-Galaxy
- RAD-Galaxy 2
- RAD-Gigastar
- RAD-Gigastar 2
- RAD-Moon 2
- RAD-Moon 3
- RAD-Moon T1S
- RAD-Pluto
- RAD-Star 2
- RAD-SuperMoon
- RADComet
- ValueCAN 3
- ValueCAN 4
## Usage ## License
### Using the C++ API
The C++ API is designed to be modern and easy to use. All library functions and classes are in the namespace `icsneo`. Most applications will start by calling `icsneo::FindAllDevices()`. This will return an `std::vector` of `std::shared_ptr<icsneo::Device>` objects. You will want to keep a copy of the `shared_ptr` to any devices you want to use, as allowing it to go out of scope will automatically close the device and free all memory associated with it.
Any time you get bus traffic from the API, you will receive it as an `std::shared_ptr<icsneo::Message>`. The message will be valid as long as the `shared_ptr` stays in scope. Checking the type of the message allows you to cast it accordingly and access extra data for certain protocols. For instance, casting an `icsneo::Message` to an `icsneo::CANMessage` allows you to access the arbitration ID. libicsneo is licensed as BSD-3 with an extra clause, see [LICENSE](LICENSE)
for more details.
A barebones example is provided. For a more complete example, check the included `examples`.
``` c++
std::vector<std::shared_ptr<icsneo::Device>> devices = icsneo::FindAllDevices();
std::cout << devices.size() << " found!" << std::endl;
for(auto& device : devices)
std::cout << "Found " << device->describe() << std::endl; // "Found neoVI FIRE 2 CY2345"
std::shared_ptr<icsneo::Device> myDevice = devices[0];
if(!myDevice->open()) // Device tried and failed to open, print the last error
std::cout << icsneo::GetLastError() << std::endl;
myDevice->goOnline(); // Start receiving messages
myDevice->enableMessagePolling(); // Allow the use of myDevice->getMessages() later
// Alternatively, assign a callback for new messages
std::this_thread::wait_for(std::chrono::seconds(5));
std::vector<std::shared_ptr<icsneo::Message>> messages = myDevice->getMessages();
std::cout << "We got " << messages.size() << " messages!" << std::endl;
for(auto& msg : messages) {
switch(msg->network.getType()) {
case icsneo::Network::Type::CAN:
case icsneo::Network::Type::SWCAN:
case icsneo::Network::Type::LSFTCAN: {
// A message of type CAN is guaranteed to be a CANMessage, so we can static cast safely
auto canmsg = std::static_pointer_cast<icsneo::CANMessage>(msg);
// canmsg->arbid is valid here
// canmsg->data is an std::vector<uint8_t>, you can check .size() for the DLC of the message
// canmsg->timestamp is the time recorded by the hardware in nanoseconds since (1/1/2007 12:00:00 GMT)
}
default:
// Handle others
}
}
myDevice->close();
```
### Using the C API
The C API is designed to be a robust and fault tolerant interface which allows easy integration with other languages as well as existing C applications. When calling `icsneo_findAllDevices()` you will provide a buffer of `neodevice_t` structures, which will be written with the found devices. These `neodevice_t` structures can be uses to interface with the API from then on. Once you call `icsneo_close()` with a device, that device and all associated memory will be freed. You will need to run `icsneo_findAllDevices()` again to reconnect.
Messages are passed in the form of `neomessage_t` structures when calling `icsneo_getMessages()`. These structures contain a `uint8_t*` to the payload data, and this pointer will be valid until the next call to `icsneo_getMessages()` or the device is closed.
A barebones example is provided. For a more complete example, check the included `examples`.
``` c
size_t deviceCount = 10; // Pre-set to the size of your buffer before the icsneo_findAllDevices() call
neodevice_t devices[10];
icsneo_findAllDevices(devices, &deviceCount);
printf("We found %ull devices\n", deviceCount);
for(size_t i = 0; i < deviceCount; i++) {
neodevice_t* myDevice = &devices[i];
char desc[ICSNEO_DEVICETYPE_LONGEST_DESCRIPTION];
size_t sz = ICSNEO_DEVICETYPE_LONGEST_DESCRIPTION;
icsneo_describeDevice(myDevice, desc, &sz);
printf("Found %s\n", desc); // "Found neoVI FIRE 2 CY2345"
}
neodevice_t* myDevice = &devices[0];
if(!icsneo_openDevice(myDevice)) {
neoevent_t error;
if(icsneo_getLastError(&error))
printf("Error! %s\n", error.description);
}
icsneo_goOnline(myDevice); // Start receiving messages
icsneo_enableMessagePolling(myDevice); // Allow the use of icsneo_getMessages() later
sleep(5);
neomessage_t messages[50];
size_t messageCount = 50;
icsneo_getMessages(myDevice, messages, &messageCount, 0 /* non-blocking */);
printf("We got %ull messages!\n", messageCount);
for(size_t i = 0; i < messageCount; i++) {
if(messages[i].type == ICSNEO_NETWORK_TYPE_CAN) {
// A message of type CAN should be interperated a neomessage_can_t, so we can cast safely
neomessage_can_t* canmsg = (neomessage_can_t*)&messages[i];
// canmsg->arbid is valid here
// canmsg->data is an uint8_t*, you can check canmsg->length for the length of the payload
// canmsg->timestamp is the time recorded by the hardware in nanoseconds since (1/1/2007 12:00:00 GMT)
}
}
icsneo_closeDevice(myDevice);
```
### Debugging
To enable debug printing set the `LIBICSNEO_PRINT_EVENTS` environmental variable to the desired `APIEvent::Severity` level, all `Event`s greater than or equal to that level will be printed to stderr. For example, to print all warnings and errors: `LIBICSNEO_PRINT_EVENTS=32`.
## Building from Source
### FTD3XX
Some devices require FTD3XX for USB communication so the [FTDI D3XX library](https://ftdichip.com/drivers/d3xx-drivers/) will be automatically downloaded and included. If you would like to use a system copy of D3XX instead you can set `FTD3XX_ROOT` to the path containing `f3d3xx.h` (`-DFTD3XX_ROOT=<path to directory containing ftd3xx.h>`).
### Windows
- Open a terminal and install the following:
```
winget install Microsoft.VisualStudio.2022.Community
winget install Kitware.CMake
winget install Git.Git
winget install Ninja-build.Ninja
```
- Reboot so cmake is in the system path
- Open a developer Powershell for VS2022 and run the following:
```
git clone https://github.com/intrepidcs/libicsneo
cd libicsneo
cmake -S . -B build -G "Ninja"
cmake --build build
# All dlls and libs are now inside the build directory
```
Building will require MSVC 2017 version 15.7 or newer and CMake to be installed.
### macOS
Getting the dependencies is easiest with the Homebrew package manager. You will also need XCode installed. You can then install CMake, an up-to-date version of GCC or Clang, and `libusb-1.0`.
### Linux
#### General Dependencies
- CMake 3.12 or above
- GCC 7 or above
- `libusb-1.0-0-dev`
- `libpcap0.8-dev`
- `build-essential` is recommended
#### Fedora
```
dnf install git @development-tools gcc-c++ libpcap-devel libusb1-devel cmake
```
#### Debian/Ubuntu
```
apt install git build-essential libpcap0.8-dev libusb-1.0-0-dev cmake
```
#### Building
```
git clone https://github.com/intrepidcs/libicsneo
cd libicsneo
cmake -S . -B build
cmake --build build
# Optional: Install globally:
cp *.so /usr/local/lib/
```
#### udev
If you'd like to be able to run programs that use this library without being root, consider using the included udev rules:
```
cp 99-intrepidcs.rules /etc/udev/rules.d/
udevadm control --reload-rules && udevadm trigger
```
+54
View File
@@ -0,0 +1,54 @@
#include "icsneo/icsneo.h"
#include "icsneo/icsneocpp.h"
#include "icsneo/device/devicefinder.h"
#include <string>
#include <algorithm>
using namespace icsneo;
struct icsneoOpenOptions_t {
/** Open the device in online mode on open. */
bool goOnlineOnOpen = true;
/** Enable message polling on open. */
bool enablePollingOnOpen = true;
/** Synchronize the device RTC on open.
* Useful for devices that don't have an RTC battery like ValueCAN4 */
bool syncRTCOnOpen = true;
};
typedef struct icsneo_device_t {
// This is the actual device handle, when its not open it will be NULL.
std::shared_ptr<Device> device;
icsneoOpenOptions_t openOptions;
} *icsneo_device_ptr_t;
icsneo_result_t icsneo_find(icsneo_device_ptr_t* devices, uint32_t* devices_count, void* reserved) {
static std::deque<icsneo_device_t> found_icsneo_devices;
if (!devices || !devices_count) {
return icsneo_error_invalid_parameter;
}
// Find all devices and get the minimum size to process
auto found_devices = DeviceFinder::FindAll();
auto min_size = std::minmax(found_devices.size(), static_cast<size_t>(*devices_count)).first;
// lets resize the array to the minimum size
for (auto i = 0; i < min_size; i++) {
const auto* dev = devices[i];
dev = new icsneo_device_t {};
dev->device = found_devices[i];
}
return icsneo_error_success;
}
icsneo_result_t icsneo_open(icsneo_device_ptr_t* device) {
if (!device) {
return icsneo_error_invalid_parameter;
}
return icsneo_error_success;
}
+51
View File
@@ -0,0 +1,51 @@
#define VER_FILEVERSION @PROJECT_VERSION_MAJOR@,@PROJECT_VERSION_MINOR@,@PROJECT_VERSION_PATCH@
#define VER_FILEVERSION_STR "v@PROJECT_VERSION_MAJOR@.@PROJECT_VERSION_MINOR@.@PROJECT_VERSION_PATCH@@BUILD_METADATA_PLUS@ @BUILD_GIT_INFO@"
#define VER_PRODUCTVERSION VER_FILEVERSION
#define VER_PRODUCTVERSION_STR VER_FILEVERSION_STR
#ifndef DEBUG
#define VER_DEBUG 0
#else
#define VER_DEBUG VS_FF_DEBUG
#endif
#include <windows.h>
VS_VERSION_INFO VERSIONINFO
FILEVERSION VER_FILEVERSION
PRODUCTVERSION VER_PRODUCTVERSION
FILEFLAGSMASK (VS_FF_DEBUG)
FILEFLAGS (VER_DEBUG)
FILEOS VOS__WINDOWS32
FILETYPE VFT_DLL
FILESUBTYPE VFT2_UNKNOWN
BEGIN
BLOCK "StringFileInfo"
BEGIN
BLOCK "040904E4"
BEGIN
VALUE "CompanyName", "Intrepid Control Systems, Inc."
VALUE "FileDescription", "Intrepid Control Systems Open Device Communication C API"
VALUE "FileVersion", VER_FILEVERSION_STR
VALUE "InternalName", "icsneo.dll"
VALUE "LegalCopyright", "Intrepid Control Systems, Inc. (C) 2018-2024"
VALUE "OriginalFilename", "icsneo.dll"
VALUE "ProductName", "libicsneo"
VALUE "ProductVersion", VER_PRODUCTVERSION_STR
END
END
BLOCK "VarFileInfo"
BEGIN
/* The following line should only be modified for localized versions. */
/* It consists of any number of WORD,WORD pairs, with each pair */
/* describing a language,codepage combination supported by the file. */
/* */
/* For example, a file might have values "0x409,1252" indicating that it */
/* supports English language (0x409) in the Windows ANSI codepage (1252). */
VALUE "Translation", 0x409, 1252
END
END
+2 -2
View File
@@ -462,7 +462,7 @@ bool icsneo_transmit(const neodevice_t* device, const neomessage_t* message) {
if(!icsneo_isValidNeoDevice(device)) if(!icsneo_isValidNeoDevice(device))
return false; return false;
if(auto frame = std::dynamic_pointer_cast<icsneo::Frame>(CreateMessageFromNeoMessage(message))) if(auto frame = std::dynamic_pointer_cast<icsneo::BusMessage>(CreateMessageFromNeoMessage(message)))
return device->device->transmit(frame); return device->device->transmit(frame);
return false; return false;
@@ -738,7 +738,7 @@ int icsneo_getDeviceStatus(const neodevice_t* device, void* status, size_t* size
if(!msg) // Did not receive a message if(!msg) // Did not receive a message
return false; return false;
auto rawMessage = std::static_pointer_cast<RawMessage>(msg); auto rawMessage = std::static_pointer_cast<InternalMessage>(msg);
if(!rawMessage || (rawMessage->network.getNetID() != Network::NetID::DeviceStatus)) if(!rawMessage || (rawMessage->network.getNetID() != Network::NetID::DeviceStatus))
return false; return false;
+1 -1
View File
@@ -29,7 +29,7 @@ BEGIN
VALUE "FileDescription", "Intrepid Control Systems Open Device Communication C API" VALUE "FileDescription", "Intrepid Control Systems Open Device Communication C API"
VALUE "FileVersion", VER_FILEVERSION_STR VALUE "FileVersion", VER_FILEVERSION_STR
VALUE "InternalName", "icsneoc.dll" VALUE "InternalName", "icsneoc.dll"
VALUE "LegalCopyright", "Intrepid Control Systems, Inc. (C) 2018-2024" VALUE "LegalCopyright", "Intrepid Control Systems, Inc. (C) 2018-2025"
VALUE "OriginalFilename", "icsneoc.dll" VALUE "OriginalFilename", "icsneoc.dll"
VALUE "ProductName", "libicsneo" VALUE "ProductName", "libicsneo"
VALUE "ProductVersion", VER_PRODUCTVERSION_STR VALUE "ProductVersion", VER_PRODUCTVERSION_STR
File diff suppressed because it is too large Load Diff
+51
View File
@@ -0,0 +1,51 @@
#define VER_FILEVERSION @PROJECT_VERSION_MAJOR@,@PROJECT_VERSION_MINOR@,@PROJECT_VERSION_PATCH@
#define VER_FILEVERSION_STR "v@PROJECT_VERSION_MAJOR@.@PROJECT_VERSION_MINOR@.@PROJECT_VERSION_PATCH@@BUILD_METADATA_PLUS@ @BUILD_GIT_INFO@"
#define VER_PRODUCTVERSION VER_FILEVERSION
#define VER_PRODUCTVERSION_STR VER_FILEVERSION_STR
#ifndef DEBUG
#define VER_DEBUG 0
#else
#define VER_DEBUG VS_FF_DEBUG
#endif
#include <windows.h>
VS_VERSION_INFO VERSIONINFO
FILEVERSION VER_FILEVERSION
PRODUCTVERSION VER_PRODUCTVERSION
FILEFLAGSMASK (VS_FF_DEBUG)
FILEFLAGS (VER_DEBUG)
FILEOS VOS__WINDOWS32
FILETYPE VFT_DLL
FILESUBTYPE VFT2_UNKNOWN
BEGIN
BLOCK "StringFileInfo"
BEGIN
BLOCK "040904E4"
BEGIN
VALUE "CompanyName", "Intrepid Control Systems, Inc."
VALUE "FileDescription", "Intrepid Control Systems Open Device Communication C API"
VALUE "FileVersion", VER_FILEVERSION_STR
VALUE "InternalName", "icsneo.dll"
VALUE "LegalCopyright", "Intrepid Control Systems, Inc. (C) 2018-2024"
VALUE "OriginalFilename", "icsneo.dll"
VALUE "ProductName", "libicsneo"
VALUE "ProductVersion", VER_PRODUCTVERSION_STR
END
END
BLOCK "VarFileInfo"
BEGIN
/* The following line should only be modified for localized versions. */
/* It consists of any number of WORD,WORD pairs, with each pair */
/* describing a language,codepage combination supported by the file. */
/* */
/* For example, a file might have values "0x409,1252" indicating that it */
/* supports English language (0x409) in the Windows ANSI codepage (1252). */
VALUE "Translation", 0x409, 1252
END
END
+7
View File
@@ -73,6 +73,7 @@ static constexpr const char* VALUE_NOT_YET_PRESENT = "The value is not yet prese
static constexpr const char* TIMEOUT = "The timeout was reached."; 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.";
// 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!";
@@ -119,6 +120,7 @@ static constexpr const char* DISK_NOT_CONNECTED = "The program tried to access a
static constexpr const char* UNEXPECTED_RESPONSE = "Received an unexpected or invalid response from the device."; static constexpr const char* UNEXPECTED_RESPONSE = "Received an unexpected or invalid response from the device.";
static constexpr const char* LIN_SETTINGS_NOT_AVAILABLE = "LIN settings are not available for this device."; static constexpr const char* LIN_SETTINGS_NOT_AVAILABLE = "LIN settings are not available for this device.";
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.";
// 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.";
@@ -184,6 +186,7 @@ static constexpr const char* VSA_OTHER_ERROR = "Unknown error in VSA read API.";
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.";
const char* APIEvent::DescriptionForType(Type type) { const char* APIEvent::DescriptionForType(Type type) {
switch(type) { switch(type) {
// API Errors // API Errors
@@ -221,6 +224,8 @@ const char* APIEvent::DescriptionForType(Type type) {
return WIVI_NOT_SUPPORTED; return WIVI_NOT_SUPPORTED;
case Type::RestrictedEntryFlag: case Type::RestrictedEntryFlag:
return RESTRICTED_ENTRY_FLAG; return RESTRICTED_ENTRY_FLAG;
case Type::NotSupported:
return NOT_SUPPORTED;
// Device Errors // Device Errors
case Type::PollingMessageOverflow: case Type::PollingMessageOverflow:
@@ -342,6 +347,8 @@ const char* APIEvent::DescriptionForType(Type type) {
return GETIFADDRS_ERROR; return GETIFADDRS_ERROR;
case Type::SendToError: case Type::SendToError:
return SEND_TO_ERROR; return SEND_TO_ERROR;
case Type::GPTPNotSupported:
return GPTP_NOT_SUPPORTED;
// FTD3XX // FTD3XX
case Type::FTOK: case Type::FTOK:
+18
View File
@@ -0,0 +1,18 @@
if(LIBICSNEO_ENABLE_BINDINGS_PYTHON)
add_subdirectory(python)
endif()
if(LIBICSNEO_ENABLE_BINDINGS_RUST)
include(FetchContent)
FetchContent_Declare(
Corrosion
GIT_REPOSITORY https://github.com/corrosion-rs/corrosion.git
GIT_TAG v0.5 # Optionally specify a commit hash, version tag or branch here
)
FetchContent_MakeAvailable(Corrosion)
corrosion_import_crate(MANIFEST_PATH ${CMAKE_SOURCE_DIR}/bindings/rust/icsneoc2rs/Cargo.toml)
else()
message(STATUS "Not building rust bindings")
endif()
+34
View File
@@ -0,0 +1,34 @@
cmake_minimum_required(VERSION 3.20)
set(PYBIND11_FINDPYTHON ON)
find_package(pybind11 CONFIG REQUIRED)
pybind11_add_module(icsneopy
icsneopy/api/event.cpp
icsneopy/api/eventcallback.cpp
icsneopy/api/eventmanager.cpp
icsneopy/api/version.cpp
icsneopy/device/devicetype.cpp
icsneopy/communication/network.cpp
icsneopy/communication/message/message.cpp
icsneopy/communication/message/canmessage.cpp
icsneopy/communication/message/canerrormessage.cpp
icsneopy/communication/message/ethernetmessage.cpp
icsneopy/communication/message/linmessage.cpp
icsneopy/communication/message/tc10statusmessage.cpp
icsneopy/communication/message/mdiomessage.cpp
icsneopy/communication/message/gptpstatusmessage.cpp
icsneopy/communication/message/ethernetstatusmessage.cpp
icsneopy/communication/message/callback/messagecallback.cpp
icsneopy/communication/message/filter/messagefilter.cpp
icsneopy/device/device.cpp
icsneopy/icsneocpp.cpp
)
target_link_libraries(icsneopy PRIVATE icsneocpp)
install(TARGETS icsneopy LIBRARY DESTINATION icsneopy)
find_program(STUBGEN stubgen REQUIRED)
add_custom_command(TARGET icsneopy POST_BUILD COMMAND ${STUBGEN} -m icsneopy -o .)
install(FILES ${CMAKE_CURRENT_BINARY_DIR}/icsneopy.pyi __init__.py py.typed DESTINATION icsneopy)
+1
View File
@@ -0,0 +1 @@
from .icsneopy import *
+170
View File
@@ -0,0 +1,170 @@
#include <pybind11/pybind11.h>
#include <pybind11/stl.h>
#include <pybind11/functional.h>
#include "icsneo/api/event.h"
namespace icsneo {
void init_event(pybind11::module_& m) {
pybind11::class_<APIEvent, std::shared_ptr<APIEvent>> apiEvent(m, "APIEvent");
pybind11::enum_<APIEvent::Type>(apiEvent, "Type")
.value("Any", APIEvent::Type::Any)
.value("InvalidNeoDevice", APIEvent::Type::InvalidNeoDevice)
.value("RequiredParameterNull", APIEvent::Type::RequiredParameterNull)
.value("BufferInsufficient", APIEvent::Type::BufferInsufficient)
.value("OutputTruncated", APIEvent::Type::OutputTruncated)
.value("ParameterOutOfRange", APIEvent::Type::ParameterOutOfRange)
.value("DeviceCurrentlyOpen", APIEvent::Type::DeviceCurrentlyOpen)
.value("DeviceCurrentlyClosed", APIEvent::Type::DeviceCurrentlyClosed)
.value("DeviceCurrentlyOnline", APIEvent::Type::DeviceCurrentlyOnline)
.value("DeviceCurrentlyOffline", APIEvent::Type::DeviceCurrentlyOffline)
.value("DeviceCurrentlyPolling", APIEvent::Type::DeviceCurrentlyPolling)
.value("DeviceNotCurrentlyPolling", APIEvent::Type::DeviceNotCurrentlyPolling)
.value("UnsupportedTXNetwork", APIEvent::Type::UnsupportedTXNetwork)
.value("MessageMaxLengthExceeded", APIEvent::Type::MessageMaxLengthExceeded)
.value("ValueNotYetPresent", APIEvent::Type::ValueNotYetPresent)
.value("Timeout", APIEvent::Type::Timeout)
.value("WiVINotSupported", APIEvent::Type::WiVINotSupported)
.value("RestrictedEntryFlag", APIEvent::Type::RestrictedEntryFlag)
.value("NotSupported", APIEvent::Type::NotSupported)
.value("PollingMessageOverflow", APIEvent::Type::PollingMessageOverflow)
.value("NoSerialNumber", APIEvent::Type::NoSerialNumber)
.value("IncorrectSerialNumber", APIEvent::Type::IncorrectSerialNumber)
.value("SettingsReadError", APIEvent::Type::SettingsReadError)
.value("SettingsVersionError", APIEvent::Type::SettingsVersionError)
.value("SettingsLengthError", APIEvent::Type::SettingsLengthError)
.value("SettingsChecksumError", APIEvent::Type::SettingsChecksumError)
.value("SettingsNotAvailable", APIEvent::Type::SettingsNotAvailable)
.value("SettingsReadOnly", APIEvent::Type::SettingsReadOnly)
.value("CANSettingsNotAvailable", APIEvent::Type::CANSettingsNotAvailable)
.value("CANFDSettingsNotAvailable", APIEvent::Type::CANFDSettingsNotAvailable)
.value("LSFTCANSettingsNotAvailable", APIEvent::Type::LSFTCANSettingsNotAvailable)
.value("SWCANSettingsNotAvailable", APIEvent::Type::SWCANSettingsNotAvailable)
.value("BaudrateNotFound", APIEvent::Type::BaudrateNotFound)
.value("UnexpectedNetworkType", APIEvent::Type::UnexpectedNetworkType)
.value("DeviceFirmwareOutOfDate", APIEvent::Type::DeviceFirmwareOutOfDate)
.value("SettingsStructureMismatch", APIEvent::Type::SettingsStructureMismatch)
.value("SettingsStructureTruncated", APIEvent::Type::SettingsStructureTruncated)
.value("NoDeviceResponse", APIEvent::Type::NoDeviceResponse)
.value("MessageFormattingError", APIEvent::Type::MessageFormattingError)
.value("CANFDNotSupported", APIEvent::Type::CANFDNotSupported)
.value("RTRNotSupported", APIEvent::Type::RTRNotSupported)
.value("DeviceDisconnected", APIEvent::Type::DeviceDisconnected)
.value("OnlineNotSupported", APIEvent::Type::OnlineNotSupported)
.value("TerminationNotSupportedDevice", APIEvent::Type::TerminationNotSupportedDevice)
.value("TerminationNotSupportedNetwork", APIEvent::Type::TerminationNotSupportedNetwork)
.value("AnotherInTerminationGroupEnabled", APIEvent::Type::AnotherInTerminationGroupEnabled)
.value("NoSerialNumberFW", APIEvent::Type::NoSerialNumberFW)
.value("NoSerialNumber12V", APIEvent::Type::NoSerialNumber12V)
.value("NoSerialNumberFW12V", APIEvent::Type::NoSerialNumberFW12V)
.value("EthPhyRegisterControlNotAvailable", APIEvent::Type::EthPhyRegisterControlNotAvailable)
.value("DiskNotSupported", APIEvent::Type::DiskNotSupported)
.value("EOFReached", APIEvent::Type::EOFReached)
.value("SettingsDefaultsUsed", APIEvent::Type::SettingsDefaultsUsed)
.value("AtomicOperationRetried", APIEvent::Type::AtomicOperationRetried)
.value("AtomicOperationCompletedNonatomically", APIEvent::Type::AtomicOperationCompletedNonatomically)
.value("WiVIStackRefreshFailed", APIEvent::Type::WiVIStackRefreshFailed)
.value("WiVIUploadStackOverflow", APIEvent::Type::WiVIUploadStackOverflow)
.value("I2CMessageExceedsMaxLength", APIEvent::Type::I2CMessageExceedsMaxLength)
.value("A2BMessageIncompleteFrame", APIEvent::Type::A2BMessageIncompleteFrame)
.value("CoreminiUploadVersionMismatch", APIEvent::Type::CoreminiUploadVersionMismatch)
.value("DiskNotConnected", APIEvent::Type::DiskNotConnected)
.value("UnexpectedResponse", APIEvent::Type::UnexpectedResponse)
.value("LiveDataInvalidHandle", APIEvent::Type::LiveDataInvalidHandle)
.value("LiveDataInvalidCommand", APIEvent::Type::LiveDataInvalidCommand)
.value("LiveDataInvalidArgument", APIEvent::Type::LiveDataInvalidArgument)
.value("LiveDataVersionMismatch", APIEvent::Type::LiveDataVersionMismatch)
.value("LiveDataNoDeviceResponse", APIEvent::Type::LiveDataNoDeviceResponse)
.value("LiveDataMaxSignalsReached", APIEvent::Type::LiveDataMaxSignalsReached)
.value("LiveDataCommandFailed", APIEvent::Type::LiveDataCommandFailed)
.value("LiveDataEncoderError", APIEvent::Type::LiveDataEncoderError)
.value("LiveDataDecoderError", APIEvent::Type::LiveDataDecoderError)
.value("LiveDataNotSupported", APIEvent::Type::LiveDataNotSupported)
.value("LINSettingsNotAvailable", APIEvent::Type::LINSettingsNotAvailable)
.value("ModeNotFound", APIEvent::Type::ModeNotFound)
.value("AppErrorParsingFailed", APIEvent::Type::AppErrorParsingFailed)
.value("FailedToRead", APIEvent::Type::FailedToRead)
.value("FailedToWrite", APIEvent::Type::FailedToWrite)
.value("DriverFailedToOpen", APIEvent::Type::DriverFailedToOpen)
.value("DriverFailedToClose", APIEvent::Type::DriverFailedToClose)
.value("PacketChecksumError", APIEvent::Type::PacketChecksumError)
.value("TransmitBufferFull", APIEvent::Type::TransmitBufferFull)
.value("DeviceInUse", APIEvent::Type::DeviceInUse)
.value("PCAPCouldNotStart", APIEvent::Type::PCAPCouldNotStart)
.value("PCAPCouldNotFindDevices", APIEvent::Type::PCAPCouldNotFindDevices)
.value("PacketDecodingError", APIEvent::Type::PacketDecodingError)
.value("SocketFailedToOpen", APIEvent::Type::SocketFailedToOpen)
.value("FailedToBind", APIEvent::Type::FailedToBind)
.value("ErrorSettingSocketOption", APIEvent::Type::ErrorSettingSocketOption)
.value("GetIfAddrsError", APIEvent::Type::GetIfAddrsError)
.value("SendToError", APIEvent::Type::SendToError)
.value("MDIOMessageExceedsMaxLength", APIEvent::Type::MDIOMessageExceedsMaxLength)
.value("FTOK", APIEvent::Type::FTOK)
.value("FTInvalidHandle", APIEvent::Type::FTInvalidHandle)
.value("FTDeviceNotFound", APIEvent::Type::FTDeviceNotFound)
.value("FTDeviceNotOpened", APIEvent::Type::FTDeviceNotOpened)
.value("FTIOError", APIEvent::Type::FTIOError)
.value("FTInsufficientResources", APIEvent::Type::FTInsufficientResources)
.value("FTInvalidParameter", APIEvent::Type::FTInvalidParameter)
.value("FTInvalidBaudRate", APIEvent::Type::FTInvalidBaudRate)
.value("FTDeviceNotOpenedForErase", APIEvent::Type::FTDeviceNotOpenedForErase)
.value("FTDeviceNotOpenedForWrite", APIEvent::Type::FTDeviceNotOpenedForWrite)
.value("FTFailedToWriteDevice", APIEvent::Type::FTFailedToWriteDevice)
.value("FTEEPROMReadFailed", APIEvent::Type::FTEEPROMReadFailed)
.value("FTEEPROMWriteFailed", APIEvent::Type::FTEEPROMWriteFailed)
.value("FTEEPROMEraseFailed", APIEvent::Type::FTEEPROMEraseFailed)
.value("FTEEPROMNotPresent", APIEvent::Type::FTEEPROMNotPresent)
.value("FTEEPROMNotProgrammed", APIEvent::Type::FTEEPROMNotProgrammed)
.value("FTInvalidArgs", APIEvent::Type::FTInvalidArgs)
.value("FTNotSupported", APIEvent::Type::FTNotSupported)
.value("FTNoMoreItems", APIEvent::Type::FTNoMoreItems)
.value("FTTimeout", APIEvent::Type::FTTimeout)
.value("FTOperationAborted", APIEvent::Type::FTOperationAborted)
.value("FTReservedPipe", APIEvent::Type::FTReservedPipe)
.value("FTInvalidControlRequestDirection", APIEvent::Type::FTInvalidControlRequestDirection)
.value("FTInvalidControlRequestType", APIEvent::Type::FTInvalidControlRequestType)
.value("FTIOPending", APIEvent::Type::FTIOPending)
.value("FTIOIncomplete", APIEvent::Type::FTIOIncomplete)
.value("FTHandleEOF", APIEvent::Type::FTHandleEOF)
.value("FTBusy", APIEvent::Type::FTBusy)
.value("FTNoSystemResources", APIEvent::Type::FTNoSystemResources)
.value("FTDeviceListNotReady", APIEvent::Type::FTDeviceListNotReady)
.value("FTDeviceNotConnected", APIEvent::Type::FTDeviceNotConnected)
.value("FTIncorrectDevicePath", APIEvent::Type::FTIncorrectDevicePath)
.value("FTOtherError", APIEvent::Type::FTOtherError)
.value("VSABufferCorrupted", APIEvent::Type::VSABufferCorrupted)
.value("VSATimestampNotFound", APIEvent::Type::VSATimestampNotFound)
.value("VSABufferFormatError", APIEvent::Type::VSABufferFormatError)
.value("VSAMaxReadAttemptsReached", APIEvent::Type::VSAMaxReadAttemptsReached)
.value("VSAByteParseFailure", APIEvent::Type::VSAByteParseFailure)
.value("VSAExtendedMessageError", APIEvent::Type::VSAExtendedMessageError)
.value("VSAOtherError", APIEvent::Type::VSAOtherError)
.value("NoErrorFound", APIEvent::Type::NoErrorFound)
.value("TooManyEvents", APIEvent::Type::TooManyEvents)
.value("Unknown", APIEvent::Type::Unknown);
pybind11::enum_<APIEvent::Severity>(apiEvent, "Severity")
.value("Any", APIEvent::Severity::Any)
.value("EventInfo", APIEvent::Severity::EventInfo)
.value("EventWarning", APIEvent::Severity::EventWarning)
.value("Error", APIEvent::Severity::Error);
apiEvent
.def("get_type", &APIEvent::getType)
.def("get_severity", &APIEvent::getSeverity)
.def("get_description", &APIEvent::getDescription)
.def("describe", &APIEvent::describe)
.def("__repr__", &APIEvent::describe);
pybind11::class_<EventFilter, std::shared_ptr<EventFilter>>(m, "EventFilter")
.def(pybind11::init())
.def(pybind11::init<APIEvent::Type>())
.def(pybind11::init<APIEvent::Severity>())
.def_readwrite("type", &EventFilter::type)
.def_readwrite("severity", &EventFilter::severity)
.def_readwrite("serial", &EventFilter::serial);
}
} // namespace icsneo
@@ -0,0 +1,16 @@
#include <pybind11/pybind11.h>
#include <pybind11/stl.h>
#include <pybind11/functional.h>
#include "icsneo/api/eventcallback.h"
namespace icsneo {
void init_eventcallback(pybind11::module_& m) {
pybind11::class_<EventCallback>(m, "EventCallback")
.def(pybind11::init<EventCallback::fn_eventCallback, EventFilter>())
.def(pybind11::init<EventCallback::fn_eventCallback>());
}
} // namespace icsneo
@@ -0,0 +1,18 @@
#include <pybind11/pybind11.h>
#include <pybind11/stl.h>
#include <pybind11/functional.h>
#include "icsneo/api/eventmanager.h"
namespace icsneo {
void init_eventmanager(pybind11::module_& m) {
pybind11::class_<EventManager>(m, "EventManager")
.def_static("get_instance", &EventManager::GetInstance, pybind11::return_value_policy::reference)
.def("add_event_callback", &EventManager::addEventCallback)
.def("remove_event_callback", &EventManager::removeEventCallback)
.def("get_last_error", &EventManager::getLastError);
}
} // namespace icsneo
+28
View File
@@ -0,0 +1,28 @@
#include <pybind11/pybind11.h>
#include <pybind11/stl.h>
#include <pybind11/functional.h>
#include "icsneo/api/version.h"
#include <sstream>
namespace icsneo {
void init_version(pybind11::module_& m) {
pybind11::class_<neoversion_t>(m, "NeoVersion")
.def_readonly("major", &neoversion_t::major)
.def_readonly("minor", &neoversion_t::minor)
.def_readonly("patch", &neoversion_t::patch)
.def_readonly("metadata", &neoversion_t::metadata)
.def_readonly("buildBranch", &neoversion_t::buildBranch)
.def_readonly("buildTag", &neoversion_t::buildTag)
.def("__repr__", [](const neoversion_t& self) -> std::string {
std::stringstream ss;
ss << self;
return ss.str();
});
m.def("get_version", &GetVersion);
}
} // namespace icsneo
@@ -0,0 +1,15 @@
#include <pybind11/pybind11.h>
#include <pybind11/stl.h>
#include <pybind11/functional.h>
#include "icsneo/communication/message/callback/messagecallback.h"
namespace icsneo {
void init_messagecallback(pybind11::module_& m) {
pybind11::class_<MessageCallback, std::shared_ptr<MessageCallback>>(m, "MessageCallback")
.def(pybind11::init<MessageCallback::fn_messageCallback, std::shared_ptr<MessageFilter>>());
}
} // namespace icsneo
@@ -0,0 +1,38 @@
#include <pybind11/pybind11.h>
#include <pybind11/stl.h>
#include <pybind11/functional.h>
#include "icsneo/communication/message/canerrormessage.h"
namespace icsneo {
void init_errorcodes(pybind11::module_& m) {
pybind11::enum_<CANErrorCode>(m, "CANErrorCode")
.value("NoError", CANErrorCode::NoError)
.value("StuffError", CANErrorCode::StuffError)
.value("FormError", CANErrorCode::FormError)
.value("AckError", CANErrorCode::AckError)
.value("Bit1Error", CANErrorCode::Bit1Error)
.value("Bit0Error", CANErrorCode::Bit0Error)
.value("CRCError", CANErrorCode::CRCError)
.value("NoChange", CANErrorCode::NoChange);
}
void init_canerrormessage(pybind11::module_& m) {
init_errorcodes(m);
pybind11::class_<CANErrorMessage, std::shared_ptr<CANErrorMessage>, Message>(m, "CANErrorMessage")
.def_readonly("network", &CANErrorMessage::network)
.def_readonly("transmitErrorCount", &CANErrorMessage::transmitErrorCount)
.def_readonly("receiveErrorCount", &CANErrorMessage::receiveErrorCount)
.def_readonly("busOff", &CANErrorMessage::busOff)
.def_readonly("errorPassive", &CANErrorMessage::errorPassive)
.def_readonly("errorWarn", &CANErrorMessage::errorWarn)
.def_readonly("dataErrorCode", &CANErrorMessage::dataErrorCode)
.def_readonly("errorCode", &CANErrorMessage::errorCode);
m.attr("CANErrorCountMessage") = m.attr("CANErrorMessage");
}
} // namespace icsneo
@@ -0,0 +1,22 @@
#include <pybind11/pybind11.h>
#include <pybind11/stl.h>
#include <pybind11/functional.h>
#include "icsneo/communication/message/canmessage.h"
namespace icsneo {
void init_canmessage(pybind11::module_& m) {
pybind11::class_<CANMessage, std::shared_ptr<CANMessage>, BusMessage>(m, "CANMessage")
.def(pybind11::init())
.def_readwrite("arbid", &CANMessage::arbid)
.def_readwrite("dlcOnWire", &CANMessage::dlcOnWire)
.def_readwrite("isRemote", &CANMessage::isRemote)
.def_readwrite("isExtended", &CANMessage::isExtended)
.def_readwrite("isCANFD", &CANMessage::isCANFD)
.def_readwrite("baudrateSwitch", &CANMessage::baudrateSwitch)
.def_readwrite("errorStateIndicator", &CANMessage::errorStateIndicator);
}
} // namespace icsneo
@@ -0,0 +1,27 @@
#include <pybind11/pybind11.h>
#include <pybind11/stl.h>
#include <pybind11/functional.h>
#include "icsneo/communication/message/ethernetmessage.h"
namespace icsneo {
void init_ethernetmessage(pybind11::module_& m) {
pybind11::class_<MACAddress>(m, "MACAddress")
.def("to_string", &MACAddress::toString)
.def("__repr__", &MACAddress::toString);
pybind11::class_<EthernetMessage, std::shared_ptr<EthernetMessage>, BusMessage>(m, "EthernetMessage")
.def(pybind11::init())
.def_readwrite("preemptionEnabled", &EthernetMessage::preemptionEnabled)
.def_readwrite("preemptionFlags", &EthernetMessage::preemptionFlags)
.def_readwrite("fcs", &EthernetMessage::fcs)
.def_readwrite("frameTooShort", &EthernetMessage::frameTooShort)
.def_readwrite("noPadding", &EthernetMessage::noPadding)
.def("get_destination_mac", &EthernetMessage::getDestinationMAC, pybind11::return_value_policy::reference)
.def("get_source_mac", &EthernetMessage::getSourceMAC, pybind11::return_value_policy::reference)
.def("get_ether_type", &EthernetMessage::getEtherType);
}
} // namespace icsneo
@@ -0,0 +1,35 @@
#include <pybind11/pybind11.h>
#include <pybind11/stl.h>
#include <pybind11/functional.h>
#include "icsneo/communication/message/ethernetstatusmessage.h"
namespace icsneo {
void init_ethernetstatusmessage(pybind11::module_& m) {
pybind11::class_<EthernetStatusMessage, std::shared_ptr<EthernetStatusMessage>, Message> ethernetStatusMessage(m, "EthernetStatusMessage");
pybind11::enum_<EthernetStatusMessage::LinkSpeed>(ethernetStatusMessage, "LinkSpeed")
.value("LinkSpeedAuto", EthernetStatusMessage::LinkSpeed::LinkSpeedAuto)
.value("LinkSpeed10", EthernetStatusMessage::LinkSpeed::LinkSpeed10)
.value("LinkSpeed100", EthernetStatusMessage::LinkSpeed::LinkSpeed100)
.value("LinkSpeed1000", EthernetStatusMessage::LinkSpeed::LinkSpeed1000)
.value("LinkSpeed2500", EthernetStatusMessage::LinkSpeed::LinkSpeed2500)
.value("LinkSpeed5000", EthernetStatusMessage::LinkSpeed::LinkSpeed5000)
.value("LinkSpeed10000", EthernetStatusMessage::LinkSpeed::LinkSpeed10000);
pybind11::enum_<EthernetStatusMessage::LinkMode>(ethernetStatusMessage, "LinkMode")
.value("LinkModeAuto", EthernetStatusMessage::LinkMode::LinkModeAuto)
.value("LinkModeMaster", EthernetStatusMessage::LinkMode::LinkModeMaster)
.value("LinkModeSlave", EthernetStatusMessage::LinkMode::LinkModeSlave)
.value("LinkModeInvalid", EthernetStatusMessage::LinkMode::LinkModeInvalid);
ethernetStatusMessage
.def_readonly("network", &EthernetStatusMessage::network)
.def_readonly("state", &EthernetStatusMessage::state)
.def_readonly("speed", &EthernetStatusMessage::speed)
.def_readonly("duplex", &EthernetStatusMessage::duplex)
.def_readonly("mode", &EthernetStatusMessage::mode);
}
} // namespace icsneo
@@ -0,0 +1,17 @@
#include <pybind11/pybind11.h>
#include <pybind11/stl.h>
#include <pybind11/functional.h>
#include "icsneo/communication/message/filter/messagefilter.h"
namespace icsneo {
void init_messagefilter(pybind11::module_& m) {
pybind11::class_<MessageFilter, std::shared_ptr<MessageFilter>>(m, "MessageFilter")
.def(pybind11::init())
.def(pybind11::init<Message::Type>())
.def(pybind11::init<Network::NetID>());
}
} // namespace icsneo
@@ -0,0 +1,79 @@
#include <pybind11/pybind11.h>
#include <pybind11/stl.h>
#include <pybind11/functional.h>
#include "icsneo/communication/message/gptpstatusmessage.h"
namespace icsneo {
void init_gptpstatusmessage(pybind11::module_& m) {
pybind11::class_<GPTPStatus, std::shared_ptr<GPTPStatus>, Message> gptpStatus(m, "GPTPStatus");
pybind11::class_<GPTPStatus::Timestamp>(gptpStatus, "Timestamp")
.def_readonly("seconds", &GPTPStatus::Timestamp::seconds)
.def_readonly("nanoseconds", &GPTPStatus::Timestamp::nanoseconds)
.def("to_seconds", &GPTPStatus::Timestamp::toSeconds, pybind11::call_guard<pybind11::gil_scoped_release>());
pybind11::class_<GPTPStatus::ScaledNanoSeconds>(gptpStatus, "ScaledNanoSeconds")
.def_readonly("nanosecondsMSB", &GPTPStatus::ScaledNanoSeconds::nanosecondsMSB)
.def_readonly("nanosecondsLSB", &GPTPStatus::ScaledNanoSeconds::nanosecondsLSB)
.def_readonly("fractionalNanoseconds", &GPTPStatus::ScaledNanoSeconds::fractionalNanoseconds);
pybind11::class_<GPTPStatus::PortID>(gptpStatus, "PortID")
.def_readonly("clockIdentity", &GPTPStatus::PortID::clockIdentity)
.def_readonly("portNumber", &GPTPStatus::PortID::portNumber);
pybind11::class_<GPTPStatus::ClockQuality>(gptpStatus, "ClockQuality")
.def_readonly("clockClass", &GPTPStatus::ClockQuality::clockClass)
.def_readonly("clockAccuracy", &GPTPStatus::ClockQuality::clockAccuracy)
.def_readonly("offsetScaledLogVariance", &GPTPStatus::ClockQuality::offsetScaledLogVariance);
pybind11::class_<GPTPStatus::SystemID>(gptpStatus, "SystemID")
.def_readonly("priority1", &GPTPStatus::SystemID::priority1)
.def_readonly("clockQuality", &GPTPStatus::SystemID::clockQuality)
.def_readonly("priority2", &GPTPStatus::SystemID::priority2)
.def_readonly("clockID", &GPTPStatus::SystemID::clockID);
pybind11::class_<GPTPStatus::PriorityVector>(gptpStatus, "PriorityVector")
.def_readonly("sysID", &GPTPStatus::PriorityVector::sysID)
.def_readonly("stepsRemoved", &GPTPStatus::PriorityVector::stepsRemoved)
.def_readonly("portID", &GPTPStatus::PriorityVector::portID)
.def_readonly("portNumber", &GPTPStatus::PriorityVector::portNumber);
pybind11::class_<GPTPStatus::ParentDS>(gptpStatus, "ParentDS")
.def_readonly("parentPortIdentity", &GPTPStatus::ParentDS::parentPortIdentity)
.def_readonly("cumulativeRateRatio", &GPTPStatus::ParentDS::cumulativeRateRatio)
.def_readonly("grandmasterIdentity", &GPTPStatus::ParentDS::grandmasterIdentity)
.def_readonly("gmClockQualityClockClass", &GPTPStatus::ParentDS::gmClockQualityClockClass)
.def_readonly("gmClockQualityClockAccuracy", &GPTPStatus::ParentDS::gmClockQualityClockAccuracy)
.def_readonly("gmClockQualityOffsetScaledLogVariance", &GPTPStatus::ParentDS::gmClockQualityOffsetScaledLogVariance)
.def_readonly("gmPriority1", &GPTPStatus::ParentDS::gmPriority1)
.def_readonly("gmPriority2", &GPTPStatus::ParentDS::gmPriority2);
pybind11::class_<GPTPStatus::CurrentDS>(gptpStatus, "CurrentDS")
.def_readonly("stepsRemoved", &GPTPStatus::CurrentDS::stepsRemoved)
.def_readonly("offsetFromMaster", &GPTPStatus::CurrentDS::offsetFromMaster)
.def_readonly("lastgmPhaseChange", &GPTPStatus::CurrentDS::lastgmPhaseChange)
.def_readonly("lastgmFreqChange", &GPTPStatus::CurrentDS::lastgmFreqChange)
.def_readonly("gmTimeBaseIndicator", &GPTPStatus::CurrentDS::gmTimeBaseIndicator)
.def_readonly("gmChangeCount", &GPTPStatus::CurrentDS::gmChangeCount)
.def_readonly("timeOfLastgmChangeEvent", &GPTPStatus::CurrentDS::timeOfLastgmChangeEvent)
.def_readonly("timeOfLastgmPhaseChangeEvent", &GPTPStatus::CurrentDS::timeOfLastgmPhaseChangeEvent)
.def_readonly("timeOfLastgmFreqChangeEvent", &GPTPStatus::CurrentDS::timeOfLastgmFreqChangeEvent);
gptpStatus.def_readonly("currentTime", &GPTPStatus::currentTime)
.def_readonly("gmPriority", &GPTPStatus::gmPriority)
.def_readonly("msOffsetNs", &GPTPStatus::msOffsetNs)
.def_readonly("isSync", &GPTPStatus::isSync)
.def_readonly("linkStatus", &GPTPStatus::linkStatus)
.def_readonly("linkDelayNS", &GPTPStatus::linkDelayNS)
.def_readonly("selectedRole", &GPTPStatus::selectedRole)
.def_readonly("asCapable", &GPTPStatus::asCapable)
.def_readonly("isSyntonized", &GPTPStatus::isSyntonized)
.def_readonly("lastRXSyncTS", &GPTPStatus::lastRXSyncTS)
.def_readonly("currentDS", &GPTPStatus::currentDS)
.def_readonly("parentDS", &GPTPStatus::parentDS);
}
} // namespace icsneo
@@ -0,0 +1,59 @@
#include <pybind11/pybind11.h>
#include <pybind11/stl.h>
#include <pybind11/functional.h>
#include "icsneo/communication/message/linmessage.h"
namespace icsneo {
void init_linmessage(pybind11::module_& m) {
pybind11::class_<LINErrorFlags>(m, "LINErrorFlags")
.def_readwrite("ErrRxBreakOnly", &LINErrorFlags::ErrRxBreakOnly)
.def_readwrite("ErrRxBreakSyncOnly", &LINErrorFlags::ErrRxBreakSyncOnly)
.def_readwrite("ErrTxRxMismatch", &LINErrorFlags::ErrTxRxMismatch)
.def_readwrite("ErrRxBreakNotZero", &LINErrorFlags::ErrRxBreakNotZero)
.def_readwrite("ErrRxBreakTooShort", &LINErrorFlags::ErrRxBreakTooShort)
.def_readwrite("ErrRxSyncNot55", &LINErrorFlags::ErrRxSyncNot55)
.def_readwrite("ErrRxDataLenOver8", &LINErrorFlags::ErrRxDataLenOver8)
.def_readwrite("ErrFrameSync", &LINErrorFlags::ErrFrameSync)
.def_readwrite("ErrFrameMessageID", &LINErrorFlags::ErrFrameMessageID)
.def_readwrite("ErrFrameResponderData", &LINErrorFlags::ErrFrameResponderData)
.def_readwrite("ErrChecksumMatch", &LINErrorFlags::ErrChecksumMatch);
pybind11::class_<LINStatusFlags>(m, "LINStatusFlags")
.def_readwrite("TxChecksumEnhanced", &LINStatusFlags::TxChecksumEnhanced)
.def_readwrite("TxCommander", &LINStatusFlags::TxCommander)
.def_readwrite("TxResponder", &LINStatusFlags::TxResponder)
.def_readwrite("TxAborted", &LINStatusFlags::TxAborted)
.def_readwrite("UpdateResponderOnce", &LINStatusFlags::UpdateResponderOnce)
.def_readwrite("HasUpdatedResponderOnce", &LINStatusFlags::HasUpdatedResponderOnce)
.def_readwrite("BusRecovered", &LINStatusFlags::BusRecovered)
.def_readwrite("BreakOnly", &LINStatusFlags::BreakOnly);
pybind11::class_<LINMessage, std::shared_ptr<LINMessage>, BusMessage> linMessage(m, "LINMessage");
pybind11::enum_<LINMessage::Type>(linMessage, "Type")
.value("NOT_SET", LINMessage::Type::NOT_SET)
.value("LIN_COMMANDER_MSG", LINMessage::Type::LIN_COMMANDER_MSG)
.value("LIN_HEADER_ONLY", LINMessage::Type::LIN_HEADER_ONLY)
.value("LIN_BREAK_ONLY", LINMessage::Type::LIN_BREAK_ONLY)
.value("LIN_SYNC_ONLY", LINMessage::Type::LIN_SYNC_ONLY)
.value("LIN_UPDATE_RESPONDER", LINMessage::Type::LIN_UPDATE_RESPONDER)
.value("LIN_ERROR", LINMessage::Type::LIN_ERROR);
linMessage
.def(pybind11::init<>())
.def(pybind11::init<uint8_t>())
.def_static("calc_checksum", &LINMessage::calcChecksum)
.def("calc_protected_id", &LINMessage::calcProtectedID)
.def_readwrite("ID", &LINMessage::ID)
.def_readwrite("protectedID", &LINMessage::protectedID)
.def_readwrite("checksum", &LINMessage::checksum)
.def_readwrite("linMsgType", &LINMessage::linMsgType)
.def_readwrite("isEnhancedChecksum", &LINMessage::isEnhancedChecksum)
.def_readwrite("errFlags", &LINMessage::errFlags)
.def_readwrite("statusFlags", &LINMessage::statusFlags);
}
} // namespace icsneo
@@ -0,0 +1,35 @@
#include <pybind11/pybind11.h>
#include <pybind11/stl.h>
#include <pybind11/functional.h>
#include "icsneo/communication/message/mdiomessage.h"
namespace icsneo {
void init_mdiomessage(pybind11::module_& m) {
pybind11::class_<MDIOMessage, std::shared_ptr<MDIOMessage>, BusMessage> mdioMessage(m, "MDIOMessage");
pybind11::enum_<MDIOMessage::Clause>(mdioMessage, "Clause")
.value("Clause45", MDIOMessage::Clause::Clause45)
.value("Clause22", MDIOMessage::Clause::Clause22);
pybind11::enum_<MDIOMessage::Direction>(mdioMessage, "Direction")
.value("Write", MDIOMessage::Direction::Write)
.value("Read", MDIOMessage::Direction::Read);
mdioMessage
.def(pybind11::init())
.def_readwrite("isTXMsg", &MDIOMessage::isTXMsg)
.def_readwrite("txTimeout", &MDIOMessage::txTimeout)
.def_readwrite("txAborted", &MDIOMessage::txAborted)
.def_readwrite("txInvalidBus", &MDIOMessage::txInvalidBus)
.def_readwrite("txInvalidPhyAddr", &MDIOMessage::txInvalidPhyAddr)
.def_readwrite("txInvalidRegAddr", &MDIOMessage::txInvalidRegAddr)
.def_readwrite("txInvalidClause", &MDIOMessage::txInvalidClause)
.def_readwrite("txInvalidOpcode", &MDIOMessage::txInvalidOpcode)
.def_readwrite("phyAddress", &MDIOMessage::phyAddress)
.def_readwrite("devAddress", &MDIOMessage::devAddress)
.def_readwrite("regAddress", &MDIOMessage::regAddress)
.def_readwrite("direction", &MDIOMessage::direction)
.def_readwrite("clause", &MDIOMessage::clause);
}
} // namespace icsneo
@@ -0,0 +1,54 @@
#include <pybind11/pybind11.h>
#include <pybind11/stl.h>
#include <pybind11/functional.h>
#include "icsneo/communication/message/message.h"
namespace icsneo {
void init_message(pybind11::module_& m) {
pybind11::class_<Message, std::shared_ptr<Message>> message(m, "Message");
pybind11::enum_<Message::Type>(message, "Type")
.value("BusMessage", Message::Type::BusMessage)
.value("CANErrorCount", Message::Type::CANErrorCount)
.value("CANError", Message::Type::CANError)
.value("LINHeaderOnly", Message::Type::LINHeaderOnly)
.value("LINBreak", Message::Type::LINBreak)
.value("Invalid", Message::Type::Invalid)
.value("InternalMessage", Message::Type::InternalMessage)
.value("ReadSettings", Message::Type::ReadSettings)
.value("ResetStatus", Message::Type::ResetStatus)
.value("DeviceVersion", Message::Type::DeviceVersion)
.value("Main51", Message::Type::Main51)
.value("FlexRayControl", Message::Type::FlexRayControl)
.value("EthernetPhyRegister", Message::Type::EthernetPhyRegister)
.value("LogicalDiskInfo", Message::Type::LogicalDiskInfo)
.value("ExtendedResponse", Message::Type::ExtendedResponse)
.value("WiVICommandResponse", Message::Type::WiVICommandResponse)
.value("ScriptStatus", Message::Type::ScriptStatus)
.value("ComponentVersions", Message::Type::ComponentVersions)
.value("SupportedFeatures", Message::Type::SupportedFeatures)
.value("GenericBinaryStatus", Message::Type::GenericBinaryStatus)
.value("LiveData", Message::Type::LiveData)
.value("HardwareInfo", Message::Type::HardwareInfo)
.value("TC10Status", Message::Type::TC10Status)
.value("AppError", Message::Type::AppError)
.value("GPTPStatus", Message::Type::GPTPStatus)
.value("EthernetStatus", Message::Type::EthernetStatus);
message.def(pybind11::init<Message::Type>());
message.def_readonly("type", &Message::type);
message.def_readwrite("timestamp", &Message::timestamp);
pybind11::class_<InternalMessage, std::shared_ptr<InternalMessage>, Message>(m, "InternalMessage")
.def_readwrite("network", &InternalMessage::network)
.def_readwrite("data", &InternalMessage::data);
pybind11::class_<BusMessage, std::shared_ptr<BusMessage>, InternalMessage>(m, "BusMessage")
.def_readwrite("description", &BusMessage::description)
.def_readwrite("transmitted", &BusMessage::transmitted)
.def_readwrite("error", &BusMessage::error);
}
} // namespace icsneo
@@ -0,0 +1,25 @@
#include <pybind11/pybind11.h>
#include <pybind11/stl.h>
#include <pybind11/functional.h>
#include "icsneo/communication/message/tc10statusmessage.h"
namespace icsneo {
void init_tc10statusmessage(pybind11::module_& m) {
pybind11::enum_<TC10WakeStatus>(m, "TC10WakeStatus")
.value("NoWakeReceived", TC10WakeStatus::NoWakeReceived)
.value("WakeReceived", TC10WakeStatus::WakeReceived);
pybind11::enum_<TC10SleepStatus>(m, "TC10SleepStatus")
.value("NoSleepReceived", TC10SleepStatus::NoSleepReceived)
.value("SleepReceived", TC10SleepStatus::SleepReceived)
.value("SleepFailed", TC10SleepStatus::SleepFailed)
.value("SleepAborted", TC10SleepStatus::SleepAborted);
pybind11::class_<TC10StatusMessage, std::shared_ptr<TC10StatusMessage>, Message>(m, "TC10StatusMessage")
.def_readonly("wakeStatus", &TC10StatusMessage::wakeStatus)
.def_readonly("sleepStatus", &TC10StatusMessage::sleepStatus);
}
} // namespace icsneo
@@ -0,0 +1,197 @@
#include <pybind11/pybind11.h>
#include <pybind11/stl.h>
#include <pybind11/functional.h>
#include "icsneo/communication/network.h"
namespace icsneo {
void init_network(pybind11::module_& m) {
pybind11::class_<Network> network(m, "Network");
pybind11::enum_<Network::NetID>(network, "NetID")
.value("Device", Network::NetID::Device)
.value("HSCAN", Network::NetID::HSCAN)
.value("MSCAN", Network::NetID::MSCAN)
.value("SWCAN", Network::NetID::SWCAN)
.value("LSFTCAN", Network::NetID::LSFTCAN)
.value("FordSCP", Network::NetID::FordSCP)
.value("J1708", Network::NetID::J1708)
.value("Aux", Network::NetID::Aux)
.value("J1850VPW", Network::NetID::J1850VPW)
.value("ISO9141", Network::NetID::ISO9141)
.value("DiskData", Network::NetID::DiskData)
.value("Main51", Network::NetID::Main51)
.value("RED", Network::NetID::RED)
.value("SCI", Network::NetID::SCI)
.value("ISO9141_2", Network::NetID::ISO9141_2)
.value("ISO14230", Network::NetID::ISO14230)
.value("LIN", Network::NetID::LIN)
.value("OP_Ethernet1", Network::NetID::OP_Ethernet1)
.value("OP_Ethernet2", Network::NetID::OP_Ethernet2)
.value("OP_Ethernet3", Network::NetID::OP_Ethernet3)
.value("RED_EXT_MEMORYREAD", Network::NetID::RED_EXT_MEMORYREAD)
.value("RED_INT_MEMORYREAD", Network::NetID::RED_INT_MEMORYREAD)
.value("RED_DFLASH_READ", Network::NetID::RED_DFLASH_READ)
.value("NeoMemorySDRead", Network::NetID::NeoMemorySDRead)
.value("CAN_ERRBITS", Network::NetID::CAN_ERRBITS)
.value("NeoMemoryWriteDone", Network::NetID::NeoMemoryWriteDone)
.value("RED_WAVE_CAN1_LOGICAL", Network::NetID::RED_WAVE_CAN1_LOGICAL)
.value("RED_WAVE_CAN2_LOGICAL", Network::NetID::RED_WAVE_CAN2_LOGICAL)
.value("RED_WAVE_LIN1_LOGICAL", Network::NetID::RED_WAVE_LIN1_LOGICAL)
.value("RED_WAVE_LIN2_LOGICAL", Network::NetID::RED_WAVE_LIN2_LOGICAL)
.value("RED_WAVE_LIN1_ANALOG", Network::NetID::RED_WAVE_LIN1_ANALOG)
.value("RED_WAVE_LIN2_ANALOG", Network::NetID::RED_WAVE_LIN2_ANALOG)
.value("RED_WAVE_MISC_ANALOG", Network::NetID::RED_WAVE_MISC_ANALOG)
.value("RED_WAVE_MISCDIO2_LOGICAL", Network::NetID::RED_WAVE_MISCDIO2_LOGICAL)
.value("RED_NETWORK_COM_ENABLE_EX", Network::NetID::RED_NETWORK_COM_ENABLE_EX)
.value("RED_NEOVI_NETWORK", Network::NetID::RED_NEOVI_NETWORK)
.value("RED_READ_BAUD_SETTINGS", Network::NetID::RED_READ_BAUD_SETTINGS)
.value("RED_OLDFORMAT", Network::NetID::RED_OLDFORMAT)
.value("RED_SCOPE_CAPTURE", Network::NetID::RED_SCOPE_CAPTURE)
.value("RED_HARDWARE_EXCEP", Network::NetID::RED_HARDWARE_EXCEP)
.value("RED_GET_RTC", Network::NetID::RED_GET_RTC)
.value("ISO9141_3", Network::NetID::ISO9141_3)
.value("HSCAN2", Network::NetID::HSCAN2)
.value("HSCAN3", Network::NetID::HSCAN3)
.value("OP_Ethernet4", Network::NetID::OP_Ethernet4)
.value("OP_Ethernet5", Network::NetID::OP_Ethernet5)
.value("ISO9141_4", Network::NetID::ISO9141_4)
.value("LIN2", Network::NetID::LIN2)
.value("LIN3", Network::NetID::LIN3)
.value("LIN4", Network::NetID::LIN4)
.value("RED_App_Error", Network::NetID::RED_App_Error)
.value("CGI", Network::NetID::CGI)
.value("Reset_Status", Network::NetID::Reset_Status)
.value("FB_Status", Network::NetID::FB_Status)
.value("App_Signal_Status", Network::NetID::App_Signal_Status)
.value("Read_Datalink_Cm_Tx_Msg", Network::NetID::Read_Datalink_Cm_Tx_Msg)
.value("Read_Datalink_Cm_Rx_Msg", Network::NetID::Read_Datalink_Cm_Rx_Msg)
.value("Logging_Overflow", Network::NetID::Logging_Overflow)
.value("ReadSettings", Network::NetID::ReadSettings)
.value("HSCAN4", Network::NetID::HSCAN4)
.value("HSCAN5", Network::NetID::HSCAN5)
.value("RS232", Network::NetID::RS232)
.value("UART", Network::NetID::UART)
.value("UART2", Network::NetID::UART2)
.value("UART3", Network::NetID::UART3)
.value("UART4", Network::NetID::UART4)
.value("SWCAN2", Network::NetID::SWCAN2)
.value("Ethernet_DAQ", Network::NetID::Ethernet_DAQ)
.value("Data_To_Host", Network::NetID::Data_To_Host)
.value("TextAPI_To_Host", Network::NetID::TextAPI_To_Host)
.value("SPI1", Network::NetID::SPI1)
.value("OP_Ethernet6", Network::NetID::OP_Ethernet6)
.value("Red_VBat", Network::NetID::Red_VBat)
.value("OP_Ethernet7", Network::NetID::OP_Ethernet7)
.value("OP_Ethernet8", Network::NetID::OP_Ethernet8)
.value("OP_Ethernet9", Network::NetID::OP_Ethernet9)
.value("OP_Ethernet10", Network::NetID::OP_Ethernet10)
.value("OP_Ethernet11", Network::NetID::OP_Ethernet11)
.value("FlexRay1a", Network::NetID::FlexRay1a)
.value("FlexRay1b", Network::NetID::FlexRay1b)
.value("FlexRay2a", Network::NetID::FlexRay2a)
.value("FlexRay2b", Network::NetID::FlexRay2b)
.value("LIN5", Network::NetID::LIN5)
.value("FlexRay", Network::NetID::FlexRay)
.value("FlexRay2", Network::NetID::FlexRay2)
.value("OP_Ethernet12", Network::NetID::OP_Ethernet12)
.value("I2C", Network::NetID::I2C)
.value("MOST25", Network::NetID::MOST25)
.value("MOST50", Network::NetID::MOST50)
.value("MOST150", Network::NetID::MOST150)
.value("Ethernet", Network::NetID::Ethernet)
.value("GMFSA", Network::NetID::GMFSA)
.value("TCP", Network::NetID::TCP)
.value("HSCAN6", Network::NetID::HSCAN6)
.value("HSCAN7", Network::NetID::HSCAN7)
.value("LIN6", Network::NetID::LIN6)
.value("LSFTCAN2", Network::NetID::LSFTCAN2)
.value("LogicalDiskInfo", Network::NetID::LogicalDiskInfo)
.value("WiVICommand", Network::NetID::WiVICommand)
.value("ScriptStatus", Network::NetID::ScriptStatus)
.value("EthPHYControl", Network::NetID::EthPHYControl)
.value("ExtendedCommand", Network::NetID::ExtendedCommand)
.value("ExtendedData", Network::NetID::ExtendedData)
.value("FlexRayControl", Network::NetID::FlexRayControl)
.value("CoreMiniPreLoad", Network::NetID::CoreMiniPreLoad)
.value("HW_COM_Latency_Test", Network::NetID::HW_COM_Latency_Test)
.value("DeviceStatus", Network::NetID::DeviceStatus)
.value("UDP", Network::NetID::UDP)
.value("ForwardedMessage", Network::NetID::ForwardedMessage)
.value("I2C2", Network::NetID::I2C2)
.value("I2C3", Network::NetID::I2C3)
.value("I2C4", Network::NetID::I2C4)
.value("Ethernet2", Network::NetID::Ethernet2)
.value("A2B1", Network::NetID::A2B1)
.value("A2B2", Network::NetID::A2B2)
.value("Ethernet3", Network::NetID::Ethernet3)
.value("WBMS", Network::NetID::WBMS)
.value("DWCAN9", Network::NetID::DWCAN9)
.value("DWCAN10", Network::NetID::DWCAN10)
.value("DWCAN11", Network::NetID::DWCAN11)
.value("DWCAN12", Network::NetID::DWCAN12)
.value("DWCAN13", Network::NetID::DWCAN13)
.value("DWCAN14", Network::NetID::DWCAN14)
.value("DWCAN15", Network::NetID::DWCAN15)
.value("DWCAN16", Network::NetID::DWCAN16)
.value("LIN7", Network::NetID::LIN7)
.value("LIN8", Network::NetID::LIN8)
.value("SPI2", Network::NetID::SPI2)
.value("MDIO1", Network::NetID::MDIO1)
.value("MDIO2", Network::NetID::MDIO2)
.value("MDIO3", Network::NetID::MDIO3)
.value("MDIO4", Network::NetID::MDIO4)
.value("MDIO5", Network::NetID::MDIO5)
.value("MDIO6", Network::NetID::MDIO6)
.value("MDIO7", Network::NetID::MDIO7)
.value("MDIO8", Network::NetID::MDIO8)
.value("OP_Ethernet13", Network::NetID::OP_Ethernet13)
.value("OP_Ethernet14", Network::NetID::OP_Ethernet14)
.value("OP_Ethernet15", Network::NetID::OP_Ethernet15)
.value("OP_Ethernet16", Network::NetID::OP_Ethernet16)
.value("SPI3", Network::NetID::SPI3)
.value("SPI4", Network::NetID::SPI4)
.value("SPI5", Network::NetID::SPI5)
.value("SPI6", Network::NetID::SPI6)
.value("SPI7", Network::NetID::SPI7)
.value("SPI8", Network::NetID::SPI8)
.value("LIN9", Network::NetID::LIN9)
.value("LIN10", Network::NetID::LIN10)
.value("LIN11", Network::NetID::LIN11)
.value("LIN12", Network::NetID::LIN12)
.value("LIN13", Network::NetID::LIN13)
.value("LIN14", Network::NetID::LIN14)
.value("LIN15", Network::NetID::LIN15)
.value("LIN16", Network::NetID::LIN16)
.value("Any", Network::NetID::Any)
.value("Invalid", Network::NetID::Invalid);
pybind11::enum_<Network::Type>(network, "Type")
.value("Invalid", Network::Type::Invalid)
.value("Internal", Network::Type::Internal)
.value("CAN", Network::Type::CAN)
.value("LIN", Network::Type::LIN)
.value("FlexRay", Network::Type::FlexRay)
.value("MOST", Network::Type::MOST)
.value("Ethernet", Network::Type::Ethernet)
.value("LSFTCAN", Network::Type::LSFTCAN)
.value("SWCAN", Network::Type::SWCAN)
.value("ISO9141", Network::Type::ISO9141)
.value("I2C", Network::Type::I2C)
.value("A2B", Network::Type::A2B)
.value("SPI", Network::Type::SPI)
.value("MDIO", Network::Type::MDIO)
.value("Any", Network::Type::Any)
.value("Other", Network::Type::Other);
network
.def(pybind11::init<Network::NetID>())
.def("__repr__", [](Network& self) { return Network::GetNetIDString(self.getNetID()); })
.def_static("get_net_id_string", &Network::GetNetIDString, pybind11::arg("netid"), pybind11::arg("expand") = true)
.def("get_net_id", &Network::getNetID)
.def("get_type", &Network::getType);
}
} // namespace icsneo
@@ -0,0 +1,47 @@
#include <pybind11/pybind11.h>
#include <pybind11/stl.h>
#include <pybind11/functional.h>
#include <pybind11/chrono.h>
#include "icsneo/device/device.h"
namespace icsneo {
void init_device(pybind11::module_& m) {
pybind11::class_<Device, std::shared_ptr<Device>>(m, "Device")
.def("get_type", &Device::getType)
.def("get_serial", &Device::getSerial)
.def("get_serial_number", &Device::getSerialNumber)
.def("get_product_name", &Device::getProductName)
.def("open", [](Device& device) { return device.open(); }, pybind11::call_guard<pybind11::gil_scoped_release>())
.def("close", &Device::close, pybind11::call_guard<pybind11::gil_scoped_release>())
.def("is_open", &Device::isOpen)
.def("go_online", &Device::goOnline, pybind11::call_guard<pybind11::gil_scoped_release>())
.def("go_offline", &Device::goOffline, pybind11::call_guard<pybind11::gil_scoped_release>())
.def("is_online", &Device::isOnline)
.def("enable_message_polling", &Device::enableMessagePolling, pybind11::call_guard<pybind11::gil_scoped_release>())
.def("disable_message_polling", &Device::disableMessagePolling, pybind11::call_guard<pybind11::gil_scoped_release>())
.def("is_message_polling_enabled", &Device::isMessagePollingEnabled)
.def("get_messages", [](Device& device) { return device.getMessages(); }, pybind11::call_guard<pybind11::gil_scoped_release>())
.def("get_current_message_count", &Device::getCurrentMessageCount)
.def("get_polling_message_limit", &Device::getPollingMessageLimit)
.def("set_polling_message_limit", &Device::setPollingMessageLimit)
.def("add_message_callback", &Device::addMessageCallback, pybind11::call_guard<pybind11::gil_scoped_release>())
.def("remove_message_callback", &Device::removeMessageCallback, pybind11::call_guard<pybind11::gil_scoped_release>())
.def("transmit", pybind11::overload_cast<std::shared_ptr<BusMessage>>(&Device::transmit), pybind11::call_guard<pybind11::gil_scoped_release>())
.def("get_supported_rx_networks", &Device::getSupportedRXNetworks, pybind11::return_value_policy::reference)
.def("get_supported_tx_networks", &Device::getSupportedTXNetworks, pybind11::return_value_policy::reference)
.def("get_rtc", &Device::getRTC, pybind11::call_guard<pybind11::gil_scoped_release>())
.def("set_rtc", &Device::setRTC, pybind11::call_guard<pybind11::gil_scoped_release>())
.def("describe", &Device::describe)
.def("is_online_supported", &Device::isOnlineSupported)
.def("supports_tc10", &Device::supportsTC10)
.def("request_tc10_wake", &Device::requestTC10Wake, pybind11::call_guard<pybind11::gil_scoped_release>())
.def("request_tc10_sleep", &Device::requestTC10Sleep, pybind11::call_guard<pybind11::gil_scoped_release>())
.def("get_tc10_status", &Device::getTC10Status, 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("__repr__", &Device::describe);
}
} // namespace icsneo
@@ -0,0 +1,72 @@
#include <pybind11/pybind11.h>
#include <pybind11/stl.h>
#include <pybind11/functional.h>
#include "icsneo/device/devicetype.h"
namespace icsneo {
void init_devicetype(pybind11::module_& m) {
pybind11::class_<DeviceType> deviceType(m, "DeviceType");
pybind11::enum_<DeviceType::Enum>(deviceType, "Enum")
.value("Unknown", DeviceType::Enum::Unknown)
.value("BLUE", DeviceType::Enum::BLUE)
.value("ECU_AVB", DeviceType::Enum::ECU_AVB)
.value("RADSupermoon", DeviceType::Enum::RADSupermoon)
.value("DW_VCAN", DeviceType::Enum::DW_VCAN)
.value("RADMoon2", DeviceType::Enum::RADMoon2)
.value("RADMars", DeviceType::Enum::RADMars)
.value("VCAN4_1", DeviceType::Enum::VCAN4_1)
.value("FIRE", DeviceType::Enum::FIRE)
.value("RADPluto", DeviceType::Enum::RADPluto)
.value("VCAN4_2EL", DeviceType::Enum::VCAN4_2EL)
.value("RADIO_CANHUB", DeviceType::Enum::RADIO_CANHUB)
.value("NEOECU12", DeviceType::Enum::NEOECU12)
.value("OBD2_LCBADGE", DeviceType::Enum::OBD2_LCBADGE)
.value("RADMoonDuo", DeviceType::Enum::RADMoonDuo)
.value("FIRE3", DeviceType::Enum::FIRE3)
.value("VCAN3", DeviceType::Enum::VCAN3)
.value("RADJupiter", DeviceType::Enum::RADJupiter)
.value("VCAN4_IND", DeviceType::Enum::VCAN4_IND)
.value("RADGigastar", DeviceType::Enum::RADGigastar)
.value("RED2", DeviceType::Enum::RED2)
.value("EtherBADGE", DeviceType::Enum::EtherBADGE)
.value("RAD_A2B", DeviceType::Enum::RAD_A2B)
.value("RADEpsilon", DeviceType::Enum::RADEpsilon)
.value("RADGalaxy2", DeviceType::Enum::RADGalaxy2)
.value("RADMoon3", DeviceType::Enum::RADMoon3)
.value("RADComet", DeviceType::Enum::RADComet)
.value("FIRE3_FlexRay", DeviceType::Enum::FIRE3_FlexRay)
.value("Connect", DeviceType::Enum::Connect)
.value("RADComet3", DeviceType::Enum::RADComet3)
.value("RADMoonT1S", DeviceType::Enum::RADMoonT1S)
.value("RADGigastar2", DeviceType::Enum::RADGigastar2)
.value("RED", DeviceType::Enum::RED)
.value("ECU", DeviceType::Enum::ECU)
.value("IEVB", DeviceType::Enum::IEVB)
.value("Pendant", DeviceType::Enum::Pendant)
.value("OBD2_PRO", DeviceType::Enum::OBD2_PRO)
.value("ECUChip_UART", DeviceType::Enum::ECUChip_UART)
.value("PLASMA", DeviceType::Enum::PLASMA)
.value("NEOAnalog", DeviceType::Enum::NEOAnalog)
.value("CT_OBD", DeviceType::Enum::CT_OBD)
.value("ION", DeviceType::Enum::ION)
.value("RADStar", DeviceType::Enum::RADStar)
.value("VCAN4_4", DeviceType::Enum::VCAN4_4)
.value("VCAN4_2", DeviceType::Enum::VCAN4_2)
.value("CMProbe", DeviceType::Enum::CMProbe)
.value("EEVB", DeviceType::Enum::EEVB)
.value("VCANrf", DeviceType::Enum::VCANrf)
.value("FIRE2", DeviceType::Enum::FIRE2)
.value("Flex", DeviceType::Enum::Flex)
.value("RADGalaxy", DeviceType::Enum::RADGalaxy)
.value("RADStar2", DeviceType::Enum::RADStar2)
.value("VividCAN", DeviceType::Enum::VividCAN)
.value("OBD2_SIM", DeviceType::Enum::OBD2_SIM);
deviceType.def(pybind11::init<DeviceType::Enum>());
deviceType.def("get_device_type", &DeviceType::getDeviceType);
deviceType.def("get_generic_product_name", &DeviceType::getGenericProductName);
}
} // namespace icsneo
+57
View File
@@ -0,0 +1,57 @@
#include <pybind11/pybind11.h>
#include <pybind11/stl.h>
#include <pybind11/functional.h>
#include "icsneo/icsneocpp.h"
namespace icsneo {
void init_event(pybind11::module_&);
void init_eventcallback(pybind11::module_&);
void init_eventmanager(pybind11::module_&);
void init_network(pybind11::module_&);
void init_devicetype(pybind11::module_&);
void init_message(pybind11::module_&);
void init_canmessage(pybind11::module_&);
void init_canerrormessage(pybind11::module_&);
void init_ethernetmessage(pybind11::module_&);
void init_linmessage(pybind11::module_&);
void init_tc10statusmessage(pybind11::module_&);
void init_gptpstatusmessage(pybind11::module_&);
void init_mdiomessage(pybind11::module_&);
void init_ethernetstatusmessage(pybind11::module_&);
void init_device(pybind11::module_&);
void init_messagefilter(pybind11::module_&);
void init_messagecallback(pybind11::module_&);
void init_version(pybind11::module_&);
PYBIND11_MODULE(icsneopy, m) {
pybind11::options options;
options.disable_enum_members_docstring();
m.doc() = "libicsneo Python module";
init_event(m);
init_eventcallback(m);
init_eventmanager(m);
init_version(m);
init_devicetype(m);
init_network(m);
init_message(m);
init_canmessage(m);
init_canerrormessage(m);
init_ethernetmessage(m);
init_linmessage(m);
init_tc10statusmessage(m);
init_gptpstatusmessage(m);
init_mdiomessage(m);
init_ethernetstatusmessage(m);
init_messagefilter(m);
init_messagecallback(m);
init_device(m);
m.def("find_all_devices", &FindAllDevices);
m.def("get_supported_devices", &GetSupportedDevices);
m.def("get_last_error", &GetLastError);
}
} // namespace icsneo
View File
+17
View File
@@ -0,0 +1,17 @@
# Generated by Cargo
# will have compiled files and executables
debug/
target/
# These are backup files generated by rustfmt
**/*.rs.bk
# MSVC Windows builds of rustc generate these, which store debugging information
*.pdb
# RustRover
# JetBrains specific template is maintained in a separate JetBrains.gitignore that can
# be found at https://github.com/github/gitignore/blob/main/Global/JetBrains.gitignore
# and can be added to the global gitignore or merged into this file. For a more nuclear
# option (not recommended) you can uncomment the following to ignore the entire idea folder.
#.idea/
+293
View File
@@ -0,0 +1,293 @@
# This file is automatically @generated by Cargo.
# It is not intended for manual editing.
version = 4
[[package]]
name = "aho-corasick"
version = "1.1.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8e60d3430d3a69478ad0993f19238d2df97c507009a52b3c10addcd7f6bcb916"
dependencies = [
"memchr",
]
[[package]]
name = "bindgen"
version = "0.71.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5f58bf3d7db68cfbac37cfc485a8d711e87e064c3d0fe0435b92f7a407f9d6b3"
dependencies = [
"bitflags",
"cexpr",
"clang-sys",
"itertools",
"log",
"prettyplease",
"proc-macro2",
"quote",
"regex",
"rustc-hash",
"shlex",
"syn",
]
[[package]]
name = "bitflags"
version = "2.8.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8f68f53c83ab957f72c32642f3868eec03eb974d1fb82e453128456482613d36"
[[package]]
name = "cexpr"
version = "0.6.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "6fac387a98bb7c37292057cffc56d62ecb629900026402633ae9160df93a8766"
dependencies = [
"nom",
]
[[package]]
name = "cfg-if"
version = "1.0.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd"
[[package]]
name = "clang-sys"
version = "1.8.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0b023947811758c97c59bf9d1c188fd619ad4718dcaa767947df1cadb14f39f4"
dependencies = [
"glob",
"libc",
"libloading",
]
[[package]]
name = "either"
version = "1.13.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "60b1af1c220855b6ceac025d3f6ecdd2b7c4894bfe9cd9bda4fbb4bc7c0d4cf0"
[[package]]
name = "glob"
version = "0.3.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a8d1add55171497b4705a648c6b583acafb01d58050a51727785f0b2c8e0a2b2"
[[package]]
name = "icsneoc2rs"
version = "0.1.0"
dependencies = [
"bindgen",
"scopeguard",
]
[[package]]
name = "itertools"
version = "0.13.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "413ee7dfc52ee1a4949ceeb7dbc8a33f2d6c088194d9f922fb8318faf1f01186"
dependencies = [
"either",
]
[[package]]
name = "libc"
version = "0.2.169"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b5aba8db14291edd000dfcc4d620c7ebfb122c613afb886ca8803fa4e128a20a"
[[package]]
name = "libloading"
version = "0.8.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "fc2f4eb4bc735547cfed7c0a4922cbd04a4655978c09b54f1f7b228750664c34"
dependencies = [
"cfg-if",
"windows-targets",
]
[[package]]
name = "log"
version = "0.4.25"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "04cbf5b083de1c7e0222a7a51dbfdba1cbe1c6ab0b15e29fff3f6c077fd9cd9f"
[[package]]
name = "memchr"
version = "2.7.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "78ca9ab1a0babb1e7d5695e3530886289c18cf2f87ec19a575a0abdce112e3a3"
[[package]]
name = "minimal-lexical"
version = "0.2.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "68354c5c6bd36d73ff3feceb05efa59b6acb7626617f4962be322a825e61f79a"
[[package]]
name = "nom"
version = "7.1.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d273983c5a657a70a3e8f2a01329822f3b8c8172b73826411a55751e404a0a4a"
dependencies = [
"memchr",
"minimal-lexical",
]
[[package]]
name = "prettyplease"
version = "0.2.29"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "6924ced06e1f7dfe3fa48d57b9f74f55d8915f5036121bef647ef4b204895fac"
dependencies = [
"proc-macro2",
"syn",
]
[[package]]
name = "proc-macro2"
version = "1.0.93"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "60946a68e5f9d28b0dc1c21bb8a97ee7d018a8b322fa57838ba31cc878e22d99"
dependencies = [
"unicode-ident",
]
[[package]]
name = "quote"
version = "1.0.38"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0e4dccaaaf89514f546c693ddc140f729f958c247918a13380cccc6078391acc"
dependencies = [
"proc-macro2",
]
[[package]]
name = "regex"
version = "1.11.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b544ef1b4eac5dc2db33ea63606ae9ffcfac26c1416a2806ae0bf5f56b201191"
dependencies = [
"aho-corasick",
"memchr",
"regex-automata",
"regex-syntax",
]
[[package]]
name = "regex-automata"
version = "0.4.9"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "809e8dc61f6de73b46c85f4c96486310fe304c434cfa43669d7b40f711150908"
dependencies = [
"aho-corasick",
"memchr",
"regex-syntax",
]
[[package]]
name = "regex-syntax"
version = "0.8.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2b15c43186be67a4fd63bee50d0303afffcef381492ebe2c5d87f324e1b8815c"
[[package]]
name = "rustc-hash"
version = "2.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c7fb8039b3032c191086b10f11f319a6e99e1e82889c5cc6046f515c9db1d497"
[[package]]
name = "scopeguard"
version = "1.2.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "94143f37725109f92c262ed2cf5e59bce7498c01bcc1502d7b9afe439a4e9f49"
[[package]]
name = "shlex"
version = "1.3.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0fda2ff0d084019ba4d7c6f371c95d8fd75ce3524c3cb8fb653a3023f6323e64"
[[package]]
name = "syn"
version = "2.0.96"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d5d0adab1ae378d7f53bdebc67a39f1f151407ef230f0ce2883572f5d8985c80"
dependencies = [
"proc-macro2",
"quote",
"unicode-ident",
]
[[package]]
name = "unicode-ident"
version = "1.0.16"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a210d160f08b701c8721ba1c726c11662f877ea6b7094007e1ca9a1041945034"
[[package]]
name = "windows-targets"
version = "0.52.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9b724f72796e036ab90c1021d4780d4d3d648aca59e491e6b98e725b84e99973"
dependencies = [
"windows_aarch64_gnullvm",
"windows_aarch64_msvc",
"windows_i686_gnu",
"windows_i686_gnullvm",
"windows_i686_msvc",
"windows_x86_64_gnu",
"windows_x86_64_gnullvm",
"windows_x86_64_msvc",
]
[[package]]
name = "windows_aarch64_gnullvm"
version = "0.52.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "32a4622180e7a0ec044bb555404c800bc9fd9ec262ec147edd5989ccd0c02cd3"
[[package]]
name = "windows_aarch64_msvc"
version = "0.52.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "09ec2a7bb152e2252b53fa7803150007879548bc709c039df7627cabbd05d469"
[[package]]
name = "windows_i686_gnu"
version = "0.52.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8e9b5ad5ab802e97eb8e295ac6720e509ee4c243f69d781394014ebfe8bbfa0b"
[[package]]
name = "windows_i686_gnullvm"
version = "0.52.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0eee52d38c090b3caa76c563b86c3a4bd71ef1a819287c19d586d7334ae8ed66"
[[package]]
name = "windows_i686_msvc"
version = "0.52.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "240948bc05c5e7c6dabba28bf89d89ffce3e303022809e73deaefe4f6ec56c66"
[[package]]
name = "windows_x86_64_gnu"
version = "0.52.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "147a5c80aabfbf0c7d901cb5895d1de30ef2907eb21fbbab29ca94c5b08b1a78"
[[package]]
name = "windows_x86_64_gnullvm"
version = "0.52.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "24d5b23dc417412679681396f2b49f3de8c1473deb516bd34410872eff51ed0d"
[[package]]
name = "windows_x86_64_msvc"
version = "0.52.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "589f6da84c646204747d1270a2a5661ea66ed1cced2631d546fdfb155959f9ec"
+22
View File
@@ -0,0 +1,22 @@
[package]
name = "icsneoc2rs"
version = "0.1.0"
edition = "2021"
[lib]
name = "icsneoc2rs"
crate-type = ["rlib", "staticlib", "cdylib"]
path = "src/lib.rs"
[[example]]
name = "simple"
path = "examples/simple.rs"
[dev-dependencies]
scopeguard = "1.2.0"
[features]
static = []
[build-dependencies]
bindgen = "0.71.1"
+40
View File
@@ -0,0 +1,40 @@
use std::env;
use std::path::PathBuf;
pub fn main() {
// Tell cargo to look for shared libraries in the specified directory
println!("cargo:rustc-link-search=../../../build");
// Tell cargo to tell rustc to link the system
// shared library.
println!("cargo:rustc-link-lib=icsneoc2");
// The bindgen::Builder is the main entry point
// to bindgen, and lets you build up options for
// the resulting bindings.
let bindings = bindgen::Builder::default()
// The input header we would like to generate
// bindings for.
.header("../../../include/icsneo/icsneoc2.h")
.clang_arg("-I../../../include")
// Tell cargo to invalidate the built crate whenever any of the
// included header files changed.
.parse_callbacks(Box::new(bindgen::CargoCallbacks::new()))
.derive_default(true)
.derive_debug(true)
.derive_partialeq(true)
.derive_copy(true)
.default_enum_style(bindgen::EnumVariation::Rust { non_exhaustive: true })
.default_alias_style(bindgen::AliasVariation::TypeAlias)
.generate_cstr(true)
// Finish the builder and generate the bindings.
.generate()
// Unwrap the Result and panic on failure.
.expect("Unable to generate bindings");
// Write the bindings to the $OUT_DIR/bindings.rs file.
let out_path = PathBuf::from(env::var("OUT_DIR").unwrap());
bindings
.write_to_file(out_path.join("bindings.rs"))
.expect("Couldn't write bindings!");
}
+333
View File
@@ -0,0 +1,333 @@
use icsneoc2rs::ffi::_icsneoc2_msg_bus_type_t::*;
use icsneoc2rs::ffi::_icsneoc2_msg_type_t::*;
use icsneoc2rs::ffi::_icsneoc2_netid_t;
use icsneoc2rs::ffi::_icsneoc2_netid_t::*;
use icsneoc2rs::ffi::_icsneoc2_open_options_t::*;
use icsneoc2rs::ffi::icsneoc2_message_t;
use icsneoc2rs::ffi::icsneoc2_msg_bus_type_t;
use icsneoc2rs::ffi::icsneoc2_msg_type_t;
use icsneoc2rs::ffi::icsneoc2_netid_t;
use icsneoc2rs::Device;
use icsneoc2rs::Error;
use icsneoc2rs::Result as ICSNeoResult;
use scopeguard::defer;
fn main() -> ICSNeoResult<()> {
print!("Finding devices... ");
let devices = Device::find_all(255)?;
println!(
"OK, {} device{} found...",
devices.len(),
if devices.len() > 1 { "s" } else { "" }
);
for device in devices {
device.device_is_valid()?;
// Get description of the device
let description = match device.device_description_get() {
Ok(description) => description,
Err(err) => {
println!("Failed to get description of device: {err}");
continue;
}
};
println!("{} @ Handle {:?}", description, device.handle);
// Get/Set open options
let mut open_options = match device.device_open_options_get() {
Ok(value) => value,
Err(err) => {
println!("Failed to get open options of device: {err}");
continue;
}
};
// Disable Syncing RTC and going online
open_options &= !(icsneoc2_open_options_sync_rtc as u32);
open_options &= !(icsneoc2_open_options_go_online as u32);
match device.device_open_options_set(open_options) {
Ok(value) => value,
Err(err) => {
print_error(&device, &description, err);
continue;
}
};
println!("\tDevice open options: {open_options:#02x}");
// Open the device
print!("\tOpening device... ");
match device.device_open() {
Ok(value) => value,
Err(err) => {
print_error(&device, &description, err);
continue;
}
};
println!("OK");
defer! {
print_device_events(&device, &description).expect("Critical: Failed to print device events");
}
// Get timestamp resolution of the device
print!("\tGetting timestamp resolution... ");
let timestamp_resolution = match device.device_timestamp_resolution_get() {
Ok(value) => value,
Err(err) => {
print_error(&device, &description, err);
continue;
}
};
println!("{timestamp_resolution}ns");
// Get baudrates for HSCAN
print!("\tGetting HSCAN baudrate... ");
let baudrate = match device.device_baudrate_get(icsneoc2_netid_hscan) {
Ok(value) => value,
Err(err) => {
print_error(&device, &description, err);
continue;
}
};
println!("{baudrate}mbit/s");
// Get FD baudrates for HSCAN
print!("\tGetting FD HSCAN baudrate... ");
let fd_baudrate = match device.device_canfd_baudrate_get(icsneoc2_netid_hscan) {
Ok(value) => value,
Err(err) => {
print_error(&device, &description, err);
continue;
}
};
println!("{fd_baudrate}mbit/s");
// Set baudrates for HSCAN
// saveToDevice: If this is set to true, the baudrate will be saved on the device
// and will persist through a power cycle
print!("\tSetting HSCAN baudrate... ");
let save_to_device = false;
match device.device_baudrate_set(icsneoc2_netid_hscan, baudrate, save_to_device) {
Ok(value) => value,
Err(err) => {
print_error(&device, &description, err);
continue;
}
};
println!("OK");
// Set FD baudrates for HSCAN
print!("\tSetting FD HSCAN baudrate... ");
match device.device_canfd_baudrate_set(icsneoc2_netid_hscan, fd_baudrate, save_to_device) {
Ok(value) => value,
Err(err) => {
print_error(&device, &description, err);
continue;
}
};
println!("OK");
// Get RTC
print!("\tGetting RTC... ");
let current_rtc = match device.device_rtc_get() {
Ok(value) => value,
Err(err) => {
print_error(&device, &description, err);
continue;
}
};
println!("{current_rtc}");
// Set RTC
print!("\tSetting RTC... ");
match device.device_rtc_set(current_rtc) {
Ok(value) => value,
Err(err) => {
print_error(&device, &description, err);
continue;
}
};
println!("OK");
// Get RTC
print!("\tGetting RTC... ");
let rtc = match device.device_rtc_get() {
Ok(value) => value,
Err(err) => {
print_error(&device, &description, err);
continue;
}
};
println!("{rtc}");
// Go online, start acking traffic
print!("\tGoing online... ");
match device.device_go_online(true) {
Ok(value) => value,
Err(err) => {
print_error(&device, &description, err);
continue;
}
};
// Redundant check to show how to check if the device is online, if the previous
// icsneoc2_device_go_online call was successful we can assume we are online already
let is_online = match device.device_is_online() {
Ok(value) => value,
Err(err) => {
print_error(&device, &description, err);
continue;
}
};
println!("{}", if is_online { "Online" } else { "Offline" });
// Transmit CAN messages
if transmit_can_messages(&device).is_err() {
continue;
}
println!("\tWaiting 1 second for messages...");
std::thread::sleep(std::time::Duration::from_secs(1));
// Get the messages
let messages = match device.device_messages_get(20000, 3000) {
Ok(messages) => messages,
Err(err) => {
print_error(&device, &description, err);
continue;
}
};
// Process the messages
if process_messages(&device, messages).is_err() {
continue;
}
// Close the device
print!("\tClosing device... ");
match device.device_close() {
Ok(value) => value,
Err(err) => {
print_error(&device, &description, err);
continue;
}
};
println!("OK");
}
Ok(())
}
fn print_error(device: &Device, device_description: &String, err: Error) {
println!("Failed: {err}");
print_device_events(device, device_description)
.expect("Critical: Failed to print device events");
}
fn transmit_can_messages(device: &Device) -> ICSNeoResult<()> {
const MESSAGE_COUNT: usize = 100;
println!("\tTransmitting {MESSAGE_COUNT} messages...");
for i in 0..MESSAGE_COUNT {
let message = match device.message_can_create(1) {
Ok(messages) => messages[0],
Err(err) => {
println!("Failed to create CAN message #{i}: {err}");
continue;
}
};
device.message_netid_set(message, icsneoc2_netid_hscan)?;
device.message_can_arbid_set(message, 0x10)?;
device.message_can_canfd_set(message, true)?;
device.message_can_extended_set(message, true)?;
device.message_can_baudrate_switch_set(message, true)?;
device.message_data_set(
message,
vec![
(i >> 56 & 0xFF) as u8,
(i >> 48 & 0xFF) as u8,
(i >> 40 & 0xFF) as u8,
(i >> 32 & 0xFF) as u8,
(i >> 24 & 0xFF) as u8,
(i >> 16 & 0xFF) as u8,
(i >> 8 & 0xFF) as u8,
(i & 0xFF) as u8,
],
)?;
device.message_can_dlc_set(message, -1)?;
device.device_messages_transmit(vec![message])?;
}
Ok(())
}
fn process_messages(device: &Device, messages: Vec<*mut icsneoc2_message_t>) -> ICSNeoResult<()> {
let mut tx_count: u32 = 0;
for (i, message) in messages.iter().enumerate() {
// Get the message type
let msg_type = device.message_type_get(*message)?;
// Get the message type name
let msg_type_name = device.message_type_name_get(msg_type)?;
// Check if the message is a bus message, ignore otherwise
if msg_type != icsneoc2_msg_type_bus as icsneoc2_msg_type_t {
println!("\tIgnoring message type : {msg_type} ({msg_type_name})");
continue;
}
// Get the message bus type
let msg_bus_type = device.message_bus_type_get(*message)?;
// Get the message type name
let msg_bus_type_name = device.bus_type_name_get(msg_bus_type)?;
// Check if message is a transmit message
if device.message_is_transmit(*message)? {
tx_count += 1;
continue;
}
println!("\t{i} Message type: {msg_type} bus type: {msg_bus_type_name} ({msg_bus_type})\n");
// Check if the message is a CAN message, ignore otherwise
if msg_bus_type == icsneoc2_msg_bus_type_can as icsneoc2_msg_bus_type_t {
let netid = device.message_netid_get(*message)?;
let netid_name = device.netid_name_get(netid)?;
let arbid = device.message_can_arbid_get(*message)?;
let dlc = device.message_can_dlc_get(*message)?;
let is_remote = device.message_can_is_remote(*message)?;
let is_canfd = device.message_can_is_canfd(*message)?;
let is_extended = device.message_can_is_extended(*message)?;
let data = device.message_data_get(*message, 64)?;
// Finally lets print the RX message
println!("\t NetID: {netid_name} ({:#02x})\tArbID: {arbid:#02x}\t DLC: {dlc}\t Remote: {is_remote}\t \
CANFD: {is_canfd}\t Extended: {is_extended}\t Data length: {}\n", netid as icsneoc2_netid_t,data.len());
println!("\t Data: {data:#02x?}\n");
} else {
println!("\tIgnoring bus message type: {msg_bus_type} ({msg_bus_type_name})\n");
}
}
println!(
"\tReceived {} messages total, {} were TX messages",
messages.len(),
tx_count
);
Ok(())
}
fn print_device_events(device: &Device, device_description: &String) -> ICSNeoResult<()> {
let events = match device.device_events_get(1024) {
Ok(events) => events,
Err(err) => {
println!("Failed to get device events: {err}");
return Err(err);
}
};
for (i, event) in events.iter().enumerate() {
let description = match device.event_description_get(*event) {
Ok(description) => description,
Err(err) => {
println!("Failed to get event description: {err}");
continue;
}
};
println!("\t{device_description}: Event {i}: {description}");
}
// Get global events
let global_events = match device.events_get(1024) {
Ok(events) => events,
Err(err) => {
println!("Failed to get global events: {err}");
return Err(err);
}
};
for (i, event) in global_events.iter().enumerate() {
let description = match device.event_description_get(*event) {
Ok(description) => description,
Err(err) => {
println!("Failed to get event description: {err}");
continue;
}
};
println!("\t{device_description}: Global Event {i}: {description}");
}
println!(
"\t{device_description}: Received {} events and {} global events\n",
events.len(),
global_events.len()
);
Ok(())
}
+5
View File
@@ -0,0 +1,5 @@
#![allow(non_upper_case_globals)]
#![allow(non_camel_case_types)]
#![allow(non_snake_case)]
include!(concat!(env!("OUT_DIR"), "/bindings.rs"));
+902
View File
@@ -0,0 +1,902 @@
pub mod ffi;
use ffi::_icsneoc2_error_t::{icsneoc2_error_invalid_device, icsneoc2_error_success};
use ffi::_icsneoc2_open_options_t::*;
use ffi::*;
use std::ffi::CString;
use std::fmt::Display;
#[derive(Debug, Clone)]
pub enum Error {
/// icsneoc2 API error
APIError(icsneoc2_error_t, String),
}
impl Display for Error {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
match self {
Error::APIError(error_code, error_string) => write!(f, "API Error: \"{}\" ({})", error_string, error_code),
}
}
}
pub type Result<T> = core::result::Result<T, Error>;
#[derive(Debug, Clone)]
pub struct Device {
/// Handle to the device.
pub handle: *mut icsneoc2_device_t,
}
impl Drop for Device {
fn drop(&mut self) {
// Make sure the device is closed before we go out of scope.
self.device_close().expect("Failed to close device!");
}
}
impl Device {
pub fn find_all(device_count: u32) -> Result<Vec<Self>> {
// Find all the devices
const MAX_DEVICE_COUNT: u32 = 255;
let mut devices: [*mut icsneoc2_device_t; MAX_DEVICE_COUNT as usize] =
[std::ptr::null_mut(); 255];
let mut devices_count: u32 = if device_count > MAX_DEVICE_COUNT {
MAX_DEVICE_COUNT
} else {
device_count
};
let res = unsafe {
icsneoc2_device_find_all(
devices.as_mut_ptr(),
&mut devices_count as *mut u32,
std::ptr::null_mut(),
)
};
// Check the error code
if res != icsneoc2_error_success as icsneoc2_error_t {
return Err(Self::error_code_get(res));
}
// Return the results
let found_devices: Vec<Self> = devices[..devices_count as usize]
.iter()
.map(|d| Self { handle: *d })
.collect();
Ok(found_devices)
}
pub fn bus_type_name_get(&self, bus_type: icsneoc2_msg_bus_type_t) -> Result<String> {
// Get the string
let mut str: Vec<u8> = vec![0; 255];
let mut str_length: u32 = 255;
let res = unsafe {
icsneoc2_bus_type_name_get(bus_type, str.as_mut_ptr() as *mut i8, &mut str_length)
};
// Check the error code
if res != icsneoc2_error_success as icsneoc2_error_t {
return Err(Self::error_code_get(res));
}
// Convert the vec to an String
str.resize(str_length as usize, 0);
let str_string = {
CString::new(str)
.expect("CString::new failed")
.into_string()
.expect("CString::new::into_string")
};
Ok(str_string)
}
pub fn device_baudrate_get(&self, netid: _icsneoc2_netid_t) -> Result<u64> {
let mut value: u64 = 0;
let res: icsneoc2_error_t =
unsafe { ffi::icsneoc2_device_baudrate_get(self.handle, netid as icsneoc2_netid_t, &mut value) };
// Check the error code
if res != icsneoc2_error_success as icsneoc2_error_t {
return Err(Self::error_code_get(res));
}
Ok(value)
}
pub fn device_baudrate_set(
&self,
netid: _icsneoc2_netid_t,
value: u64,
save: bool,
) -> Result<()> {
let res: icsneoc2_error_t =
unsafe { ffi::icsneoc2_device_baudrate_set(self.handle, netid as icsneoc2_netid_t, value, save) };
// Check the error code
if res != icsneoc2_error_success as icsneoc2_error_t {
return Err(Self::error_code_get(res));
}
Ok(())
}
pub fn device_canfd_baudrate_get(&self, netid: _icsneoc2_netid_t) -> Result<u64> {
let mut value: u64 = 0;
let res: icsneoc2_error_t =
unsafe { ffi::icsneoc2_device_canfd_baudrate_get(self.handle, netid as icsneoc2_netid_t, &mut value) };
// Check the error code
if res != icsneoc2_error_success as icsneoc2_error_t {
return Err(Self::error_code_get(res));
}
Ok(value)
}
pub fn device_canfd_baudrate_set(
&self,
netid: _icsneoc2_netid_t,
value: u64,
save: bool,
) -> Result<()> {
let res: icsneoc2_error_t =
unsafe { ffi::icsneoc2_device_canfd_baudrate_set(self.handle, netid as icsneoc2_netid_t, value, save) };
// Check the error code
if res != icsneoc2_error_success as icsneoc2_error_t {
return Err(Self::error_code_get(res));
}
Ok(())
}
pub fn device_close(&self) -> Result<()> {
let res: icsneoc2_error_t = unsafe { ffi::icsneoc2_device_close(self.handle) };
// Check the error code
if res != icsneoc2_error_success as icsneoc2_error_t {
return Err(Self::error_code_get(res));
}
Ok(())
}
pub fn device_description_get(&self) -> Result<String> {
// Get the error code
let mut description: Vec<u8> = vec![0; 255];
let mut description_length: u32 = 255;
let res = unsafe {
icsneoc2_device_description_get(
self.handle,
description.as_mut_ptr() as *mut i8,
&mut description_length,
)
};
// Check the error code
if res != icsneoc2_error_success as icsneoc2_error_t {
return Err(Self::error_code_get(res));
}
// Convert the vec to an String
description.resize(description_length as usize, 0);
let description_str = {
CString::new(description)
.expect("CString::new failed")
.into_string()
.expect("CString::new::into_string")
};
Ok(description_str)
}
pub fn device_events_get(&self, event_count: u32) -> Result<Vec<*mut icsneoc2_event_t>> {
let mut events: Vec<*mut icsneoc2_event_t> =
vec![std::ptr::null_mut(); event_count as usize];
let mut event_count: u32 = event_count;
let res: icsneoc2_error_t = unsafe {
ffi::icsneoc2_device_events_get(self.handle, events.as_mut_ptr(), &mut event_count)
};
// Check the error code
if res != icsneoc2_error_success as icsneoc2_error_t {
return Err(Self::error_code_get(res));
}
events.resize(event_count as usize, std::ptr::null_mut());
Ok(events)
}
pub fn device_go_online(&self, go_online: bool) -> Result<()> {
let res: icsneoc2_error_t =
unsafe { ffi::icsneoc2_device_go_online(self.handle, go_online) };
// Check the error code
if res != icsneoc2_error_success as icsneoc2_error_t {
return Err(Self::error_code_get(res));
}
Ok(())
}
pub fn device_is_online(&self) -> Result<bool> {
let mut is_online: bool = false;
let res: icsneoc2_error_t =
unsafe { ffi::icsneoc2_device_is_online(self.handle, &mut is_online) };
// Check the error code
if res != icsneoc2_error_success as icsneoc2_error_t {
return Err(Self::error_code_get(res));
}
Ok(is_online)
}
pub fn device_is_online_supported(&self) -> Result<bool> {
let mut is_online_supported: bool = false;
let res: icsneoc2_error_t = unsafe {
ffi::icsneoc2_device_is_online_supported(self.handle, &mut is_online_supported)
};
// Check the error code
if res != icsneoc2_error_success as icsneoc2_error_t {
return Err(Self::error_code_get(res));
}
Ok(is_online_supported)
}
pub fn device_is_valid(&self) -> Result<bool> {
let res: icsneoc2_error_t = unsafe { icsneoc2_device_is_valid(self.handle) };
match res {
res if res == icsneoc2_error_success as icsneoc2_error_t => Ok(true),
res if res == icsneoc2_error_invalid_device as icsneoc2_error_t => Ok(false),
_ => Err(Self::error_code_get(res)),
}
}
pub fn device_is_open(&self) -> Result<bool> {
let mut is_open: bool = false;
let res: icsneoc2_error_t =
unsafe { ffi::icsneoc2_device_is_open(self.handle, &mut is_open) };
// Check the error code
if res != icsneoc2_error_success as icsneoc2_error_t {
return Err(Self::error_code_get(res));
}
Ok(is_open)
}
pub fn device_is_disconnected(&self) -> Result<bool> {
let mut is_disconnected: bool = false;
let res: icsneoc2_error_t =
unsafe { ffi::icsneoc2_device_is_disconnected(self.handle, &mut is_disconnected) };
// Check the error code
if res != icsneoc2_error_success as icsneoc2_error_t {
return Err(Self::error_code_get(res));
}
Ok(is_disconnected)
}
pub fn device_load_default_settings(&self, save: bool) -> Result<()> {
let res: icsneoc2_error_t =
unsafe { ffi::icsneoc2_device_load_default_settings(self.handle, save) };
// Check the error code
if res != icsneoc2_error_success as icsneoc2_error_t {
return Err(Self::error_code_get(res));
}
Ok(())
}
pub fn device_message_count_get(&self) -> Result<u32> {
let mut value: u32 = 0;
let res: icsneoc2_error_t =
unsafe { ffi::icsneoc2_device_message_count_get(self.handle, &mut value) };
// Check the error code
if res != icsneoc2_error_success as icsneoc2_error_t {
return Err(Self::error_code_get(res));
}
Ok(value)
}
pub fn device_message_polling_get(&self) -> Result<bool> {
let mut value: bool = false;
let res: icsneoc2_error_t =
unsafe { ffi::icsneoc2_device_message_polling_get(self.handle, &mut value) };
// Check the error code
if res != icsneoc2_error_success as icsneoc2_error_t {
return Err(Self::error_code_get(res));
}
Ok(value)
}
pub fn device_message_polling_limit_get(&self) -> Result<u32> {
let mut value: u32 = 0;
let res: icsneoc2_error_t =
unsafe { ffi::icsneoc2_device_message_polling_limit_get(self.handle, &mut value) };
// Check the error code
if res != icsneoc2_error_success as icsneoc2_error_t {
return Err(Self::error_code_get(res));
}
Ok(value)
}
pub fn device_message_polling_set(&self, enable: bool) -> Result<()> {
let res: icsneoc2_error_t =
unsafe { ffi::icsneoc2_device_message_polling_set(self.handle, enable) };
// Check the error code
if res != icsneoc2_error_success as icsneoc2_error_t {
return Err(Self::error_code_get(res));
}
Ok(())
}
pub fn device_message_polling_set_limit(&self, value: u32) -> Result<()> {
let res: icsneoc2_error_t =
unsafe { ffi::icsneoc2_device_message_polling_set_limit(self.handle, value) };
// Check the error code
if res != icsneoc2_error_success as icsneoc2_error_t {
return Err(Self::error_code_get(res));
}
Ok(())
}
pub fn device_messages_get(
&self,
message_count: u32,
timeout_ms: u32,
) -> Result<Vec<*mut icsneoc2_message_t>> {
let mut messages: Vec<*mut icsneoc2_message_t> =
vec![std::ptr::null_mut(); message_count as usize];
let mut message_count: u32 = message_count;
let res: icsneoc2_error_t = unsafe {
ffi::icsneoc2_device_messages_get(
self.handle,
messages.as_mut_ptr(),
&mut message_count,
timeout_ms,
)
};
// Check the error code
if res != icsneoc2_error_success as icsneoc2_error_t {
return Err(Self::error_code_get(res));
}
messages.resize(message_count as usize, std::ptr::null_mut());
Ok(messages)
}
pub fn device_messages_transmit(&self, messages: Vec<*mut icsneoc2_message_t>) -> Result<u32> {
let mut messages_count: u32 = messages.len() as u32;
let mut messages = messages;
let res: icsneoc2_error_t = unsafe {
ffi::icsneoc2_device_messages_transmit(
self.handle,
messages.as_mut_ptr(),
&mut messages_count,
)
};
// Check the error code
if res != icsneoc2_error_success as icsneoc2_error_t {
return Err(Self::error_code_get(res));
}
Ok(messages_count)
}
pub fn device_open(&self) -> Result<()> {
let res: icsneoc2_error_t = unsafe { ffi::icsneoc2_device_open(self.handle) };
// Check the error code
if res != icsneoc2_error_success as icsneoc2_error_t {
return Err(Self::error_code_get(res));
}
Ok(())
}
pub fn device_open_options_get(&self) -> Result<ffi::icsneoc2_open_options_t> {
let mut open_options: ffi::icsneoc2_open_options_t =
icsneoc2_open_options_none as ffi::icsneoc2_open_options_t;
let res: icsneoc2_error_t =
unsafe { ffi::icsneoc2_device_open_options_get(self.handle, &mut open_options) };
// Check the error code
if res != icsneoc2_error_success as icsneoc2_error_t {
return Err(Self::error_code_get(res));
}
Ok(open_options)
}
pub fn device_open_options_set(
&self,
open_options: ffi::icsneoc2_open_options_t,
) -> Result<()> {
let res: icsneoc2_error_t =
unsafe { ffi::icsneoc2_device_open_options_set(self.handle, open_options) };
// Check the error code
if res != icsneoc2_error_success as icsneoc2_error_t {
return Err(Self::error_code_get(res));
}
Ok(())
}
pub fn device_rtc_get(&self) -> Result<i64> {
let mut value: i64 = 0;
let res: icsneoc2_error_t =
unsafe { ffi::icsneoc2_device_rtc_get(self.handle, &mut value) };
// Check the error code
if res != icsneoc2_error_success as icsneoc2_error_t {
return Err(Self::error_code_get(res));
}
Ok(value)
}
pub fn device_rtc_set(&self, value: i64) -> Result<()> {
let res: icsneoc2_error_t = unsafe { ffi::icsneoc2_device_rtc_set(self.handle, value) };
// Check the error code
if res != icsneoc2_error_success as icsneoc2_error_t {
return Err(Self::error_code_get(res));
}
Ok(())
}
pub fn device_serial_get(&self) -> Result<String> {
// Get the string
let mut str: Vec<u8> = vec![0; 255];
let mut str_length: u32 = 255;
let res = unsafe {
icsneoc2_device_serial_get(self.handle, str.as_mut_ptr() as *mut i8, &mut str_length)
};
// Check the error code
if res != icsneoc2_error_success as icsneoc2_error_t {
return Err(Self::error_code_get(res));
}
// Convert the vec to an String
str.resize(str_length as usize, 0);
let str_string = {
CString::new(str)
.expect("CString::new failed")
.into_string()
.expect("CString::new::into_string")
};
Ok(str_string)
}
pub fn device_supports_tc10(&self) -> Result<bool> {
let mut value: bool = false;
let res: icsneoc2_error_t =
unsafe { ffi::icsneoc2_device_supports_tc10(self.handle, &mut value) };
// Check the error code
if res != icsneoc2_error_success as icsneoc2_error_t {
return Err(Self::error_code_get(res));
}
Ok(value)
}
pub fn device_timestamp_resolution_get(&self) -> Result<u32> {
let mut timestamp_resolution: u32 = 0;
let res: icsneoc2_error_t = unsafe {
ffi::icsneoc2_device_timestamp_resolution_get(self.handle, &mut timestamp_resolution)
};
// Check the error code
if res != icsneoc2_error_success as icsneoc2_error_t {
return Err(Self::error_code_get(res));
}
Ok(timestamp_resolution)
}
pub fn device_type_from_type(&self, device_type: icsneoc2_devicetype_t) -> Result<String> {
// Get the string
let mut str: Vec<u8> = vec![0; 255];
let mut str_length: u32 = 255;
let res = unsafe {
icsneoc2_device_type_name_get(
device_type,
str.as_mut_ptr() as *mut i8,
&mut str_length,
)
};
// Check the error code
if res != icsneoc2_error_success as icsneoc2_error_t {
return Err(Self::error_code_get(res));
}
// Convert the vec to an String
str.resize(str_length as usize, 0);
let str_string = {
CString::new(str)
.expect("CString::new failed")
.into_string()
.expect("CString::new::into_string")
};
Ok(str_string)
}
pub fn device_type_get(&self) -> Result<icsneoc2_devicetype_t> {
let mut value: icsneoc2_devicetype_t = 0;
let res: icsneoc2_error_t =
unsafe { ffi::icsneoc2_device_type_get(self.handle, &mut value) };
// Check the error code
if res != icsneoc2_error_success as icsneoc2_error_t {
return Err(Self::error_code_get(res));
}
Ok(value)
}
pub fn error_code_get(error_code: icsneoc2_error_t) -> Error {
// Get the error code
let mut error_description: Vec<u8> = vec![0; 255];
let mut error_description_length: u32 = 255;
let res = unsafe {
icsneoc2_error_code_get(
error_code,
error_description.as_mut_ptr() as *mut i8,
&mut error_description_length,
)
};
// Check the error code
if res != icsneoc2_error_success as icsneoc2_error_t {
return Error::APIError(res, "icsneoc2_error_code_get() failed.".to_string());
}
// Convert the vec to an String
error_description.resize(error_description_length as usize, 0);
let error_str = CString::new(error_description)
.expect("CString::new failed")
.into_string()
.expect("CString::new::into_string");
Error::APIError(error_code, error_str)
}
pub fn event_description_get(&self, event: *mut icsneoc2_event_t) -> Result<String> {
// Get the string
let mut str: Vec<u8> = vec![0; 255];
let mut str_length: u32 = 255;
let res = unsafe {
icsneoc2_event_description_get(event, str.as_mut_ptr() as *mut i8, &mut str_length)
};
// Check the error code
if res != icsneoc2_error_success as icsneoc2_error_t {
return Err(Self::error_code_get(res));
}
// Convert the vec to an String
str.resize(str_length as usize, 0);
let str_string = {
CString::new(str)
.expect("CString::new failed")
.into_string()
.expect("CString::new::into_string")
};
Ok(str_string)
}
pub fn events_get(&self, event_count: u32) -> Result<Vec<*mut icsneoc2_event_t>> {
let mut events: Vec<*mut icsneoc2_event_t> =
vec![std::ptr::null_mut(); event_count as usize];
let mut event_count: u32 = event_count;
let res: icsneoc2_error_t =
unsafe { ffi::icsneoc2_events_get(events.as_mut_ptr(), &mut event_count) };
// Check the error code
if res != icsneoc2_error_success as icsneoc2_error_t {
return Err(Self::error_code_get(res));
}
events.resize(event_count as usize, std::ptr::null_mut());
Ok(events)
}
pub fn message_bus_type_get(
&self,
message: *mut icsneoc2_message_t,
) -> Result<icsneoc2_msg_bus_type_t> {
let mut value: icsneoc2_msg_bus_type_t = 0;
let res: icsneoc2_error_t =
unsafe { ffi::icsneoc2_message_bus_type_get(self.handle, message, &mut value) };
// Check the error code
if res != icsneoc2_error_success as icsneoc2_error_t {
return Err(Self::error_code_get(res));
}
Ok(value)
}
pub fn message_can_arbid_get(&self, message: *mut icsneoc2_message_t) -> Result<u32> {
let mut value: u32 = 0;
let res: icsneoc2_error_t =
unsafe { ffi::icsneoc2_message_can_arbid_get(self.handle, message, &mut value) };
// Check the error code
if res != icsneoc2_error_success as icsneoc2_error_t {
return Err(Self::error_code_get(res));
}
Ok(value)
}
pub fn message_can_arbid_set(
&self,
message: *mut icsneoc2_message_t,
value: u32,
) -> Result<()> {
let res: icsneoc2_error_t =
unsafe { ffi::icsneoc2_message_can_arbid_set(self.handle, message, value) };
// Check the error code
if res != icsneoc2_error_success as icsneoc2_error_t {
return Err(Self::error_code_get(res));
}
Ok(())
}
pub fn message_can_baudrate_switch_get(
&self,
message: *mut icsneoc2_message_t,
) -> Result<bool> {
let mut value: bool = false;
let res: icsneoc2_error_t = unsafe {
ffi::icsneoc2_message_can_baudrate_switch_get(self.handle, message, &mut value)
};
// Check the error code
if res != icsneoc2_error_success as icsneoc2_error_t {
return Err(Self::error_code_get(res));
}
Ok(value)
}
pub fn message_can_baudrate_switch_set(
&self,
message: *mut icsneoc2_message_t,
value: bool,
) -> Result<()> {
let res: icsneoc2_error_t = unsafe {
ffi::icsneoc2_message_can_baudrate_switch_set(self.handle, message, value)
};
// Check the error code
if res != icsneoc2_error_success as icsneoc2_error_t {
return Err(Self::error_code_get(res));
}
Ok(())
}
pub fn message_can_canfd_set(
&self,
message: *mut icsneoc2_message_t,
value: bool,
) -> Result<()> {
let res: icsneoc2_error_t =
unsafe { ffi::icsneoc2_message_can_canfd_set(self.handle, message, value) };
// Check the error code
if res != icsneoc2_error_success as icsneoc2_error_t {
return Err(Self::error_code_get(res));
}
Ok(())
}
pub fn message_can_create(&self, message_count: u32) -> Result<Vec<*mut icsneoc2_message_t>> {
let mut messages: Vec<*mut icsneoc2_message_t> =
vec![std::ptr::null_mut(); message_count as usize];
let res: icsneoc2_error_t = unsafe {
ffi::icsneoc2_message_can_create(self.handle, messages.as_mut_ptr(), message_count)
};
// Check the error code
if res != icsneoc2_error_success as icsneoc2_error_t {
return Err(Self::error_code_get(res));
}
Ok(messages)
}
pub fn message_can_dlc_get(&self, message: *mut icsneoc2_message_t) -> Result<i32> {
let mut value: i32 = 0;
let res: icsneoc2_error_t =
unsafe { ffi::icsneoc2_message_can_dlc_get(self.handle, message, &mut value) };
// Check the error code
if res != icsneoc2_error_success as icsneoc2_error_t {
return Err(Self::error_code_get(res));
}
Ok(value)
}
pub fn message_can_dlc_set(&self, message: *mut icsneoc2_message_t, value: i32) -> Result<()> {
let res: icsneoc2_error_t =
unsafe { ffi::icsneoc2_message_can_dlc_set(self.handle, message, value) };
// Check the error code
if res != icsneoc2_error_success as icsneoc2_error_t {
return Err(Self::error_code_get(res));
}
Ok(())
}
pub fn message_can_error_state_indicator_get(
&self,
message: *mut icsneoc2_message_t,
) -> Result<bool> {
let mut value: bool = false;
let res: icsneoc2_error_t = unsafe {
ffi::icsneoc2_message_can_error_state_indicator_get(self.handle, message, &mut value)
};
// Check the error code
if res != icsneoc2_error_success as icsneoc2_error_t {
return Err(Self::error_code_get(res));
}
Ok(value)
}
pub fn message_can_extended_set(
&self,
message: *mut icsneoc2_message_t,
value: bool,
) -> Result<()> {
let res: icsneoc2_error_t =
unsafe { ffi::icsneoc2_message_can_extended_set(self.handle, message, value) };
// Check the error code
if res != icsneoc2_error_success as icsneoc2_error_t {
return Err(Self::error_code_get(res));
}
Ok(())
}
pub fn message_can_free(&self, message: *mut icsneoc2_message_t) -> Result<()> {
let res: icsneoc2_error_t = unsafe { ffi::icsneoc2_message_can_free(self.handle, message) };
// Check the error code
if res != icsneoc2_error_success as icsneoc2_error_t {
return Err(Self::error_code_get(res));
}
Ok(())
}
pub fn message_can_is_canfd(&self, message: *mut icsneoc2_message_t) -> Result<bool> {
let mut value: bool = false;
let res: icsneoc2_error_t =
unsafe { ffi::icsneoc2_message_can_is_canfd(self.handle, message, &mut value) };
// Check the error code
if res != icsneoc2_error_success as icsneoc2_error_t {
return Err(Self::error_code_get(res));
}
Ok(value)
}
pub fn message_can_is_extended(&self, message: *mut icsneoc2_message_t) -> Result<bool> {
let mut value: bool = false;
let res: icsneoc2_error_t =
unsafe { ffi::icsneoc2_message_can_is_extended(self.handle, message, &mut value) };
// Check the error code
if res != icsneoc2_error_success as icsneoc2_error_t {
return Err(Self::error_code_get(res));
}
Ok(value)
}
pub fn message_can_is_remote(&self, message: *mut icsneoc2_message_t) -> Result<bool> {
let mut value: bool = false;
let res: icsneoc2_error_t =
unsafe { ffi::icsneoc2_message_can_is_remote(self.handle, message, &mut value) };
// Check the error code
if res != icsneoc2_error_success as icsneoc2_error_t {
return Err(Self::error_code_get(res));
}
Ok(value)
}
pub fn message_data_get(
&self,
message: *mut icsneoc2_message_t,
data_length: u32,
) -> Result<Vec<u8>> {
let mut data: Vec<u8> = vec![0; data_length as usize];
let mut data_length = data_length;
let res: icsneoc2_error_t = unsafe {
ffi::icsneoc2_message_data_get(
self.handle,
message,
data.as_mut_ptr(),
&mut data_length,
)
};
// Check the error code
if res != icsneoc2_error_success as icsneoc2_error_t {
return Err(Self::error_code_get(res));
}
data.resize(data_length as usize, 0);
Ok(data)
}
pub fn message_data_set(&self, message: *mut icsneoc2_message_t, data: Vec<u8>) -> Result<()> {
let mut data = data;
let res: icsneoc2_error_t = unsafe {
ffi::icsneoc2_message_data_set(
self.handle,
message,
data.as_mut_ptr(),
data.len() as u32,
)
};
// Check the error code
if res != icsneoc2_error_success as icsneoc2_error_t {
return Err(Self::error_code_get(res));
}
Ok(())
}
pub fn message_is_transmit(&self, message: *mut icsneoc2_message_t) -> Result<bool> {
let mut value: bool = false;
let res: icsneoc2_error_t =
unsafe { ffi::icsneoc2_message_is_transmit(self.handle, message, &mut value) };
// Check the error code
if res != icsneoc2_error_success as icsneoc2_error_t {
return Err(Self::error_code_get(res));
}
Ok(value)
}
pub fn message_is_valid(&self, message: *mut icsneoc2_message_t) -> Result<bool> {
let mut value: bool = false;
let res: icsneoc2_error_t =
unsafe { ffi::icsneoc2_message_is_valid(self.handle, message, &mut value) };
// Check the error code
if res != icsneoc2_error_success as icsneoc2_error_t {
return Err(Self::error_code_get(res));
}
Ok(value)
}
pub fn message_netid_get(&self, message: *mut icsneoc2_message_t) -> Result<_icsneoc2_netid_t> {
let mut value: icsneoc2_netid_t = 0;
let res: icsneoc2_error_t =
unsafe { ffi::icsneoc2_message_netid_get(self.handle, message, &mut value) };
// Check the error code
if res != icsneoc2_error_success as icsneoc2_error_t {
return Err(Self::error_code_get(res));
}
// TODO: This is gross, there is probably a better way to do this.
// TryFrom impl would be a lot of work to implement because there are so many values.
// We are relying on the function call to always return a valid value.
let value: _icsneoc2_netid_t = unsafe { std::mem::transmute(value as u32) };
Ok(value)
}
pub fn message_netid_set(
&self,
message: *mut icsneoc2_message_t,
value: _icsneoc2_netid_t,
) -> Result<()> {
let res: icsneoc2_error_t =
unsafe { ffi::icsneoc2_message_netid_set(self.handle, message, value as icsneoc2_netid_t) };
// Check the error code
if res != icsneoc2_error_success as icsneoc2_error_t {
return Err(Self::error_code_get(res));
}
Ok(())
}
pub fn message_type_get(
&self,
message: *mut icsneoc2_message_t,
) -> Result<icsneoc2_msg_type_t> {
let mut value: icsneoc2_msg_type_t = 0;
let res: icsneoc2_error_t =
unsafe { ffi::icsneoc2_message_type_get(self.handle, message, &mut value) };
// Check the error code
if res != icsneoc2_error_success as icsneoc2_error_t {
return Err(Self::error_code_get(res));
}
Ok(value)
}
pub fn message_type_name_get(&self, msg_type: icsneoc2_msg_type_t) -> Result<String> {
// Get the string
let mut str: Vec<u8> = vec![0; 255];
let mut str_length: u32 = 255;
let res = unsafe {
icsneoc2_message_type_name_get(msg_type, str.as_mut_ptr() as *mut i8, &mut str_length)
};
// Check the error code
if res != icsneoc2_error_success as icsneoc2_error_t {
return Err(Self::error_code_get(res));
}
// Convert the vec to an String
str.resize(str_length as usize, 0);
let str_string = {
CString::new(str)
.expect("CString::new failed")
.into_string()
.expect("CString::new::into_string")
};
Ok(str_string)
}
pub fn netid_name_get(&self, netid: _icsneoc2_netid_t) -> Result<String> {
// Get the string
let mut str: Vec<u8> = vec![0; 255];
let mut str_length: u32 = 255;
let res =
unsafe { icsneoc2_netid_name_get(netid as icsneoc2_netid_t, str.as_mut_ptr() as *mut i8, &mut str_length) };
// Check the error code
if res != icsneoc2_error_success as icsneoc2_error_t {
return Err(Self::error_code_get(res));
}
// Convert the vec to an String
str.resize(str_length as usize, 0);
let str_string = {
CString::new(str)
.expect("CString::new failed")
.into_string()
.expect("CString::new::into_string")
};
Ok(str_string)
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_device_find_all() {
let devices = Device::find_all(0).unwrap();
assert_eq!(devices.len(), 0);
}
}
+18
View File
@@ -0,0 +1,18 @@
#!/bin/sh
VERSION="1.10.5"
ROOT="$PWD/libpcap"
SOURCE="$ROOT/source"
BUILD="$ROOT/build"
INSTALL="$ROOT/install"
mkdir -p "$ROOT"
cd "$ROOT" || exit 1
curl -LO "https://www.tcpdump.org/release/libpcap-$VERSION.tar.xz" || exit 1
tar -xf "libpcap-$VERSION.tar.xz" || exit 1
mv "libpcap-$VERSION" "$SOURCE" || exit 1
cmake -D CMAKE_POSITION_INDEPENDENT_CODE=ON -D CMAKE_INSTALL_PREFIX="$INSTALL" -D BUILD_SHARED_LIBS=OFF -D BUILD_WITH_LIBNL=OFF -D DISABLE_DBUS=ON -D DISABLE_LINUX_USBMON=ON -D DISABLE_BLUETOOTH=ON -D DISABLE_NETMAP=ON -D DISABLE_DPDK=ON -D DISABLE_RDMA=ON -D DISABLE_DAG=ON -D DISABLE_SEPTEL=ON -D DISABLE_SNF=ON -D DISABLE_TC=ON -B "$BUILD" -S "$SOURCE" || exit 1
cmake --build "$BUILD" || exit 1
cmake --install "$BUILD" || exit 1
+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
+7
View File
@@ -0,0 +1,7 @@
#!/bin/sh
python3 -m venv env || exit 1
. env/bin/activate || exit 1
python3 -m pip install cibuildwheel || exit 1
python3 -m cibuildwheel --output-dir wheelhouse || exit 1
+9
View File
@@ -0,0 +1,9 @@
@setlocal
@echo off
call "%VCVARS64_2022%"
python.exe -m venv env || exit /b 1
call env\Scripts\Activate.bat || exit /b 1
python.exe -m pip install cibuildwheel || exit /b 1
python.exe -m cibuildwheel --output-dir wheelhouse --platform windows || exit /b 1
+1 -1
View File
@@ -1,2 +1,2 @@
call "%VCVARS32%" call "%VCVARS32_2022%"
call "ci\build-windows.bat" call "ci\build-windows.bat"
+1 -1
View File
@@ -1,2 +1,2 @@
call "%VCVARS64%" call "%VCVARS64_2022%"
call "ci\build-windows.bat" call "ci\build-windows.bat"
+45 -48
View File
@@ -20,8 +20,6 @@ using namespace icsneo;
int Communication::messageCallbackIDCounter = 1; int Communication::messageCallbackIDCounter = 1;
Communication::~Communication() { Communication::~Communication() {
if(redirectingRead)
clearRedirectRead();
if(isOpen()) if(isOpen())
close(); close();
} }
@@ -44,6 +42,11 @@ void Communication::spawnThreads() {
void Communication::joinThreads() { void Communication::joinThreads() {
closing = true; closing = true;
if(pauseReadTask) {
resumeReads();
}
if(readTaskThread.joinable()) if(readTaskThread.joinable())
readTaskThread.join(); readTaskThread.join();
closing = false; closing = false;
@@ -96,23 +99,6 @@ bool Communication::sendCommand(ExtendedCommand cmd, std::vector<uint8_t> argume
return sendCommand(Command::Extended, arguments); return sendCommand(Command::Extended, arguments);
} }
bool Communication::redirectRead(std::function<void(std::vector<uint8_t>&&)> redirectTo) {
if(redirectingRead)
return false;
redirectionFn = redirectTo;
redirectingRead = true;
return true;
}
void Communication::clearRedirectRead() {
if(!redirectingRead)
return;
// The mutex is required to clear the redirection, but not to set it
std::lock_guard<std::mutex> lk(redirectingReadMutex);
redirectingRead = false;
redirectionFn = std::function<void(std::vector<uint8_t>&&)>();
}
bool Communication::getSettingsSync(std::vector<uint8_t>& data, std::chrono::milliseconds timeout) { bool Communication::getSettingsSync(std::vector<uint8_t>& data, std::chrono::milliseconds timeout) {
static const std::shared_ptr<MessageFilter> filter = std::make_shared<MessageFilter>(Network::NetID::ReadSettings); static const std::shared_ptr<MessageFilter> filter = std::make_shared<MessageFilter>(Network::NetID::ReadSettings);
std::shared_ptr<Message> msg = waitForMessageSync([this]() { std::shared_ptr<Message> msg = waitForMessageSync([this]() {
@@ -261,44 +247,55 @@ void Communication::dispatchMessage(const std::shared_ptr<Message>& msg) {
EventManager::GetInstance().downgradeErrorsOnCurrentThread(); EventManager::GetInstance().downgradeErrorsOnCurrentThread();
} }
void Communication::readTask() { void Communication::pauseReads() {
std::vector<uint8_t> readBytes; std::unique_lock<std::mutex> lk(pauseReadTaskMutex);
pauseReadTask = true;
}
void Communication::resumeReads() {
std::unique_lock<std::mutex> lk(pauseReadTaskMutex);
if(!pauseReadTask) {
return;
}
pauseReadTask = false;
lk.unlock();
pauseReadTaskCv.notify_one();
}
bool Communication::readsArePaused() {
std::unique_lock<std::mutex> lk(pauseReadTaskMutex);
return pauseReadTask;
}
void Communication::readTask() {
EventManager::GetInstance().downgradeErrorsOnCurrentThread(); EventManager::GetInstance().downgradeErrorsOnCurrentThread();
while(!closing) { while(!closing) {
readBytes.clear(); if(pauseReadTask) {
if(driver->readAvailable()) { std::unique_lock<std::mutex> lk(pauseReadTaskMutex);
handleInput(*packetizer, readBytes); pauseReadTaskCv.wait(lk, [this]() { return !pauseReadTask; });
}
if(driver->waitForRx(readTaskWakeLimit, readTaskWakeTimeout)) {
if(pauseReadTask) {
/**
* Reads could have paused while the driver was not available
*/
continue;
}
handleInput(*packetizer);
} }
} }
} }
void Communication::handleInput(Packetizer& p, std::vector<uint8_t>& readBytes) { void Communication::handleInput(Packetizer& p) {
if(redirectingRead) { if(p.input(driver->getReadBuffer())) {
// redirectingRead is an atomic so it can be set without acquiring a mutex for(const auto& packet : p.output()) {
// However, we do not clear it without the mutex. The idea is that if another std::shared_ptr<Message> msg;
// thread calls clearRedirectRead(), it will block until the redirectionFn if(!decoder->decode(msg, packet))
// finishes, and after that the redirectionFn will not be called again. continue;
std::unique_lock<std::mutex> lk(redirectingReadMutex);
// So after we acquire the mutex, we need to check the atomic again, and
// if it has become cleared, we *can not* run the redirectionFn.
if(redirectingRead) {
redirectionFn(std::move(readBytes));
} else {
// The redirectionFn got cleared while we were acquiring the lock
lk.unlock(); // We don't need the lock anymore
handleInput(p, readBytes); // and we might as well process this input ourselves
}
} else {
if(p.input(driver->getReadBuffer())) {
for(const auto& packet : p.output()) {
std::shared_ptr<Message> msg;
if(!decoder->decode(msg, packet))
continue;
dispatchMessage(msg); dispatchMessage(msg);
}
} }
} }
} }
+79 -24
View File
@@ -3,8 +3,9 @@
#include "icsneo/communication/message/serialnumbermessage.h" #include "icsneo/communication/message/serialnumbermessage.h"
#include "icsneo/communication/message/resetstatusmessage.h" #include "icsneo/communication/message/resetstatusmessage.h"
#include "icsneo/communication/message/readsettingsmessage.h" #include "icsneo/communication/message/readsettingsmessage.h"
#include "icsneo/communication/message/canerrorcountmessage.h" #include "icsneo/communication/message/canerrormessage.h"
#include "icsneo/communication/message/neoreadmemorysdmessage.h" #include "icsneo/communication/message/neoreadmemorysdmessage.h"
#include "icsneo/communication/message/flashmemorymessage.h"
#include "icsneo/communication/message/extendedresponsemessage.h" #include "icsneo/communication/message/extendedresponsemessage.h"
#include "icsneo/communication/message/wiviresponsemessage.h" #include "icsneo/communication/message/wiviresponsemessage.h"
#include "icsneo/communication/message/scriptstatusmessage.h" #include "icsneo/communication/message/scriptstatusmessage.h"
@@ -16,6 +17,11 @@
#include "icsneo/communication/message/extendeddatamessage.h" #include "icsneo/communication/message/extendeddatamessage.h"
#include "icsneo/communication/message/livedatamessage.h" #include "icsneo/communication/message/livedatamessage.h"
#include "icsneo/communication/message/diskdatamessage.h" #include "icsneo/communication/message/diskdatamessage.h"
#include "icsneo/communication/message/hardwareinfo.h"
#include "icsneo/communication/message/tc10statusmessage.h"
#include "icsneo/communication/message/gptpstatusmessage.h"
#include "icsneo/communication/message/apperrormessage.h"
#include "icsneo/communication/message/ethernetstatusmessage.h"
#include "icsneo/communication/command.h" #include "icsneo/communication/command.h"
#include "icsneo/device/device.h" #include "icsneo/device/device.h"
#include "icsneo/communication/packet/canpacket.h" #include "icsneo/communication/packet/canpacket.h"
@@ -35,6 +41,8 @@
#include "icsneo/communication/packet/mdiopacket.h" #include "icsneo/communication/packet/mdiopacket.h"
#include "icsneo/communication/packet/genericbinarystatuspacket.h" #include "icsneo/communication/packet/genericbinarystatuspacket.h"
#include "icsneo/communication/packet/livedatapacket.h" #include "icsneo/communication/packet/livedatapacket.h"
#include "icsneo/communication/packet/hardwareinfopacket.h"
#include <iostream> #include <iostream>
using namespace icsneo; using namespace icsneo;
@@ -81,13 +89,13 @@ bool Decoder::decode(std::shared_ptr<Message>& result, const std::shared_ptr<Pac
result->timestamp *= timestampResolution; result->timestamp *= timestampResolution;
switch(result->type) { switch(result->type) {
case Message::Type::Frame: { case Message::Type::BusMessage: {
CANMessage& can = *static_cast<CANMessage*>(result.get()); CANMessage& can = *static_cast<CANMessage*>(result.get());
can.network = packet->network; can.network = packet->network;
break; break;
} }
case Message::Type::CANErrorCount: { case Message::Type::CANErrorCount: {
CANErrorCountMessage& can = *static_cast<CANErrorCountMessage*>(result.get()); CANErrorMessage& can = *static_cast<CANErrorMessage*>(result.get());
can.network = packet->network; can.network = packet->network;
break; break;
} }
@@ -172,6 +180,7 @@ bool Decoder::decode(std::shared_ptr<Message>& result, const std::shared_ptr<Pac
LINMessage& msg = *static_cast<LINMessage*>(result.get()); LINMessage& msg = *static_cast<LINMessage*>(result.get());
msg.network = packet->network; msg.network = packet->network;
msg.timestamp *= timestampResolution;
return true; return true;
} }
case Network::Type::MDIO: { case Network::Type::MDIO: {
@@ -224,32 +233,49 @@ bool Decoder::decode(std::shared_ptr<Message>& result, const std::shared_ptr<Pac
// They come in as CAN but we will handle them in the device rather than // They come in as CAN but we will handle them in the device rather than
// passing them onto the user. // passing them onto the user.
if(packet->data.size() < 24) { if(packet->data.size() < 24) {
auto rawmsg = std::make_shared<RawMessage>(Network::NetID::Device); auto rawmsg = std::make_shared<InternalMessage>(Network::NetID::Device);
result = rawmsg; result = rawmsg;
rawmsg->data = packet->data; rawmsg->data = packet->data;
return true; return true;
} }
result = HardwareCANPacket::DecodeToMessage(packet->data); const auto can = std::dynamic_pointer_cast<CANMessage>(HardwareCANPacket::DecodeToMessage(packet->data));
if(!result) { if(!can) {
report(APIEvent::Type::PacketDecodingError, APIEvent::Severity::Error); report(APIEvent::Type::PacketDecodingError, APIEvent::Severity::Error);
return false; // A nullptr was returned, the packet was malformed return false;
}
if(can->arbid == 0x162) {
result = EthernetStatusMessage::DecodeToMessage(can->data);
if(!result) {
report(APIEvent::Type::PacketDecodingError, APIEvent::Severity::Error);
return false;
}
} else {
// TODO: move more handleNeoVIMessage handling here, the Decoder layer will parse the message and the Device layer can cache the values
can->network = packet->network;
result = can;
} }
// Timestamps are in (resolution) ns increments since 1/1/2007 GMT 00:00:00.0000 result->timestamp *= timestampResolution;
// The resolution depends on the device
auto* raw = dynamic_cast<RawMessage*>(result.get());
if(raw == nullptr) {
report(APIEvent::Type::PacketDecodingError, APIEvent::Severity::Error);
return false; // A nullptr was returned, the packet was malformed
}
raw->timestamp *= timestampResolution;
raw->network = packet->network;
return true; return true;
} }
case Network::NetID::DeviceStatus: { case Network::NetID::DeviceStatus: {
// Just pass along the data, the device needs to handle this itself // Just pass along the data, the device needs to handle this itself
result = std::make_shared<RawMessage>(packet->network, packet->data); result = std::make_shared<InternalMessage>(packet->network, packet->data);
return true;
}
case Network::NetID::RED_INT_MEMORYREAD: {
if(packet->data.size() != 512 + sizeof(uint16_t)) {
report(APIEvent::Type::PacketDecodingError, APIEvent::Severity::Error);
return false; // Should get enough data for a start address and sector
}
const auto msg = std::make_shared<FlashMemoryMessage>();
result = msg;
msg->startAddress = *reinterpret_cast<uint16_t*>(packet->data.data());
msg->data.insert(msg->data.end(), packet->data.begin() + 2, packet->data.end());
return true; return true;
} }
case Network::NetID::NeoMemorySDRead: { case Network::NetID::NeoMemorySDRead: {
@@ -266,11 +292,11 @@ bool Decoder::decode(std::shared_ptr<Message>& result, const std::shared_ptr<Pac
} }
case Network::NetID::ExtendedCommand: { case Network::NetID::ExtendedCommand: {
if(packet->data.size() < sizeof(ExtendedResponseMessage::PackedGenericResponse)) if(packet->data.size() < sizeof(ExtendedResponseMessage::ResponseHeader))
break; // Handle as a raw message, might not be a generic response break; // Handle as a raw message, might not be a generic response
const auto& resp = *reinterpret_cast<ExtendedResponseMessage::PackedGenericResponse*>(packet->data.data()); const auto& resp = *reinterpret_cast<ExtendedResponseMessage::ResponseHeader*>(packet->data.data());
switch(resp.header.command) { switch(resp.command) {
case ExtendedCommand::GetComponentVersions: case ExtendedCommand::GetComponentVersions:
result = ComponentVersionPacket::DecodeToMessage(packet->data); result = ComponentVersionPacket::DecodeToMessage(packet->data);
return true; return true;
@@ -280,14 +306,25 @@ bool Decoder::decode(std::shared_ptr<Message>& result, const std::shared_ptr<Pac
case ExtendedCommand::GenericBinaryInfo: case ExtendedCommand::GenericBinaryInfo:
result = GenericBinaryStatusPacket::DecodeToMessage(packet->data); result = GenericBinaryStatusPacket::DecodeToMessage(packet->data);
return true; return true;
case ExtendedCommand::GenericReturn: case ExtendedCommand::GenericReturn: {
result = std::make_shared<ExtendedResponseMessage>(resp.command, resp.returnCode); if(packet->data.size() < sizeof(ExtendedResponseMessage::PackedGenericResponse))
break;
const auto& packedResp = *reinterpret_cast<ExtendedResponseMessage::PackedGenericResponse*>(packet->data.data());
result = std::make_shared<ExtendedResponseMessage>(packedResp.command, packedResp.returnCode);
return true; return true;
}
case ExtendedCommand::LiveData: case ExtendedCommand::LiveData:
result = HardwareLiveDataPacket::DecodeToMessage(packet->data, report); result = HardwareLiveDataPacket::DecodeToMessage(packet->data, report);
return true; return true;
case ExtendedCommand::GetTC10Status:
result = TC10StatusMessage::DecodeToMessage(packet->data);
return true;
case ExtendedCommand::GetGPTPStatus: {
result = GPTPStatus::DecodeToMessage(packet->data, report);
return true;
}
default: default:
// No defined handler, treat this as a RawMessage // No defined handler, treat this as a InternalMessage
break; break;
} }
break; break;
@@ -358,6 +395,16 @@ bool Decoder::decode(std::shared_ptr<Message>& result, const std::shared_ptr<Pac
return true; return true;
} }
case Command::GetHardwareInfo: {
result = HardwareInfoPacket::DecodeToMessage(packet->data);
if(!result) {
report(APIEvent::Type::PacketDecodingError, APIEvent::Severity::Error);
return false;
}
return true;
}
default: default:
auto msg = std::make_shared<Main51Message>(); auto msg = std::make_shared<Main51Message>();
msg->command = Command(packet->data[0]); msg->command = Command(packet->data[0]);
@@ -381,6 +428,14 @@ bool Decoder::decode(std::shared_ptr<Message>& result, const std::shared_ptr<Pac
packet->data.resize(length); packet->data.resize(length);
return decode(result, packet); return decode(result, packet);
} }
case Network::NetID::RED_App_Error: {
result = AppErrorMessage::DecodeToMessage(packet->data, report);
if(!result) {
report(APIEvent::Type::PacketDecodingError, APIEvent::Severity::EventWarning);
return false;
}
return true;
}
case Network::NetID::ReadSettings: { case Network::NetID::ReadSettings: {
auto msg = std::make_shared<ReadSettingsMessage>(); auto msg = std::make_shared<ReadSettingsMessage>();
msg->response = ReadSettingsMessage::Response(packet->data[0]); msg->response = ReadSettingsMessage::Response(packet->data[0]);
@@ -444,6 +499,6 @@ bool Decoder::decode(std::shared_ptr<Message>& result, const std::shared_ptr<Pac
} }
// For the moment other types of messages will automatically be decoded as raw messages // For the moment other types of messages will automatically be decoded as raw messages
result = std::make_shared<RawMessage>(packet->network, packet->data); result = std::make_shared<InternalMessage>(packet->network, packet->data);
return true; return true;
} }
+34 -6
View File
@@ -8,6 +8,35 @@
using namespace icsneo; using namespace icsneo;
bool Driver::pushRx(const uint8_t* buf, size_t numReceived) {
bool ret = readBuffer.write(buf, numReceived);
rxWaitCv.notify_all();
return ret;
}
void Driver::clearBuffers()
{
WriteOperation flushop;
readBuffer.clear();
rxWaitCv.notify_all();
while (writeQueue.try_dequeue(flushop)) {}
}
bool Driver::waitForRx(size_t limit, std::chrono::milliseconds timeout) {
return waitForRx([limit, this]() {
return readBuffer.size() >= limit;
}, timeout);
}
bool Driver::waitForRx(std::function<bool()> predicate, std::chrono::milliseconds timeout) {
std::unique_lock<std::mutex> lk(rxWaitMutex);
return rxWaitCv.wait_for(lk, timeout, predicate);
}
bool Driver::readWait(std::vector<uint8_t>& bytes, std::chrono::milliseconds timeout, size_t limit) { bool Driver::readWait(std::vector<uint8_t>& bytes, std::chrono::milliseconds timeout, size_t limit) {
// A limit of zero indicates no limit // A limit of zero indicates no limit
if(limit == 0) if(limit == 0)
@@ -16,14 +45,13 @@ bool Driver::readWait(std::vector<uint8_t>& bytes, std::chrono::milliseconds tim
if(limit > (readBuffer.size() + 4)) if(limit > (readBuffer.size() + 4))
limit = (readBuffer.size() + 4); limit = (readBuffer.size() + 4);
bytes.resize(limit);
// wait until we have enough data, or the timout occurs // wait until we have enough data, or the timout occurs
const auto timeoutTime = std::chrono::steady_clock::now() + timeout; waitForRx(limit, timeout);
while (readBuffer.size() < limit && std::chrono::steady_clock::now() < timeoutTime) {
std::this_thread::sleep_for(std::chrono::milliseconds(1));
}
size_t actuallyRead = std::min(readBuffer.size(), limit); size_t actuallyRead = std::min(readBuffer.size(), limit);
bytes.resize(actuallyRead);
readBuffer.read(bytes.data(), 0, actuallyRead); readBuffer.read(bytes.data(), 0, actuallyRead);
readBuffer.pop(actuallyRead); readBuffer.pop(actuallyRead);
bytes.resize(actuallyRead); bytes.resize(actuallyRead);
@@ -66,4 +94,4 @@ bool Driver::write(const std::vector<uint8_t>& bytes) {
report(APIEvent::Type::Unknown, APIEvent::Severity::Error); report(APIEvent::Type::Unknown, APIEvent::Severity::Error);
return ret; return ret;
} }
+5 -5
View File
@@ -23,8 +23,8 @@ bool Encoder::encode(const Packetizer& packetizer, std::vector<uint8_t>& result,
result.clear(); result.clear();
switch(message->type) { switch(message->type) {
case Message::Type::Frame: { case Message::Type::BusMessage: {
auto frame = std::dynamic_pointer_cast<Frame>(message); auto frame = std::dynamic_pointer_cast<BusMessage>(message);
// Frame uses frame->data as the buffer unless directed otherwise // Frame uses frame->data as the buffer unless directed otherwise
buffer = &frame->data; buffer = &frame->data;
@@ -130,8 +130,8 @@ bool Encoder::encode(const Packetizer& packetizer, std::vector<uint8_t>& result,
break; break;
} }
case Message::Type::RawMessage: { case Message::Type::InternalMessage: {
auto raw = std::dynamic_pointer_cast<RawMessage>(message); auto raw = std::dynamic_pointer_cast<InternalMessage>(message);
// Raw message uses raw->data as the buffer unless directed otherwise // Raw message uses raw->data as the buffer unless directed otherwise
buffer = &raw->data; buffer = &raw->data;
@@ -243,7 +243,7 @@ bool Encoder::encode(const Packetizer& packetizer, std::vector<uint8_t>& result,
* In this case, command 0x06 is SetLEDState. * In this case, command 0x06 is SetLEDState.
* This old command type is not really used anywhere else. * This old command type is not really used anywhere else.
*/ */
auto canmsg = std::make_shared<RawMessage>(Network::NetID::Device); auto canmsg = std::make_shared<InternalMessage>(Network::NetID::Device);
msg = canmsg; msg = canmsg;
if(arguments.empty()) { if(arguments.empty()) {
report(APIEvent::Type::MessageFormattingError, APIEvent::Severity::Error); report(APIEvent::Type::MessageFormattingError, APIEvent::Severity::Error);
+148
View File
@@ -0,0 +1,148 @@
#include <icsneo/communication/message/apperrormessage.h>
namespace icsneo {
#pragma pack(push, 2)
typedef struct {
uint16_t error_type;
uint16_t network_id;
uint32_t uiTimeStamp10uS;
uint32_t uiTimeStamp10uSMSB;
} AppErrorData;
#pragma pack(pop)
std::shared_ptr<Message> AppErrorMessage::DecodeToMessage(const std::vector<uint8_t>& bytestream, const device_eventhandler_t& report) {
const AppErrorData* data = reinterpret_cast<const AppErrorData*>(bytestream.data());
if(!data) {
report(APIEvent::Type::AppErrorParsingFailed, APIEvent::Severity::Error);
return nullptr;
}
auto appErr = std::make_shared<AppErrorMessage>();
appErr->errorType = data->error_type;
appErr->errorNetID = static_cast<Network::NetID>(data->network_id);
appErr->timestamp10us = data->uiTimeStamp10uS;
appErr->timestamp10usMSB = data->uiTimeStamp10uSMSB;
appErr->network = Network::NetID::RED_App_Error;
return appErr;
}
AppErrorType AppErrorMessage::getAppErrorType() {
AppErrorType errType = static_cast<AppErrorType>(errorType);
if(errType > AppErrorType::AppNoError) {
return AppErrorType::AppNoError;
}
return errType;
}
std::string AppErrorMessage::getAppErrorString() {
auto netIDString = Network::GetNetIDString(errorNetID);
AppErrorType errType = static_cast<AppErrorType>(errorType);
switch (errType) {
case AppErrorType::AppErrorRxMessagesFull:
return std::string(netIDString) + ": RX message buffer full";
case AppErrorType::AppErrorTxMessagesFull:
return std::string(netIDString) + ": TX message buffer full";
case AppErrorType::AppErrorTxReportMessagesFull:
return std::string(netIDString) + ": TX report buffer full";
case AppErrorType::AppErrorBadCommWithDspIC:
return "Received bad packet from DSP IC";
case AppErrorType::AppErrorDriverOverflow:
return std::string(netIDString) + ": Driver overflow";
case AppErrorType::AppErrorPCBuffOverflow:
return "PC buffer overflow";
case AppErrorType::AppErrorPCChksumError:
return "PC checksum error";
case AppErrorType::AppErrorPCMissedByte:
return "PC missed byte";
case AppErrorType::AppErrorPCOverrunError:
return "PC overrun error";
case AppErrorType::AppErrorSettingFailure:
return std::string(netIDString) + ": Settings incorrectly set";
case AppErrorType::AppErrorTooManySelectedNetworks:
return "Too many selected networks";
case AppErrorType::AppErrorNetworkNotEnabled:
return std::string(netIDString) + ": Network not enabled";
case AppErrorType::AppErrorRtcNotCorrect:
return "RTC not correct";
case AppErrorType::AppErrorLoadedDefaultSettings:
return "Loaded default settings";
case AppErrorType::AppErrorFeatureNotUnlocked:
return "Feature not unlocked";
case AppErrorType::AppErrorFeatureRtcCmdDropped:
return "RTC command dropped";
case AppErrorType::AppErrorTxMessagesFlushed:
return "TX message buffer flushed";
case AppErrorType::AppErrorTxMessagesHalfFull:
return "TX message buffer half full";
case AppErrorType::AppErrorNetworkNotValid:
return "Network is not valid";
case AppErrorType::AppErrorTxInterfaceNotImplemented:
return "TX interface is not implemented";
case AppErrorType::AppErrorTxMessagesCommEnableIsOff:
return "TX message communication is disabled";
case AppErrorType::AppErrorRxFilterMatchCountExceeded:
return "RX filter match count exceeded";
case AppErrorType::AppErrorEthPreemptionNotEnabled:
return std::string(netIDString) + ": Ethernet preemption not enabled";
case AppErrorType::AppErrorTxNotSupportedInMode:
return std::string(netIDString) + ": Transmit is not supported in this mode";
case AppErrorType::AppErrorJumboFramesNotSupported:
return std::string(netIDString) + ": Jumbo frames not supported";
case AppErrorType::AppErrorEthernetIpFragment:
return "Ethernet IP fragment received";
case AppErrorType::AppErrorTxMessagesUnderrun:
return std::string(netIDString) + ": Transmit buffer underrun";
case AppErrorType::AppErrorDeviceFanFailure:
return "Device fan failure";
case AppErrorType::AppErrorDeviceOvertemperature:
return "Device overtemperature";
case AppErrorType::AppErrorTxMessageIndexOutOfRange:
return "Transmit message index out of range";
case AppErrorType::AppErrorUndersizedFrameDropped:
return std::string(netIDString) + ": Undersized frame dropped";
case AppErrorType::AppErrorOversizedFrameDropped:
return std::string(netIDString) + ": Oversized frame dropped";
case AppErrorType::AppErrorWatchdogEvent:
return "Watchdog event occured";
case AppErrorType::AppErrorSystemClockFailure:
return "Device clock failed";
case AppErrorType::AppErrorSystemClockRecovered:
return "Device clock recovered";
case AppErrorType::AppErrorSystemPeripheralReset:
return "Device peripheral reset";
case AppErrorType::AppErrorSystemCommunicationFailure:
return "Device communication failure";
case AppErrorType::AppErrorTxMessagesUnsupportedSourceOrPacketId:
return std::string(netIDString) + ": Transmit unsupported source or packet ID";
case AppErrorType::AppErrorWbmsManagerConnectFailed:
return std::string(netIDString) + ": Failed to connect to managers with settings";
case AppErrorType::AppErrorWbmsManagerConnectBadState:
return std::string(netIDString) + ": Connected to managers in a invalid state";
case AppErrorType::AppErrorWbmsManagerConnectTimeout:
return std::string(netIDString) + ": Timeout while attempting to connect to managers";
case AppErrorType::AppErrorFailedToInitializeLoggerDisk:
return "Device failed to initialize storage disk";
case AppErrorType::AppErrorInvalidSetting:
return std::string(netIDString) + ": Invalid settings";
case AppErrorType::AppErrorSystemFailureRequestedReset:
return "Device rebooted to recover from an unexpected error condition";
case AppErrorType::AppErrorPortKeyMistmatch:
return std::string(netIDString) + ": Mismatch between key in manager and stored key";
case AppErrorType::AppErrorBusFailure:
return std::string(netIDString) + ": Bus failure";
case AppErrorType::AppErrorTapOverflow:
return std::string(netIDString) + ": Tap overflow";
case AppErrorType::AppErrorEthTxNoLink:
return std::string(netIDString) + ": Attempted Ethernet transmit without link";
case AppErrorType::AppErrorErrorBufferOverflow:
return "Device error buffer overflow";
case AppErrorType::AppNoError:
return "No error";
default:
return "Unknown error";
}
}
} // namespace icsneo
@@ -102,11 +102,11 @@ bool A2BWAVOutput::callIfMatch(const std::shared_ptr<Message>& message) const {
return false; return false;
} }
if(message->type != Message::Type::Frame) { if(message->type != Message::Type::BusMessage) {
return false; return false;
} }
const auto& frameMsg = std::dynamic_pointer_cast<Frame>(message); const auto& frameMsg = std::dynamic_pointer_cast<BusMessage>(message);
if(!frameMsg) { if(!frameMsg) {
return false; return false;
@@ -0,0 +1,57 @@
#include "icsneo/communication/message/ethernetstatusmessage.h"
using namespace icsneo;
#pragma pack(push, 1)
enum LinkSpeed {
ethSpeed10,
ethSpeed100,
ethSpeed1000,
ethSpeedAutoNeg,
ethSpeed2500,
ethSpeed5000,
ethSpeed10000,
};
enum LinkMode {
OPETH_LINK_AUTO,
OPETH_LINK_MASTER,
OPETH_LINK_SLAVE,
OPETH_LINK_INVALID = 255,
};
struct Packet {
uint8_t state;
uint8_t speed;
uint8_t duplex;
uint16_t network;
uint8_t mode;
};
#pragma pack(pop)
std::shared_ptr<Message> EthernetStatusMessage::DecodeToMessage(const std::vector<uint8_t>& bytestream) {
if(bytestream.size() < sizeof(Packet)) {
return nullptr;
}
Packet* packet = (Packet*)bytestream.data();
LinkSpeed speed;
switch(packet->speed) {
case ethSpeed10: speed = EthernetStatusMessage::LinkSpeed::LinkSpeed10; break;
case ethSpeed100: speed = EthernetStatusMessage::LinkSpeed::LinkSpeed100; break;
case ethSpeed1000: speed = EthernetStatusMessage::LinkSpeed::LinkSpeed1000; break;
case ethSpeedAutoNeg: speed = EthernetStatusMessage::LinkSpeed::LinkSpeedAuto; break;
case ethSpeed2500: speed = EthernetStatusMessage::LinkSpeed::LinkSpeed2500; break;
case ethSpeed5000: speed = EthernetStatusMessage::LinkSpeed::LinkSpeed5000; break;
case ethSpeed10000: speed = EthernetStatusMessage::LinkSpeed::LinkSpeed10000; break;
default: return nullptr;
}
LinkMode mode;
switch(packet->mode) {
case OPETH_LINK_INVALID: mode = EthernetStatusMessage::LinkMode::LinkModeInvalid; break;
case OPETH_LINK_AUTO: mode = EthernetStatusMessage::LinkMode::LinkModeAuto; break;
case OPETH_LINK_MASTER: mode = EthernetStatusMessage::LinkMode::LinkModeMaster; break;
case OPETH_LINK_SLAVE: mode = EthernetStatusMessage::LinkMode::LinkModeSlave; break;
default: return nullptr;
}
return std::make_shared<EthernetStatusMessage>(packet->network, packet->state, speed, packet->duplex, mode);
}
+219
View File
@@ -0,0 +1,219 @@
#include <icsneo/communication/message/gptpstatusmessage.h>
#include <icsneo/communication/message/extendedresponsemessage.h>
#include <cstring>
namespace icsneo {
typedef double float64;
typedef int64_t time_interval;
typedef uint64_t _clock_identity;
#pragma pack(push, 1)
struct port_identity {
_clock_identity clock_identity;
uint16_t port_number;
};
struct _scaled_ns {
int16_t nanoseconds_msb;
int64_t nanoseconds_lsb;
int16_t fractional_nanoseconds;
};
struct _clock_quality {
uint8_t clock_class;
uint8_t clock_accuracy;
uint16_t offset_scaled_log_variance;
};
struct system_identity {
uint8_t priority_1;
struct _clock_quality clock_quality;
uint8_t priority_2;
_clock_identity clock_identity;
};
struct _timestamp {
uint16_t seconds_msb;
uint32_t seconds_lsb;
uint32_t nanoseconds;
};
struct priority_vector {
struct system_identity sysid;
uint16_t steps_removed;
struct port_identity portid;
uint16_t port_number;
};
// IEEE 802.1AS-2020 14.3
// This is a read-only data structure
struct _current_ds {
uint16_t steps_removed;
time_interval offset_from_master;
struct _scaled_ns last_gm_phase_change;
float64 last_gm_freq_change;
uint16_t gm_time_base_indicator;
uint32_t gm_change_count;
uint32_t time_of_last_gm_change_event;
uint32_t time_of_last_gm_phase_change_event;
uint32_t time_of_last_gm_freq_change_event;
};
// IEEE 802.1AS-2020 14.4
// This is a read-only data structure
struct _parent_ds {
struct port_identity parent_port_identity;
int32_t cumulative_rate_ratio;
_clock_identity grandmaster_identity;
uint8_t gm_clock_quality_clock_class;
uint8_t gm_clock_quality_clock_accuracy;
uint16_t gm_clock_quality_offset_scaled_log_variance;
uint8_t gm_priority1;
uint8_t gm_priority2;
};
struct _GPTPStatus
{
struct _timestamp current_time;
struct priority_vector gm_priority;
int64_t ms_offset_ns;
uint8_t is_sync;
uint8_t link_status;
int64_t link_delay_ns;
uint8_t selected_role;
uint8_t as_capable;
uint8_t is_syntonized;
struct _timestamp last_rx_sync_ts; // t2 in IEEE 1588-2019 Figure-16
struct _current_ds current_ds;
struct _parent_ds parent_ds;
};
#pragma pack(pop)
static void SetField(GPTPStatus::Timestamp& output, const _timestamp& input) {
output.seconds = ((uint64_t)(input.seconds_msb) << 32) | ((uint64_t)input.seconds_lsb);
output.nanoseconds = input.nanoseconds;
}
static void SetField(GPTPStatus::PortID& output, const port_identity& input) {
output.clockIdentity = input.clock_identity;
output.portNumber = input.port_number;
}
static void SetField(GPTPStatus::ClockQuality& output, const _clock_quality& input) {
output.clockClass = input.clock_class;
output.clockAccuracy = input.clock_accuracy;
output.offsetScaledLogVariance = input.offset_scaled_log_variance;
}
static void SetField(GPTPStatus::SystemID& output, const system_identity& input) {
output.priority1 = input.priority_1;
SetField(output.clockQuality, input.clock_quality);
output.priority2 = input.priority_2;
output.clockID = input.clock_identity;
}
static void SetField(GPTPStatus::ScaledNanoSeconds& output, const _scaled_ns& input) {
output.nanosecondsMSB = input.nanoseconds_msb;
output.nanosecondsLSB = input.nanoseconds_lsb;
output.fractionalNanoseconds = input.fractional_nanoseconds;
}
static void SetField(GPTPStatus::PriorityVector& output, const priority_vector& input) {
SetField(output.sysID, input.sysid);
output.stepsRemoved = input.steps_removed;
SetField(output.portID, input.portid);
output.portNumber = input.port_number;
}
static void SetField(GPTPStatus::CurrentDS& output, const _current_ds& input) {
output.stepsRemoved = input.steps_removed;
output.offsetFromMaster = input.offset_from_master;
SetField(output.lastgmPhaseChange, input.last_gm_phase_change);
output.lastgmFreqChange = input.last_gm_freq_change;
output.gmTimeBaseIndicator = input.gm_time_base_indicator;
output.gmChangeCount = input.gm_change_count;
output.timeOfLastgmChangeEvent = input.time_of_last_gm_change_event;
output.timeOfLastgmPhaseChangeEvent = input.time_of_last_gm_phase_change_event;
output.timeOfLastgmFreqChangeEvent = input.time_of_last_gm_freq_change_event;
}
static void SetField(GPTPStatus::ParentDS& output, const _parent_ds& input) {
SetField(output.parentPortIdentity, input.parent_port_identity);
output.cumulativeRateRatio = input.cumulative_rate_ratio;
output.grandmasterIdentity = input.grandmaster_identity;
output.gmClockQualityClockClass = input.gm_clock_quality_clock_class;
output.gmClockQualityClockAccuracy = input.gm_clock_quality_clock_accuracy;
output.gmClockQualityOffsetScaledLogVariance = input.gm_clock_quality_offset_scaled_log_variance;
output.gmPriority1 = input.gm_priority1;
output.gmPriority2 = input.gm_priority2;
}
[[maybe_unused]] static void SetField(uint8_t& output, const uint8_t& input) {
output = input;
}
[[maybe_unused]] static void SetField(uint16_t& output, const uint16_t& input) {
output = input;
}
[[maybe_unused]] static void SetField(uint32_t& output, const uint32_t& input) {
output = input;
}
[[maybe_unused]] static void SetField(uint64_t& output, const uint64_t& input) {
output = input;
}
[[maybe_unused]] static void SetField(int8_t& output, const int8_t& input) {
output = input;
}
[[maybe_unused]] static void SetField(int16_t& output, const int16_t& input) {
output = input;
}
[[maybe_unused]] static void SetField(int32_t& output, const int32_t& input) {
output = input;
}
[[maybe_unused]] static void SetField(int64_t& output, const int64_t& input) {
output = input;
}
std::shared_ptr<GPTPStatus> GPTPStatus::DecodeToMessage(std::vector<uint8_t>& bytes, const device_eventhandler_t&) {
// The following does not lead to overflow since we only call this function if it has at least ResponseHeader length bytes
std::shared_ptr<GPTPStatus> res = std::make_shared<GPTPStatus>();
auto* header = reinterpret_cast<ExtendedResponseMessage::ResponseHeader*>(bytes.data());
uint16_t length = header->length;
_GPTPStatus* input = reinterpret_cast<_GPTPStatus*>(bytes.data() + sizeof(ExtendedResponseMessage::ResponseHeader));
#define CheckLengthAndSet(output, input) if(length >= sizeof(decltype(input))) { \
SetField(output, input); \
length -= sizeof(decltype(input)); \
} else {\
memset(&output, 0, sizeof(decltype(output))); \
length = 0; \
res->shortFormat = true; \
}
CheckLengthAndSet(res->currentTime, input->current_time);
CheckLengthAndSet(res->gmPriority, input->gm_priority);
CheckLengthAndSet(res->msOffsetNs, input->ms_offset_ns);
CheckLengthAndSet(res->isSync, input->is_sync);
CheckLengthAndSet(res->linkStatus, input->link_status);
CheckLengthAndSet(res->linkDelayNS, input->link_delay_ns);
CheckLengthAndSet(res->selectedRole, input->selected_role);
CheckLengthAndSet(res->asCapable, input->as_capable);
CheckLengthAndSet(res->isSyntonized, input->is_syntonized);
CheckLengthAndSet(res->lastRXSyncTS, input->last_rx_sync_ts);
CheckLengthAndSet(res->currentDS, input->current_ds);
CheckLengthAndSet(res->parentDS, input->parent_ds);
return res;
}
}
+6 -6
View File
@@ -1,7 +1,7 @@
#include "icsneo/communication/message/neomessage.h" #include "icsneo/communication/message/neomessage.h"
#include "icsneo/communication/message/canmessage.h" #include "icsneo/communication/message/canmessage.h"
#include "icsneo/communication/message/ethernetmessage.h" #include "icsneo/communication/message/ethernetmessage.h"
#include "icsneo/communication/message/canerrorcountmessage.h" #include "icsneo/communication/message/canerrormessage.h"
#include "icsneo/communication/message/linmessage.h" #include "icsneo/communication/message/linmessage.h"
using namespace icsneo; using namespace icsneo;
@@ -14,9 +14,9 @@ neomessage_t icsneo::CreateNeoMessage(const std::shared_ptr<Message> message) {
neomsg.timestamp = message->timestamp; neomsg.timestamp = message->timestamp;
switch (message->type) switch (message->type)
{ {
case Message::Type::Frame: { case Message::Type::BusMessage: {
neomessage_frame_t& frame = *(neomessage_frame_t*)&neomsg; neomessage_frame_t& frame = *(neomessage_frame_t*)&neomsg;
auto framemsg = std::static_pointer_cast<Frame>(message); auto framemsg = std::static_pointer_cast<BusMessage>(message);
const auto netType = framemsg->network.getType(); const auto netType = framemsg->network.getType();
frame.netid = (neonetid_t)framemsg->network.getNetID(); frame.netid = (neonetid_t)framemsg->network.getNetID();
@@ -51,7 +51,7 @@ neomessage_t icsneo::CreateNeoMessage(const std::shared_ptr<Message> message) {
eth.status.incompleteFrame = ethmsg->frameTooShort; eth.status.incompleteFrame = ethmsg->frameTooShort;
// TODO Fill in extra status bits // TODO Fill in extra status bits
//eth.status.xyz = ethmsg->preemptionEnabled; //eth.status.xyz = ethmsg->preemptionEnabled;
//eth.status.xyz = ethmsg->fcsAvailable; //eth.status.xyz = ethmsg->fcs;
//eth.status.xyz = ethmsg->noPadding; //eth.status.xyz = ethmsg->noPadding;
break; break;
} }
@@ -104,7 +104,7 @@ neomessage_t icsneo::CreateNeoMessage(const std::shared_ptr<Message> message) {
} }
case Message::Type::CANErrorCount: { case Message::Type::CANErrorCount: {
neomessage_can_error_t& canerror = *(neomessage_can_error_t*)&neomsg; neomessage_can_error_t& canerror = *(neomessage_can_error_t*)&neomsg;
auto canerrormsg = std::static_pointer_cast<CANErrorCountMessage>(message); auto canerrormsg = std::static_pointer_cast<CANErrorMessage>(message);
canerror.transmitErrorCount = canerrormsg->transmitErrorCount; canerror.transmitErrorCount = canerrormsg->transmitErrorCount;
canerror.receiveErrorCount = canerrormsg->receiveErrorCount; canerror.receiveErrorCount = canerrormsg->receiveErrorCount;
canerror.status.canBusOff = canerrormsg->busOff; canerror.status.canBusOff = canerrormsg->busOff;
@@ -120,7 +120,7 @@ neomessage_t icsneo::CreateNeoMessage(const std::shared_ptr<Message> message) {
std::shared_ptr<Message> icsneo::CreateMessageFromNeoMessage(const neomessage_t* neomessage) { std::shared_ptr<Message> icsneo::CreateMessageFromNeoMessage(const neomessage_t* neomessage) {
switch((Message::Type)neomessage->messageType) { switch((Message::Type)neomessage->messageType) {
case Message::Type::Frame: { case Message::Type::BusMessage: {
const Network network = ((neomessage_frame_t*)neomessage)->netid; const Network network = ((neomessage_frame_t*)neomessage)->netid;
switch(network.getType()) { switch(network.getType()) {
case Network::Type::CAN: case Network::Type::CAN:
@@ -0,0 +1,31 @@
#include "icsneo/communication/message/tc10statusmessage.h"
#include "icsneo/communication/command.h"
using namespace icsneo;
#pragma pack(push, 2)
struct Header {
ExtendedCommand command;
uint16_t length;
};
struct Packet {
Header header;
TC10WakeStatus wakeStatus;
TC10SleepStatus sleepStatus;
};
#pragma pack(pop)
std::shared_ptr<TC10StatusMessage> TC10StatusMessage::DecodeToMessage(const std::vector<uint8_t>& bytestream) {
if(bytestream.size() < sizeof(Packet)) {
return nullptr;
}
const Packet* packet = (Packet*)bytestream.data();
if (packet->header.command != ExtendedCommand::GetTC10Status) {
return nullptr;
}
if (packet->header.length < sizeof(Packet) - sizeof(Header)) {
return nullptr;
}
return std::make_shared<TC10StatusMessage>(packet->wakeStatus, packet->sleepStatus);
}
+5 -2
View File
@@ -177,8 +177,11 @@ void MultiChannelCommunication::vnetReadTask(size_t vnetIndex) {
if(queue.wait_dequeue_timed(payloadBytes, std::chrono::milliseconds(250))) { if(queue.wait_dequeue_timed(payloadBytes, std::chrono::milliseconds(250))) {
if(closing) if(closing)
break; break;
handleInput(*vnetPacketizer, payloadBytes); auto& ringBuffer = driver->getReadBuffer();
ringBuffer.write(payloadBytes);
handleInput(*vnetPacketizer);
} }
} }
} }
+13 -11
View File
@@ -1,9 +1,9 @@
#include "icsneo/communication/packet/canpacket.h" #include "icsneo/communication/packet/canpacket.h"
#include "icsneo/communication/message/canerrorcountmessage.h" #include "icsneo/communication/message/canerrormessage.h"
using namespace icsneo; using namespace icsneo;
static std::optional<uint8_t> CAN_DLCToLength(uint8_t length, bool fd) { std::optional<uint8_t> icsneo::CAN_DLCToLength(uint8_t length, bool fd) {
if (length <= 8) if (length <= 8)
return length; return length;
@@ -29,7 +29,7 @@ static std::optional<uint8_t> CAN_DLCToLength(uint8_t length, bool fd) {
return std::nullopt; return std::nullopt;
} }
static std::optional<uint8_t> CAN_LengthToDLC(size_t dataLength, bool fd) std::optional<uint8_t> icsneo::CAN_LengthToDLC(size_t dataLength, bool fd)
{ {
if (dataLength <= 8) if (dataLength <= 8)
return uint8_t(dataLength); return uint8_t(dataLength);
@@ -53,16 +53,18 @@ static std::optional<uint8_t> CAN_LengthToDLC(size_t dataLength, bool fd)
return std::nullopt; return std::nullopt;
} }
std::shared_ptr<Message> HardwareCANPacket::DecodeToMessage(const std::vector<uint8_t>& bytestream) { std::shared_ptr<Message> HardwareCANPacket::DecodeToMessage(const std::vector<uint8_t>& bytestream) {
const HardwareCANPacket* data = (const HardwareCANPacket*)bytestream.data(); const HardwareCANPacket* data = (const HardwareCANPacket*)bytestream.data();
const HardwareCANErrorPacket* errPacket = (const HardwareCANErrorPacket*)bytestream.data();
if(data->dlc.RB1) { // Change counts reporting if(errPacket->ERROR_INDICATOR) {
auto msg = std::make_shared<CANErrorMessage>();
const bool busOff = data->data[0] & 0b00100000; msg->receiveErrorCount = errPacket->REC;
msg->transmitErrorCount = errPacket->TEC;
auto msg = std::make_shared<CANErrorCountMessage>(data->data[2], data->data[1], busOff); msg->errorWarn = HardwareCANErrorPacket::GetErrorWarn(errPacket->flags);
msg->errorPassive = HardwareCANErrorPacket::GetErrorPassive(errPacket->flags);
msg->busOff = HardwareCANErrorPacket::GetBusOff(errPacket->flags);
msg->errorCode = (CANErrorCode)errPacket->error_code;
msg->dataErrorCode = (CANErrorCode)errPacket->brs_data_error_code;
// 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
msg->timestamp = data->timestamp.TS; msg->timestamp = data->timestamp.TS;
+9 -8
View File
@@ -16,8 +16,8 @@ std::shared_ptr<EthernetMessage> HardwareEthernetPacket::DecodeToMessage(const s
if(packet->Length < 4) if(packet->Length < 4)
return nullptr; return nullptr;
const size_t ethernetFrameSize = packet->Length - (sizeof(uint16_t) * 2); const size_t fcsSize = packet->header.FCS_AVAIL ? 4 : 0;
const size_t bytestreamExpectedSize = sizeof(HardwareEthernetPacket) + ethernetFrameSize; 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;
@@ -36,8 +36,6 @@ std::shared_ptr<EthernetMessage> HardwareEthernetPacket::DecodeToMessage(const s
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.fcsAvailable = packet->header.FCS_AVAIL;
message.frameTooShort = packet->header.RUNT_FRAME; message.frameTooShort = packet->header.RUNT_FRAME;
if(message.frameTooShort) if(message.frameTooShort)
@@ -47,11 +45,14 @@ std::shared_ptr<EthernetMessage> HardwareEthernetPacket::DecodeToMessage(const s
// 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;
// Network ID is also not set, this will be fixed in the Decoder as well const std::vector<uint8_t>::const_iterator databegin = bytestream.begin() + sizeof(HardwareEthernetPacket);
const std::vector<uint8_t>::const_iterator dataend = databegin + packet->Length - fcsSize;
const std::vector<uint8_t>::const_iterator databegin = bytestream.begin() + (sizeof(HardwareEthernetPacket) - (sizeof(uint16_t) * 2));
const std::vector<uint8_t>::const_iterator dataend = databegin + ethernetFrameSize;
message.data.insert(message.data.begin(), databegin, dataend); message.data.insert(message.data.begin(), databegin, dataend);
if(fcsSize) {
uint32_t& fcs = message.fcs.emplace();
std::copy(dataend, dataend + fcsSize, (uint8_t*)&fcs);
}
return messagePtr; return messagePtr;
} }
@@ -0,0 +1,50 @@
#include "icsneo/communication/packet/hardwareinfopacket.h"
#include "icsneo/communication/message/hardwareinfo.h"
#include <iostream>
using namespace icsneo;
#pragma pack(push, 1)
typedef struct
{
uint8_t valid;
struct
{
uint8_t day;
uint8_t month;
uint16_t year;
} manufactureDate;
struct
{
uint8_t major;
uint8_t minor;
} hwRev;
uint8_t deviceId;
struct
{
uint8_t major;
uint8_t minor;
} blVersion;
} HardwareInfoFrame;
#pragma pack(pop)
std::shared_ptr<HardwareInfo> HardwareInfoPacket::DecodeToMessage(const std::vector<uint8_t>& bytes) {
if(bytes.size() < (sizeof(HardwareInfoFrame) + 1)) {
return nullptr;
}
const auto* frame = reinterpret_cast<const HardwareInfoFrame*>(&bytes[1]);
auto msg = std::make_shared<HardwareInfo>();
msg->manufactureDate.day = frame->manufactureDate.day;
msg->manufactureDate.year = frame->manufactureDate.year;
msg->manufactureDate.month = frame->manufactureDate.month;
msg->hardwareRevision.major = frame->hwRev.major;
msg->hardwareRevision.minor = frame->hwRev.minor;
msg->bootloaderVersion.major = frame->blVersion.major;
msg->bootloaderVersion.minor = frame->blVersion.minor;
return msg;
}
+240 -20
View File
@@ -218,8 +218,7 @@ bool Device::open(OpenFlags flags, OpenStatusHandler handler) {
if(block) // Extensions say no if(block) // Extensions say no
return false; return false;
// Get component versions *after* the extension "onDeviceOpen" hooks (e.g. device reflashes) // Get component versions again *after* the extension "onDeviceOpen" hooks (e.g. device reflashes)
if(supportsComponentVersions()) { if(supportsComponentVersions()) {
if(auto compVersions = com->getComponentVersionsSync()) if(auto compVersions = com->getComponentVersionsSync())
componentVersions = std::move(*compVersions); componentVersions = std::move(*compVersions);
@@ -348,6 +347,15 @@ APIEvent::Type Device::attemptToBeginCommunication() {
else else
versions = std::move(*maybeVersions); versions = std::move(*maybeVersions);
// Get component versions before the extension "onDeviceOpen" hooks so that we can properly check verisons
if(supportsComponentVersions()) {
if(auto compVersions = com->getComponentVersionsSync())
componentVersions = std::move(*compVersions);
else
return getCommunicationNotEstablishedError();
}
return APIEvent::Type::NoErrorFound; return APIEvent::Type::NoErrorFound;
} }
@@ -472,7 +480,7 @@ int8_t Device::prepareScriptLoad() {
return false; return false;
} }
const auto resp = std::static_pointer_cast<RawMessage>(generic); const auto resp = std::static_pointer_cast<InternalMessage>(generic);
retVal = (int8_t)resp->data[0]; retVal = (int8_t)resp->data[0];
} }
@@ -656,7 +664,86 @@ bool Device::clearScript(Disk::MemoryType memType)
return true; return true;
} }
bool Device::transmit(std::shared_ptr<Frame> frame) { std::optional<CoreminiHeader> Device::readCoreminiHeader(Disk::MemoryType memType) {
if(!isOpen()) {
report(APIEvent::Type::DeviceCurrentlyClosed, APIEvent::Severity::Error);
return std::nullopt;
}
auto startAddress = getCoreminiStartAddress(memType);
if(!startAddress) {
return std::nullopt;
}
auto connected = isLogicalDiskConnected();
if(!connected) {
return std::nullopt; // Already added an API error
}
#pragma pack(push, 2)
struct RawCoreminiHeader {
uint16_t fileType;
uint16_t fileVersion;
uint32_t storedFileSize;
uint32_t fileChecksum;
union
{
struct
{
uint32_t skipDecompression : 1;
uint32_t encryptedMode : 1;
uint32_t reserved : 30;
} bits;
uint32_t word;
} flags;
uint8_t fileHash[32];
union
{
struct
{
uint32_t lsb;
uint32_t msb;
} words;
uint64_t time64;
} createTime;
uint8_t reserved[8];
};
#pragma pack(pop)
RawCoreminiHeader header = {};
auto numRead = readLogicalDisk(*startAddress, (uint8_t*)&header, sizeof(header), std::chrono::milliseconds(2000), memType);
if(!numRead) {
return std::nullopt; // Already added an API error
}
if(*numRead != sizeof(header)) {
report(APIEvent::Type::FailedToRead, APIEvent::Severity::Error);
return std::nullopt;
}
if(header.fileType != 0x0907) {
report(APIEvent::Type::MessageFormattingError, APIEvent::Severity::Error);
return std::nullopt;
}
std::optional<CoreminiHeader> ret;
ret.emplace();
ret->coreminiVersion = header.fileVersion;
ret->storedFileSize = header.storedFileSize;
ret->fileChecksum = header.fileChecksum;
ret->skipDecompression = static_cast<bool>(header.flags.bits.skipDecompression);
ret->encryptedMode = static_cast<bool>(header.flags.bits.encryptedMode);
std::copy(std::begin(header.fileHash), std::end(header.fileHash), ret->fileHash.begin());
static constexpr std::chrono::seconds icsEpochDelta(1167609600);
static constexpr uint8_t timestampResolution = 25;
static constexpr uint16_t nsInUs = 1'000;
ret->timestamp += icsEpochDelta + std::chrono::microseconds(header.createTime.time64 * timestampResolution / nsInUs);
return ret;
}
bool Device::transmit(std::shared_ptr<BusMessage> frame) {
if(!isOpen()) { if(!isOpen()) {
report(APIEvent::Type::DeviceCurrentlyClosed, APIEvent::Severity::Error); report(APIEvent::Type::DeviceCurrentlyClosed, APIEvent::Severity::Error);
return false; return false;
@@ -689,7 +776,7 @@ bool Device::transmit(std::shared_ptr<Frame> frame) {
return com->sendPacket(packet); return com->sendPacket(packet);
} }
bool Device::transmit(std::vector<std::shared_ptr<Frame>> frames) { bool Device::transmit(std::vector<std::shared_ptr<BusMessage>> frames) {
for(auto& frame : frames) { for(auto& frame : frames) {
if(!transmit(frame)) if(!transmit(frame))
return false; return false;
@@ -722,6 +809,32 @@ Network Device::getNetworkByNumber(Network::Type type, size_t index) const {
return Network::NetID::Invalid; return Network::NetID::Invalid;
} }
std::shared_ptr<HardwareInfo> Device::getHardwareInfo(std::chrono::milliseconds timeout) {
if(!isOpen()) {
report(APIEvent::Type::DeviceCurrentlyClosed, APIEvent::Severity::Error);
return nullptr;
}
auto filter = std::make_shared<MessageFilter>(Message::Type::HardwareInfo);
auto response = com->waitForMessageSync([this]() {
return com->sendCommand(Command::GetHardwareInfo);
}, filter, timeout);
if(!response) {
report(APIEvent::Type::Timeout, APIEvent::Severity::Error);
return nullptr;
}
auto hardwareInfo = std::dynamic_pointer_cast<HardwareInfo>(response);
if(!hardwareInfo) {
report(APIEvent::Type::UnexpectedResponse, APIEvent::Severity::Error);
return nullptr;
}
return hardwareInfo;
}
std::optional<uint64_t> Device::readLogicalDisk(uint64_t pos, uint8_t* into, uint64_t amount, std::chrono::milliseconds timeout, Disk::MemoryType memType) { std::optional<uint64_t> Device::readLogicalDisk(uint64_t pos, uint8_t* into, uint64_t amount, std::chrono::milliseconds timeout, Disk::MemoryType memType) {
if(!into || timeout <= std::chrono::milliseconds(0)) { if(!into || timeout <= std::chrono::milliseconds(0)) {
@@ -1608,18 +1721,9 @@ void Device::handleInternalMessage(std::shared_ptr<Message> message) {
case Message::Type::ResetStatus: case Message::Type::ResetStatus:
latestResetStatus = std::static_pointer_cast<ResetStatusMessage>(message); latestResetStatus = std::static_pointer_cast<ResetStatusMessage>(message);
break; break;
case Message::Type::RawMessage: { case Message::Type::InternalMessage: {
auto rawMessage = std::static_pointer_cast<RawMessage>(message); auto rawMessage = std::static_pointer_cast<InternalMessage>(message);
switch(rawMessage->network.getNetID()) { switch(rawMessage->network.getNetID()) {
case Network::NetID::Device: {
// Device is not guaranteed to be a CANMessage, it might be a RawMessage
// if it couldn't be decoded to a CANMessage. We only care about the
// CANMessage decoding right now.
auto canmsg = std::dynamic_pointer_cast<CANMessage>(message);
if(canmsg)
handleNeoVIMessage(std::move(canmsg));
break;
}
case Network::NetID::DeviceStatus: case Network::NetID::DeviceStatus:
// Device Status format is unique per device, so the devices need to decode it themselves // Device Status format is unique per device, so the devices need to decode it themselves
handleDeviceStatus(rawMessage); handleDeviceStatus(rawMessage);
@@ -1629,6 +1733,15 @@ void Device::handleInternalMessage(std::shared_ptr<Message> message) {
} }
break; break;
} }
case Message::Type::BusMessage: {
// Device is not guaranteed to be a CANMessage, it might be a InternalMessage
// if it couldn't be decoded to a CANMessage. We only care about the
// CANMessage decoding right now.
auto canmsg = std::dynamic_pointer_cast<CANMessage>(message);
if(canmsg)
handleNeoVIMessage(std::move(canmsg));
break;
}
default: break; default: break;
} }
forEachExtension([&](const std::shared_ptr<DeviceExtension>& ext) { forEachExtension([&](const std::shared_ptr<DeviceExtension>& ext) {
@@ -1785,7 +1898,7 @@ std::optional<std::chrono::time_point<std::chrono::system_clock>> Device::getRTC
if(!generic) // Did not receive a message if(!generic) // Did not receive a message
return std::nullopt; return std::nullopt;
auto rawMes = std::dynamic_pointer_cast<RawMessage>(generic); auto rawMes = std::dynamic_pointer_cast<InternalMessage>(generic);
if(!rawMes) if(!rawMes)
return std::nullopt; return std::nullopt;
@@ -1841,7 +1954,7 @@ bool Device::setRTC(const std::chrono::time_point<std::chrono::system_clock>& ti
} }
auto m51msg = std::dynamic_pointer_cast<Main51Message>(generic); auto m51msg = std::dynamic_pointer_cast<Main51Message>(generic);
if(!m51msg || m51msg->data.size() != 1) { if(!m51msg || m51msg->data.empty() || m51msg->data.size() > 2) {
report(APIEvent::Type::MessageFormattingError, APIEvent::Severity::Error); report(APIEvent::Type::MessageFormattingError, APIEvent::Severity::Error);
return false; return false;
} }
@@ -2085,7 +2198,7 @@ bool Device::readVSA(const VSAExtractionSettings& extractionSettings) {
if(isOnline()) { if(isOnline()) {
goOffline(); goOffline();
} }
auto innerReadVSA = [&](uint64_t diskSize) -> const bool { auto innerReadVSA = [&](uint64_t diskSize) -> bool {
// Adjust driver to offset to start of VSA file // Adjust driver to offset to start of VSA file
const auto& offset = getVSAOffsetInLogicalDisk(); const auto& offset = getVSAOffsetInLogicalDisk();
if(!offset) { if(!offset) {
@@ -3148,4 +3261,111 @@ std::optional<uint64_t> Device::getVSADiskSize() {
return std::nullopt; return std::nullopt;
} }
return diskSize; return diskSize;
} }
bool Device::requestTC10Wake(Network::NetID network) {
if(!supportsTC10()) {
report(APIEvent::Type::NotSupported, APIEvent::Severity::Error);
return false;
}
std::vector<uint8_t> args(sizeof(network));
*(Network::NetID*)args.data() = network;
auto msg = com->waitForMessageSync([&] {
return com->sendCommand(ExtendedCommand::RequestTC10Wake, args);
}, std::make_shared<MessageFilter>(Message::Type::ExtendedResponse), std::chrono::milliseconds(1000));
if(!msg) {
report(APIEvent::Type::NoDeviceResponse, APIEvent::Severity::Error);
return false;
}
auto resp = std::static_pointer_cast<ExtendedResponseMessage>(msg);
if(!resp) {
report(APIEvent::Type::UnexpectedResponse, APIEvent::Severity::Error);
return false;
}
return resp->response == ExtendedResponse::OK;
}
bool Device::requestTC10Sleep(Network::NetID network) {
if(!supportsTC10()) {
report(APIEvent::Type::NotSupported, APIEvent::Severity::Error);
return false;
}
std::vector<uint8_t> args(sizeof(network));
*(Network::NetID*)args.data() = network;
auto msg = com->waitForMessageSync([&] {
return com->sendCommand(ExtendedCommand::RequestTC10Sleep, args);
}, std::make_shared<MessageFilter>(Message::Type::ExtendedResponse), std::chrono::milliseconds(1000));
if(!msg) {
report(APIEvent::Type::NoDeviceResponse, APIEvent::Severity::Error);
return false;
}
auto typed = std::static_pointer_cast<ExtendedResponseMessage>(msg);
if(!typed) {
report(APIEvent::Type::UnexpectedResponse, APIEvent::Severity::Error);
return false;
}
return typed->response == ExtendedResponse::OK;
}
std::optional<TC10StatusMessage> Device::getTC10Status(Network::NetID network) {
if(!supportsTC10()) {
report(APIEvent::Type::NotSupported, APIEvent::Severity::Error);
return std::nullopt;
}
std::vector<uint8_t> args(sizeof(network));
*(Network::NetID*)args.data() = network;
auto msg = com->waitForMessageSync([&] {
return com->sendCommand(ExtendedCommand::GetTC10Status, args);
}, std::make_shared<MessageFilter>(Message::Type::TC10Status), std::chrono::milliseconds(1000));
if(!msg) {
report(APIEvent::Type::NoDeviceResponse, APIEvent::Severity::Error);
return std::nullopt;
}
auto typed = std::static_pointer_cast<TC10StatusMessage>(msg);
if(!typed) {
report(APIEvent::Type::UnexpectedResponse, APIEvent::Severity::Error);
return std::nullopt;
}
return *typed;
}
std::optional<GPTPStatus> Device::getGPTPStatus(std::chrono::milliseconds timeout) {
if(!supportsGPTP()) {
report(APIEvent::Type::GPTPNotSupported, APIEvent::Severity::Error);
return std::nullopt;
}
if(!isOpen()) {
report(APIEvent::Type::DeviceCurrentlyClosed, APIEvent::Severity::Error);
return std::nullopt;
}
std::shared_ptr<Message> response = com->waitForMessageSync(
[this](){
return com->sendCommand(ExtendedCommand::GetGPTPStatus, {});
},
std::make_shared<MessageFilter>(Message::Type::GPTPStatus),
timeout
);
if(!response) {
report(APIEvent::Type::NoDeviceResponse, APIEvent::Severity::Error);
return std::nullopt;
}
auto retMsg = std::static_pointer_cast<GPTPStatus>(response);
if(!retMsg) {
return std::nullopt;
}
return *retMsg;
}
+32
View File
@@ -137,6 +137,10 @@ std::vector<std::shared_ptr<Device>> DeviceFinder::FindAll() {
makeIfSerialMatches<NeoOBD2SIM>(dev, newFoundDevices); makeIfSerialMatches<NeoOBD2SIM>(dev, newFoundDevices);
#endif #endif
#ifdef __NEOVICONNECT_H_
makeIfSerialMatches<NeoVIConnect>(dev, newFoundDevices);
#endif
#ifdef __NEOVIFIRE_H_ #ifdef __NEOVIFIRE_H_
makeIfPIDMatches<NeoVIFIRE>(dev, newFoundDevices); makeIfPIDMatches<NeoVIFIRE>(dev, newFoundDevices);
#endif #endif
@@ -181,6 +185,10 @@ std::vector<std::shared_ptr<Device>> DeviceFinder::FindAll() {
makeIfSerialMatches<RADComet3>(dev, newFoundDevices); makeIfSerialMatches<RADComet3>(dev, newFoundDevices);
#endif #endif
#ifdef __RADMOONT1S_H_
makeIfSerialMatches<RADMoonT1S>(dev, newFoundDevices);
#endif
#ifdef __RADEPSILON_H_ #ifdef __RADEPSILON_H_
makeIfSerialMatches<RADEpsilon>(dev, newFoundDevices); makeIfSerialMatches<RADEpsilon>(dev, newFoundDevices);
#endif #endif
@@ -189,6 +197,10 @@ std::vector<std::shared_ptr<Device>> DeviceFinder::FindAll() {
makeIfSerialMatches<RADGalaxy>(dev, newFoundDevices); makeIfSerialMatches<RADGalaxy>(dev, newFoundDevices);
#endif #endif
#ifdef __RADGALAXY2_H_
makeIfSerialMatches<RADGalaxy2>(dev, newFoundDevices);
#endif
#ifdef __RADMARS_H_ #ifdef __RADMARS_H_
makeIfSerialMatches<RADMars>(dev, newFoundDevices); makeIfSerialMatches<RADMars>(dev, newFoundDevices);
#endif #endif
@@ -196,6 +208,10 @@ std::vector<std::shared_ptr<Device>> DeviceFinder::FindAll() {
#ifdef __RADGIGASTAR_H_ #ifdef __RADGIGASTAR_H_
makeIfSerialMatches<RADGigastar>(dev, newFoundDevices); makeIfSerialMatches<RADGigastar>(dev, newFoundDevices);
#endif #endif
#ifdef __RADGIGASTAR2_H_
makeIfSerialMatches<RADGigastar2>(dev, newFoundDevices);
#endif
#ifdef __RADJUPITER_H_ #ifdef __RADJUPITER_H_
makeIfSerialMatches<RADJupiter>(dev, newFoundDevices); makeIfSerialMatches<RADJupiter>(dev, newFoundDevices);
@@ -288,6 +304,10 @@ const std::vector<DeviceType>& DeviceFinder::GetSupportedDevices() {
NeoVIRED2::DEVICE_TYPE, NeoVIRED2::DEVICE_TYPE,
#endif #endif
#ifdef __NEOVICONNECT_H_
NeoVIConnect::DEVICE_TYPE,
#endif
#ifdef __NEOVIFIRE_H_ #ifdef __NEOVIFIRE_H_
NeoVIFIRE::DEVICE_TYPE, NeoVIFIRE::DEVICE_TYPE,
#endif #endif
@@ -324,6 +344,10 @@ const std::vector<DeviceType>& DeviceFinder::GetSupportedDevices() {
RADComet3::DEVICE_TYPE, RADComet3::DEVICE_TYPE,
#endif #endif
#ifdef __RADMOONT1S_H_
RADMoonT1S::DEVICE_TYPE,
#endif
#ifdef __RADEPSILON_H_ #ifdef __RADEPSILON_H_
RADEpsilon::DEVICE_TYPE, RADEpsilon::DEVICE_TYPE,
#endif #endif
@@ -332,6 +356,10 @@ const std::vector<DeviceType>& DeviceFinder::GetSupportedDevices() {
RADGalaxy::DEVICE_TYPE, RADGalaxy::DEVICE_TYPE,
#endif #endif
#ifdef __RADGALAXY2_H_
RADGalaxy2::DEVICE_TYPE,
#endif
#ifdef __RADMARS_H_ #ifdef __RADMARS_H_
RADMars::DEVICE_TYPE, RADMars::DEVICE_TYPE,
#endif #endif
@@ -340,6 +368,10 @@ const std::vector<DeviceType>& DeviceFinder::GetSupportedDevices() {
RADGigastar::DEVICE_TYPE, RADGigastar::DEVICE_TYPE,
#endif #endif
#ifdef __RADGIGASTAR2_H_
RADGigastar2::DEVICE_TYPE,
#endif
#if defined __RADMOON2_H_ || defined __RADMOON2ZL_H_ #if defined __RADMOON2_H_ || defined __RADMOON2ZL_H_
RADMoon2::DEVICE_TYPE, RADMoon2::DEVICE_TYPE,
#endif #endif
+1 -1
View File
@@ -45,7 +45,7 @@ void FlexRay::Extension::handleMessage(const std::shared_ptr<Message>& message)
} }
} }
bool FlexRay::Extension::transmitHook(const std::shared_ptr<Frame>& frame, bool& success) { bool FlexRay::Extension::transmitHook(const std::shared_ptr<BusMessage>& frame, bool& success) {
if(!frame || frame->network.getType() != Network::Type::FlexRay) if(!frame || frame->network.getType() != Network::Type::FlexRay)
return true; // Don't hook non-FlexRay messages return true; // Don't hook non-FlexRay messages
+19 -9
View File
@@ -1,5 +1,6 @@
#include "icsneo/disk/neomemorydiskdriver.h" #include "icsneo/disk/neomemorydiskdriver.h"
#include "icsneo/communication/message/neoreadmemorysdmessage.h" #include "icsneo/communication/message/neoreadmemorysdmessage.h"
#include "icsneo/communication/message/flashmemorymessage.h"
#include <cstring> #include <cstring>
#include <iostream> #include <iostream>
@@ -8,7 +9,8 @@ using namespace icsneo::Disk;
std::optional<uint64_t> NeoMemoryDiskDriver::readLogicalDiskAligned(Communication& com, device_eventhandler_t report, std::optional<uint64_t> NeoMemoryDiskDriver::readLogicalDiskAligned(Communication& com, device_eventhandler_t report,
uint64_t pos, uint8_t* into, uint64_t amount, std::chrono::milliseconds timeout, MemoryType memType) { uint64_t pos, uint8_t* into, uint64_t amount, std::chrono::milliseconds timeout, MemoryType memType) {
static std::shared_ptr<MessageFilter> NeoMemorySDRead = std::make_shared<MessageFilter>(Network::NetID::NeoMemorySDRead); const auto filter = std::make_shared<MessageFilter>((memType == MemoryType::SD ? Network::NetID::NeoMemorySDRead : Network::NetID::RED_INT_MEMORYREAD));
filter->includeInternalInAny = true;
if(pos % SectorSize != 0) if(pos % SectorSize != 0)
return std::nullopt; return std::nullopt;
@@ -20,7 +22,7 @@ std::optional<uint64_t> NeoMemoryDiskDriver::readLogicalDiskAligned(Communicatio
const uint8_t memLocation = (uint8_t)memType; const uint8_t memLocation = (uint8_t)memType;
uint64_t numWords = amount / 2; uint64_t numWords = amount / 2;
auto msg = com.waitForMessageSync([&currentSector, &memLocation, &com, &numWords] { auto msg = com.waitForMessageSync([&currentSector, &memLocation, &com, &numWords] {
return com.sendCommand(Command::NeoReadMemory, { return com.sendCommand(Command::NeoReadMemory, {
memLocation, memLocation,
@@ -33,18 +35,26 @@ std::optional<uint64_t> NeoMemoryDiskDriver::readLogicalDiskAligned(Communicatio
uint8_t((numWords >> 16) & 0xFF), uint8_t((numWords >> 16) & 0xFF),
uint8_t((numWords >> 24) & 0xFF) uint8_t((numWords >> 24) & 0xFF)
}); });
}, NeoMemorySDRead, timeout); }, filter, timeout);
if(!msg) if(!msg)
return 0; return 0;
const auto sdmsg = std::dynamic_pointer_cast<NeoReadMemorySDMessage>(msg); if(memType == MemoryType::SD) {
if(!sdmsg || sdmsg->data.size() != SectorSize) { const auto mem = std::dynamic_pointer_cast<NeoReadMemorySDMessage>(msg);
report(APIEvent::Type::PacketDecodingError, APIEvent::Severity::Error); if(!mem || mem->data.size() != SectorSize) {
return std::nullopt; report(APIEvent::Type::PacketDecodingError, APIEvent::Severity::Error);
return std::nullopt;
}
memcpy(into, mem->data.data(), SectorSize);
} else { // flash
const auto mem = std::dynamic_pointer_cast<FlashMemoryMessage>(msg);
if(!mem || mem->data.size() != SectorSize) {
report(APIEvent::Type::PacketDecodingError, APIEvent::Severity::Error);
return std::nullopt;
}
memcpy(into, mem->data.data(), SectorSize);
} }
memcpy(into, sdmsg->data.data(), SectorSize);
return SectorSize; return SectorSize;
} }
+19 -171
View File
@@ -1,188 +1,36 @@
#!/usr/bin/env python3 # Configuration file for the Sphinx documentation builder.
# -*- coding: utf-8 -*-
# #
# NOTE: The conf.py file is automatically updated by CMake when there are # For the full list of built-in configuration values, see the documentation:
# changes to the version. Update the conf.py.template and then build to # https://www.sphinx-doc.org/en/master/usage/configuration.html
# propagate changes here. This file should be committed so that
# ReadTheDocs can use it.
#
# This file is execfile()d with the current directory set to its
# containing dir.
#
# Note that not all possible configuration values are present in this
# autogenerated file.
#
# All configuration values have a default; values that are commented out
# serve to show the default.
# If extensions (or modules to document with autodoc) are in another directory,
# add these directories to sys.path here. If the directory is relative to the
# documentation root, use os.path.abspath to make it absolute, like shown here.
#
import os
import subprocess import subprocess
# import sys
# sys.path.insert(0, os.path.abspath('.'))
subprocess.call('cd ..; doxygen docs/icsneocpp/Doxyfile', shell=True)
subprocess.call('cd ..; doxygen docs/icsneoc/Doxyfile', shell=True)
# -- General configuration ------------------------------------------------ # -- Project information -----------------------------------------------------
# https://www.sphinx-doc.org/en/master/usage/configuration.html#project-information
# If your documentation needs a minimal Sphinx version, state it here.
#
# needs_sphinx = '1.0'
# Add any Sphinx extension module names here, as strings. They can be
# extensions coming with Sphinx (named 'sphinx.ext.*') or your custom
# ones.
extensions = ['sphinx.ext.imgmath', 'sphinx.ext.todo', 'breathe' ]
breathe_projects = { "libicsneo": "build/doxygen/xml" }
breathe_default_project = "libicsneo"
try:
os.makedirs('build/sphinx')
except FileExistsError:
pass
try:
os.makedirs('build/doxygen')
except FileExistsError:
pass
subprocess.call('cd ..; doxygen docs/Doxyfile', shell=True)
# Add any paths that contain templates here, relative to this directory.
templates_path = ['_templates']
# The suffix(es) of source filenames.
# You can specify multiple suffix as a list of string:
#
# source_suffix = ['.rst', '.md']
source_suffix = '.rst'
# The master toctree document.
master_doc = 'index'
# General information about the project.
project = 'libicsneo' project = 'libicsneo'
copyright = '2018-2024, Intrepid Control Systems, Inc.' copyright = '2024-2025, Intrepid Control Systems, Inc.'
author = 'Intrepid Control Systems, Inc.' author = 'Intrepid Control Systems, Inc.'
# The version info for the project you're documenting, acts as replacement for # -- General configuration ---------------------------------------------------
# |version| and |release|, also used in various other places throughout the # https://www.sphinx-doc.org/en/master/usage/configuration.html#general-configuration
# built documents.
#
# The short X.Y version.
version = '0.2.0'
# The full version, including alpha/beta/rc tags.
release = '0.2.0 '
# The language for content autogenerated by Sphinx. Refer to documentation extensions = ['breathe', 'sphinx.ext.autodoc']
# for a list of supported languages.
#
# This is also used if you do content translation via gettext catalogs.
# Usually you set "language" from the command line for these cases.
language = None
# List of patterns, relative to source directory, that match files and templates_path = ['_templates']
# directories to ignore when looking for source files.
# This patterns also effect to html_static_path and html_extra_path
exclude_patterns = ['_build', 'Thumbs.db', '.DS_Store'] exclude_patterns = ['_build', 'Thumbs.db', '.DS_Store']
# The name of the Pygments (syntax highlighting) style to use. breathe_projects = {
pygments_style = 'sphinx' 'icsneocpp': 'icsneocpp/doxygen/xml',
'icsneoc': 'icsneoc/doxygen/xml',
}
# If true, `todo` and `todoList` produce output, else they produce nothing. breathe_default_project = 'icsneocpp'
todo_include_todos = False
# -- Options for HTML output -------------------------------------------------
# https://www.sphinx-doc.org/en/master/usage/configuration.html#options-for-html-output
# -- Options for HTML output ----------------------------------------------
# The theme to use for HTML and HTML Help pages. See the documentation for
# a list of builtin themes.
#
html_theme = 'sphinx_rtd_theme' html_theme = 'sphinx_rtd_theme'
# Theme options are theme-specific and customize the look and feel of a theme
# further. For a list of options available for each theme, see the
# documentation.
#
html_theme_options = {
}
# Add any paths that contain custom static files (such as style sheets) here,
# relative to this directory. They are copied after the builtin static files,
# so a file named "default.css" will overwrite the builtin "default.css".
html_static_path = ['_static']
# Custom sidebar templates, must be a dictionary that maps document names
# to template names.
#
# This is required for the alabaster theme
# refs: http://alabaster.readthedocs.io/en/latest/installation.html#sidebars
html_sidebars = {
'**': [
'relations.html', # needs 'show_related': True theme option to display
'searchbox.html',
]
}
# -- Options for HTMLHelp output ------------------------------------------
# Output file base name for HTML help builder.
htmlhelp_basename = 'libicsneodoc'
# -- Options for LaTeX output ---------------------------------------------
latex_elements = {
# The paper size ('letterpaper' or 'a4paper').
#
# 'papersize': 'letterpaper',
# The font size ('10pt', '11pt' or '12pt').
#
# 'pointsize': '10pt',
# Additional stuff for the LaTeX preamble.
#
# 'preamble': '',
# Latex figure (float) alignment
#
# 'figure_align': 'htbp',
}
# Grouping the document tree into LaTeX files. List of tuples
# (source start file, target name, title,
# author, documentclass [howto, manual, or own class]).
latex_documents = [
(master_doc, 'libicsneo.tex', 'libicsneo Documentation',
'Intrepid Control Systems, Inc.', 'manual'),
]
# -- Options for manual page output ---------------------------------------
# One entry per manual page. List of tuples
# (source start file, name, description, authors, manual section).
man_pages = [
(master_doc, 'libicsneo', 'libicsneo Documentation',
[author], 1)
]
# -- Options for Texinfo output -------------------------------------------
# Grouping the document tree into Texinfo files. List of tuples
# (source start file, target name, title, author,
# dir menu entry, description, category)
texinfo_documents = [
(master_doc, 'libicsneo', 'libicsneo Documentation',
author, 'libicsneo', 'One line description of project.',
'Miscellaneous'),
]
-188
View File
@@ -1,188 +0,0 @@
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
#
# NOTE: The conf.py file is automatically updated by CMake when there are
# changes to the version. Update the conf.py.template and then build to
# propagate changes here. This file should be committed so that
# ReadTheDocs can use it.
#
# This file is execfile()d with the current directory set to its
# containing dir.
#
# Note that not all possible configuration values are present in this
# autogenerated file.
#
# All configuration values have a default; values that are commented out
# serve to show the default.
# If extensions (or modules to document with autodoc) are in another directory,
# add these directories to sys.path here. If the directory is relative to the
# documentation root, use os.path.abspath to make it absolute, like shown here.
#
import os
import subprocess
# import sys
# sys.path.insert(0, os.path.abspath('.'))
# -- General configuration ------------------------------------------------
# If your documentation needs a minimal Sphinx version, state it here.
#
# needs_sphinx = '1.0'
# Add any Sphinx extension module names here, as strings. They can be
# extensions coming with Sphinx (named 'sphinx.ext.*') or your custom
# ones.
extensions = ['sphinx.ext.imgmath', 'sphinx.ext.todo', 'breathe' ]
breathe_projects = { "libicsneo": "build/doxygen/xml" }
breathe_default_project = "libicsneo"
try:
os.makedirs('build/sphinx')
except FileExistsError:
pass
try:
os.makedirs('build/doxygen')
except FileExistsError:
pass
subprocess.call('cd ..; doxygen docs/Doxyfile', shell=True)
# Add any paths that contain templates here, relative to this directory.
templates_path = ['_templates']
# The suffix(es) of source filenames.
# You can specify multiple suffix as a list of string:
#
# source_suffix = ['.rst', '.md']
source_suffix = '.rst'
# The master toctree document.
master_doc = 'index'
# General information about the project.
project = 'libicsneo'
copyright = '2018-2024, Intrepid Control Systems, Inc.'
author = 'Intrepid Control Systems, Inc.'
# The version info for the project you're documenting, acts as replacement for
# |version| and |release|, also used in various other places throughout the
# built documents.
#
# The short X.Y version.
version = '@PROJECT_VERSION_MAJOR@.@PROJECT_VERSION_MINOR@.@PROJECT_VERSION_PATCH@'
# The full version, including alpha/beta/rc tags.
release = '@PROJECT_VERSION_MAJOR@.@PROJECT_VERSION_MINOR@.@PROJECT_VERSION_PATCH@ @BUILD_METADATA@'
# The language for content autogenerated by Sphinx. Refer to documentation
# for a list of supported languages.
#
# This is also used if you do content translation via gettext catalogs.
# Usually you set "language" from the command line for these cases.
language = None
# List of patterns, relative to source directory, that match files and
# directories to ignore when looking for source files.
# This patterns also effect to html_static_path and html_extra_path
exclude_patterns = ['_build', 'Thumbs.db', '.DS_Store']
# The name of the Pygments (syntax highlighting) style to use.
pygments_style = 'sphinx'
# If true, `todo` and `todoList` produce output, else they produce nothing.
todo_include_todos = False
# -- Options for HTML output ----------------------------------------------
# The theme to use for HTML and HTML Help pages. See the documentation for
# a list of builtin themes.
#
html_theme = 'sphinx_rtd_theme'
# Theme options are theme-specific and customize the look and feel of a theme
# further. For a list of options available for each theme, see the
# documentation.
#
html_theme_options = {
}
# Add any paths that contain custom static files (such as style sheets) here,
# relative to this directory. They are copied after the builtin static files,
# so a file named "default.css" will overwrite the builtin "default.css".
html_static_path = ['_static']
# Custom sidebar templates, must be a dictionary that maps document names
# to template names.
#
# This is required for the alabaster theme
# refs: http://alabaster.readthedocs.io/en/latest/installation.html#sidebars
html_sidebars = {
'**': [
'relations.html', # needs 'show_related': True theme option to display
'searchbox.html',
]
}
# -- Options for HTMLHelp output ------------------------------------------
# Output file base name for HTML help builder.
htmlhelp_basename = 'libicsneodoc'
# -- Options for LaTeX output ---------------------------------------------
latex_elements = {
# The paper size ('letterpaper' or 'a4paper').
#
# 'papersize': 'letterpaper',
# The font size ('10pt', '11pt' or '12pt').
#
# 'pointsize': '10pt',
# Additional stuff for the LaTeX preamble.
#
# 'preamble': '',
# Latex figure (float) alignment
#
# 'figure_align': 'htbp',
}
# Grouping the document tree into LaTeX files. List of tuples
# (source start file, target name, title,
# author, documentclass [howto, manual, or own class]).
latex_documents = [
(master_doc, 'libicsneo.tex', 'libicsneo Documentation',
'Intrepid Control Systems, Inc.', 'manual'),
]
# -- Options for manual page output ---------------------------------------
# One entry per manual page. List of tuples
# (source start file, name, description, authors, manual section).
man_pages = [
(master_doc, 'libicsneo', 'libicsneo Documentation',
[author], 1)
]
# -- Options for Texinfo output -------------------------------------------
# Grouping the document tree into Texinfo files. List of tuples
# (source start file, target name, title, author,
# dir menu entry, description, category)
texinfo_documents = [
(master_doc, 'libicsneo', 'libicsneo Documentation',
author, 'libicsneo', 'One line description of project.',
'Miscellaneous'),
]
-44
View File
@@ -1,44 +0,0 @@
********************
**C API** (icsneoc)
********************
.. Usage
.. ======
.. Finding Devices
.. ~~~~~~~~~~~~~~~~
.. Finding a device is simple
.. Connecting to Devices
.. ~~~~~~~~~~~~~~~~~~~~~~
Reference
==========
Typedefs
~~~~~~~~~
.. doxygentypedef:: devicehandle_t
.. doxygentypedef:: neodevice_handle_t
.. doxygentypedef:: devicetype_t
Structures
~~~~~~~~~~~
.. doxygenstruct:: neoversion_t
:members:
:undoc-members:
.. doxygenstruct:: neodevice_t
:members:
:undoc-members:
.. doxygenstruct:: neomessage_t
:members:
:undoc-members:
.. doxygenstruct:: neomessage_can_t
:members:
:undoc-members:
Functions
~~~~~~~~~~
.. doxygenfile:: icsneoc.h
File diff suppressed because it is too large Load Diff
+14
View File
@@ -0,0 +1,14 @@
=====
C API
=====
.. doxygenfile:: icsneoc.h
:project: icsneoc
.. doxygenfile:: device/neodevice.h
:project: icsneoc
.. doxygenfile:: communication/message/neomessage.h
:project: icsneoc
.. doxygenfile:: api/version.h
:project: icsneoc
.. doxygenfile:: api/event.h
:project: icsneoc
+43
View File
@@ -0,0 +1,43 @@
==========
C Examples
==========
A variety of examples can be found within ``examples/c``, see below for an
example that uses the polling API to receive CAN frames.
.. code-block:: c
size_t deviceCount = 10; // Pre-set to the size of your buffer before the icsneo_findAllDevices() call
neodevice_t devices[10];
icsneo_findAllDevices(devices, &deviceCount);
printf("We found %ull devices\n", deviceCount);
for(size_t i = 0; i < deviceCount; i++) {
neodevice_t* myDevice = &devices[i];
char desc[ICSNEO_DEVICETYPE_LONGEST_DESCRIPTION];
size_t sz = ICSNEO_DEVICETYPE_LONGEST_DESCRIPTION;
icsneo_describeDevice(myDevice, desc, &sz);
printf("Found %s\n", desc); // "Found neoVI FIRE 2 CY2345"
}
neodevice_t* myDevice = &devices[0];
if(!icsneo_openDevice(myDevice)) {
neoevent_t error;
if(icsneo_getLastError(&error))
printf("Error! %s\n", error.description);
}
icsneo_goOnline(myDevice); // Start receiving messages
icsneo_enableMessagePolling(myDevice); // Allow the use of icsneo_getMessages() later
sleep(5);
neomessage_t messages[50];
size_t messageCount = 50;
icsneo_getMessages(myDevice, messages, &messageCount, 0 /* non-blocking */);
printf("We got %ull messages!\n", messageCount);
for(size_t i = 0; i < messageCount; i++) {
if(messages[i].type == ICSNEO_NETWORK_TYPE_CAN) {
// A message of type CAN should be interperated a neomessage_can_t, so we can cast safely
neomessage_can_t* canmsg = (neomessage_can_t*)&messages[i];
// canmsg->arbid is valid here
// canmsg->data is an uint8_t*, you can check canmsg->length for the length of the payload
// canmsg->timestamp is the time recorded by the hardware in nanoseconds since (1/1/2007 12:00:00 GMT)
}
}
icsneo_closeDevice(myDevice);
+9
View File
@@ -0,0 +1,9 @@
icsneoc
=======
.. toctree::
:maxdepth: 2
installation
examples
api
+7
View File
@@ -0,0 +1,7 @@
============
Installation
============
The installation steps for the C API are the same as the C++ API as the C API is
a wrapper for the C++ library. The ``LIBICSNEO_BUILD_ICSNEOC`` CMake option is
default ``ON`` but note that the C API depends on this flag to build.
-31
View File
@@ -1,31 +0,0 @@
************************
**C++ API** (icsneocpp)
************************
.. Usage
.. ======
.. Finding Devices
.. ~~~~~~~~~~~~~~~~
.. Finding a device is simple
.. Connecting to Devices
.. ~~~~~~~~~~~~~~~~~~~~~~
Reference
==========
.. Classes
.. ~~~~~~~~
.. Structures
.. ~~~~~~~~~~~
.. Functions
.. ~~~~~~~~~~
.. doxygennamespace:: icsneo
.. doxygenclass:: icsneo::Device
:members:
:undoc-members:
File diff suppressed because it is too large Load Diff
+8
View File
@@ -0,0 +1,8 @@
=======
C++ API
=======
.. doxygennamespace:: icsneo
:members:
:undoc-members:
:content-only:
+55
View File
@@ -0,0 +1,55 @@
============
API Concepts
============
Overview
~~~~~~~~~~~~~~~~~~~~
Events convey information about the API's inner workings to the user. There are 3 severity levels: ``EventInfo``, ``EventWarning``, and ``Error``.
**However, the API treats events of severities** ``EventInfo`` **and** ``EventWarning`` **differently than those of severity** ``Error`` **.**
From here on out, when we (and the API functions) refer to "events", we refer exclusively to those of severities ``EventInfo`` and ``EventWarning``, which use the events_ system.
Those of severity ``Error`` are referred to as "errors", which use a separate errors_ system.
Events should periodically be read out in order to avoid overflowing, and the last error should be read out immediately after an API function fails.
Additionally, `event callbacks`_ can be registered, which may remove the need to periodically read events in some cases.
.. _events:
Events
~~~~~~~~~~~~~~~~~~~~
The API stores events in a single buffer that can has a default size of 10,000 events.
This limit includes 1 reserved slot at the end of the buffer for a potential Event of type ``TooManyEvents`` and severity ``EventWarning``, which is added when there are too many events for the buffer to hold.
This could occur if the events aren't read out by the user often enough, or if the user sets the size of the buffer to a value smaller than the number of existing events.
There will only ever be one of these ``TooManyEvents`` events, and it will always be located at the very end of the buffer if it exists.
Because of this reserved slot, the buffer by default is able to hold 9,999 events. If capacity is exceeded, the oldest events in the buffer are automatically discarded until the buffer is exactly at capacity again.
When events are read out by the user, they are removed from the buffer. If an event filter is used, only the filtered events will be removed from the buffer.
In a multithreaded environment, all threads will log their events to the same buffer. In this case, the order of events will largely be meaningless, although the behavior of ``TooManyEvents`` is still guaranteed to be as described above.
.. _event callbacks:
Event Callbacks
~~~~~~~~~~~~~~~~~~~~
Users may register event callbacks, which are automatically called whenever a matching event is logged.
Message callbacks consist of a user-defined ``std::function< void( std::shared_ptr<APIEvent> ) >`` and optional EventFilter used for matching.
If no EventFilter is provided, the default-constructed one will be used, which matches any event.
Registering a callback returns an ``int`` representing the id of the callback, which should be stored by the user and later used to remove the callback when desired.
Note that this functionality is only available in C and C++. C does not currently support filters.
Event callbacks are run after the event has been added to the buffer of events. The buffer of events may be safely modified within the callback, such as getting (flushing) the type and severity of the triggering event.
Using event callbacks in this manner means that periodically reading events is unnecessary.
.. _errors:
Errors
~~~~~~~~~
The error system is threadsafe and separate from the events_ system.
Each thread keeps track of the last error logged on it, and getting the last error will return the last error from the calling thread, removing it in the process.
Trying to get the last error when there is none will return an event of type ``NoErrorFound`` and severity ``EventInfo``.
The API also contains some threads for internal use which may potentially log errors of their own and are inaccessible to the user.
These threads have been marked to downgrade any errors that occur on them to severity ``EventWarning`` and will log the corresponding event in the events_ system described above.
@@ -1,64 +1,6 @@
**************** ===============
**API Usage**
****************
API Concepts
================
Overview
~~~~~~~~~~~~~~~~~~~~
Events convey information about the API's inner workings to the user. There are 3 severity levels: ``EventInfo``, ``EventWarning``, and ``Error``.
**However, the API treats events of severities** ``EventInfo`` **and** ``EventWarning`` **differently than those of severity** ``Error`` **.**
From here on out, when we (and the API functions) refer to "events", we refer exclusively to those of severities ``EventInfo`` and ``EventWarning``, which use the events_ system.
Those of severity ``Error`` are referred to as "errors", which use a separate errors_ system.
Events should periodically be read out in order to avoid overflowing, and the last error should be read out immediately after an API function fails.
Additionally, `event callbacks`_ can be registered, which may remove the need to periodically read events in some cases.
.. _events:
Events
~~~~~~~~~~~~~~~~~~~~
The API stores events in a single buffer that can has a default size of 10,000 events.
This limit includes 1 reserved slot at the end of the buffer for a potential Event of type ``TooManyEvents`` and severity ``EventWarning``, which is added when there are too many events for the buffer to hold.
This could occur if the events aren't read out by the user often enough, or if the user sets the size of the buffer to a value smaller than the number of existing events.
There will only ever be one of these ``TooManyEvents`` events, and it will always be located at the very end of the buffer if it exists.
Because of this reserved slot, the buffer by default is able to hold 9,999 events. If capacity is exceeded, the oldest events in the buffer are automatically discarded until the buffer is exactly at capacity again.
When events are read out by the user, they are removed from the buffer. If an event filter is used, only the filtered events will be removed from the buffer.
In a multithreaded environment, all threads will log their events to the same buffer. In this case, the order of events will largely be meaningless, although the behavior of ``TooManyEvents`` is still guaranteed to be as described above.
.. _event callbacks:
Event Callbacks
~~~~~~~~~~~~~~~~~~~~
Users may register event callbacks, which are automatically called whenever a matching event is logged.
Message callbacks consist of a user-defined ``std::function< void( std::shared_ptr<APIEvent> ) >`` and optional EventFilter used for matching.
If no EventFilter is provided, the default-constructed one will be used, which matches any event.
Registering a callback returns an ``int`` representing the id of the callback, which should be stored by the user and later used to remove the callback when desired.
Note that this functionality is only available in C and C++. C does not currently support filters.
Event callbacks are run after the event has been added to the buffer of events. The buffer of events may be safely modified within the callback, such as getting (flushing) the type and severity of the triggering event.
Using event callbacks in this manner means that periodically reading events is unnecessary.
.. _errors:
Errors
~~~~~~~~~
The error system is threadsafe and separate from the events_ system.
Each thread keeps track of the last error logged on it, and getting the last error will return the last error from the calling thread, removing it in the process.
Trying to get the last error when there is none will return an event of type ``NoErrorFound`` and severity ``EventInfo``.
The API also contains some threads for internal use which may potentially log errors of their own and are inaccessible to the user.
These threads have been marked to downgrade any errors that occur on them to severity ``EventWarning`` and will log the corresponding event in the events_ system described above.
Device Concepts Device Concepts
================ ===============
Open/Close Status Open/Close Status
~~~~~~~~~~~~~~~~~~~~~~~ ~~~~~~~~~~~~~~~~~~~~~~~
+52
View File
@@ -0,0 +1,52 @@
============
C++ Examples
============
A variety of examples can be found within ``examples/cpp``, see below for an
example that uses the polling API to receive CAN frames.
The C++ API is designed to be modern and easy to use. All library functions and
classes are in the namespace ``icsneo``. Most applications will start by calling
``icsneo::FindAllDevices()``. This will return an ``std::vector`` of
``std::shared_ptr<icsneo::Device>`` objects. You will want to keep a copy of the
``shared_ptr`` to any devices you want to use, as allowing it to go out of scope
will automatically close the device and free all memory associated with it.
Any time you get bus traffic from the API, you will receive it as an
``std::shared_ptr<icsneo::Message>``. The message will be valid as long as the
``shared_ptr`` stays in scope. Checking the type of the message allows you to
cast it accordingly and access extra data for certain protocols. For instance,
casting an ``icsneo::Message`` to an ``icsneo::CANMessage`` allows you to access
the arbitration ID.
.. code-block:: cpp
std::vector<std::shared_ptr<icsneo::Device>> devices = icsneo::FindAllDevices();
std::cout << devices.size() << " found!" << std::endl;
for(auto& device : devices)
std::cout << "Found " << device->describe() << std::endl; // "Found neoVI FIRE 2 CY2345"
std::shared_ptr<icsneo::Device> myDevice = devices[0];
if(!myDevice->open()) // Device tried and failed to open, print the last error
std::cout << icsneo::GetLastError() << std::endl;
myDevice->goOnline(); // Start receiving messages
myDevice->enableMessagePolling(); // Allow the use of myDevice->getMessages() later
// Alternatively, assign a callback for new messages
std::this_thread::wait_for(std::chrono::seconds(5));
std::vector<std::shared_ptr<icsneo::Message>> messages = myDevice->getMessages();
std::cout << "We got " << messages.size() << " messages!" << std::endl;
for(auto& msg : messages) {
switch(msg->network.getType()) {
case icsneo::Network::Type::CAN:
case icsneo::Network::Type::SWCAN:
case icsneo::Network::Type::LSFTCAN: {
// A message of type CAN is guaranteed to be a CANMessage, so we can static cast safely
auto canmsg = std::static_pointer_cast<icsneo::CANMessage>(msg);
// canmsg->arbid is valid here
// canmsg->data is an std::vector<uint8_t>, you can check .size() for the DLC of the message
// canmsg->timestamp is the time recorded by the hardware in nanoseconds since (1/1/2007 12:00:00 GMT)
}
default:
// Handle others
}
}
myDevice->close();
+11
View File
@@ -0,0 +1,11 @@
icsneocpp
=========
.. toctree::
:maxdepth: 2
installation
deviceconcepts
apiconcepts
examples
api
+39
View File
@@ -0,0 +1,39 @@
============
Installation
============
Dependencies
============
The minimum requirements to build libicsneo are:
- CMake version 3.12 or newer
- A C++17 compiler
- libusb and libpcap on Linux and macOS
Building library & examples
===========================
For a list of available configuration options, see the ``option()`` entries in
``CMakeLists.txt``.
To build libicsneo with default options:
#. ``cmake -B build``
#. ``cmake --build build``
Adding to existing projects
===========================
libicsneo supports being added as a sub-projects with CMake's
``add_subdirectory()``.
#. Clone libicsneo into the desired location within the project
#. Add ``add_subdirectory(path/to/libicsneo)`` to ``CMakeLists.txt``
#. Link the project to libicsneo with ``target_link_libraries(app icsneocpp)``
Linux udev Rules
================
Linux users may want to install the included udev rules to run libicsneo based
applications without root, this can be done with:
``cp 99-intrepidcs.rules /etc/udev/rules.d/``
+10
View File
@@ -0,0 +1,10 @@
==========
Python API
==========
.. automodule:: icsneopy
:members:
:undoc-members:
:show-inheritance:
:imported-members:
:special-members: __init__
+90
View File
@@ -0,0 +1,90 @@
===============
Python Examples
===============
Transmit CAN frames on HSCAN
============================
.. code-block:: python
import icsneopy
devices: list[icsneopy.Device] = icsneopy.find_all_devices()
# grab the first/only device found
device: icsneopy.Device = devices[0]
message = icsneopy.CANMessage()
message.network = icsneopy.Network(icsneopy.Network.NetID.HSCAN)
message.arbid = 0x56
message.data = (0x11, 0x22, 0x33)
device.open()
device.go_online()
device.transmit(message)
Receive CAN frames on HSCAN
===========================
.. code-block:: python
import icsneopy
import time
devices: list[icsneopy.Device] = icsneopy.find_all_devices()
# grab the first/only device found
device: icsneopy.Device = devices[0]
def on_message(message: icsneopy.CANMessage):
print(message.arbid, message.data)
message_filter = icsneopy.MessageFilter(icsneopy.Network.NetID.HSCAN)
callback = icsneopy.MessageCallback(on_message, message_filter)
device.add_message_callback(callback)
device.open()
device.go_online()
# rx for 10s
time.sleep(10)
Monitor Ethernet Status
=======================
.. code-block:: python
import icsneopy
import time
def main():
devices = icsneopy.find_all_devices()
if len(devices) == 0:
print("error: no devices found")
return False
device = devices[0]
print(f"info: monitoring Ethernet status on {device}")
def on_message(message):
print(f"info: network: {message.network}, state: {message.state}, speed: {message.speed}, duplex: {message.duplex}, mode: {message.mode}")
filter = icsneopy.MessageFilter(icsneopy.Message.Type.EthernetStatus)
callback = icsneopy.MessageCallback(on_message, filter)
device.add_message_callback(callback)
if not device.open():
print("error: unable to open device")
return False
if not device.go_online():
print("error: unable to go online")
return False
while True:
time.sleep(1)
main()
+9
View File
@@ -0,0 +1,9 @@
========
icsneopy
========
.. toctree::
:maxdepth: 2
examples
api
+11 -6
View File
@@ -1,10 +1,15 @@
Welcome to libicsneo's documentation! =========
======================================= libicsneo
=========
libicsneo is the `Intrepid Control Systems <https://intrepidcs.com/>`_ device
communication library. The source code for libicsneo can be found on GitHub:
`https://github.com/intrepidcs/libicsneo <https://github.com/intrepidcs/libicsneo>`_
.. toctree:: .. toctree::
:maxdepth: 3 :maxdepth: 1
:caption: Documentation :caption: Documentation
Usage icsneocpp/index
icsneocpp icsneopy/index
icsneoc icsneoc/index
+4 -1
View File
@@ -1 +1,4 @@
breathe==4.12.0 sphinx
icsneopy
breathe
sphinx_rtd_theme
+10
View File
@@ -1,6 +1,7 @@
option(LIBICSNEO_BUILD_C_INTERACTIVE_EXAMPLE "Build the command-line interactive C example." ON) option(LIBICSNEO_BUILD_C_INTERACTIVE_EXAMPLE "Build the command-line interactive C example." ON)
option(LIBICSNEO_BUILD_C_SIMPLE_EXAMPLE "Build the command-line simple C example." ON) option(LIBICSNEO_BUILD_C_SIMPLE_EXAMPLE "Build the command-line simple C example." ON)
option(LIBICSNEO_BUILD_C_LEGACY_EXAMPLE "Build the command-line simple C example." ON) option(LIBICSNEO_BUILD_C_LEGACY_EXAMPLE "Build the command-line simple C example." ON)
option(LIBICSNEO_BUILD_C2_SIMPLE_EXAMPLE "Build the command-line simple C example." ON)
option(LIBICSNEO_BUILD_CPP_SIMPLE_EXAMPLE "Build the simple C++ example." ON) option(LIBICSNEO_BUILD_CPP_SIMPLE_EXAMPLE "Build the simple C++ example." ON)
option(LIBICSNEO_BUILD_CPP_INTERACTIVE_EXAMPLE "Build the command-line interactive C++ example." ON) option(LIBICSNEO_BUILD_CPP_INTERACTIVE_EXAMPLE "Build the command-line interactive C++ example." ON)
option(LIBICSNEO_BUILD_CPP_A2B_EXAMPLE "Build the A2B example." ON) option(LIBICSNEO_BUILD_CPP_A2B_EXAMPLE "Build the A2B example." ON)
@@ -9,6 +10,7 @@ option(LIBICSNEO_BUILD_CPP_LIVEDATA_EXAMPLE "Build the Live Data example." ON)
option(LIBICSNEO_BUILD_CPP_COREMINI_EXAMPLE "Build the Coremini example." ON) option(LIBICSNEO_BUILD_CPP_COREMINI_EXAMPLE "Build the Coremini example." ON)
option(LIBICSNEO_BUILD_CPP_MDIO_EXAMPLE "Build the MDIO example." ON) option(LIBICSNEO_BUILD_CPP_MDIO_EXAMPLE "Build the MDIO example." ON)
option(LIBICSNEO_BUILD_CPP_VSA_EXAMPLE "Build the VSA example." ON) option(LIBICSNEO_BUILD_CPP_VSA_EXAMPLE "Build the VSA example." ON)
option(LIBICSNEO_BUILD_CPP_APP_ERROR_EXAMPLE "Build the app error example." ON)
# Disabled until we properly build these in-tree # Disabled until we properly build these in-tree
# option(LIBICSNEO_BUILD_CSHARP_INTERACTIVE_EXAMPLE "Build the command-line interactive C# example." OFF) # option(LIBICSNEO_BUILD_CSHARP_INTERACTIVE_EXAMPLE "Build the command-line interactive C# example." OFF)
@@ -26,6 +28,10 @@ if(LIBICSNEO_BUILD_C_LEGACY_EXAMPLE)
add_subdirectory(c/legacy) add_subdirectory(c/legacy)
endif() endif()
if(LIBICSNEO_BUILD_C2_SIMPLE_EXAMPLE)
add_subdirectory(c2/simple)
endif()
if(LIBICSNEO_BUILD_CPP_SIMPLE_EXAMPLE) if(LIBICSNEO_BUILD_CPP_SIMPLE_EXAMPLE)
add_subdirectory(cpp/simple) add_subdirectory(cpp/simple)
endif() endif()
@@ -58,6 +64,10 @@ if(LIBICSNEO_BUILD_CPP_VSA_EXAMPLE)
add_subdirectory(cpp/vsa) add_subdirectory(cpp/vsa)
endif() endif()
if(LIBICSNEO_BUILD_CPP_APP_ERROR_EXAMPLE)
add_subdirectory(cpp/apperror)
endif()
# if(LIBICSNEO_BUILD_CSHARP_INTERACTIVE_EXAMPLE) # if(LIBICSNEO_BUILD_CSHARP_INTERACTIVE_EXAMPLE)
# add_subdirectory(csharp) # add_subdirectory(csharp)
# endif() # endif()
+2
View File
@@ -0,0 +1,2 @@
add_executable(libicsneo-simple-example src/main.c)
target_link_libraries(libicsneo-simple-example icsneoc2)
+454
View File
@@ -0,0 +1,454 @@
#include <icsneo/icsneoc2.h>
#include <stdio.h>
#include <time.h>
#if defined(_WIN32) || defined(_WIN64)
#include <windows.h>
#else
#include <unistd.h>
#endif
/**
* @brief Sleeps for a specified number of milliseconds.
*
* Sleeps for a specified number of milliseconds using Sleep() on Windows and sleep() on *nix.
*
* @param ms The number of milliseconds to sleep.
*/
void sleep_ms(uint32_t ms) {
#if defined(_WIN32) || defined(_WIN64)
Sleep(ms);
#else
sleep(ms / 1000);
#endif
}
/**
* @brief Prints an error message with the given string and error code.
*
* If the error code is not icsneoc2_error_success, prints the error string for the given error code
* and returns the error code.
*
* @param message The message to print.
* @param error The error code to print.
* @return error as int
*/
int print_error_code(const char* message, icsneoc2_error_t error) {
char error_str[256] = {0};
uint32_t error_length = 256;
icsneoc2_error_t res = icsneoc2_error_code_get(error, error_str, &error_length);
if (res != icsneoc2_error_success) {
printf("%s: Failed to get string for error code %d with error code %d\n", message, error, res);
return res;
}
printf("%s: \"%s\" (%u)\n", message, error_str, error);
return (int)error;
}
/**
* @brief Processes a list of messages from a device.
*
* This function iterates over a given array of messages received from a specified device.
* For each message in the array, it retrieves and prints the message type and bus type.
* If an error occurs while retrieving these details, an error message is printed.
*
* @param device A pointer to the icsneoc2_device_t structure representing the device.
* @param messages An array of pointers to icsneoc2_message_t structures containing the messages to process.
* @param messages_count The number of messages in the messages array.
*
* @return An icsneoc2_error_t value indicating success or failure of the message processing.
*/
int process_messages(icsneoc2_device_t* device, icsneoc2_message_t** messages, uint32_t messages_count);
/**
* @brief Prints device and global events for a given device.
*
* This function retrieves and prints all current events associated with the specified device,
* as well as any global events not tied to a specific device. For each event, it retrieves
* and prints a description. If retrieving events or their descriptions fails, an error
* message is printed. The function also prints a summary of the count of device-specific
* and global events processed.
*
* @param device A pointer to the icsneoc2_device_t structure representing the device to get events from.
* @param device_description A description of the device used in the output.
*/
void print_device_events(icsneoc2_device_t* device, const char* device_description);
/**
* @brief Transmits a series of CAN messages from a device.
*
* This function creates and transmits 100 CAN messages with incrementing payload data.
* Each message is configured with specific attributes such as network ID, arbitration
* ID, CANFD status, extended status, and baudrate switch. After successfully transmitting
* each message, it is freed from memory.
*
* @param device A pointer to the icsneoc2_device_t structure representing the device to transmit messages from.
*
* @return An icsneoc2_error_t value indicating success or failure of the message transmission process.
*/
int transmit_can_messages(icsneoc2_device_t* device);
/**
* @brief Get the RTC (Real time clock) of a device and print it.
*
* @param[in] device The device to get the RTC of.
* @param[in] description A description of the device for printing purpose.
*
* @return icsneoc2_error_t icsneoc2_error_success if successful, icsneoc2_error_invalid_parameters otherwise.
*/
icsneoc2_error_t get_and_print_rtc(icsneoc2_device_t* device, const char* description);
int main(int argc, char* argv[]) {
(void)argc;
(void)argv;
icsneoc2_device_t* devices[255] = {0};
uint32_t devices_count = 255;
printf("Finding devices...\n");
icsneoc2_error_t res = icsneoc2_device_find_all(devices, &devices_count, NULL);
if (res != icsneoc2_error_success) {
return print_error_code("\tFailed to find devices", res);
};
printf("OK, %u device%s found\n", devices_count, devices_count == 1 ? "" : "s");
// List off the devices
for (uint32_t i = 0; i < devices_count; i++) {
icsneoc2_device_t* device = devices[i];
// Get description of the device
const char description[255] = {0};
uint32_t description_length = 255;
res = icsneoc2_device_description_get(device, description, &description_length);
if (res != icsneoc2_error_success) {
print_device_events(device, description);
return print_error_code("\tFailed to get device description", res);
};
printf("%.*s @ Handle %p\n", description_length, description, device);
// Get/Set open options
icsneoc2_open_options_t options = icsneoc2_open_options_none;
res = icsneoc2_device_open_options_get(device, &options);
if (res != icsneoc2_error_success) {
print_device_events(device, description);
return print_error_code("\tFailed to get open options", res);
}
// Disable Syncing RTC and going online
options &= ~icsneoc2_open_options_sync_rtc;
options &= ~icsneoc2_open_options_go_online;
printf("\tDevice open options: 0x%x\n", options);
res = icsneoc2_device_open_options_set(device, options);
if (res != icsneoc2_error_success) {
print_device_events(device, description);
return print_error_code("\tFailed to set open options", res);
}
// Open the device
printf("\tOpening device: %s...\n", description);
res = icsneoc2_device_open(device);
if (res != icsneoc2_error_success) {
print_device_events(device, description);
return print_error_code("\tFailed to open device", res);
};
// Get timestamp resolution of the device
printf("\tGetting timestamp resolution... ");
uint32_t timestamp_resolution = 0;
res = icsneoc2_device_timestamp_resolution_get(device, &timestamp_resolution);
if (res != icsneoc2_error_success) {
print_device_events(device, description);
return print_error_code("\tFailed to get timestamp resolution", res);
}
printf("%uns\n", timestamp_resolution);
// Get baudrates for HSCAN
printf("\tGetting HSCAN Baudrate... ");
uint64_t baudrate = 0;
res = icsneoc2_device_baudrate_get(device, icsneoc2_netid_hscan, &baudrate);
if (res != icsneoc2_error_success) {
print_device_events(device, description);
return print_error_code("\tFailed to get baudrate", res);
};
printf("%llumbit/s\n", baudrate);
// Get FDbaudrates for HSCAN
printf("\tGetting FD HSCAN Baudrate... ");
uint64_t fd_baudrate = 0;
res = icsneoc2_device_canfd_baudrate_get(device, icsneoc2_netid_hscan, &fd_baudrate);
if (res != icsneoc2_error_success) {
print_device_events(device, description);
return print_error_code("\tFailed to get FD baudrate", res);
};
printf("%llumbit/s\n", fd_baudrate);
// Set baudrates for HSCAN
// save_to_device: If this is set to true, the baudrate will be saved on the device
// and will persist through a power cycle
bool save_to_device = false;
printf("\tSetting HSCAN Baudrate... ");
res = icsneoc2_device_baudrate_set(device, icsneoc2_netid_hscan, baudrate, save_to_device);
if (res != icsneoc2_error_success) {
print_device_events(device, description);
return print_error_code("\tFailed to set baudrate", res);
};
printf("Ok\n");
// Set FDbaudrates for HSCAN
printf("\tSetting FD HSCAN Baudrate... ");
res = icsneoc2_device_canfd_baudrate_set(device, icsneoc2_netid_hscan, fd_baudrate, save_to_device);
if (res != icsneoc2_error_success) {
print_device_events(device, description);
return print_error_code("\tFailed to set FD baudrate", res);
};
printf("Ok\n");
// Get RTC
printf("\tGetting RTC... ");
res = get_and_print_rtc(device, description);
if (res != icsneoc2_error_success) {
print_device_events(device, description);
return print_error_code("\tFailed to get RTC", res);
}
// Set RTC
printf("\tSetting RTC to current time... ");
time_t current_time = time(NULL);
res = icsneoc2_device_rtc_set(device, current_time);
if (res != icsneoc2_error_success) {
print_device_events(device, description);
return print_error_code("\tFailed to set RTC", res);
}
printf("Ok\n");
// Get RTC
printf("\tGetting RTC... ");
res = get_and_print_rtc(device, description);
if (res != icsneoc2_error_success) {
print_device_events(device, description);
return print_error_code("\tFailed to get RTC", res);
}
// Go online, start acking traffic
printf("\tGoing online... ");
res = icsneoc2_device_go_online(device, true);
if (res != icsneoc2_error_success) {
print_device_events(device, description);
return print_error_code("\tFailed to go online", res);
}
// Redundant check to show how to check if the device is online, if the previous
// icsneoc2_device_go_online call was successful we can assume we are online already
bool is_online = false;
res = icsneoc2_device_is_online(device, &is_online);
if (res != icsneoc2_error_success) {
print_device_events(device, description);
return print_error_code("\tFailed to check if online", res);
}
printf("%s\n", is_online ? "Online" : "Offline");
// Transmit CAN messages
res = transmit_can_messages(device);
if (res != icsneoc2_error_success) {
print_device_events(device, description);
return print_error_code("\tFailed to transmit CAN messages", res);
}
// Wait for the bus to collect some messages, requires an active bus to get messages
printf("\tWaiting 1 second for messages...\n");
sleep_ms(1000);
// Get the messages
icsneoc2_message_t* messages[20000] = {0};
uint32_t message_count = 20000;
printf("\tGetting messages from device with timeout of 3000ms on %s...\n", description);
res = icsneoc2_device_messages_get(device, messages, &message_count, 3000);
if (res != icsneoc2_error_success) {
print_device_events(device, description);
return print_error_code("\tFailed to get messages from device", res);
};
// Process the messages
res = process_messages(device, messages, message_count);
if (res != icsneoc2_error_success) {
print_device_events(device, description);
return print_error_code("\tFailed to process messages", res);
}
// Finally, close the device.
printf("\tClosing device: %s...\n", description);
res = icsneoc2_device_close(device);
if (res != icsneoc2_error_success) {
print_device_events(device, description);
return print_error_code("\tFailed to close device", res);
};
// Print device events
print_device_events(device, description);
}
printf("\n");
return 0;
}
icsneoc2_error_t get_and_print_rtc(icsneoc2_device_t* device, const char* description) {
time_t unix_epoch = 0;
icsneoc2_error_t res = icsneoc2_device_rtc_get(device, &unix_epoch);
if (res != icsneoc2_error_success) {
return res;
}
char rtc_time[32] = {0};
strftime(rtc_time, sizeof(rtc_time), "%Y-%m-%d %H:%M:%S", localtime(&unix_epoch));
printf("RTC: %lld %s\n", unix_epoch, rtc_time);
return icsneoc2_error_success;
}
void print_device_events(icsneoc2_device_t* device, const char* device_description) {
// Get device events
icsneoc2_event_t* events[1024] = {0};
uint32_t events_count = 1024;
icsneoc2_error_t res = icsneoc2_device_events_get(device, events, &events_count);
if (res != icsneoc2_error_success) {
(void)print_error_code("\tFailed to get device events", res);
return;
}
// Loop over each event and describe it.
for (uint32_t i = 0; i < events_count; i++) {
const char event_description[255] = {0};
uint32_t event_description_length = 255;
res = icsneoc2_event_description_get(events[i], event_description, &event_description_length);
if (res != icsneoc2_error_success) {
print_error_code("\tFailed to get event description", res);
continue;
}
printf("\t%s: Event %u: %s\n", device_description, i, event_description);
}
// Get global events
icsneoc2_event_t* global_events[1024] = {0};
uint32_t global_events_count = 1024;
res = icsneoc2_events_get(global_events, &global_events_count);
if (res != icsneoc2_error_success) {
(void)print_error_code("\tFailed to get global events", res);
return;
}
// Loop over each event and describe it.
for (uint32_t i = 0; i < global_events_count; i++) {
const char event_description[255] = {0};
uint32_t event_description_length = 255;
res = icsneoc2_event_description_get(global_events[i], event_description, &event_description_length);
if (res != icsneoc2_error_success) {
print_error_code("\tFailed to get global event description", res);
continue;
}
printf("\t%s: Global Event %u: %s\n", device_description, i, event_description);
}
printf("\t%s: Received %u events and %u global events\n", device_description, events_count, global_events_count);
}
int process_messages(icsneoc2_device_t* device, icsneoc2_message_t** messages, uint32_t messages_count) {
// Print the type and bus type of each message
uint32_t tx_count = 0;
for (uint32_t i = 0; i < messages_count; i++) {
icsneoc2_message_t* message = messages[i];
// Get the message type
icsneoc2_msg_type_t msg_type = 0;
icsneoc2_error_t res = icsneoc2_message_type_get(device, message, &msg_type);
if (res != icsneoc2_error_success) {
return print_error_code("\tFailed to get message type", res);
}
// Get the message type name
char msg_type_name[128] = {0};
uint32_t msg_type_name_length = 128;
res = icsneoc2_message_type_name_get(msg_type, msg_type_name, &msg_type_name_length);
if (res != icsneoc2_error_success) {
return print_error_code("\tFailed to get message type name", res);
}
// Check if the message is a bus message, ignore otherwise
if (msg_type != icsneoc2_msg_type_bus) {
printf("Ignoring message type: %u (%s)\n", msg_type, msg_type_name);
continue;
}
icsneoc2_msg_bus_type_t bus_type = 0;
res = icsneoc2_message_bus_type_get(device, message, &bus_type);
if (res != icsneoc2_error_success) {
return print_error_code("\tFailed to get message bus type", res);
}
const char bus_name[128] = {0};
uint32_t bus_name_length = 128;
res = icsneoc2_bus_type_name_get(bus_type, bus_name, &bus_name_length);
if (res != icsneoc2_error_success) {
return print_error_code("\tFailed to get message bus type name", res);
}
bool is_tx = false;
res = icsneoc2_message_is_transmit(device, message, &is_tx);
if (res != icsneoc2_error_success) {
return print_error_code("\tFailed to get message is transmit", res);
}
if (is_tx) {
tx_count++;
continue;
}
printf("\t%d) Message type: %u bus type: %s (%u)\n", i, msg_type, bus_name, bus_type);
if (bus_type == icsneoc2_msg_bus_type_can) {
uint32_t arbid = 0;
int32_t dlc = 0;
icsneoc2_netid_t netid = 0;
bool is_remote = false;
bool is_canfd = false;
bool is_extended = false;
uint8_t data[64] = {0};
uint32_t data_length = 64;
const char netid_name[128] = {0};
uint32_t netid_name_length = 128;
uint32_t result = icsneoc2_message_netid_get(device, message, &netid);
result += icsneoc2_netid_name_get(netid, netid_name, &netid_name_length);
result += icsneoc2_message_can_arbid_get(device, message, &arbid);
result += icsneoc2_message_can_dlc_get(device, message, &dlc);
result += icsneoc2_message_can_is_remote(device, message, &is_remote);
result += icsneoc2_message_can_is_canfd(device, message, &is_canfd);
result += icsneoc2_message_can_is_extended(device, message, &is_extended);
result += icsneoc2_message_data_get(device, message, data, &data_length);
if (result != icsneoc2_error_success) {
printf("\tFailed get get CAN parameters (error: %u) for index %u\n", result, i);
continue;
}
printf("\t NetID: %s (0x%x)\tArbID: 0x%x\t DLC: %u\t Remote: %d\t CANFD: %d\t Extended: %d\t Data length: %u\n", netid_name, netid, arbid, dlc, is_remote, is_canfd, is_extended, data_length);
printf("\t Data: [");
for (uint32_t x = 0; x < data_length; x++) {
printf(" 0x%x", data[x]);
}
printf(" ]\n");
}
}
printf("\tReceived %u messages total, %u were TX messages\n", messages_count, tx_count);
return icsneoc2_error_success;
}
int transmit_can_messages(icsneoc2_device_t* device) {
uint64_t counter = 0;
const uint32_t msg_count = 100;
printf("\tTransmitting %d messages...\n", msg_count);
for (uint32_t i = 0; i < msg_count; i++) {
// Create the message
icsneoc2_message_t* message = NULL;
uint32_t message_count = 1;
icsneoc2_error_t res = icsneoc2_message_can_create(device, &message, message_count);
if (res != icsneoc2_error_success) {
return print_error_code("\tFailed to create messages", res);
}
// Set the message attributes
res = icsneoc2_message_netid_set(device, message, icsneoc2_netid_hscan);
res += icsneoc2_message_can_arbid_set(device, message, 0x10);
res += icsneoc2_message_can_canfd_set(device, message, true);
res += icsneoc2_message_can_extended_set(device, message, true);
res += icsneoc2_message_can_baudrate_switch_set(device, message, true);
// Create the payload
uint8_t data[8] = {0};
data[0] = (uint8_t)(counter >> 56);
data[1] = (uint8_t)(counter >> 48);
data[2] = (uint8_t)(counter >> 40);
data[3] = (uint8_t)(counter >> 32);
data[4] = (uint8_t)(counter >> 24);
data[5] = (uint8_t)(counter >> 16);
data[6] = (uint8_t)(counter >> 8);
data[7] = (uint8_t)(counter >> 0);
res += icsneoc2_message_data_set(device, message, data, sizeof(data));
res += icsneoc2_message_can_dlc_set(device, message, -1);
if (res != icsneoc2_error_success) {
return print_error_code("\tFailed to modify message", res);
}
res = icsneoc2_device_messages_transmit(device, &message, &message_count);
res += icsneoc2_message_can_free(device, message);
if (res != icsneoc2_error_success) {
return print_error_code("\tFailed to transmit messages", res);
}
counter++;
}
return icsneoc2_error_success;
}
+2 -2
View File
@@ -259,8 +259,8 @@ void example4(const std::shared_ptr<icsneo::Device>& rada2b) {
auto handler = rada2b->addMessageCallback(std::make_shared<icsneo::MessageCallback>( auto handler = rada2b->addMessageCallback(std::make_shared<icsneo::MessageCallback>(
[] (std::shared_ptr<icsneo::Message> newMsg) { [] (std::shared_ptr<icsneo::Message> newMsg) {
if(newMsg->type == icsneo::Message::Type::Frame) { if(newMsg->type == icsneo::Message::Type::BusMessage) {
const auto& frame = std::dynamic_pointer_cast<icsneo::Frame>(newMsg); const auto& frame = std::dynamic_pointer_cast<icsneo::BusMessage>(newMsg);
if(frame && frame->network.getNetID() == icsneo::Network::NetID::I2C2) { if(frame && frame->network.getNetID() == icsneo::Network::NetID::I2C2) {
const auto& i2cMessage = std::dynamic_pointer_cast<icsneo::I2CMessage>(frame); const auto& i2cMessage = std::dynamic_pointer_cast<icsneo::I2CMessage>(frame);
+2
View File
@@ -0,0 +1,2 @@
add_executable(libicsneocpp-app-error src/AppErrorExample.cpp)
target_link_libraries(libicsneocpp-app-error icsneocpp)
@@ -0,0 +1,85 @@
#include <iostream>
#include <iomanip>
#include <thread>
#include <chrono>
#include "icsneo/icsneocpp.h"
#include "icsneo/communication/message/apperrormessage.h"
#include "icsneo/communication/message/message.h"
/*
* App errors are responses from the device indicating internal runtime errors
* NOTE: To trigger the app error in this example, disable the HSCAN network on the device
* (e.g. with neoVI Explorer)
*/
int main() {
std::cout << "Running libicsneo " << icsneo::GetVersion() << std::endl;
std::cout << "\nFinding devices... " << std::flush;
auto devices = icsneo::FindAllDevices();
std::cout << "OK, " << devices.size() << " device" << (devices.size() == 1 ? "" : "s") << " found" << std::endl;
// List off the devices
for(auto& device : devices)
std::cout << '\t' << device->describe() << " @ Handle " << device->getNeoDevice().handle << std::endl;
std::cout << std::endl;
for(auto device : devices) {
std::cout << "Connecting to " << device->describe() << "... ";
bool ret = device->open();
if(!ret) { // Failed to open
std::cout << "FAIL" << std::endl;
std::cout << icsneo::GetLastError() << std::endl << std::endl;
continue;
}
std::cout << "OK" << std::endl << std::endl;
// Create an app error message filter, including "internal" messages
auto filter = std::make_shared<icsneo::MessageFilter>(icsneo::Message::Type::AppError);
filter->includeInternalInAny = true;
// ...and register a callback with it.
// Add your error handling here
auto handler = device->addMessageCallback(std::make_shared<icsneo::MessageCallback>(filter, [](std::shared_ptr<icsneo::Message> message) {
auto msg = std::static_pointer_cast<icsneo::AppErrorMessage>(message);
if(icsneo::Network::NetID::RED_App_Error == msg->network.getNetID()) {
std::cout << std::endl << "App error reported:" << std::endl;
std::cout << msg->getAppErrorString() << std::endl << std::endl;
}
}));
std::cout << "Going online... ";
ret = device->goOnline();
if(!ret) {
std::cout << "FAIL" << std::endl;
device->close();
continue;
}
std::cout << "OK" << std::endl;
// Prepare a CAN message
std::cout << std::endl << "Transmitting a CAN frame... ";
auto txMessage = std::make_shared<icsneo::CANMessage>();
txMessage->network = icsneo::Network::NetID::HSCAN;
txMessage->arbid = 0x22;
txMessage->data.insert(txMessage->data.end(), {0xaa, 0xbb, 0xcc});
// The DLC will come from the length of the data vector
txMessage->isExtended = false;
txMessage->isCANFD = false;
// Transmit a CAN message on HSCAN, even though HSCAN is disabled on the device!
// Expect to see an app error caught in the callback defined above
ret = device->transmit(txMessage);
std::cout << (ret ? "OK" : "FAIL") << std::endl;
std::this_thread::sleep_for(std::chrono::milliseconds(1000));
// Go offline, stop sending and receiving traffic
device->removeMessageCallback(handler);
std::cout << "Going offline... ";
ret = device->goOffline();
std::cout << (ret ? "OK" : "FAIL") << std::endl;
std::cout << "Disconnecting... ";
ret = device->close();
std::cout << (ret ? "OK\n" : "FAIL\n") << std::endl;
}
return 0;
}
@@ -184,9 +184,9 @@ std::shared_ptr<icsneo::Device> selectDevice(const std::vector<std::shared_ptr<i
void printMessage(const std::shared_ptr<icsneo::Message>& message) { void printMessage(const std::shared_ptr<icsneo::Message>& message) {
switch(message->type) { switch(message->type) {
case icsneo::Message::Type::Frame: { case icsneo::Message::Type::BusMessage: {
// A message of type Frame is guaranteed to be a Frame, so we can static cast safely // A message of type Frame is guaranteed to be a Frame, so we can static cast safely
auto frame = std::static_pointer_cast<icsneo::Frame>(message); auto frame = std::static_pointer_cast<icsneo::BusMessage>(message);
switch(frame->network.getType()) { switch(frame->network.getType()) {
case icsneo::Network::Type::CAN: { case icsneo::Network::Type::CAN: {
// A message of type CAN is guaranteed to be a CANMessage, so we can static cast safely // A message of type CAN is guaranteed to be a CANMessage, so we can static cast safely
@@ -264,10 +264,10 @@ void printMessage(const std::shared_ptr<icsneo::Message>& message) {
break; break;
} }
break; break;
} // end of icsneo::Message::Type::Frame } // end of icsneo::Message::Type::BusMessage
case icsneo::Message::Type::CANErrorCount: { case icsneo::Message::Type::CANErrorCount: {
// A message of type CANErrorCount is guaranteed to be a CANErrorCount, so we can static cast safely // A message of type CANErrorCount is guaranteed to be a CANErrorCount, so we can static cast safely
auto cec = std::static_pointer_cast<icsneo::CANErrorCountMessage>(message); auto cec = std::static_pointer_cast<icsneo::CANErrorMessage>(message);
std::cout << "\t\t" << cec->network << " error counts changed, REC=" << cec->receiveErrorCount std::cout << "\t\t" << cec->network << " error counts changed, REC=" << cec->receiveErrorCount
<< " TEC=" << cec->transmitErrorCount << " (" << (cec->busOff ? "" : "Not ") << "Bus Off)" << std::endl; << " TEC=" << cec->transmitErrorCount << " (" << (cec->busOff ? "" : "Not ") << "Bus Off)" << std::endl;
break; break;
+2 -2
View File
@@ -96,8 +96,8 @@ int main() {
std::cout << "OK" << std::endl << std::endl; std::cout << "OK" << std::endl << std::endl;
auto handler = device->addMessageCallback(std::make_shared<icsneo::MessageCallback>([&](std::shared_ptr<icsneo::Message> message) { auto handler = device->addMessageCallback(std::make_shared<icsneo::MessageCallback>([&](std::shared_ptr<icsneo::Message> message) {
if(icsneo::Message::Type::Frame == message->type) { if(icsneo::Message::Type::BusMessage == message->type) {
auto frame = std::static_pointer_cast<icsneo::Frame>(message); auto frame = std::static_pointer_cast<icsneo::BusMessage>(message);
if(icsneo::Network::Type::LIN == frame->network.getType()) { if(icsneo::Network::Type::LIN == frame->network.getType()) {
auto msg = std::static_pointer_cast<icsneo::LINMessage>(message); auto msg = std::static_pointer_cast<icsneo::LINMessage>(message);
std::cout << msg->network << " RX frame | ID: 0x" << std::hex << static_cast<int>(msg->ID) << " | "; std::cout << msg->network << " RX frame | ID: 0x" << std::hex << static_cast<int>(msg->ID) << " | ";
+2 -2
View File
@@ -92,8 +92,8 @@ int main()
auto handler = device->addMessageCallback(std::make_shared<icsneo::MessageCallback>([&](std::shared_ptr<icsneo::Message> message) auto handler = device->addMessageCallback(std::make_shared<icsneo::MessageCallback>([&](std::shared_ptr<icsneo::Message> message)
{ {
if(icsneo::Message::Type::Frame == message->type) { if(icsneo::Message::Type::BusMessage == message->type) {
auto frame = std::static_pointer_cast<icsneo::Frame>(message); auto frame = std::static_pointer_cast<icsneo::BusMessage>(message);
if(icsneo::Network::Type::MDIO == frame->network.getType()) { if(icsneo::Network::Type::MDIO == frame->network.getType()) {
auto msg = std::static_pointer_cast<icsneo::MDIOMessage>(message); auto msg = std::static_pointer_cast<icsneo::MDIOMessage>(message);
std::cout << msg->network << " " << ((msg->isTXMsg)? "TX" : "RX") << " frame\n"; std::cout << msg->network << " " << ((msg->isTXMsg)? "TX" : "RX") << " frame\n";
+6 -6
View File
@@ -169,9 +169,9 @@ int main() {
// MessageCallbacks are powerful, and can filter on things like ArbID for you. See the documentation // MessageCallbacks are powerful, and can filter on things like ArbID for you. See the documentation
auto handler = device->addMessageCallback(std::make_shared<icsneo::MessageCallback>([](std::shared_ptr<icsneo::Message> message) { auto handler = device->addMessageCallback(std::make_shared<icsneo::MessageCallback>([](std::shared_ptr<icsneo::Message> message) {
switch(message->type) { switch(message->type) {
case icsneo::Message::Type::Frame: { case icsneo::Message::Type::BusMessage: {
// A message of type Frame is guaranteed to be a Frame, so we can static cast safely // A message of type BusMessage is guaranteed to be a BusMessage, so we can static cast safely
auto frame = std::static_pointer_cast<icsneo::Frame>(message); auto frame = std::static_pointer_cast<icsneo::BusMessage>(message);
switch(frame->network.getType()) { switch(frame->network.getType()) {
case icsneo::Network::Type::CAN: { case icsneo::Network::Type::CAN: {
// A message of type CAN is guaranteed to be a CANMessage, so we can static cast safely // A message of type CAN is guaranteed to be a CANMessage, so we can static cast safely
@@ -202,7 +202,7 @@ int main() {
case icsneo::Network::Type::Ethernet: { case icsneo::Network::Type::Ethernet: {
auto ethMessage = std::static_pointer_cast<icsneo::EthernetMessage>(message); auto ethMessage = std::static_pointer_cast<icsneo::EthernetMessage>(message);
std::cout << "\t\t" << ethMessage->network << " Frame - " << std::dec std::cout << "\t\t" << ethMessage->network << " BusMessage - " << std::dec
<< ethMessage->data.size() << " bytes on wire\n"; << ethMessage->data.size() << " bytes on wire\n";
std::cout << "\t\t Timestamped:\t"<< ethMessage->timestamp << " ns since 1/1/2007\n"; std::cout << "\t\t Timestamped:\t"<< ethMessage->timestamp << " ns since 1/1/2007\n";
@@ -249,10 +249,10 @@ int main() {
break; break;
} }
break; break;
} // end of icsneo::Message::Type::Frame } // end of icsneo::Message::Type::BusMessage
case icsneo::Message::Type::CANErrorCount: { case icsneo::Message::Type::CANErrorCount: {
// A message of type CANErrorCount is guaranteed to be a CANErrorCount, so we can static cast safely // A message of type CANErrorCount is guaranteed to be a CANErrorCount, so we can static cast safely
auto cec = std::static_pointer_cast<icsneo::CANErrorCountMessage>(message); auto cec = std::static_pointer_cast<icsneo::CANErrorMessage>(message);
// Print the error counts // Print the error counts
std::cout << "\t\t" << cec->network << " error counts changed, REC=" << std::to_string(cec->receiveErrorCount) std::cout << "\t\t" << cec->network << " error counts changed, REC=" << std::to_string(cec->receiveErrorCount)
+7 -7
View File
@@ -16,13 +16,13 @@ void onEvent(std::shared_ptr<icsneo::APIEvent> event) {
std::cout << event->describe() << std::endl; std::cout << event->describe() << std::endl;
} }
std::vector<std::shared_ptr<icsneo::Frame>> constructRandomFrames(size_t frameCount, MessageType frameType) { std::vector<std::shared_ptr<icsneo::BusMessage>> constructRandomFrames(size_t frameCount, MessageType frameType) {
static constexpr size_t ClassicCANSize = 8; static constexpr size_t ClassicCANSize = 8;
static constexpr size_t CANFDSize = 64; static constexpr size_t CANFDSize = 64;
static constexpr size_t ShortEthSize = 500; static constexpr size_t ShortEthSize = 500;
static constexpr size_t LongEthSize = 1500; static constexpr size_t LongEthSize = 1500;
std::vector<std::shared_ptr<icsneo::Frame>> frames; std::vector<std::shared_ptr<icsneo::BusMessage>> frames;
std::random_device randDev; std::random_device randDev;
std::mt19937 randEngine(randDev()); std::mt19937 randEngine(randDev());
std::uniform_int_distribution randByteDist(0,255); std::uniform_int_distribution randByteDist(0,255);
@@ -166,10 +166,10 @@ int main(int argc, char* argv[]) {
uint64_t canFrameCount = 0; uint64_t canFrameCount = 0;
uint64_t ethFrameCount = 0; uint64_t ethFrameCount = 0;
rxDevice->addMessageCallback(std::make_shared<icsneo::MessageCallback>([&](std::shared_ptr<icsneo::Message> msg) { rxDevice->addMessageCallback(std::make_shared<icsneo::MessageCallback>([&](std::shared_ptr<icsneo::Message> msg) {
if(msg->type != icsneo::Message::Type::Frame) { if(msg->type != icsneo::Message::Type::BusMessage) {
return; return;
} }
const auto frame = std::static_pointer_cast<icsneo::Frame>(msg); const auto frame = std::static_pointer_cast<icsneo::BusMessage>(msg);
if(frame->network.getType() == icsneo::Network::Type::CAN) { if(frame->network.getType() == icsneo::Network::Type::CAN) {
++canFrameCount; ++canFrameCount;
} else if(frame->network.getType() == icsneo::Network::Type::Ethernet) { } else if(frame->network.getType() == icsneo::Network::Type::Ethernet) {
@@ -200,7 +200,7 @@ int main(int argc, char* argv[]) {
const uint8_t NumFrameTypes = 4; const uint8_t NumFrameTypes = 4;
const size_t FrameCountPerType = 2500; const size_t FrameCountPerType = 2500;
std::vector<std::shared_ptr<icsneo::Frame>> frames; std::vector<std::shared_ptr<icsneo::BusMessage>> frames;
for(uint8_t i = 0; i < NumFrameTypes; i++) { for(uint8_t i = 0; i < NumFrameTypes; i++) {
std::cout << "info: transmitting " << FrameCountPerType << " random " << MessageTypeLabels[i] << " frames" << std::endl; std::cout << "info: transmitting " << FrameCountPerType << " random " << MessageTypeLabels[i] << " frames" << std::endl;
auto tempFrames = constructRandomFrames(FrameCountPerType, static_cast<MessageType>(i)); auto tempFrames = constructRandomFrames(FrameCountPerType, static_cast<MessageType>(i));
@@ -216,10 +216,10 @@ int main(int argc, char* argv[]) {
size_t currentMessage = 0; size_t currentMessage = 0;
rxDevice->addMessageCallback(std::make_shared<icsneo::MessageCallback>([&](std::shared_ptr<icsneo::Message> msg) { rxDevice->addMessageCallback(std::make_shared<icsneo::MessageCallback>([&](std::shared_ptr<icsneo::Message> msg) {
if(msg->type != icsneo::Message::Type::Frame) { if(msg->type != icsneo::Message::Type::BusMessage) {
return; return;
} }
auto frame = std::static_pointer_cast<icsneo::Frame>(msg); auto frame = std::static_pointer_cast<icsneo::BusMessage>(msg);
if(frames[currentMessage]->data == frame->data) { if(frames[currentMessage]->data == frame->data) {
currentMessage++; currentMessage++;
} }

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