84 Commits
Author SHA1 Message Date
Thomas StoddardandKyle Schwarz 5620c98eda Examples: Add more error reporting 2026-05-13 17:03:01 -04:00
Thomas StoddardandKyle Schwarz c466d75dae All: neoVI Explorer -> ICS Device Manager 2026-05-13 15:45:28 -04:00
Thomas StoddardandKyle Schwarz d7fc7ffa47 RADGigastar2 & RADGalaxy2: Add PhyEnableFor support 2026-05-12 18:38:32 -04:00
Kyle Schwarz 70ad76771e Servd: Clean up unused parseError 2026-05-12 16:57:04 -04:00
Kyle Schwarz 87c10410e8 Servd: Remove no devices found event 2026-05-12 15:58:11 -04:00
Thomas StoddardandKyle Schwarz 7cca96dcfb All: Switch to Servd default on
See README for details on how to install Servd.
2026-05-08 13:28:49 -04:00
Kyle Schwarz d45b72ef68 Settings: Increase response timeouts 2026-05-07 09:05:57 -04:00
Thomas StoddardandKyle Schwarz da02927da7 APIEvent: Add missing types 2026-05-06 16:57:00 -04:00
Thomas StoddardandKyle Schwarz b5a6f6ace6 Core: MACsec: Validate AN range and enable slots during addition 2026-05-06 13:47:25 -04:00
David RebbeandKyle Schwarz 0d2bbed7d5 C2: Add TC10 APIs 2026-05-06 11:04:44 -04:00
Kyle Schwarz a68b64c641 Device: Refactor supportsNetworkMutex 2026-05-05 20:35:51 -04:00
David RebbeandKyle Schwarz 9abd9389f4 Docs: Add Linux pcap info 2026-05-05 20:34:23 -04:00
David RebbeandKyle Schwarz d682627b40 CI: Fedora 44 & Ubuntu 26.04 2026-05-05 16:11:48 -04:00
David RebbeandKyle Schwarz 9ae3e115fc C2: Add Ethernet message support 2026-04-30 15:28:40 -04:00
Kyle Schwarz 87f45e060e Device: RADGalaxy2: Adjust bootloader pipeline 2026-04-28 15:37:17 -04:00
Thomas StoddardandKyle Schwarz 0cb30cfc5b Bindings: icsneopy: Add install instructions 2026-04-28 15:26:02 -04:00
Max BrombachandKyle Schwarz 79ff19015a Device: RAD-Gigastar 1 & 2: Add SFP flashing to bootloader pipelines 2026-04-24 16:12:45 -04:00
David RebbeandKyle Schwarz 9c4323987f C2: CAN error message support 2026-04-17 11:39:38 -04:00
David RebbeandKyle Schwarz f5f6d0828b C2: Add LIN message support 2026-04-15 15:50:33 -04:00
David RebbeandKyle Schwarz 6dc005fcea C2: Add PCBSN and MAC Address support 2026-04-14 13:37:27 -04:00
David RebbeandKyle Schwarz 5b553b63d3 C2: Add icsneoc2_device_reconnect 2026-04-08 16:19:31 -04:00
Michael BowersandKyle Schwarz 97a6b4a04f Device: RADGalaxy2: Remove EnterApplicationPhase 2026-04-06 10:57:09 -04:00
Thomas StoddardandKyle Schwarz 67929a19bc Example: Fix type casting for MSVC warnings 2026-04-06 10:17:16 -04:00
Thomas StoddardandKyle Schwarz e7c2c07947 Bindings: Python: Update to pybind11 3.0.3 2026-04-03 16:16:27 -04:00
Thomas StoddardandKyle Schwarz 146ddaf23c Device: Add T1S extended settings 2026-04-03 12:14:17 -04:00
Thomas StoddardandKyle Schwarz 6f2ad54adc Device: Add get_pcb_serial() & get_mac_address() 2026-04-02 15:45:58 -04:00
Max Brombach 87e2a65b71 Device: VividCAN: Add bootloader pipeline and chips 2026-03-30 10:43:41 -04:00
Thomas StoddardandKyle Schwarz 26e8a2c3d9 Device: FIRE3: Add BASE-T settings 2026-03-26 13:56:12 -04:00
David RebbeandKyle Schwarz 0ef26fec63 C2: Fix preprocessor defines for libclang parsing 2026-03-25 09:28:56 -04:00
Thomas StoddardandKyle Schwarz 682299cb8c API: Add icsneoc2 2026-03-24 21:08:40 -04:00
Yaroslav StetsykandKyle Schwarz 294e707924 Device: NeoVIFIRE3T1SLIN: Add bootloader details 2026-03-20 15:54:23 -04:00
Kyle Schwarz 22d2b7c984 Servd: Adjust buffer sizes 2026-03-18 18:21:55 -04:00
Kyle Schwarz 5a4a1489a8 DXX: Update for max packet size 2026-03-18 15:35:31 -04:00
Thomas StoddardandKyle Schwarz b0b7623b4c Core: MACsec: Mirror 128-bit keys 2026-03-16 13:59:40 -04:00
Max BrombachandKyle Schwarz 171422d8e1 Device: RAD-Gemini: Add chip info and fix bootloader pipeline 2026-03-10 15:13:09 -04:00
Kyle Schwarz 81769db025 Device: NeoVIFIRE3: Add CAN networks to settings 2026-03-06 16:08:40 -05:00
Kyle Schwarz 0e60f8f459 Device: RADComet3: Handle AE_LINK_INVALID 2026-03-04 19:37:00 -05:00
Thomas StoddardandKyle Schwarz 0aa7d338fd Bindings: Python: Add formatDisk 2026-03-03 15:38:13 -05:00
Kyle Schwarz 224e840841 Device: Increase DiskFormatProgress timeout 2026-02-17 17:16:49 -05:00
Max Brombach 174c0b80d4 Device: VCAN4-IND: Add chips and bootloader information 2026-02-17 12:00:34 -05:00
Max BrombachandKyle Schwarz 19092bceb6 Device: RAD-MoonT1S: Add bootloader pipeline and chip 2026-02-13 13:17:59 -05:00
Kyle Schwarz 25b673075f All: Copyright 2026 2026-02-13 10:08:09 -05:00
Max BrombachandKyle Schwarz 1a7bc4df47 Device: RADJupiter: Add bootloader pipeline 2026-02-12 17:05:39 -05:00
Max BrombachandKyle Schwarz 20a2474508 Device: Settings: Add missing bit-packed variables to CAN_SETTINGS 2026-02-12 16:25:57 -05:00
Thomas StoddardandKyle Schwarz d18ca9e6eb Device: RAD-Galaxy: Add support for Analog Output 2026-02-11 18:43:30 -05:00
Max BrombachandKyle Schwarz 6cda765fe0 Device: FIRE2: Skip flashing Core chip when chip variant is unknown 2026-02-10 21:20:47 -05:00
Jonathan SchwartzandKyle Schwarz 730aaf5fed Device: FIRE3: Update disk counts 2026-02-06 14:32:31 -05:00
Kyle Schwarz 1f10adb760 ThirdParty: Update icspb & libredxx 2026-01-30 17:12:09 -05:00
Thomas StoddardandKyle Schwarz 6a32823a0f Device: FlexRay: Add additional configuration options for Controller and Cluster 2026-01-30 13:06:39 -05:00
Thomas StoddardandKyle Schwarz 5f16adc103 Device: RADComet3: Add Ethernet settings 2026-01-28 16:00:39 -05:00
Jonathan SchwartzandKyle Schwarz f6926cbb22 Device: Unlock network mutex when going offline 2026-01-27 15:22:12 -05:00
Thomas StoddardandKyle Schwarz 4c7b8e107a Device: RADComet: Add T1S settings 2026-01-23 13:03:39 -05:00
Jonathan SchwartzandKyle Schwarz 0e55101a16 Device: goOnline: Refactor network locking
Only lock known networks.
2026-01-22 16:46:51 -05:00
Max BrombachandKyle Schwarz 68ebb6dae4 Device: Add EnterApplicationPhases step 2026-01-20 14:25:29 -05:00
Jonathan SchwartzandKyle Schwarz 8cb62c2cae Device: Carry bootloader version for potential compatibility checks 2026-01-12 17:45:10 -05:00
Kyle Schwarz d74051f57e Driver: Servd: Refactor to TCP 2026-01-12 13:03:55 -05:00
Thomas Stoddard 530a99d264 Add T1S PLCA and related settings support for Fire3T1S, RadComet3, RadGigaStar2, and RadMoonT1S devices 2026-01-09 18:16:10 +00:00
Thomas StoddardandKyle Schwarz 5ee450353b Bindings: Python: Add T1S members 2026-01-07 23:32:20 -05:00
Thomas StoddardandKyle Schwarz 516bca682c EthernetMessage: Add T1S symbol support 2026-01-07 16:34:34 -05:00
Jonathan SchwartzandKyle Schwarz 3f5150bef3 FirmIO: Fix instability and memory leak issues 2026-01-07 13:35:23 -05:00
Thomas StoddardandKyle Schwarz 2a2d55f20d Bindings: Python : Add baudrate and LIN mode methods 2026-01-07 10:51:25 -05:00
Thomas StoddardandKyle Schwarz 977677e3af Bindings: Add LiveData and LiveDataMessage support in Python bindings 2026-01-05 10:40:14 -05:00
Kyle Schwarz 000036f745 Driver: DXX: Update
Fixes D2XX HANDLE leak.
2025-12-19 22:30:14 -05:00
Kyle Schwarz be6a15c017 Device: Galaxy2: Update supported networks 2025-12-18 12:22:12 -05:00
Nicholas ZamoraandKyle Schwarz 5288385495 Driver: DXX: Update libredxx for FT260 support 2025-12-16 11:05:11 -05:00
Max Brombach d6d9fc16ef Device: Update chips for ValueCAN4_2EL bootloader 2025-12-10 19:47:23 +00:00
Kyle Schwarz dbab92b25c Bindings: Python: Migrate to smart_holder 2025-12-09 14:24:40 -05:00
Max Brombach 579160f6d4 Device: Fix Epsilon-XL bootloader pipeline and chip info 2025-12-08 21:16:14 +00:00
Emily Brooks 737d5ceb3b TransmitMessage: Mark timestamp as extended when using CAN FD 2025-12-05 13:53:26 -05:00
Emily Brooks 95521a5548 TransmitMessage: Add TX support for neoVI network 2025-12-05 10:53:53 -05:00
Emily BrooksandKyle Schwarz 16cd476c01 Network: neoVI: Add TX support 2025-12-03 14:43:35 -05:00
Thomas StoddardandKyle Schwarz d328d314b6 Bindings: Python: Update pybind11
Updates to 3.0.1 and switches to smart_holder & native_enum.
2025-11-24 11:56:09 -05:00
Bryant JonesandKyle Schwarz 7b5b94d980 Docs: Python: Add SPI example 2025-11-20 17:08:30 -05:00
Kyle Schwarz fedb4b88f3 Build: Update icspb 2025-11-10 11:29:42 -05:00
Kyle Schwarz 5cac3a4600 Examples: Remove commented example 2025-11-05 12:01:58 -05:00
Yasser YassineandKyle Schwarz 9ff4bf7d0d MACsec: Refactor API 2025-11-05 12:00:07 -05:00
Kyle Schwarz 30c009fe8f Device: Refactor online keep alive 2025-11-04 16:24:49 -05:00
Max BrombachandKyle Schwarz 51e4fdc6d9 Device: Update tree structs and add size checks to non-deprecated devices 2025-11-04 14:29:37 -05:00
Yasser YassineandKyle Schwarz 39b54d8c4e Device: Fix bootloader phases 2025-11-04 12:37:19 -05:00
Kyle Schwarz 615b7d8d56 Bindings: Python: Document 3.14 support 2025-11-04 11:51:55 -05:00
Kyle Schwarz e3f4bbdc73 Device: sendEthPhyMsg(): Drop online requirement 2025-11-04 11:06:51 -05:00
Nicholas ZamoraandKyle Schwarz 563c444def Device: Add RAD-Gemini 2025-11-03 09:37:50 -05:00
Kyle Schwarz 3f3300d677 Communication: EthernetStatusMessage: Handle BASE-T invalid case 2025-10-31 12:31:03 -04:00
Max BrombachandKyle Schwarz b9e3542bcf Device: Use variant Core chip and fix ZChip flash for FIRE2 2025-10-31 12:02:02 -04:00
231 changed files with 22744 additions and 2319 deletions
+48 -48
View File
@@ -119,30 +119,6 @@ unit_test windows/x86:
- linux-build
timeout: 5m
build linux/ubuntu/2204/amd64/gcc:
<<: *build_linux_ubuntu_gcc
image: ubuntu:22.04
unit_test linux/ubuntu/2204/amd64/gcc:
<<: *test_linux_ubuntu_gcc
image: ubuntu:22.04
dependencies:
- build linux/ubuntu/2204/amd64/gcc
needs:
- build linux/ubuntu/2204/amd64/gcc
build linux/ubuntu/2204/amd64/clang:
<<: *build_linux_ubuntu_clang
image: ubuntu:22.04
unit_test linux/ubuntu/2204/amd64/clang:
<<: *test_linux_ubuntu_clang
image: ubuntu:22.04
dependencies:
- build linux/ubuntu/2204/amd64/clang
needs:
- build linux/ubuntu/2204/amd64/clang
build linux/ubuntu/2404/amd64/gcc:
<<: *build_linux_ubuntu_gcc
image: ubuntu:24.04
@@ -167,6 +143,30 @@ unit_test linux/ubuntu/2404/amd64/clang:
needs:
- build linux/ubuntu/2404/amd64/clang
build linux/ubuntu/2604/amd64/gcc:
<<: *build_linux_ubuntu_gcc
image: ubuntu:26.04
unit_test linux/ubuntu/2604/amd64/gcc:
<<: *test_linux_ubuntu_gcc
image: ubuntu:26.04
dependencies:
- build linux/ubuntu/2604/amd64/gcc
needs:
- build linux/ubuntu/2604/amd64/gcc
build linux/ubuntu/2604/amd64/clang:
<<: *build_linux_ubuntu_clang
image: ubuntu:26.04
unit_test linux/ubuntu/2604/amd64/clang:
<<: *test_linux_ubuntu_clang
image: ubuntu:26.04
dependencies:
- build linux/ubuntu/2604/amd64/clang
needs:
- build linux/ubuntu/2604/amd64/clang
#-------------------------------------------------------------------------------
# Fedora
#-------------------------------------------------------------------------------
@@ -243,30 +243,6 @@ unit_test linux/ubuntu/2404/amd64/clang:
- linux-build
timeout: 5m
build linux/fedora/42/amd64/gcc:
<<: *build_linux_fedora_gcc
image: fedora:42
unit_test linux/fedora/42/amd64/gcc:
<<: *test_linux_fedora_gcc
image: fedora:42
dependencies:
- build linux/fedora/42/amd64/gcc
needs:
- build linux/fedora/42/amd64/gcc
build linux/fedora/42/amd64/clang:
<<: *build_linux_fedora_clang
image: fedora:42
unit_test linux/fedora/42/amd64/clang:
<<: *test_linux_fedora_clang
image: fedora:42
dependencies:
- build linux/fedora/42/amd64/clang
needs:
- build linux/fedora/42/amd64/clang
build linux/fedora/43/amd64/gcc:
<<: *build_linux_fedora_gcc
image: fedora:43
@@ -291,6 +267,30 @@ unit_test linux/fedora/43/amd64/clang:
needs:
- build linux/fedora/43/amd64/clang
build linux/fedora/44/amd64/gcc:
<<: *build_linux_fedora_gcc
image: fedora:44
unit_test linux/fedora/44/amd64/gcc:
<<: *test_linux_fedora_gcc
image: fedora:44
dependencies:
- build linux/fedora/44/amd64/gcc
needs:
- build linux/fedora/44/amd64/gcc
build linux/fedora/44/amd64/clang:
<<: *build_linux_fedora_clang
image: fedora:44
unit_test linux/fedora/44/amd64/clang:
<<: *test_linux_fedora_clang
image: fedora:44
dependencies:
- build linux/fedora/44/amd64/clang
needs:
- build linux/fedora/44/amd64/clang
#-------------------------------------------------------------------------------
# Python Module
#-------------------------------------------------------------------------------
+3
View File
@@ -5,3 +5,6 @@ KERNEL=="ttyACM?", ATTRS{idVendor}=="093c", GROUP="users", MODE="0666"
ACTION=="add", SUBSYSTEMS=="usb", ATTRS{idVendor}=="093c", KERNEL=="ttyUSB*", \
RUN+="/bin/sh -c 'echo $id:1.0>/sys/bus/usb/drivers/ftdi_sio/unbind'"
ACTION=="add", SUBSYSTEMS=="usb", ATTRS{idVendor}=="093c", DRIVER=="usbhid", \
RUN+="/bin/sh -c 'echo $id:1.0>/sys/bus/usb/drivers/usbhid/unbind'"
+48 -10
View File
@@ -11,6 +11,8 @@ option(LIBICSNEO_BUILD_DOCS "Build documentation. Don't use in Visual Studio." O
option(LIBICSNEO_BUILD_EXAMPLES "Build examples." ON)
option(LIBICSNEO_BUILD_ICSNEOC "Build dynamic 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_STATIC "Build static icsnVC40 compatibility library" ON)
set(LIBICSNEO_NPCAP_INCLUDE_DIR "" CACHE STRING "Npcap include directory; set to build with Npcap")
@@ -170,10 +172,6 @@ if(LIBICSNEO_ENABLE_TCP)
)
endif()
if(LIBICSNEO_BUILD_EXAMPLES)
add_subdirectory(examples)
endif()
# Extensions
set(LIBICSNEO_SOURCE_DIR ${CMAKE_CURRENT_SOURCE_DIR})
foreach(EXT_PATH ${LIBICSNEO_EXTENSION_DIRS})
@@ -195,7 +193,6 @@ set(SRC_FILES
communication/message/tc10statusmessage.cpp
communication/message/gptpstatusmessage.cpp
communication/message/ethernetstatusmessage.cpp
communication/message/macsecmessage.cpp
communication/message/networkmutexmessage.cpp
communication/message/clientidmessage.cpp
communication/message/transmitmessage.cpp
@@ -226,8 +223,9 @@ set(SRC_FILES
communication/communication.cpp
communication/driver.cpp
communication/livedata.cpp
communication/ringbuffer.cpp
communication/crc32.cpp
core/ringbuffer.cpp
core/crc32.cpp
core/macseccfg.cpp
device/extensions/flexray/extension.cpp
device/extensions/flexray/controller.cpp
device/idevicesettings.cpp
@@ -289,6 +287,7 @@ endif()
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/icsneoc2/version.rc.template ${CMAKE_CURRENT_BINARY_DIR}/generated/icsneoc2/version.rc)
foreach(EXTINC ${LIBICSNEO_EXTENSION_INCLUDES})
message("Including " ${EXTINC})
@@ -360,7 +359,7 @@ if(LIBICSNEO_ENABLE_DXX)
include(FetchContent)
FetchContent_Declare(libredxx
GIT_REPOSITORY https://github.com/Zeranoe/libredxx.git
GIT_TAG e1fe2bd6ba6079b17037379d78f3f18024b389d7
GIT_TAG e823a96c39a64ab41b7d1632dbe8f86bb854df83
)
set(LIBREDXX_DISABLE_INSTALL ON)
FetchContent_MakeAvailable(libredxx)
@@ -392,7 +391,7 @@ endif()
include(FetchContent)
FetchContent_Declare(icspb
GIT_REPOSITORY ${LIBICSNEO_ICSPB_REPO}
GIT_TAG 2881dc4239319214dbf72fd3aa0427a4aefddd42
GIT_TAG 3339fa6b83a6b3e7704d41f5c2f2175cfc761a1f
)
FetchContent_MakeAvailable(icspb)
target_link_libraries(icsneocpp PRIVATE icspb::icspb)
@@ -426,6 +425,38 @@ if(LIBICSNEO_BUILD_ICSNEOC_STATIC)
target_compile_options(icsneoc-static PRIVATE ${LIBICSNEO_COMPILER_WARNINGS})
endif()
if(LIBICSNEO_BUILD_ICSNEOC2)
add_library(icsneoc2 SHARED api/icsneoc2/icsneoc2.cpp api/icsneoc2/icsneoc2settings.cpp api/icsneoc2/icsneoc2messages.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_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_options(icsneoc2 PRIVATE ${LIBICSNEO_COMPILER_WARNINGS})
if(WIN32)
set_target_properties(icsneoc2 PROPERTIES WINDOWS_EXPORT_ALL_SYMBOLS ON)
endif()
endif()
if(LIBICSNEO_BUILD_ICSNEOC2_STATIC)
add_library(icsneoc2-static STATIC api/icsneoc2/icsneoc2.cpp api/icsneoc2/icsneoc2settings.cpp api/icsneoc2/icsneoc2messages.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)
target_compile_options(icsneoc2-static PRIVATE ${LIBICSNEO_COMPILER_WARNINGS})
endif()
if(LIBICSNEO_BUILD_ICSNEOLEGACY)
add_library(icsneolegacy SHARED
api/icsneolegacy/icsneolegacy.cpp
@@ -467,6 +498,10 @@ endif()
add_subdirectory(bindings)
if(LIBICSNEO_BUILD_EXAMPLES)
add_subdirectory(examples)
endif()
# googletest
if(LIBICSNEO_BUILD_UNIT_TESTS)
include(FetchContent)
@@ -475,6 +510,7 @@ if(LIBICSNEO_BUILD_UNIT_TESTS)
GIT_TAG 6986c2b575f77135401a4e1c65a7a42f20e18fef
)
FetchContent_MakeAvailable(googletest)
include(GoogleTest)
add_executable(libicsneo-unit-tests
test/unit/main.cpp
@@ -489,6 +525,7 @@ if(LIBICSNEO_BUILD_UNIT_TESTS)
test/unit/livedataencoderdecodertest.cpp
test/unit/ringbuffertest.cpp
test/unit/apperrordecodertest.cpp
test/unit/icsneoc2.cpp
test/unit/windowsstrings.cpp
test/unit/periodictest.cpp
)
@@ -497,12 +534,13 @@ if(LIBICSNEO_BUILD_UNIT_TESTS)
target_link_libraries(libicsneo-unit-tests gtest gtest_main)
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})
enable_testing()
add_test(NAME libicsneo-unit-test-suite COMMAND libicsneo-unit-tests)
gtest_discover_tests(libicsneo-unit-tests TEST_PREFIX "unit/" PROPERTIES LABELS "unit")
endif()
set(CPACK_PROJECT_NAME ${PROJECT_NAME})
+1 -1
View File
@@ -1,4 +1,4 @@
Copyright (c) 2018-2025 Intrepid Control Systems, Inc.
Copyright (c) 2018-2026 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:
+11 -1
View File
@@ -4,11 +4,20 @@ 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.
## Installation
libicsneo relies on Servd, IntrepidCS's device communication server.
Servd can be installed for all platforms from https://cdn.intrepidcs.net/servd/.
Instructions for installing each API can be found in its respective documentation.
## Documentation
- [C++](https://libicsneo.readthedocs.io/en/latest/icsneocpp/)
- [Python](https://libicsneo.readthedocs.io/en/latest/icsneopy/)
- [C](https://libicsneo.readthedocs.io/en/latest/icsneoc/)
- [C](https://libicsneo.readthedocs.io/en/latest/icsneoc/) (deprecated, use C2)
- [C2](https://libicsneo.readthedocs.io/en/latest/icsneoc2/)
## Hardware Support
@@ -27,6 +36,7 @@ each of the respective APIs.
- RAD-EpsilonXL
- RAD-Galaxy
- RAD-Galaxy 2
- RAD-Gemini
- RAD-Gigastar
- RAD-Gigastar 2
- RAD-Moon 2
+1 -1
View File
@@ -29,7 +29,7 @@ BEGIN
VALUE "FileDescription", "Intrepid Control Systems Open Device Communication C API"
VALUE "FileVersion", VER_FILEVERSION_STR
VALUE "InternalName", "icsneoc.dll"
VALUE "LegalCopyright", "Intrepid Control Systems, Inc. (C) 2018-2025"
VALUE "LegalCopyright", "Intrepid Control Systems, Inc. (C) 2018-2026"
VALUE "OriginalFilename", "icsneoc.dll"
VALUE "ProductName", "libicsneo"
VALUE "ProductVersion", VER_PRODUCTVERSION_STR
File diff suppressed because it is too large Load Diff
+53
View File
@@ -0,0 +1,53 @@
// This header is for internal icsneoc2 use only, it should not be included by users of the API.
#pragma once
#include "icsneo/icsneoc2.h"
#include "icsneo/device/device.h"
#include "icsneo/communication/message/message.h"
#include "icsneo/communication/message/scriptstatusmessage.h"
#include "icsneo/api/event.h"
#include "icsneo/disk/diskdetails.h"
#include <memory>
#include <vector>
using namespace icsneo;
typedef struct icsneoc2_message_t {
std::shared_ptr<Message> message;
} icsneoc2_message_t;
typedef struct icsneoc2_event_t {
APIEvent event;
} icsneoc2_event_t;
typedef struct icsneoc2_device_info_t {
std::shared_ptr<Device> device;
icsneoc2_device_info_t* next;
} icsneoc2_device_info_t;
typedef struct icsneoc2_device_t {
std::shared_ptr<Device> device;
} icsneoc2_device_t;
typedef struct icsneoc2_disk_details_t {
std::shared_ptr<DiskDetails> details;
} icsneoc2_disk_details_t;
typedef struct icsneoc2_script_status_t {
std::shared_ptr<ScriptStatusMessage> status;
} icsneoc2_script_status_t;
/**
* Safely copies a std::string to a char array.
*
* @param dest The buffer to copy the string into
* @param dest_size* The size of the buffer. Will be modified to the length of the string without the null terminator.
* @param src The string to copy
*
* @return true if the string was successfully copied, false otherwise
*
* @note This function always null terminates the buffer, even if the string is too long.
* In the case of truncation, dest_size will reflect the truncated length (not including the null terminator).
*/
bool safe_str_copy(char* dest, size_t* dest_size, std::string_view src);
+617
View File
@@ -0,0 +1,617 @@
#include "icsneo/icsneoc2messages.h" // TODO: Remove this after the complete refactor
#include "icsneo/icsneoc2.h"
#include "icsneoc2_internal.h"
#include "icsneo/icsneocpp.h"
#include "icsneo/communication/message/message.h"
#include "icsneo/communication/message/canmessage.h"
#include "icsneo/communication/message/canerrormessage.h"
#include "icsneo/communication/message/linmessage.h"
#include "icsneo/communication/message/ethernetmessage.h"
#include "icsneo/communication/packet/canpacket.h"
icsneoc2_error_t icsneoc2_message_is_valid(icsneoc2_message_t* message, bool* is_valid) {
if(!message || !is_valid) {
return icsneoc2_error_invalid_parameters;
}
*is_valid = (bool)message->message;
return icsneoc2_error_success;
}
icsneoc2_error_t icsneoc2_message_is_transmit(icsneoc2_message_t* message, bool* value) {
if(!message || !value) {
return icsneoc2_error_invalid_parameters;
}
// We can static cast here because we are relying on the type being correct at this point
auto frame = std::dynamic_pointer_cast<Frame>(message->message);
if(!frame) {
return icsneoc2_error_invalid_type;
}
*value = frame->transmitted;
return icsneoc2_error_success;
}
icsneoc2_error_t icsneoc2_message_is_error(icsneoc2_message_t* message, bool* value) {
if(!message || !value) {
return icsneoc2_error_invalid_parameters;
}
auto frame = std::dynamic_pointer_cast<Frame>(message->message);
if(!frame) {
return icsneoc2_error_invalid_type;
}
*value = frame->error;
return icsneoc2_error_success;
}
icsneoc2_error_t icsneoc2_message_netid_get(icsneoc2_message_t* message, icsneoc2_netid_t* netid) {
if(!message || !netid) {
return icsneoc2_error_invalid_parameters;
}
auto raw = std::dynamic_pointer_cast<RawMessage>(message->message);
if(!raw) {
return icsneoc2_error_invalid_type;
}
*netid = static_cast<icsneoc2_netid_t>(raw->network.getNetID());
return icsneoc2_error_success;
}
icsneoc2_error_t icsneoc2_netid_name_get(icsneoc2_netid_t netid, char* value, size_t* value_length) {
if(!value || !value_length) {
return icsneoc2_error_invalid_parameters;
}
auto netid_str = std::string(Network::GetNetIDString(static_cast<Network::NetID>(netid), true));
// Copy the string into value
return safe_str_copy(value, value_length, netid_str) ? icsneoc2_error_success : icsneoc2_error_string_copy_failed;
}
icsneoc2_error_t icsneoc2_netid_network_type_get(icsneoc2_netid_t netid, icsneoc2_network_type_t* network_type) {
if(!network_type) {
return icsneoc2_error_invalid_parameters;
}
*network_type = static_cast<icsneoc2_network_type_t>(Network::GetTypeOfNetID(static_cast<Network::NetID>(netid), true));
return icsneoc2_error_success;
}
icsneoc2_error_t icsneoc2_message_netid_set(icsneoc2_message_t* message, icsneoc2_netid_t netid) {
if(!message) {
return icsneoc2_error_invalid_parameters;
}
auto raw = std::dynamic_pointer_cast<RawMessage>(message->message);
if(!raw) {
return icsneoc2_error_invalid_type;
}
raw->network = Network(static_cast<neonetid_t>(netid), true);
return icsneoc2_error_success;
}
icsneoc2_error_t icsneoc2_message_data_set(icsneoc2_message_t* message, uint8_t* data, size_t data_length) {
if(!message || !data) {
return icsneoc2_error_invalid_parameters;
}
// Make sure the message has the data field (RawMessage or Frame)
auto raw_message = std::dynamic_pointer_cast<RawMessage>(message->message);
if(!raw_message) {
return icsneoc2_error_invalid_type;
}
raw_message->data.resize(data_length);
std::copy(data, data + data_length, raw_message->data.begin());
return icsneoc2_error_success;
}
icsneoc2_error_t icsneoc2_message_data_get(icsneoc2_message_t* message, uint8_t* data, size_t* data_length) {
if(!message || !data_length) {
return icsneoc2_error_invalid_parameters;
}
// Make sure the message has the data field (RawMessage or Frame)
auto raw_message = std::dynamic_pointer_cast<RawMessage>(message->message);
if(!raw_message) {
return icsneoc2_error_invalid_type;
}
if(!data) {
*data_length = raw_message->data.size();
return icsneoc2_error_success;
}
if(*data_length < raw_message->data.size()) {
return icsneoc2_error_invalid_parameters;
}
std::copy(raw_message->data.begin(), raw_message->data.begin() + raw_message->data.size(), data);
*data_length = raw_message->data.size();
return icsneoc2_error_success;
}
icsneoc2_error_t icsneoc2_message_can_create(icsneoc2_message_t** message) {
if(!message) {
return icsneoc2_error_invalid_parameters;
}
try {
*message = new icsneoc2_message_t;
// Initialize the internal message as a CANMessage so that all icsneoc2_message_can_*_set
// functions work correctly on user-created transmit messages.
(*message)->message = std::make_shared<CANMessage>();
} catch(const std::bad_alloc&) {
return icsneoc2_error_out_of_memory;
}
return icsneoc2_error_success;
}
icsneoc2_error_t icsneoc2_message_free(icsneoc2_message_t* message) {
if(!message) {
return icsneoc2_error_invalid_parameters;
}
delete message;
return icsneoc2_error_success;
}
icsneoc2_error_t icsneoc2_message_can_props_set(icsneoc2_message_t* message, const uint64_t* arb_id, const uint64_t* flags) {
if(!message) {
return icsneoc2_error_invalid_parameters;
}
auto can_msg = std::dynamic_pointer_cast<CANMessage>(message->message);
if(!can_msg) {
return icsneoc2_error_invalid_type;
}
if(arb_id) {
can_msg->arbid = static_cast<uint32_t>(*arb_id);
}
if(flags) {
can_msg->isRemote = (*flags & ICSNEOC2_MESSAGE_CAN_FLAGS_RTR);
can_msg->isExtended = (*flags & ICSNEOC2_MESSAGE_CAN_FLAGS_IDE);
can_msg->isCANFD = (*flags & ICSNEOC2_MESSAGE_CAN_FLAGS_FDF);
can_msg->baudrateSwitch = (*flags & ICSNEOC2_MESSAGE_CAN_FLAGS_BRS);
can_msg->errorStateIndicator = (*flags & ICSNEOC2_MESSAGE_CAN_FLAGS_ESI);
}
return icsneoc2_error_success;
}
icsneoc2_error_t icsneoc2_message_can_props_get(icsneoc2_message_t* message, uint64_t* arb_id, uint64_t* flags) {
if(!message) {
return icsneoc2_error_invalid_parameters;
}
auto can_msg = std::dynamic_pointer_cast<CANMessage>(message->message);
if(!can_msg) {
return icsneoc2_error_invalid_type;
}
if(arb_id) {
*arb_id = can_msg->arbid;
}
if(flags) {
*flags = 0;
if(can_msg->isRemote) {
*flags |= ICSNEOC2_MESSAGE_CAN_FLAGS_RTR;
}
if(can_msg->isExtended) {
*flags |= ICSNEOC2_MESSAGE_CAN_FLAGS_IDE;
}
if(can_msg->isCANFD) {
*flags |= ICSNEOC2_MESSAGE_CAN_FLAGS_FDF;
}
if(can_msg->baudrateSwitch) {
*flags |= ICSNEOC2_MESSAGE_CAN_FLAGS_BRS;
}
if(can_msg->errorStateIndicator) {
*flags |= ICSNEOC2_MESSAGE_CAN_FLAGS_ESI;
}
if(can_msg->txAborted) {
*flags |= ICSNEOC2_MESSAGE_CAN_FLAGS_TX_ABORTED;
}
if(can_msg->txLostArb) {
*flags |= ICSNEOC2_MESSAGE_CAN_FLAGS_TX_LOST_ARB;
}
if(can_msg->txError) {
*flags |= ICSNEOC2_MESSAGE_CAN_FLAGS_TX_ERROR;
}
}
return icsneoc2_error_success;
}
icsneoc2_error_t icsneoc2_message_network_type_get(icsneoc2_message_t* message, icsneoc2_network_type_t* network_type) {
if(!message) {
return icsneoc2_error_invalid_parameters;
}
auto raw = std::dynamic_pointer_cast<RawMessage>(message->message);
if(!raw) {
return icsneoc2_error_invalid_type;
}
*network_type = (icsneoc2_network_type_t)raw->network.getType();
return icsneoc2_error_success;
}
icsneoc2_error_t icsneoc2_message_is_raw(icsneoc2_message_t* message, bool* is_raw) {
if(!message) {
return icsneoc2_error_invalid_parameters;
}
*is_raw = std::dynamic_pointer_cast<RawMessage>(message->message) != nullptr;
return icsneoc2_error_success;
}
icsneoc2_error_t icsneoc2_message_is_frame(icsneoc2_message_t* message, bool* is_frame) {
if(!message) {
return icsneoc2_error_invalid_parameters;
}
*is_frame = std::dynamic_pointer_cast<Frame>(message->message) != nullptr;
return icsneoc2_error_success;
}
icsneoc2_error_t icsneoc2_message_is_can(icsneoc2_message_t* message, bool* is_can) {
if(!message) {
return icsneoc2_error_invalid_parameters;
}
*is_can = std::dynamic_pointer_cast<CANMessage>(message->message) != nullptr;
return icsneoc2_error_success;
}
icsneoc2_error_t icsneoc2_message_is_can_error(icsneoc2_message_t* message, bool* is_can_error) {
if(!message || !is_can_error) {
return icsneoc2_error_invalid_parameters;
}
*is_can_error = std::dynamic_pointer_cast<CANErrorMessage>(message->message) != nullptr;
return icsneoc2_error_success;
}
icsneoc2_error_t icsneoc2_message_can_error_props_get(
icsneoc2_message_t *message, uint8_t *tx_err_count, uint8_t *rx_err_count,
icsneoc2_can_error_code_t *error_code,
icsneoc2_can_error_code_t *data_error_code,
icsneoc2_message_can_error_flags_t *flags) {
if(!message) {
return icsneoc2_error_invalid_parameters;
}
auto can_err = std::dynamic_pointer_cast<CANErrorMessage>(message->message);
if(!can_err) {
return icsneoc2_error_invalid_type;
}
if(tx_err_count) {
*tx_err_count = can_err->transmitErrorCount;
}
if(rx_err_count) {
*rx_err_count = can_err->receiveErrorCount;
}
if(error_code) {
*error_code = static_cast<icsneoc2_can_error_code_t>(can_err->errorCode);
}
if(data_error_code) {
*data_error_code = static_cast<icsneoc2_can_error_code_t>(can_err->dataErrorCode);
}
if(flags) {
*flags = 0;
if(can_err->busOff) {
*flags |= ICSNEOC2_MESSAGE_CAN_ERROR_FLAGS_BUS_OFF;
}
if(can_err->errorPassive) {
*flags |= ICSNEOC2_MESSAGE_CAN_ERROR_FLAGS_ERROR_PASSIVE;
}
if(can_err->errorWarn) {
*flags |= ICSNEOC2_MESSAGE_CAN_ERROR_FLAGS_ERROR_WARN;
}
}
return icsneoc2_error_success;
}
icsneoc2_error_t icsneoc2_message_is_lin(icsneoc2_message_t* message, bool* is_lin) {
if(!message || !is_lin) {
return icsneoc2_error_invalid_parameters;
}
*is_lin = std::dynamic_pointer_cast<LINMessage>(message->message) != nullptr;
return icsneoc2_error_success;
}
icsneoc2_error_t icsneoc2_message_lin_create(icsneoc2_message_t** message, uint8_t id) {
if(!message) {
return icsneoc2_error_invalid_parameters;
}
try {
*message = new icsneoc2_message_t;
(*message)->message = std::make_shared<LINMessage>(id);
} catch(const std::bad_alloc&) {
return icsneoc2_error_out_of_memory;
}
return icsneoc2_error_success;
}
icsneoc2_error_t icsneoc2_message_lin_props_get(const icsneoc2_message_t* message,
uint8_t* id, uint8_t* protected_id, uint8_t* checksum,
icsneoc2_lin_msg_type_t* msg_type, bool* is_enhanced_checksum) {
if(!message) {
return icsneoc2_error_invalid_parameters;
}
auto lin_msg = std::dynamic_pointer_cast<LINMessage>(message->message);
if(!lin_msg) {
return icsneoc2_error_invalid_type;
}
if(id) {
*id = lin_msg->ID;
}
if(protected_id) {
*protected_id = lin_msg->protectedID;
}
if(checksum) {
*checksum = lin_msg->checksum;
}
if(msg_type) {
*msg_type = static_cast<icsneoc2_lin_msg_type_t>(lin_msg->linMsgType);
}
if(is_enhanced_checksum) {
*is_enhanced_checksum = lin_msg->isEnhancedChecksum;
}
return icsneoc2_error_success;
}
icsneoc2_error_t icsneoc2_message_lin_props_set(icsneoc2_message_t* message,
const uint8_t* id, const uint8_t* checksum,
const icsneoc2_lin_msg_type_t* msg_type, const bool* is_enhanced_checksum) {
if(!message) {
return icsneoc2_error_invalid_parameters;
}
auto lin_msg = std::dynamic_pointer_cast<LINMessage>(message->message);
if(!lin_msg) {
return icsneoc2_error_invalid_type;
}
if(id) {
lin_msg->ID = *id & 0x3Fu;
lin_msg->protectedID = lin_msg->calcProtectedID(lin_msg->ID);
}
if(checksum) {
lin_msg->checksum = *checksum;
}
if(msg_type) {
lin_msg->linMsgType = static_cast<LINMessage::Type>(*msg_type);
}
if(is_enhanced_checksum) {
lin_msg->isEnhancedChecksum = *is_enhanced_checksum;
}
return icsneoc2_error_success;
}
icsneoc2_error_t icsneoc2_message_lin_err_flags_get(const icsneoc2_message_t* message, icsneoc2_lin_err_flags_t* err_flags) {
if(!message || !err_flags) {
return icsneoc2_error_invalid_parameters;
}
auto lin_msg = std::dynamic_pointer_cast<LINMessage>(message->message);
if(!lin_msg) {
return icsneoc2_error_invalid_type;
}
*err_flags = 0;
if(lin_msg->errFlags.ErrRxBreakOnly) *err_flags |= ICSNEOC2_LIN_ERR_RX_BREAK_ONLY;
if(lin_msg->errFlags.ErrRxBreakSyncOnly) *err_flags |= ICSNEOC2_LIN_ERR_RX_BREAK_SYNC_ONLY;
if(lin_msg->errFlags.ErrTxRxMismatch) *err_flags |= ICSNEOC2_LIN_ERR_TX_RX_MISMATCH;
if(lin_msg->errFlags.ErrRxBreakNotZero) *err_flags |= ICSNEOC2_LIN_ERR_RX_BREAK_NOT_ZERO;
if(lin_msg->errFlags.ErrRxBreakTooShort) *err_flags |= ICSNEOC2_LIN_ERR_RX_BREAK_TOO_SHORT;
if(lin_msg->errFlags.ErrRxSyncNot55) *err_flags |= ICSNEOC2_LIN_ERR_RX_SYNC_NOT_55;
if(lin_msg->errFlags.ErrRxDataLenOver8) *err_flags |= ICSNEOC2_LIN_ERR_RX_DATA_LEN_OVER_8;
if(lin_msg->errFlags.ErrFrameSync) *err_flags |= ICSNEOC2_LIN_ERR_FRAME_SYNC;
if(lin_msg->errFlags.ErrFrameMessageID) *err_flags |= ICSNEOC2_LIN_ERR_FRAME_MESSAGE_ID;
if(lin_msg->errFlags.ErrFrameResponderData) *err_flags |= ICSNEOC2_LIN_ERR_FRAME_RESPONDER_DATA;
if(lin_msg->errFlags.ErrChecksumMatch) *err_flags |= ICSNEOC2_LIN_ERR_CHECKSUM_MATCH;
return icsneoc2_error_success;
}
icsneoc2_error_t icsneoc2_message_lin_status_flags_get(const icsneoc2_message_t* message, icsneoc2_lin_status_flags_t* status_flags) {
if(!message || !status_flags) {
return icsneoc2_error_invalid_parameters;
}
auto lin_msg = std::dynamic_pointer_cast<LINMessage>(message->message);
if(!lin_msg) {
return icsneoc2_error_invalid_type;
}
*status_flags = 0;
if(lin_msg->statusFlags.TxChecksumEnhanced) *status_flags |= ICSNEOC2_LIN_STATUS_TX_CHECKSUM_ENHANCED;
if(lin_msg->statusFlags.TxCommander) *status_flags |= ICSNEOC2_LIN_STATUS_TX_COMMANDER;
if(lin_msg->statusFlags.TxResponder) *status_flags |= ICSNEOC2_LIN_STATUS_TX_RESPONDER;
if(lin_msg->statusFlags.TxAborted) *status_flags |= ICSNEOC2_LIN_STATUS_TX_ABORTED;
if(lin_msg->statusFlags.UpdateResponderOnce) *status_flags |= ICSNEOC2_LIN_STATUS_UPDATE_RESPONDER_ONCE;
if(lin_msg->statusFlags.HasUpdatedResponderOnce) *status_flags |= ICSNEOC2_LIN_STATUS_HAS_UPDATED_RESPONDER_ONCE;
if(lin_msg->statusFlags.BusRecovered) *status_flags |= ICSNEOC2_LIN_STATUS_BUS_RECOVERED;
if(lin_msg->statusFlags.BreakOnly) *status_flags |= ICSNEOC2_LIN_STATUS_BREAK_ONLY;
return icsneoc2_error_success;
}
icsneoc2_error_t icsneoc2_message_lin_calc_checksum(icsneoc2_message_t* message) {
if(!message) {
return icsneoc2_error_invalid_parameters;
}
auto lin_msg = std::dynamic_pointer_cast<LINMessage>(message->message);
if(!lin_msg) {
return icsneoc2_error_invalid_type;
}
LINMessage::calcChecksum(*lin_msg);
return icsneoc2_error_success;
}
icsneoc2_error_t icsneoc2_message_eth_create(icsneoc2_message_t** message) {
if(!message) {
return icsneoc2_error_invalid_parameters;
}
try {
*message = new icsneoc2_message_t;
(*message)->message = std::make_shared<EthernetMessage>();
} catch(const std::bad_alloc&) {
return icsneoc2_error_out_of_memory;
}
return icsneoc2_error_success;
}
icsneoc2_error_t icsneoc2_message_eth_props_set(icsneoc2_message_t* message, const icsneoc2_message_eth_flags_t* flags, const bool* has_fcs, const uint32_t* fcs) {
if(!message) {
return icsneoc2_error_invalid_parameters;
}
auto eth_msg = std::dynamic_pointer_cast<EthernetMessage>(message->message);
if(!eth_msg) {
return icsneoc2_error_invalid_type;
}
if(flags) {
eth_msg->frameTooShort = (*flags & ICSNEOC2_MESSAGE_ETH_FLAGS_FRAME_TOO_SHORT);
eth_msg->noPadding = (*flags & ICSNEOC2_MESSAGE_ETH_FLAGS_NO_PADDING);
eth_msg->fcsVerified = (*flags & ICSNEOC2_MESSAGE_ETH_FLAGS_FCS_VERIFIED);
eth_msg->txAborted = (*flags & ICSNEOC2_MESSAGE_ETH_FLAGS_TX_ABORTED);
eth_msg->crcError = (*flags & ICSNEOC2_MESSAGE_ETH_FLAGS_CRC_ERROR);
}
if(has_fcs && !*has_fcs) {
eth_msg->fcs = std::nullopt;
} else if(has_fcs && *has_fcs) {
// I'm pretty sure we can leave this alone, setting fcs below will take care of the behavior,
// otherwise we get into a weird state where we have to set fcs to zero if fcs is null but has_fcs is true.
}
if (fcs) {
eth_msg->fcs = *fcs;
}
return icsneoc2_error_success;
}
icsneoc2_error_t icsneoc2_message_eth_props_get(icsneoc2_message_t* message, icsneoc2_message_eth_flags_t* flags, bool* has_fcs, uint32_t* fcs) {
if(!message) {
return icsneoc2_error_invalid_parameters;
}
auto eth_msg = std::dynamic_pointer_cast<EthernetMessage>(message->message);
if(!eth_msg) {
return icsneoc2_error_invalid_type;
}
if(flags) {
*flags = 0;
if(eth_msg->noPadding)
*flags |= ICSNEOC2_MESSAGE_ETH_FLAGS_NO_PADDING;
if(eth_msg->fcsVerified)
*flags |= ICSNEOC2_MESSAGE_ETH_FLAGS_FCS_VERIFIED;
if(eth_msg->txAborted)
*flags |= ICSNEOC2_MESSAGE_ETH_FLAGS_TX_ABORTED;
if(eth_msg->crcError)
*flags |= ICSNEOC2_MESSAGE_ETH_FLAGS_CRC_ERROR;
if(eth_msg->frameTooShort)
*flags |= ICSNEOC2_MESSAGE_ETH_FLAGS_FRAME_TOO_SHORT;
}
if(has_fcs) {
*has_fcs = eth_msg->fcs.has_value();
}
if(fcs) {
if(eth_msg->fcs) {
*fcs = eth_msg->fcs.value();
} else {
*fcs = 0;
}
}
return icsneoc2_error_success;
}
icsneoc2_error_t icsneoc2_message_eth_mac_get(icsneoc2_message_t* message, uint8_t* dst_mac, uint8_t* src_mac) {
if(!message) {
return icsneoc2_error_invalid_parameters;
}
auto eth_msg = std::dynamic_pointer_cast<EthernetMessage>(message->message);
if(!eth_msg) {
return icsneoc2_error_invalid_type;
}
if(dst_mac) {
if(auto mac = eth_msg->getDestinationMAC(); mac.has_value()) {
const auto& mac_value = mac.value();
std::memcpy(dst_mac, mac_value.data(), mac_value.size());
} else {
return icsneoc2_error_invalid_data;
}
}
if(src_mac) {
if(auto mac = eth_msg->getSourceMAC(); mac.has_value()) {
const auto& mac_value = mac.value();
std::memcpy(src_mac, mac_value.data(), mac_value.size());
} else {
return icsneoc2_error_invalid_data;
}
}
return icsneoc2_error_success;
}
icsneoc2_error_t icsneoc2_message_eth_ether_type_get(icsneoc2_message_t* message, uint16_t* ether_type) {
if(!message || !ether_type) {
return icsneoc2_error_invalid_parameters;
}
auto eth_msg = std::dynamic_pointer_cast<EthernetMessage>(message->message);
if(!eth_msg) {
return icsneoc2_error_invalid_type;
}
if (auto et = eth_msg->getEtherType(); et.has_value()) {
*ether_type = et.value();
} else {
return icsneoc2_error_invalid_data;
}
return icsneoc2_error_success;
}
icsneoc2_error_t icsneoc2_message_eth_t1s_props_set(icsneoc2_message_t* message, const icsneoc2_message_eth_t1s_flags_t* flags, const uint8_t* node_id, const uint8_t* burst_count, const uint8_t* symbol_type) {
if(!message) {
return icsneoc2_error_invalid_parameters;
}
auto eth_msg = std::dynamic_pointer_cast<EthernetMessage>(message->message);
if(!eth_msg) {
return icsneoc2_error_invalid_type;
}
// If all parameters are null/zero, clear the T1S state. Otherwise, if any parameters are set and we don't have a T1S state, create it.
if(!flags && !node_id && !burst_count && !symbol_type) {
eth_msg->t1s = std::nullopt;
return icsneoc2_error_success;
}
if((flags || node_id || burst_count || symbol_type) && !eth_msg->t1s.has_value()) {
eth_msg->t1s.emplace();
}
if(flags) {
eth_msg->t1s->isSymbol = (*flags & ICSNEOC2_MESSAGE_ETH_T1S_FLAGS_IS_T1S_SYMBOL);
eth_msg->t1s->isBurst = (*flags & ICSNEOC2_MESSAGE_ETH_T1S_FLAGS_IS_T1S_BURST);
eth_msg->t1s->txCollision = (*flags & ICSNEOC2_MESSAGE_ETH_T1S_FLAGS_TX_COLLISION);
eth_msg->t1s->isWake = (*flags & ICSNEOC2_MESSAGE_ETH_T1S_FLAGS_IS_T1S_WAKE);
}
if(node_id) {
eth_msg->t1s->nodeId = *node_id;
}
if(burst_count) {
eth_msg->t1s->burstCount = *burst_count;
}
if(symbol_type) {
eth_msg->t1s->symbolType = *symbol_type;
}
return icsneoc2_error_success;
}
icsneoc2_error_t icsneoc2_message_eth_t1s_props_get(icsneoc2_message_t* message, icsneoc2_message_eth_t1s_flags_t* flags, uint8_t* node_id, uint8_t* burst_count, uint8_t* symbol_type) {
if(!message) {
return icsneoc2_error_invalid_parameters;
}
auto eth_msg = std::dynamic_pointer_cast<EthernetMessage>(message->message);
if(!eth_msg) {
return icsneoc2_error_invalid_type;
}
if(flags) {
*flags = 0;
if(eth_msg->t1s.has_value()) {
if(eth_msg->t1s->isSymbol)
*flags |= ICSNEOC2_MESSAGE_ETH_T1S_FLAGS_IS_T1S_SYMBOL;
if(eth_msg->t1s->isBurst)
*flags |= ICSNEOC2_MESSAGE_ETH_T1S_FLAGS_IS_T1S_BURST;
if(eth_msg->t1s->txCollision)
*flags |= ICSNEOC2_MESSAGE_ETH_T1S_FLAGS_TX_COLLISION;
if(eth_msg->t1s->isWake)
*flags |= ICSNEOC2_MESSAGE_ETH_T1S_FLAGS_IS_T1S_WAKE;
}
}
if(node_id) {
*node_id = eth_msg->t1s.has_value() ? eth_msg->t1s->nodeId : 0;
}
if(burst_count) {
*burst_count = eth_msg->t1s.has_value() ? eth_msg->t1s->burstCount : 0;
}
if(symbol_type) {
*symbol_type = eth_msg->t1s.has_value() ? eth_msg->t1s->symbolType : 0;
}
return icsneoc2_error_success;
}
icsneoc2_error_t icsneoc2_message_is_ethernet(icsneoc2_message_t* message, bool* is_ethernet) {
if(!message) {
return icsneoc2_error_invalid_parameters;
}
*is_ethernet = std::dynamic_pointer_cast<EthernetMessage>(message->message) != nullptr;
return icsneoc2_error_success;
}
+894
View File
@@ -0,0 +1,894 @@
#include "icsneo/icsneoc2.h"
#include "icsneo/icsneoc2settings.h"
#include "icsneo/device/device.h"
#include "icsneo/device/devicefinder.h"
#include "icsneo/icsneocpp.h"
#include "icsneo/communication/message/message.h"
#include "icsneo/communication/message/canmessage.h"
#include "icsneo/communication/message/linmessage.h"
#include "icsneo/communication/message/ethernetmessage.h"
#include "icsneo/communication/packet/canpacket.h"
#include "icsneo/communication/io.h"
#include <string>
#include <vector>
#include <list>
#include <map>
#include <algorithm>
#include <optional>
#include <sstream>
using namespace icsneo;
#include "icsneoc2_internal.h"
icsneoc2_error_t icsneoc2_settings_apply_defaults(icsneoc2_device_t* device, bool save) {
// Make sure the device is valid
auto res = icsneoc2_device_is_valid(device);
if(res != icsneoc2_error_success) {
return res;
}
if(!device->device->settings->applyDefaults(!save)) {
return icsneoc2_error_set_settings_failure;
}
return icsneoc2_error_success;
}
icsneoc2_error_t icsneoc2_settings_apply(icsneoc2_device_t* device) {
// Make sure the device is valid
auto res = icsneoc2_device_is_valid(device);
if(res != icsneoc2_error_success) {
return res;
}
if(!device->device->settings->apply()) {
return icsneoc2_error_set_settings_failure;
}
return icsneoc2_error_success;
}
icsneoc2_error_t icsneoc2_settings_refresh(icsneoc2_device_t* device) {
// Make sure the device is valid
auto res = icsneoc2_device_is_valid(device);
if(res != icsneoc2_error_success) {
return res;
}
if(!device->device->settings->refresh()) {
return icsneoc2_error_get_settings_failure;
}
return icsneoc2_error_success;
}
icsneoc2_error_t icsneoc2_settings_baudrate_get(icsneoc2_device_t* device, icsneoc2_netid_t netid, int64_t* baudrate) {
if(!baudrate) {
return icsneoc2_error_invalid_parameters;
}
// Make sure the device is valid
auto res = icsneoc2_device_is_valid(device);
if(res != icsneoc2_error_success) {
return res;
}
auto baudrate_value = device->device->settings->getBaudrateFor(Network(netid));
if(baudrate_value < 0) {
*baudrate = 0;
return icsneoc2_error_invalid_type;
}
*baudrate = baudrate_value;
return icsneoc2_error_success;
}
icsneoc2_error_t icsneoc2_settings_baudrate_set(icsneoc2_device_t* device, icsneoc2_netid_t netid, int64_t baudrate) {
// Make sure the device is valid
auto res = icsneoc2_device_is_valid(device);
if(res != icsneoc2_error_success) {
return res;
}
if(!device->device->settings->setBaudrateFor(Network(netid), baudrate)) {
return icsneoc2_error_set_settings_failure;
}
return icsneoc2_error_success;
}
icsneoc2_error_t icsneoc2_settings_canfd_baudrate_get(icsneoc2_device_t* device, icsneoc2_netid_t netid, int64_t* baudrate) {
if(!baudrate) {
return icsneoc2_error_invalid_parameters;
}
// Make sure the device is valid
auto res = icsneoc2_device_is_valid(device);
if(res != icsneoc2_error_success) {
return res;
}
*baudrate = device->device->settings->getFDBaudrateFor(Network(netid));
if(*baudrate < 0) {
*baudrate = 0;
return icsneoc2_error_invalid_type;
}
return icsneoc2_error_success;
}
icsneoc2_error_t icsneoc2_settings_canfd_baudrate_set(icsneoc2_device_t* device, icsneoc2_netid_t netid, int64_t baudrate) {
// Make sure the device is valid
auto res = icsneoc2_device_is_valid(device);
if(res != icsneoc2_error_success) {
return res;
}
if(!device->device->settings->setFDBaudrateFor(Network(netid), baudrate)) {
return icsneoc2_error_set_settings_failure;
}
return icsneoc2_error_success;
}
icsneoc2_error_t icsneoc2_settings_termination_is_supported(icsneoc2_device_t* device, icsneoc2_netid_t netid, bool* supported) {
// Make sure the device is valid
auto res = icsneoc2_device_is_valid(device);
if(res != icsneoc2_error_success) {
return res;
}
if(!supported) {
return icsneoc2_error_invalid_parameters;
}
*supported = device->device->settings->isTerminationSupportedFor(Network(static_cast<Network::NetID>(netid)));
return icsneoc2_error_success;
}
icsneoc2_error_t icsneoc2_settings_termination_can_enable(icsneoc2_device_t* device, icsneoc2_netid_t netid, bool* can_enable) {
// Make sure the device is valid
auto res = icsneoc2_device_is_valid(device);
if(res != icsneoc2_error_success) {
return res;
}
if(!can_enable) {
return icsneoc2_error_invalid_parameters;
}
*can_enable = device->device->settings->canTerminationBeEnabledFor(Network(static_cast<Network::NetID>(netid)));
return icsneoc2_error_success;
}
icsneoc2_error_t icsneoc2_settings_termination_is_enabled(icsneoc2_device_t* device, icsneoc2_netid_t netid, bool* enabled) {
// Make sure the device is valid
auto res = icsneoc2_device_is_valid(device);
if(res != icsneoc2_error_success) {
return res;
}
if(!enabled) {
return icsneoc2_error_invalid_parameters;
}
*enabled = device->device->settings->isTerminationEnabledFor(Network(static_cast<Network::NetID>(netid))).value_or(false);
return icsneoc2_error_success;
}
icsneoc2_error_t icsneoc2_settings_termination_set(icsneoc2_device_t* device, icsneoc2_netid_t netid, bool enable) {
// Make sure the device is valid
auto res = icsneoc2_device_is_valid(device);
if(res != icsneoc2_error_success) {
return res;
}
if(!device->device->settings->setTerminationFor(Network(static_cast<Network::NetID>(netid)), enable)) {
return icsneoc2_error_set_settings_failure;
}
return icsneoc2_error_success;
}
icsneoc2_error_t icsneoc2_settings_commander_resistor_enabled(icsneoc2_device_t* device, icsneoc2_netid_t netid, bool* enabled) {
// Make sure the device is valid
auto res = icsneoc2_device_is_valid(device);
if(res != icsneoc2_error_success) {
return res;
}
if(!enabled) {
return icsneoc2_error_invalid_parameters;
}
*enabled = device->device->settings->isCommanderResistorEnabledFor(Network(static_cast<Network::NetID>(netid))).value_or(false);
return icsneoc2_error_success;
}
icsneoc2_error_t icsneoc2_settings_commander_resistor_set(icsneoc2_device_t* device, icsneoc2_netid_t netid, bool enable) {
// Make sure the device is valid
auto res = icsneoc2_device_is_valid(device);
if(res != icsneoc2_error_success) {
return res;
}
if(!device->device->settings->setCommanderResistorFor(Network(static_cast<Network::NetID>(netid)), enable)) {
return icsneoc2_error_set_settings_failure;
}
return icsneoc2_error_success;
}
icsneoc2_error_t icsneoc2_settings_lin_mode_get(icsneoc2_device_t* device, icsneoc2_netid_t netid, icsneoc2_lin_mode_t* value) {
// Make sure the device is valid
auto res = icsneoc2_device_is_valid(device);
if(res != icsneoc2_error_success) {
return res;
}
if(!value) {
return icsneoc2_error_invalid_parameters;
}
auto network = Network(static_cast<Network::NetID>(netid));
if(auto result = device->device->settings->getLINModeFor(network); result.has_value()) {
*value = static_cast<icsneoc2_lin_mode_t>(result.value());
return icsneoc2_error_success;
} else {
*value = 0;
return icsneoc2_error_get_settings_failure;
}
}
icsneoc2_error_t icsneoc2_settings_lin_mode_set(icsneoc2_device_t* device, icsneoc2_netid_t netid, icsneoc2_lin_mode_t value) {
// Make sure the device is valid
auto res = icsneoc2_device_is_valid(device);
if(res != icsneoc2_error_success) {
return res;
}
auto network = Network(static_cast<Network::NetID>(netid));
if(!device->device->settings->setLINModeFor(network, static_cast<LINMode>(value))) {
return icsneoc2_error_set_settings_failure;
}
return icsneoc2_error_success;
}
icsneoc2_error_t icsneoc2_settings_lin_commander_response_time_get(icsneoc2_device_t* device, icsneoc2_netid_t netid, uint8_t* value) {
// Make sure the device is valid
auto res = icsneoc2_device_is_valid(device);
if(res != icsneoc2_error_success) {
return res;
}
if(!value) {
return icsneoc2_error_invalid_parameters;
}
auto network = Network(static_cast<Network::NetID>(netid));
if(auto result = device->device->settings->getLINCommanderResponseTimeFor(network); result.has_value()) {
*value = result.value();
return icsneoc2_error_success;
} else {
*value = 0;
return icsneoc2_error_get_settings_failure;
}
}
icsneoc2_error_t icsneoc2_settings_lin_commander_response_time_set(icsneoc2_device_t* device, icsneoc2_netid_t netid, uint8_t value) {
// Make sure the device is valid
auto res = icsneoc2_device_is_valid(device);
if(res != icsneoc2_error_success) {
return res;
}
auto network = Network(static_cast<Network::NetID>(netid));
if(!device->device->settings->setLINCommanderResponseTimeFor(network, value)) {
return icsneoc2_error_set_settings_failure;
}
return icsneoc2_error_success;
}
icsneoc2_error_t icsneoc2_settings_phy_enable_get(icsneoc2_device_t* device, uint8_t index, bool* value) {
// Make sure the device is valid
auto res = icsneoc2_device_is_valid(device);
if(res != icsneoc2_error_success) {
return res;
}
if(!value) {
return icsneoc2_error_invalid_parameters;
}
if(auto result = device->device->settings->getPhyEnable(index); result.has_value()) {
*value = result.value();
return icsneoc2_error_success;
} else {
*value = false;
return icsneoc2_error_get_settings_failure;
}
}
icsneoc2_error_t icsneoc2_settings_phy_enable_set(icsneoc2_device_t* device, uint8_t index, bool value) {
// Make sure the device is valid
auto res = icsneoc2_device_is_valid(device);
if(res != icsneoc2_error_success) {
return res;
}
if(!device->device->settings->setPhyEnable(index, value)) {
return icsneoc2_error_set_settings_failure;
}
return icsneoc2_error_success;
}
icsneoc2_error_t icsneoc2_settings_phy_mode_get(icsneoc2_device_t* device, uint8_t index, icsneoc2_ae_link_mode_t* value) {
// Make sure the device is valid
auto res = icsneoc2_device_is_valid(device);
if(res != icsneoc2_error_success) {
return res;
}
if(!value) {
return icsneoc2_error_invalid_parameters;
}
if(auto result = device->device->settings->getPhyMode(index); result.has_value()) {
*value = static_cast<icsneoc2_ae_link_mode_t>(result.value());
return icsneoc2_error_success;
} else {
*value = 0;
return icsneoc2_error_get_settings_failure;
}
}
icsneoc2_error_t icsneoc2_settings_phy_mode_set(icsneoc2_device_t* device, uint8_t index, icsneoc2_ae_link_mode_t value) {
// Make sure the device is valid
auto res = icsneoc2_device_is_valid(device);
if(res != icsneoc2_error_success) {
return res;
}
if(!device->device->settings->setPhyMode(index, static_cast<AELinkMode>(value))) {
return icsneoc2_error_set_settings_failure;
}
return icsneoc2_error_success;
}
icsneoc2_error_t icsneoc2_settings_phy_speed_get(icsneoc2_device_t* device, uint8_t index, icsneoc2_eth_phy_link_mode_t* value) {
// Make sure the device is valid
auto res = icsneoc2_device_is_valid(device);
if(res != icsneoc2_error_success) {
return res;
}
if(!value) {
return icsneoc2_error_invalid_parameters;
}
if(auto result = device->device->settings->getPhySpeed(index); result.has_value()) {
*value = static_cast<icsneoc2_eth_phy_link_mode_t>(result.value());
return icsneoc2_error_success;
} else {
*value = 0;
return icsneoc2_error_get_settings_failure;
}
}
icsneoc2_error_t icsneoc2_settings_phy_speed_set(icsneoc2_device_t* device, uint8_t index, icsneoc2_eth_phy_link_mode_t value) {
// Make sure the device is valid
auto res = icsneoc2_device_is_valid(device);
if(res != icsneoc2_error_success) {
return res;
}
if(!device->device->settings->setPhySpeed(index, static_cast<EthPhyLinkMode>(value))) {
return icsneoc2_error_set_settings_failure;
}
return icsneoc2_error_success;
}
icsneoc2_error_t icsneoc2_settings_phy_role_for_get(icsneoc2_device_t* device, icsneoc2_netid_t netid, icsneoc2_ae_link_mode_t* value) {
// Make sure the device is valid
auto res = icsneoc2_device_is_valid(device);
if(res != icsneoc2_error_success) {
return res;
}
if(!value) {
return icsneoc2_error_invalid_parameters;
}
auto network = Network(static_cast<Network::NetID>(netid));
if(auto result = device->device->settings->getPhyRoleFor(network); result.has_value()) {
*value = static_cast<icsneoc2_ae_link_mode_t>(result.value());
return icsneoc2_error_success;
} else {
*value = 0;
return icsneoc2_error_get_settings_failure;
}
}
icsneoc2_error_t icsneoc2_settings_phy_role_for_set(icsneoc2_device_t* device, icsneoc2_netid_t netid, icsneoc2_ae_link_mode_t value) {
// Make sure the device is valid
auto res = icsneoc2_device_is_valid(device);
if(res != icsneoc2_error_success) {
return res;
}
auto network = Network(static_cast<Network::NetID>(netid));
if(!device->device->settings->setPhyRoleFor(network, static_cast<AELinkMode>(value))) {
return icsneoc2_error_set_settings_failure;
}
return icsneoc2_error_success;
}
icsneoc2_error_t icsneoc2_settings_phy_link_mode_for_get(icsneoc2_device_t* device, icsneoc2_netid_t netid, icsneoc2_eth_phy_link_mode_t* value) {
// Make sure the device is valid
auto res = icsneoc2_device_is_valid(device);
if(res != icsneoc2_error_success) {
return res;
}
if(!value) {
return icsneoc2_error_invalid_parameters;
}
auto network = Network(static_cast<Network::NetID>(netid));
if(auto result = device->device->settings->getPhyLinkModeFor(network); result.has_value()) {
*value = static_cast<icsneoc2_eth_phy_link_mode_t>(result.value());
return icsneoc2_error_success;
} else {
*value = 0;
return icsneoc2_error_get_settings_failure;
}
}
icsneoc2_error_t icsneoc2_settings_phy_link_mode_for_set(icsneoc2_device_t* device, icsneoc2_netid_t netid, icsneoc2_eth_phy_link_mode_t value) {
// Make sure the device is valid
auto res = icsneoc2_device_is_valid(device);
if(res != icsneoc2_error_success) {
return res;
}
auto network = Network(static_cast<Network::NetID>(netid));
if(!device->device->settings->setPhyLinkModeFor(network, static_cast<EthPhyLinkMode>(value))) {
return icsneoc2_error_set_settings_failure;
}
return icsneoc2_error_success;
}
icsneoc2_error_t icsneoc2_settings_phy_enable_for_get(icsneoc2_device_t* device, icsneoc2_netid_t netid, bool* value) {
// Make sure the device is valid
auto res = icsneoc2_device_is_valid(device);
if(res != icsneoc2_error_success) {
return res;
}
if(!value) {
return icsneoc2_error_invalid_parameters;
}
auto network = Network(static_cast<Network::NetID>(netid));
if(auto result = device->device->settings->getPhyEnableFor(network); result.has_value()) {
*value = result.value();
return icsneoc2_error_success;
} else {
*value = false;
return icsneoc2_error_get_settings_failure;
}
}
icsneoc2_error_t icsneoc2_settings_phy_enable_for_set(icsneoc2_device_t* device, icsneoc2_netid_t netid, bool value) {
// Make sure the device is valid
auto res = icsneoc2_device_is_valid(device);
if(res != icsneoc2_error_success) {
return res;
}
auto network = Network(static_cast<Network::NetID>(netid));
if(!device->device->settings->setPhyEnableFor(network, value)) {
return icsneoc2_error_set_settings_failure;
}
return icsneoc2_error_success;
}
icsneoc2_error_t icsneoc2_settings_supported_phy_link_modes_for(icsneoc2_device_t* device, icsneoc2_netid_t netid, icsneoc2_eth_phy_link_mode_t** link_modes, size_t* link_modes_count) {
// Make sure the device is valid
auto res = icsneoc2_device_is_valid(device);
if(res != icsneoc2_error_success) {
return res;
}
if(!link_modes || !link_modes_count) {
return icsneoc2_error_invalid_parameters;
}
auto network = Network(static_cast<Network::NetID>(netid));
auto modes = device->device->settings->getSupportedPhyLinkModesFor(network);
*link_modes_count = std::minmax(modes.size(), *link_modes_count).first;
memcpy(*link_modes, modes.data(), *link_modes_count * sizeof(icsneoc2_eth_phy_link_mode_t));
return icsneoc2_error_success;
}
icsneoc2_error_t icsneoc2_settings_t1s_is_plca_enabled_for(icsneoc2_device_t* device, icsneoc2_netid_t netid, bool* value) {
// Make sure the device is valid
auto res = icsneoc2_device_is_valid(device);
if(res != icsneoc2_error_success) {
return res;
}
if(!value) {
return icsneoc2_error_invalid_parameters;
}
auto network = Network(static_cast<Network::NetID>(netid));
if(auto result = device->device->settings->isT1SPLCAEnabledFor(network); result.has_value()) {
*value = result.value();
return icsneoc2_error_success;
} else {
*value = false;
return icsneoc2_error_get_settings_failure;
}
}
icsneoc2_error_t icsneoc2_settings_t1s_plca_enabled_for_set(icsneoc2_device_t* device, icsneoc2_netid_t netid, bool value) {
// Make sure the device is valid
auto res = icsneoc2_device_is_valid(device);
if(res != icsneoc2_error_success) {
return res;
}
auto network = Network(static_cast<Network::NetID>(netid));
if(!device->device->settings->setT1SPLCAFor(network, value)) {
return icsneoc2_error_set_settings_failure;
}
return icsneoc2_error_success;
}
icsneoc2_error_t icsneoc2_settings_t1s_local_id_get(icsneoc2_device_t* device, icsneoc2_netid_t netid, uint8_t* value){
// Make sure the device is valid
auto res = icsneoc2_device_is_valid(device);
if(res != icsneoc2_error_success) {
return res;
}
if(!value) {
return icsneoc2_error_invalid_parameters;
}
auto network = Network(static_cast<Network::NetID>(netid));
if(auto result = device->device->settings->getT1SLocalIDFor(network); result.has_value()) {
*value = result.value();
return icsneoc2_error_success;
} else {
*value = 0;
return icsneoc2_error_get_settings_failure;
}
}
icsneoc2_error_t icsneoc2_settings_t1s_local_id_set(icsneoc2_device_t* device, icsneoc2_netid_t netid, uint8_t value){
// Make sure the device is valid
auto res = icsneoc2_device_is_valid(device);
if(res != icsneoc2_error_success) {
return res;
}
auto network = Network(static_cast<Network::NetID>(netid));
if(!device->device->settings->setT1SLocalIDFor(network, value)) {
return icsneoc2_error_set_settings_failure;
}
return icsneoc2_error_success;
}
icsneoc2_error_t icsneoc2_settings_t1s_max_nodes_get(icsneoc2_device_t* device, icsneoc2_netid_t netid, uint8_t* value) {
// Make sure the device is valid
auto res = icsneoc2_device_is_valid(device);
if(res != icsneoc2_error_success) {
return res;
}
if(!value) {
return icsneoc2_error_invalid_parameters;
}
auto network = Network(static_cast<Network::NetID>(netid));
if(auto result = device->device->settings->getT1SMaxNodesFor(network); result.has_value()) {
*value = result.value();
return icsneoc2_error_success;
} else {
*value = 0;
return icsneoc2_error_get_settings_failure;
}
}
icsneoc2_error_t icsneoc2_settings_t1s_max_nodes_set(icsneoc2_device_t* device, icsneoc2_netid_t netid, uint8_t value) {
// Make sure the device is valid
auto res = icsneoc2_device_is_valid(device);
if(res != icsneoc2_error_success) {
return res;
}
auto network = Network(static_cast<Network::NetID>(netid));
if(!device->device->settings->setT1SMaxNodesFor(network, value)) {
return icsneoc2_error_set_settings_failure;
}
return icsneoc2_error_success;
}
icsneoc2_error_t icsneoc2_settings_t1s_tx_opp_timer_get(icsneoc2_device_t* device, icsneoc2_netid_t netid, uint8_t* value) {
// Make sure the device is valid
auto res = icsneoc2_device_is_valid(device);
if(res != icsneoc2_error_success) {
return res;
}
if(!value) {
return icsneoc2_error_invalid_parameters;
}
auto network = Network(static_cast<Network::NetID>(netid));
if(auto result = device->device->settings->getT1STxOppTimerFor(network); result.has_value()) {
*value = result.value();
return icsneoc2_error_success;
} else {
*value = 0;
return icsneoc2_error_get_settings_failure;
}
}
icsneoc2_error_t icsneoc2_settings_t1s_tx_opp_timer_set(icsneoc2_device_t* device, icsneoc2_netid_t netid, uint8_t value) {
// Make sure the device is valid
auto res = icsneoc2_device_is_valid(device);
if(res != icsneoc2_error_success) {
return res;
}
auto network = Network(static_cast<Network::NetID>(netid));
if(!device->device->settings->setT1STxOppTimerFor(network, value)) {
return icsneoc2_error_set_settings_failure;
}
return icsneoc2_error_success;
}
icsneoc2_error_t icsneoc2_settings_t1s_burst_timer_get(icsneoc2_device_t* device, icsneoc2_netid_t netid, uint8_t* value) {
auto res = icsneoc2_device_is_valid(device);
if(res != icsneoc2_error_success) {
return res;
}
if(!value) {
return icsneoc2_error_invalid_parameters;
}
auto network = Network(static_cast<Network::NetID>(netid));
if(auto result = device->device->settings->getT1SBurstTimerFor(network); result.has_value()) {
*value = result.value();
return icsneoc2_error_success;
} else {
*value = 0;
return icsneoc2_error_get_settings_failure;
}
}
icsneoc2_error_t icsneoc2_settings_t1s_burst_timer_set(icsneoc2_device_t* device, icsneoc2_netid_t netid, uint8_t value) {
auto res = icsneoc2_device_is_valid(device);
if(res != icsneoc2_error_success) {
return res;
}
auto network = Network(static_cast<Network::NetID>(netid));
if(!device->device->settings->setT1SBurstTimerFor(network, value)) {
return icsneoc2_error_set_settings_failure;
}
return icsneoc2_error_success;
}
icsneoc2_error_t icsneoc2_settings_t1s_max_burst_timer_for_get(icsneoc2_device_t* device, icsneoc2_netid_t netid, uint8_t* value) {
// Make sure the device is valid
auto res = icsneoc2_device_is_valid(device);
if(res != icsneoc2_error_success) {
return res;
}
if(!value) {
return icsneoc2_error_invalid_parameters;
}
auto network = Network(static_cast<Network::NetID>(netid));
if(auto result = device->device->settings->getT1SMaxBurstFor(network); result.has_value()) {
*value = result.value();
return icsneoc2_error_success;
} else {
*value = 0;
return icsneoc2_error_get_settings_failure;
}
}
icsneoc2_error_t icsneoc2_settings_t1s_max_burst_timer_for_set(icsneoc2_device_t* device, icsneoc2_netid_t netid, uint8_t value) {
// Make sure the device is valid
auto res = icsneoc2_device_is_valid(device);
if(res != icsneoc2_error_success) {
return res;
}
auto network = Network(static_cast<Network::NetID>(netid));
if(!device->device->settings->setT1SMaxBurstFor(network, value)) {
return icsneoc2_error_set_settings_failure;
}
return icsneoc2_error_success;
}
icsneoc2_error_t icsneoc2_settings_t1s_local_id_alternate_get(icsneoc2_device_t* device, icsneoc2_netid_t netid, uint8_t* value) {
auto res = icsneoc2_device_is_valid(device);
if(res != icsneoc2_error_success) {
return res;
}
if(!value) {
return icsneoc2_error_invalid_parameters;
}
auto network = Network(static_cast<Network::NetID>(netid));
if(auto result = device->device->settings->getT1SLocalIDAlternateFor(network); result.has_value()) {
*value = result.value();
return icsneoc2_error_success;
} else {
*value = 0;
return icsneoc2_error_get_settings_failure;
}
}
icsneoc2_error_t icsneoc2_settings_t1s_local_id_alternate_set(icsneoc2_device_t* device, icsneoc2_netid_t netid, uint8_t value) {
auto res = icsneoc2_device_is_valid(device);
if(res != icsneoc2_error_success) {
return res;
}
auto network = Network(static_cast<Network::NetID>(netid));
if(!device->device->settings->setT1SLocalIDAlternateFor(network, value)) {
return icsneoc2_error_set_settings_failure;
}
return icsneoc2_error_success;
}
icsneoc2_error_t icsneoc2_settings_t1s_is_termination_enabled_for(icsneoc2_device_t* device, icsneoc2_netid_t netid, bool* value) {
auto res = icsneoc2_device_is_valid(device);
if(res != icsneoc2_error_success) {
return res;
}
if(!value) {
return icsneoc2_error_invalid_parameters;
}
auto network = Network(static_cast<Network::NetID>(netid));
if(auto result = device->device->settings->isT1STerminationEnabledFor(network); result.has_value()) {
*value = result.value();
return icsneoc2_error_success;
} else {
*value = false;
return icsneoc2_error_get_settings_failure;
}
}
icsneoc2_error_t icsneoc2_settings_t1s_termination_for_set(icsneoc2_device_t* device, icsneoc2_netid_t netid, bool value) {
auto res = icsneoc2_device_is_valid(device);
if(res != icsneoc2_error_success) {
return res;
}
auto network = Network(static_cast<Network::NetID>(netid));
if(!device->device->settings->setT1STerminationFor(network, value)) {
return icsneoc2_error_set_settings_failure;
}
return icsneoc2_error_success;
}
icsneoc2_error_t icsneoc2_settings_t1s_is_bus_decoding_beacons_enabled_for(icsneoc2_device_t* device, icsneoc2_netid_t netid, bool* value) {
auto res = icsneoc2_device_is_valid(device);
if(res != icsneoc2_error_success) {
return res;
}
if(!value) {
return icsneoc2_error_invalid_parameters;
}
auto network = Network(static_cast<Network::NetID>(netid));
if(auto result = device->device->settings->isT1SBusDecodingBeaconsEnabledFor(network); result.has_value()) {
*value = result.value();
return icsneoc2_error_success;
} else {
*value = false;
return icsneoc2_error_get_settings_failure;
}
}
icsneoc2_error_t icsneoc2_settings_t1s_bus_decoding_beacons_for_set(icsneoc2_device_t* device, icsneoc2_netid_t netid, bool value) {
auto res = icsneoc2_device_is_valid(device);
if(res != icsneoc2_error_success) {
return res;
}
auto network = Network(static_cast<Network::NetID>(netid));
if(!device->device->settings->setT1SBusDecodingBeaconsFor(network, value)) {
return icsneoc2_error_set_settings_failure;
}
return icsneoc2_error_success;
}
icsneoc2_error_t icsneoc2_settings_t1s_is_bus_decoding_all_enabled_for(icsneoc2_device_t* device, icsneoc2_netid_t netid, bool* value) {
auto res = icsneoc2_device_is_valid(device);
if(res != icsneoc2_error_success) {
return res;
}
if(!value) {
return icsneoc2_error_invalid_parameters;
}
auto network = Network(static_cast<Network::NetID>(netid));
if(auto result = device->device->settings->isT1SBusDecodingAllEnabledFor(network); result.has_value()) {
*value = result.value();
return icsneoc2_error_success;
} else {
*value = false;
return icsneoc2_error_get_settings_failure;
}
}
icsneoc2_error_t icsneoc2_settings_t1s_bus_decoding_all_for_set(icsneoc2_device_t* device, icsneoc2_netid_t netid, bool value) {
auto res = icsneoc2_device_is_valid(device);
if(res != icsneoc2_error_success) {
return res;
}
auto network = Network(static_cast<Network::NetID>(netid));
if(!device->device->settings->setT1SBusDecodingAllFor(network, value)) {
return icsneoc2_error_set_settings_failure;
}
return icsneoc2_error_success;
}
icsneoc2_error_t icsneoc2_settings_t1s_multi_id_enable_mask_get(icsneoc2_device_t* device, icsneoc2_netid_t netid, uint8_t* value) {
auto res = icsneoc2_device_is_valid(device);
if(res != icsneoc2_error_success) {
return res;
}
if(!value) {
return icsneoc2_error_invalid_parameters;
}
auto network = Network(static_cast<Network::NetID>(netid));
if(auto result = device->device->settings->getT1SMultiIDEnableMaskFor(network); result.has_value()) {
*value = result.value();
return icsneoc2_error_success;
} else {
*value = 0;
return icsneoc2_error_get_settings_failure;
}
}
icsneoc2_error_t icsneoc2_settings_t1s_multi_id_enable_mask_set(icsneoc2_device_t* device, icsneoc2_netid_t netid, uint8_t value) {
auto res = icsneoc2_device_is_valid(device);
if(res != icsneoc2_error_success) {
return res;
}
auto network = Network(static_cast<Network::NetID>(netid));
if(!device->device->settings->setT1SMultiIDEnableMaskFor(network, value)) {
return icsneoc2_error_set_settings_failure;
}
return icsneoc2_error_success;
}
icsneoc2_error_t icsneoc2_settings_t1s_multi_id_get(icsneoc2_device_t* device, icsneoc2_netid_t netid, uint8_t index, uint8_t* value) {
auto res = icsneoc2_device_is_valid(device);
if(res != icsneoc2_error_success) {
return res;
}
if(!value) {
return icsneoc2_error_invalid_parameters;
}
auto network = Network(static_cast<Network::NetID>(netid));
if(auto result = device->device->settings->getT1SMultiIDFor(network, index); result.has_value()) {
*value = result.value();
return icsneoc2_error_success;
} else {
*value = 0;
return icsneoc2_error_get_settings_failure;
}
}
icsneoc2_error_t icsneoc2_settings_t1s_multi_id_set(icsneoc2_device_t* device, icsneoc2_netid_t netid, uint8_t index, uint8_t value) {
auto res = icsneoc2_device_is_valid(device);
if(res != icsneoc2_error_success) {
return res;
}
auto network = Network(static_cast<Network::NetID>(netid));
if(!device->device->settings->setT1SMultiIDFor(network, index, value)) {
return icsneoc2_error_set_settings_failure;
}
return icsneoc2_error_success;
}
icsneoc2_error_t icsneoc2_settings_misc_io_analog_output_enabled_set(icsneoc2_device_t* device, uint8_t pin, uint8_t value) {
// Make sure the device is valid
auto res = icsneoc2_device_is_valid(device);
if(res != icsneoc2_error_success) {
return res;
}
if(!device->device->settings->setMiscIOAnalogOutputEnabled(pin, value)) {
return icsneoc2_error_set_settings_failure;
}
return icsneoc2_error_success;
}
icsneoc2_error_t icsneoc2_settings_misc_io_analog_output_set(icsneoc2_device_t* device, uint8_t pin, icsneoc2_misc_io_analog_voltage_t value) {
// Make sure the device is valid
auto res = icsneoc2_device_is_valid(device);
if(res != icsneoc2_error_success) {
return res;
}
if(!device->device->settings->setMiscIOAnalogOutput(pin, static_cast<MiscIOAnalogVoltage>(value))) {
return icsneoc2_error_set_settings_failure;
}
return icsneoc2_error_success;
}
icsneoc2_error_t icsneoc2_settings_disabled_get(icsneoc2_device_t* device, bool* value) {
if(!value) {
return icsneoc2_error_invalid_parameters;
}
// Make sure the device is valid
auto res = icsneoc2_device_is_valid(device);
if(res != icsneoc2_error_success) {
return res;
}
*value = device->device->settings->disabled;
return icsneoc2_error_success;
}
icsneoc2_error_t icsneoc2_settings_readonly_get(icsneoc2_device_t* device, bool* value) {
if(!value) {
return icsneoc2_error_invalid_parameters;
}
// Make sure the device is valid
auto res = icsneoc2_device_is_valid(device);
if(res != icsneoc2_error_success) {
return res;
}
*value = device->device->settings->readonly;
return icsneoc2_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", "icsneoc2.dll"
VALUE "LegalCopyright", "Intrepid Control Systems, Inc. (C) 2018-2026"
VALUE "OriginalFilename", "icsneoc2.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
+104 -29
View File
@@ -22,29 +22,6 @@ void APIEvent::init(Type event, APIEvent::Severity severity) {
eventStruct.timestamp = EventClock::to_time_t(timepoint);
}
std::string APIEvent::describe() const noexcept {
std::stringstream ss;
if(device)
ss << *device; // Makes use of device.describe()
else
ss << "API";
Severity severity = getSeverity();
if(severity == Severity::EventInfo) {
ss << " Info: ";
} else if(severity == Severity::EventWarning) {
ss << " Warning: ";
} else if(severity == Severity::Error) {
ss << " Error: ";
} else {
// Should never get here, since Severity::Any should only be used for filtering
ss << " Any: ";
}
ss << getDescription();
return ss.str();
}
void APIEvent::downgradeFromError() noexcept {
eventStruct.severity = (uint8_t) APIEvent::Severity::EventWarning;
}
@@ -86,8 +63,8 @@ static constexpr const char* NO_SERIAL_NUMBER_12V = "Communication could not be
static constexpr const char* NO_SERIAL_NUMBER = "Communication could not be established with the device. Perhaps it is not powered or requires a firmware update using Vehicle Spy.";
static constexpr const char* INCORRECT_SERIAL_NUMBER = "The device did not return the expected serial number!";
static constexpr const char* SETTINGS_READ = "The device settings could not be read.";
static constexpr const char* SETTINGS_VERSION = "The settings version is incorrect, please update your firmware with neoVI Explorer.";
static constexpr const char* SETTINGS_LENGTH = "The settings length is incorrect, please update your firmware with neoVI Explorer.";
static constexpr const char* SETTINGS_VERSION = "The settings version is incorrect, please update your firmware with ICS Device Manager.";
static constexpr const char* SETTINGS_LENGTH = "The settings length is incorrect, please update your firmware with ICS Device Manager.";
static constexpr const char* SETTINGS_CHECKSUM = "The settings checksum is incorrect, attempting to set defaults may remedy this issue.";
static constexpr const char* SETTINGS_NOT_AVAILABLE = "Settings are not available for this device.";
static constexpr const char* SETTINGS_READONLY = "Settings are read-only for this device.";
@@ -118,18 +95,28 @@ static constexpr const char* ATOMIC_OPERATION_COMPLETED_NONATOMICALLY = "An idea
static constexpr const char* WIVI_STACK_REFRESH_FAILED = "The Wireless neoVI stack encountered a communication error.";
static constexpr const char* WIVI_UPLOAD_STACK_OVERFLOW = "The Wireless neoVI upload stack has encountered an overflow condition.";
static constexpr const char* A2B_MESSAGE_INCOMPLETE_FRAME = "At least one of the frames of the A2B message does not contain samples for each channel and stream.";
static constexpr const char* I2C_MESSAGE_EXCEED_MAX_LENGTH = "The I2C message was too long.";
static constexpr const char* COREMINI_UPLOAD_VERSION_MISMATCH = "The version of the coremini engine on the device and the script uploaded are not the same.";
static constexpr const char* DISK_NOT_CONNECTED = "The program tried to access a disk that is not connected.";
static constexpr const char* UNEXPECTED_RESPONSE = "Received an unexpected or invalid response from the device.";
static constexpr const char* LIVE_DATA_INVALID_HANDLE = "The live data handle was invalid.";
static constexpr const char* LIVE_DATA_INVALID_COMMAND = "The live data command was invalid.";
static constexpr const char* LIVE_DATA_INVALID_ARGUMENT = "The live data argument was invalid.";
static constexpr const char* LIVE_DATA_VERSION_MISMATCH = "The live data version between libicsneo and firmware are not the same.";
static constexpr const char* LIVE_DATA_NO_DEVICE_RESPONSE = "Expected a response from the device for live data but none were found.";
static constexpr const char* LIVE_DATA_MAX_SIGNALS_REACHED = "The max amound of signals to subscribe to for live data has been reached.";
static constexpr const char* LIVE_DATA_COMMAND_FAILED = "The live data command failed.";
static constexpr const char* LIVE_DATA_ENCODER_ERROR = "Failure to encode live data message.";
static constexpr const char* LIVE_DATA_DECODER_ERROR = "Failure to decode live data message.";
static constexpr const char* LIVE_DATA_NOT_SUPPORTED = "Live data is not supported on 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* APP_ERROR_PARSING_FAILED = "Failure to decode app error message.";
static constexpr const char* GPTP_NOT_SUPPORTED = "GPTP clock synchronization is not supported on this device.";
static constexpr const char* SETTING_NOT_AVAILABLE = "Requested a setting that is not available on this device";
static constexpr const char* DISK_FORMAT_NOT_SUPPORTED = "Disk formatting is not supported on this device.";
static constexpr const char* DISK_FORMAT_INVALID_COUNT = "Disk format config disk count is mismatched with device disk count.";
// Transport Errors
static constexpr const char* FAILED_TO_READ = "A read operation failed.";
static constexpr const char* FAILED_TO_WRITE = "A write operation failed.";
@@ -146,6 +133,7 @@ static constexpr const char* FAILED_TO_BIND = "Unable to bind socket.";
static constexpr const char* ERROR_SETTING_SOCKET_OPTION = "A call to setsockopt() failed.";
static constexpr const char* GETIFADDRS_ERROR = "A call to getifaddrs() failed.";
static constexpr const char* SEND_TO_ERROR = "A call to sendto() failed.";
static constexpr const char* MDIO_MESSAGE_EXCEED_MAX_LENGTH = "The MDIO message was too long.";
// VSA
static constexpr const char* VSA_BUFFER_CORRUPTED = "VSA data in record buffer is corrupted.";
@@ -156,6 +144,16 @@ static constexpr const char* VSA_BYTE_PARSE_FAILURE = "Failure to parse record b
static constexpr const char* VSA_EXTENDED_MESSAGE_ERROR = "Failure to parse extended message record sequence";
static constexpr const char* VSA_OTHER_ERROR = "Unknown error in VSA read API.";
// MACSEC
static constexpr const char* MACSEC_SECY_LIMIT = "Attempted to exceed the limit of SecY additions to this port";
static constexpr const char* MACSEC_RULE_LIMIT = "Attempted to exceed the limit of rule additions to this port";
static constexpr const char* MACSEC_SA_LIMIT = "Attempted to exceed the limit of SA additions to this port";
static constexpr const char* MACSEC_INVALID_SECY_INDEX = "Attempted to access an invalid SecY index";
static constexpr const char* MACSEC_INVALID_SA_INDEX = "Attempted to access an invalid SA index";
static constexpr const char* MACSEC_INVALID_RULE_INDEX = "Attempted to access an invalid rule index";
static constexpr const char* MACSEC_REKEY_NOT_ENABLED = "Attempted to set rekey SA when rekey was not enabled";
static constexpr const char* MACSEC_NOT_SUPPORTED = "MACsec is not supported on this device";
static constexpr const char* MACSEC_CONFIG_MISMATCH = "Attempted to configure device with a macsec configuration for a different device";
// Servd
static constexpr const char* SERVD_BIND_ERROR = "Error binding socket for Servd communication";
static constexpr const char* SERVD_NONBLOCK_ERROR = "Error setting non-blocking mode for Servd socket";
@@ -168,6 +166,7 @@ static constexpr const char* SERVD_RECV_ERROR = "Error receiving from Servd";
static constexpr const char* SERVD_POLL_ERROR = "Error polling on Servd socket";
static constexpr const char* SERVD_NODATA_ERROR = "No data received from Servd";
static constexpr const char* SERVD_JOIN_MULTICAST_ERROR = "Error joining Servd multicast group";
static constexpr const char* SERVD_NOT_REACHABLE = "Could not reach Servd; ensure it is installed and running";
// DXX
static constexpr const char* DXX_ERROR_SYS = "System error, check errno/GetLastError()";
@@ -176,6 +175,7 @@ static constexpr const char* DXX_ERROR_OVERFLOW = "Overflow in DXX";
static constexpr const char* DXX_ERROR_IO = "I/O failure in DXX";
static constexpr const char* DXX_ERROR_ARG = "Invalid arg passed to DXX";
static constexpr const char* NO_ERROR_FOUND = "No errors were found.";
static constexpr const char* TOO_MANY_EVENTS = "Too many events have occurred. The list has been truncated.";
static constexpr const char* UNKNOWN = "An unknown internal error occurred.";
static constexpr const char* INVALID = "An invalid internal error occurred.";
@@ -303,6 +303,8 @@ const char* APIEvent::DescriptionForType(Type type) {
return WIVI_STACK_REFRESH_FAILED;
case Type::WiVIUploadStackOverflow:
return WIVI_UPLOAD_STACK_OVERFLOW;
case Type::I2CMessageExceedsMaxLength:
return I2C_MESSAGE_EXCEED_MAX_LENGTH;
case Type::A2BMessageIncompleteFrame:
return A2B_MESSAGE_INCOMPLETE_FRAME;
case Type::CoreminiUploadVersionMismatch:
@@ -311,10 +313,32 @@ const char* APIEvent::DescriptionForType(Type type) {
return DISK_NOT_CONNECTED;
case Type::UnexpectedResponse:
return UNEXPECTED_RESPONSE;
case Type::LiveDataInvalidHandle:
return LIVE_DATA_INVALID_HANDLE;
case Type::LiveDataInvalidCommand:
return LIVE_DATA_INVALID_COMMAND;
case Type::LiveDataInvalidArgument:
return LIVE_DATA_INVALID_ARGUMENT;
case Type::LiveDataVersionMismatch:
return LIVE_DATA_VERSION_MISMATCH;
case Type::LiveDataNoDeviceResponse:
return LIVE_DATA_NO_DEVICE_RESPONSE;
case Type::LiveDataMaxSignalsReached:
return LIVE_DATA_MAX_SIGNALS_REACHED;
case Type::LiveDataCommandFailed:
return LIVE_DATA_COMMAND_FAILED;
case Type::LiveDataEncoderError:
return LIVE_DATA_ENCODER_ERROR;
case Type::LiveDataDecoderError:
return LIVE_DATA_DECODER_ERROR;
case Type::LiveDataNotSupported:
return LIVE_DATA_NOT_SUPPORTED;
case Type::LINSettingsNotAvailable:
return LIN_SETTINGS_NOT_AVAILABLE;
case Type::ModeNotFound:
return MODE_NOT_FOUND;
case Type::AppErrorParsingFailed:
return APP_ERROR_PARSING_FAILED;
case Type::SettingNotAvaiableDevice:
return SETTING_NOT_AVAILABLE;
// Transport Errors
@@ -348,6 +372,8 @@ const char* APIEvent::DescriptionForType(Type type) {
return GETIFADDRS_ERROR;
case Type::SendToError:
return SEND_TO_ERROR;
case Type::MDIOMessageExceedsMaxLength:
return MDIO_MESSAGE_EXCEED_MAX_LENGTH;
case Type::GPTPNotSupported:
return GPTP_NOT_SUPPORTED;
case Type::DiskFormatNotSupported:
@@ -371,6 +397,25 @@ const char* APIEvent::DescriptionForType(Type type) {
case Type::VSAOtherError:
return VSA_OTHER_ERROR;
// MACSEC
case Type::MACsecSecYLimit:
return MACSEC_SECY_LIMIT;
case Type::MACsecSaLimit:
return MACSEC_SA_LIMIT;
case Type::MACsecRuleLimit:
return MACSEC_RULE_LIMIT;
case Type::MACsecInvalidSecYIndex:
return MACSEC_INVALID_SECY_INDEX;
case Type::MACsecInvalidSaIndex:
return MACSEC_INVALID_SA_INDEX;
case Type::MACsecInvalidRuleIndex:
return MACSEC_INVALID_RULE_INDEX;
case Type::MACsecRekeyNotEnabled:
return MACSEC_REKEY_NOT_ENABLED;
case Type::MACsecNotSupported:
return MACSEC_NOT_SUPPORTED;
case Type::MACsecConfigMismatch:
return MACSEC_CONFIG_MISMATCH;
// Servd
case Type::ServdBindError:
return SERVD_BIND_ERROR;
@@ -394,6 +439,8 @@ const char* APIEvent::DescriptionForType(Type type) {
return SERVD_NODATA_ERROR;
case Type::ServdJoinMulticastError:
return SERVD_JOIN_MULTICAST_ERROR;
case Type::ServdNotReachable:
return SERVD_NOT_REACHABLE;
// DXX
case Type::DXXErrorSys:
@@ -408,13 +455,41 @@ const char* APIEvent::DescriptionForType(Type type) {
return DXX_ERROR_ARG;
// Other Errors
case Type::NoErrorFound:
return NO_ERROR_FOUND;
case Type::TooManyEvents:
return TOO_MANY_EVENTS;
case Type::Unknown:
return UNKNOWN;
default:
return INVALID;
}
return INVALID;
}
std::string APIEvent::describe() const noexcept {
std::stringstream ss;
if(device)
ss << *device; // Makes use of device.describe()
else
ss << "API";
Severity severity = getSeverity();
if(severity == Severity::EventInfo) {
ss << " Info: ";
} else if(severity == Severity::EventWarning) {
ss << " Warning: ";
} else if(severity == Severity::Error) {
ss << " Error: ";
} else {
// Should never get here, since Severity::Any should only be used for filtering
ss << " Any: ";
}
const char* description = DescriptionForType(getType());
if(description == INVALID)
ss << description << " (0x" << std::hex << eventStruct.eventNumber << ")";
else
ss << description;
return ss.str();
}
bool EventFilter::match(const APIEvent& event) const noexcept {
+3
View File
@@ -1076,6 +1076,9 @@ int LegacyDLLExport icsneoGetDeviceSettingsType(void* hObject, EPlasmaIonVnetCha
case NEODEVICE_RADMOON3:
*pDeviceSettingsType = DeviceRADMoon3SettingsType;
break;
case NEODEVICE_RADGEMINI:
*pDeviceSettingsType = DeviceRADGeminiSettingsType;
break;
case NEODEVICE_RED2:
*pDeviceSettingsType = DeviceRed2SettingsType;
break;
+5 -2
View File
@@ -9,7 +9,7 @@ else()
FetchContent_Declare(
pybind11
GIT_REPOSITORY https://github.com/pybind/pybind11.git
GIT_TAG v2.13.6
GIT_TAG v3.0.3
)
FetchContent_MakeAvailable(pybind11)
endif()
@@ -22,6 +22,7 @@ pybind11_add_module(icsneopy
icsneopy/device/devicetype.cpp
icsneopy/communication/network.cpp
icsneopy/communication/io.cpp
icsneopy/communication/livedata.cpp
icsneopy/communication/message/message.cpp
icsneopy/communication/message/canmessage.cpp
icsneopy/communication/message/canerrormessage.cpp
@@ -32,13 +33,15 @@ pybind11_add_module(icsneopy
icsneopy/communication/message/gptpstatusmessage.cpp
icsneopy/communication/message/ethernetstatusmessage.cpp
icsneopy/communication/message/spimessage.cpp
icsneopy/communication/message/macsecmessage.cpp
icsneopy/communication/message/scriptstatusmessage.cpp
icsneopy/communication/message/ethphymessage.cpp
icsneopy/communication/message/livedatamessage.cpp
icsneopy/communication/message/callback/messagecallback.cpp
icsneopy/communication/message/filter/messagefilter.cpp
icsneopy/core/macseccfg.cpp
icsneopy/flexray/flexray.cpp
icsneopy/disk/diskdriver.cpp
icsneopy/disk/diskdetails.cpp
icsneopy/device/chipid.cpp
icsneopy/device/versionreport.cpp
icsneopy/device/device.cpp
+10 -6
View File
@@ -1,14 +1,15 @@
#include <pybind11/pybind11.h>
#include <pybind11/stl.h>
#include <pybind11/functional.h>
#include <pybind11/native_enum.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")
pybind11::classh<APIEvent> apiEvent(m, "APIEvent");
pybind11::native_enum<APIEvent::Type>(apiEvent, "Type", "enum.IntEnum")
.value("Any", APIEvent::Type::Any)
.value("InvalidNeoDevice", APIEvent::Type::InvalidNeoDevice)
.value("RequiredParameterNull", APIEvent::Type::RequiredParameterNull)
@@ -125,6 +126,7 @@ void init_event(pybind11::module_& m) {
.value("ServdPollError", APIEvent::Type::ServdPollError)
.value("ServdNoDataError", APIEvent::Type::ServdNoDataError)
.value("ServdJoinMulticastError", APIEvent::Type::ServdJoinMulticastError)
.value("ServdNotReachable", APIEvent::Type::ServdNotReachable)
.value("DXXErrorSys", APIEvent::Type::DXXErrorSys)
.value("DXXErrorInt", APIEvent::Type::DXXErrorInt)
.value("DXXErrorOverflow", APIEvent::Type::DXXErrorOverflow)
@@ -132,13 +134,15 @@ void init_event(pybind11::module_& m) {
.value("DXXErrorArg", APIEvent::Type::DXXErrorArg)
.value("NoErrorFound", APIEvent::Type::NoErrorFound)
.value("TooManyEvents", APIEvent::Type::TooManyEvents)
.value("Unknown", APIEvent::Type::Unknown);
.value("Unknown", APIEvent::Type::Unknown)
.finalize();
pybind11::enum_<APIEvent::Severity>(apiEvent, "Severity")
pybind11::native_enum<APIEvent::Severity>(apiEvent, "Severity", "enum.IntEnum")
.value("Any", APIEvent::Severity::Any)
.value("EventInfo", APIEvent::Severity::EventInfo)
.value("EventWarning", APIEvent::Severity::EventWarning)
.value("Error", APIEvent::Severity::Error);
.value("Error", APIEvent::Severity::Error)
.finalize();
apiEvent
.def("get_type", &APIEvent::getType)
@@ -147,7 +151,7 @@ void init_event(pybind11::module_& m) {
.def("describe", &APIEvent::describe)
.def("__repr__", &APIEvent::describe);
pybind11::class_<EventFilter, std::shared_ptr<EventFilter>>(m, "EventFilter")
pybind11::classh<EventFilter>(m, "EventFilter")
.def(pybind11::init())
.def(pybind11::init<APIEvent::Type>())
.def(pybind11::init<APIEvent::Severity>())
@@ -7,7 +7,7 @@
namespace icsneo {
void init_eventcallback(pybind11::module_& m) {
pybind11::class_<EventCallback>(m, "EventCallback")
pybind11::classh<EventCallback>(m, "EventCallback")
.def(pybind11::init<EventCallback::fn_eventCallback, EventFilter>())
.def(pybind11::init<EventCallback::fn_eventCallback>());
}
@@ -7,7 +7,7 @@
namespace icsneo {
void init_eventmanager(pybind11::module_& m) {
pybind11::class_<EventManager>(m, "EventManager")
pybind11::classh<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)
+1 -1
View File
@@ -9,7 +9,7 @@
namespace icsneo {
void init_version(pybind11::module_& m) {
pybind11::class_<neoversion_t>(m, "NeoVersion")
pybind11::classh<neoversion_t>(m, "NeoVersion")
.def_readonly("major", &neoversion_t::major)
.def_readonly("minor", &neoversion_t::minor)
.def_readonly("patch", &neoversion_t::patch)
@@ -0,0 +1,79 @@
#include <pybind11/pybind11.h>
#include <pybind11/stl.h>
#include <pybind11/functional.h>
#include <pybind11/native_enum.h>
#include "icsneo/communication/livedata.h"
namespace icsneo {
void init_livedata(pybind11::module_& m) {
// LiveDataValue struct
pybind11::classh<LiveDataValue>(m, "LiveDataValue")
.def(pybind11::init<>())
.def_readwrite("value", &LiveDataValue::value);
// LiveDataArgument struct
pybind11::classh<LiveDataArgument>(m, "LiveDataArgument")
.def(pybind11::init<>())
.def_readwrite("object_type", &LiveDataArgument::objectType)
.def_readwrite("object_index", &LiveDataArgument::objectIndex)
.def_readwrite("signal_index", &LiveDataArgument::signalIndex)
.def_readwrite("value_type", &LiveDataArgument::valueType);
// LiveDataCommand enum
pybind11::native_enum<LiveDataCommand>(m, "LiveDataCommand", "enum.IntEnum")
.value("STATUS", LiveDataCommand::STATUS)
.value("SUBSCRIBE", LiveDataCommand::SUBSCRIBE)
.value("UNSUBSCRIBE", LiveDataCommand::UNSUBSCRIBE)
.value("RESPONSE", LiveDataCommand::RESPONSE)
.value("CLEAR_ALL", LiveDataCommand::CLEAR_ALL)
.value("SET_VALUE", LiveDataCommand::SET_VALUE)
.finalize();
// LiveDataStatus enum
pybind11::native_enum<LiveDataStatus>(m, "LiveDataStatus", "enum.IntEnum")
.value("SUCCESS", LiveDataStatus::SUCCESS)
.value("ERR_UNKNOWN_COMMAND", LiveDataStatus::ERR_UNKNOWN_COMMAND)
.value("ERR_HANDLE", LiveDataStatus::ERR_HANDLE)
.value("ERR_DUPLICATE", LiveDataStatus::ERR_DUPLICATE)
.value("ERR_FULL", LiveDataStatus::ERR_FULL)
.finalize();
// LiveDataObjectType enum
pybind11::enum_<LiveDataObjectType>(m, "LiveDataObjectType")
.value("MISC", LiveDataObjectType::MISC)
.value("SNA", LiveDataObjectType::SNA)
.export_values();
// LiveDataValueType enum
pybind11::native_enum<LiveDataValueType>(m, "LiveDataValueType", "enum.IntEnum")
.value("GPS_LATITUDE", LiveDataValueType::GPS_LATITUDE)
.value("GPS_LONGITUDE", LiveDataValueType::GPS_LONGITUDE)
.value("GPS_ALTITUDE", LiveDataValueType::GPS_ALTITUDE)
.value("GPS_SPEED", LiveDataValueType::GPS_SPEED)
.value("GPS_VALID", LiveDataValueType::GPS_VALID)
.value("GPS_ENABLE", LiveDataValueType::GPS_ENABLE)
.value("MANUAL_TRIGGER", LiveDataValueType::MANUAL_TRIGGER)
.value("TIME_SINCE_MSG", LiveDataValueType::TIME_SINCE_MSG)
.value("GPS_ACCURACY", LiveDataValueType::GPS_ACCURACY)
.value("GPS_BEARING", LiveDataValueType::GPS_BEARING)
.value("GPS_TIME", LiveDataValueType::GPS_TIME)
.value("GPS_TIME_VALID", LiveDataValueType::GPS_TIME_VALID)
.value("DAQ_ENABLE", LiveDataValueType::DAQ_ENABLE)
.finalize();
// LiveDataUtil namespace functions
m.def("get_new_handle", &LiveDataUtil::getNewHandle,
"Generate a new unique LiveData handle");
m.def("livedata_value_to_double", &LiveDataUtil::liveDataValueToDouble,
pybind11::arg("val"),
"Convert LiveDataValue to double (32.32 fixed-point to floating-point)");
m.def("livedata_double_to_value", &LiveDataUtil::liveDataDoubleToValue,
pybind11::arg("d"),
"Convert double to LiveDataValue (32.32 fixed-point format). Returns LiveDataValue or None on failure.");
}
} // namespace icsneo
@@ -7,7 +7,7 @@
namespace icsneo {
void init_messagecallback(pybind11::module_& m) {
pybind11::class_<MessageCallback, std::shared_ptr<MessageCallback>>(m, "MessageCallback")
pybind11::classh<MessageCallback>(m, "MessageCallback")
.def(pybind11::init<MessageCallback::fn_messageCallback, std::shared_ptr<MessageFilter>>());
}
@@ -1,13 +1,14 @@
#include <pybind11/pybind11.h>
#include <pybind11/stl.h>
#include <pybind11/functional.h>
#include <pybind11/native_enum.h>
#include "icsneo/communication/message/canerrormessage.h"
namespace icsneo {
void init_errorcodes(pybind11::module_& m) {
pybind11::enum_<CANErrorCode>(m, "CANErrorCode")
pybind11::native_enum<CANErrorCode>(m, "CANErrorCode", "enum.IntEnum")
.value("NoError", CANErrorCode::NoError)
.value("StuffError", CANErrorCode::StuffError)
.value("FormError", CANErrorCode::FormError)
@@ -15,12 +16,13 @@ void init_errorcodes(pybind11::module_& m) {
.value("Bit1Error", CANErrorCode::Bit1Error)
.value("Bit0Error", CANErrorCode::Bit0Error)
.value("CRCError", CANErrorCode::CRCError)
.value("NoChange", CANErrorCode::NoChange);
.value("NoChange", CANErrorCode::NoChange)
.finalize();
}
void init_canerrormessage(pybind11::module_& m) {
init_errorcodes(m);
pybind11::class_<CANErrorMessage, std::shared_ptr<CANErrorMessage>, Message>(m, "CANErrorMessage")
pybind11::classh<CANErrorMessage, Message>(m, "CANErrorMessage")
.def_readonly("network", &CANErrorMessage::network)
.def_readonly("transmitErrorCount", &CANErrorMessage::transmitErrorCount)
.def_readonly("receiveErrorCount", &CANErrorMessage::receiveErrorCount)
@@ -7,7 +7,7 @@
namespace icsneo {
void init_canmessage(pybind11::module_& m) {
pybind11::class_<CANMessage, std::shared_ptr<CANMessage>, Frame>(m, "CANMessage")
pybind11::classh<CANMessage, Frame>(m, "CANMessage")
.def(pybind11::init())
.def_readwrite("arbid", &CANMessage::arbid)
.def_readwrite("dlcOnWire", &CANMessage::dlcOnWire)
@@ -15,7 +15,10 @@ void init_canmessage(pybind11::module_& m) {
.def_readwrite("isExtended", &CANMessage::isExtended)
.def_readwrite("isCANFD", &CANMessage::isCANFD)
.def_readwrite("baudrateSwitch", &CANMessage::baudrateSwitch)
.def_readwrite("errorStateIndicator", &CANMessage::errorStateIndicator);
.def_readwrite("errorStateIndicator", &CANMessage::errorStateIndicator)
.def_readwrite("txAborted", &CANMessage::txAborted)
.def_readwrite("txLostArb", &CANMessage::txLostArb)
.def_readwrite("txError", &CANMessage::txError);
}
} // namespace icsneo
@@ -7,21 +7,29 @@
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>, Frame>(m, "EthernetMessage")
pybind11::classh<EthernetMessage::T1S>(m, "EthernetMessageT1S")
.def(pybind11::init())
.def_readwrite("isSymbol", &EthernetMessage::T1S::isSymbol)
.def_readwrite("isBurst", &EthernetMessage::T1S::isBurst)
.def_readwrite("txCollision", &EthernetMessage::T1S::txCollision)
.def_readwrite("isWake", &EthernetMessage::T1S::isWake)
.def_readwrite("nodeId", &EthernetMessage::T1S::nodeId)
.def_readwrite("burstCount", &EthernetMessage::T1S::burstCount)
.def_readwrite("symbolType", &EthernetMessage::T1S::symbolType);
pybind11::classh<EthernetMessage, Frame>(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_readwrite("fcsVerified", &EthernetMessage::fcsVerified)
.def_readwrite("txAborted", &EthernetMessage::txAborted)
.def_readwrite("crcError", &EthernetMessage::crcError)
.def_readwrite("t1s", &EthernetMessage::t1s)
.def_readwrite("preemptionFlags", &EthernetMessage::preemptionFlags)
.def("get_destination_mac", &EthernetMessage::getDestinationMAC)
.def("get_source_mac", &EthernetMessage::getSourceMAC)
.def("get_ether_type", &EthernetMessage::getEtherType);
}
} // namespace icsneo
@@ -7,7 +7,7 @@
namespace icsneo {
void init_ethernetstatusmessage(pybind11::module_& m) {
pybind11::class_<EthernetStatusMessage, std::shared_ptr<EthernetStatusMessage>, Message> ethernetStatusMessage(m, "EthernetStatusMessage");
pybind11::classh<EthernetStatusMessage, Message> ethernetStatusMessage(m, "EthernetStatusMessage");
pybind11::enum_<EthernetStatusMessage::LinkSpeed>(ethernetStatusMessage, "LinkSpeed")
.value("LinkSpeedAuto", EthernetStatusMessage::LinkSpeed::LinkSpeedAuto)
@@ -7,7 +7,17 @@
namespace icsneo {
void init_ethphymessage(pybind11::module_& m) {
pybind11::class_<PhyMessage, std::shared_ptr<PhyMessage>>(m, "PhyMessage")
pybind11::classh<Clause22Message>(m, "Clause22Message")
.def_readwrite("phyAddr", &Clause22Message::phyAddr)
.def_readwrite("page", &Clause22Message::page)
.def_readwrite("regAddr", &Clause22Message::regAddr)
.def_readwrite("regVal", &Clause22Message::regVal);
pybind11::classh<Clause45Message>(m, "Clause45Message")
.def_readwrite("port", &Clause45Message::port)
.def_readwrite("device", &Clause45Message::device)
.def_readwrite("regAddr", &Clause45Message::regAddr)
.def_readwrite("regVal", &Clause45Message::regVal);
pybind11::classh<PhyMessage>(m, "PhyMessage")
.def(pybind11::init())
.def_readwrite("Enabled", &PhyMessage::Enabled)
.def_readwrite("WriteEnable", &PhyMessage::WriteEnable)
@@ -16,19 +26,7 @@ void init_ethphymessage(pybind11::module_& m) {
.def_readwrite("BusIndex", &PhyMessage::BusIndex)
.def_readwrite("Clause22", &PhyMessage::Clause22)
.def_readwrite("Clause45", &PhyMessage::Clause45);
pybind11::class_<Clause22Message>(m, "Clause22Message")
.def(pybind11::init())
.def_readwrite("phyAddr", &Clause22Message::phyAddr)
.def_readwrite("page", &Clause22Message::page)
.def_readwrite("regAddr", &Clause22Message::regAddr)
.def_readwrite("regVal", &Clause22Message::regVal);
pybind11::class_<Clause45Message>(m, "Clause45Message")
.def(pybind11::init())
.def_readwrite("port", &Clause45Message::port)
.def_readwrite("device", &Clause45Message::device)
.def_readwrite("regAddr", &Clause45Message::regAddr)
.def_readwrite("regVal", &Clause45Message::regVal);
pybind11::class_<EthPhyMessage, std::shared_ptr<EthPhyMessage>, Message>(m, "EthPhyMessage")
pybind11::classh<EthPhyMessage, Message>(m, "EthPhyMessage")
.def(pybind11::init())
.def_readwrite("messages", &EthPhyMessage::messages);
}
@@ -7,7 +7,7 @@
namespace icsneo {
void init_messagefilter(pybind11::module_& m) {
pybind11::class_<MessageFilter, std::shared_ptr<MessageFilter>>(m, "MessageFilter")
pybind11::classh<MessageFilter>(m, "MessageFilter")
.def(pybind11::init())
.def(pybind11::init<Message::Type>())
.def(pybind11::init<Network::NetID>());
@@ -7,72 +7,73 @@
namespace icsneo {
void init_gptpstatusmessage(pybind11::module_& m) {
pybind11::class_<GPTPStatus, std::shared_ptr<GPTPStatus>, Message> gptpStatus(m, "GPTPStatus");
pybind11::classh<GPTPStatus, Message> gptpStatus(m, "GPTPStatus");
pybind11::class_<GPTPStatus::Timestamp>(gptpStatus, "Timestamp")
pybind11::classh<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::classh<GPTPStatus::ScaledNanoSeconds>(gptpStatus, "ScaledNanoSeconds")
.def_readonly("nanoseconds_msb", &GPTPStatus::ScaledNanoSeconds::nanosecondsMSB)
.def_readonly("nanoseconds_lsb", &GPTPStatus::ScaledNanoSeconds::nanosecondsLSB)
.def_readonly("fractional_nanoseconds", &GPTPStatus::ScaledNanoSeconds::fractionalNanoseconds);
pybind11::class_<GPTPStatus::PortID>(gptpStatus, "PortID")
.def_readonly("clockIdentity", &GPTPStatus::PortID::clockIdentity)
.def_readonly("portNumber", &GPTPStatus::PortID::portNumber);
pybind11::classh<GPTPStatus::PortID>(gptpStatus, "PortID")
.def_readonly("clock_identity", &GPTPStatus::PortID::clockIdentity)
.def_readonly("port_number", &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::classh<GPTPStatus::ClockQuality>(gptpStatus, "ClockQuality")
.def_readonly("clock_class", &GPTPStatus::ClockQuality::clockClass)
.def_readonly("clock_accuracy", &GPTPStatus::ClockQuality::clockAccuracy)
.def_readonly("offset_scaled_log_variance", &GPTPStatus::ClockQuality::offsetScaledLogVariance);
pybind11::class_<GPTPStatus::SystemID>(gptpStatus, "SystemID")
pybind11::classh<GPTPStatus::SystemID>(gptpStatus, "SystemID")
.def_readonly("priority1", &GPTPStatus::SystemID::priority1)
.def_readonly("clockQuality", &GPTPStatus::SystemID::clockQuality)
.def_readonly("clock_quality", &GPTPStatus::SystemID::clockQuality)
.def_readonly("priority2", &GPTPStatus::SystemID::priority2)
.def_readonly("clockID", &GPTPStatus::SystemID::clockID);
.def_readonly("clock_id", &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::classh<GPTPStatus::PriorityVector>(gptpStatus, "PriorityVector")
.def_readonly("sys_id", &GPTPStatus::PriorityVector::sysID)
.def_readonly("steps_removed", &GPTPStatus::PriorityVector::stepsRemoved)
.def_readonly("port_id", &GPTPStatus::PriorityVector::portID)
.def_readonly("port_number", &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::classh<GPTPStatus::ParentDS>(gptpStatus, "ParentDS")
.def_readonly("parent_port_identity", &GPTPStatus::ParentDS::parentPortIdentity)
.def_readonly("cumulative_rate_ratio", &GPTPStatus::ParentDS::cumulativeRateRatio)
.def_readonly("grandmaster_identity", &GPTPStatus::ParentDS::grandmasterIdentity)
.def_readonly("gm_clock_quality_clock_class", &GPTPStatus::ParentDS::gmClockQualityClockClass)
.def_readonly("gm_clock_quality_clock_accuracy", &GPTPStatus::ParentDS::gmClockQualityClockAccuracy)
.def_readonly("gm_clock_quality_offset_scaled_log_variance", &GPTPStatus::ParentDS::gmClockQualityOffsetScaledLogVariance)
.def_readonly("gm_priority1", &GPTPStatus::ParentDS::gmPriority1)
.def_readonly("gm_priority2", &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);
pybind11::classh<GPTPStatus::CurrentDS>(gptpStatus, "CurrentDS")
.def_readonly("steps_removed", &GPTPStatus::CurrentDS::stepsRemoved)
.def_readonly("offset_from_master", &GPTPStatus::CurrentDS::offsetFromMaster)
.def_readonly("lastgm_phase_change", &GPTPStatus::CurrentDS::lastgmPhaseChange)
.def_readonly("lastgm_freq_change", &GPTPStatus::CurrentDS::lastgmFreqChange)
.def_readonly("gm_time_base_indicator", &GPTPStatus::CurrentDS::gmTimeBaseIndicator)
.def_readonly("gm_change_count", &GPTPStatus::CurrentDS::gmChangeCount)
.def_readonly("time_of_lastgm_change_event", &GPTPStatus::CurrentDS::timeOfLastgmChangeEvent)
.def_readonly("time_of_lastgm_phase_change_event", &GPTPStatus::CurrentDS::timeOfLastgmPhaseChangeEvent)
.def_readonly("time_of_lastgm_freq_change_event", &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);
gptpStatus.def_readonly("current_time", &GPTPStatus::currentTime)
.def_readonly("gm_priority", &GPTPStatus::gmPriority)
.def_readonly("ms_offset_ns", &GPTPStatus::msOffsetNs)
.def_readonly("is_sync", &GPTPStatus::isSync)
.def_readonly("link_status", &GPTPStatus::linkStatus)
.def_readonly("link_delay_ns", &GPTPStatus::linkDelayNS)
.def_readonly("selected_role", &GPTPStatus::selectedRole)
.def_readonly("as_capable", &GPTPStatus::asCapable)
.def_readonly("is_syntonized", &GPTPStatus::isSyntonized)
.def_readonly("last_rx_sync_ts", &GPTPStatus::lastRXSyncTS)
.def_readonly("current_ds", &GPTPStatus::currentDS)
.def_readonly("parent_ds", &GPTPStatus::parentDS)
.def_readonly("short_format", &GPTPStatus::shortFormat);
}
@@ -7,7 +7,7 @@
namespace icsneo {
void init_linmessage(pybind11::module_& m) {
pybind11::class_<LINErrorFlags>(m, "LINErrorFlags")
pybind11::classh<LINErrorFlags>(m, "LINErrorFlags")
.def_readwrite("ErrRxBreakOnly", &LINErrorFlags::ErrRxBreakOnly)
.def_readwrite("ErrRxBreakSyncOnly", &LINErrorFlags::ErrRxBreakSyncOnly)
.def_readwrite("ErrTxRxMismatch", &LINErrorFlags::ErrTxRxMismatch)
@@ -20,7 +20,7 @@ void init_linmessage(pybind11::module_& m) {
.def_readwrite("ErrFrameResponderData", &LINErrorFlags::ErrFrameResponderData)
.def_readwrite("ErrChecksumMatch", &LINErrorFlags::ErrChecksumMatch);
pybind11::class_<LINStatusFlags>(m, "LINStatusFlags")
pybind11::classh<LINStatusFlags>(m, "LINStatusFlags")
.def_readwrite("TxChecksumEnhanced", &LINStatusFlags::TxChecksumEnhanced)
.def_readwrite("TxCommander", &LINStatusFlags::TxCommander)
.def_readwrite("TxResponder", &LINStatusFlags::TxResponder)
@@ -30,7 +30,7 @@ void init_linmessage(pybind11::module_& m) {
.def_readwrite("BusRecovered", &LINStatusFlags::BusRecovered)
.def_readwrite("BreakOnly", &LINStatusFlags::BreakOnly);
pybind11::class_<LINMessage, std::shared_ptr<LINMessage>, Frame> linMessage(m, "LINMessage");
pybind11::classh<LINMessage, Frame> linMessage(m, "LINMessage");
pybind11::enum_<LINMessage::Type>(linMessage, "Type")
.value("NOT_SET", LINMessage::Type::NOT_SET)
@@ -0,0 +1,50 @@
#include <pybind11/pybind11.h>
#include <pybind11/stl.h>
#include <pybind11/functional.h>
#include <pybind11/chrono.h>
#include "icsneo/communication/message/livedatamessage.h"
namespace icsneo {
void init_livedatamessage(pybind11::module_& m) {
// LiveDataMessage base class
pybind11::classh<LiveDataMessage, RawMessage>(m, "LiveDataMessage")
.def(pybind11::init<>())
.def_readwrite("handle", &LiveDataMessage::handle)
.def_readwrite("cmd", &LiveDataMessage::cmd);
// LiveDataCommandMessage (for subscribe/unsubscribe)
pybind11::classh<LiveDataCommandMessage, LiveDataMessage>(m, "LiveDataCommandMessage")
.def(pybind11::init<>())
.def_readwrite("update_period", &LiveDataCommandMessage::updatePeriod)
.def_readwrite("expiration_time", &LiveDataCommandMessage::expirationTime)
.def_readwrite("args", &LiveDataCommandMessage::args)
.def("append_signal_arg", &LiveDataCommandMessage::appendSignalArg,
pybind11::arg("value_type"),
"Append a signal argument to the command message");
// LiveDataValueMessage (received values)
pybind11::classh<LiveDataValueMessage, LiveDataMessage>(m, "LiveDataValueMessage")
.def(pybind11::init<>())
.def_readwrite("num_args", &LiveDataValueMessage::numArgs)
.def_readwrite("values", &LiveDataValueMessage::values);
// LiveDataStatusMessage (status responses)
pybind11::classh<LiveDataStatusMessage, LiveDataMessage>(m, "LiveDataStatusMessage")
.def(pybind11::init<>())
.def_readwrite("requested_command", &LiveDataStatusMessage::requestedCommand)
.def_readwrite("status", &LiveDataStatusMessage::status);
// LiveDataSetValueMessage (for setting values)
pybind11::classh<LiveDataSetValueMessage, LiveDataMessage>(m, "LiveDataSetValueMessage")
.def(pybind11::init<>())
.def_readwrite("args", &LiveDataSetValueMessage::args)
.def_readwrite("values", &LiveDataSetValueMessage::values)
.def("append_set_value", &LiveDataSetValueMessage::appendSetValue,
pybind11::arg("value_type"),
pybind11::arg("value"),
"Append a value to set in the message");
}
} // namespace icsneo
@@ -1,160 +0,0 @@
#include <pybind11/pybind11.h>
#include <pybind11/stl.h>
#include <pybind11/functional.h>
#include "icsneo/communication/message/macsecmessage.h"
namespace icsneo {
void init_macsecmessage(pybind11::module_ & m)
{
pybind11::enum_<MACsecPacketType>(m, "MACsecPacketType")
.value("NoVLAN_OrMPLS", MACsecPacketType::NoVLANOrMPLS)
.value("SingleVLAN", MACsecPacketType::SingleVLAN)
.value("DualVLAN", MACsecPacketType::DualVLAN)
.value("MPLS", MACsecPacketType::MPLS)
.value("SingleVLAN_FollowByMPLS", MACsecPacketType::SingleVLANFollowedByMPLS)
.value("DualVLAN_FollowByMPLS", MACsecPacketType::DualVLANFollowedByMPLS)
.value("Unsupported", MACsecPacketType::Unsupported);
pybind11::enum_<MACsecValidateFrameType>(m, "MACsecValidateFrameType")
.value("Disabled", MACsecValidateFrameType::Disabled)
.value("Check", MACsecValidateFrameType::Check)
.value("Strict", MACsecValidateFrameType::Strict)
.value("NA", MACsecValidateFrameType::NA);
pybind11::enum_<MACsecSecTagIcvStripType>(m, "MACsecSecTagIcvStripType")
.value("StripBoth", MACsecSecTagIcvStripType::StripBoth)
.value("StripSecTagPreserveICV", MACsecSecTagIcvStripType::StripSecTagPreserveICV)
.value("PreserveSecTagStripICV", MACsecSecTagIcvStripType::PreserveSecTagStripICV)
.value("PreserveBoth", MACsecSecTagIcvStripType::PreserveBoth);
pybind11::enum_<MACsecCipherSuiteType>(m, "MACsecCipherSuiteType")
.value("AES_128", MACsecCipherSuiteType::GcmAes128)
.value("AES_256", MACsecCipherSuiteType::GcmAes256)
.value("AES_128_XPN", MACsecCipherSuiteType::GcmAes128Xpn)
.value("AES_256_XPN", MACsecCipherSuiteType::GcmAes256Xpn);
pybind11::class_<MACsecVLANTag, std::shared_ptr<MACsecVLANTag>>(m, "MACsecVLANTag")
.def(pybind11::init())
.def_readwrite("vid", &MACsecVLANTag::vid)
.def_readwrite("pri_cfi", &MACsecVLANTag::priCfi);
pybind11::class_<MACsecMPLSOuter, std::shared_ptr<MACsecMPLSOuter>>(m, "MACsecMPLSOuter")
.def(pybind11::init())
.def_readwrite("mpls_label", &MACsecMPLSOuter::mplsLabel)
.def_readwrite("exp", &MACsecMPLSOuter::exp);
pybind11::class_<MACsecRule, std::shared_ptr<MACsecRule>>(m, "MACsecRule")
.def(pybind11::init())
.def_readwrite("index", &MACsecRule::index)
.def_readwrite("keyMacDa", &MACsecRule::keyMacDa)
.def_readwrite("maskMacDa", &MACsecRule::maskMacDa)
.def_readwrite("keyMacSa", &MACsecRule::keyMacSa)
.def_readwrite("maskMacSa", &MACsecRule::maskMacSa)
.def_readwrite("keyEthertype", &MACsecRule::keyEthertype)
.def_readwrite("maskEthertype", &MACsecRule::maskEthertype)
.def_readwrite("keyVlanTagOuter1", &MACsecRule::keyVlanTagOuter1)
.def_readwrite("keyMplsOuter1", &MACsecRule::keyMplsOuter1)
.def_readwrite("maskVlanTagOuter1", &MACsecRule::maskVlanTagOuter1)
.def_readwrite("maskMplsOuter1", &MACsecRule::maskMplsOuter1)
.def_readwrite("keyVlanTagOuter2", &MACsecRule::keyVlanTagOuter2)
.def_readwrite("keyMplsOuter2", &MACsecRule::keyMplsOuter2)
.def_readwrite("maskVlanTagOuter2", &MACsecRule::maskVlanTagOuter2)
.def_readwrite("maskMplsOuter2", &MACsecRule::maskMplsOuter2)
.def_readwrite("keyBonusData", &MACsecRule::keyBonusData)
.def_readwrite("maskBonusData", &MACsecRule::maskBonusData)
.def_readwrite("keyTagMatchBitmap", &MACsecRule::keyTagMatchBitmap)
.def_readwrite("maskTagMatchBitmap", &MACsecRule::maskTagMatchBitmap)
.def_readwrite("keyPacketType", &MACsecRule::keyPacketType)
.def_readwrite("maskPacketType", &MACsecRule::maskPacketType)
.def_readwrite("keyInnerVlanType", &MACsecRule::keyInnerVlanType)
.def_readwrite("maskInnerVlanType", &MACsecRule::maskInnerVlanType)
.def_readwrite("keyOuterVlanType", &MACsecRule::keyOuterVlanType)
.def_readwrite("maskOuterVlanType", &MACsecRule::maskOuterVlanType)
.def_readwrite("keyNumTags", &MACsecRule::keyNumTags)
.def_readwrite("maskNumTags", &MACsecRule::maskNumTags)
.def_readwrite("keyExpress", &MACsecRule::keyExpress)
.def_readwrite("maskExpress", &MACsecRule::maskExpress)
.def_readwrite("isMpls", &MACsecRule::isMpls)
.def_readwrite("enable", &MACsecRule::enable);
pybind11::class_<MACsecMap, std::shared_ptr<MACsecMap>>(m, "MACsecMap")
.def(pybind11::init())
.def_readwrite("index", &MACsecMap::index)
.def_readwrite("secTagSci", &MACsecMap::secTagSci)
.def_readwrite("secYIndex", &MACsecMap::secYIndex)
.def_readwrite("isControlPacket", &MACsecMap::isControlPacket)
.def_readwrite("scIndex", &MACsecMap::scIndex)
.def_readwrite("auxiliaryPlcy", &MACsecMap::auxiliaryPlcy)
.def_readwrite("ruleId", &MACsecMap::ruleId)
.def_readwrite("enable", &MACsecMap::enable);
pybind11::class_<MACsecSecY, std::shared_ptr<MACsecSecY>>(m, "MACsecSecY")
.def(pybind11::init())
.def_readwrite("index", &MACsecSecY::index)
.def_readwrite("controlledPortEnabled", &MACsecSecY::controlledPortEnabled)
.def_readwrite("frameValidationType", &MACsecSecY::frameValidationType)
.def_readwrite("secTagIcvStripType", &MACsecSecY::secTagIcvStripType)
.def_readwrite("cipher", &MACsecSecY::cipher)
.def_readwrite("confidentialOffset", &MACsecSecY::confidentialOffset)
.def_readwrite("icvIncludesDaSa", &MACsecSecY::icvIncludesDaSa)
.def_readwrite("replayProtect", &MACsecSecY::replayProtect)
.def_readwrite("replayWindow", &MACsecSecY::replayWindow)
.def_readwrite("protectFrames", &MACsecSecY::protectFrames)
.def_readwrite("secTagOffset", &MACsecSecY::secTagOffset)
.def_readwrite("secTagTci", &MACsecSecY::secTagTci)
.def_readwrite("mtu", &MACsecSecY::mtu)
.def_readwrite("enable", &MACsecSecY::enable);
pybind11::class_<MACsecSc, std::shared_ptr<MACsecSc>>(m, "MACsecSc")
.def(pybind11::init())
.def_readwrite("index", &MACsecSc::index)
.def_readwrite("secYIndex", &MACsecSc::secYIndex)
.def_readwrite("sci", &MACsecSc::sci)
.def_readwrite("saIndex0", &MACsecSc::saIndex0)
.def_readwrite("saIndex1", &MACsecSc::saIndex1)
.def_readwrite("saIndex0InUse", &MACsecSc::saIndex0InUse)
.def_readwrite("saIndex1InUse", &MACsecSc::saIndex1InUse)
.def_readwrite("enableAutoRekey", &MACsecSc::enableAutoRekey)
.def_readwrite("isActiveSa1", &MACsecSc::isActiveSa1)
.def_readwrite("enable", &MACsecSc::enable);
pybind11::class_<MACsecSa, std::shared_ptr<MACsecSa>>(m, "MACsecSa")
.def(pybind11::init())
.def_readwrite("index", &MACsecSa::index)
.def_readwrite("sak", &MACsecSa::sak)
.def_readwrite("hashKey", &MACsecSa::hashKey)
.def_readwrite("salt", &MACsecSa::salt)
.def_readwrite("ssci", &MACsecSa::ssci)
.def_readwrite("an", &MACsecSa::an)
.def_readwrite("nextPn", &MACsecSa::nextPn)
.def_readwrite("enable", &MACsecSa::enable);
pybind11::class_<MACSecFlags, std::shared_ptr<MACSecFlags>>(m, "MACSecFlags")
.def(pybind11::init())
.def_readwrite("en", &MACSecFlags::en);
pybind11::class_<MACsecConfig, std::shared_ptr<MACsecConfig>>(m, "MACsecConfig")
.def(pybind11::init())
.def_readwrite("flags", &MACsecConfig::flags)
.def_readwrite("rule", &MACsecConfig::rule)
.def_readwrite("map", &MACsecConfig::map)
.def_readwrite("secy", &MACsecConfig::secy)
.def_readwrite("sc", &MACsecConfig::sc)
.def_readwrite("sa", &MACsecConfig::sa);
pybind11::class_<MACSecGlobalFlags, std::shared_ptr<MACSecGlobalFlags>>(m, "MACSecGlobalFlags")
.def(pybind11::init())
.def_readwrite("en", &MACSecGlobalFlags::en)
.def_readwrite("nvm", &MACSecGlobalFlags::nvm);
pybind11::class_<MACsecMessage, std::shared_ptr<MACsecMessage>>(m, "MACsecMessage")
.def(pybind11::init())
.def_readwrite("flags", &MACsecMessage::flags)
.def_readwrite("rx", &MACsecMessage::rx)
.def_readwrite("tx", &MACsecMessage::tx);
}
} // namespace icsneo
@@ -7,7 +7,7 @@
namespace icsneo {
void init_mdiomessage(pybind11::module_& m) {
pybind11::class_<MDIOMessage, std::shared_ptr<MDIOMessage>, Frame> mdioMessage(m, "MDIOMessage");
pybind11::classh<MDIOMessage, Frame> mdioMessage(m, "MDIOMessage");
pybind11::enum_<MDIOMessage::Clause>(mdioMessage, "Clause")
.value("Clause45", MDIOMessage::Clause::Clause45)
.value("Clause22", MDIOMessage::Clause::Clause22);
@@ -1,14 +1,16 @@
#include <pybind11/pybind11.h>
#include <pybind11/stl.h>
#include <pybind11/functional.h>
#include <pybind11/native_enum.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")
// Using py::smart_holder for safer lifetime management
pybind11::classh<Message> message(m, "Message");
pybind11::native_enum<Message::Type>(message, "Type", "enum.IntEnum")
.value("Frame", Message::Type::Frame)
.value("CANErrorCount", Message::Type::CANErrorCount)
.value("CANError", Message::Type::CANError)
@@ -34,17 +36,18 @@ void init_message(pybind11::module_& m) {
.value("TC10Status", Message::Type::TC10Status)
.value("AppError", Message::Type::AppError)
.value("GPTPStatus", Message::Type::GPTPStatus)
.value("EthernetStatus", Message::Type::EthernetStatus);
.value("EthernetStatus", Message::Type::EthernetStatus)
.finalize();
message.def(pybind11::init<Message::Type>());
message.def_readonly("type", &Message::type);
message.def_readwrite("timestamp", &Message::timestamp);
pybind11::class_<RawMessage, std::shared_ptr<RawMessage>, Message>(m, "RawMessage")
pybind11::classh<RawMessage, Message>(m, "RawMessage")
.def_readwrite("network", &RawMessage::network)
.def_readwrite("data", &RawMessage::data);
pybind11::class_<Frame, std::shared_ptr<Frame>, RawMessage>(m, "Frame")
pybind11::classh<Frame, RawMessage>(m, "Frame")
.def_readwrite("description", &Frame::description)
.def_readwrite("transmitted", &Frame::transmitted)
.def_readwrite("error", &Frame::error);
@@ -7,7 +7,7 @@
namespace icsneo {
void init_scriptstatusmessage(pybind11::module_& m) {
pybind11::class_<ScriptStatusMessage, std::shared_ptr<ScriptStatusMessage>, Message>(m, "ScriptStatusMessage")
pybind11::classh<ScriptStatusMessage, Message>(m, "ScriptStatusMessage")
.def_readonly("isEncrypted", &ScriptStatusMessage::isEncrypted)
.def_readonly("isCoreminiRunning", &ScriptStatusMessage::isCoreminiRunning)
.def_readonly("sectorOverflows", &ScriptStatusMessage::sectorOverflows)
@@ -7,7 +7,7 @@
namespace icsneo {
void init_spimessage(pybind11::module_& m) {
pybind11::class_<SPIMessage, std::shared_ptr<SPIMessage>, Frame> spiMessage(m, "SPIMessage");
pybind11::classh<SPIMessage, Frame> spiMessage(m, "SPIMessage");
pybind11::enum_<SPIMessage::Direction>(spiMessage, "Direction")
.value("Write", SPIMessage::Direction::Write)
.value("Read", SPIMessage::Direction::Read);
@@ -17,7 +17,7 @@ void init_tc10statusmessage(pybind11::module_& m) {
.value("SleepFailed", TC10SleepStatus::SleepFailed)
.value("SleepAborted", TC10SleepStatus::SleepAborted);
pybind11::class_<TC10StatusMessage, std::shared_ptr<TC10StatusMessage>, Message>(m, "TC10StatusMessage")
pybind11::classh<TC10StatusMessage, Message>(m, "TC10StatusMessage")
.def_readonly("wakeStatus", &TC10StatusMessage::wakeStatus)
.def_readonly("sleepStatus", &TC10StatusMessage::sleepStatus);
}
@@ -1,15 +1,16 @@
#include <pybind11/pybind11.h>
#include <pybind11/stl.h>
#include <pybind11/functional.h>
#include <pybind11/native_enum.h>
#include "icsneo/communication/network.h"
namespace icsneo {
void init_network(pybind11::module_& m) {
pybind11::class_<Network> network(m, "Network");
pybind11::classh<Network> network(m, "Network");
pybind11::enum_<Network::NetID>(network, "NetID")
pybind11::native_enum<Network::NetID>(network, "NetID", "enum.IntEnum")
.value("Device", Network::NetID::Device)
.value("DWCAN_01", Network::NetID::DWCAN_01)
.value("DWCAN_08", Network::NetID::DWCAN_08)
@@ -166,9 +167,10 @@ void init_network(pybind11::module_& m) {
.value("LIN_15", Network::NetID::LIN_15)
.value("LIN_16", Network::NetID::LIN_16)
.value("Any", Network::NetID::Any)
.value("Invalid", Network::NetID::Invalid);
.value("Invalid", Network::NetID::Invalid)
.finalize();
pybind11::enum_<Network::Type>(network, "Type")
pybind11::native_enum<Network::Type>(network, "Type", "enum.Enum")
.value("Invalid", Network::Type::Invalid)
.value("Internal", Network::Type::Internal)
.value("CAN", Network::Type::CAN)
@@ -185,7 +187,8 @@ void init_network(pybind11::module_& m) {
.value("MDIO", Network::Type::MDIO)
.value("AutomotiveEthernet", Network::Type::AutomotiveEthernet)
.value("Any", Network::Type::Any)
.value("Other", Network::Type::Other);
.value("Other", Network::Type::Other)
.finalize();
network
.def(pybind11::init<Network::NetID>())
+166
View File
@@ -0,0 +1,166 @@
#include <pybind11/pybind11.h>
#include <pybind11/stl.h>
#include <pybind11/functional.h>
#include "icsneo/core/macseccfg.h"
namespace icsneo {
void init_macsecconfig(pybind11::module_ & m)
{
pybind11::enum_<MACsecPacketType>(m, "MACsecPacketType")
.value("DEFAULT", MACsecPacketType::Default)
.value("SINGLE_VLAN", MACsecPacketType::SingleVLAN)
.value("DUAL_VLAN", MACsecPacketType::DualVLAN)
.value("MPLS", MACsecPacketType::MPLS)
.value("SINGLE_VLAN_FOLLOWED_BY_MPLS", MACsecPacketType::SingleVLANFollowedByMPLS)
.value("DUAL_VLAN_FOLLOWED_BY_MPLS", MACsecPacketType::DualVLANFollowedByMPLS)
.value("UNSUPPORTED", MACsecPacketType::Unsupported);
pybind11::enum_<MACsecValidation>(m, "MACsecValidation")
.value("DISABLED", MACsecValidation::Disabled)
.value("CHECK", MACsecValidation::Check)
.value("STRICT", MACsecValidation::Strict)
.value("NA", MACsecValidation::NA);
pybind11::enum_<MACsecStrip>(m, "MACsecStrip")
.value("STRIP_SECTAG_AND_ICV", MACsecStrip::StripSecTagAndIcv)
.value("STRIP_SECTAG_PRESERVE_ICV", MACsecStrip::StripSecTagPreserveICV)
.value("PRESERVE_SECTAG_STRIP_ICV", MACsecStrip::PreserveSecTagStripICV)
.value("NO_STRIP", MACsecStrip::NoStrip);
pybind11::enum_<MACsecCipherSuite>(m, "MACsecCipherSuite")
.value("GCM_AES_128", MACsecCipherSuite::GcmAes128)
.value("GCM_AES_256", MACsecCipherSuite::GcmAes256)
.value("GCM_AES_128_XPN", MACsecCipherSuite::GcmAes128Xpn)
.value("GCM_AES_256_XPN", MACsecCipherSuite::GcmAes256Xpn);
pybind11::classh<MACsecVLANTag>(m, "MACsecVLANTag")
.def(pybind11::init())
.def_readwrite("vid", &MACsecVLANTag::vid)
.def_readwrite("pri_cfi", &MACsecVLANTag::priCfi);
pybind11::classh<MACsecMPLSOuter>(m, "MACsecMPLSOuter")
.def(pybind11::init())
.def_readwrite("mpls_label", &MACsecMPLSOuter::mplsLabel)
.def_readwrite("exp", &MACsecMPLSOuter::exp);
pybind11::classh<MACsecTci>(m, "MACsecTci")
.def(pybind11::init())
.def_readwrite("es", &MACsecTci::es)
.def_readwrite("sc", &MACsecTci::sc)
.def_readwrite("scb", &MACsecTci::scb)
.def_readwrite("e", &MACsecTci::e)
.def_readwrite("c", &MACsecTci::c);
pybind11::classh<MACsecRxRule>(m, "MACsecRxRule")
.def(pybind11::init())
.def_readwrite("key_mac_da", &MACsecRxRule::keyMacDa)
.def_readwrite("mask_mac_da", &MACsecRxRule::maskMacDa)
.def_readwrite("key_mask_sa", &MACsecRxRule::keyMacSa)
.def_readwrite("mask_mac_sa", &MACsecRxRule::maskMacSa)
.def_readwrite("key_ether_type", &MACsecRxRule::keyEthertype)
.def_readwrite("mask_ether_type", &MACsecRxRule::maskEthertype)
.def_readwrite("key_vlan_tag_outer1", &MACsecRxRule::keyVlanTagOuter1)
.def_readwrite("key_mpls_outer1", &MACsecRxRule::keyMplsOuter1)
.def_readwrite("mask_vlan_tag_outer1", &MACsecRxRule::maskVlanTagOuter1)
.def_readwrite("mask_mpls_outer1", &MACsecRxRule::maskMplsOuter1)
.def_readwrite("key_vlan_tag_outer2", &MACsecRxRule::keyVlanTagOuter2)
.def_readwrite("key_mpls_outer2", &MACsecRxRule::keyMplsOuter2)
.def_readwrite("mask_vlan_tag_outer2", &MACsecRxRule::maskVlanTagOuter2)
.def_readwrite("mask_mpls_outer2", &MACsecRxRule::maskMplsOuter2)
.def_readwrite("key_bonus_data", &MACsecRxRule::keyBonusData)
.def_readwrite("mask_bonus_data", &MACsecRxRule::maskBonusData)
.def_readwrite("key_tag_match_bitmap", &MACsecRxRule::keyTagMatchBitmap)
.def_readwrite("mask_tag_match_bitmap", &MACsecRxRule::maskTagMatchBitmap)
.def_readwrite("key_packet_type", &MACsecRxRule::keyPacketType)
.def_readwrite("mask_packet_type", &MACsecRxRule::maskPacketType)
.def_readwrite("key_inner_vlan_type", &MACsecRxRule::keyInnerVlanType)
.def_readwrite("mask_inner_vlan_type", &MACsecRxRule::maskInnerVlanType)
.def_readwrite("key_outer_vlan_type", &MACsecRxRule::keyOuterVlanType)
.def_readwrite("mask_outer_vlan_type", &MACsecRxRule::maskOuterVlanType)
.def_readwrite("key_num_tags", &MACsecRxRule::keyNumTags)
.def_readwrite("mask_num_tags", &MACsecRxRule::maskNumTags)
.def_readwrite("key_express", &MACsecRxRule::keyExpress)
.def_readwrite("mask_express", &MACsecRxRule::maskExpress)
.def_readwrite("is_mpls", &MACsecRxRule::isMpls);
pybind11::classh<MACsecTxSecY>(m, "MACsecTxSecY")
.def(pybind11::init())
.def_readwrite("enable_control_port", &MACsecTxSecY::enableControlPort)
.def_readwrite("cipher", &MACsecTxSecY::cipher)
.def_readwrite("confidentiality_offset", &MACsecTxSecY::confidentialityOffset)
.def_readwrite("icv_includes_da_sa", &MACsecTxSecY::icvIncludesDaSa)
.def_readwrite("protect_frames", &MACsecTxSecY::protectFrames)
.def_readwrite("sec_tag_offset", &MACsecTxSecY::secTagOffset)
.def_readwrite("sec_tag_tci", &MACsecTxSecY::tci)
.def_readwrite("mtu", &MACsecTxSecY::mtu)
.def_readwrite("is_control_packet", &MACsecTxSecY::isControlPacket)
.def_readwrite("auxiliary_policy", &MACsecTxSecY::auxiliaryPolicy)
.def_readwrite("sci", &MACsecTxSecY::sci);
pybind11::classh<MACsecRxSecY>(m, "MACsecRxSecY")
.def(pybind11::init())
.def_readwrite("enable_control_port", &MACsecRxSecY::enableControlPort)
.def_readwrite("frame_validation", &MACsecRxSecY::frameValidation)
.def_readwrite("frame_strip", &MACsecRxSecY::frameStrip)
.def_readwrite("cipher", &MACsecRxSecY::cipher)
.def_readwrite("confidentiality_offset", &MACsecRxSecY::confidentialityOffset)
.def_readwrite("icv_includes_da_sa", &MACsecRxSecY::icvIncludesDaSa)
.def_readwrite("replay_protect", &MACsecRxSecY::replayProtect)
.def_readwrite("replay_window", &MACsecRxSecY::replayWindow)
.def_readwrite("is_control_packet", &MACsecRxSecY::isControlPacket)
.def_readwrite("sci", &MACsecRxSecY::sci);
pybind11::classh<MACsecTxSa>(m, "MACsecTxSa")
.def(pybind11::init())
.def_readwrite("sak", &MACsecTxSa::sak)
.def_readwrite("hash_key", &MACsecTxSa::hashKey)
.def_readwrite("salt", &MACsecTxSa::salt)
.def_readwrite("ssci", &MACsecTxSa::ssci)
.def_readwrite("next_pn", &MACsecTxSa::nextPn)
.def_readwrite("an", &MACsecTxSa::an);
pybind11::classh<MACsecRxSa>(m, "MACsecRxSa")
.def(pybind11::init())
.def_readwrite("sak", &MACsecRxSa::sak)
.def_readwrite("hash_key", &MACsecRxSa::hashKey)
.def_readwrite("salt", &MACsecRxSa::salt)
.def_readwrite("ssci", &MACsecRxSa::ssci)
.def_readwrite("next_pn", &MACsecRxSa::nextPn);
pybind11::classh<MACsecConfig>(m, "MACsecConfig")
.def(pybind11::init<icsneo::DeviceType>())
.def("add_rx_secy", &MACsecConfig::addRxSecY, pybind11::call_guard<pybind11::gil_scoped_release>())
.def("add_tx_secY", &MACsecConfig::addTxSecY, pybind11::call_guard<pybind11::gil_scoped_release>())
.def("add_rx_rule", &MACsecConfig::addRxRule, pybind11::call_guard<pybind11::gil_scoped_release>())
.def("add_rx_sa", &MACsecConfig::addRxSa, pybind11::call_guard<pybind11::gil_scoped_release>())
.def("add_tx_sa", &MACsecConfig::addTxSa, pybind11::call_guard<pybind11::gil_scoped_release>())
.def("get_rx_secy", [](MACsecConfig& cfg, uint8_t index) -> MACsecRxSecY& { return cfg.getRxSecY(index); }, pybind11::call_guard<pybind11::gil_scoped_release>())
.def("get_tx_secy", [](MACsecConfig& cfg, uint8_t index) -> MACsecTxSecY& { return cfg.getTxSecY(index); }, pybind11::call_guard<pybind11::gil_scoped_release>())
.def("get_rx_sa", [](MACsecConfig& cfg, uint8_t index) -> MACsecRxSa& { return cfg.getRxSa(index); }, pybind11::call_guard<pybind11::gil_scoped_release>())
.def("get_tx_sa", [](MACsecConfig& cfg, uint8_t index) -> MACsecTxSa& { return cfg.getTxSa(index); }, pybind11::call_guard<pybind11::gil_scoped_release>())
.def("get_rx_rule", [](MACsecConfig& cfg, uint8_t index) -> MACsecRxRule& { return cfg.getRxRule(index); }, pybind11::call_guard<pybind11::gil_scoped_release>())
.def("set_tx_sa_index", &MACsecConfig::setTxSaIndex, pybind11::call_guard<pybind11::gil_scoped_release>())
.def("enable_tx_rekey", &MACsecConfig::enableTxRekey, pybind11::call_guard<pybind11::gil_scoped_release>())
.def("set_tx_sa_rekey_index", &MACsecConfig::setTxSaRekeyIndex, pybind11::call_guard<pybind11::gil_scoped_release>())
.def("disable_tx_rekey", &MACsecConfig::disableTxRekey, pybind11::call_guard<pybind11::gil_scoped_release>())
.def("set_rx_sa_index", &MACsecConfig::setRxSaIndex, pybind11::call_guard<pybind11::gil_scoped_release>())
.def("enable_rx_rekey", &MACsecConfig::enableRxRekey, pybind11::call_guard<pybind11::gil_scoped_release>())
.def("set_rx_sa_rekey_index", &MACsecConfig::setRxSaRekeyIndex, pybind11::call_guard<pybind11::gil_scoped_release>())
.def("disable_rx_rekey", &MACsecConfig::disableRxRekey, pybind11::call_guard<pybind11::gil_scoped_release>())
.def("set_rx_enable", &MACsecConfig::setRxEnable, pybind11::call_guard<pybind11::gil_scoped_release>())
.def("set_tx_enable", &MACsecConfig::setTxEnable, pybind11::call_guard<pybind11::gil_scoped_release>())
.def("set_storage", &MACsecConfig::setStorage, pybind11::call_guard<pybind11::gil_scoped_release>())
.def("clear", &MACsecConfig::clear, pybind11::call_guard<pybind11::gil_scoped_release>())
.def("serialize", &MACsecConfig::serialize, pybind11::call_guard<pybind11::gil_scoped_release>())
.def("get_bin_index", &MACsecConfig::getBinIndex, pybind11::call_guard<pybind11::gil_scoped_release>())
.def("get_type", &MACsecConfig::getType, pybind11::call_guard<pybind11::gil_scoped_release>())
.def("get_max_num_rule", &MACsecConfig::getMaxNumRule, pybind11::call_guard<pybind11::gil_scoped_release>())
.def("get_max_num_secy", &MACsecConfig::getMaxNumSecY, pybind11::call_guard<pybind11::gil_scoped_release>())
.def("get_max_num_sa", &MACsecConfig::getMaxNumSa, pybind11::call_guard<pybind11::gil_scoped_release>());
}
} // namespace icsneo
+11 -4
View File
@@ -1,13 +1,14 @@
#include <pybind11/pybind11.h>
#include <pybind11/stl.h>
#include <pybind11/functional.h>
#include <pybind11/native_enum.h>
#include "icsneo/device/chipid.h"
namespace icsneo {
void init_chipid(pybind11::module_& m) {
pybind11::enum_<ChipID>(m, "ChipID")
pybind11::native_enum<ChipID>(m, "ChipID", "enum.IntEnum")
.value("neoVIFIRE_MCHIP", ChipID::neoVIFIRE_MCHIP)
.value("neoVIFIRE_LCHIP", ChipID::neoVIFIRE_LCHIP)
.value("neoVIFIRE_UCHIP", ChipID::neoVIFIRE_UCHIP)
@@ -102,7 +103,7 @@ void init_chipid(pybind11::module_& m) {
.value("neoOBD2Dev_MCHIP", ChipID::neoOBD2Dev_MCHIP)
.value("neoOBD2Dev_SCHIP", ChipID::neoOBD2Dev_SCHIP)
.value("neoOBD2SIMDoIP_MCHIP", ChipID::neoOBD2SIMDoIP_MCHIP)
.value("SFPModule_MCHIP", ChipID::SFPModule_MCHIP)
.value("SFPModule_88q2112_MCHIP", ChipID::SFPModule_88q2112_MCHIP)
.value("RADEpsilonT_MCHIP", ChipID::RADEpsilonT_MCHIP)
.value("RADEpsilonExpress_MCHIP", ChipID::RADEpsilonExpress_MCHIP)
.value("RADProxima_MCHIP", ChipID::RADProxima_MCHIP)
@@ -110,7 +111,7 @@ void init_chipid(pybind11::module_& m) {
.value("RAD_GALAXY_2_ZMPCHIP_ID", ChipID::RAD_GALAXY_2_ZMPCHIP_ID)
.value("NewDevice59_MCHIP", ChipID::NewDevice59_MCHIP)
.value("RADMoon2_Z7010_ZYNQ", ChipID::RADMoon2_Z7010_ZYNQ)
.value("neoVIFIRE2_CORE_SG4", ChipID::neoVIFIRE2_CORE_SG4)
.value("neoVIFIRE2_Core_SG4", ChipID::neoVIFIRE2_Core_SG4)
.value("RADBMS_MCHIP", ChipID::RADBMS_MCHIP)
.value("RADMoon2_ZL_MCHIP", ChipID::RADMoon2_ZL_MCHIP)
.value("RADGigastar_USBZ_Z7010_ZYNQ", ChipID::RADGigastar_USBZ_Z7010_ZYNQ)
@@ -125,11 +126,17 @@ void init_chipid(pybind11::module_& m) {
.value("RADGigastar_FFG_ZYNQ", ChipID::RADGigastar_FFG_ZYNQ)
.value("VEM_02_FR_FCHIP", ChipID::VEM_02_FR_FCHIP)
.value("Connect_ZCHIP", ChipID::Connect_ZCHIP)
.value("SFPModule_88q2221_MCHIP", ChipID::SFPModule_88q2221_MCHIP)
.value("RADGALAXY2_SYSMON_CHIP", ChipID::RADGALAXY2_SYSMON_CHIP)
.value("SFPModule_88q3244_MCHIP", ChipID::SFPModule_88q3244_MCHIP)
.value("RADCOMET3_ZCHIP", ChipID::RADCOMET3_ZCHIP)
.value("Connect_LINUX", ChipID::Connect_LINUX)
.value("SFPModule_lan8670_MCHIP", ChipID::SFPModule_lan8670_MCHIP)
.value("RADGigastar2_ZYNQ", ChipID::RADGigastar2_ZYNQ)
.value("Invalid", ChipID::Invalid);
.value("SFPModule_ent11100_MCHIP", ChipID::SFPModule_ent11100_MCHIP)
.value("RADGemini_MCHIP", ChipID::RADGemini_MCHIP)
.value("Invalid", ChipID::Invalid)
.finalize();
}
} // namespace icsneo
+14 -1
View File
@@ -5,13 +5,14 @@
#include "icsneo/device/device.h"
#include "icsneo/device/extensions/deviceextension.h"
#include "icsneo/disk/diskdetails.h"
#include <fstream>
namespace icsneo {
void init_device(pybind11::module_& m) {
pybind11::class_<Device, std::shared_ptr<Device>>(m, "Device")
pybind11::classh<Device>(m, "Device")
.def("__repr__", &Device::describe)
.def("add_message_callback", &Device::addMessageCallback, pybind11::call_guard<pybind11::gil_scoped_release>())
.def("clear_script", &Device::clearScript, pybind11::call_guard<pybind11::gil_scoped_release>())
@@ -31,6 +32,8 @@ void init_device(pybind11::module_& m) {
.def("get_script_status", &Device::getScriptStatus, pybind11::call_guard<pybind11::gil_scoped_release>())
.def("get_serial_number", &Device::getSerialNumber)
.def("get_serial", &Device::getSerial)
.def("get_pcb_serial", &Device::getPCBSerial, pybind11::call_guard<pybind11::gil_scoped_release>())
.def("get_mac_address", &Device::getMACAddress, 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_tc10_status", &Device::getTC10Status, pybind11::call_guard<pybind11::gil_scoped_release>())
@@ -52,11 +55,21 @@ void init_device(pybind11::module_& m) {
.def("start_script", &Device::startScript, pybind11::call_guard<pybind11::gil_scoped_release>())
.def("stop_script", &Device::stopScript, pybind11::call_guard<pybind11::gil_scoped_release>())
.def("supports_tc10", &Device::supportsTC10)
.def("supports_live_data", &Device::supportsLiveData)
.def("subscribe_live_data", &Device::subscribeLiveData, pybind11::arg("message"), pybind11::call_guard<pybind11::gil_scoped_release>())
.def("unsubscribe_live_data", &Device::unsubscribeLiveData, pybind11::arg("handle"), pybind11::call_guard<pybind11::gil_scoped_release>())
.def("clear_all_live_data", &Device::clearAllLiveData, pybind11::call_guard<pybind11::gil_scoped_release>())
.def("set_value_live_data", &Device::setValueLiveData, pybind11::arg("message"), pybind11::call_guard<pybind11::gil_scoped_release>())
.def("transmit", pybind11::overload_cast<std::shared_ptr<Frame>>(&Device::transmit), pybind11::call_guard<pybind11::gil_scoped_release>())
.def("upload_coremini", [](Device& device, std::string& path, Disk::MemoryType memType) { std::ifstream ifs(path, std::ios::binary); return device.uploadCoremini(ifs, memType); }, pybind11::call_guard<pybind11::gil_scoped_release>())
.def("write_macsec_config", &Device::writeMACsecConfig, pybind11::call_guard<pybind11::gil_scoped_release>())
.def("send_eth_phy_msg", &Device::sendEthPhyMsg, pybind11::arg("message"), pybind11::arg("timeout") = std::chrono::milliseconds(50), pybind11::call_guard<pybind11::gil_scoped_release>())
.def("get_chip_versions", &Device::getChipVersions, pybind11::arg("refreshComponents") = true, pybind11::call_guard<pybind11::gil_scoped_release>())
.def("supports_disk_formatting", &Device::supportsDiskFormatting, pybind11::call_guard<pybind11::gil_scoped_release>())
.def("get_disk_count", &Device::getDiskCount, pybind11::call_guard<pybind11::gil_scoped_release>())
.def("get_disk_details", &Device::getDiskDetails, pybind11::arg("timeout") = std::chrono::milliseconds(100), pybind11::call_guard<pybind11::gil_scoped_release>())
.def("force_disk_config_update", &Device::forceDiskConfigUpdate, pybind11::arg("config"), pybind11::call_guard<pybind11::gil_scoped_release>())
.def("format_disk", [](Device& device, const DiskDetails& config) -> bool { return device.formatDisk(config); }, pybind11::arg("config"), pybind11::call_guard<pybind11::gil_scoped_release>())
.def_readonly("settings", &Device::settings);
}
@@ -1,14 +1,15 @@
#include <pybind11/pybind11.h>
#include <pybind11/stl.h>
#include <pybind11/functional.h>
#include <pybind11/native_enum.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")
pybind11::classh<DeviceType> deviceType(m, "DeviceType");
pybind11::native_enum<DeviceType::Enum>(deviceType, "Enum", "enum.IntEnum")
.value("Unknown", DeviceType::Enum::Unknown)
.value("BLUE", DeviceType::Enum::BLUE)
.value("ECU_AVB", DeviceType::Enum::ECU_AVB)
@@ -36,6 +37,7 @@ void init_devicetype(pybind11::module_& m) {
.value("RADEpsilonXL", DeviceType::Enum::RADEpsilonXL)
.value("RADGalaxy2", DeviceType::Enum::RADGalaxy2)
.value("RADMoon3", DeviceType::Enum::RADMoon3)
.value("RADGemini", DeviceType::Enum::RADGemini)
.value("RADComet", DeviceType::Enum::RADComet)
.value("FIRE3_FlexRay", DeviceType::Enum::FIRE3_FlexRay)
.value("FIRE3_T1S_LIN", DeviceType::Enum::FIRE3_T1S_LIN)
@@ -69,7 +71,8 @@ void init_devicetype(pybind11::module_& m) {
.value("RADGalaxy", DeviceType::Enum::RADGalaxy)
.value("RADStar2", DeviceType::Enum::RADStar2)
.value("VividCAN", DeviceType::Enum::VividCAN)
.value("OBD2_SIM", DeviceType::Enum::OBD2_SIM);
.value("OBD2_SIM", DeviceType::Enum::OBD2_SIM)
.finalize();
deviceType.def(pybind11::init<DeviceType::Enum>());
deviceType.def("get_device_type", &DeviceType::getDeviceType);
deviceType.def("get_generic_product_name", &DeviceType::getGenericProductName);
@@ -7,7 +7,7 @@
namespace icsneo {
void init_deviceextension(pybind11::module_& m) {
pybind11::class_<DeviceExtension, std::shared_ptr<DeviceExtension>>(m, "DeviceExtension")
pybind11::classh<DeviceExtension>(m, "DeviceExtension")
.def("get_name", &DeviceExtension::getName);
}
@@ -12,35 +12,117 @@ namespace icsneo {
struct DeviceSettingsNamespace {
using EthLinkMode = AELinkMode;
using LinkSpeed = EthLinkSpeed;
};
void init_idevicesettings(pybind11::module_& m) {
pybind11::class_<DeviceSettingsNamespace> settings(m, "Settings");
pybind11::classh<DeviceSettingsNamespace> settings(m, "Settings");
pybind11::enum_<DeviceSettingsNamespace::EthLinkMode>(settings, "EthernetLinkMode")
.value("Auto", DeviceSettingsNamespace::EthLinkMode::AE_LINK_AUTO)
.value("Slave", DeviceSettingsNamespace::EthLinkMode::AE_LINK_SLAVE)
.value("Master", DeviceSettingsNamespace::EthLinkMode::AE_LINK_MASTER);
pybind11::enum_<DeviceSettingsNamespace::LinkSpeed>(settings, "EthernetLinkSpeed")
.value("Speed10M", DeviceSettingsNamespace::LinkSpeed::ETH_SPEED_10)
.value("Speed100M", DeviceSettingsNamespace::LinkSpeed::ETH_SPEED_100)
.value("Speed1G", DeviceSettingsNamespace::LinkSpeed::ETH_SPEED_1000)
.value("Speed2_5G", DeviceSettingsNamespace::LinkSpeed::ETH_SPEED_2500)
.value("Speed5G", DeviceSettingsNamespace::LinkSpeed::ETH_SPEED_5000)
.value("Speed10G", DeviceSettingsNamespace::LinkSpeed::ETH_SPEED_10000);
pybind11::enum_<EthPhyLinkMode>(settings, "PhyLinkMode")
.value("ETH_LINK_MODE_AUTO_NEGOTIATION", ETH_LINK_MODE_AUTO_NEGOTIATION)
.value("ETH_LINK_MODE_10MBPS_HALFDUPLEX", ETH_LINK_MODE_10MBPS_HALFDUPLEX)
.value("ETH_LINK_MODE_10MBPS_FULLDUPLEX", ETH_LINK_MODE_10MBPS_FULLDUPLEX)
.value("ETH_LINK_MODE_100MBPS_HALFDUPLEX", ETH_LINK_MODE_100MBPS_HALFDUPLEX)
.value("ETH_LINK_MODE_100MBPS_FULLDUPLEX", ETH_LINK_MODE_100MBPS_FULLDUPLEX)
.value("ETH_LINK_MODE_1GBPS_HALFDUPLEX", ETH_LINK_MODE_1GBPS_HALFDUPLEX)
.value("ETH_LINK_MODE_1GBPS_FULLDUPLEX", ETH_LINK_MODE_1GBPS_FULLDUPLEX)
.value("ETH_LINK_MODE_2_5GBPS_FULLDUPLEX", ETH_LINK_MODE_2_5GBPS_FULLDUPLEX)
.value("ETH_LINK_MODE_5GBPS_FULLDUPLEX", ETH_LINK_MODE_5GBPS_FULLDUPLEX)
.value("ETH_LINK_MODE_10GBPS_FULLDUPLEX", ETH_LINK_MODE_10GBPS_FULLDUPLEX);
pybind11::class_<IDeviceSettings, std::shared_ptr<IDeviceSettings>>(m, "IDeviceSettings")
pybind11::enum_<LINMode>(settings, "LINMode")
.value("Sleep", LINMode::SLEEP_MODE)
.value("Slow", LINMode::SLOW_MODE)
.value("Normal", LINMode::NORMAL_MODE)
.value("Fast", LINMode::FAST_MODE);
pybind11::enum_<MiscIOAnalogVoltage>(settings, "MiscIOAnalogVoltage")
.value("V0", MiscIOAnalogVoltage::V0)
.value("V1", MiscIOAnalogVoltage::V1)
.value("V2", MiscIOAnalogVoltage::V2)
.value("V3", MiscIOAnalogVoltage::V3)
.value("V4", MiscIOAnalogVoltage::V4)
.value("V5", MiscIOAnalogVoltage::V5);
pybind11::classh<IDeviceSettings>(m, "IDeviceSettings")
.def("apply", &IDeviceSettings::apply, pybind11::arg("temporary") = 0, pybind11::call_guard<pybind11::gil_scoped_release>())
.def("apply_defaults", &IDeviceSettings::applyDefaults, pybind11::arg("temporary") = 0, pybind11::call_guard<pybind11::gil_scoped_release>())
.def("refresh", &IDeviceSettings::refresh, pybind11::call_guard<pybind11::gil_scoped_release>())
// Baudrate methods
.def("get_baudrate", &IDeviceSettings::getBaudrateFor, pybind11::call_guard<pybind11::gil_scoped_release>())
.def("set_baudrate", &IDeviceSettings::setBaudrateFor, pybind11::call_guard<pybind11::gil_scoped_release>())
.def("get_fd_baudrate", &IDeviceSettings::getFDBaudrateFor, pybind11::call_guard<pybind11::gil_scoped_release>())
.def("set_fd_baudrate", &IDeviceSettings::setFDBaudrateFor, pybind11::call_guard<pybind11::gil_scoped_release>())
// Termination methods
.def("is_termination_supported", &IDeviceSettings::isTerminationSupportedFor, pybind11::call_guard<pybind11::gil_scoped_release>())
.def("can_termination_be_enabled", &IDeviceSettings::canTerminationBeEnabledFor, pybind11::call_guard<pybind11::gil_scoped_release>())
.def("is_termination_enabled", &IDeviceSettings::isTerminationEnabledFor, pybind11::call_guard<pybind11::gil_scoped_release>())
.def("set_termination", &IDeviceSettings::setTerminationFor, pybind11::call_guard<pybind11::gil_scoped_release>())
.def("get_termination_groups", &IDeviceSettings::getTerminationGroups, pybind11::call_guard<pybind11::gil_scoped_release>())
// LIN methods
.def("is_commander_resistor_enabled", &IDeviceSettings::isCommanderResistorEnabledFor, pybind11::call_guard<pybind11::gil_scoped_release>())
.def("set_commander_resistor", &IDeviceSettings::setCommanderResistorFor, pybind11::call_guard<pybind11::gil_scoped_release>())
.def("get_lin_mode", &IDeviceSettings::getLINModeFor, pybind11::call_guard<pybind11::gil_scoped_release>())
.def("set_lin_mode", &IDeviceSettings::setLINModeFor, pybind11::call_guard<pybind11::gil_scoped_release>())
.def("get_lin_commander_response_time", &IDeviceSettings::getLINCommanderResponseTimeFor, pybind11::call_guard<pybind11::gil_scoped_release>())
.def("set_lin_commander_response_time", &IDeviceSettings::setLINCommanderResponseTimeFor, pybind11::call_guard<pybind11::gil_scoped_release>())
// Ethernet PHY methods (index-based for switch devices)
.def("get_phy_enable", &IDeviceSettings::getPhyEnable, pybind11::call_guard<pybind11::gil_scoped_release>())
.def("get_phy_mode", &IDeviceSettings::getPhyMode, pybind11::call_guard<pybind11::gil_scoped_release>())
.def("get_phy_speed", &IDeviceSettings::getPhySpeed, pybind11::call_guard<pybind11::gil_scoped_release>())
.def("set_phy_enable", &IDeviceSettings::setPhyEnable, pybind11::call_guard<pybind11::gil_scoped_release>())
.def("set_phy_mode", &IDeviceSettings::setPhyMode, pybind11::call_guard<pybind11::gil_scoped_release>())
.def("set_phy_speed", &IDeviceSettings::setPhySpeed, pybind11::call_guard<pybind11::gil_scoped_release>())
.def("refresh", &IDeviceSettings::refresh, pybind11::call_guard<pybind11::gil_scoped_release>());
// Ethernet PHY methods (network-based for multi-interface devices)
.def("get_phy_enable_for", &IDeviceSettings::getPhyEnableFor, pybind11::call_guard<pybind11::gil_scoped_release>())
.def("get_phy_role_for", &IDeviceSettings::getPhyRoleFor, pybind11::call_guard<pybind11::gil_scoped_release>())
.def("get_phy_link_mode_for", &IDeviceSettings::getPhyLinkModeFor, pybind11::call_guard<pybind11::gil_scoped_release>())
.def("set_phy_enable_for", &IDeviceSettings::setPhyEnableFor, pybind11::call_guard<pybind11::gil_scoped_release>())
.def("set_phy_role_for", &IDeviceSettings::setPhyRoleFor, pybind11::call_guard<pybind11::gil_scoped_release>())
.def("set_phy_link_mode_for", &IDeviceSettings::setPhyLinkModeFor, pybind11::call_guard<pybind11::gil_scoped_release>())
.def("get_supported_phy_link_modes_for", &IDeviceSettings::getSupportedPhyLinkModesFor, pybind11::call_guard<pybind11::gil_scoped_release>())
// 10BASE-T1S methods
.def("is_t1s_plca_enabled", &IDeviceSettings::isT1SPLCAEnabledFor, pybind11::call_guard<pybind11::gil_scoped_release>())
.def("set_t1s_plca", &IDeviceSettings::setT1SPLCAFor, pybind11::call_guard<pybind11::gil_scoped_release>())
.def("get_t1s_local_id", &IDeviceSettings::getT1SLocalIDFor, pybind11::call_guard<pybind11::gil_scoped_release>())
.def("set_t1s_local_id", &IDeviceSettings::setT1SLocalIDFor, pybind11::call_guard<pybind11::gil_scoped_release>())
.def("get_t1s_max_nodes", &IDeviceSettings::getT1SMaxNodesFor, pybind11::call_guard<pybind11::gil_scoped_release>())
.def("set_t1s_max_nodes", &IDeviceSettings::setT1SMaxNodesFor, pybind11::call_guard<pybind11::gil_scoped_release>())
.def("get_t1s_tx_opp_timer", &IDeviceSettings::getT1STxOppTimerFor, pybind11::call_guard<pybind11::gil_scoped_release>())
.def("set_t1s_tx_opp_timer", &IDeviceSettings::setT1STxOppTimerFor, pybind11::call_guard<pybind11::gil_scoped_release>())
.def("get_t1s_max_burst", &IDeviceSettings::getT1SMaxBurstFor, pybind11::call_guard<pybind11::gil_scoped_release>())
.def("set_t1s_max_burst", &IDeviceSettings::setT1SMaxBurstFor, pybind11::call_guard<pybind11::gil_scoped_release>())
.def("get_t1s_burst_timer", &IDeviceSettings::getT1SBurstTimerFor, pybind11::call_guard<pybind11::gil_scoped_release>())
.def("set_t1s_burst_timer", &IDeviceSettings::setT1SBurstTimerFor, pybind11::call_guard<pybind11::gil_scoped_release>())
.def("get_t1s_local_id_alternate", &IDeviceSettings::getT1SLocalIDAlternateFor, pybind11::call_guard<pybind11::gil_scoped_release>())
.def("set_t1s_local_id_alternate", &IDeviceSettings::setT1SLocalIDAlternateFor, pybind11::call_guard<pybind11::gil_scoped_release>())
.def("is_t1s_termination_enabled", &IDeviceSettings::isT1STerminationEnabledFor, pybind11::call_guard<pybind11::gil_scoped_release>())
.def("set_t1s_termination", &IDeviceSettings::setT1STerminationFor, pybind11::call_guard<pybind11::gil_scoped_release>())
.def("is_t1s_bus_decoding_beacons_enabled", &IDeviceSettings::isT1SBusDecodingBeaconsEnabledFor, pybind11::call_guard<pybind11::gil_scoped_release>())
.def("set_t1s_bus_decoding_beacons", &IDeviceSettings::setT1SBusDecodingBeaconsFor, pybind11::call_guard<pybind11::gil_scoped_release>())
.def("is_t1s_bus_decoding_all_enabled", &IDeviceSettings::isT1SBusDecodingAllEnabledFor, pybind11::call_guard<pybind11::gil_scoped_release>())
.def("set_t1s_bus_decoding_all", &IDeviceSettings::setT1SBusDecodingAllFor, pybind11::call_guard<pybind11::gil_scoped_release>())
.def("get_t1s_multi_id_enable_mask", &IDeviceSettings::getT1SMultiIDEnableMaskFor, pybind11::call_guard<pybind11::gil_scoped_release>())
.def("set_t1s_multi_id_enable_mask", &IDeviceSettings::setT1SMultiIDEnableMaskFor, pybind11::call_guard<pybind11::gil_scoped_release>())
.def("get_t1s_multi_id", &IDeviceSettings::getT1SMultiIDFor, pybind11::call_guard<pybind11::gil_scoped_release>())
.def("set_t1s_multi_id", &IDeviceSettings::setT1SMultiIDFor, pybind11::call_guard<pybind11::gil_scoped_release>())
.def("set_misc_io_analog_output_enabled", &IDeviceSettings::setMiscIOAnalogOutputEnabled, pybind11::call_guard<pybind11::gil_scoped_release>())
.def("set_misc_io_analog_output", &IDeviceSettings::setMiscIOAnalogOutput, pybind11::call_guard<pybind11::gil_scoped_release>())
// Status properties
.def_readonly("disabled", &IDeviceSettings::disabled)
.def_readonly("readonly", &IDeviceSettings::readonly);
}
} // namespace icsneo
@@ -7,7 +7,7 @@
namespace icsneo {
void init_versionreport(pybind11::module_& m) {
pybind11::class_<VersionReport>(m, "VersionReport")
pybind11::classh<VersionReport>(m, "VersionReport")
.def_readonly("id", &VersionReport::id)
.def_readonly("name", &VersionReport::name)
.def_readonly("major", &VersionReport::major)
@@ -0,0 +1,29 @@
#include <pybind11/pybind11.h>
#include <pybind11/stl.h>
#include "icsneo/disk/diskdetails.h"
namespace icsneo {
void init_diskdetails(pybind11::module_& m) {
pybind11::enum_<DiskLayout>(m, "DiskLayout")
.value("Spanned", DiskLayout::Spanned)
.value("RAID0", DiskLayout::RAID0);
pybind11::classh<DiskInfo>(m, "DiskInfo")
.def(pybind11::init())
.def_readwrite("present", &DiskInfo::present)
.def_readwrite("initialized", &DiskInfo::initialized)
.def_readwrite("formatted", &DiskInfo::formatted)
.def_readwrite("sectors", &DiskInfo::sectors)
.def_readwrite("bytes_per_sector", &DiskInfo::bytesPerSector)
.def("size", &DiskInfo::size);
pybind11::classh<DiskDetails>(m, "DiskDetails")
.def(pybind11::init())
.def_readwrite("layout", &DiskDetails::layout)
.def_readwrite("full_format", &DiskDetails::fullFormat)
.def_readwrite("disks", &DiskDetails::disks);
}
} // namespace icsneo
+1 -1
View File
@@ -13,7 +13,7 @@ struct DiskNamespace {
};
void init_diskdriver(pybind11::module_& m) {
pybind11::class_<DiskNamespace> disk(m, "Disk");
pybind11::classh<DiskNamespace> disk(m, "Disk");
pybind11::enum_<Disk::Access>(disk, "Access")
.value("None", Disk::Access::None)
.value("EntireCard", Disk::Access::EntireCard)
+13 -9
View File
@@ -23,8 +23,8 @@ struct ClusterNamespace {
using SPPType = icsneo::FlexRay::Cluster::SPPType;
};
void init_extension(pybind11::class_<FlexRayNamespace>& c) {
pybind11::class_<MessageBuffer, std::shared_ptr<MessageBuffer>>(c, "MessageBuffer")
void init_extension(pybind11::classh<FlexRayNamespace>& c) {
pybind11::classh<MessageBuffer>(c, "MessageBuffer")
.def(pybind11::init())
.def_readwrite("is_dynamic", &MessageBuffer::isDynamic)
.def_readwrite("is_sync", &MessageBuffer::isSync)
@@ -39,7 +39,7 @@ void init_extension(pybind11::class_<FlexRayNamespace>& c) {
.def_readwrite("cycle_repetition", &MessageBuffer::cycleRepetition)
.def_readwrite("continuous_mode", &MessageBuffer::continuousMode);
auto controller = pybind11::class_<Controller, std::shared_ptr<Controller>>(c, "Controller")
auto controller = pybind11::classh<Controller>(c, "Controller")
.def("get_network", &Controller::getNetwork)
.def("get_configuration", &Controller::getConfiguration)
.def("set_configuration", &Controller::setConfiguration)
@@ -59,11 +59,12 @@ void init_extension(pybind11::class_<FlexRayNamespace>& c) {
.def("freeze", &Controller::freeze)
.def("trigger_mts", &Controller::triggerMTS);
pybind11::class_<Controller::Configuration>(controller, "Configuration")
pybind11::classh<Controller::Configuration>(controller, "Configuration")
.def(pybind11::init())
.def_readwrite("accept_startup_range_microticks", &Controller::Configuration::AcceptStartupRangeMicroticks)
.def_readwrite("allow_passive_to_active_cycle_pairs", &Controller::Configuration::AllowPassiveToActiveCyclePairs)
.def_readwrite("cluster_drift_damping", &Controller::Configuration::ClusterDriftDamping)
.def_readwrite("allow_halt_due_to_clock", &Controller::Configuration::AllowHaltDueToClock)
.def_readwrite("channel_a", &Controller::Configuration::ChannelA)
.def_readwrite("channel_b", &Controller::Configuration::ChannelB)
.def_readwrite("decoding_correction_microticks", &Controller::Configuration::DecodingCorrectionMicroticks)
@@ -74,6 +75,7 @@ void init_extension(pybind11::class_<FlexRayNamespace>& c) {
.def_readwrite("extern_offset_correction_microticks", &Controller::Configuration::ExternOffsetCorrectionMicroticks)
.def_readwrite("extern_rate_correction_microticks", &Controller::Configuration::ExternRateCorrectionMicroticks)
.def_readwrite("key_slot_id", &Controller::Configuration::KeySlotID)
.def_readwrite("key_slot_only_enabled", &Controller::Configuration::KeySlotOnlyEnabled)
.def_readwrite("key_slot_used_for_startup", &Controller::Configuration::KeySlotUsedForStartup)
.def_readwrite("key_slot_used_for_sync", &Controller::Configuration::KeySlotUsedForSync)
.def_readwrite("latest_tx_minislot", &Controller::Configuration::LatestTxMinislot)
@@ -93,7 +95,7 @@ void init_extension(pybind11::class_<FlexRayNamespace>& c) {
.def_readwrite("wakeup_on_channel_b", &Controller::Configuration::WakeupOnChannelB);
// Dummy class for cluster namespace
pybind11::class_<ClusterNamespace> cluster(c, "Cluster");
pybind11::classh<ClusterNamespace> cluster(c, "Cluster");
pybind11::enum_<Cluster::SpeedType>(cluster, "SpeedType")
.value("FLEXRAY_BAUDRATE_10M", Cluster::SpeedType::FLEXRAY_BAUDRATE_10M)
@@ -107,13 +109,14 @@ void init_extension(pybind11::class_<FlexRayNamespace>& c) {
.value("FLEXRAY_SPP_6", Cluster::SPPType::FLEXRAY_SPP_6)
.value("FLEXRAY_SPP_5_ALT", Cluster::SPPType::FLEXRAY_SPP_5_ALT);
pybind11::class_<Cluster::Configuration>(cluster, "Configuration")
pybind11::classh<Cluster::Configuration>(cluster, "Configuration")
.def(pybind11::init())
.def_readwrite("speed", &Cluster::Configuration::Speed)
.def_readwrite("strobe_point_position", &Cluster::Configuration::StrobePointPosition)
.def_readwrite("action_point_offset", &Cluster::Configuration::ActionPointOffset)
.def_readwrite("casr_x_low_max", &Cluster::Configuration::CASRxLowMax)
.def_readwrite("cold_start_attempts", &Cluster::Configuration::ColdStartAttempts)
.def_readwrite("cycle_duration_micro_sec", &Cluster::Configuration::CycleDurationMicroSec)
.def_readwrite("dynamic_slot_idle_phase_minislots", &Cluster::Configuration::DynamicSlotIdlePhaseMinislots)
.def_readwrite("listen_noise_macroticks", &Cluster::Configuration::ListenNoiseMacroticks)
.def_readwrite("macroticks_per_cycle", &Cluster::Configuration::MacroticksPerCycle)
@@ -143,7 +146,7 @@ void init_extension(pybind11::class_<FlexRayNamespace>& c) {
} // namespace FlexRay
void init_flexraymessage(pybind11::module_& m) {
pybind11::class_<FlexRayMessage, std::shared_ptr<FlexRayMessage>, Frame>(m, "FlexRayMessage")
pybind11::classh<FlexRayMessage, Frame>(m, "FlexRayMessage")
.def(pybind11::init())
.def_readwrite("slotid", &FlexRayMessage::slotid)
.def_readwrite("tsslen", &FlexRayMessage::tsslen)
@@ -159,14 +162,15 @@ void init_flexraymessage(pybind11::module_& m) {
.def_readwrite("sync_frame", &FlexRayMessage::sync)
.def_readwrite("startup_frame", &FlexRayMessage::startup)
.def_readwrite("dynamic_frame", &FlexRayMessage::dynamic)
.def_readwrite("cycle", &FlexRayMessage::cycle);
.def_readwrite("cycle", &FlexRayMessage::cycle)
.def_readwrite("cycle_repetition", &FlexRayMessage::cycleRepetition);
//// TODO: Eliminate FlexRayControlMessage class references in controller class and eliminate getStatus function in bindings
}
void init_flexray(pybind11::module_& m) {
// Dummy class to act as FlexRay namespace
pybind11::class_<FlexRayNamespace> flexray(m, "FlexRay");
pybind11::classh<FlexRayNamespace> flexray(m, "FlexRay");
pybind11::enum_<FlexRayNamespace::Symbol>(flexray, "Symbol")
.value("None", FlexRayNamespace::Symbol::None)
+8 -2
View File
@@ -22,9 +22,10 @@ void init_gptpstatusmessage(pybind11::module_&);
void init_mdiomessage(pybind11::module_&);
void init_spimessage(pybind11::module_&);
void init_ethernetstatusmessage(pybind11::module_&);
void init_macsecmessage(pybind11::module_&);
void init_macsecconfig(pybind11::module_&);
void init_scriptstatusmessage(pybind11::module_&);
void init_diskdriver(pybind11::module_&);
void init_diskdetails(pybind11::module_&);
void init_deviceextension(pybind11::module_&);
void init_chipid(pybind11::module_&);
void init_versionreport(pybind11::module_&);
@@ -35,6 +36,8 @@ void init_version(pybind11::module_&);
void init_flexray(pybind11::module_& m);
void init_idevicesettings(pybind11::module_&);
void init_ethphymessage(pybind11::module_&);
void init_livedata(pybind11::module_&);
void init_livedatamessage(pybind11::module_&);
PYBIND11_MODULE(icsneopy, m) {
pybind11::options options;
@@ -48,6 +51,7 @@ PYBIND11_MODULE(icsneopy, m) {
init_devicetype(m);
init_network(m);
init_io(m);
init_livedata(m);
init_message(m);
init_canmessage(m);
init_canerrormessage(m);
@@ -57,12 +61,14 @@ PYBIND11_MODULE(icsneopy, m) {
init_gptpstatusmessage(m);
init_mdiomessage(m);
init_ethernetstatusmessage(m);
init_macsecmessage(m);
init_macsecconfig(m);
init_scriptstatusmessage(m);
init_spimessage(m);
init_livedatamessage(m);
init_messagefilter(m);
init_messagecallback(m);
init_diskdriver(m);
init_diskdetails(m);
init_flexray(m);
init_ethphymessage(m);
init_chipid(m);
+5 -1
View File
@@ -326,11 +326,15 @@ bool Decoder::decode(std::shared_ptr<Message>& result, const std::shared_ptr<Pac
case ExtendedCommand::GenericBinaryInfo:
result = GenericBinaryStatusPacket::DecodeToMessage(packet->data);
return true;
case ExtendedCommand::SoftwareUpdate: {
result = std::make_shared<ExtendedResponseMessage>(ExtendedCommand::SoftwareUpdate, ExtendedResponse::OperationPending, packet->data);
return true;
}
case ExtendedCommand::GenericReturn: {
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);
result = std::make_shared<ExtendedResponseMessage>(packedResp.command, packedResp.returnCode, packet->data);
return true;
}
case ExtendedCommand::LiveData:
+2
View File
@@ -56,6 +56,7 @@ bool Encoder::encode(const Packetizer& packetizer, std::vector<uint8_t>& result,
break;
}
case Network::Type::Internal:
case Network::Type::CAN:
case Network::Type::SWCAN:
case Network::Type::LSFTCAN: {
@@ -284,6 +285,7 @@ bool Encoder::encode(const Packetizer& packetizer, std::vector<uint8_t>& result,
case Command::RequestSerialNumber:
case Command::EnableNetworkCommunication:
case Command::EnableNetworkCommunicationEx:
case Command::KeepAlive:
case Command::GetMainVersion:
case Command::GetSecondaryVersions:
case Command::NeoReadMemory:
+6 -5
View File
@@ -19,7 +19,8 @@ double liveDataValueToDouble(const LiveDataValue& val) {
return val.value * liveDataFixedPointToDouble;
}
bool liveDataDoubleToValue(const double& dFloat, LiveDataValue& value) {
std::optional<LiveDataValue> liveDataDoubleToValue(const double& dFloat) {
LiveDataValue value;
union {
struct
{
@@ -56,23 +57,23 @@ bool liveDataDoubleToValue(const double& dFloat, LiveDataValue& value) {
value.value = CminiFixedPt.ValueLarge;
if(dFloat == (double)0.0)
return true;
return value;
//check if double can be stored as 32.32
// 0x1 0000 0000 0000 0000 * CM_FIXED_POINT_TO_DOUBLEVALUE = 0x1 0000 0000
if(dFloat > INT32_MAX_DOUBLE || dFloat < INT32_MIN_DOUBLE) {
EventManager::GetInstance().add(APIEvent::Type::FixedPointOverflow, APIEvent::Severity::Error);
return false;
return std::nullopt;
}
// Use absolute value for minimum fixed point check
double absFloat = (dFloat < 0.0) ? -dFloat : dFloat;
if(absFloat < MIN_FIXED_POINT_DOUBLE) {
EventManager::GetInstance().add(APIEvent::Type::FixedPointPrecision, APIEvent::Severity::Error);
return false;
return std::nullopt;
}
return true;
return value;
}
} // namespace LiveDataUtil
@@ -18,6 +18,7 @@ enum TLinkMode {
T_LINK_MASTER,
T_LINK_SLAVE,
T_LINK_AUTO,
T_LINK_INVALID = 255,
};
enum AELinkMode {
@@ -60,6 +61,7 @@ std::shared_ptr<Message> EthernetStatusMessage::DecodeToMessage(const std::vecto
case T_LINK_MASTER: mode = EthernetStatusMessage::LinkMode::LinkModeMaster; break;
case T_LINK_SLAVE: mode = EthernetStatusMessage::LinkMode::LinkModeSlave; break;
case T_LINK_AUTO: mode = EthernetStatusMessage::LinkMode::LinkModeAuto; break;
case T_LINK_INVALID: mode = EthernetStatusMessage::LinkMode::LinkModeInvalid; break;
default: return nullptr;
}
break;
-531
View File
@@ -1,531 +0,0 @@
#include "icsneo/communication/message/macsecmessage.h"
#include "icsneo/communication/crc32.h"
#include <memory>
#include <cstdint>
#include <iostream>
#include <cstring>
namespace icsneo
{
#ifdef _MSC_VER
#pragma warning(push)
#pragma warning(disable : 4201) // nameless struct/union
#endif
#pragma pack(push, 1)
/* MACsec Rule */
/**
* @brief Structure of Vlan tag
*
*/
typedef struct
{
uint16_t vid; /*!< 12 bits */
uint8_t priCfi; /*!< PRI - 3 bits, CFI - 1bit */
} MACSEC_VLANTAG_t;
/**
* @brief Structure of MPLS
*
*/
typedef struct
{
uint32_t mplsLabel; /*!< 20 bits */
uint8_t exp; /*!< 3 bits */
} MACSEC_MPLS_OUTER_t;
/**
* @brief Define Encoded Packet Type from the parser
*
*/
static constexpr int MACSEC_SETTINGS_RULE_SIZE = 88;
typedef union _MACSecRule
{
struct
{
uint8_t index;
uint8_t keyMacDa[6]; /*!< MAC DA field extracted from the packet */
uint8_t maskMacDa[6]; /*!< Set bits to 1 to mask/exclude corresponding flowid_tcam_data bit from compare */
uint8_t keyMacSa[6]; /*!< MAC SA field extracted from the packet */
uint8_t maskMacSa[6]; /*!< Set bits to 1 to mask/exclude corresponding flowid_tcam_data bit from compare */
uint16_t keyEthertype; /*!< First E-Type found in the packet that doesn't match one of the preconfigured custom tag. */
uint16_t maskEthertype; /*!< Set bits to 1 to mask/exclude corresponding flowid_tcam_data bit from compare */
MACSEC_VLANTAG_t keyVlanTagOuter1; /*!< outermost/1st VLAN ID {8'd0, VLAN_ID[11:0]}, or 20-bit MPLS label. */
MACSEC_MPLS_OUTER_t keyMplsOuter1;
MACSEC_VLANTAG_t maskVlanTagOuter1; /*!< Set bits to 1 to mask/exclude corresponding flowid_tcam_data bit from compare */
MACSEC_MPLS_OUTER_t maskMplsOuter1;
MACSEC_VLANTAG_t keyVlanTagOuter2; /*!< 2nd outermost VLAN ID {8'd0, VLAN_ID[11:0]}, or 20-bit MPLS label. */
MACSEC_MPLS_OUTER_t keyMplsOuter2;
MACSEC_VLANTAG_t maskVlanTagOuter2; /*!< Set bits to 1 to mask/exclude corresponding flowid_tcam_data bit from compare */
MACSEC_MPLS_OUTER_t maskMplsOuter2;
uint16_t keyBonusData; /*!< 2 bytes of additional bonus data extracted from one of the custom tags. */
uint16_t maskBonusData; /*!< Set bits to 1 to mask/exclude corresponding flowid_tcam_data bit from compare */
uint8_t
keyTagMatchBitmap; /*!< 8 bits total. Maps 1 to 1 bitwise with the set of custom tags. (set bit[N]=1 if check Nth custom tag) */
uint8_t maskTagMatchBitmap; /*!< Set bits to 1 to mask/exclude corresponding flowid_tcam_data bit from compare */
uint8_t keyPacketType; /*!< Encoded Packet Type, see MACSEC_PACKET_TYPE */
uint8_t maskPacketType; /*!< Set bits to 1 to mask/exclude corresponding flowid_tcam_data bit from compare */
uint16_t
keyInnerVlanType; /*!< 3 bits total. Encoded value indicating which VLAN TPID value matched for the second outermost VLAN Tag. */
uint16_t maskInnerVlanType; /*!< Set bits to 1 to mask/exclude corresponding flowid_tcam_data bit from compare */
uint16_t keyOuterVlanType; /*!< 3 bits total. Encoded value indicating which VLAN TPID value matched for the outermost VLAN Tag. */
uint16_t maskOuterVlanType; /*!< Set bits to 1 to mask/exclude corresponding flowid_tcam_data bit from compare */
uint8_t
keyNumTags; /*!< 7 bits total. Number of VLAN/custom tags or MPLS lables detected. Ingress: before SecTag; Egress: total detected. Exclude MCS header tags. i.e. Bit 2: 2 tags/labels before SecTAG...Bit 6: 6 or more tags/labels before SecTAG. */
uint8_t maskNumTags; /*!< Set bits to 1 to mask/exclude corresponding flowid_tcam_data bit from compare */
uint8_t keyExpress; /*!< 1 bits. Express packet. */
uint8_t maskExpress; /*!< Set bits to 1 to mask/exclude corresponding flowid_tcam_data bit from compare */
uint8_t isMpls;
uint8_t rsvd[5];
uint8_t enable;
};
uint8_t byte[MACSEC_SETTINGS_RULE_SIZE];
} MACSecRule_t;
/* MACsec Map */
static constexpr int MACSEC_SETTINGS_MAP_SIZE = 20;
typedef union _MACSecMap
{
struct
{
uint8_t index;
uint64_t secTagSci; /*!< Identifies the SecTAG SCI for this Flow. */
uint8_t secYIndex; /*!< index for entry in Egress secY Policy */
uint8_t isControlPacket; /*!< Identifies all packets matching this index lookup as control packets. */
uint8_t scIndex; /*!< Identifies the SC for this Flow. */
uint8_t auxiliaryPlcy; /*!< Auxiliary policy bits. */
uint8_t ruleId; /*!< Identifies the Rule for this Flow. */
uint8_t rsvd[5];
uint8_t enable;
};
uint8_t byte[MACSEC_SETTINGS_MAP_SIZE];
} MACSecMap_t;
/* MACsec SecY */
/**
* @brief Define the permit police for frames as defined in 802.1ae
*
*/
static constexpr int MACSEC_SETTINGS_SECY_SIZE = 24;
typedef union _MACSecSecY
{
struct
{
uint8_t index; /*!< Identifies the SecY for this Flow. */
uint8_t controlledPortEnabled; /*!< Enable (or disable) operation of the Controlled port associated with this SecY */
uint8_t frameValidationType; /*!< see MACSEC_VALIDATEFRAME */
uint8_t secTagIcvStripType; /*!< see MACSEC_STRIP_SECTAG_ICV */
uint8_t cipher; /*!< Define the cipher suite to use for this SecY see MACSEC_CIPHER_SUITE */
uint8_t confidentialOffset; /*!< Define the number of bytes that are unencrypted following the SecTag. */
uint8_t icvIncludesDaSa; /*!< When set, the outer DA/SA bytes are included in the authentication GHASH calculation */
uint8_t replayProtect; /*!< Enables Anti-Replay protection */
uint32_t replayWindow; /*!< Unsigned value indicating the size of the anti-replay window. */
uint8_t
protectFrames; /*!< 0 = do not encrypt or authenticate this packet; 1 = always Authenticate frame and if SecTag.TCI.E = 1 encrypt the packet as well. */
uint8_t
secTagOffset; /*!< Define the offset in bytes from either the start of the packet or a matching Etype depending on SecTag_Insertion_Mode. */
uint8_t secTagTci; /*!< Tag Control Information excluding the AN field which originates from the SA Policy table */
uint16_t mtu; /*!< Specifies the outgoing MTU for this SecY */
uint8_t rsvd[6];
uint8_t enable;
};
uint8_t byte[MACSEC_SETTINGS_SECY_SIZE];
} MACSecSecY_t;
/* MACsec SC */
static constexpr int MACSEC_SETTINGS_SC_SIZE = 24;
typedef union _MACSecSc
{
struct
{
uint8_t index; /*!< SC index. */
uint8_t secYIndex; /*!< SecY associated with this packet. */
uint64_t sci; /*!< The Secure Channel Identifier. */
uint8_t saIndex0; /*!< Define the 1st SA to use */
uint8_t saIndex1; /*!< Define the 2nd SA to use */
uint8_t saIndex0InUse; /*!< Specifies whether 1st SA is in use or not. */
uint8_t saIndex1InUse; /*!< Specifies whether 2nd SA is in use or not. */
uint8_t enableAutoRekey; /*!< If enabled, then once the pn_threshold is reached, auto rekey will happen. */
uint8_t
isActiveSa1; /*!< If set, then sa_index1 is the currently active SA index. If cleared, the sa_index0 is the currently active SA index). */
uint8_t rsvd[7];
uint8_t enable;
};
uint8_t byte[MACSEC_SETTINGS_SC_SIZE];
} MACSecSc_t;
/* MACsec SA */
static constexpr int MACSEC_SETTINGS_SA_SIZE = 80;
typedef union _MACSecSa
{
struct
{
uint8_t index; /*!< SA index */
uint8_t
sak[32]; /*!< 256b SAK: Define the encryption key to be used to encrypte this packet. The lower 128 bits are used for 128-bit ciphers. */
uint8_t hashKey[16]; /*!< 128b Hash Key: Key used for authentication. */
uint8_t salt[12]; /*!< 96b Salt value: Salt value used in XPN ciphers. */
uint32_t ssci; /*!< 32b SSCI value: Short Secure Channel Identifier, used in XPN ciphers. */
uint8_t an; /*!< 2b SecTag Association Number (AN) */
uint64_t nextPn; /*!< 64b next_pn value: Next packet number to insert into outgoing packet on a particular SA. */
uint8_t rsvd[5];
uint8_t enable;
};
uint8_t byte[MACSEC_SETTINGS_SA_SIZE];
} MACSecSa_t;
/* MACsec Flags */
typedef union _MACSecFlags
{
struct
{
uint32_t en : 1; // '1' = enable; '0' = disable
uint32_t reserved : 31;
};
uint32_t flags_32b;
} MACSecFlags_t;
#define MACSEC_SETTINGS_FLAGS_SIZE (4)
/* MACSec Settings for 1 port/phy */
typedef struct MACSEC_CONFIG_t
{
MACSecFlags_t flags;
MACSecRule_t rule[MACsecConfig::NumRules];
MACSecMap_t map[MACsecConfig::NumMaps];
MACSecSecY_t secy[MACsecConfig::NumSecY];
MACSecSc_t sc[MACsecConfig::NumSc];
MACSecSa_t sa[MACsecConfig::NumSa];
} MACSEC_CONFIG;
typedef union _MACSecGlobalFlags
{
struct
{
uint32_t en : 1; // '1' = enable; '0' = disable
uint32_t nvm : 1; // store macsec config in non-volatile memory
uint32_t reserved : 30;
};
uint32_t flags_32b;
} MACSecGlobalFlags_t;
#define MACSEC_SETTINGS_SIZE (2040) // leave space for expansion and keep nicely aligned for flashing
typedef union _MACSEC_SETTINGS
{
struct
{
MACSecGlobalFlags_t flags;
MACSEC_CONFIG rx;
MACSEC_CONFIG tx;
};
uint8_t byte[MACSEC_SETTINGS_SIZE];
} MACSEC_SETTINGS;
#define MACSEC_SETTINGS_VERSION 1
struct MACSEC_SETTINGS_W_HDR
{
uint16_t version;
uint16_t len;
uint32_t crc32;
MACSEC_SETTINGS macsec;
};
#pragma pack(pop)
#ifdef _MSC_VER
#pragma warning(pop)
#endif
std::shared_ptr<MACsecMessage> MACsecMessage::DecodeToMessage(const std::vector<uint8_t>& bytestream, const device_eventhandler_t& report)
{
if (bytestream.empty() || (bytestream.size() < sizeof(MACSEC_SETTINGS_W_HDR)))
{
report(APIEvent::Type::RequiredParameterNull, APIEvent::Severity::Error);
return nullptr;
}
MACSEC_SETTINGS_W_HDR* macsecArgs = (MACSEC_SETTINGS_W_HDR*)bytestream.data();
if (macsecArgs->version != MACSEC_SETTINGS_VERSION)
{
report(APIEvent::Type::SettingsVersionError, APIEvent::Severity::Error);
return nullptr;
}
if (macsecArgs->len != sizeof(MACSEC_SETTINGS))
{
report(APIEvent::Type::SettingsLengthError, APIEvent::Severity::Error);
return nullptr;
}
const auto crcCalculted = crc32(0, (uint8_t*)&macsecArgs->macsec, macsecArgs->len);
if (macsecArgs->crc32 != crcCalculted)
{
report(APIEvent::Type::SettingsChecksumError, APIEvent::Severity::Error);
return nullptr;
}
auto msg = std::make_shared<MACsecMessage>();
const auto& copyConfig = [](const MACSEC_CONFIG& source, MACsecConfig& dest)
{
dest.flags.en = source.flags.en;
for (int index = 0; index < MACsecConfig::NumRules; index++)
{
if(!source.rule[index].enable) continue;
#undef __COPY_ITEM
#define __COPY_ITEM(___name__) dest.rule[index].___name__ = (decltype(dest.rule[index].___name__))source.rule[index].___name__
#undef __COPY_ARR
#define __COPY_ARR(___name__) (void)memcpy(dest.rule[index].___name__.data(), source.rule[index].___name__, dest.rule[index].___name__.size())
__COPY_ITEM(index);
__COPY_ARR(keyMacDa);
__COPY_ARR(maskMacDa);
__COPY_ARR(keyMacSa);
__COPY_ARR(maskMacSa);
__COPY_ITEM(keyVlanTagOuter1.vid);
__COPY_ITEM(keyVlanTagOuter1.priCfi);
__COPY_ITEM(keyMplsOuter1.mplsLabel);
__COPY_ITEM(keyMplsOuter1.exp);
__COPY_ITEM(maskVlanTagOuter1.vid);
__COPY_ITEM(maskVlanTagOuter1.priCfi);
__COPY_ITEM(maskMplsOuter1.mplsLabel);
__COPY_ITEM(maskMplsOuter1.exp);
__COPY_ITEM(keyVlanTagOuter2.vid);
__COPY_ITEM(keyVlanTagOuter2.priCfi);
__COPY_ITEM(keyMplsOuter2.mplsLabel);
__COPY_ITEM(keyMplsOuter2.exp);
__COPY_ITEM(maskVlanTagOuter2.vid);
__COPY_ITEM(maskVlanTagOuter2.priCfi);
__COPY_ITEM(maskMplsOuter2.mplsLabel);
__COPY_ITEM(maskMplsOuter2.exp);
__COPY_ITEM(keyEthertype);
__COPY_ITEM(maskEthertype);
__COPY_ITEM(keyBonusData);
__COPY_ITEM(maskBonusData);
__COPY_ITEM(keyTagMatchBitmap);
__COPY_ITEM(maskTagMatchBitmap);
__COPY_ITEM(keyPacketType);
__COPY_ITEM(maskPacketType);
__COPY_ITEM(keyInnerVlanType);
__COPY_ITEM(maskInnerVlanType);
__COPY_ITEM(keyOuterVlanType);
__COPY_ITEM(maskOuterVlanType);
__COPY_ITEM(keyNumTags);
__COPY_ITEM(maskNumTags);
__COPY_ITEM(keyExpress);
__COPY_ITEM(maskExpress);
__COPY_ITEM(isMpls);
__COPY_ITEM(enable);
}
for (int index = 0; index < MACsecConfig::NumMaps; index++)
{
if(!source.map[index].enable) continue;
#undef __COPY_ITEM
#define __COPY_ITEM(___name__) dest.map[index].___name__ = source.map[index].___name__
__COPY_ITEM(index);
__COPY_ITEM(secTagSci);
__COPY_ITEM(secYIndex);
__COPY_ITEM(isControlPacket);
__COPY_ITEM(scIndex);
__COPY_ITEM(auxiliaryPlcy);
__COPY_ITEM(ruleId);
__COPY_ITEM(enable);
}
for (int index = 0; index < MACsecConfig::NumSecY; index++)
{
if(!source.secy[index].enable) continue;
#undef __COPY_ITEM
#define __COPY_ITEM(___name__) dest.secy[index].___name__ = (decltype(dest.secy[index].___name__))source.secy[index].___name__
__COPY_ITEM(index);
__COPY_ITEM(controlledPortEnabled);
__COPY_ITEM(frameValidationType);
__COPY_ITEM(secTagIcvStripType);
__COPY_ITEM(cipher);
__COPY_ITEM(confidentialOffset);
__COPY_ITEM(icvIncludesDaSa);
__COPY_ITEM(replayProtect);
__COPY_ITEM(replayWindow);
__COPY_ITEM(protectFrames);
__COPY_ITEM(secTagOffset);
__COPY_ITEM(secTagTci);
__COPY_ITEM(mtu);
__COPY_ITEM(enable);
}
for (int index = 0; index < MACsecConfig::NumSc; index++)
{
if(!source.sc[index].enable) continue;
#undef __COPY_ITEM
#define __COPY_ITEM(___name__) dest.sc[index].___name__ = source.sc[index].___name__
__COPY_ITEM(index);
__COPY_ITEM(secYIndex);
__COPY_ITEM(sci);
__COPY_ITEM(saIndex0);
__COPY_ITEM(saIndex1);
__COPY_ITEM(saIndex0InUse);
__COPY_ITEM(saIndex1InUse);
__COPY_ITEM(enableAutoRekey);
__COPY_ITEM(isActiveSa1);
__COPY_ITEM(enable);
}
for (int index = 0; index < MACsecConfig::NumSa; index++)
{
if(!source.sa[index].enable) continue;
#undef __COPY_ITEM
#define __COPY_ITEM(___name__) dest.sa[index].___name__ = source.sa[index].___name__
#undef __COPY_ARR
#define __COPY_ARR(___name__) (void)memcpy(dest.sa[index].___name__.data(), source.sa[index].___name__, dest.sa[index].___name__.size())
__COPY_ITEM(index);
__COPY_ARR(sak);
__COPY_ARR(hashKey);
__COPY_ARR(salt);
__COPY_ITEM(ssci);
__COPY_ITEM(an);
__COPY_ITEM(nextPn);
__COPY_ITEM(enable);
}
};
msg->flags.en = macsecArgs->macsec.flags.en;
copyConfig(macsecArgs->macsec.rx, msg->rx);
copyConfig(macsecArgs->macsec.tx, msg->tx);
return msg;
}
bool MACsecMessage::EncodeFromMessage(std::vector<uint8_t>& bytestream, const device_eventhandler_t& report) const
{
MACSEC_SETTINGS_W_HDR* macsecArgs;
bytestream.resize(sizeof(MACSEC_SETTINGS_W_HDR), 0);
macsecArgs = (MACSEC_SETTINGS_W_HDR*)bytestream.data();
macsecArgs->version = MACSEC_SETTINGS_VERSION;
macsecArgs->len = sizeof(MACSEC_SETTINGS_W_HDR);
const auto& copyConfig = [](const MACsecConfig& source, MACSEC_CONFIG& dest)
{
dest.flags.en = (uint8_t)source.flags.en;
for (int index = 0; index < MACsecConfig::NumRules; index++)
{
if(!source.rule[index].enable) continue;
#undef __COPY_ITEM
#define __COPY_ITEM(___name__) dest.rule[index].___name__ = (decltype(dest.rule[index].___name__))source.rule[index].___name__
#undef __COPY_ARR
#define __COPY_ARR(___name__) (void)memcpy(dest.rule[index].___name__, source.rule[index].___name__.data(), source.rule[index].___name__.size())
__COPY_ITEM(index);
__COPY_ARR(keyMacDa);
__COPY_ARR(maskMacDa);
__COPY_ARR(keyMacSa);
__COPY_ARR(maskMacSa);
__COPY_ITEM(keyVlanTagOuter1.vid);
__COPY_ITEM(keyVlanTagOuter1.priCfi);
__COPY_ITEM(keyMplsOuter1.mplsLabel);
__COPY_ITEM(keyMplsOuter1.exp);
__COPY_ITEM(maskVlanTagOuter1.vid);
__COPY_ITEM(maskVlanTagOuter1.priCfi);
__COPY_ITEM(maskMplsOuter1.mplsLabel);
__COPY_ITEM(maskMplsOuter1.exp);
__COPY_ITEM(keyVlanTagOuter2.vid);
__COPY_ITEM(keyVlanTagOuter2.priCfi);
__COPY_ITEM(keyMplsOuter2.mplsLabel);
__COPY_ITEM(keyMplsOuter2.exp);
__COPY_ITEM(maskVlanTagOuter2.vid);
__COPY_ITEM(maskVlanTagOuter2.priCfi);
__COPY_ITEM(maskMplsOuter2.mplsLabel);
__COPY_ITEM(maskMplsOuter2.exp);
__COPY_ITEM(keyEthertype);
__COPY_ITEM(maskEthertype);
__COPY_ITEM(keyBonusData);
__COPY_ITEM(maskBonusData);
__COPY_ITEM(keyTagMatchBitmap);
__COPY_ITEM(maskTagMatchBitmap);
__COPY_ITEM(keyPacketType);
__COPY_ITEM(maskPacketType);
__COPY_ITEM(keyInnerVlanType);
__COPY_ITEM(maskInnerVlanType);
__COPY_ITEM(keyOuterVlanType);
__COPY_ITEM(maskOuterVlanType);
__COPY_ITEM(keyNumTags);
__COPY_ITEM(maskNumTags);
__COPY_ITEM(keyExpress);
__COPY_ITEM(maskExpress);
__COPY_ITEM(isMpls);
__COPY_ITEM(enable);
}
for (int index = 0; index < MACsecConfig::NumMaps; index++)
{
if(!source.map[index].enable) continue;
#undef __COPY_ITEM
#define __COPY_ITEM(___name__) dest.map[index].___name__ = source.map[index].___name__
__COPY_ITEM(index);
__COPY_ITEM(secTagSci);
__COPY_ITEM(secYIndex);
__COPY_ITEM(isControlPacket);
__COPY_ITEM(scIndex);
__COPY_ITEM(auxiliaryPlcy);
__COPY_ITEM(ruleId);
__COPY_ITEM(enable);
}
for (int index = 0; index < MACsecConfig::NumSecY; index++)
{
if(!source.secy[index].enable) continue;
#undef __COPY_ITEM
#define __COPY_ITEM(___name__) dest.secy[index].___name__ = (decltype(dest.secy[index].___name__))source.secy[index].___name__
__COPY_ITEM(index);
__COPY_ITEM(controlledPortEnabled);
__COPY_ITEM(frameValidationType);
__COPY_ITEM(secTagIcvStripType);
__COPY_ITEM(cipher);
__COPY_ITEM(confidentialOffset);
__COPY_ITEM(icvIncludesDaSa);
__COPY_ITEM(replayProtect);
__COPY_ITEM(replayWindow);
__COPY_ITEM(protectFrames);
__COPY_ITEM(secTagOffset);
__COPY_ITEM(secTagTci);
__COPY_ITEM(mtu);
__COPY_ITEM(enable);
}
for (int index = 0; index < MACsecConfig::NumSc; index++)
{
if(!source.sc[index].enable) continue;
#undef __COPY_ITEM
#define __COPY_ITEM(___name__) dest.sc[index].___name__ = source.sc[index].___name__
__COPY_ITEM(index);
__COPY_ITEM(secYIndex);
__COPY_ITEM(sci);
__COPY_ITEM(saIndex0);
__COPY_ITEM(saIndex1);
__COPY_ITEM(saIndex0InUse);
__COPY_ITEM(saIndex1InUse);
__COPY_ITEM(enableAutoRekey);
__COPY_ITEM(isActiveSa1);
__COPY_ITEM(enable);
}
for (int index = 0; index < MACsecConfig::NumSa; index++)
{
if(!source.sa[index].enable) continue;
#undef __COPY_ITEM
#define __COPY_ITEM(___name__) dest.sa[index].___name__ = source.sa[index].___name__
#undef __COPY_ARR
#define __COPY_ARR(___name__) (void)memcpy(dest.sa[index].___name__, source.sa[index].___name__.data(), source.sa[index].___name__.size())
__COPY_ITEM(index);
__COPY_ARR(sak);
__COPY_ARR(hashKey);
__COPY_ARR(salt);
__COPY_ITEM(ssci);
__COPY_ITEM(an);
__COPY_ITEM(nextPn);
__COPY_ITEM(enable);
}
};
macsecArgs->macsec.flags.en = this->flags.en;
macsecArgs->macsec.flags.nvm = this->flags.nvm;
copyConfig(this->rx, macsecArgs->macsec.rx);
copyConfig(this->tx, macsecArgs->macsec.tx);
macsecArgs->crc32 = crc32(0, (uint8_t*)&macsecArgs->macsec, sizeof(MACSEC_SETTINGS));
(void)report;
return true;
}
} // namespace icsneo
+1 -1
View File
@@ -48,7 +48,7 @@ neomessage_t icsneo::CreateNeoMessage(const std::shared_ptr<Message> message) {
case Network::Type::AutomotiveEthernet: {
neomessage_eth_t& eth = *(neomessage_eth_t*)&neomsg;
auto ethmsg = std::static_pointer_cast<EthernetMessage>(message);
eth.preemptionFlags = ethmsg->preemptionFlags;
eth.preemptionFlags = ethmsg->preemptionFlags.value_or(0);
eth.status.incompleteFrame = ethmsg->frameTooShort;
// TODO Fill in extra status bits
//eth.status.xyz = ethmsg->preemptionEnabled;
+69 -29
View File
@@ -7,31 +7,6 @@
using namespace icsneo;
// copied.. TODO
static std::optional<uint8_t> CAN_LengthToDLC(size_t dataLength, bool fd) {
if(dataLength <= 8)
return uint8_t(dataLength);
if(fd) {
if(dataLength <= 12)
return uint8_t(0x9);
if(dataLength <= 16)
return uint8_t(0xA);
if(dataLength <= 20)
return uint8_t(0xB);
if(dataLength <= 24)
return uint8_t(0xC);
if(dataLength <= 32)
return uint8_t(0xD);
if(dataLength <= 48)
return uint8_t(0xE);
if(dataLength <= 64)
return uint8_t(0xF);
}
return std::nullopt;
}
static std::vector<uint8_t> EncodeFromMessageEthernet(std::shared_ptr<Frame> frame, const device_eventhandler_t& report) {
auto ethmsg = std::dynamic_pointer_cast<EthernetMessage>(frame);
if(!ethmsg) {
@@ -104,6 +79,7 @@ static std::vector<uint8_t> EncodeFromMessageCAN(std::shared_ptr<Frame> frame, c
canpacket->header.BRS = canmsg->baudrateSwitch ? 1 : 0;
canpacket->header.ESI = canmsg->errorStateIndicator ? 1 : 0;
canpacket->dlc.RTR = 0;
canpacket->timestamp.IsExtended = 1;
} else {
canpacket->header.EDL = 0;
@@ -126,10 +102,71 @@ static std::vector<uint8_t> EncodeFromMessageCAN(std::shared_ptr<Frame> frame, c
return encoded;
}
static std::vector<uint8_t> EncodeFromMessageLIN(std::shared_ptr<Frame> /* frame */, const device_eventhandler_t& report) {
// TODO
report(APIEvent::Type::UnsupportedTXNetwork, APIEvent::Severity::Error);
return {};
static std::vector<uint8_t> EncodeFromMessageLIN(std::shared_ptr<Frame> frame, const device_eventhandler_t& report) {
auto linmsg = std::dynamic_pointer_cast<LINMessage>(frame);
if(!linmsg) {
report(APIEvent::Type::MessageFormattingError, APIEvent::Severity::Error);
return {};
}
if(linmsg->linMsgType == LINMessage::Type::NOT_SET) {
report(APIEvent::Type::RequiredParameterNull, APIEvent::Severity::Error);
return {};
}
size_t dataLen = std::min<size_t>(8, linmsg->data.size());
std::vector<uint8_t> encoded;
encoded.resize(sizeof(TransmitMessage));
TransmitMessage* const msg = (TransmitMessage*)encoded.data();
HardwareLINPacket* const linpacket = (HardwareLINPacket*)(msg->commonHeader);
memset(linpacket, 0, sizeof(HardwareLINPacket));
// Protected ID and ID
linmsg->protectedID = linmsg->calcProtectedID(linmsg->ID);
linpacket->CoreMiniBitsLIN.ID = linmsg->protectedID & 0x3F;
// LIN message type flags
switch(linmsg->linMsgType) {
case LINMessage::Type::LIN_COMMANDER_MSG:
linpacket->CoreMiniBitsLIN.TXCommander = 1;
break;
case LINMessage::Type::LIN_HEADER_ONLY:
linpacket->CoreMiniBitsLIN.TXCommander = 1;
break;
case LINMessage::Type::LIN_UPDATE_RESPONDER:
linpacket->CoreMiniBitsLIN.TXResponder = 1;
break;
case LINMessage::Type::LIN_BREAK_ONLY:
linpacket->CoreMiniBitsLIN.BreakOnly = 1;
break;
default:
break;
}
// Enhanced checksum
linpacket->CoreMiniBitsLIN.TxChkSumEnhanced = linmsg->isEnhancedChecksum ? 1 : 0;
// Data and checksum
bool hasData = (linmsg->linMsgType == LINMessage::Type::LIN_COMMANDER_MSG ||
linmsg->linMsgType == LINMessage::Type::LIN_UPDATE_RESPONDER) && dataLen > 0;
if(hasData) {
// len includes data bytes + 1 checksum byte
linpacket->CoreMiniBitsLIN.len = static_cast<uint16_t>(dataLen + 1);
std::copy(linmsg->data.begin(), linmsg->data.begin() + dataLen, linpacket->data);
// Checksum goes after data: in data[dataLen] if < 8, otherwise in LINByte9
if(dataLen < 8)
linpacket->data[dataLen] = linmsg->checksum;
else
linpacket->CoreMiniBitsLIN.LINByte9 = linmsg->checksum;
} else {
linpacket->CoreMiniBitsLIN.len = 0;
}
// Description/stats and network
linpacket->stats = linmsg->description;
return encoded;
}
std::vector<uint8_t> TransmitMessage::EncodeFromMessage(std::shared_ptr<Frame> frame, uint32_t client_id, const device_eventhandler_t& report) {
@@ -139,6 +176,7 @@ std::vector<uint8_t> TransmitMessage::EncodeFromMessage(std::shared_ptr<Frame> f
case Network::Type::AutomotiveEthernet:
result = EncodeFromMessageEthernet(frame, report);
break;
case Network::Type::Internal:
case Network::Type::CAN:
result = EncodeFromMessageCAN(frame, report);
break;
@@ -150,6 +188,8 @@ std::vector<uint8_t> TransmitMessage::EncodeFromMessage(std::shared_ptr<Frame> f
return result;
}
// common fields
if(result.empty())
return result;
TransmitMessage* const msg = (TransmitMessage*)result.data();
msg->options.clientId = client_id;
msg->options.networkId = static_cast<uint32_t>(frame->network.getNetID());
+6 -2
View File
@@ -29,8 +29,7 @@ static std::optional<uint8_t> CAN_DLCToLength(uint8_t length, bool fd) {
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)
return uint8_t(dataLength);
@@ -120,7 +119,12 @@ std::shared_ptr<Message> HardwareCANPacket::DecodeToMessage(const std::vector<ui
}
msg->transmitted = data->eid.TXMSG;
// Set the generic frame error state
msg->error = data->eid.TXAborted || data->eid.TXError || data->eid.TXLostArb;
// Set specific error states for CANError
msg->txAborted = data->eid.TXAborted;
msg->txLostArb = data->eid.TXLostArb;
msg->txError = data->eid.TXError;
msg->description = data->stats;
return msg;
+35 -11
View File
@@ -1,6 +1,7 @@
#include "icsneo/communication/packet/ethernetpacket.h"
#include <algorithm> // for std::copy
#include <algorithm>
#include <iostream>
#include <optional>
using namespace icsneo;
@@ -10,29 +11,49 @@ std::shared_ptr<EthernetMessage> HardwareEthernetPacket::DecodeToMessage(const s
// Make sure we have enough to read the packet length first
if(bytestream.size() < sizeof(HardwareEthernetPacket))
return nullptr;
// packet->Length will also encompass the two uint16_t's at the end of the struct, make sure that at least they are here
if(packet->Length < 4)
return nullptr;
const size_t fcsSize = packet->header.FCS_AVAIL ? 4 : 0;
// Ensure Length is sufficient for FCS extraction to avoid invalid iterator arithmetic
if(packet->Length < fcsSize)
return nullptr;
const size_t bytestreamExpectedSize = sizeof(HardwareEthernetPacket) + packet->Length;
const size_t bytestreamActualSize = bytestream.size();
if(bytestreamActualSize < bytestreamExpectedSize)
return nullptr;
auto messagePtr = std::make_shared<EthernetMessage>();
EthernetMessage& message = *messagePtr;
// Standard Ethernet fields
message.transmitted = packet->eid.TXMSG;
if(message.transmitted)
message.description = packet->stats;
message.preemptionEnabled = packet->header.PREEMPTION_ENABLED;
if(message.preemptionEnabled)
message.preemptionFlags = (uint8_t)((rawWords[0] & 0x03F8) >> 4);
message.frameTooShort = packet->header.RUNT_FRAME;
message.noPadding = !packet->header.ENABLE_PADDING;
message.fcsVerified = packet->header.FCS_VERIFIED;
message.txAborted = packet->eid.TXAborted;
message.crcError = packet->header.CRC_ERROR;
if(message.frameTooShort)
message.error = true;
// This timestamp is raw off the device (in timestampResolution increments)
// Decoder will fix as it has information about the timestampResolution increments
message.timestamp = packet->timestamp.TS;
// Ethernet Frame Preemption for TSN
if(packet->header.PREEMPTION_ENABLED) {
message.preemptionFlags = static_cast<uint8_t>((rawWords[0] & 0x03F8) >> 4);
}
// Check if this is a T1S packet and populate T1S-specific fields
if(packet->header.T1S_ETHERNET) {
auto& t1s = message.t1s.emplace();
t1s.isSymbol = packet->eid.T1S_SYMBOL;
t1s.isBurst = packet->eid.T1S_BURST;
t1s.txCollision = packet->t1s_status.TXCollision;
t1s.isWake = packet->t1s_status.T1SWake;
t1s.nodeId = packet->t1s_node.T1S_NODE_ID;
t1s.burstCount = packet->t1s_node.T1S_BURST_COUNT;
}
const std::vector<uint8_t>::const_iterator databegin = bytestream.begin() + sizeof(HardwareEthernetPacket);
const std::vector<uint8_t>::const_iterator dataend = databegin + packet->Length - fcsSize;
message.data.insert(message.data.begin(), databegin, dataend);
@@ -55,7 +76,7 @@ bool HardwareEthernetPacket::EncodeFromMessage(const EthernetMessage& message, s
if(description & 0x8000)
return false;
const bool preempt = message.preemptionEnabled;
const bool preempt = message.preemptionFlags.has_value();
// full header including parent
const size_t headerByteCount = preempt ? 15 : 14;
// local header for netID, description, and flags
@@ -104,12 +125,15 @@ bool HardwareEthernetPacket::EncodeFromMessage(const EthernetMessage& message, s
uint8_t flags = 0x00;
if(!message.noPadding) flags |= FLAG_PADDING;
if(message.fcs) flags |= FLAG_FCS;
if(message.preemptionEnabled) flags |= FLAG_PREEMPTION;
if(message.preemptionFlags.has_value()) {
flags |= FLAG_PREEMPTION;
}
bytestream.push_back(flags);
if(preempt)
bytestream.push_back(static_cast<uint8_t>(message.preemptionFlags));
if(preempt) {
bytestream.push_back(message.preemptionFlags.value());
}
bytestream.insert(bytestream.end(), message.data.begin(), message.data.end());
-91
View File
@@ -1,91 +0,0 @@
#include "icsneo/communication/ringbuffer.h"
#include <stdexcept>
namespace icsneo {
RingBuffer::RingBuffer(size_t bufferSize) : readCursor(0), writeCursor(0) {
// round the buffer size to the nearest power of 2
bufferSize = RoundUp(bufferSize);
mask = bufferSize - 1;
buf = new uint8_t[bufferSize];
}
RingBuffer::~RingBuffer() {
delete[] buf;
buf = nullptr;
}
const uint8_t& RingBuffer::operator[](size_t offset) const {
return get(offset);
}
size_t RingBuffer::size() const {
// The values in the cursors are monotonic, i.e. they only ever increment. They can be considered to be the total number of elements ever written or read
auto currentWriteCursor = writeCursor.load(std::memory_order_relaxed);
auto currentReadCursor = readCursor.load(std::memory_order_relaxed);
// Using unmasked values, writeCursor is guaranteed to be >= readCursor. If they are equal that means the buffer is empty
return currentWriteCursor - currentReadCursor;
}
void RingBuffer::pop_front() {
pop(1);
}
void RingBuffer::pop(size_t count) {
if (size() < count) {
throw std::runtime_error("RingBuffer: Underflow");
}
readCursor.fetch_add(count, std::memory_order_release);
}
const uint8_t& RingBuffer::get(size_t offset) const {
if (offset >= size()) {
throw std::runtime_error("RingBuffer: Index out of range");
}
auto currentReadCursor = readCursor.load(std::memory_order_acquire);
return *resolve(currentReadCursor, offset);
}
bool RingBuffer::write(const uint8_t* addr, size_t length) {
const auto freeSpace = (capacity() - size());
if (length > freeSpace) {
return false;
}
auto currentWriteCursor = writeCursor.load(std::memory_order_relaxed);
auto spaceAtEnd = std::min(freeSpace, capacity() - (currentWriteCursor & mask)); // number of bytes from (masked) writeCursor to the end of the writable space (i.e. we reach the masked read cursor or the end of the buffer)
auto firstCopySize = std::min(spaceAtEnd, length);
(void)memcpy(resolve(currentWriteCursor, 0), addr, firstCopySize);
if (firstCopySize < length)
{
(void)memcpy(buf, &addr[firstCopySize], length - firstCopySize);
}
writeCursor.store(currentWriteCursor + length, std::memory_order_release);
return true;
}
bool RingBuffer::write(const std::vector<uint8_t>& source) {
return write(source.data(), source.size());
}
bool RingBuffer::read(uint8_t* dest, size_t startIndex, size_t length) const {
auto currentSize = size();
if ((startIndex >= currentSize) || ((startIndex + length) > size())) {
return false;
}
auto currentReadCursor = readCursor.load(std::memory_order_relaxed);
auto bytesAtEnd = std::min<size_t>(capacity() - ((currentReadCursor + startIndex) & mask), length);
const auto bytesAtStart = (length - bytesAtEnd);
(void)memcpy(dest, resolve(currentReadCursor, startIndex), bytesAtEnd);
if (bytesAtStart > 0) {
(void)memcpy(&dest[bytesAtEnd], buf, bytesAtStart);
}
return true;
}
void RingBuffer::clear() {
pop(size());
}
}
+5 -6
View File
@@ -4,8 +4,7 @@
* Created on: Jun 22, 2020
* Author: BJones
*/
#include "icsneo/communication/crc32.h"
#include <stddef.h>
#include "icsneo/core/crc32.h"
static const unsigned long crc32_table[256] = { 0x00000000, 0x77073096, 0xEE0E612C, 0x990951BA, 0x076DC419, 0x706AF48F, 0xE963A535,
0x9E6495A3, 0x0EDB8832, 0x79DCB8A4, 0xE0D5E91E, 0x97D2D988, 0x09B64C2B, 0x7EB17CBD, 0xE7B82D07, 0x90BF1D91, 0x1DB71064, 0x6AB020F2,
@@ -32,7 +31,7 @@ static const unsigned long crc32_table[256] = { 0x00000000, 0x77073096, 0xEE0E61
0x47B2CF7F, 0x30B5FFE9, 0xBDBDF21C, 0xCABAC28A, 0x53B39330, 0x24B4A3A6, 0xBAD03605, 0xCDD70693, 0x54DE5729, 0x23D967BF, 0xB3667A2E,
0xC4614AB8, 0x5D681B02, 0x2A6F2B94, 0xB40BBE37, 0xC30C8EA1, 0x5A05DF1B, 0x2D02EF8D };
uint32_t crc32(uint32_t crc, const unsigned char* buf, uint32_t len)
uint32_t icsneo::crc32(uint32_t crc, const unsigned char* buf, uint32_t len)
{
unsigned char octet;
const unsigned char* p = buf;
@@ -50,13 +49,13 @@ static unsigned char rev_crc32_table[256];
static void revgen(void)
{
size_t k;
uint16_t k;
for (k = 0; k < 256; k++)
rev_crc32_table[crc32_table[k] >> 24] = (uint8_t)k;
rev_crc32_table[crc32_table[k] >> 24] = (unsigned char)k;
}
uint32_t revcrc32(uint32_t crc, const unsigned char* buf, uint32_t len)
uint32_t icsneo::revcrc32(uint32_t crc, const unsigned char* buf, uint32_t len)
{
unsigned char k;
revgen();
+831
View File
@@ -0,0 +1,831 @@
#include "icsneo/core/macseccfg.h"
#include "icsneo/api/eventmanager.h"
#include "icsneo/core/crc32.h"
#include <cstring>
namespace icsneo {
#ifdef _MSC_VER
#pragma warning(push)
#pragma warning(disable : 4201) // nameless struct/union
#endif
#pragma pack(push, 1)
typedef struct
{
uint16_t VID; /*!< 12 bits */
uint8_t PRI_CFI; /*!< PRI - 3 bits, CFI - 1bit */
} MACSEC_VLANTAG_t;
/**
* @brief Structure of MPLS
*
*/
typedef struct
{
uint32_t MPLS_label; /*!< 20 bits */
uint8_t exp; /*!< 3 bits */
} MACSEC_MPLS_OUTER_t;
#define MACSEC_SETTINGS_RULE_SIZE (88)
typedef union _MACSecRule
{
struct
{
uint8_t index;
uint8_t key_MAC_DA[6]; /*!< MAC DA field extracted from the packet */
uint8_t mask_MAC_DA[6]; /*!< Set bits to 1 to mask/exclude corresponding flowid_tcam_data bit from compare */
uint8_t key_MAC_SA[6]; /*!< MAC SA field extracted from the packet */
uint8_t mask_MAC_SA[6]; /*!< Set bits to 1 to mask/exclude corresponding flowid_tcam_data bit from compare */
uint16_t key_Ethertype; /*!< First E-Type found in the packet that doesn't match one of the preconfigured custom tag. */
uint16_t mask_Ethertype; /*!< Set bits to 1 to mask/exclude corresponding flowid_tcam_data bit from compare */
MACSEC_VLANTAG_t key_vlantag_outer1; /*!< outermost/1st VLAN ID {8'd0, VLAN_ID[11:0]}, or 20-bit MPLS label. */
MACSEC_MPLS_OUTER_t key_MPLS_outer1;
MACSEC_VLANTAG_t mask_vlantag_outer1; /*!< Set bits to 1 to mask/exclude corresponding flowid_tcam_data bit from compare */
MACSEC_MPLS_OUTER_t mask_MPLS_outer1;
MACSEC_VLANTAG_t key_vlantag_outer2; /*!< 2nd outermost VLAN ID {8'd0, VLAN_ID[11:0]}, or 20-bit MPLS label. */
MACSEC_MPLS_OUTER_t key_MPLS_outer2;
MACSEC_VLANTAG_t mask_vlantag_outer2; /*!< Set bits to 1 to mask/exclude corresponding flowid_tcam_data bit from compare */
MACSEC_MPLS_OUTER_t mask_MPLS_outer2;
uint16_t key_bonus_data; /*!< 2 bytes of additional bonus data extracted from one of the custom tags. */
uint16_t mask_bonus_data; /*!< Set bits to 1 to mask/exclude corresponding flowid_tcam_data bit from compare */
uint8_t
key_tag_match_bitmap; /*!< 8 bits total. Maps 1 to 1 bitwise with the set of custom tags. (set bit[N]=1 if check Nth custom tag) */
uint8_t mask_tag_match_bitmap; /*!< Set bits to 1 to mask/exclude corresponding flowid_tcam_data bit from compare */
MACsecPacketType key_packet_type; /*!< Encoded Packet Type, see MACSEC_PACKET_TYPE */
uint8_t mask_packet_type; /*!< Set bits to 1 to mask/exclude corresponding flowid_tcam_data bit from compare */
uint16_t
key_inner_vlan_type; /*!< 3 bits total. Encoded value indicating which VLAN TPID value matched for the second outermost VLAN Tag. */
uint16_t mask_inner_vlan_type; /*!< Set bits to 1 to mask/exclude corresponding flowid_tcam_data bit from compare */
uint16_t key_outer_vlan_type; /*!< 3 bits total. Encoded value indicating which VLAN TPID value matched for the outermost VLAN Tag. */
uint16_t mask_outer_vlan_type; /*!< Set bits to 1 to mask/exclude corresponding flowid_tcam_data bit from compare */
uint8_t
key_num_tags; /*!< 7 bits total. Number of VLAN/custom tags or MPLS lables detected. Ingress: before SecTag; Egress: total detected. Exclude MCS header tags. i.e. Bit 2: 2 tags/labels before SecTAG...Bit 6: 6 or more tags/labels before SecTAG. */
uint8_t mask_num_tags; /*!< Set bits to 1 to mask/exclude corresponding flowid_tcam_data bit from compare */
uint8_t key_express; /*!< 1 bits. Express packet. */
uint8_t mask_express; /*!< Set bits to 1 to mask/exclude corresponding flowid_tcam_data bit from compare */
uint8_t isMPLS;
uint8_t rsvd[5];
uint8_t enable;
};
uint8_t byte[MACSEC_SETTINGS_RULE_SIZE];
} MACSecRule_t;
/* MACsec Map */
#define MACSEC_SETTINGS_MAP_SIZE (20)
typedef union _MACSecMap
{
struct
{
uint8_t index;
uint64_t sectag_sci; /*!< Identifies the SecTAG SCI for this Flow. */
uint8_t secYIndex; /*!< index for entry in Egress secY Policy */
uint8_t isControlPacket; /*!< Identifies all packets matching this index lookup as control packets. */
uint8_t scIndex; /*!< Identifies the SC for this Flow. */
uint8_t auxiliary_plcy; /*!< Auxiliary policy bits. */
uint8_t ruleId; /*!< Identifies the Rule for this Flow. */
uint8_t rsvd[5];
uint8_t enable;
};
uint8_t byte[MACSEC_SETTINGS_MAP_SIZE];
} MACSecMap_t;
/* MACsec SecY */
#define MACSEC_SETTINGS_SECY_SIZE (24)
typedef union _MACSecSecY
{
struct
{
uint8_t index; /*!< Identifies the SecY for this Flow. */
uint8_t controlled_port_enabled; /*!< Enable (or disable) operation of the Controlled port associated with this SecY */
MACsecValidation validate_frames; /*!< see MACSEC_VALIDATEFRAME */
MACsecStrip strip_sectag_icv; /*!< see MACSEC_STRIP_SECTAG_ICV */
MACsecCipherSuite cipher; /*!< Define the cipher suite to use for this SecY */
uint8_t confidential_offset; /*!< Define the number of bytes that are unencrypted following the SecTag. */
uint8_t icv_includes_da_sa; /*!< When set, the outer DA/SA bytes are included in the authentication GHASH calculation */
uint8_t replay_protect; /*!< Enables Anti-Replay protection */
uint32_t replay_window; /*!< Unsigned value indicating the size of the anti-replay window. */
uint8_t
protect_frames; /*!< 0 = do not encrypt or authenticate this packet; 1 = always Authenticate frame and if SecTag.TCI.E = 1 encrypt the packet as well. */
uint8_t
sectag_offset; /*!< Define the offset in bytes from either the start of the packet or a matching Etype depending on SecTag_Insertion_Mode. */
uint8_t sectag_tci; /*!< Tag Control Information excluding the AN field which originates from the SA Policy table */
uint16_t mtu; /*!< Specifies the outgoing MTU for this SecY */
uint8_t rsvd[6];
uint8_t enable;
};
uint8_t byte[MACSEC_SETTINGS_SECY_SIZE];
} MACSecSecY_t;
/* MACsec SC */
#define MACSEC_SETTINGS_SC_SIZE (24)
typedef union _MACSecSc
{
struct
{
uint8_t index; /*!< SC index. */
uint8_t secYIndex; /*!< SecY associated with this packet. */
uint64_t sci; /*!< The Secure Channel Identifier. */
uint8_t sa_index0; /*!< Define the 1st SA to use */
uint8_t sa_index1; /*!< Define the 2nd SA to use */
uint8_t sa_index0_in_use; /*!< Specifies whether 1st SA is in use or not. */
uint8_t sa_index1_in_use; /*!< Specifies whether 2nd SA is in use or not. */
uint8_t enable_auto_rekey; /*!< If enabled, then once the pn_threshold is reached, auto rekey will happen. */
uint8_t
isActiveSA1; /*!< If set, then sa_index1 is the currently active SA index. If cleared, the sa_index0 is the currently active SA index). */
uint8_t rsvd[7];
uint8_t enable;
};
uint8_t byte[MACSEC_SETTINGS_SC_SIZE];
} MACSecSc_t;
/* MACsec SA */
#define MACSEC_SETTINGS_SA_SIZE (80)
typedef union _MACSecSa
{
struct
{
uint8_t index; /*!< SA index */
uint8_t
sak[32]; /*!< SAK: All 32 bytes are written to the firmware. For AES-128 the firmware requires bytes [0..15] == bytes [16..31] (mirrored); serialize() handles this automatically. */
uint8_t hashKey[16]; /*!< 128b Hash Key: Key used for authentication. */
uint8_t salt[12]; /*!< 96b Salt value: Salt value used in XPN ciphers. */
uint32_t ssci; /*!< 32b SSCI value: Short Secure Channel Identifier, used in XPN ciphers. */
uint8_t AN; /*!< 2b SecTag Association Number (AN) */
uint64_t nextPN; /*!< 64b next_pn value: Next packet number to insert into outgoing packet on a particular SA. */
uint8_t rsvd[5];
uint8_t enable;
};
uint8_t byte[MACSEC_SETTINGS_SA_SIZE];
} MACSecSa_t;
/* MACsec Flags */
#define MACSEC_SETTINGS_FLAGS_SIZE (4)
typedef union _MACSecFlags
{
struct
{
uint32_t en : 1; // '1' = enable; '0' = disable
uint32_t reserved : 31;
};
uint32_t flags_32b;
} MACSecFlags_t;
/* MACSec Settings for 1 port/phy */
#define MACSEC_NUM_FLAGS_PER_CONFIG (1)
#define MACSEC_NUM_RULES_PER_CONFIG (2)
#define MACSEC_NUM_MAPS_PER_CONFIG (2)
#define MACSEC_NUM_SECY_PER_CONFIG (2)
#define MACSEC_NUM_SC_PER_CONFIG (2)
#define MACSEC_NUM_SA_PER_CONFIG (4)
typedef struct MACSEC_CONFIG_t
{
MACSecFlags_t flags;
MACSecRule_t rule[MACSEC_NUM_RULES_PER_CONFIG];
MACSecMap_t map[MACSEC_NUM_MAPS_PER_CONFIG];
MACSecSecY_t secy[MACSEC_NUM_SECY_PER_CONFIG];
MACSecSc_t sc[MACSEC_NUM_SC_PER_CONFIG];
MACSecSa_t sa[MACSEC_NUM_SA_PER_CONFIG];
} MACSEC_CONFIG;
typedef union _MACSecGlobalFlags
{
struct
{
uint32_t en : 1; // '1' = enable; '0' = disable
uint32_t nvm : 1; // store macsec config in non-volatile memory
uint32_t reserved : 30;
};
uint32_t flags_32b;
} MACSecGlobalFlags_t;
#define MACSEC_SETTINGS_SIZE (2040) // leave space for expansion and keep nicely aligned for flashing
typedef union _MACSEC_SETTINGS
{
struct
{
MACSecGlobalFlags_t flags;
MACSEC_CONFIG rx;
MACSEC_CONFIG tx;
};
uint8_t byte[MACSEC_SETTINGS_SIZE];
} MACSEC_SETTINGS;
#define MACSEC_SETTINGS_VERSION 1
typedef struct MACSEC_SETTINGS_W_HDR
{
uint16_t version;
uint16_t len;
uint32_t crc32;
MACSEC_SETTINGS macsec;
} MACSEC_SETTINGS_W_HDR;
#define MACSEC_SETTINGS_W_HDR_SIZE (2048)
#pragma pack(pop)
#ifdef _MSC_VER
#pragma warning(pop)
#endif
static void ReportEvent(APIEvent::Type event, APIEvent::Severity severity) {
auto& em = EventManager::GetInstance();
em.add(APIEvent(event, severity));
}
MACsecConfig::MACsecConfig(const DeviceType& deviceType) : type(deviceType) {
switch(deviceType.getDeviceType()) {
case icsneo::DeviceType::Enum::RADMoon2:
case icsneo::DeviceType::Enum::RADMoon3:
case icsneo::DeviceType::Enum::RADEpsilon:
maxSecY = 2;
maxRule = 2;
maxSa = 4;
binIndex = 0;
break;
default:
maxSecY = 0;
maxSa = 0;
maxRule = 0;
binIndex = 0;
ReportEvent(APIEvent::Type::MACsecNotSupported, APIEvent::Severity::Error);
return;
}
}
int MACsecConfig::addRxSecY(const MACsecRxSecY& secY, uint8_t saIndex) {
if(rxSecY.size() >= maxSecY) {
ReportEvent(APIEvent::Type::MACsecSecYLimit, APIEvent::Severity::Error);
return -1;
}
if(saIndex >= rxSa.size()) {
ReportEvent(APIEvent::Type::MACsecInvalidSaIndex, APIEvent::Severity::Error);
return -1;
}
int ret = static_cast<int>(rxSecY.size());
rxSecY.emplace_back(secY);
rxSecYSaIndices.emplace_back(saIndex, saIndex + 1);
rxSecYRekey.emplace_back(false);
rxRuleIndices.emplace_back(0);
return ret;
}
int MACsecConfig::addTxSecY(const MACsecTxSecY& secY, uint8_t saIndex) {
if(txSecY.size() >= maxSecY) {
ReportEvent(APIEvent::Type::MACsecSecYLimit, APIEvent::Severity::Error);
return -1;
}
if(saIndex >= txSa.size()) {
ReportEvent(APIEvent::Type::MACsecInvalidSaIndex, APIEvent::Severity::Error);
return -1;
}
int ret = static_cast<int>(txSecY.size());
txSecY.emplace_back(secY);
txSecYSaIndices.emplace_back(saIndex, saIndex + 1);
txSecYRekey.emplace_back(false);
return ret;
}
int MACsecConfig::addRxSa(const MACsecRxSa& sa) {
// Validate AN is in valid range
if(sa.an > 3) {
ReportEvent(APIEvent::Type::MACsecSaLimit, APIEvent::Severity::Error);
return -1;
}
// Check if we've exceeded the maximum SA count
if(rxSa.size() >= maxSa) {
ReportEvent(APIEvent::Type::MACsecSaLimit, APIEvent::Severity::Error);
return -1;
}
// Ensure vector is large enough to hold index sa.an (sparse array)
// This allows SA index to match the AN value from the MACsec SecTAG
if(rxSa.size() <= sa.an) {
rxSa.resize(sa.an + 1);
}
// Mark it enabled; padding slots created by resize() above default to enabled=false.
rxSa[sa.an] = sa;
rxSa[sa.an].enabled = true;
return sa.an;
}
int MACsecConfig::addTxSa(const MACsecTxSa& sa) {
if(txSa.size() >= maxSa) {
ReportEvent(APIEvent::Type::MACsecSaLimit, APIEvent::Severity::Error);
return -1;
}
int ret = static_cast<int>(txSa.size());
txSa.emplace_back(sa);
return ret;
}
int MACsecConfig::addRxRule(const MACsecRxRule& rule, uint8_t secYIndex) {
if(rxRule.size() >= maxRule) {
ReportEvent(APIEvent::Type::MACsecSaLimit, APIEvent::Severity::Error);
return -1;
}
if(maxSecY >= rxRule.size()) {
ReportEvent(APIEvent::Type::MACsecSecYLimit, APIEvent::Severity::Error);
return -1;
}
int ret = static_cast<int>(rxRule.size());
rxRuleIndices[secYIndex] = static_cast<uint8_t>(rxRule.size());
rxRule.emplace_back(rule);
return ret;
}
MACsecRxRule& MACsecConfig::getRxRule(uint8_t ruleIndex) {
return rxRule[ruleIndex];
}
const MACsecRxRule& MACsecConfig::getRxRule(uint8_t ruleIndex) const {
return rxRule[ruleIndex];
}
MACsecRxSecY& MACsecConfig::getRxSecY(uint8_t secYIndex) {
return rxSecY[secYIndex];
}
const MACsecRxSecY& MACsecConfig::getRxSecY(uint8_t secYIndex) const {
return rxSecY[secYIndex];
}
MACsecTxSecY& MACsecConfig::getTxSecY(uint8_t secYIndex) {
return txSecY[secYIndex];
}
const MACsecTxSecY& MACsecConfig::getTxSecY(uint8_t secYIndex) const {
return txSecY[secYIndex];
}
MACsecRxSa& MACsecConfig::getRxSa(uint8_t saIndex) {
return rxSa[saIndex];
}
const MACsecRxSa& MACsecConfig::getRxSa(uint8_t saIndex) const {
return rxSa[saIndex];
}
MACsecTxSa& MACsecConfig::getTxSa(uint8_t saIndex) {
return txSa[saIndex];
}
const MACsecTxSa& MACsecConfig::getTxSa(uint8_t saIndex) const {
return txSa[saIndex];
}
bool MACsecConfig::setTxSaIndex(uint8_t secYIndex, uint8_t saIndex) {
if(secYIndex >= txSecY.size()) {
ReportEvent(APIEvent::Type::MACsecInvalidSecYIndex, APIEvent::Severity::Error);
return false;
}
if(saIndex >= txSa.size()) {
ReportEvent(APIEvent::Type::MACsecInvalidSaIndex, APIEvent::Severity::Error);
return false;
}
txSecYSaIndices[secYIndex].first = saIndex;
return true;
}
bool MACsecConfig::enableTxRekey(uint8_t secYIndex, uint8_t rekeySaIndex) {
if(secYIndex >= txSecY.size()) {
ReportEvent(APIEvent::Type::MACsecInvalidSecYIndex, APIEvent::Severity::Error);
return false;
}
if(rekeySaIndex >= txSa.size()) {
ReportEvent(APIEvent::Type::MACsecInvalidSaIndex, APIEvent::Severity::Error);
return false;
}
txSecYSaIndices[secYIndex].second = rekeySaIndex;
txSecYRekey[secYIndex] = true;
return true;
}
bool MACsecConfig::setTxSaRekeyIndex(uint8_t secYIndex, uint8_t saIndex) {
if(secYIndex >= txSecY.size()) {
ReportEvent(APIEvent::Type::MACsecInvalidSecYIndex, APIEvent::Severity::Error);
return false;
}
if(saIndex >= txSa.size()) {
ReportEvent(APIEvent::Type::MACsecInvalidSaIndex, APIEvent::Severity::Error);
return false;
}
txSecYSaIndices[secYIndex].second = saIndex;
return true;
}
void MACsecConfig::disableTxRekey(uint8_t secYIndex) {
if(secYIndex >= txSecY.size()) {
ReportEvent(APIEvent::Type::MACsecInvalidSecYIndex, APIEvent::Severity::EventWarning);
return;
}
txSecYRekey[secYIndex] = false;
}
bool MACsecConfig::setRxSaIndex(uint8_t secYIndex, uint8_t saIndex) {
if(secYIndex >= rxSecY.size()) {
ReportEvent(APIEvent::Type::MACsecInvalidSecYIndex, APIEvent::Severity::Error);
return false;
}
if(saIndex >= rxSa.size()) {
ReportEvent(APIEvent::Type::MACsecInvalidSaIndex, APIEvent::Severity::Error);
return false;
}
rxSecYSaIndices[secYIndex].first = saIndex;
return true;
}
bool MACsecConfig::enableRxRekey(uint8_t secYIndex, uint8_t rekeySaIndex) {
if(secYIndex >= rxSecY.size()) {
ReportEvent(APIEvent::Type::MACsecInvalidSecYIndex, APIEvent::Severity::Error);
return false;
}
if(rekeySaIndex >= rxSa.size()) {
ReportEvent(APIEvent::Type::MACsecInvalidSaIndex, APIEvent::Severity::Error);
return false;
}
rxSecYSaIndices[secYIndex].second = rekeySaIndex;
rxSecYRekey[secYIndex] = true;
return true;
}
bool MACsecConfig::setRxSaRekeyIndex(uint8_t secYIndex, uint8_t saIndex) {
if(secYIndex >= rxSecY.size()) {
ReportEvent(APIEvent::Type::MACsecInvalidSecYIndex, APIEvent::Severity::Error);
return false;
}
if(saIndex >= rxSa.size()) {
ReportEvent(APIEvent::Type::MACsecInvalidSaIndex, APIEvent::Severity::Error);
return false;
}
rxSecYSaIndices[secYIndex].second = saIndex;
return true;
}
void MACsecConfig::disableRxRekey(uint8_t secYIndex) {
if(secYIndex >= rxSecY.size()) {
ReportEvent(APIEvent::Type::MACsecInvalidSecYIndex, APIEvent::Severity::EventWarning);
return;
}
rxSecYRekey[secYIndex] = false;
}
void MACsecConfig::setRxEnable(bool newRxEnable) {
enableRx = newRxEnable;
}
void MACsecConfig::setTxEnable(bool newTxEnable) {
enableTx = newTxEnable;
}
void MACsecConfig::setStorage(bool temporary) {
nvm = !temporary;
}
void MACsecConfig::clear() {
// Set everything back to default, except device maximums
rxSecY.clear();
txSecY.clear();
rxSa.clear();
txSa.clear();
rxRule.clear();
rxSecYRekey.clear();
txSecYRekey.clear();
rxSecYSaIndices.clear();
txSecYSaIndices.clear();
rxRuleIndices.clear();
enableRx = false;
enableTx = false;
nvm = false;
}
MACsecConfig::operator bool() const {
return (maxSa != 0) || (maxSecY != 0) || (maxRule != 0);
}
uint16_t MACsecConfig::getBinIndex() const {
return binIndex;
}
DeviceType MACsecConfig::getType() const {
return type;
}
uint8_t MACsecConfig::getMaxNumRule() const {
return maxRule;
}
uint8_t MACsecConfig::getMaxNumSecY() const {
return maxSecY;
}
uint8_t MACsecConfig::getMaxNumSa() const {
return maxSa;
}
static uint8_t TCItoInt(const MACsecTci& tci) {
uint8_t res = 0;
res |= tci.c ? 0x01u : 0;
res |= tci.e ? 0x02u : 0;
res |= tci.scb ? 0x04u : 0;
res |= tci.sc ? 0x08u : 0;
res |= tci.es ? 0x10u : 0;
return res;
}
static void SetHardwareTxSecY(
MACSEC_SETTINGS_W_HDR* hwSettings,
const MACsecTxSecY& secY,
bool rekeyEnabled,
const std::pair<uint8_t, uint8_t>& saIndices,
uint8_t index
) {
MACSecSecY_t* hwSecY = &hwSettings->macsec.tx.secy[index];
MACSecSc_t* hwSc = &hwSettings->macsec.tx.sc[index];
MACSecMap_t* hwMap = &hwSettings->macsec.tx.map[index];
hwSecY->index = index;
hwSecY->enable = true;
hwSecY->controlled_port_enabled = secY.enableControlPort ? 0x1u : 0x0u;
hwSecY->cipher = secY.cipher;
hwSecY->confidential_offset = secY.confidentialityOffset;
hwSecY->icv_includes_da_sa = secY.icvIncludesDaSa ? 0x1u : 0x0u;
hwSecY->mtu = secY.mtu;
hwSecY->sectag_tci = TCItoInt(secY.tci);
hwSecY->sectag_offset = secY.secTagOffset;
hwSecY->protect_frames = secY.protectFrames;
hwSc->index = index;
hwSc->enable = true;
hwSc->secYIndex = index;
hwSc->enable_auto_rekey = rekeyEnabled ? 0x1u : 0x0u;
hwSc->sa_index0 = saIndices.first;
hwSc->sa_index1 = saIndices.second;
hwSc->sa_index0_in_use = true;
hwSc->sa_index1_in_use = rekeyEnabled ? true : false;
hwSc->isActiveSA1 = rekeyEnabled ? true : false;
hwSc->sci = secY.sci;
hwMap->index = index;
hwMap->enable = true;
hwMap->auxiliary_plcy = secY.auxiliaryPolicy;
hwMap->secYIndex = index;
hwMap->isControlPacket = secY.isControlPacket ? 0x1u : 0x0u;
hwMap->scIndex = index;
hwMap->sectag_sci = secY.sci;
}
static void SetHardwareRxSecY(
MACSEC_SETTINGS_W_HDR* hwSettings,
const MACsecRxSecY& secY,
bool rekeyEnabled,
uint8_t ruleIndex,
const std::pair<uint8_t, uint8_t>& saIndices,
uint8_t index
) {
MACSecSecY_t* hwSecY = &hwSettings->macsec.rx.secy[index];
MACSecSc_t* hwSc = &hwSettings->macsec.rx.sc[index];
MACSecMap_t* hwMap = &hwSettings->macsec.rx.map[index];
hwSecY->index = index;
hwSecY->enable = 0x1u;
hwSecY->controlled_port_enabled = secY.enableControlPort ? 0x1u : 0x0u;
hwSecY->cipher = secY.cipher;
hwSecY->confidential_offset = secY.confidentialityOffset;
hwSecY->icv_includes_da_sa = secY.icvIncludesDaSa ? 0x1u : 0x0u;
hwSecY->replay_protect = secY.replayProtect ? 0x1u : 0x0u;
hwSecY->replay_window = secY.replayWindow;
hwSecY->validate_frames = secY.frameValidation;
hwSecY->strip_sectag_icv = secY.frameStrip;
hwSecY->sectag_offset = 12;
hwSc->index = index;
hwSc->enable = 0x1u;
hwSc->secYIndex = index;
hwSc->enable_auto_rekey = rekeyEnabled ? 0x1u : 0x0u;
hwSc->sci = secY.sci;
if(saIndices.first & 0x1u) {
hwSc->sa_index0 = rekeyEnabled ? saIndices.second : saIndices.first;
hwSc->sa_index1 = saIndices.first;
hwSc->sa_index0_in_use = rekeyEnabled ? 0x1u : 0x0u;
hwSc->sa_index1_in_use = 0x1u;
hwSc->isActiveSA1 = rekeyEnabled ? 0x0u : 0x1u;
} else {
hwSc->sa_index0 = saIndices.first;
hwSc->sa_index1 = saIndices.second;
hwSc->sa_index0_in_use = 0x1u;
hwSc->sa_index1_in_use = rekeyEnabled ? 0x1u : 0x0u;
hwSc->isActiveSA1 = rekeyEnabled ? 0x1u : 0x0u;
}
hwMap->index = index;
hwMap->enable = 0x1u;
hwMap->secYIndex = index;
hwMap->ruleId = ruleIndex;
hwMap->isControlPacket = secY.isControlPacket ? 0x1u : 0x0u;
hwMap->scIndex = index;
hwMap->sectag_sci = secY.sci;
}
static void SetHardwareTxSa(MACSEC_SETTINGS_W_HDR* hwSettings, const MACsecTxSa& sa, uint8_t index) {
MACSecSa_t* hwSa = &hwSettings->macsec.tx.sa[index];
hwSa->index = index;
hwSa->enable = 0x1u;
memcpy(hwSa->sak, sa.sak.data(), 32);
memcpy(hwSa->hashKey, sa.hashKey.data(), 16);
memcpy(hwSa->salt, sa.salt.data(), 12);
hwSa->ssci = sa.ssci;
hwSa->AN = sa.an;
hwSa->nextPN = sa.nextPn;
}
static void SetHardwareRxSa(MACSEC_SETTINGS_W_HDR* hwSettings, const MACsecRxSa& sa, uint8_t index) {
MACSecSa_t* hwSa = &hwSettings->macsec.rx.sa[index];
hwSa->index = index;
hwSa->enable = sa.enabled ? 0x1u : 0x0u;
if(!sa.enabled)
return;
memcpy(hwSa->sak, sa.sak.data(), 32);
memcpy(hwSa->hashKey, sa.hashKey.data(), 16);
memcpy(hwSa->salt, sa.salt.data(), 12);
hwSa->ssci = sa.ssci;
hwSa->nextPN = sa.nextPn;
}
static void SetHardwareRxRule(MACSecRule_t* hwRule, const MACsecRxRule& rule, uint8_t index) {
hwRule->enable = 0x1u;
hwRule->index = index;
memcpy(hwRule->key_MAC_DA, rule.keyMacDa.data(), 6);
memcpy(hwRule->mask_MAC_DA, rule.maskMacDa.data(), 6);
memcpy(hwRule->key_MAC_SA, rule.keyMacSa.data(), 6);
memcpy(hwRule->mask_MAC_SA, rule.maskMacSa.data(), 6);
hwRule->key_Ethertype = rule.keyEthertype;
hwRule->mask_Ethertype = rule.maskEthertype;
hwRule->key_vlantag_outer1.PRI_CFI = rule.keyVlanTagOuter1.priCfi;
hwRule->key_vlantag_outer1.VID = rule.keyVlanTagOuter1.vid;
hwRule->key_MPLS_outer1.exp = rule.keyMplsOuter1.exp;
hwRule->key_MPLS_outer1.MPLS_label = rule.keyMplsOuter1.mplsLabel;
hwRule->mask_vlantag_outer1.PRI_CFI = rule.maskVlanTagOuter1.priCfi;
hwRule->mask_vlantag_outer1.VID = rule.maskVlanTagOuter1.vid;
hwRule->mask_MPLS_outer1.exp = rule.maskMplsOuter1.exp;
hwRule->mask_MPLS_outer1.MPLS_label = rule.maskMplsOuter1.mplsLabel;
hwRule->key_vlantag_outer2.PRI_CFI = rule.keyVlanTagOuter2.priCfi;
hwRule->key_vlantag_outer2.VID = rule.keyVlanTagOuter2.vid;
hwRule->key_MPLS_outer2.exp = rule.keyMplsOuter2.exp;
hwRule->key_MPLS_outer2.MPLS_label = rule.keyMplsOuter2.mplsLabel;
hwRule->mask_vlantag_outer2.PRI_CFI = rule.maskVlanTagOuter2.priCfi;
hwRule->mask_vlantag_outer2.VID = rule.maskVlanTagOuter2.vid;
hwRule->mask_MPLS_outer2.exp = rule.maskMplsOuter2.exp;
hwRule->mask_MPLS_outer2.MPLS_label = rule.maskMplsOuter2.mplsLabel;
hwRule->key_bonus_data = rule.keyBonusData;
hwRule->mask_bonus_data = rule.maskBonusData;
hwRule->key_tag_match_bitmap = rule.keyTagMatchBitmap;
hwRule->mask_tag_match_bitmap = rule.maskTagMatchBitmap;
hwRule->key_packet_type = rule.keyPacketType;
hwRule->mask_packet_type = rule.maskPacketType;
hwRule->key_inner_vlan_type = rule.keyInnerVlanType;
hwRule->mask_inner_vlan_type = rule.maskInnerVlanType;
hwRule->key_outer_vlan_type = rule.keyOuterVlanType;
hwRule->mask_outer_vlan_type = rule.maskOuterVlanType;
hwRule->key_num_tags = rule.keyNumTags;
hwRule->mask_num_tags = rule.maskNumTags;
hwRule->key_express = rule.keyExpress ? 0x1u : 0x0u;
hwRule->mask_express = rule.maskExpress ? 0x1u : 0x0u;
hwRule->isMPLS = rule.isMpls ? 0x1u : 0x0u;
}
std::vector<uint8_t> MACsecConfig::serialize() const {
std::vector<uint8_t> res(sizeof(MACSEC_SETTINGS_W_HDR), 0);
MACSEC_SETTINGS_W_HDR* hwSettings = (MACSEC_SETTINGS_W_HDR*)(res.data());
for(uint8_t i = 0; i < maxSecY; i++) {
if(i < rxSecY.size()) {
SetHardwareRxSecY(
hwSettings,
rxSecY[i],
rxSecYRekey[i],
rxRuleIndices[i],
rxSecYSaIndices[i],
i
);
} else {
hwSettings->macsec.rx.secy[i].enable = false;
hwSettings->macsec.rx.map[i].enable = false;
hwSettings->macsec.rx.sc[i].enable = false;
}
if(i < txSecY.size()) {
SetHardwareTxSecY(
hwSettings,
txSecY[i],
txSecYRekey[i],
txSecYSaIndices[i],
i
);
} else {
hwSettings->macsec.tx.secy[i].enable = false;
hwSettings->macsec.tx.map[i].enable = false;
hwSettings->macsec.tx.sc[i].enable = false;
}
}
for(uint8_t i = 0; i < maxSa; i++) {
if(i < rxSa.size()) {
SetHardwareRxSa(hwSettings, rxSa[i], i);
} else {
hwSettings->macsec.rx.sa[i].enable = false;
}
if(i < txSa.size()) {
SetHardwareTxSa(hwSettings, txSa[i], i);
} else {
hwSettings->macsec.tx.sa[i].enable = false;
}
}
// AES-128 SAK normalization: the firmware expects the 16-byte SAK mirrored
// into both halves of the 32-byte hardware SAK field. Callers only populate
// bytes [0..15]; copy them into [16..31] here, transparent to all callers.
for(uint8_t i = 0; i < static_cast<uint8_t>(rxSecY.size()); i++) {
if(rxSecY[i].cipher == MACsecCipherSuite::GcmAes128 || rxSecY[i].cipher == MACsecCipherSuite::GcmAes128Xpn) {
uint8_t primaryIdx = rxSecYSaIndices[i].first;
if(primaryIdx < maxSa)
memcpy(hwSettings->macsec.rx.sa[primaryIdx].sak + 16, hwSettings->macsec.rx.sa[primaryIdx].sak, 16);
if(rxSecYRekey[i]) {
uint8_t rekeyIdx = rxSecYSaIndices[i].second;
if(rekeyIdx < maxSa)
memcpy(hwSettings->macsec.rx.sa[rekeyIdx].sak + 16, hwSettings->macsec.rx.sa[rekeyIdx].sak, 16);
}
}
}
for(uint8_t i = 0; i < static_cast<uint8_t>(txSecY.size()); i++) {
if(txSecY[i].cipher == MACsecCipherSuite::GcmAes128 || txSecY[i].cipher == MACsecCipherSuite::GcmAes128Xpn) {
uint8_t primaryIdx = txSecYSaIndices[i].first;
if(primaryIdx < maxSa)
memcpy(hwSettings->macsec.tx.sa[primaryIdx].sak + 16, hwSettings->macsec.tx.sa[primaryIdx].sak, 16);
if(txSecYRekey[i]) {
uint8_t rekeyIdx = txSecYSaIndices[i].second;
if(rekeyIdx < maxSa)
memcpy(hwSettings->macsec.tx.sa[rekeyIdx].sak + 16, hwSettings->macsec.tx.sa[rekeyIdx].sak, 16);
}
}
}
if(rxRule.size() == 0) {
MACsecRxRule defaultRule;
MACSecRule_t* hwRxRule = &hwSettings->macsec.rx.rule[0];
MACSecRule_t* hwTxRule = &hwSettings->macsec.tx.rule[0];
SetHardwareRxRule(hwRxRule, defaultRule, 0);
SetHardwareRxRule(hwTxRule, defaultRule, 0);
//hwSettings->macsec.tx.rule[0].enable = false;
for(uint8_t i = 1; i < maxRule; i++) {
hwSettings->macsec.rx.rule[i].enable = false;
hwSettings->macsec.tx.rule[i].enable = false;
}
} else {
for(uint8_t i = 0; i < maxRule; i++) {
if(i < rxRule.size()) {
auto* hwRxRule = &hwSettings->macsec.rx.rule[i];
SetHardwareRxRule(hwRxRule, rxRule[i], i);
} else {
hwSettings->macsec.rx.rule[i].enable = false;
hwSettings->macsec.tx.rule[i].enable = false;
}
}
}
hwSettings->len = sizeof(MACSEC_SETTINGS_W_HDR);
hwSettings->version = MACSEC_SETTINGS_VERSION;
hwSettings->macsec.flags.en = (enableRx || enableTx) ? 1u : 0u;
hwSettings->macsec.flags.nvm = nvm ? 1u : 0u;
hwSettings->macsec.rx.flags.en = enableRx ? 1u : 0u;
hwSettings->macsec.tx.flags.en = enableTx ? 1u : 0u;
hwSettings->crc32 = crc32(0, (uint8_t*)&hwSettings->macsec, sizeof(MACSEC_SETTINGS));
return res;
}
}
+91
View File
@@ -0,0 +1,91 @@
#include "icsneo/core/ringbuffer.h"
#include <stdexcept>
namespace icsneo {
RingBuffer::RingBuffer(size_t bufferSize) : readCursor(0), writeCursor(0) {
// round the buffer size to the nearest power of 2
bufferSize = RoundUp(bufferSize);
mask = bufferSize - 1;
buf = new uint8_t[bufferSize];
}
RingBuffer::~RingBuffer() {
delete[] buf;
buf = nullptr;
}
const uint8_t& RingBuffer::operator[](size_t offset) const {
return get(offset);
}
size_t RingBuffer::size() const {
// The values in the cursors are monotonic, i.e. they only ever increment. They can be considered to be the total number of elements ever written or read
auto currentWriteCursor = writeCursor.load(std::memory_order_relaxed);
auto currentReadCursor = readCursor.load(std::memory_order_relaxed);
// Using unmasked values, writeCursor is guaranteed to be >= readCursor. If they are equal that means the buffer is empty
return currentWriteCursor - currentReadCursor;
}
void RingBuffer::pop_front() {
pop(1);
}
void RingBuffer::pop(size_t count) {
if (size() < count) {
throw std::runtime_error("RingBuffer: Underflow");
}
readCursor.fetch_add(count, std::memory_order_release);
}
const uint8_t& RingBuffer::get(size_t offset) const {
if (offset >= size()) {
throw std::runtime_error("RingBuffer: Index out of range");
}
auto currentReadCursor = readCursor.load(std::memory_order_acquire);
return *resolve(currentReadCursor, offset);
}
bool RingBuffer::write(const uint8_t* addr, size_t length) {
const auto freeSpace = (capacity() - size());
if (length > freeSpace) {
return false;
}
auto currentWriteCursor = writeCursor.load(std::memory_order_relaxed);
auto spaceAtEnd = std::min(freeSpace, capacity() - (currentWriteCursor & mask)); // number of bytes from (masked) writeCursor to the end of the writable space (i.e. we reach the masked read cursor or the end of the buffer)
auto firstCopySize = std::min(spaceAtEnd, length);
(void)memcpy(resolve(currentWriteCursor, 0), addr, firstCopySize);
if (firstCopySize < length)
{
(void)memcpy(buf, &addr[firstCopySize], length - firstCopySize);
}
writeCursor.store(currentWriteCursor + length, std::memory_order_release);
return true;
}
bool RingBuffer::write(const std::vector<uint8_t>& source) {
return write(source.data(), source.size());
}
bool RingBuffer::read(uint8_t* dest, size_t startIndex, size_t length) const {
auto currentSize = size();
if ((startIndex >= currentSize) || ((startIndex + length) > size())) {
return false;
}
auto currentReadCursor = readCursor.load(std::memory_order_relaxed);
auto bytesAtEnd = std::min<size_t>(capacity() - ((currentReadCursor + startIndex) & mask), length);
const auto bytesAtStart = (length - bytesAtEnd);
(void)memcpy(dest, resolve(currentReadCursor, startIndex), bytesAtEnd);
if (bytesAtStart > 0) {
(void)memcpy(&dest[bytesAtEnd], buf, bytesAtStart);
}
return true;
}
void RingBuffer::clear() {
pop(size());
}
}
+76 -39
View File
@@ -1,4 +1,5 @@
#include <sstream>
#include <iomanip>
#include "icsneo/api/eventmanager.h"
#include "icsneo/communication/message/filter/main51messagefilter.h"
#include "icsneo/communication/message/extendedresponsemessage.h"
@@ -181,12 +182,11 @@ bool Device::getMessages(std::vector<std::shared_ptr<Message>>& container, size_
if(container.size() < limit)
container.resize(limit);
size_t actuallyRead;
if(timeout != std::chrono::milliseconds(0))
actuallyRead = pollingContainer.wait_dequeue_bulk_timed(container.data(), limit, timeout);
else
actuallyRead = pollingContainer.try_dequeue_bulk(container.data(), limit);
size_t actuallyRead = 0;
if(pollingContainer.wait_dequeue_timed(container.front(), timeout)) {
actuallyRead = 1; // Account for the first message we already dequeued
actuallyRead += pollingContainer.try_dequeue_bulk(container.data() + 1, limit - 1);
}
if(container.size() > actuallyRead)
container.resize(actuallyRead);
@@ -395,7 +395,7 @@ bool Device::open(OpenFlags flags, OpenStatusHandler handler) {
if(heartbeatCV.wait_for(recvLk, std::chrono::milliseconds(3500), [&](){ return receivedMessage; })) {
receivedMessage = false;
} else {
if(!stopHeartbeatThread && !isDisconnected()) {
if(!stopHeartbeatThread) {
close();
report(APIEvent::Type::DeviceDisconnected, APIEvent::Severity::Error);
}
@@ -435,7 +435,13 @@ bool Device::reconnect(std::chrono::milliseconds timeout, std::chrono::milliseco
// Pause reads again
com->pauseReads();
}
return com->open();
if(com->open()) {
return true;
} else {
if(readsArePaused) {
com->resumeReads();
}
}
}
}
std::this_thread::sleep_for(interval);
@@ -554,32 +560,38 @@ bool Device::goOnline() {
return false;
}
if(supportsNetworkMutex()) {
if(supportsNetworkMutex) {
assignedClientId = com->getClientIDSync();
if(assignedClientId) {
std::set<Network::NetID> nets;
for(auto&& net : getSupportedTXNetworks()) {
nets.insert(net.getNetID());
}
// firmware supports clientid/mutex
networkMutexCallbackHandle = lockAllNetworks(std::numeric_limits<uint32_t>::max(), std::numeric_limits<uint32_t>::max(), NetworkMutexType::Shared, [this](std::shared_ptr<Message> message) {
auto netMutexMsg = std::static_pointer_cast<NetworkMutexMessage>(message);
if(netMutexMsg->networks.size() && netMutexMsg->event.has_value()) {
switch(*netMutexMsg->event) {
case NetworkMutexEvent::Acquired:
lockedNetworks.emplace(*netMutexMsg->networks.begin());
break;
case NetworkMutexEvent::Released: {
auto it = lockedNetworks.find(*netMutexMsg->networks.begin());
if (it != lockedNetworks.end())
lockedNetworks.erase(it);
break;
}
networkMutexCallbackHandle = lockNetworks(nets, std::numeric_limits<uint32_t>::max(), std::numeric_limits<uint32_t>::max(), NetworkMutexType::Shared, [this](std::shared_ptr<Message> message) {
auto netMutexMsg = std::static_pointer_cast<NetworkMutexMessage>(message);
if(netMutexMsg->networks.size() && netMutexMsg->event.has_value()) {
switch(*netMutexMsg->event) {
case NetworkMutexEvent::Acquired:
lockedNetworks.emplace(*netMutexMsg->networks.begin());
break;
case NetworkMutexEvent::Released: {
auto it = lockedNetworks.find(*netMutexMsg->networks.begin());
if (it != lockedNetworks.end())
lockedNetworks.erase(it);
break;
}
}
}
);
});
}
}
// (re)start the keeponline
keeponline = std::make_unique<Periodic>([this] { return enableNetworkCommunication(true, onlineTimeoutMs); }, std::chrono::milliseconds(onlineTimeoutMs / 4));
keeponline = std::make_unique<Periodic>([this] {
static std::vector<uint8_t> timeoutBytes = std::vector<uint8_t>((uint8_t*)&onlineTimeoutMs, (uint8_t*)&onlineTimeoutMs + sizeof(onlineTimeoutMs));
return com->sendCommand(Command::KeepAlive, timeoutBytes);
}, std::chrono::milliseconds(onlineTimeoutMs / 4));
online = true;
@@ -601,6 +613,11 @@ bool Device::goOffline() {
return true;
}
if(assignedClientId.has_value()) {
unlockAllNetworks();
assignedClientId.reset();
}
if(!enableNetworkCommunication(false))
return false;
@@ -2090,10 +2107,6 @@ std::optional<EthPhyMessage> Device::sendEthPhyMsg(const EthPhyMessage& message,
report(APIEvent::Type::EthPhyRegisterControlNotAvailable, APIEvent::Severity::Error);
return std::nullopt;
}
if(!isOnline()) {
report(APIEvent::Type::DeviceCurrentlyOffline, APIEvent::Severity::Error);
return std::nullopt;
}
std::vector<uint8_t> bytes;
HardwareEthernetPhyRegisterPacket::EncodeFromMessage(message, bytes, report);
@@ -2241,6 +2254,24 @@ bool Device::setRTC(const std::chrono::time_point<std::chrono::system_clock>& ti
return m51msg->data.front();
}
std::optional<std::vector<uint8_t>> Device::getPCBSerial() {
auto serialMsg = com->getSerialNumberSync();
if(!serialMsg || !serialMsg->hasPCBSerial) {
return std::nullopt;
}
return std::vector<uint8_t>(serialMsg->pcbSerial, serialMsg->pcbSerial + sizeof(serialMsg->pcbSerial));
}
std::optional<std::vector<uint8_t>> Device::getMACAddress() {
auto serialMsg = com->getSerialNumberSync();
if(!serialMsg || !serialMsg->hasMacAddress) {
return std::nullopt;
}
return std::vector<uint8_t>(serialMsg->macAddress, serialMsg->macAddress + sizeof(serialMsg->macAddress));
}
std::optional<std::set<SupportedFeature>> Device::getSupportedFeatures() {
auto timeout = std::chrono::milliseconds(100);
std::shared_ptr<Message> msg = com->waitForMessageSync(
@@ -3740,13 +3771,19 @@ std::optional<GPTPStatus> Device::getGPTPStatus(std::chrono::milliseconds timeou
return *retMsg;
}
bool Device::writeMACsecConfig(const MACsecMessage& message, uint16_t binaryIndex)
{
std::vector<uint8_t> raw;
bool Device::writeMACsecConfig(const MACsecConfig& cfg) {
if(!cfg) {
report(APIEvent::Type::MACsecNotSupported, APIEvent::Severity::Error);
return false;
}
message.EncodeFromMessage(raw, report);
if(getType() != cfg.getType()) {
report(APIEvent::Type::MACsecConfigMismatch, APIEvent::Severity::Error);
return false;
}
return writeBinaryFile(raw, binaryIndex);
std::vector<uint8_t> raw = cfg.serialize();
return writeBinaryFile(raw, cfg.getBinIndex());
}
bool Device::enableNetworkCommunication(bool enable, uint32_t timeout) {
@@ -3798,7 +3835,7 @@ bool Device::formatDisk(const DiskDetails& config, const DiskFormatProgress& han
return com->sendCommand(ExtendedCommand::DiskFormatProgress, {});
},
std::make_shared<ExtendedResponseFilter>(ExtendedCommand::DiskFormatProgress),
std::chrono::milliseconds(200)
std::chrono::milliseconds(5000)
);
if(!response) {
@@ -3890,7 +3927,7 @@ std::shared_ptr<DiskDetails> Device::getDiskDetails(std::chrono::milliseconds ti
[[nodiscard]] std::optional<int> Device::lockNetworks(const std::set<Network::NetID>& networks, uint32_t priority, uint32_t ttlMs, NetworkMutexType type, std::function<void(std::shared_ptr<Message>)>&& on_event)
{
if(!supportsNetworkMutex()) {
if(!supportsNetworkMutex) {
report(APIEvent::Type::NotSupported, APIEvent::Severity::Error);
return std::nullopt;
}
@@ -3940,7 +3977,7 @@ std::shared_ptr<DiskDetails> Device::getDiskDetails(std::chrono::milliseconds ti
bool Device::unlockNetworks(const std::set<Network::NetID>& networks)
{
if(!supportsNetworkMutex()) {
if(!supportsNetworkMutex) {
report(APIEvent::Type::NotSupported, APIEvent::Severity::Error);
return false;
}
@@ -3980,7 +4017,7 @@ bool Device::unlockNetworks(const std::set<Network::NetID>& networks)
std::shared_ptr<NetworkMutexMessage> Device::getNetworkMutexStatus(Network::NetID network)
{
if(!supportsNetworkMutex()) {
if(!supportsNetworkMutex) {
report(APIEvent::Type::NotSupported, APIEvent::Severity::Error);
return nullptr;
}
@@ -4002,7 +4039,7 @@ std::shared_ptr<NetworkMutexMessage> Device::getNetworkMutexStatus(Network::NetI
[[nodiscard]] std::optional<int> Device::lockAllNetworks(uint32_t priority, uint32_t ttlMs, NetworkMutexType type, std::function<void(std::shared_ptr<Message>)>&& on_event)
{
if(!supportsNetworkMutex()) {
if(!supportsNetworkMutex) {
report(APIEvent::Type::NotSupported, APIEvent::Severity::Error);
return std::nullopt;
}
@@ -4049,7 +4086,7 @@ std::shared_ptr<NetworkMutexMessage> Device::getNetworkMutexStatus(Network::NetI
bool Device::unlockAllNetworks()
{
if(!supportsNetworkMutex()) {
if(!supportsNetworkMutex) {
report(APIEvent::Type::NotSupported, APIEvent::Severity::Error);
return false;
}
+8
View File
@@ -225,6 +225,10 @@ std::vector<std::shared_ptr<Device>> DeviceFinder::FindAll() {
makeIfSerialMatches<RADMoon3>(dev, newFoundDevices);
#endif
#ifdef __RADGEMINI_H_
makeIfSerialMatches<RADGemini>(dev, newFoundDevices);
#endif
#ifdef __RADMOONDUO_H_
makeIfSerialMatches<RADMoonDuo>(dev, newFoundDevices);
#endif
@@ -384,6 +388,10 @@ const std::vector<DeviceType>& DeviceFinder::GetSupportedDevices() {
RADMoon3::DEVICE_TYPE,
#endif
#ifdef __RADGEMINI_H_
RADGemini::DEVICE_TYPE,
#endif
#ifdef __RADMOONDUO_H_
RADMoonDuo::DEVICE_TYPE,
#endif
+18 -4
View File
@@ -235,7 +235,7 @@ bool IDeviceSettings::apply(bool temporary) {
std::shared_ptr<Main51Message> msg = std::dynamic_pointer_cast<Main51Message>(com->waitForMessageSync([this, &bytestream]() {
return com->sendCommand(Command::SetSettings, bytestream);
}, std::make_shared<Main51MessageFilter>(Command::SetSettings), std::chrono::milliseconds(2000)));
}, std::make_shared<Main51MessageFilter>(Command::SetSettings), std::chrono::milliseconds(5000)));
if(!msg || msg->data[0] != 1) { // We did not receive a response
// Attempt to get the settings from the device so we're up to date if possible
@@ -261,7 +261,7 @@ bool IDeviceSettings::apply(bool temporary) {
msg = std::dynamic_pointer_cast<Main51Message>(com->waitForMessageSync([this, &bytestream]() {
return com->sendCommand(Command::SetSettings, bytestream);
}, std::make_shared<Main51MessageFilter>(Command::SetSettings), std::chrono::milliseconds(2000)));
}, std::make_shared<Main51MessageFilter>(Command::SetSettings), std::chrono::milliseconds(5000)));
if(!msg || msg->data[0] != 1) {
// Attempt to get the settings from the device so we're up to date if possible
if(refresh()) {
@@ -303,7 +303,7 @@ bool IDeviceSettings::applyDefaults(bool temporary) {
std::shared_ptr<Main51Message> msg = std::dynamic_pointer_cast<Main51Message>(com->waitForMessageSync([this]() {
return com->sendCommand(Command::SetDefaultSettings);
}, std::make_shared<Main51MessageFilter>(Command::SetDefaultSettings), std::chrono::milliseconds(1000)));
}, std::make_shared<Main51MessageFilter>(Command::SetDefaultSettings), std::chrono::milliseconds(5000)));
if(!msg || msg->data[0] != 1) {
// Attempt to get the settings from the device so we're up to date if possible
if(refresh()) {
@@ -338,7 +338,7 @@ bool IDeviceSettings::applyDefaults(bool temporary) {
msg = std::dynamic_pointer_cast<Main51Message>(com->waitForMessageSync([this, &bytestream]() {
return com->sendCommand(Command::SetSettings, bytestream);
}, std::make_shared<Main51MessageFilter>(Command::SetSettings), std::chrono::milliseconds(2000)));
}, std::make_shared<Main51MessageFilter>(Command::SetSettings), std::chrono::milliseconds(5000)));
if(!msg || msg->data[0] != 1) {
// Attempt to get the settings from the device so we're up to date if possible
if(refresh()) {
@@ -945,4 +945,18 @@ template<typename T> bool IDeviceSettings::applyStructure(const T& newStructure)
memcpy(settings.data(), &newStructure, structSize);
return apply();
}
bool IDeviceSettings::setMiscIOAnalogOutputEnabled(uint8_t pin, bool enabled) {
(void)pin;
(void)enabled;
report(APIEvent::Type::SettingNotAvaiableDevice, APIEvent::Severity::Error);
return false;
}
bool IDeviceSettings::setMiscIOAnalogOutput(uint8_t pin, MiscIOAnalogVoltage voltage) {
(void)pin;
(void)voltage;
report(APIEvent::Type::SettingNotAvaiableDevice, APIEvent::Severity::Error);
return false;
}
+3 -1
View File
@@ -7,12 +7,13 @@ import subprocess
subprocess.call('cd ..; doxygen docs/icsneocpp/Doxyfile', shell=True)
subprocess.call('cd ..; doxygen docs/icsneoc/Doxyfile', shell=True)
subprocess.call('cd ..; doxygen docs/icsneoc2/Doxyfile', shell=True)
# -- Project information -----------------------------------------------------
# https://www.sphinx-doc.org/en/master/usage/configuration.html#project-information
project = 'libicsneo'
copyright = '2024-2025, Intrepid Control Systems, Inc.'
copyright = '2024-2026, Intrepid Control Systems, Inc.'
author = 'Intrepid Control Systems, Inc.'
# -- General configuration ---------------------------------------------------
@@ -26,6 +27,7 @@ exclude_patterns = ['_build', 'Thumbs.db', '.DS_Store']
breathe_projects = {
'icsneocpp': 'icsneocpp/doxygen/xml',
'icsneoc': 'icsneoc/doxygen/xml',
'icsneoc2': 'icsneoc2/doxygen/xml',
}
breathe_default_project = 'icsneocpp'
+1
View File
@@ -0,0 +1 @@
doxygen
+2 -2
View File
@@ -1,5 +1,5 @@
icsneoc
=======
icsneoc (deprecated, use icsneoc2)
============================
.. toctree::
:maxdepth: 2
+1
View File
@@ -0,0 +1 @@
doxygen
File diff suppressed because it is too large Load Diff
+12
View File
@@ -0,0 +1,12 @@
======
C2 API
======
.. doxygenfile:: icsneoc2.h
:project: icsneoc2
.. doxygenfile:: icsneoc2messages.h
:project: icsneoc2
.. doxygenfile:: icsneoc2settings.h
:project: icsneoc2
.. doxygenfile:: icsneoc2types.h
:project: icsneoc2
+84
View File
@@ -0,0 +1,84 @@
=================
icsneoc2 Examples
=================
Simple
======
:download:`Download example <../../examples/c2/simple/src/main.c>`
.. literalinclude:: ../../examples/c2/simple/src/main.c
:language: c
Disk Format
===========
:download:`Download example <../../examples/c2/diskformat/src/main.c>`
.. literalinclude:: ../../examples/c2/diskformat/src/main.c
:language: c
Read Messages
=============
:download:`Download example <../../examples/c2/read_messages/src/main.c>`
.. literalinclude:: ../../examples/c2/read_messages/src/main.c
:language: c
Device Info
===========
:download:`Download example <../../examples/c2/device_info/src/main.c>`
.. literalinclude:: ../../examples/c2/device_info/src/main.c
:language: c
LIN
===
:download:`Download example <../../examples/c2/lin/src/main.c>`
.. literalinclude:: ../../examples/c2/lin/src/main.c
:language: c
LIN Transmit
============
:download:`Download example <../../examples/c2/lin_transmit/src/main.c>`
.. literalinclude:: ../../examples/c2/lin_transmit/src/main.c
:language: c
Ethernet Transmit
=================
:download:`Download example <../../examples/c2/ethernet_transmit/src/main.c>`
.. literalinclude:: ../../examples/c2/ethernet_transmit/src/main.c
:language: c
Ethernet Receive
================
:download:`Download example <../../examples/c2/ethernet_receive/src/main.c>`
.. literalinclude:: ../../examples/c2/ethernet_receive/src/main.c
:language: c
T1S Loopback
============
:download:`Download example <../../examples/c2/t1s_loopback/src/main.c>`
.. literalinclude:: ../../examples/c2/t1s_loopback/src/main.c
:language: c
TC10
====
:download:`Download example <../../examples/c2/tc10/src/main.c>`
.. literalinclude:: ../../examples/c2/tc10/src/main.c
:language: c
+9
View File
@@ -0,0 +1,9 @@
icsneoc2
========
.. toctree::
:maxdepth: 2
installation
examples
api
+7
View File
@@ -0,0 +1,7 @@
============
Installation
============
The installation steps for the C2 API are the same as the C++ API as the C2 API is
a wrapper for the C++ library. The ``LIBICSNEO_BUILD_ICSNEOC2`` CMake option is
default ``ON`` but note that the C2 API depends on this flag to build.
+1
View File
@@ -0,0 +1 @@
doxygen
+1 -1
View File
@@ -6,7 +6,7 @@ Prerequisites
=============
- Python 3.8 or higher
- icsneopy library installed
- icsneopy installed (see :doc:`installation`)
- CAN hardware device connected
:download:`Download complete example <../../examples/python/can/can_complete_example.py>`
+1 -1
View File
@@ -8,7 +8,7 @@ Prerequisites
=============
- Python 3.8 or higher
- icsneopy library installed
- icsneopy installed (see :doc:`installation`)
- Intrepid Control Systems Device
:download:`Download complete example <../../examples/python/ethernet/ethernet_complete_example.py>`
+33
View File
@@ -27,6 +27,15 @@ Complete CAN Example
:language: python
LiveData Subscription and Monitoring
=====================================
:download:`Download example <../../examples/python/livedata/livedata_example.py>`
.. literalinclude:: ../../examples/python/livedata/livedata_example.py
:language: python
Transmit Ethernet frames on Ethernet 01
========================================
@@ -74,3 +83,27 @@ Device Firmware/Chip Versions
.. literalinclude:: ../../examples/python/device/chip_versions.py
:language: python
SPI Example for 10BASE-T1S
=============================
:download:`Download example <../../examples/python/spi/spi_example.py>`
.. literalinclude:: ../../examples/python/spi/spi_example.py
:language: python
10BASE-T1S Settings Configuration
=================================
:download:`Download example <../../examples/python/t1s/t1s_settings.py>`
.. literalinclude:: ../../examples/python/t1s/t1s_settings.py
:language: python
Analog Output Control
=====================
:download:`Download example <../../examples/python/analog_out/analog_out_basic.py>`
.. literalinclude:: ../../examples/python/analog_out/analog_out_basic.py
:language: python
+191
View File
@@ -0,0 +1,191 @@
=======================
FlexRay Getting Started
=======================
Prerequisites
=============
- icsneopy installed (see :doc:`installation`)
- FlexRay hardware device connected (e.g., Fire3 Flexray)
- Proper FlexRay bus termination (100Ω on each channel end)
Physical Hardware Setup for Two-Node Testing
---------------------------------------------
For testing the basic transmit and receive examples with a single device:
- Hardware: Device with dual FlexRay controllers (e.g., neoVI FIRE 3 Flexray)
- Connection: FLEXRAY_01 Channel A looped to FLEXRAY_02 Channel A
- Termination: 100Ω termination resistors on both ends of the loopback
- Cable: Use proper FlexRay twisted pair cable (impedance matched)
.. note::
The basic transmit/receive examples are configured for this loopback setup
where both controllers act as coldstart nodes. For use on an existing
FlexRay network, see the passive monitoring configuration notes in the
receive example.
FlexRay Coldstart
-----------------
FlexRay networks require at least one "coldstart node" to initialize the network timing.
The coldstart node is responsible for starting the FlexRay communication cycle.
For a complete standalone coldstart example, see the Additional Examples section below.
Basic Setup
===========
1. Import the library and find FlexRay device:
.. code-block:: python
import icsneopy
devices = icsneopy.find_all_devices()
# Find a device with FlexRay support
device = None
for dev in devices:
if dev.get_extension("FlexRay"):
device = dev
break
if not device:
raise RuntimeError("No FlexRay-capable device found")
2. Configure FlexRay controller:
.. literalinclude:: ../../examples/python/flexray/flexray_transmit_basic.py
:language: python
:lines: 12-111
3. Open device and go online:
.. code-block:: python
if not device.open():
raise RuntimeError("Failed to open device")
if not device.go_online():
raise RuntimeError("Failed to go online")
Transmitting FlexRay Frames
============================
This example demonstrates a coldstart node that initiates a FlexRay network
and transmits simulated sensor data continuously in slot 1.
**Hardware Setup**: FLEXRAY_01 looped to FLEXRAY_02
**Usage**:
1. Start the receive example first
2. Start this transmit example second
3. Network will initialize and frames will be transmitted
.. literalinclude:: ../../examples/python/flexray/flexray_transmit_basic.py
:language: python
:lines: 113-170
Key Configuration Parameters:
- **slotid**: The FlexRay slot ID for transmission (1-2047 for static segment)
- **cycle**: The FlexRay cycle number (0-63)
- **cycle_repetition**: How often the frame repeats (1 = every cycle, 2 = every other cycle)
- **channel**: Transmission channel (A, B, or AB for both)
- **key_slot_id**: Must be unique per node on the network
- **key_slot_used_for_startup**: True for coldstart nodes
- **key_slot_used_for_sync**: True to provide synchronization frames
Receiving FlexRay Frames
=========================
This example demonstrates receiving FlexRay frames on FLEXRAY_02 Channel A.
**Hardware Setup**: FLEXRAY_01 looped to FLEXRAY_02
**Configuration Note**: This example is configured with coldstart capability
for two-node loopback testing. For passive monitoring on an existing FlexRay
network:
1. Set ``key_slot_used_for_startup = False`` in the controller configuration
2. Remove the ``controller.set_allow_coldstart(True)`` call
3. Ensure all cluster parameters match the existing network
4. The node will sync and receive without transmitting
**Usage**:
1. Start this receive example first
2. Start the transmit example second
3. Frames from slot 1 will be displayed with hex and decimal payload views
.. literalinclude:: ../../examples/python/flexray/flexray_receive_basic.py
:language: python
:lines: 103-170
FlexRay Coldstart Configuration
================================
To use the Coldstart example, ensure the following:
Set the Flexray network in ICS Device Manager to Coldstart.
No other nodes should be present on the network during testing.
Nothing connected to Fire3 FlexRay bus.
Critical Coldstart Settings
----------------------------
.. literalinclude:: ../../examples/python/flexray/flexray_coldstart.py
:language: python
:lines: 40-48
Configuration Example:
.. literalinclude:: ../../examples/python/flexray/flexray_coldstart.py
:language: python
:lines: 20-64
Setting Coldstart on Controller:
.. code-block:: python
controller.set_allow_coldstart(True)
controller.set_start_when_going_online(True)
Cleanup and Resource Management
================================
Always close the device when finished:
.. code-block:: python
try:
# Your FlexRay operations here
pass
finally:
device.close()
See the basic transmit and receive examples for complete implementations.
Additional Examples
===================
Transmit Basic
--------------
Complete working example with coldstart node transmitting simulated sensor data.
All example files are available for download:
**Transmit Basic** - Coldstart node transmitting simulated sensor data
:download:`flexray_transmit_basic.py <../../examples/python/flexray/flexray_transmit_basic.py>`
**Receive Basic** - Receiving and displaying FlexRay frames with formatted output
:download:`flexray_receive_basic.py <../../examples/python/flexray/flexray_receive_basic.py>`
**Coldstart** - Standalone coldstart example demonstrating network initialization
:download:`flexray_coldstart.py <../../examples/python/flexray/flexray_coldstart.py>`
+2
View File
@@ -5,8 +5,10 @@ icsneopy
.. toctree::
:maxdepth: 2
installation
can_getting_started
ethernet_getting_started
flexray_getting_started
examples
api
radepsilon
+38
View File
@@ -0,0 +1,38 @@
============
Installation
============
icsneopy is available on PyPI at https://pypi.org/project/icsneopy/ and can be installed with pip:
.. code-block:: bash
pip install icsneopy
Pre-release
===========
For the latest features, install with the ``--pre`` flag to include pre-release versions:
.. code-block:: bash
pip install --pre icsneopy
Upgrading
=========
To upgrade an existing installation:
.. code-block:: bash
pip install --pre --upgrade icsneopy
Linux udev Rules
================
Linux users may want to install the included udev rules to run icsneopy-based
applications without root. The rules file can be found in the libicsneo source
repository at https://github.com/intrepidcs/libicsneo/.
.. code-block:: bash
sudo cp 99-intrepidcs.rules /etc/udev/rules.d/
+16
View File
@@ -13,3 +13,19 @@ communication library. The source code for libicsneo can be found on GitHub:
icsneocpp/index
icsneopy/index
icsneoc/index
icsneoc2/index
Linux Installation
==================
Applications that use raw Ethernet device discovery, such as PCAP-backed
discovery, need permission to open raw network sockets. Instead of running your
application with ``sudo``, grant the installed executable the required Linux
capabilities:
.. code-block:: bash
sudo setcap cap_net_raw,cap_net_admin=eip /usr/bin/your-app
Replace ``/usr/bin/your-app`` with the full path to the application executable.
+75
View File
@@ -1,6 +1,17 @@
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_LEGACY_EXAMPLE "Build the command-line simple C example." ON)
option(LIBICSNEO_BUILD_C2_SIMPLE_EXAMPLE "Build the simple C2 example." ON)
option(LIBICSNEO_BUILD_C2_READ_MESSAGES_EXAMPLE "Build the C2 read messages example." ON)
option(LIBICSNEO_BUILD_C2_DISKFORMAT_EXAMPLE "Build the C2 disk format example." ON)
option(LIBICSNEO_BUILD_C2_RECONNECT_EXAMPLE "Build the C2 reconnect example." ON)
option(LIBICSNEO_BUILD_C2_DEVICE_INFO_EXAMPLE "Build the C2 device info example." ON)
option(LIBICSNEO_BUILD_C2_LIN_EXAMPLE "Build the C2 LIN example." ON)
option(LIBICSNEO_BUILD_C2_LIN_TRANSMIT_EXAMPLE "Build the C2 LIN transmit example." ON)
option(LIBICSNEO_BUILD_C2_ETHERNET_TRANSMIT_EXAMPLE "Build the C2 ethernet transmit example." ON)
option(LIBICSNEO_BUILD_C2_ETHERNET_RECEIVE_EXAMPLE "Build the C2 ethernet receive example." ON)
option(LIBICSNEO_BUILD_C2_T1S_LOOPBACK_EXAMPLE "Build the C2 RAD-Comet3 T1S loopback example." ON)
option(LIBICSNEO_BUILD_C2_TC10_EXAMPLE "Build the C2 TC10 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_A2B_EXAMPLE "Build the A2B example." ON)
@@ -10,9 +21,13 @@ 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_VSA_EXAMPLE "Build the VSA example." ON)
option(LIBICSNEO_BUILD_CPP_APP_ERROR_EXAMPLE "Build the app error example." ON)
option(LIBICSNEO_BUILD_CPP_APP_ERROR_EXAMPLE "Build the macsec example" ON)
option(LIBICSNEO_BUILD_CPP_FLEXRAY_EXAMPLE "Build the FlexRay example." ON)
option(LIBICSNEO_BUILD_CPP_SPI_EXAMPLE "Build the SPI example." ON)
option(LIBICSNEO_BUILD_CPP_MUTEX_EXAMPLE "Build the NetworkMutex example." ON)
option(LIBICSNEO_BUILD_CPP_ANALOG_OUT_EXAMPLE "Build the analog output example." ON)
option(LIBICSNEO_BUILD_CPP_DISKFORMAT_EXAMPLE "Build the disk format example." ON)
option(LIBICSNEO_BUILD_CPP_T1S_EXAMPLE "Build the T1S example." ON)
add_compile_options(${LIBICSNEO_COMPILER_WARNINGS})
@@ -28,6 +43,50 @@ if(LIBICSNEO_BUILD_C_LEGACY_EXAMPLE)
add_subdirectory(c/legacy)
endif()
if(LIBICSNEO_BUILD_C2_SIMPLE_EXAMPLE)
add_subdirectory(c2/simple)
endif()
if(LIBICSNEO_BUILD_C2_READ_MESSAGES_EXAMPLE)
add_subdirectory(c2/read_messages)
endif()
if(LIBICSNEO_BUILD_C2_DISKFORMAT_EXAMPLE)
add_subdirectory(c2/diskformat)
endif()
if(LIBICSNEO_BUILD_C2_RECONNECT_EXAMPLE)
add_subdirectory(c2/reconnect)
endif()
if(LIBICSNEO_BUILD_C2_DEVICE_INFO_EXAMPLE)
add_subdirectory(c2/device_info)
endif()
if(LIBICSNEO_BUILD_C2_LIN_EXAMPLE)
add_subdirectory(c2/lin)
endif()
if(LIBICSNEO_BUILD_C2_LIN_TRANSMIT_EXAMPLE)
add_subdirectory(c2/lin_transmit)
endif()
if(LIBICSNEO_BUILD_C2_ETHERNET_TRANSMIT_EXAMPLE)
add_subdirectory(c2/ethernet_transmit)
endif()
if(LIBICSNEO_BUILD_C2_ETHERNET_RECEIVE_EXAMPLE)
add_subdirectory(c2/ethernet_receive)
endif()
if(LIBICSNEO_BUILD_C2_T1S_LOOPBACK_EXAMPLE)
add_subdirectory(c2/t1s_loopback)
endif()
if(LIBICSNEO_BUILD_C2_TC10_EXAMPLE)
add_subdirectory(c2/tc10)
endif()
if(LIBICSNEO_BUILD_CPP_SIMPLE_EXAMPLE)
add_subdirectory(cpp/simple)
endif()
@@ -64,6 +123,10 @@ if(LIBICSNEO_BUILD_CPP_APP_ERROR_EXAMPLE)
add_subdirectory(cpp/apperror)
endif()
if(LIBICSNEO_BUILD_CPP_APP_ERROR_EXAMPLE)
add_subdirectory(cpp/macsec)
endif()
if(LIBICSNEO_BUILD_CPP_FLEXRAY_EXAMPLE)
add_subdirectory(cpp/flexray)
endif()
@@ -75,3 +138,15 @@ endif()
if(LIBICSNEO_BUILD_CPP_MUTEX_EXAMPLE)
add_subdirectory(cpp/mutex)
endif()
if(LIBICSNEO_BUILD_CPP_ANALOG_OUT_EXAMPLE)
add_subdirectory(cpp/analog_out)
endif()
if(LIBICSNEO_BUILD_CPP_DISKFORMAT_EXAMPLE)
add_subdirectory(cpp/diskformat)
endif()
if(LIBICSNEO_BUILD_CPP_T1S_EXAMPLE)
add_subdirectory(cpp/t1s)
endif()
+6
View File
@@ -0,0 +1,6 @@
add_executable(libicsneoc2-device-info-example src/main.c)
target_link_libraries(libicsneoc2-device-info-example icsneoc2-static)
if(WIN32)
target_compile_definitions(libicsneoc2-device-info-example PRIVATE _CRT_SECURE_NO_WARNINGS)
endif()
+127
View File
@@ -0,0 +1,127 @@
#include <icsneo/icsneoc2.h>
#include <stdio.h>
#include <inttypes.h>
int print_error_code(const char* message, icsneoc2_error_t error) {
char error_str[64];
size_t error_str_len = sizeof(error_str);
icsneoc2_error_t res = icsneoc2_error_code_get(error, error_str, &error_str_len);
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;
}
int main() {
icsneoc2_error_t res;
/* ===== Device Selection ===== */
printf("Searching for devices...\n");
icsneoc2_device_info_t* found_devices = NULL;
res = icsneoc2_device_enumerate(0, &found_devices);
if(res != icsneoc2_error_success) {
return print_error_code("Failed to enumerate devices", res);
}
if(!found_devices) {
printf("No devices found.\n");
return 1;
}
/* Count and display devices */
int device_count = 0;
for(icsneoc2_device_info_t* cur = found_devices; cur; cur = icsneoc2_device_info_next(cur)) {
char desc[128] = {0};
size_t desc_len = sizeof(desc);
icsneoc2_device_info_description_get(cur, desc, &desc_len);
char serial[32] = {0};
size_t serial_len = sizeof(serial);
icsneoc2_device_info_serial_get(cur, serial, &serial_len);
printf(" [%d] %s (Serial: %s)\n", device_count + 1, desc, serial);
device_count++;
}
int device_choice;
printf("Select device (1-%d): ", device_count);
if(scanf("%d", &device_choice) != 1 || device_choice < 1 || device_choice > device_count) {
printf("Invalid selection.\n");
icsneoc2_enumeration_free(found_devices);
return 1;
}
/* Find the selected device_info node */
icsneoc2_device_info_t* selected_info = found_devices;
for(int i = 1; i < device_choice; i++) {
selected_info = icsneoc2_device_info_next(selected_info);
}
/* Open the selected device */
icsneoc2_device_t* device = NULL;
res = icsneoc2_device_create(selected_info, &device);
if(res != icsneoc2_error_success) {
icsneoc2_enumeration_free(found_devices);
return print_error_code("Failed to create device from device info", res);
}
res = icsneoc2_device_open(device, icsneoc2_open_options_default);
icsneoc2_enumeration_free(found_devices);
if(res != icsneoc2_error_success) {
icsneoc2_device_free(device);
return print_error_code("Failed to open device", res);
}
char description[128] = {0};
size_t description_length = sizeof(description);
icsneoc2_device_description_get(device, description, &description_length);
printf("\nOpened device: %s\n\n", description);
/* ===== Serial Number ===== */
char serial[32] = {0};
size_t serial_len = sizeof(serial);
res = icsneoc2_device_serial_get(device, serial, &serial_len);
if(res == icsneoc2_error_success) {
printf("Serial: %s\n", serial);
} else {
print_error_code("Failed to get serial", res);
}
/* ===== PCB Serial Number ===== */
uint8_t pcbsn[16] = {0};
size_t pcbsn_len = sizeof(pcbsn);
res = icsneoc2_device_pcb_serial_get(device, pcbsn, &pcbsn_len);
if(res == icsneoc2_error_success) {
printf("PCB Serial: ");
for(size_t i = 0; i < pcbsn_len; i++) {
printf("%c", pcbsn[i]);
}
printf("\n");
} else {
print_error_code("Failed to get PCB serial (device may not support it)", res);
}
/* ===== MAC Address ===== */
uint8_t mac[6] = {0};
size_t mac_len = sizeof(mac);
res = icsneoc2_device_mac_address_get(device, mac, &mac_len);
if(res == icsneoc2_error_success) {
printf("MAC: ");
for(size_t i = 0; i < mac_len; i++) {
if(i > 0) printf(":");
printf("%02X", mac[i]);
}
printf("\n");
} else {
print_error_code("Failed to get MAC address (device may not support it)", res);
}
/* Cleanup */
printf("\nClosing device... ");
res = icsneoc2_device_close(device);
printf("%s\n", res == icsneoc2_error_success ? "OK" : "FAIL");
icsneoc2_device_free(device);
return 0;
}
+6
View File
@@ -0,0 +1,6 @@
add_executable(libicsneoc2-diskformat-example src/main.c)
target_link_libraries(libicsneoc2-diskformat-example icsneoc2-static)
if(WIN32)
target_compile_definitions(libicsneoc2-diskformat-example PRIVATE _CRT_SECURE_NO_WARNINGS)
endif()
+183
View File
@@ -0,0 +1,183 @@
#include <icsneo/icsneoc2.h>
#include <stdio.h>
#include <inttypes.h>
/**
* Prints an error message with the given string and error code.
*
* @param message The message to print.
* @param error The error code to print.
* @return error as int
*/
static int print_error_code(const char* message, icsneoc2_error_t error) {
char error_str[64];
size_t error_str_len = sizeof(error_str);
icsneoc2_error_code_get(error, error_str, &error_str_len);
printf("%s: \"%s\" (%u)\n", message, error_str, error);
return (int)error;
}
/**
* Progress callback invoked periodically during disk formatting.
*
* @param sectors_formatted Number of sectors formatted so far.
* @param total_sectors Total number of sectors to format.
* @param user_data Unused opaque pointer.
* @return icsneoc2_disk_format_directive_continue to keep formatting.
*/
static icsneoc2_disk_format_directive_t format_progress(uint64_t sectors_formatted, uint64_t total_sectors, void* user_data) {
(void)user_data;
double pct = total_sectors > 0 ? (100.0 * (double)sectors_formatted / (double)total_sectors) : 0.0;
printf("\r Progress: %" PRIu64 " / %" PRIu64 " sectors (%d%%)", sectors_formatted, total_sectors, (int)pct);
fflush(stdout);
return icsneoc2_disk_format_directive_continue;
}
int main() {
/* Open the first available device (no online needed for formatting) */
printf("Opening first available device...\n");
icsneoc2_device_t* device = NULL;
icsneoc2_error_t res = icsneoc2_device_open_first(0, ICSNEOC2_OPEN_OPTIONS_NONE, &device);
if(res != icsneoc2_error_success) {
return print_error_code("\tFailed to open first device", res);
}
/* Get a description of the opened device */
char description[255] = {0};
size_t description_length = sizeof(description);
res = icsneoc2_device_description_get(device, description, &description_length);
if(res != icsneoc2_error_success) {
icsneoc2_device_free(device);
return print_error_code("\tFailed to get device description", res);
}
printf("\tOpened device: %s\n", description);
/* Check disk formatting support */
bool supported = false;
res = icsneoc2_device_supports_disk_formatting(device, &supported);
if(res != icsneoc2_error_success) {
print_error_code("\tFailed to check disk formatting support", res);
icsneoc2_device_close(device);
icsneoc2_device_free(device);
return -1;
}
if(!supported) {
printf("\terror: %s does not support disk formatting\n", description);
icsneoc2_device_close(device);
icsneoc2_device_free(device);
return -1;
}
size_t disk_count = 0;
icsneoc2_device_disk_count_get(device, &disk_count);
printf("\tDisk count: %zu\n", disk_count);
/* Query disk details */
printf("\tQuerying disk details... ");
fflush(stdout);
icsneoc2_disk_details_t* details = NULL;
res = icsneoc2_device_disk_details_get(device, &details);
if(res != icsneoc2_error_success) {
printf("FAIL\n");
print_error_code("\tFailed to get disk details", res);
icsneoc2_device_close(device);
icsneoc2_device_free(device);
return -1;
}
printf("OK\n");
/* Display current state */
icsneoc2_disk_layout_t layout = 0;
icsneoc2_disk_details_layout_get(details, &layout);
printf("\t Layout : %s\n", layout == icsneoc2_disk_layout_raid0 ? "RAID0" : "Spanned");
size_t detail_count = 0;
icsneoc2_disk_details_count_get(details, &detail_count);
for(size_t i = 0; i < detail_count; i++) {
icsneoc2_disk_format_flags_t flags = 0;
icsneoc2_disk_details_flags_get(details, i, &flags);
printf("\t Disk [%zu]:\n", i);
printf("\t Present : %s\n", (flags & ICSNEOC2_DISK_FORMAT_FLAGS_PRESENT) ? "yes" : "no");
printf("\t Initialized : %s\n", (flags & ICSNEOC2_DISK_FORMAT_FLAGS_INITIALIZED) ? "yes" : "no");
printf("\t Formatted : %s\n", (flags & ICSNEOC2_DISK_FORMAT_FLAGS_FORMATTED) ? "yes" : "no");
if(flags & ICSNEOC2_DISK_FORMAT_FLAGS_PRESENT) {
uint64_t sectors = 0, bps = 0;
icsneoc2_disk_details_size_get(details, i, &sectors, &bps);
printf("\t Size : %" PRIu64 " MB (%" PRIu64 " sectors x %" PRIu64 " bytes)\n",
(sectors * bps) / (1024 * 1024), sectors, bps);
}
}
/* Build format config: mark present disks for formatting */
bool any_present = false;
for(size_t i = 0; i < detail_count; i++) {
icsneoc2_disk_format_flags_t flags = 0;
icsneoc2_disk_details_flags_get(details, i, &flags);
if(flags & ICSNEOC2_DISK_FORMAT_FLAGS_PRESENT) {
flags |= ICSNEOC2_DISK_FORMAT_FLAGS_FORMATTED;
icsneoc2_disk_details_flags_set(details, i, flags);
any_present = true;
}
}
icsneoc2_disk_details_full_format_set(details, false); /* Quick format */
if(!any_present) {
printf("\n\terror: no disks are present in the device\n");
icsneoc2_disk_details_free(details);
icsneoc2_device_close(device);
icsneoc2_device_free(device);
return -1;
}
/* Confirm */
printf("\n\tThis will format the disk(s) in %s.\n", description);
printf("\tAll existing data will be lost. Continue? [y/N]: ");
char confirm[8] = {0};
if(scanf("%7s", confirm) != 1 || (confirm[0] != 'y' && confirm[0] != 'Y')) {
printf("\tAborted.\n");
icsneoc2_disk_details_free(details);
icsneoc2_device_close(device);
icsneoc2_device_free(device);
return 0;
}
/* Format */
printf("\n\tStarting format...\n");
res = icsneoc2_device_format_disk(device, details, format_progress, NULL);
printf("\n"); /* newline after progress line */
if(res != icsneoc2_error_success) {
print_error_code("\tFormat failed", res);
icsneoc2_disk_details_free(details);
icsneoc2_device_close(device);
icsneoc2_device_free(device);
return -1;
}
printf("\tFormat complete!\n");
icsneoc2_disk_details_free(details);
/* Verify */
printf("\n\tVerifying disk state after format... ");
fflush(stdout);
icsneoc2_disk_details_t* post_details = NULL;
res = icsneoc2_device_disk_details_get(device, &post_details);
if(res != icsneoc2_error_success) {
printf("FAIL (could not re-query disk details)\n");
} else {
printf("OK\n");
size_t post_count = 0;
icsneoc2_disk_details_count_get(post_details, &post_count);
for(size_t i = 0; i < post_count; i++) {
icsneoc2_disk_format_flags_t flags = 0;
icsneoc2_disk_details_flags_get(post_details, i, &flags);
printf("\t Disk [%zu] formatted: %s\n", i, (flags & ICSNEOC2_DISK_FORMAT_FLAGS_FORMATTED) ? "yes" : "no");
}
icsneoc2_disk_details_free(post_details);
}
printf("\tClosing device: %s...\n", description);
icsneoc2_device_close(device);
icsneoc2_device_free(device);
return 0;
}
@@ -0,0 +1,6 @@
add_executable(libicsneoc2-ethernet-receive-example src/main.c)
target_link_libraries(libicsneoc2-ethernet-receive-example icsneoc2-static)
if(WIN32)
target_compile_definitions(libicsneoc2-ethernet-receive-example PRIVATE _CRT_SECURE_NO_WARNINGS)
endif()
+223
View File
@@ -0,0 +1,223 @@
#include <icsneo/icsneoc2.h>
#include <icsneo/icsneoc2messages.h>
#include <stdio.h>
#include <inttypes.h>
#ifdef _WIN32
#include <windows.h>
#else
#include <unistd.h>
#endif
void sleep_ms(uint32_t ms) {
#ifdef _WIN32
Sleep(ms);
#else
sleep(ms / 1000);
#endif
}
int print_error_code(const char* message, icsneoc2_error_t error) {
char error_str[64];
size_t error_str_len = sizeof(error_str);
icsneoc2_error_t res = icsneoc2_error_code_get(error, error_str, &error_str_len);
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;
}
void print_events(void) {
icsneoc2_event_t* events[256] = {0};
size_t events_count = 256;
for(size_t i = 0; i < events_count; ++i) {
icsneoc2_error_t res = icsneoc2_event_get(&events[i], NULL);
if(res != icsneoc2_error_success) {
(void)print_error_code("\tFailed to get events", res);
return;
}
if(events[i] == NULL) {
events_count = i;
break;
}
}
for(size_t i = 0; i < events_count; i++) {
char description[255] = {0};
size_t description_length = 255;
icsneoc2_error_t res = icsneoc2_event_description_get(events[i], description, &description_length);
if(res != icsneoc2_error_success) {
print_error_code("\tFailed to get event description", res);
continue;
}
printf("\tEvent %zu: %s\n", i, description);
}
for(size_t i = 0; i < events_count; i++) {
icsneoc2_event_free(events[i]);
}
if(events_count > 0) {
printf("\tReceived %zu events\n", events_count);
}
}
void print_mac(const char* label, const uint8_t* mac) {
printf("%s: %02x:%02x:%02x:%02x:%02x:%02x", label, mac[0], mac[1], mac[2], mac[3], mac[4], mac[5]);
}
int process_ethernet_message(icsneoc2_message_t* message, size_t index) {
icsneoc2_netid_t netid = 0;
char netid_name[128] = {0};
size_t netid_name_length = 128;
icsneoc2_error_t res = icsneoc2_message_netid_get(message, &netid);
if(res != icsneoc2_error_success) {
return print_error_code("\tFailed to get netid", res);
}
res = icsneoc2_netid_name_get(netid, netid_name, &netid_name_length);
if(res != icsneoc2_error_success) {
return print_error_code("\tFailed to get netid name", res);
}
/* Get data length first */
size_t data_length = 0;
res = icsneoc2_message_data_get(message, NULL, &data_length);
if(res != icsneoc2_error_success) {
return print_error_code("\tFailed to get data length", res);
}
printf("\t%zu) Ethernet Frame on %s (0x%x) - %zu bytes\n", index, netid_name, netid, data_length);
/* Get MAC addresses and EtherType if we have enough data */
uint8_t dst_mac[6] = {0};
uint8_t src_mac[6] = {0};
uint16_t ether_type = 0;
res = icsneoc2_message_eth_mac_get(message, dst_mac, src_mac);
if(res == icsneoc2_error_success) {
printf("\t ");
print_mac("Dst", dst_mac);
printf(" ");
print_mac("Src", src_mac);
printf("\n");
}
res = icsneoc2_message_eth_ether_type_get(message, &ether_type);
if(res == icsneoc2_error_success) {
printf("\t EtherType: 0x%04x\n", ether_type);
}
/* Get flags */
icsneoc2_message_eth_flags_t flags = 0;
res = icsneoc2_message_eth_props_get(message, &flags, NULL, NULL);
if(res == icsneoc2_error_success && flags != 0) {
printf("\t Flags: 0x%" PRIx64, flags);
if(flags & ICSNEOC2_MESSAGE_ETH_FLAGS_CRC_ERROR) printf(" [CRC_ERROR]");
if(flags & ICSNEOC2_MESSAGE_ETH_FLAGS_FRAME_TOO_SHORT) printf(" [FRAME_TOO_SHORT]");
if(flags & ICSNEOC2_MESSAGE_ETH_FLAGS_TX_ABORTED) printf(" [TX_ABORTED]");
if(flags & ICSNEOC2_MESSAGE_ETH_FLAGS_FCS_VERIFIED) printf(" [FCS_VERIFIED]");
if(flags & ICSNEOC2_MESSAGE_ETH_FLAGS_PREEMPTION_ENABLED) printf(" [PREEMPTION]");
if(flags & ICSNEOC2_MESSAGE_ETH_FLAGS_IS_T1S) printf(" [T1S]");
printf("\n");
}
/* Print data bytes */
uint8_t data[1600] = {0};
res = icsneoc2_message_data_get(message, data, &data_length);
if(res == icsneoc2_error_success) {
printf("\t Data:\n\t ");
for(size_t x = 0; x < data_length; x++) {
printf("0x%02x ", data[x]);
if((x + 1) % 20 == 0 && x + 1 < data_length) {
printf("\n\t ");
}
}
printf("\n");
}
return icsneoc2_error_success;
}
int main(void) {
/* Open the first available device */
printf("Opening first available device...\n");
icsneoc2_device_t* device = NULL;
icsneoc2_error_t res = icsneoc2_device_open_first(0, icsneoc2_open_options_default, &device);
if(res != icsneoc2_error_success) {
return print_error_code("Failed to open first device", res);
}
/* Get a description of the opened device */
char description[255] = {0};
size_t description_length = 255;
res = icsneoc2_device_description_get(device, description, &description_length);
if(res != icsneoc2_error_success) {
return print_error_code("Failed to get device description", res);
}
printf("Opened device: %s\n", description);
/* Wait for Ethernet frames to arrive */
const int duration_seconds = 10;
printf("Listening for Ethernet frames for %d seconds...\n", duration_seconds);
sleep_ms(duration_seconds * 1000);
/* Retrieve and process messages */
icsneoc2_message_t* messages[20000] = {0};
size_t message_count = 20000;
size_t eth_count = 0;
for(size_t i = 0; i < message_count; ++i) {
res = icsneoc2_device_message_get(device, &messages[i], 0);
if(res != icsneoc2_error_success) {
print_events();
return print_error_code("Failed to get messages", res);
}
if(messages[i] == NULL) {
message_count = i;
break;
}
}
printf("Got %zu messages total, filtering for Ethernet...\n", message_count);
for(size_t i = 0; i < message_count; i++) {
icsneoc2_message_t* message = messages[i];
/* Check if this is a TX echo (skip it) */
bool is_tx = false;
res = icsneoc2_message_is_transmit(message, &is_tx);
if(res != icsneoc2_error_success || is_tx) {
continue;
}
/* Check if this is an Ethernet message */
bool is_ethernet = false;
res = icsneoc2_message_is_ethernet(message, &is_ethernet);
if(res != icsneoc2_error_success || !is_ethernet) {
continue;
}
process_ethernet_message(message, eth_count);
eth_count++;
}
printf("Received %zu Ethernet frames out of %zu total messages\n", eth_count, message_count);
/* Free all messages */
for(size_t i = 0; i < message_count; ++i) {
icsneoc2_message_free(messages[i]);
}
/* Print any events */
print_events();
/* Close the device */
printf("Closing device...\n");
res = icsneoc2_device_close(device);
if(res != icsneoc2_error_success) {
return print_error_code("Failed to close device", res);
}
return 0;
}
@@ -0,0 +1,6 @@
add_executable(libicsneoc2-ethernet-transmit-example src/main.c)
target_link_libraries(libicsneoc2-ethernet-transmit-example icsneoc2-static)
if(WIN32)
target_compile_definitions(libicsneoc2-ethernet-transmit-example PRIVATE _CRT_SECURE_NO_WARNINGS)
endif()
+204
View File
@@ -0,0 +1,204 @@
#include <icsneo/icsneoc2.h>
#include <icsneo/icsneoc2messages.h>
#include <stdio.h>
#include <inttypes.h>
#ifdef _WIN32
#include <windows.h>
#else
#include <unistd.h>
#endif
int print_error_code(const char* message, icsneoc2_error_t error) {
char error_str[64];
size_t error_str_len = sizeof(error_str);
icsneoc2_error_t res = icsneoc2_error_code_get(error, error_str, &error_str_len);
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;
}
void print_events(void) {
icsneoc2_event_t* events[256] = {0};
size_t events_count = 256;
for(size_t i = 0; i < events_count; ++i) {
icsneoc2_error_t res = icsneoc2_event_get(&events[i], NULL);
if(res != icsneoc2_error_success) {
(void)print_error_code("\tFailed to get events", res);
return;
}
if(events[i] == NULL) {
events_count = i;
break;
}
}
for(size_t i = 0; i < events_count; i++) {
char description[255] = {0};
size_t description_length = 255;
icsneoc2_error_t res = icsneoc2_event_description_get(events[i], description, &description_length);
if(res != icsneoc2_error_success) {
print_error_code("\tFailed to get event description", res);
continue;
}
printf("\tEvent %zu: %s\n", i, description);
}
for(size_t i = 0; i < events_count; i++) {
icsneoc2_event_free(events[i]);
}
if(events_count > 0) {
printf("\tReceived %zu events\n", events_count);
}
}
int main(void) {
/* Open the first available device */
printf("Opening first available device...\n");
icsneoc2_device_t* device = NULL;
icsneoc2_error_t res = icsneoc2_device_open_first(0, icsneoc2_open_options_default, &device);
if(res != icsneoc2_error_success) {
return print_error_code("Failed to open first device", res);
}
/* Get a description of the opened device */
char description[255] = {0};
size_t description_length = 255;
res = icsneoc2_device_description_get(device, description, &description_length);
if(res != icsneoc2_error_success) {
return print_error_code("Failed to get device description", res);
}
printf("Opened device: %s\n", description);
icsneoc2_netid_t tx_networks[255] = {0};
size_t tx_net_count = sizeof(tx_networks) / sizeof(tx_networks[0]);
res = icsneoc2_device_supported_tx_networks_get(device, tx_networks, &tx_net_count);
if(res != icsneoc2_error_success) {
print_events();
return print_error_code("Failed to get TX networks", res);
}
/* Filter for Ethernet/AutomotiveEthernet networks */
icsneoc2_netid_t eth_networks[64] = {0};
char eth_names[64][128] = {{0}};
size_t eth_count = 0;
for(size_t i = 0; i < tx_net_count && eth_count < 64; i++) {
/* Create a temporary message to check network type */
icsneoc2_message_t* tmp = NULL;
res = icsneoc2_message_eth_create(&tmp);
if(res != icsneoc2_error_success) continue;
res = icsneoc2_message_netid_set(tmp, tx_networks[i]);
if(res != icsneoc2_error_success) { icsneoc2_message_free(tmp); continue; }
icsneoc2_network_type_t ntype = 0;
res = icsneoc2_message_network_type_get(tmp, &ntype);
icsneoc2_message_free(tmp);
if(res != icsneoc2_error_success) continue;
if(ntype == icsneoc2_network_type_ethernet || ntype == icsneoc2_network_type_automotive_ethernet) {
eth_networks[eth_count] = tx_networks[i];
size_t name_len = 128;
icsneoc2_netid_name_get(tx_networks[i], eth_names[eth_count], &name_len);
eth_count++;
}
}
if(eth_count == 0) {
printf("No Ethernet TX networks available on this device.\n");
icsneoc2_device_close(device);
return 0;
}
/* Let the user pick */
printf("Available Ethernet TX networks:\n");
for(size_t i = 0; i < eth_count; i++) {
printf(" %zu) %s\n", i + 1, eth_names[i]);
}
printf("Select network [1-%zu]: ", eth_count);
int selection = 0;
if(scanf("%d", &selection) != 1 || selection < 1 || (size_t)selection > eth_count) {
printf("Invalid selection, using first available.\n");
selection = 1;
}
icsneoc2_netid_t netid = eth_networks[selection - 1];
printf("Selected: %s\n", eth_names[selection - 1]);
/* Transmit Ethernet frames */
const size_t msg_count = 10;
printf("Transmitting %zu Ethernet frames on %s...\n", msg_count, eth_names[selection - 1]);
for(size_t i = 0; i < msg_count; i++) {
/* Create an Ethernet message */
icsneoc2_message_t* message = NULL;
res = icsneoc2_message_eth_create(&message);
if(res != icsneoc2_error_success) {
print_events();
return print_error_code("Failed to create Ethernet message", res);
}
/* Set the network ID */
res = icsneoc2_message_netid_set(message, netid );
if(res != icsneoc2_error_success) {
icsneoc2_message_free(message);
print_events();
return print_error_code("Failed to set netid", res);
}
/* Build Ethernet frame data:
* Bytes 0-5: Destination MAC (00:FC:70:00:01:02)
* Bytes 6-11: Source MAC (00:FC:70:00:01:01)
* Bytes 12-13: EtherType (0x0800 = IPv4)
* Bytes 14+: Payload
*/
uint8_t frame_data[] = {
0x00, 0xFC, 0x70, 0x00, 0x01, 0x02, /* Destination MAC */
0x00, 0xFC, 0x70, 0x00, 0x01, 0x01, /* Source MAC */
0x08, 0x00, /* EtherType (IPv4) */
0x45, 0x00, 0x00, 0x20, /* IPv4: ver/IHL, DSCP, total length (32) */
0x00, 0x00, 0x00, 0x00, /* Identification, flags/fragment offset */
0x40, 0x11, 0x00, 0x00, /* TTL (64), protocol (UDP), checksum (0) */
0xC0, 0xA8, 0x01, 0x01, /* Source IP (192.168.1.1) */
0xC0, 0xA8, 0x01, 0x02, /* Destination IP (192.168.1.2) */
0xC3, 0x50, 0xC3, 0x51, /* UDP: src port (50000), dst port (50001) */
0x00, 0x0C, 0x00, 0x00, /* UDP: length (12), checksum (0) */
0x00, 0x00, 0x00, 0x00 /* UDP payload (4 bytes, frame counter) */
};
/* Put the frame counter in the UDP payload */
frame_data[42] = (uint8_t)((i >> 24) & 0xFF);
frame_data[43] = (uint8_t)((i >> 16) & 0xFF);
frame_data[44] = (uint8_t)((i >> 8) & 0xFF);
frame_data[45] = (uint8_t)(i & 0xFF);
res = icsneoc2_message_data_set(message, frame_data, sizeof(frame_data));
if(res != icsneoc2_error_success) {
icsneoc2_message_free(message);
print_events();
return print_error_code("Failed to set frame data", res);
}
/* Transmit the message */
res = icsneoc2_device_message_transmit(device, message);
if(res != icsneoc2_error_success) {
icsneoc2_message_free(message);
print_events();
return print_error_code("Failed to transmit Ethernet frame", res);
}
icsneoc2_message_free(message);
printf("\tTransmitted frame %zu\n", i + 1);
}
printf("Successfully transmitted %zu Ethernet frames\n", msg_count);
/* Print any events */
print_events();
/* Close the device */
printf("Closing device...\n");
res = icsneoc2_device_close(device);
if(res != icsneoc2_error_success) {
return print_error_code("Failed to close device", res);
}
return 0;
}
+6
View File
@@ -0,0 +1,6 @@
add_executable(libicsneoc2-lin-example src/main.c)
target_link_libraries(libicsneoc2-lin-example icsneoc2-static)
if(WIN32)
target_compile_definitions(libicsneoc2-lin-example PRIVATE _CRT_SECURE_NO_WARNINGS)
endif()
+311
View File
@@ -0,0 +1,311 @@
/* Note: This example requires LIN 1 and LIN 2 channels to be connected on the device */
#include <icsneo/icsneoc2.h>
#include <icsneo/icsneoc2messages.h>
#include <icsneo/icsneoc2settings.h>
#ifdef _WIN32
#include <windows.h>
#else
#include <unistd.h>
#endif
#include <stdio.h>
#include <inttypes.h>
void sleep_ms(uint32_t ms) {
#ifdef _WIN32
Sleep(ms);
#else
sleep(ms / 1000);
#endif
}
int print_error_code(const char* message, icsneoc2_error_t error) {
char error_str[64];
size_t error_str_len = sizeof(error_str);
icsneoc2_error_t res = icsneoc2_error_code_get(error, error_str, &error_str_len);
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;
}
void print_events(const char* device_description) {
icsneoc2_event_t* events[1024] = {0};
size_t events_count = 1024;
for(size_t i = 0; i < events_count; ++i) {
icsneoc2_error_t res = icsneoc2_event_get(&events[i], NULL);
if(res != icsneoc2_error_success) {
for(size_t j = 0; j < i; ++j) {
icsneoc2_event_free(events[j]);
}
(void)print_error_code("\tFailed to get device events", res);
return;
}
if(events[i] == NULL) {
events_count = i;
break;
}
}
for(size_t i = 0; i < events_count; i++) {
char event_description[255] = {0};
size_t event_description_length = 255;
icsneoc2_error_t 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 %zu: %s\n", device_description, i, event_description);
}
for(size_t i = 0; i < events_count; i++) {
icsneoc2_event_free(events[i]);
}
printf("\t%s: Received %zu events\n", device_description, events_count);
}
void process_lin_messages(icsneoc2_message_t** messages, size_t count) {
for(size_t i = 0; i < count; i++) {
bool is_lin = false;
icsneoc2_error_t res = icsneoc2_message_is_lin(messages[i], &is_lin);
if(res != icsneoc2_error_success || !is_lin)
continue;
uint8_t id = 0;
uint8_t protected_id = 0;
uint8_t checksum = 0;
icsneoc2_lin_msg_type_t msg_type = 0;
bool is_enhanced_checksum = false;
res = icsneoc2_message_lin_props_get(messages[i], &id, &protected_id, &checksum, &msg_type, &is_enhanced_checksum);
if(res != icsneoc2_error_success) {
print_error_code("\tFailed to get LIN properties", res);
continue;
}
icsneoc2_netid_t netid = 0;
icsneoc2_message_netid_get(messages[i], &netid);
char netid_name[128] = {0};
size_t netid_name_length = 128;
icsneoc2_netid_name_get(netid, netid_name, &netid_name_length);
uint8_t data[64] = {0};
size_t data_length = 64;
icsneoc2_message_data_get(messages[i], data, &data_length);
icsneoc2_lin_err_flags_t err_flags = 0;
icsneoc2_message_lin_err_flags_get(messages[i], &err_flags);
printf("\t%s RX | ID: 0x%02x | Protected ID: 0x%02x\n", netid_name, id, protected_id);
printf("\tData: [");
for(size_t x = 0; x < data_length; x++) {
printf(" 0x%02x", data[x]);
}
printf(" ]\n");
printf("\tChecksum type: %s\n", is_enhanced_checksum ? "Enhanced" : "Classic");
printf("\tChecksum: 0x%02x\n", checksum);
printf("\tChecksum valid: %s\n\n", (!(err_flags & ICSNEOC2_LIN_ERR_CHECKSUM_MATCH)) ? "yes" : "no");
}
}
int main() {
/* Open the first available device */
printf("Opening first available device...\n");
icsneoc2_device_t* device = NULL;
icsneoc2_error_t res = icsneoc2_device_open_first(0, icsneoc2_open_options_default, &device);
if(res != icsneoc2_error_success) {
return print_error_code("\tFailed to open first device", res);
}
char description[255] = {0};
size_t description_length = 255;
res = icsneoc2_device_description_get(device, description, &description_length);
if(res != icsneoc2_error_success) {
icsneoc2_device_close(device);
return print_error_code("\tFailed to get device description", res);
}
printf("\tOpened device: %s\n\n", description);
/* Configure LIN settings */
int64_t baud = 19200;
printf("Enable LIN 01 commander resistor... ");
res = icsneoc2_settings_commander_resistor_set(device, icsneoc2_netid_lin_01, true);
printf("%s\n", res == icsneoc2_error_success ? "OK" : "FAIL");
printf("Disable LIN 02 commander resistor... ");
res = icsneoc2_settings_commander_resistor_set(device, icsneoc2_netid_lin_02, false);
printf("%s\n", res == icsneoc2_error_success ? "OK" : "FAIL");
printf("Setting LIN 01 baudrate to %" PRId64 " bit/s... ", baud);
res = icsneoc2_settings_baudrate_set(device, icsneoc2_netid_lin_01, baud);
printf("%s\n", res == icsneoc2_error_success ? "OK" : "FAIL");
printf("Setting LIN 02 baudrate to %" PRId64 " bit/s... ", baud);
res = icsneoc2_settings_baudrate_set(device, icsneoc2_netid_lin_02, baud);
printf("%s\n", res == icsneoc2_error_success ? "OK" : "FAIL");
printf("Setting LIN 01 mode to NORMAL... ");
res = icsneoc2_settings_lin_mode_set(device, icsneoc2_netid_lin_01, icsneoc2_lin_mode_normal);
printf("%s\n", res == icsneoc2_error_success ? "OK" : "FAIL");
printf("Setting LIN 02 mode to NORMAL... ");
res = icsneoc2_settings_lin_mode_set(device, icsneoc2_netid_lin_02, icsneoc2_lin_mode_normal);
printf("%s\n", res == icsneoc2_error_success ? "OK" : "FAIL");
printf("Applying settings... ");
res = icsneoc2_settings_apply(device);
if(res != icsneoc2_error_success) {
print_events(description);
icsneoc2_device_close(device);
return print_error_code("\tFailed to apply settings", res);
}
printf("OK\n");
printf("Getting LIN 01 baudrate... ");
int64_t read_baud = 0;
res = icsneoc2_settings_baudrate_get(device, icsneoc2_netid_lin_01, &read_baud);
if(res == icsneoc2_error_success)
printf("OK, %" PRId64 " bit/s\n", read_baud);
else
printf("FAIL\n");
printf("Getting LIN 02 baudrate... ");
res = icsneoc2_settings_baudrate_get(device, icsneoc2_netid_lin_02, &read_baud);
if(res == icsneoc2_error_success)
printf("OK, %" PRId64 " bit/s\n\n", read_baud);
else
printf("FAIL\n\n");
/* Transmit a LIN responder data update on LIN 02 */
printf("Transmitting a LIN 02 responder data frame... ");
{
icsneoc2_message_t* msg = NULL;
res = icsneoc2_message_lin_create(&msg, 0x11);
if(res != icsneoc2_error_success) {
print_events(description);
icsneoc2_device_close(device);
return print_error_code("\tFailed to create LIN message", res);
}
icsneoc2_lin_msg_type_t msg_type = icsneoc2_lin_msg_type_update_responder;
res = icsneoc2_message_lin_props_set(msg, NULL, NULL, &msg_type, NULL);
uint8_t data[] = {0xaa, 0xbb, 0xcc, 0xdd, 0x11, 0x22, 0x33, 0x44};
res += icsneoc2_message_data_set(msg, data, sizeof(data));
res += icsneoc2_message_netid_set(msg, icsneoc2_netid_lin_02);
res += icsneoc2_message_lin_calc_checksum(msg);
if(res != icsneoc2_error_success) {
icsneoc2_message_free(msg);
print_events(description);
icsneoc2_device_close(device);
return print_error_code("\tFailed to set LIN message properties", res);
}
res = icsneoc2_device_message_transmit(device, msg);
icsneoc2_message_free(msg);
if(res != icsneoc2_error_success) {
print_events(description);
icsneoc2_device_close(device);
return print_error_code("\tFailed to transmit LIN responder message", res);
}
printf("OK\n");
}
/* Transmit a LIN commander header on LIN 01 */
printf("Transmitting a LIN 01 commander header... ");
{
icsneoc2_message_t* msg = NULL;
res = icsneoc2_message_lin_create(&msg, 0x11);
if(res != icsneoc2_error_success) {
print_events(description);
icsneoc2_device_close(device);
return print_error_code("\tFailed to create LIN message", res);
}
icsneoc2_lin_msg_type_t msg_type = icsneoc2_lin_msg_type_header_only;
res = icsneoc2_message_lin_props_set(msg, NULL, NULL, &msg_type, NULL);
res += icsneoc2_message_netid_set(msg, icsneoc2_netid_lin_01);
if(res != icsneoc2_error_success) {
icsneoc2_message_free(msg);
print_events(description);
icsneoc2_device_close(device);
return print_error_code("\tFailed to set LIN message properties", res);
}
res = icsneoc2_device_message_transmit(device, msg);
icsneoc2_message_free(msg);
if(res != icsneoc2_error_success) {
print_events(description);
icsneoc2_device_close(device);
return print_error_code("\tFailed to transmit LIN header", res);
}
printf("OK\n\n");
}
sleep_ms(100);
/* Transmit a LIN commander message with data on LIN 01 */
printf("Transmitting a LIN 01 commander frame with data... ");
{
icsneoc2_message_t* msg = NULL;
res = icsneoc2_message_lin_create(&msg, 0x22);
if(res != icsneoc2_error_success) {
print_events(description);
icsneoc2_device_close(device);
return print_error_code("\tFailed to create LIN message", res);
}
icsneoc2_lin_msg_type_t msg_type = icsneoc2_lin_msg_type_commander_msg;
bool enhanced = true;
res = icsneoc2_message_lin_props_set(msg, NULL, NULL, &msg_type, &enhanced);
uint8_t data[] = {0x11, 0x22, 0x33, 0x44, 0xaa, 0xbb, 0xcc, 0xdd};
res += icsneoc2_message_data_set(msg, data, sizeof(data));
res += icsneoc2_message_netid_set(msg, icsneoc2_netid_lin_01);
res += icsneoc2_message_lin_calc_checksum(msg);
if(res != icsneoc2_error_success) {
icsneoc2_message_free(msg);
print_events(description);
icsneoc2_device_close(device);
return print_error_code("\tFailed to set LIN message properties", res);
}
res = icsneoc2_device_message_transmit(device, msg);
icsneoc2_message_free(msg);
if(res != icsneoc2_error_success) {
print_events(description);
icsneoc2_device_close(device);
return print_error_code("\tFailed to transmit LIN commander message", res);
}
printf("OK\n\n");
}
sleep_ms(100);
/* Read back any received messages and display LIN frames */
icsneoc2_message_t* messages[2048] = {0};
size_t message_count = 2048;
printf("Getting messages...\n");
for(size_t i = 0; i < message_count; ++i) {
res = icsneoc2_device_message_get(device, &messages[i], 0);
if(res != icsneoc2_error_success) {
for(size_t j = 0; j < i; ++j) {
icsneoc2_message_free(messages[j]);
}
print_events(description);
icsneoc2_device_close(device);
return print_error_code("\tFailed to get messages", res);
}
if(messages[i] == NULL) {
message_count = i;
break;
}
}
printf("\tReceived %zu messages\n", message_count);
process_lin_messages(messages, message_count);
for(size_t i = 0; i < message_count; ++i) {
icsneoc2_message_free(messages[i]);
}
/* Cleanup */
print_events(description);
printf("Closing device... ");
res = icsneoc2_device_close(device);
printf("%s\n", res == icsneoc2_error_success ? "OK" : "FAIL");
return 0;
}
+6
View File
@@ -0,0 +1,6 @@
add_executable(libicsneoc2-lin-transmit-example src/main.c)
target_link_libraries(libicsneoc2-lin-transmit-example icsneoc2-static)
if(WIN32)
target_compile_definitions(libicsneoc2-lin-transmit-example PRIVATE _CRT_SECURE_NO_WARNINGS)
endif()
+276
View File
@@ -0,0 +1,276 @@
#include <icsneo/icsneoc2.h>
#include <icsneo/icsneoc2messages.h>
#include <icsneo/icsneoc2settings.h>
#ifdef _WIN32
#include <windows.h>
#else
#include <unistd.h>
#endif
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <inttypes.h>
void sleep_ms(uint32_t ms) {
#ifdef _WIN32
Sleep(ms);
#else
sleep(ms / 1000);
#endif
}
int print_error_code(const char* message, icsneoc2_error_t error) {
char error_str[64];
size_t error_str_len = sizeof(error_str);
icsneoc2_error_t res = icsneoc2_error_code_get(error, error_str, &error_str_len);
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;
}
int read_int(const char* prompt, int min_val, int max_val) {
int value;
while(1) {
printf("%s", prompt);
if(scanf("%d", &value) != 1) {
/* Clear invalid input */
int c;
while((c = getchar()) != '\n' && c != EOF) {}
printf("Invalid input, try again.\n");
continue;
}
if(value < min_val || value > max_val) {
printf("Please enter a value between %d and %d.\n", min_val, max_val);
continue;
}
return value;
}
}
int read_hex(const char* prompt, int min_val, int max_val) {
int value;
while(1) {
printf("%s", prompt);
if(scanf("%x", &value) != 1) {
/* Clear invalid input */
int c;
while((c = getchar()) != '\n' && c != EOF) {}
printf("Invalid input, try again.\n");
continue;
}
if(value < min_val || value > max_val) {
printf("Please enter a value between 0x%X and 0x%X.\n", min_val, max_val);
continue;
}
return value;
}
}
int main() {
icsneoc2_error_t res;
/* ===== Device Selection ===== */
printf("Searching for devices...\n");
icsneoc2_device_info_t* found_devices = NULL;
res = icsneoc2_device_enumerate(0, &found_devices);
if(res != icsneoc2_error_success) {
return print_error_code("Failed to enumerate devices", res);
}
if(!found_devices) {
printf("No devices found.\n");
return 1;
}
/* Count and display devices */
int device_count = 0;
for(icsneoc2_device_info_t* cur = found_devices; cur; cur = icsneoc2_device_info_next(cur)) {
char desc[128] = {0};
size_t desc_len = sizeof(desc);
icsneoc2_device_info_description_get(cur, desc, &desc_len);
printf(" [%d] %s\n", device_count + 1, desc);
device_count++;
}
int device_choice = read_int("Select device: ", 1, device_count);
/* Find the selected device_info node */
icsneoc2_device_info_t* selected_info = found_devices;
for(int i = 1; i < device_choice; i++) {
selected_info = icsneoc2_device_info_next(selected_info);
}
/* Open the selected device */
icsneoc2_device_t* device = NULL;
res = icsneoc2_device_create(selected_info, &device);
if(res != icsneoc2_error_success) {
icsneoc2_enumeration_free(found_devices);
return print_error_code("Failed to create device from device info", res);
}
res = icsneoc2_device_open(device, icsneoc2_open_options_default);
icsneoc2_enumeration_free(found_devices);
if(res != icsneoc2_error_success) {
icsneoc2_device_free(device);
return print_error_code("Failed to open device", res);
}
char description[128] = {0};
size_t description_length = sizeof(description);
icsneoc2_device_description_get(device, description, &description_length);
printf("Opened device: %s\n\n", description);
/* ===== LIN Network Selection ===== */
/* Get all supported TX networks */
size_t tx_net_count = 0;
res = icsneoc2_device_supported_tx_networks_get(device, NULL, &tx_net_count);
if(res != icsneoc2_error_success || tx_net_count == 0) {
printf("No supported TX networks.\n");
icsneoc2_device_close(device);
return 1;
}
icsneoc2_netid_t* tx_networks = (icsneoc2_netid_t*)malloc(tx_net_count * sizeof(icsneoc2_netid_t));
if(!tx_networks) {
printf("Out of memory.\n");
icsneoc2_device_close(device);
icsneoc2_device_free(device);
return 1;
}
res = icsneoc2_device_supported_tx_networks_get(device, tx_networks, &tx_net_count);
if(res != icsneoc2_error_success) {
free(tx_networks);
icsneoc2_device_close(device);
icsneoc2_device_free(device);
return print_error_code("Failed to get TX networks", res);
}
/* Filter for LIN networks */
icsneoc2_netid_t lin_networks[64] = {0};
char lin_names[64][128] = {{0}};
size_t lin_count = 0;
for(size_t i = 0; i < tx_net_count && lin_count < 64; i++) {
icsneoc2_message_t* tmp = NULL;
res = icsneoc2_message_lin_create(&tmp, 0);
if(res != icsneoc2_error_success) continue;
res = icsneoc2_message_netid_set(tmp, tx_networks[i]);
if(res != icsneoc2_error_success) { icsneoc2_message_free(tmp); continue; }
icsneoc2_network_type_t ntype = 0;
res = icsneoc2_message_network_type_get(tmp, &ntype);
icsneoc2_message_free(tmp);
if(res != icsneoc2_error_success) continue;
if(ntype == icsneoc2_network_type_lin) {
lin_networks[lin_count] = tx_networks[i];
size_t name_len = 128;
icsneoc2_netid_name_get(tx_networks[i], lin_names[lin_count], &name_len);
lin_count++;
}
}
free(tx_networks);
if(lin_count == 0) {
printf("No LIN networks available on this device.\n");
icsneoc2_device_close(device);
icsneoc2_device_free(device);
return 1;
}
printf("Available LIN networks:\n");
for(size_t i = 0; i < lin_count; i++) {
printf(" [%zu] %s\n", i + 1, lin_names[i]);
}
int lin_choice = read_int("Select LIN network: ", 1, (int)lin_count);
icsneoc2_netid_t selected_netid = lin_networks[lin_choice - 1];
printf("Selected: %s\n\n", lin_names[lin_choice - 1]);
/* ===== Commander / Responder Selection ===== */
printf("Message type:\n");
printf(" [1] Commander frame\n");
printf(" [2] Responder frame (update responder + header only)\n");
int type_choice = read_int("Select message type: ", 1, 2);
bool is_commander = (type_choice == 1);
printf("Selected: %s\n\n", is_commander ? "Commander" : "Responder");
uint8_t id_choice = (uint8_t)read_hex("Select LIN ID (0x00-0x3F): ", 0, 0x3F);
printf("Selected: 0x%02X\n\n", id_choice);
/* ===== Configure LIN ===== */
printf("Configuring %s... ", lin_names[lin_choice - 1]);
res = icsneoc2_settings_commander_resistor_set(device, selected_netid, is_commander);
res += icsneoc2_settings_baudrate_set(device, selected_netid, 19200);
res += icsneoc2_settings_lin_mode_set(device, selected_netid, icsneoc2_lin_mode_normal);
res += icsneoc2_settings_apply(device);
if(res != icsneoc2_error_success) {
icsneoc2_device_close(device);
icsneoc2_device_free(device);
return print_error_code("Failed to configure LIN", res);
}
printf("OK\n\n");
/* ===== Transmit Loop ===== */
printf("Transmitting on %s every second for 10 seconds...\n", lin_names[lin_choice - 1]);
uint8_t counter = 0;
for(int i = 0; i < 10; i++) {
icsneoc2_message_t* msg = NULL;
res = icsneoc2_message_lin_create(&msg, id_choice);
if(res != icsneoc2_error_success) {
print_error_code("\tFailed to create LIN message", res);
break;
}
uint8_t data[] = {counter, counter + 1, counter + 2, counter + 3, 0xAA, 0xBB, 0xCC, 0xDD};
bool enhanced = true;
if(is_commander) {
/* Commander: send header-only frame to poll the bus */
icsneoc2_lin_msg_type_t msg_type = icsneoc2_lin_msg_type_header_only;
res = icsneoc2_message_lin_props_set(msg, NULL, NULL, &msg_type, &enhanced);
res += icsneoc2_message_netid_set(msg, selected_netid);
if(res != icsneoc2_error_success) {
icsneoc2_message_free(msg);
print_error_code("\tFailed to set commander properties", res);
break;
}
res = icsneoc2_device_message_transmit(device, msg);
icsneoc2_message_free(msg);
if(res != icsneoc2_error_success) {
print_error_code("\tFailed to transmit header", res);
break;
}
} else {
/* Responder: update the responder table with new data */
icsneoc2_lin_msg_type_t msg_type = icsneoc2_lin_msg_type_update_responder;
res = icsneoc2_message_lin_props_set(msg, NULL, NULL, &msg_type, &enhanced);
res += icsneoc2_message_data_set(msg, data, sizeof(data));
res += icsneoc2_message_lin_calc_checksum(msg);
res += icsneoc2_message_netid_set(msg, selected_netid);
if(res != icsneoc2_error_success) {
icsneoc2_message_free(msg);
print_error_code("\tFailed to update responder", res);
break;
}
res = icsneoc2_device_message_transmit(device, msg);
icsneoc2_message_free(msg);
if(res != icsneoc2_error_success) {
print_error_code("\tFailed to transmit responder update", res);
break;
}
}
printf("[%2d/10] Transmitted %s msg ID=0x%02X, counter=%u\n",
i + 1, is_commander ? "commander" : "responder", id_choice, counter);
counter += 4;
sleep_ms(1000);
}
/* Cleanup */
printf("\nClosing device... ");
res = icsneoc2_device_close(device);
printf("%s\n", res == icsneoc2_error_success ? "OK" : "FAIL");
icsneoc2_device_free(device);
return 0;
}
+6
View File
@@ -0,0 +1,6 @@
add_executable(libicsneoc2-read_messages-example src/main.c)
target_link_libraries(libicsneoc2-read_messages-example icsneoc2-static)
if(WIN32)
target_compile_definitions(libicsneoc2-read_messages-example PRIVATE _CRT_SECURE_NO_WARNINGS)
endif()
+331
View File
@@ -0,0 +1,331 @@
#include <icsneo/icsneoc2.h>
#include <icsneo/icsneoc2settings.h>
#include <icsneo/icsneoc2messages.h>
#include <stdio.h>
#include <inttypes.h>
#include <time.h>
#ifdef _WIN32
#include <windows.h>
#else
#include <unistd.h>
#endif
/**
* 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) {
#ifdef _WIN32
Sleep(ms);
#else
sleep(ms / 1000);
#endif
}
/**
* Prints all events
*
* @param device_description A description of the device used in the output.
*/
void print_events(const char* device_description);
/**
* 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[64];
size_t error_str_len = sizeof(error_str);
icsneoc2_error_t res = icsneoc2_error_code_get(error, error_str, &error_str_len);
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;
}
/**
* 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 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_message(icsneoc2_message_t** messages, size_t messages_count);
int transmit_can_messages(icsneoc2_device_t* device);
int main() {
// Open the first available device with default options
printf("Opening first available device...\n");
icsneoc2_device_t* open_device = NULL;
icsneoc2_error_t res = icsneoc2_device_open_first(0, icsneoc2_open_options_default, &open_device);
if(res != icsneoc2_error_success) {
return print_error_code("\tFailed to open first device", res);
};
// Get a description of the opened device
char description[255] = {0};
size_t description_length = 255;
res = icsneoc2_device_description_get(open_device, description, &description_length);
if(res != icsneoc2_error_success) {
icsneoc2_device_free(open_device);
return print_error_code("\tFailed to get device description", res);
};
printf("\tOpened device: %s\n", description);
// Transmit messages for debugging purposes
// transmit_can_messages(open_device);
// sleep_ms(1000);
// Get the messages
icsneoc2_message_t* messages[20000] = {0};
size_t message_count = 20000;
time_t start_time = time(NULL);
printf("\tGetting messages from device with timeout of 3000ms on %s...\n", description);
for(size_t i = 0; i < message_count; ++i) {
res = icsneoc2_device_message_get(open_device, &messages[i], 0);
if(res != icsneoc2_error_success) {
print_events(description);
icsneoc2_device_free(open_device);
return print_error_code("\tFailed to get messages from device", res);
};
if(messages[i] == NULL) {
// no more messages
message_count = i;
break;
}
}
if(res != icsneoc2_error_success) {
print_events(description);
icsneoc2_device_free(open_device);
return print_error_code("\tFailed to get messages from device", res);
}
time_t end_time = time(NULL);
printf("\tGot %zu messages in %lld seconds\n", message_count, (long long)(end_time - start_time));
// Process the messages
res = process_message(messages, message_count);
if(res != icsneoc2_error_success) {
print_events(description);
icsneoc2_device_free(open_device);
return print_error_code("\tFailed to process messages", res);
}
// Finally, close the device.
printf("\tClosing device: %s...\n", description);
res = icsneoc2_device_close(open_device);
if(res != icsneoc2_error_success) {
print_events(description);
icsneoc2_device_free(open_device);
return print_error_code("\tFailed to close device", res);
};
icsneoc2_device_free(open_device);
printf("\n");
return 0;
}
void print_events(const char* device_description) {
icsneoc2_event_t* events[1024] = {0};
size_t events_count = 1024;
for(size_t i = 0; i < events_count; ++i) {
// no device filter, get all events
icsneoc2_error_t res = icsneoc2_event_get(&events[i], NULL);
if(res != icsneoc2_error_success) {
(void)print_error_code("\tFailed to get device events", res);
return;
}
if(events[i] == NULL) {
events_count = i;
break;
}
}
// Loop over each event and describe it.
for(size_t i = 0; i < events_count; i++) {
char event_description[255] = {0};
size_t event_description_length = 255;
icsneoc2_error_t 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 %zu: %s\n", device_description, i, event_description);
}
for(size_t i = 0; i < events_count; i++) {
icsneoc2_event_free(events[i]);
}
printf("\t%s: Received %zu events\n", device_description, events_count);
}
int process_message(icsneoc2_message_t** messages, size_t messages_count) {
// Print the type and bus type of each message
size_t tx_count = 0;
size_t can_error_count = 0;
icsneoc2_error_t res = icsneoc2_error_success;
for(size_t i = 0; i < messages_count; i++) {
icsneoc2_message_t* message = messages[i];
bool is_can_error = false;
res = icsneoc2_message_is_can_error(message, &is_can_error);
if(res != icsneoc2_error_success) {
return print_error_code("\tFailed to check if message is a CAN error", res);
}
if(is_can_error) {
icsneoc2_network_type_t network_type;
uint8_t tec = 0;
uint8_t rec = 0;
icsneoc2_can_error_code_t error_code = 0;
icsneoc2_can_error_code_t data_error_code = 0;
icsneoc2_message_can_error_flags_t error_flags = 0;
icsneoc2_netid_t netid = 0;
char network_type_name[128] = {0};
size_t network_type_name_length = 128;
char netid_name[128] = {0};
size_t netid_name_length = 128;
res = icsneoc2_message_network_type_get(message, &network_type);
res += icsneoc2_network_type_name_get(network_type, network_type_name, &network_type_name_length);
res += icsneoc2_message_netid_get(message, &netid);
res += icsneoc2_netid_name_get(netid, netid_name, &netid_name_length);
res += icsneoc2_message_can_error_props_get(message, &tec, &rec, &error_code, &data_error_code, &error_flags);
if(res != icsneoc2_error_success) {
return print_error_code("\tFailed to get CAN error properties", res);
}
printf("\t%zd) CAN Error on %s [%s] (0x%x): TEC=%u REC=%u ErrorCode=%u DataErrorCode=%u%s%s%s\n",
i, netid_name, network_type_name, netid, tec, rec, error_code, data_error_code,
(error_flags & ICSNEOC2_MESSAGE_CAN_ERROR_FLAGS_BUS_OFF) ? " [BusOff]" : "",
(error_flags & ICSNEOC2_MESSAGE_CAN_ERROR_FLAGS_ERROR_PASSIVE) ? " [ErrorPassive]" : "",
(error_flags & ICSNEOC2_MESSAGE_CAN_ERROR_FLAGS_ERROR_WARN) ? " [ErrorWarn]" : "");
can_error_count++;
continue;
}
bool is_frame = false;
res = icsneoc2_message_is_frame(message, &is_frame);
if(res != icsneoc2_error_success) {
return print_error_code("\tFailed to check if message is a frame", res);
}
if(!is_frame) {
printf("Ignoring non-frame message at index %zu\n", i);
continue;
}
icsneoc2_network_type_t network_type;
res = icsneoc2_message_network_type_get(message, &network_type);
if(res != icsneoc2_error_success) {
return print_error_code("\tFailed to get message network type", res);
}
char network_type_name[128] = {0};
size_t network_type_name_length = 128;
res = icsneoc2_network_type_name_get(network_type, network_type_name, &network_type_name_length);
if(res != icsneoc2_error_success) {
return print_error_code("\tFailed to get message bus type name", res);
}
if(res != icsneoc2_error_success) {
return print_error_code("\tFailed to get message is transmit", res);
}
printf("\t%zd) network type: %s (%u)\n", i, network_type_name, network_type);
if(network_type == icsneoc2_network_type_can) {
uint64_t arbid = 0;
int32_t dlc = 0;
icsneoc2_netid_t netid = 0;
icsneoc2_message_can_flags_t can_flags = 0;
uint8_t data[64] = {0};
size_t data_length = 64;
char netid_name[128] = {0};
size_t netid_name_length = 128;
bool is_error = false;
bool is_tx = false;
icsneoc2_error_t result = icsneoc2_message_netid_get(message, &netid);
result += icsneoc2_netid_name_get(netid, netid_name, &netid_name_length);
result += icsneoc2_message_can_props_get(message, &arbid, &can_flags);
result += icsneoc2_message_data_get(message, data, &data_length);
result += icsneoc2_message_is_transmit(message, &is_tx);
result += icsneoc2_message_is_error(message, &is_error);
if(result != icsneoc2_error_success) {
printf("\tFailed get get CAN parameters (error: %u) for index %zu\n", result, i);
continue;
}
tx_count += is_tx ? 1 : 0;
bool is_remote = (can_flags & ICSNEOC2_MESSAGE_CAN_FLAGS_RTR) != 0;
bool is_extended = (can_flags & ICSNEOC2_MESSAGE_CAN_FLAGS_IDE) != 0;
bool is_canfd = (can_flags & ICSNEOC2_MESSAGE_CAN_FLAGS_FDF) != 0;
bool is_brs = (can_flags & ICSNEOC2_MESSAGE_CAN_FLAGS_BRS) != 0;
bool is_esi = (can_flags & ICSNEOC2_MESSAGE_CAN_FLAGS_ESI) != 0;
bool tx_aborted = (can_flags & ICSNEOC2_MESSAGE_CAN_FLAGS_TX_ABORTED) != 0;
bool tx_lost_arb = (can_flags & ICSNEOC2_MESSAGE_CAN_FLAGS_TX_LOST_ARB) != 0;
bool tx_error = (can_flags & ICSNEOC2_MESSAGE_CAN_FLAGS_TX_ERROR) != 0;
dlc = (int32_t)data_length;
printf("\t %s%s\n", is_tx ? "TX" : "RX", is_error ? " [Error]" : "");
printf("\t NetID: %s (0x%x)\tArbID: 0x%llx\tDLC: %u\tLen: %zu\n", netid_name, netid, (unsigned long long)arbid, dlc, data_length);
printf("\t Flags:%s%s%s%s%s%s%s%s\n",
is_remote ? " RTR" : "",
is_extended ? " IDE" : "",
is_canfd ? " FDF" : "",
is_brs ? " BRS" : "",
is_esi ? " ESI" : "",
tx_aborted ? " TX_ABORTED" : "",
tx_lost_arb ? " TX_LOST_ARB" : "",
tx_error ? " TX_ERROR" : "");
printf("\t Data: [");
for(size_t x = 0; x < data_length; x++) {
printf(" 0x%x", data[x]);
}
printf(" ]\n");
}
}
printf("\tReceived %zu messages total, %zu were TX messages, %zu were CAN errors\n", messages_count, tx_count, can_error_count);
return icsneoc2_error_success;
}
int transmit_can_messages(icsneoc2_device_t* device) {
uint64_t counter = 0;
const size_t msg_count = 10;
printf("\tTransmitting %zd messages...\n", msg_count);
for(size_t i = 0; i < msg_count; i++) {
// Create the message
icsneoc2_message_t* message = NULL;
icsneoc2_error_t res = icsneoc2_message_can_create(&message);
if(res != icsneoc2_error_success) {
return print_error_code("\tFailed to create messages", res);
}
// Set the message attributes
res = icsneoc2_message_netid_set(message, icsneoc2_netid_dwcan_01);
uint64_t arb_id = 0x10;
uint64_t flags = 0;
res += icsneoc2_message_can_props_set(message, &arb_id, &flags);
res += icsneoc2_message_data_set(message, (uint8_t*)&counter, sizeof(counter));
if(res != icsneoc2_error_success) {
icsneoc2_message_free(message);
return print_error_code("\tFailed to modify message", res);
}
res = icsneoc2_device_message_transmit(device, message);
res += icsneoc2_message_free(message);
if(res != icsneoc2_error_success) {
return print_error_code("\tFailed to transmit message", res);
}
counter++;
}
return icsneoc2_error_success;
}
+6
View File
@@ -0,0 +1,6 @@
add_executable(libicsneoc2-reconnect-example src/main.c)
target_link_libraries(libicsneoc2-reconnect-example icsneoc2-static)
if(WIN32)
target_compile_definitions(libicsneoc2-reconnect-example PRIVATE _CRT_SECURE_NO_WARNINGS)
endif()
+132
View File
@@ -0,0 +1,132 @@
#include <icsneo/icsneoc2.h>
#include <stdio.h>
#ifdef _WIN32
#include <windows.h>
#else
#include <unistd.h>
#endif
void sleep_ms(uint32_t ms) {
#ifdef _WIN32
Sleep(ms);
#else
usleep(ms * 1000);
#endif
}
int print_error_code(const char* message, icsneoc2_error_t error) {
char error_str[64];
size_t error_str_len = sizeof(error_str);
icsneoc2_error_t res = icsneoc2_error_code_get(error, error_str, &error_str_len);
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;
}
void print_events(void) {
icsneoc2_event_t* events[256] = {0};
size_t events_count = 256;
for(size_t i = 0; i < events_count; ++i) {
icsneoc2_error_t res = icsneoc2_event_get(&events[i], NULL);
if(res != icsneoc2_error_success) {
(void)print_error_code("\tFailed to get events", res);
return;
}
if(events[i] == NULL) {
events_count = i;
break;
}
}
for(size_t i = 0; i < events_count; i++) {
char description[255] = {0};
size_t description_length = 255;
icsneoc2_error_t res = icsneoc2_event_description_get(events[i], description, &description_length);
if(res != icsneoc2_error_success) {
print_error_code("\tFailed to get event description", res);
continue;
}
printf("\tEvent %zu: %s\n", i, description);
}
for(size_t i = 0; i < events_count; i++) {
icsneoc2_event_free(events[i]);
}
if(events_count > 0) {
printf("\tReceived %zu events\n", events_count);
}
}
int main(void) {
/* Open the first available device */
printf("Opening first available device...\n");
icsneoc2_device_t* device = NULL;
icsneoc2_error_t res = icsneoc2_device_open_first(0, icsneoc2_open_options_default, &device);
if(res != icsneoc2_error_success) {
return print_error_code("Failed to open first device", res);
}
/* Get a description of the opened device */
char description[255] = {0};
size_t description_length = 255;
res = icsneoc2_device_description_get(device, description, &description_length);
if(res != icsneoc2_error_success) {
icsneoc2_device_free(device);
return print_error_code("Failed to get device description", res);
}
printf("Opened device: %s\n", description);
/* Wait for the device to disconnect */
printf("Waiting for device to disconnect (unplug device from PC)...\n");
for(;;) {
bool is_open = true;
res = icsneoc2_device_is_open(device, &is_open);
if(res != icsneoc2_error_success) {
print_events();
icsneoc2_device_free(device);
return print_error_code("Failed to check open status", res);
}
if(!is_open) {
printf("Device disconnected!\n");
break;
}
sleep_ms(500);
}
/* Attempt to reconnect */
uint32_t timeout_ms = 20000; // 20 second timeout
printf("Attempting to reconnect (%u second timeout)...\n", timeout_ms / 1000);
res = icsneoc2_device_reconnect(device, icsneoc2_open_options_default, timeout_ms);
if(res != icsneoc2_error_success) {
print_events();
icsneoc2_device_free(device);
return print_error_code("Failed to reconnect", res);
}
printf("Reconnected successfully!\n");
/* Verify by getting the description again */
description_length = 255;
res = icsneoc2_device_description_get(device, description, &description_length);
if(res == icsneoc2_error_success) {
printf("Device: %s\n", description);
}
/* Print any events */
print_events();
/* Close the device */
printf("Closing device...\n");
res = icsneoc2_device_close(device);
if(res != icsneoc2_error_success) {
icsneoc2_device_free(device);
return print_error_code("Failed to close device", res);
}
icsneoc2_device_free(device);
printf("Done.\n");
return 0;
}
+6
View File
@@ -0,0 +1,6 @@
add_executable(libicsneoc2-simple-example src/main.c)
target_link_libraries(libicsneoc2-simple-example icsneoc2-static)
if(WIN32)
target_compile_definitions(libicsneoc2-simple-example PRIVATE _CRT_SECURE_NO_WARNINGS)
endif()
+507
View File
@@ -0,0 +1,507 @@
#include <icsneo/icsneoc2.h>
#include <icsneo/icsneoc2messages.h>
#include <icsneo/icsneoc2settings.h>
#ifdef _WIN32
#include <windows.h>
#else
#include <unistd.h>
#endif
#include <stdio.h>
#include <inttypes.h>
#include <time.h>
/**
* 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) {
#ifdef _WIN32
Sleep(ms);
#else
sleep(ms / 1000);
#endif
}
/**
* 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[64];
size_t error_str_len = sizeof(error_str);
icsneoc2_error_t res = icsneoc2_error_code_get(error, error_str, &error_str_len);
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;
}
/**
* 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 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_message_t** messages, size_t messages_count);
/**
* Prints all events
*
* @param device_description A description of the device used in the output.
*/
void print_events(const char* device_description);
/**
* 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);
/**
* 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);
int main() {
icsneoc2_device_info_t* found_devices = NULL;
printf("Finding devices...\n");
icsneoc2_error_t res = icsneoc2_device_enumerate(0, &found_devices);
if(res != icsneoc2_error_success) {
return print_error_code("\tFailed to find devices", res);
}
if(found_devices == NULL) {
printf("No devices found, exiting\n");
return 0;
}
// Count and list off the devices
size_t devices_count = 0;
for(icsneoc2_device_info_t* cur = found_devices; cur != NULL; cur = icsneoc2_device_info_next(cur)) {
devices_count++;
}
printf("OK, %zu device%s found\n", devices_count, devices_count == 1 ? "" : "s");
for(icsneoc2_device_info_t* cur = found_devices; cur != NULL; cur = icsneoc2_device_info_next(cur)) {
// Get description of the device
char description[255] = {0};
size_t description_length = 255;
res = icsneoc2_device_info_description_get(cur, description, &description_length);
if(res != icsneoc2_error_success) {
icsneoc2_enumeration_free(found_devices);
return print_error_code("\tFailed to get device description", res);
};
printf("%.*s\n", (int)description_length, description);
// Open the device without RTC sync and going online
icsneoc2_open_options_t options = icsneoc2_open_options_default;
options &= ~ICSNEOC2_OPEN_OPTIONS_SYNC_RTC;
options &= ~ICSNEOC2_OPEN_OPTIONS_GO_ONLINE;
printf("\tDevice open options: 0x%x\n", options);
printf("\tOpening device: %s...\n", description);
icsneoc2_device_t* open_device = NULL;
res = icsneoc2_device_create(cur, &open_device);
if(res != icsneoc2_error_success) {
icsneoc2_enumeration_free(found_devices);
return print_error_code("\tFailed to create device", res);
}
res = icsneoc2_device_open(open_device, options);
if(res != icsneoc2_error_success) {
icsneoc2_device_free(open_device);
icsneoc2_enumeration_free(found_devices);
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(open_device, &timestamp_resolution);
if(res != icsneoc2_error_success) {
print_events(description);
icsneoc2_device_free(open_device);
icsneoc2_enumeration_free(found_devices);
return print_error_code("\tFailed to get timestamp resolution", res);
}
printf("%uns\n", timestamp_resolution);
// Get baudrates for HSCAN
printf("\tGetting DW CAN 01 Baudrate... ");
int64_t baudrate = 0;
res = icsneoc2_settings_baudrate_get(open_device, icsneoc2_netid_dwcan_01, &baudrate);
if(res != icsneoc2_error_success) {
print_events(description);
icsneoc2_device_free(open_device);
icsneoc2_enumeration_free(found_devices);
return print_error_code("\tFailed to get baudrate", res);
};
printf("%" PRIu64 "mbit/s\n", baudrate);
// Get FDbaudrates for HSCAN
printf("\tGetting FD DW CAN 01 Baudrate... ");
int64_t fd_baudrate = 0;
res = icsneoc2_settings_canfd_baudrate_get(open_device, icsneoc2_netid_dwcan_01, &fd_baudrate);
if(res != icsneoc2_error_success) {
print_events(description);
icsneoc2_device_free(open_device);
icsneoc2_enumeration_free(found_devices);
return print_error_code("\tFailed to get FD baudrate", res);
};
printf("%" PRIu64 "mbit/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
printf("\tSetting DW CAN 01 Baudrate... ");
res = icsneoc2_settings_baudrate_set(open_device, icsneoc2_netid_dwcan_01, baudrate);
if(res != icsneoc2_error_success) {
print_events(description);
icsneoc2_device_free(open_device);
icsneoc2_enumeration_free(found_devices);
return print_error_code("\tFailed to set baudrate", res);
};
printf("Ok\n");
// Set FDbaudrates for HSCAN
printf("\tSetting FD DW CAN 01 Baudrate... ");
res = icsneoc2_settings_canfd_baudrate_set(open_device, icsneoc2_netid_dwcan_01, fd_baudrate);
if(res != icsneoc2_error_success) {
print_events(description);
icsneoc2_device_free(open_device);
icsneoc2_enumeration_free(found_devices);
return print_error_code("\tFailed to set FD baudrate", res);
};
printf("Ok\n");
// Get RTC
printf("\tGetting RTC... ");
res = get_and_print_rtc(open_device);
if(res != icsneoc2_error_success) {
print_events(description);
icsneoc2_device_free(open_device);
icsneoc2_enumeration_free(found_devices);
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(open_device, current_time);
if(res != icsneoc2_error_success) {
print_events(description);
icsneoc2_device_free(open_device);
icsneoc2_enumeration_free(found_devices);
return print_error_code("\tFailed to set RTC", res);
}
printf("Ok\n");
// Get RTC
printf("\tGetting RTC... ");
res = get_and_print_rtc(open_device);
if(res != icsneoc2_error_success) {
print_events(description);
icsneoc2_device_free(open_device);
icsneoc2_enumeration_free(found_devices);
return print_error_code("\tFailed to get RTC", res);
}
// Go online, start acking traffic
printf("\tGoing online... ");
res = icsneoc2_device_go_online(open_device, true);
if(res != icsneoc2_error_success) {
print_events(description);
icsneoc2_device_free(open_device);
icsneoc2_enumeration_free(found_devices);
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(open_device, &is_online);
if(res != icsneoc2_error_success) {
print_events(description);
icsneoc2_device_free(open_device);
icsneoc2_enumeration_free(found_devices);
return print_error_code("\tFailed to check if online", res);
}
printf("%s\n", is_online ? "Online" : "Offline");
// Transmit CAN messages
res = transmit_can_messages(open_device);
if(res != icsneoc2_error_success) {
print_events(description);
icsneoc2_device_free(open_device);
icsneoc2_enumeration_free(found_devices);
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};
size_t message_count = 20000;
printf("\tGetting messages from device with timeout of 3000ms on %s...\n", description);
for(size_t i = 0; i < message_count; ++i) {
res = icsneoc2_device_message_get(open_device, &messages[i], 0);
if(res != icsneoc2_error_success) {
for(size_t j = 0; j < i; ++j) {
icsneoc2_message_free(messages[j]);
}
print_events(description);
icsneoc2_device_free(open_device);
icsneoc2_enumeration_free(found_devices);
return print_error_code("\tFailed to get messages from device", res);
};
if(messages[i] == NULL) {
// no more messages
message_count = i;
break;
}
}
// Process the messages
res = process_messages(messages, message_count);
if(res != icsneoc2_error_success) {
for(size_t i = 0; i < message_count; ++i) {
icsneoc2_message_free(messages[i]);
}
print_events(description);
icsneoc2_device_free(open_device);
icsneoc2_enumeration_free(found_devices);
return print_error_code("\tFailed to process messages", res);
}
for(size_t i = 0; i < message_count; ++i) {
icsneoc2_message_free(messages[i]);
}
// Finally, close the device.
printf("\tClosing device: %s...\n", description);
res = icsneoc2_device_close(open_device);
if(res != icsneoc2_error_success) {
print_events(description);
icsneoc2_device_free(open_device);
icsneoc2_enumeration_free(found_devices);
return print_error_code("\tFailed to close device", res);
};
// Print device events
print_events(description);
icsneoc2_device_free(open_device);
}
icsneoc2_enumeration_free(found_devices);
printf("\n");
return 0;
}
icsneoc2_error_t get_and_print_rtc(icsneoc2_device_t* device) {
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", (long long)unix_epoch, rtc_time);
return icsneoc2_error_success;
}
void print_events(const char* device_description) {
icsneoc2_event_t* events[1024] = {0};
size_t events_count = 1024;
for(size_t i = 0; i < events_count; ++i) {
// no device filter, get all events
icsneoc2_error_t res = icsneoc2_event_get(&events[i], NULL);
if(res != icsneoc2_error_success) {
for(size_t j = 0; j < i; ++j) {
icsneoc2_event_free(events[j]);
}
(void)print_error_code("\tFailed to get device events", res);
return;
}
if(events[i] == NULL) {
events_count = i;
break;
}
}
// Loop over each event and describe it.
for(size_t i = 0; i < events_count; i++) {
char event_description[255] = {0};
size_t event_description_length = 255;
icsneoc2_error_t 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 %zu: %s\n", device_description, i, event_description);
}
for(size_t i = 0; i < events_count; i++) {
icsneoc2_event_free(events[i]);
}
printf("\t%s: Received %zu events\n", device_description, events_count);
}
int process_messages(icsneoc2_message_t** messages, size_t messages_count) {
// Print the type and bus type of each message
size_t tx_count = 0;
size_t can_error_count = 0;
for(size_t i = 0; i < messages_count; i++) {
icsneoc2_message_t* message = messages[i];
// Check for CAN error messages
bool is_can_error = false;
icsneoc2_error_t res = icsneoc2_message_is_can_error(message, &is_can_error);
if(res != icsneoc2_error_success) {
return print_error_code("\tFailed to check if message is a CAN error", res);
}
if(is_can_error) {
uint8_t tec = 0;
uint8_t rec = 0;
icsneoc2_can_error_code_t error_code = 0;
icsneoc2_can_error_code_t data_error_code = 0;
icsneoc2_message_can_error_flags_t error_flags = 0;
icsneoc2_netid_t netid = 0;
res = icsneoc2_message_netid_get(message, &netid);
res += icsneoc2_message_can_error_props_get(message, &tec, &rec, &error_code, &data_error_code, &error_flags);
if(res != icsneoc2_error_success) {
return print_error_code("\tFailed to get CAN error properties", res);
}
char netid_name[128] = {0};
size_t netid_name_length = 128;
icsneoc2_netid_name_get(netid, netid_name, &netid_name_length);
printf("\t%zd) CAN Error on %s (0x%x): TEC=%u REC=%u ErrorCode=%u DataErrorCode=%u%s%s%s\n",
i, netid_name, netid, tec, rec, error_code, data_error_code,
(error_flags & ICSNEOC2_MESSAGE_CAN_ERROR_FLAGS_BUS_OFF) ? " [BusOff]" : "",
(error_flags & ICSNEOC2_MESSAGE_CAN_ERROR_FLAGS_ERROR_PASSIVE) ? " [ErrorPassive]" : "",
(error_flags & ICSNEOC2_MESSAGE_CAN_ERROR_FLAGS_ERROR_WARN) ? " [ErrorWarn]" : "");
can_error_count++;
continue;
}
bool is_frame = false;
res = icsneoc2_message_is_frame(message, &is_frame);
if(res != icsneoc2_error_success) {
return print_error_code("\tFailed to check if message is a frame", res);
}
if(!is_frame) {
printf("Ignoring non-frame message at index %zu\n", i);
continue;
}
icsneoc2_network_type_t network_type;
res = icsneoc2_message_network_type_get(message, &network_type);
if(res != icsneoc2_error_success) {
return print_error_code("\tFailed to get message network type", res);
}
char network_type_name[128] = {0};
size_t network_type_name_length = 128;
res = icsneoc2_network_type_name_get(network_type, network_type_name, &network_type_name_length);
if(res != icsneoc2_error_success) {
return print_error_code("\tFailed to get network type name", res);
}
bool is_tx = false;
res = icsneoc2_message_is_transmit(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%zd) network type: %s (%u)\n", i, network_type_name, network_type);
if(network_type == icsneoc2_network_type_can) {
uint64_t arbid = 0;
int32_t dlc = 0;
icsneoc2_netid_t netid = 0;
icsneoc2_message_can_flags_t can_flags = 0;
uint8_t data[64] = {0};
size_t data_length = 64;
char netid_name[128] = {0};
size_t netid_name_length = 128;
icsneoc2_error_t result = icsneoc2_message_netid_get(message, &netid);
result += icsneoc2_netid_name_get(netid, netid_name, &netid_name_length);
result += icsneoc2_message_can_props_get(message, &arbid, &can_flags);
result += icsneoc2_message_data_get(message, data, &data_length);
if(result != icsneoc2_error_success) {
printf("\tFailed get get CAN parameters (error: %u) for index %zu\n", result, i);
continue;
}
bool is_remote = (can_flags & ICSNEOC2_MESSAGE_CAN_FLAGS_RTR) != 0;
bool is_extended = (can_flags & ICSNEOC2_MESSAGE_CAN_FLAGS_IDE) != 0;
bool is_canfd = (can_flags & ICSNEOC2_MESSAGE_CAN_FLAGS_FDF) != 0;
bool is_brs = (can_flags & ICSNEOC2_MESSAGE_CAN_FLAGS_BRS) != 0;
bool is_esi = (can_flags & ICSNEOC2_MESSAGE_CAN_FLAGS_ESI) != 0;
bool tx_aborted = (can_flags & ICSNEOC2_MESSAGE_CAN_FLAGS_TX_ABORTED) != 0;
bool tx_lost_arb = (can_flags & ICSNEOC2_MESSAGE_CAN_FLAGS_TX_LOST_ARB) != 0;
bool tx_error = (can_flags & ICSNEOC2_MESSAGE_CAN_FLAGS_TX_ERROR) != 0;
dlc = (int32_t)data_length;
printf("\t NetID: %s (0x%x)\tArbID: 0x%llx\tDLC: %u\tLen: %zu\n", netid_name, netid, (unsigned long long)arbid, dlc, data_length);
printf("\t Flags:%s%s%s%s%s%s%s%s\n",
is_remote ? " RTR" : "",
is_extended ? " IDE" : "",
is_canfd ? " FDF" : "",
is_brs ? " BRS" : "",
is_esi ? " ESI" : "",
tx_aborted ? " TX_ABORTED" : "",
tx_lost_arb ? " TX_LOST_ARB" : "",
tx_error ? " TX_ERROR" : "");
printf("\t Data: [");
for(size_t x = 0; x < data_length; x++) {
printf(" 0x%x", data[x]);
}
printf(" ]\n");
}
}
printf("\tReceived %zu messages total, %zu were TX messages, %zu were CAN errors\n", messages_count, tx_count, can_error_count);
return icsneoc2_error_success;
}
int transmit_can_messages(icsneoc2_device_t* device) {
uint64_t counter = 0;
const size_t msg_count = 100;
printf("\tTransmitting %zd messages...\n", msg_count);
for(size_t i = 0; i < msg_count; i++) {
// Create the message
icsneoc2_message_t* message = NULL;
icsneoc2_error_t res = icsneoc2_message_can_create(&message);
if(res != icsneoc2_error_success) {
return print_error_code("\tFailed to create messages", res);
}
// Set the message attributes
res = icsneoc2_message_netid_set(message, icsneoc2_netid_dwcan_01);
uint64_t arb_id = 0x10;
uint64_t flags = ICSNEOC2_MESSAGE_CAN_FLAGS_BRS | ICSNEOC2_MESSAGE_CAN_FLAGS_IDE | ICSNEOC2_MESSAGE_CAN_FLAGS_FDF;
res += icsneoc2_message_can_props_set(message, &arb_id, &flags);
res += icsneoc2_message_data_set(message, (uint8_t*)&counter, sizeof(counter));
if(res != icsneoc2_error_success) {
icsneoc2_message_free(message);
return print_error_code("\tFailed to modify message", res);
}
res = icsneoc2_device_message_transmit(device, message);
res += icsneoc2_message_free(message);
if(res != icsneoc2_error_success) {
return print_error_code("\tFailed to transmit message", res);
}
counter++;
}
return icsneoc2_error_success;
}
+6
View File
@@ -0,0 +1,6 @@
add_executable(libicsneoc2-t1s-loopback-example src/main.c)
target_link_libraries(libicsneoc2-t1s-loopback-example icsneoc2-static)
if(WIN32)
target_compile_definitions(libicsneoc2-t1s-loopback-example PRIVATE _CRT_SECURE_NO_WARNINGS)
endif()

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