69 Commits
Author SHA1 Message Date
Thomas StoddardandKyle Schwarz e926e10dc5 RADGigastar2: Add to MACsecConfig 2026-05-14 11:29:54 -04:00
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
171 changed files with 20644 additions and 1126 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'"
+45 -7
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})
@@ -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 48df5dd7fd0c38034f82a2f94e0eada404d5e2b9
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:
+10 -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
+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
+75 -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.";
@@ -178,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()";
@@ -186,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.";
@@ -313,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:
@@ -321,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
@@ -358,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:
@@ -423,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:
@@ -437,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 {
+4 -1
View File
@@ -9,7 +9,7 @@ else()
FetchContent_Declare(
pybind11
GIT_REPOSITORY https://github.com/pybind/pybind11.git
GIT_TAG v3.0.1
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
@@ -34,11 +35,13 @@ pybind11_add_module(icsneopy
icsneopy/communication/message/spimessage.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
+1
View File
@@ -126,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)
@@ -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
@@ -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::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,6 +7,16 @@
namespace icsneo {
void init_ethphymessage(pybind11::module_& m) {
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)
@@ -16,18 +26,6 @@ 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::classh<EthPhyMessage, Message>(m, "EthPhyMessage")
.def(pybind11::init())
.def_readwrite("messages", &EthPhyMessage::messages);
@@ -9,38 +9,38 @@ namespace icsneo {
void init_gptpstatusmessage(pybind11::module_& m) {
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")
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")
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")
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("clock_quality", &GPTPStatus::SystemID::clockQuality)
.def_readonly("priority2", &GPTPStatus::SystemID::priority2)
.def_readonly("clock_id", &GPTPStatus::SystemID::clockID);
pybind11::class_<GPTPStatus::PriorityVector>(gptpStatus, "PriorityVector")
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")
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)
@@ -50,7 +50,7 @@ void init_gptpstatusmessage(pybind11::module_& m) {
.def_readonly("gm_priority1", &GPTPStatus::ParentDS::gmPriority1)
.def_readonly("gm_priority2", &GPTPStatus::ParentDS::gmPriority2);
pybind11::class_<GPTPStatus::CurrentDS>(gptpStatus, "CurrentDS")
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)
@@ -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)
@@ -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
@@ -8,7 +8,7 @@
namespace icsneo {
void init_network(pybind11::module_& m) {
pybind11::class_<Network> network(m, "Network");
pybind11::classh<Network> network(m, "Network");
pybind11::native_enum<Network::NetID>(network, "NetID", "enum.IntEnum")
.value("Device", Network::NetID::Device)
+6 -2
View File
@@ -103,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)
@@ -111,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)
@@ -126,10 +126,14 @@ 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("SFPModule_ent11100_MCHIP", ChipID::SFPModule_ent11100_MCHIP)
.value("RADGemini_MCHIP", ChipID::RADGemini_MCHIP)
.value("Invalid", ChipID::Invalid)
.finalize();
@@ -5,6 +5,7 @@
#include "icsneo/device/device.h"
#include "icsneo/device/extensions/deviceextension.h"
#include "icsneo/disk/diskdetails.h"
#include <fstream>
@@ -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);
}
@@ -8,7 +8,7 @@
namespace icsneo {
void init_devicetype(pybind11::module_& m) {
pybind11::class_<DeviceType> deviceType(m, "DeviceType");
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)
@@ -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::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)
+10 -6
View File
@@ -23,7 +23,7 @@ struct ClusterNamespace {
using SPPType = icsneo::FlexRay::Cluster::SPPType;
};
void init_extension(pybind11::class_<FlexRayNamespace>& c) {
void init_extension(pybind11::classh<FlexRayNamespace>& c) {
pybind11::classh<MessageBuffer>(c, "MessageBuffer")
.def(pybind11::init())
.def_readwrite("is_dynamic", &MessageBuffer::isDynamic)
@@ -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)
@@ -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)
+6
View File
@@ -25,6 +25,7 @@ void init_ethernetstatusmessage(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);
@@ -60,9 +64,11 @@ PYBIND11_MODULE(icsneopy, 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:
+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
+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;
+67 -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) {
@@ -127,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) {
@@ -152,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());
+66 -10
View File
@@ -144,7 +144,7 @@ typedef union _MACSecSa
{
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. */
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. */
@@ -230,6 +230,7 @@ MACsecConfig::MACsecConfig(const DeviceType& deviceType) : type(deviceType) {
case icsneo::DeviceType::Enum::RADMoon2:
case icsneo::DeviceType::Enum::RADMoon3:
case icsneo::DeviceType::Enum::RADEpsilon:
case icsneo::DeviceType::Enum::RADGigastar2:
maxSecY = 2;
maxRule = 2;
maxSa = 4;
@@ -285,14 +286,29 @@ int MACsecConfig::addTxSecY(const MACsecTxSecY& secY, uint8_t saIndex) {
}
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;
}
int ret = static_cast<int>(rxSa.size());
rxSa.emplace_back(sa);
return ret;
// 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) {
@@ -603,13 +619,23 @@ static void SetHardwareRxSecY(
hwSc->enable = 0x1u;
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 = 0x1u;
hwSc->sa_index1_in_use = rekeyEnabled ? 0x1u : 0x0u;
hwSc->isActiveSA1 = 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;
@@ -638,7 +664,9 @@ static void SetHardwareRxSa(MACSEC_SETTINGS_W_HDR* hwSettings, const MACsecRxSa&
MACSecSa_t* hwSa = &hwSettings->macsec.rx.sa[index];
hwSa->index = index;
hwSa->enable = 0x1u;
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);
@@ -740,6 +768,34 @@ std::vector<uint8_t> MACsecConfig::serialize() const {
}
}
// 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];
+54 -28
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);
}
@@ -560,27 +560,30 @@ 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;
}
}
}
);
});
}
}
@@ -610,6 +613,11 @@ bool Device::goOffline() {
return true;
}
if(assignedClientId.has_value()) {
unlockAllNetworks();
assignedClientId.reset();
}
if(!enableNetworkCommunication(false))
return false;
@@ -2246,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(
@@ -3809,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) {
@@ -3901,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;
}
@@ -3951,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;
}
@@ -3991,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;
}
@@ -4013,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;
}
@@ -4060,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;
}
+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>`
+25
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
========================================
@@ -82,3 +91,19 @@ SPI Example for 10BASE-T1S
.. 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.
+70
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)
@@ -14,6 +25,9 @@ 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})
@@ -29,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()
@@ -80,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()
+643
View File
@@ -0,0 +1,643 @@
#include <icsneo/icsneoc2.h>
#include <icsneo/icsneoc2messages.h>
#include <icsneo/icsneoc2settings.h>
#include <inttypes.h>
#include <stdbool.h>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#ifdef _WIN32
#include <windows.h>
#else
#include <unistd.h>
#endif
#define TX_LOCAL_ID 0u
#define RX_LOCAL_ID 1u
#define T1S_MAX_NODES 8u
#define T1S_TX_OPP_TIMER 20u
#define T1S_BURST_TIMER 64u
#define T1S_MAX_BURST 128u
#define LOOPBACK_ETHER_TYPE 0x9000u
#define LOOPBACK_FRAME_SIZE 60u
typedef struct selectable_network {
icsneoc2_netid_t netid;
char name[64];
} selectable_network_t;
/* Sleep for a short period while waiting for the device to apply settings. */
static void sleep_ms(uint32_t ms);
/* Print a readable error string and return the same failure code to the caller. */
static int print_error_code(const char* message, icsneoc2_error_t error);
/* Drain and print queued library events when the example encounters an error. */
static void print_events(void);
/* Convert a netid to a readable name such as "AE 02". */
static int get_netid_name(icsneoc2_netid_t netid, char* buffer, size_t buffer_size);
/* Gather the device's TX and RX networks, keeping only automotive Ethernet ports. */
static int get_available_networks(const icsneoc2_device_t* device,
selectable_network_t* tx_networks,
size_t* tx_count,
selectable_network_t* rx_networks,
size_t* rx_count);
/* Prompt the user to choose one TX or RX network from the filtered list. */
static int prompt_for_network_selection(const char* label, const selectable_network_t* networks, size_t count, icsneoc2_netid_t* selected_netid, char* selected_name, size_t selected_name_size);
/* Apply the small set of T1S settings needed for this two-port loopback example. */
static int configure_t1s_port(icsneoc2_device_t* device, icsneoc2_netid_t netid, uint8_t local_id);
/* Print a MAC address in a compact human-readable form. */
static void print_mac(const char* label, const uint8_t* mac);
/* Print payload bytes as hex for the TX echo and RX frame output. */
static void print_payload_hex(const uint8_t* data, size_t length);
/* Build one recognizable Ethernet frame that both transmit and receive paths share. */
static void build_loopback_frame(uint8_t* frame_data, size_t frame_size, const char* tx_name, const char* rx_name);
/* Check whether a received Ethernet frame matches the loopback frame this example sent. */
static int message_matches_loopback_frame(icsneoc2_message_t* message, const uint8_t* expected, size_t expected_length, bool* matches);
/* Print the key details of an Ethernet message found during the loopback test. */
static int print_ethernet_message(icsneoc2_message_t* message, const char* direction_label);
/* Transmit the loopback Ethernet frame on the selected TX port. */
static int transmit_loopback_frame(icsneoc2_device_t* device, icsneoc2_netid_t tx_netid, const char* tx_name, const char* rx_name);
/* Poll until the example sees both the TX echo and the matching RX frame. */
static int poll_for_loopback_messages(icsneoc2_device_t* device,
icsneoc2_netid_t tx_netid,
icsneoc2_netid_t rx_netid,
const char* tx_name,
const char* rx_name,
const uint8_t* expected_frame,
size_t expected_frame_length);
int main(void) {
icsneoc2_device_t* device = NULL;
icsneoc2_error_t res;
char description[255] = {0};
char serial[64] = {0};
size_t description_length = sizeof(description);
size_t serial_length = sizeof(serial);
selectable_network_t available_tx_networks[128] = {0};
selectable_network_t available_rx_networks[128] = {0};
size_t available_tx_count = 0;
size_t available_rx_count = 0;
icsneoc2_netid_t tx_netid = 0;
icsneoc2_netid_t rx_netid = 0;
uint8_t expected_frame[LOOPBACK_FRAME_SIZE] = {0};
char tx_name[64] = {0};
char rx_name[64] = {0};
int status = 1;
printf("RAD-Comet3 C2 T1S loopback example\n");
printf("Opening first available RAD-Comet3...\n");
res = icsneoc2_device_open_first(icsneoc2_devicetype_rad_comet3, icsneoc2_open_options_default, &device);
if(res != icsneoc2_error_success) {
return print_error_code("Failed to open a RAD-Comet3", res);
}
res = icsneoc2_device_description_get(device, description, &description_length);
if(res != icsneoc2_error_success) {
print_error_code("Failed to get device description", res);
goto cleanup;
}
res = icsneoc2_device_serial_get(device, serial, &serial_length);
if(res != icsneoc2_error_success) {
print_error_code("Failed to get device serial", res);
goto cleanup;
}
printf("Opened device: %s [%s]\n", description, serial);
if(get_available_networks(device, available_tx_networks, &available_tx_count, available_rx_networks, &available_rx_count) != 0) {
goto cleanup;
}
if(prompt_for_network_selection("TX", available_tx_networks, available_tx_count, &tx_netid, tx_name, sizeof(tx_name)) != 0) {
goto cleanup;
}
if(prompt_for_network_selection("RX", available_rx_networks, available_rx_count, &rx_netid, rx_name, sizeof(rx_name)) != 0) {
goto cleanup;
}
printf("Selected loopback wiring: %s connected to %s\n", tx_name, rx_name);
if(tx_netid == rx_netid) {
printf("TX and RX networks are the same. This example is intended for a physical loopback between two ports.\n");
goto cleanup;
}
// Use the same expected frame bytes for transmit and for receive-side matching.
build_loopback_frame(expected_frame, sizeof(expected_frame), tx_name, rx_name);
res = icsneoc2_settings_refresh(device);
if(res != icsneoc2_error_success) {
print_error_code("Failed to refresh device settings", res);
goto cleanup;
}
if(configure_t1s_port(device, tx_netid, TX_LOCAL_ID) != 0) {
goto cleanup;
}
if(configure_t1s_port(device, rx_netid, RX_LOCAL_ID) != 0) {
goto cleanup;
}
printf("Applying T1S settings to the device.\n");
printf("Note: icsneoc2_settings_apply() persists these settings on the device.\n");
res = icsneoc2_settings_apply(device);
if(res != icsneoc2_error_success) {
print_error_code("Failed to apply T1S settings", res);
goto cleanup;
}
sleep_ms(500);
if(transmit_loopback_frame(device, tx_netid, tx_name, rx_name) != 0) {
goto cleanup;
}
if(poll_for_loopback_messages(device, tx_netid, rx_netid, tx_name, rx_name, expected_frame, sizeof(expected_frame)) != 0) {
print_events();
goto cleanup;
}
status = 0;
cleanup:
if(device != NULL) {
res = icsneoc2_device_close(device);
if(res != icsneoc2_error_success) {
(void)print_error_code("Failed to close device", res);
}
res = icsneoc2_device_free(device);
if(res != icsneoc2_error_success) {
(void)print_error_code("Failed to free device", res);
}
}
return status;
}
static void sleep_ms(uint32_t ms) {
#ifdef _WIN32
Sleep(ms);
#else
usleep(ms * 1000);
#endif
}
static int print_error_code(const char* message, icsneoc2_error_t error) {
char error_str[64] = {0};
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 %u with error code %u\n", message, error, res);
return (int)res;
}
printf("%s: \"%s\" (%u)\n", message, error_str, error);
return (int)error;
}
static void print_events(void) {
icsneoc2_event_t* events[64] = {0};
size_t count = sizeof(events) / sizeof(events[0]);
for(size_t i = 0; i < count; ++i) {
icsneoc2_error_t res = icsneoc2_event_get(&events[i], NULL);
if(res != icsneoc2_error_success) {
(void)print_error_code("Failed to get events", res);
return;
}
if(events[i] == NULL) {
count = i;
break;
}
}
for(size_t i = 0; i < count; ++i) {
char description[255] = {0};
size_t description_length = sizeof(description);
icsneoc2_error_t res = icsneoc2_event_description_get(events[i], description, &description_length);
if(res == icsneoc2_error_success) {
printf("Event %zu: %s\n", i, description);
}
icsneoc2_event_free(events[i]);
}
}
static int get_netid_name(icsneoc2_netid_t netid, char* buffer, size_t buffer_size) {
size_t length = buffer_size;
icsneoc2_error_t res = icsneoc2_netid_name_get(netid, buffer, &length);
if(res != icsneoc2_error_success) {
return print_error_code("Failed to get netid name", res);
}
return 0;
}
static int get_available_networks(const icsneoc2_device_t* device,
selectable_network_t* tx_networks,
size_t* tx_count,
selectable_network_t* rx_networks,
size_t* rx_count) {
icsneoc2_netid_t supported_tx_networks[128] = {0};
icsneoc2_netid_t supported_rx_networks[128] = {0};
size_t tx_supported_count = sizeof(supported_tx_networks) / sizeof(supported_tx_networks[0]);
size_t rx_supported_count = sizeof(supported_rx_networks) / sizeof(supported_rx_networks[0]);
icsneoc2_message_t* probe = NULL;
icsneoc2_network_type_t network_type = 0;
icsneoc2_error_t res = icsneoc2_device_supported_tx_networks_get(device, supported_tx_networks, &tx_supported_count);
if(res != icsneoc2_error_success) {
return print_error_code("Failed to get supported TX networks", res);
}
res = icsneoc2_device_supported_rx_networks_get(device, supported_rx_networks, &rx_supported_count);
if(res != icsneoc2_error_success) {
return print_error_code("Failed to get supported RX networks", res);
}
*tx_count = 0;
*rx_count = 0;
// Reuse one temporary Ethernet message to classify each netid by network type.
res = icsneoc2_message_eth_create(&probe);
if(res != icsneoc2_error_success) {
return print_error_code("Failed to create temporary Ethernet message", res);
}
for(size_t i = 0; i < tx_supported_count; ++i) {
res = icsneoc2_message_netid_set(probe, supported_tx_networks[i]);
if(res != icsneoc2_error_success) {
continue;
}
res = icsneoc2_message_network_type_get(probe, &network_type);
if(res != icsneoc2_error_success || network_type != icsneoc2_network_type_automotive_ethernet) {
continue;
}
tx_networks[*tx_count].netid = supported_tx_networks[i];
if(get_netid_name(supported_tx_networks[i], tx_networks[*tx_count].name, sizeof(tx_networks[*tx_count].name)) != 0) {
icsneoc2_message_free(probe);
return 1;
}
(*tx_count)++;
}
for(size_t i = 0; i < rx_supported_count; ++i) {
res = icsneoc2_message_netid_set(probe, supported_rx_networks[i]);
if(res != icsneoc2_error_success) {
continue;
}
res = icsneoc2_message_network_type_get(probe, &network_type);
if(res != icsneoc2_error_success || network_type != icsneoc2_network_type_automotive_ethernet) {
continue;
}
rx_networks[*rx_count].netid = supported_rx_networks[i];
if(get_netid_name(supported_rx_networks[i], rx_networks[*rx_count].name, sizeof(rx_networks[*rx_count].name)) != 0) {
icsneoc2_message_free(probe);
return 1;
}
(*rx_count)++;
}
icsneoc2_message_free(probe);
if(*tx_count == 0) {
printf("No automotive Ethernet TX networks are available on this device.\n");
return 1;
}
if(*rx_count == 0) {
printf("No automotive Ethernet RX networks are available on this device.\n");
return 1;
}
return 0;
}
static int prompt_for_network_selection(const char* label, const selectable_network_t* networks, size_t count, icsneoc2_netid_t* selected_netid, char* selected_name, size_t selected_name_size) {
char input[32] = {0};
char* end_ptr = NULL;
long selected_index = 0;
if(!label || !networks || count == 0 || !selected_netid || !selected_name || selected_name_size == 0) {
return print_error_code("Invalid network selection parameters", icsneoc2_error_invalid_parameters);
}
printf("Available automotive Ethernet %s networks:\n", label);
for(size_t i = 0; i < count; ++i) {
printf(" %zu) %s\n", i + 1, networks[i].name);
}
printf("Select %s network [1-%zu, default 1]: ", label, count);
if(fgets(input, sizeof(input), stdin) == NULL || input[0] == '\n') {
selected_index = 1;
} else {
selected_index = strtol(input, &end_ptr, 10);
if(end_ptr == input || selected_index < 1 || (size_t)selected_index > count) {
printf("Invalid selection, using %s.\n", networks[0].name);
selected_index = 1;
}
}
*selected_netid = networks[selected_index - 1].netid;
strncpy(selected_name, networks[selected_index - 1].name, selected_name_size - 1);
selected_name[selected_name_size - 1] = '\0';
return 0;
}
static int configure_t1s_port(icsneoc2_device_t* device, icsneoc2_netid_t netid, uint8_t local_id) {
char netid_name[64] = {0};
icsneoc2_error_t res;
bool termination = false;
if(get_netid_name(netid, netid_name, sizeof(netid_name)) != 0) {
return 1;
}
printf("Configuring %s: PLCA on, LocalID=%u, MaxNodes=%u, TxOpp=%u, BurstTimer=%u, MaxBurst=%u\n",
netid_name,
(unsigned)local_id,
(unsigned)T1S_MAX_NODES,
(unsigned)T1S_TX_OPP_TIMER,
(unsigned)T1S_BURST_TIMER,
(unsigned)T1S_MAX_BURST);
// Keep the example explicit about the small set of T1S settings needed for loopback.
res = icsneoc2_settings_t1s_plca_enabled_for_set(device, netid, true);
if(res != icsneoc2_error_success) return print_error_code("Failed to enable T1S PLCA", res);
res = icsneoc2_settings_t1s_local_id_set(device, netid, local_id);
if(res != icsneoc2_error_success) return print_error_code("Failed to set T1S local ID", res);
res = icsneoc2_settings_t1s_max_nodes_set(device, netid, T1S_MAX_NODES);
if(res != icsneoc2_error_success) return print_error_code("Failed to set T1S max nodes", res);
res = icsneoc2_settings_t1s_tx_opp_timer_set(device, netid, T1S_TX_OPP_TIMER);
if(res != icsneoc2_error_success) return print_error_code("Failed to set T1S TX opportunity timer", res);
res = icsneoc2_settings_t1s_burst_timer_set(device, netid, T1S_BURST_TIMER);
if(res != icsneoc2_error_success) return print_error_code("Failed to set T1S burst timer", res);
res = icsneoc2_settings_t1s_max_burst_timer_for_set(device, netid, T1S_MAX_BURST);
if(res != icsneoc2_error_success) return print_error_code("Failed to set T1S max burst", res);
res = icsneoc2_settings_t1s_is_termination_enabled_for(device, netid, &termination);
if(res == icsneoc2_error_success) {
res = icsneoc2_settings_t1s_termination_for_set(device, netid, true);
if(res != icsneoc2_error_success) return print_error_code("Failed to enable T1S termination", res);
} else if(res != icsneoc2_error_get_settings_failure) {
return print_error_code("Failed to query T1S termination support", res);
}
return 0;
}
static 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]);
}
static void print_payload_hex(const uint8_t* data, size_t length) {
for(size_t i = 0; i < length; ++i) {
printf("%02x", data[i]);
if(i + 1 < length) {
printf(" ");
}
}
printf("\n");
}
static void build_loopback_frame(uint8_t* frame_data, size_t frame_size, const char* tx_name, const char* rx_name) {
const char* tx_label = tx_name ? tx_name : "TX";
const char* rx_label = rx_name ? rx_name : "RX";
// Build one recognizable Ethernet frame so the receive side can match exactly what we sent.
memset(frame_data, 0, frame_size);
frame_data[0] = 0x00;
frame_data[1] = 0xFC;
frame_data[2] = 0x70;
frame_data[3] = 0x00;
frame_data[4] = 0x00;
frame_data[5] = 0x02;
frame_data[6] = 0x00;
frame_data[7] = 0xFC;
frame_data[8] = 0x70;
frame_data[9] = 0x00;
frame_data[10] = 0x00;
frame_data[11] = 0x01;
frame_data[12] = (uint8_t)((LOOPBACK_ETHER_TYPE >> 8) & 0xFF);
frame_data[13] = (uint8_t)(LOOPBACK_ETHER_TYPE & 0xFF);
snprintf((char*)&frame_data[14], frame_size - 14, "C2 T1S loopback %s->%s", tx_label, rx_label);
}
static int message_matches_loopback_frame(icsneoc2_message_t* message, const uint8_t* expected, size_t expected_length, bool* matches) {
uint8_t data[1600] = {0};
size_t data_length = sizeof(data);
uint16_t ether_type = 0;
icsneoc2_error_t res;
if(!expected || !matches || expected_length < 14) {
return print_error_code("Invalid loopback match output", icsneoc2_error_invalid_parameters);
}
*matches = false;
res = icsneoc2_message_eth_ether_type_get(message, &ether_type);
if(res != icsneoc2_error_success) {
return print_error_code("Failed to read loopback EtherType", res);
}
if(ether_type != LOOPBACK_ETHER_TYPE) {
return 0;
}
res = icsneoc2_message_data_get(message, data, &data_length);
if(res != icsneoc2_error_success) {
return print_error_code("Failed to read loopback frame data", res);
}
if(data_length < 14) {
return 0;
}
if(data_length >= expected_length) {
*matches = memcmp(data, expected, expected_length) == 0;
} else {
*matches = memcmp(data, expected, data_length) == 0;
}
return 0;
}
static int print_ethernet_message(icsneoc2_message_t* message, const char* direction_label) {
icsneoc2_netid_t netid = 0;
char netid_name[64] = {0};
uint8_t dst_mac[6] = {0};
uint8_t src_mac[6] = {0};
uint16_t ether_type = 0;
icsneoc2_message_eth_t1s_flags_t t1s_flags = 0;
uint8_t node_id = 0;
uint8_t burst_count = 0;
uint8_t symbol_type = 0;
uint8_t data[1600] = {0};
size_t data_length = sizeof(data);
icsneoc2_error_t res;
res = icsneoc2_message_netid_get(message, &netid);
if(res != icsneoc2_error_success) return print_error_code("Failed to get message netid", res);
if(get_netid_name(netid, netid_name, sizeof(netid_name)) != 0) return 1;
res = icsneoc2_message_data_get(message, data, &data_length);
if(res != icsneoc2_error_success) return print_error_code("Failed to get Ethernet data", res);
printf("%s on %s: %zu bytes\n", direction_label, netid_name, data_length);
res = icsneoc2_message_eth_mac_get(message, dst_mac, src_mac);
if(res == icsneoc2_error_success) {
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(" EtherType: 0x%04x\n", ether_type);
}
res = icsneoc2_message_eth_t1s_props_get(message, &t1s_flags, &node_id, &burst_count, &symbol_type);
if(res == icsneoc2_error_success && (t1s_flags != 0 || node_id != 0 || burst_count != 0 || symbol_type != 0)) {
printf(" T1S: node=%u burst=%u symbol=%u", (unsigned)node_id, (unsigned)burst_count, (unsigned)symbol_type);
if(t1s_flags & ICSNEOC2_MESSAGE_ETH_T1S_FLAGS_IS_T1S_SYMBOL) printf(" [SYMBOL]");
if(t1s_flags & ICSNEOC2_MESSAGE_ETH_T1S_FLAGS_IS_T1S_BURST) printf(" [BURST]");
if(t1s_flags & ICSNEOC2_MESSAGE_ETH_T1S_FLAGS_TX_COLLISION) printf(" [TX_COLLISION]");
if(t1s_flags & ICSNEOC2_MESSAGE_ETH_T1S_FLAGS_IS_T1S_WAKE) printf(" [WAKE]");
printf("\n");
}
printf(" Payload bytes: ");
if(data_length > 14) {
print_payload_hex(&data[14], data_length - 14);
} else {
printf("<none>\n");
}
return 0;
}
static int transmit_loopback_frame(icsneoc2_device_t* device, icsneoc2_netid_t tx_netid, const char* tx_name, const char* rx_name) {
icsneoc2_message_t* message = NULL;
icsneoc2_error_t res;
uint8_t frame_data[LOOPBACK_FRAME_SIZE] = {0};
build_loopback_frame(frame_data, sizeof(frame_data), tx_name, rx_name);
res = icsneoc2_message_eth_create(&message);
if(res != icsneoc2_error_success) return print_error_code("Failed to create Ethernet message", res);
res = icsneoc2_message_netid_set(message, tx_netid);
if(res != icsneoc2_error_success) {
icsneoc2_message_free(message);
return print_error_code("Failed to set Ethernet netid", res);
}
res = icsneoc2_message_data_set(message, frame_data, sizeof(frame_data));
if(res != icsneoc2_error_success) {
icsneoc2_message_free(message);
return print_error_code("Failed to set Ethernet payload", res);
}
printf("Transmitting one T1S loopback frame on %s...\n", tx_name ? tx_name : "selected TX network");
res = icsneoc2_device_message_transmit(device, message);
icsneoc2_message_free(message);
if(res != icsneoc2_error_success) return print_error_code("Failed to transmit loopback frame", res);
return 0;
}
static int poll_for_loopback_messages(icsneoc2_device_t* device,
icsneoc2_netid_t tx_netid,
icsneoc2_netid_t rx_netid,
const char* tx_name,
const char* rx_name,
const uint8_t* expected_frame,
size_t expected_frame_length) {
bool saw_tx_echo = false;
bool saw_rx_frame = false;
printf("Polling for TX echo on %s and RX frame on %s...\n", tx_name, rx_name);
for(size_t attempt = 0; attempt < 60 && !(saw_tx_echo && saw_rx_frame); ++attempt) {
icsneoc2_message_t* message = NULL;
icsneoc2_error_t res = icsneoc2_device_message_get(device, &message, 100);
if(res != icsneoc2_error_success) {
return print_error_code("Failed while polling for loopback messages", res);
}
if(message == NULL) {
continue;
}
bool is_ethernet = false;
bool matches_loopback = false;
res = icsneoc2_message_is_ethernet(message, &is_ethernet);
if(res != icsneoc2_error_success || !is_ethernet) {
icsneoc2_message_free(message);
continue;
}
icsneoc2_netid_t netid = 0;
res = icsneoc2_message_netid_get(message, &netid);
if(res != icsneoc2_error_success) {
icsneoc2_message_free(message);
return print_error_code("Failed to get polled netid", res);
}
if(netid != tx_netid && netid != rx_netid) {
icsneoc2_message_free(message);
continue;
}
// Ignore unrelated traffic on the selected ports and only count the frame this example transmitted.
if(message_matches_loopback_frame(message, expected_frame, expected_frame_length, &matches_loopback) != 0) {
icsneoc2_message_free(message);
return 1;
}
if(!matches_loopback) {
icsneoc2_message_free(message);
continue;
}
bool is_tx = false;
res = icsneoc2_message_is_transmit(message, &is_tx);
if(res != icsneoc2_error_success) {
icsneoc2_message_free(message);
return print_error_code("Failed to determine TX status", res);
}
if(netid == tx_netid && is_tx && !saw_tx_echo) {
if(print_ethernet_message(message, "TX echo") != 0) {
icsneoc2_message_free(message);
return 1;
}
saw_tx_echo = true;
} else if(netid == rx_netid && !saw_rx_frame) {
if(print_ethernet_message(message, "RX frame") != 0) {
icsneoc2_message_free(message);
return 1;
}
if(is_tx) {
printf(" Note: RX port message was also marked as transmit.\n");
}
saw_rx_frame = true;
}
icsneoc2_message_free(message);
}
if(!saw_tx_echo || !saw_rx_frame) {
printf("Loopback incomplete: saw_tx_echo=%s, saw_rx_frame=%s\n",
saw_tx_echo ? "true" : "false",
saw_rx_frame ? "true" : "false");
printf("Confirm %s is physically connected to %s and both ports are configured for 10BASE-T1S.\n", tx_name, rx_name);
return 1;
}
printf("Loopback complete: TX echo on %s and RX frame on %s were both observed.\n", tx_name, rx_name);
return 0;
}
+6
View File
@@ -0,0 +1,6 @@
add_executable(libicsneoc2-tc10-example src/main.c)
target_link_libraries(libicsneoc2-tc10-example icsneoc2-static)
if(WIN32)
target_compile_definitions(libicsneoc2-tc10-example PRIVATE _CRT_SECURE_NO_WARNINGS)
endif()
+393
View File
@@ -0,0 +1,393 @@
/*
* TC10 example.
*
* Sends TC10 wake/sleep requests, queries TC10 status, or lists connected
* devices and the Automotive Ethernet networks they support. Loosely based
* on examples/python/tc10/tc10.py. If --serial is omitted, the first
* available device is used.
*/
#include <icsneo/icsneoc2.h>
#include <icsneo/icsneoc2messages.h>
#include <ctype.h>
#include <stdbool.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
typedef struct {
const char* serial; /* may be NULL */
const char** networks; /* points into argv */
size_t networks_count;
bool send_wake;
bool send_sleep;
bool status;
bool list;
} args_t;
static int print_error_code(const char* message, icsneoc2_error_t error);
static void str_tolower(char* s);
static bool resolve_netid(const char* name, icsneoc2_netid_t* out);
static void print_usage(const char* prog);
static int parse_args(int argc, char** argv, args_t* out);
static icsneoc2_device_info_t* find_device(icsneoc2_device_info_t* list, const char* serial);
static int list_devices(icsneoc2_device_info_t* list);
static const char* tc10_wake_status_str(icsneoc2_tc10_wake_status_t s);
static const char* tc10_sleep_status_str(icsneoc2_tc10_sleep_status_t s);
int main(int argc, char** argv) {
args_t args;
if(parse_args(argc, argv, &args) != 0) {
return 1;
}
icsneoc2_device_info_t* found_devices = NULL;
icsneoc2_error_t res = icsneoc2_device_enumerate(0, &found_devices);
if(res != icsneoc2_error_success) {
return print_error_code("Failed to enumerate devices", res);
}
if(found_devices == NULL) {
fprintf(stderr, "error: no devices found\n");
return 1;
}
if(args.list) {
int rc = list_devices(found_devices);
icsneoc2_enumeration_free(found_devices);
return rc;
}
icsneoc2_device_info_t* info = find_device(found_devices, args.serial);
if(info == NULL) {
fprintf(stderr, "error: unable to find device %s\n", args.serial ? args.serial : "(any)");
icsneoc2_enumeration_free(found_devices);
return 1;
}
char description[256] = {0};
size_t description_len = sizeof(description);
res = icsneoc2_device_info_description_get(info, description, &description_len);
if(res != icsneoc2_error_success) {
icsneoc2_enumeration_free(found_devices);
return print_error_code("Failed to get device description", res);
}
icsneoc2_device_t* device = NULL;
res = icsneoc2_device_create(info, &device);
if(res != icsneoc2_error_success) {
icsneoc2_enumeration_free(found_devices);
return print_error_code("Failed to create device", res);
}
printf("Opening device %s\n", description);
res = icsneoc2_device_open(device, icsneoc2_open_options_default);
if(res != icsneoc2_error_success) {
icsneoc2_device_free(device);
icsneoc2_enumeration_free(found_devices);
return print_error_code("Failed to open device", res);
}
bool supports_tc10 = false;
res = icsneoc2_device_supports_tc10(device, &supports_tc10);
if(res != icsneoc2_error_success || !supports_tc10) {
fprintf(stderr, "error: device does not support TC10 (%s)\n", description);
icsneoc2_device_close(device);
icsneoc2_device_free(device);
icsneoc2_enumeration_free(found_devices);
return 1;
}
int rc = 0;
for(size_t i = 0; i < args.networks_count; ++i) {
const char* name = args.networks[i];
icsneoc2_netid_t netid = icsneoc2_netid_invalid;
if(!resolve_netid(name, &netid)) {
fprintf(stderr, "error: unknown network '%s'\n", name);
rc = 1;
break;
}
if(args.send_wake) {
printf("requesting TC10 wake on network %s\n", name);
res = icsneoc2_device_tc10_wake_request(device, netid);
if(res != icsneoc2_error_success) {
rc = print_error_code("Failed to send TC10 wake", res);
break;
}
} else if(args.send_sleep) {
printf("requesting TC10 sleep on network %s\n", name);
res = icsneoc2_device_tc10_sleep_request(device, netid);
if(res != icsneoc2_error_success) {
rc = print_error_code("Failed to send TC10 sleep", res);
break;
}
} else { /* args.status */
icsneoc2_tc10_sleep_status_t sleep_s = icsneoc2_tc10_sleep_status_no_sleep_received;
icsneoc2_tc10_wake_status_t wake_s = icsneoc2_tc10_wake_status_no_wake_received;
res = icsneoc2_device_tc10_status_get(device, netid, &sleep_s, &wake_s);
if(res != icsneoc2_error_success) {
rc = print_error_code("Failed to get TC10 status", res);
break;
}
printf("TC10 status on network %s: wake=%s sleep=%s\n", name,
tc10_wake_status_str(wake_s), tc10_sleep_status_str(sleep_s));
}
}
printf("Closing device %s\n", description);
icsneoc2_device_close(device);
icsneoc2_device_free(device);
icsneoc2_enumeration_free(found_devices);
return rc;
}
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_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;
}
static void str_tolower(char* s) {
for(; *s; ++s) {
*s = (char)tolower((unsigned char)*s);
}
}
/*
* Resolve a network name (e.g. "ETHERNET_01", "ae_01") to its icsneoc2_netid_t
* by iterating over all known netids and comparing names case-insensitively.
*/
static bool resolve_netid(const char* name, icsneoc2_netid_t* out) {
char want[64];
strncpy(want, name, sizeof(want) - 1);
want[sizeof(want) - 1] = '\0';
str_tolower(want);
for(uint16_t i = 0; i < icsneoc2_netid_maxsize; ++i) {
char buf[64];
size_t buf_len = sizeof(buf);
if(icsneoc2_netid_name_get((icsneoc2_netid_t)i, buf, &buf_len) != icsneoc2_error_success) {
continue;
}
str_tolower(buf);
if(strcmp(buf, want) == 0) {
*out = (icsneoc2_netid_t)i;
return true;
}
}
return false;
}
static void print_usage(const char* prog) {
printf("Usage:\n");
printf(" %s --list\n", prog);
printf(" %s [--serial SERIAL] --networks NET1 [NET2 ...] (--send-wake | --send-sleep | --status)\n", prog);
printf("\n");
printf(" --list List connected devices and the Automotive Ethernet networks they support.\n");
printf(" --serial SERIAL Serial number of the device. If omitted, the first available device is used.\n");
printf(" --networks NET ... One or more network names (e.g. ETHERNET_01 AE_01). Consumes args until the next flag.\n");
printf(" --send-wake Trigger TC10 wake on the selected networks.\n");
printf(" --send-sleep Trigger TC10 sleep on the selected networks.\n");
printf(" --status Query TC10 wake/sleep status on the selected networks.\n");
printf(" -h, --help Show this message.\n");
}
static int parse_args(int argc, char** argv, args_t* out) {
memset(out, 0, sizeof(*out));
for(int i = 1; i < argc; ++i) {
const char* a = argv[i];
if(strcmp(a, "-h") == 0 || strcmp(a, "--help") == 0) {
print_usage(argv[0]);
exit(0);
} else if(strcmp(a, "--serial") == 0) {
if(i + 1 >= argc) {
fprintf(stderr, "error: --serial requires a value\n");
return 1;
}
out->serial = argv[++i];
} else if(strcmp(a, "--send-wake") == 0) {
out->send_wake = true;
} else if(strcmp(a, "--send-sleep") == 0) {
out->send_sleep = true;
} else if(strcmp(a, "--status") == 0) {
out->status = true;
} else if(strcmp(a, "--list") == 0) {
out->list = true;
} else if(strcmp(a, "--networks") == 0) {
if(i + 1 >= argc || argv[i + 1][0] == '-') {
fprintf(stderr, "error: --networks requires at least one network name\n");
return 1;
}
out->networks = (const char**)&argv[i + 1];
size_t count = 0;
while(i + 1 < argc && argv[i + 1][0] != '-') {
++count;
++i;
}
out->networks_count = count;
} else {
fprintf(stderr, "error: unknown argument '%s'\n", a);
print_usage(argv[0]);
return 1;
}
}
if(out->list) {
if(out->send_wake || out->send_sleep || out->status || out->networks_count > 0 || out->serial) {
fprintf(stderr, "error: --list cannot be combined with other options\n");
print_usage(argv[0]);
return 1;
}
return 0;
}
if(out->networks_count == 0) {
fprintf(stderr, "error: --networks is required\n");
print_usage(argv[0]);
return 1;
}
int action_count = (out->send_wake ? 1 : 0) + (out->send_sleep ? 1 : 0) + (out->status ? 1 : 0);
if(action_count != 1) {
fprintf(stderr, "error: exactly one of --send-wake, --send-sleep, or --status is required\n");
print_usage(argv[0]);
return 1;
}
return 0;
}
static const char* tc10_wake_status_str(icsneoc2_tc10_wake_status_t s) {
switch(s) {
case icsneoc2_tc10_wake_status_no_wake_received: return "no_wake_received";
case icsneoc2_tc10_wake_status_wake_received: return "wake_received";
default: return "unknown";
}
}
static const char* tc10_sleep_status_str(icsneoc2_tc10_sleep_status_t s) {
switch(s) {
case icsneoc2_tc10_sleep_status_no_sleep_received: return "no_sleep_received";
case icsneoc2_tc10_sleep_status_sleep_received: return "sleep_received";
case icsneoc2_tc10_sleep_status_sleep_failed: return "sleep_failed";
case icsneoc2_tc10_sleep_status_sleep_aborted: return "sleep_aborted";
default: return "unknown";
}
}
/*
* Find a device matching the provided serial, or the first available device if serial is NULL.
* Returns NULL on failure (caller is responsible for the enumeration list).
*/
static icsneoc2_device_info_t* find_device(icsneoc2_device_info_t* list, const char* serial) {
if(serial == NULL) {
return list;
}
for(icsneoc2_device_info_t* cur = list; cur != NULL; cur = icsneoc2_device_info_next(cur)) {
char dev_serial[64] = {0};
size_t dev_serial_len = sizeof(dev_serial);
if(icsneoc2_device_info_serial_get(cur, dev_serial, &dev_serial_len) != icsneoc2_error_success) {
continue;
}
if(strcmp(dev_serial, serial) == 0) {
return cur;
}
}
return NULL;
}
/*
* List connected devices and the Automotive Ethernet networks each one supports.
*/
static int list_devices(icsneoc2_device_info_t* list) {
size_t index = 0;
for(icsneoc2_device_info_t* cur = list; cur != NULL; cur = icsneoc2_device_info_next(cur)) {
char serial[64] = {0};
size_t serial_len = sizeof(serial);
(void)icsneoc2_device_info_serial_get(cur, serial, &serial_len);
char description[256] = {0};
size_t description_len = sizeof(description);
(void)icsneoc2_device_info_description_get(cur, description, &description_len);
printf("[%zu] %s (%s)\n", index++, description, serial);
icsneoc2_device_t* device = NULL;
icsneoc2_error_t res = icsneoc2_device_create(cur, &device);
if(res != icsneoc2_error_success) {
print_error_code(" Failed to create device", res);
continue;
}
icsneoc2_open_options_t options = icsneoc2_open_options_default;
options &= ~ICSNEOC2_OPEN_OPTIONS_SYNC_RTC;
options &= ~ICSNEOC2_OPEN_OPTIONS_GO_ONLINE;
res = icsneoc2_device_open(device, options);
if(res != icsneoc2_error_success) {
print_error_code(" Failed to open device", res);
icsneoc2_device_free(device);
continue;
}
bool supports_tc10 = false;
(void)icsneoc2_device_supports_tc10(device, &supports_tc10);
printf(" TC10 supported: %s\n", supports_tc10 ? "yes" : "no");
size_t count = 0;
res = icsneoc2_device_supported_tx_networks_get(device, NULL, &count);
if(res != icsneoc2_error_success || count == 0) {
icsneoc2_device_close(device);
icsneoc2_device_free(device);
continue;
}
icsneoc2_netid_t* nets = (icsneoc2_netid_t*)calloc(count, sizeof(icsneoc2_netid_t));
if(nets == NULL) {
fprintf(stderr, " error: out of memory\n");
icsneoc2_device_close(device);
icsneoc2_device_free(device);
continue;
}
res = icsneoc2_device_supported_tx_networks_get(device, nets, &count);
if(res != icsneoc2_error_success) {
print_error_code(" Failed to get supported networks", res);
free(nets);
icsneoc2_device_close(device);
icsneoc2_device_free(device);
continue;
}
printf(" Automotive Ethernet networks:\n");
bool any = false;
for(size_t i = 0; i < count; ++i) {
icsneoc2_network_type_t type = icsneoc2_network_type_invalid;
if(icsneoc2_netid_network_type_get(nets[i], &type) != icsneoc2_error_success) {
continue;
}
if(type != icsneoc2_network_type_automotive_ethernet) {
continue;
}
char name[64] = {0};
size_t name_len = sizeof(name);
if(icsneoc2_netid_name_get(nets[i], name, &name_len) != icsneoc2_error_success) {
continue;
}
printf(" %s\n", name);
any = true;
}
if(!any) {
printf(" (none)\n");
}
free(nets);
icsneoc2_device_close(device);
icsneoc2_device_free(device);
}
return 0;
}
+3
View File
@@ -406,6 +406,9 @@ int main(int argc, char** argv) {
if(it == devices.end()) {
std::cerr << "Could not find RAD-A2B." << std::endl;
auto lastError = icsneo::GetLastError();
if(lastError.getType() != icsneo::APIEvent::Type::NoErrorFound)
std::cerr << lastError << std::endl;
return EXIT_FAILURE;
}
+2
View File
@@ -0,0 +1,2 @@
add_executable(libicsneocpp-analog-out src/analog_out.cpp)
target_link_libraries(libicsneocpp-analog-out icsneocpp)
+163
View File
@@ -0,0 +1,163 @@
/**
* libicsneo Analog Output example
*
* Demonstrates how to configure and control analog outputs on supported devices
*
* Usage: libicsneo-analog-out <pin> <voltage> [deviceSerial] [--yes]
*
* Arguments:
* pin: Pin number (1-3 for RAD Galaxy)
* voltage: Voltage level (0-5)
* deviceSerial: 6 character string for device serial (optional)
* --yes: Skip confirmation prompt
*/
#include <iostream>
#include <thread>
#include <chrono>
#include <string_view>
#include <cstdlib>
#include "icsneo/icsneocpp.h"
static const std::string usage = "Usage: libicsneo-analog-out <pin> <voltage> [deviceSerial] [--yes]\n\n"
"Arguments:\n"
"pin: Pin number (1-3 for RAD Galaxy)\n"
"voltage: Voltage level (0-5)\n"
"deviceSerial: 6 character string for device serial (optional)\n"
"--yes: Skip confirmation prompt\n";
int main(int argc, const char** argv) {
std::vector<std::string_view> args(argv, argv + argc);
// Parse arguments
if(args.size() < 3) {
std::cerr << "Error: Missing required arguments\n" << std::endl;
std::cerr << usage;
return -1;
}
char* endPtr;
long pinNum = std::strtol(args[1].data(), &endPtr, 10);
if(endPtr != args[1].data() + args[1].size() || pinNum < 1 || pinNum > 3) {
std::cerr << "Error: Invalid pin number (must be 1-3)" << std::endl;
return -1;
}
long voltageLevel = std::strtol(args[2].data(), &endPtr, 10);
if(endPtr != args[2].data() + args[2].size() || voltageLevel < 0 || voltageLevel > 5) {
std::cerr << "Error: Invalid voltage level (must be 0-5)" << std::endl;
return -1;
}
icsneo::MiscIOAnalogVoltage voltage = static_cast<icsneo::MiscIOAnalogVoltage>(voltageLevel);
uint8_t pin = static_cast<uint8_t>(pinNum);
// Check for optional arguments
bool skipConfirm = false;
std::string_view serial;
for(size_t i = 3; i < args.size(); i++) {
if(args[i] == "--yes") {
skipConfirm = true;
} else if(serial.empty() && args[i].size() == 6) {
serial = args[i];
}
}
// Confirmation prompt
if(!skipConfirm) {
std::cout << "WARNING: This will set analog output pin " << static_cast<int>(pin)
<< " to " << voltageLevel << "V" << std::endl;
std::cout << "Make sure nothing sensitive is connected to this pin." << std::endl;
std::cout << "Continue? (yes/no): ";
std::string response;
std::getline(std::cin, response);
if(response != "yes") {
std::cout << "Aborted." << std::endl;
return 0;
}
}
std::shared_ptr<icsneo::Device> device = nullptr;
if(!serial.empty()) {
// Find device by serial
auto devices = icsneo::FindAllDevices();
for(auto& dev : devices) {
if(dev->getSerial() == serial) {
device = dev;
break;
}
}
if(!device) {
std::cerr << "Device with serial " << serial << " not found" << std::endl;
auto lastError = icsneo::GetLastError();
if(lastError.getType() != icsneo::APIEvent::Type::NoErrorFound)
std::cerr << lastError << std::endl;
return -1;
}
} else {
// Use first available device
auto devices = icsneo::FindAllDevices();
if(devices.empty()) {
std::cerr << "No devices found" << std::endl;
auto lastError = icsneo::GetLastError();
if(lastError.getType() != icsneo::APIEvent::Type::NoErrorFound)
std::cerr << lastError << std::endl;
return -1;
}
device = devices[0];
}
std::cout << "Using device: " << device->describe() << std::endl;
if(!device->open()) {
std::cerr << "Failed to open device" << std::endl;
return -1;
}
auto settings = device->settings;
if(!settings) {
std::cerr << "Device settings not available" << std::endl;
device->close();
return -1;
}
std::cout << "Refreshing device settings..." << std::endl;
if(!settings->refresh()) {
std::cerr << "Failed to refresh settings" << std::endl;
device->close();
return -1;
}
// Enable analog output on specified pin
std::cout << "Enabling analog output on pin " << static_cast<int>(pin) << "..." << std::endl;
if(!settings->setMiscIOAnalogOutputEnabled(pin, true)) {
std::cerr << "Failed to enable analog output on pin " << static_cast<int>(pin) << std::endl;
device->close();
return -1;
}
// Set pin to specified voltage
std::cout << "Setting pin " << static_cast<int>(pin) << " to " << voltageLevel << "V..." << std::endl;
if(!settings->setMiscIOAnalogOutput(pin, voltage)) {
std::cerr << "Failed to set voltage on pin " << static_cast<int>(pin) << std::endl;
device->close();
return -1;
}
// Apply settings
std::cout << "Applying settings..." << std::endl;
if(!settings->apply()) {
std::cerr << "Failed to apply settings" << std::endl;
device->close();
return -1;
}
std::cout << "Analog output configured successfully!" << std::endl;
std::cout << "Pin " << static_cast<int>(pin) << ": Enabled at " << voltageLevel << "V" << std::endl;
device->close();
return 0;
}
@@ -9,7 +9,7 @@
/*
* App errors are responses from the device indicating internal runtime errors
* NOTE: To trigger the app error in this example, disable the DW CAN 01 network on the device
* (e.g. with neoVI Explorer)
* (e.g. with ICS Device Manager)
*/
int main() {
std::cout << "Running libicsneo " << icsneo::GetVersion() << std::endl;
@@ -17,6 +17,13 @@ int main() {
auto devices = icsneo::FindAllDevices();
std::cout << "OK, " << devices.size() << " device" << (devices.size() == 1 ? "" : "s") << " found" << std::endl;
if(devices.empty()) {
auto lastError = icsneo::GetLastError();
if(lastError.getType() != icsneo::APIEvent::Type::NoErrorFound)
std::cout << lastError << std::endl;
return 0;
}
// List off the devices
for(auto& device : devices)
std::cout << '\t' << device->describe() << " @ Handle " << device->getNeoDevice().handle << std::endl;
+3
View File
@@ -33,6 +33,9 @@ int main(int argc, char** argv) {
if(it == devices.end()) {
std::cout << "Failed to find device." << std::endl;
auto lastError = icsneo::GetLastError();
if(lastError.getType() != icsneo::APIEvent::Type::NoErrorFound)
std::cout << lastError << std::endl;
return EXIT_FAILURE;
}
+2
View File
@@ -0,0 +1,2 @@
add_executable(libicsneocpp-diskformat-example src/DiskFormatExample.cpp)
target_link_libraries(libicsneocpp-diskformat-example icsneocpp)
@@ -0,0 +1,147 @@
#include <iostream>
#include <string>
#include "icsneo/icsneocpp.h"
#include "icsneo/disk/diskdetails.h"
int main() {
std::cout << "Running libicsneo " << icsneo::GetVersion() << std::endl;
std::cout << "\nFinding devices... " << std::flush;
auto devices = icsneo::FindAllDevices();
std::cout << "OK, " << devices.size() << " device" << (devices.size() == 1 ? "" : "s") << " found" << std::endl;
if(devices.empty()) {
auto lastError = icsneo::GetLastError();
if(lastError.getType() != icsneo::APIEvent::Type::NoErrorFound)
std::cout << lastError << std::endl;
return -1;
}
// List devices and let the user pick one
for(size_t i = 0; i < devices.size(); i++) {
std::cout << " [" << i << "] " << devices[i]->describe() << std::endl;
}
size_t choice = 0;
if(devices.size() > 1) {
std::cout << "Select a device [0-" << (devices.size() - 1) << "]: ";
std::cin >> choice;
if(choice >= devices.size()) {
std::cout << "error: invalid selection" << std::endl;
return -1;
}
}
auto& device = devices[choice];
std::cout << "\nOpening " << device->describe() << "... " << std::flush;
if(!device->open()) {
std::cout << "FAIL" << std::endl;
std::cout << "error: " << icsneo::GetLastError() << std::endl;
return -1;
}
std::cout << "OK" << std::endl;
// Check that this device supports disk formatting
if(!device->supportsDiskFormatting()) {
std::cout << "error: " << device->describe() << " does not support disk formatting" << std::endl;
device->close();
return -1;
}
std::cout << "Disk count: " << device->getDiskCount() << std::endl;
// Query the current disk state from the device
std::cout << "\nQuerying disk details... " << std::flush;
auto details = device->getDiskDetails();
if(!details) {
std::cout << "FAIL" << std::endl;
std::cout << "error: " << icsneo::GetLastError() << std::endl;
device->close();
return -1;
}
std::cout << "OK" << std::endl;
std::cout << " Layout : " << (details->layout == icsneo::DiskLayout::RAID0 ? "RAID0" : "Spanned") << std::endl;
for(size_t i = 0; i < details->disks.size(); i++) {
const auto& disk = details->disks[i];
std::cout << " Disk [" << i << "]:" << std::endl;
std::cout << " Present : " << (disk.present ? "yes" : "no") << std::endl;
std::cout << " Initialized : " << (disk.initialized ? "yes" : "no") << std::endl;
std::cout << " Formatted : " << (disk.formatted ? "yes" : "no") << std::endl;
if(disk.present) {
uint64_t bytes = disk.size();
std::cout << " Size : " << (bytes / (1024 * 1024)) << " MB"
<< " (" << disk.sectors << " sectors x " << disk.bytesPerSector << " bytes)" << std::endl;
}
}
// Build a format configuration.
// We keep the existing layout and re-use the disk geometry reported by the device.
// The 'formatted' flag must be true for each disk you want the device to format.
icsneo::DiskDetails formatConfig;
formatConfig.layout = details->layout;
formatConfig.fullFormat = false; // Quick format; set to true for a full (slow) format
formatConfig.disks = details->disks;
// Mark all present disks for formatting
bool anyPresent = false;
for(auto& disk : formatConfig.disks) {
if(disk.present) {
disk.formatted = true;
anyPresent = true;
}
}
if(!anyPresent) {
std::cout << "\nerror: no disks are present in the device" << std::endl;
device->close();
return -1;
}
std::cout << "\nThis will format the disk(s) in " << device->describe() << "." << std::endl;
std::cout << "All existing data will be lost. Continue? [y/N]: ";
std::string confirm;
std::cin >> confirm;
if(confirm != "y" && confirm != "Y") {
std::cout << "Aborted." << std::endl;
device->close();
return 0;
}
std::cout << "\nStarting format..." << std::endl;
// Progress callback — called every 500 ms while formatting
auto progressHandler = [](uint64_t sectorsFormatted, uint64_t sectorsTotal) -> icsneo::Device::DiskFormatDirective {
double pct = sectorsTotal > 0 ? (100.0 * sectorsFormatted / sectorsTotal) : 0.0;
std::cout << "\r Progress: " << sectorsFormatted << " / " << sectorsTotal
<< " sectors (" << static_cast<int>(pct) << "%)" << std::flush;
return icsneo::Device::DiskFormatDirective::Continue;
};
bool success = device->formatDisk(formatConfig, progressHandler);
std::cout << std::endl; // newline after progress line
if(!success) {
std::cout << "error: format failed: " << icsneo::GetLastError() << std::endl;
device->close();
return -1;
}
std::cout << "Format complete!" << std::endl;
// Verify by re-querying disk details
std::cout << "\nVerifying disk state after format... " << std::flush;
auto postDetails = device->getDiskDetails();
if(!postDetails) {
std::cout << "FAIL (could not re-query disk details)" << std::endl;
} else {
std::cout << "OK" << std::endl;
for(size_t i = 0; i < postDetails->disks.size(); i++) {
const auto& disk = postDetails->disks[i];
std::cout << " Disk [" << i << "] formatted: " << (disk.formatted ? "yes" : "no") << std::endl;
}
}
device->close();
return 0;
}
@@ -138,6 +138,12 @@ std::vector<std::shared_ptr<icsneo::FlexRayMessage>> makeDummyFlexRayMessages(si
int main() {
auto devices = icsneo::FindAllDevices();
if(devices.empty()) {
auto lastError = icsneo::GetLastError();
if(lastError.getType() != icsneo::APIEvent::Type::NoErrorFound)
std::cerr << lastError << std::endl;
return -1;
}
std::shared_ptr<icsneo::Device> flexrayDevice = nullptr;
for (auto&& device : devices) {
if (device->getExtension("FlexRay")) {
@@ -223,8 +223,30 @@ void printMessage(const std::shared_ptr<icsneo::Message>& message) {
std::cout << "\t\t Timestamped:\t"<< ethMessage->timestamp << " ns since 1/1/2007\n";
// The MACAddress may be printed directly or accessed with the `data` member
std::cout << "\t\t Source:\t" << ethMessage->getSourceMAC() << "\n";
std::cout << "\t\t Destination:\t" << ethMessage->getDestinationMAC();
auto printMAC = [](const icsneo::MACAddress& mac) {
std::ostringstream oss;
for(size_t i = 0; i < mac.size(); i++) {
oss << std::hex << std::setw(2) << std::setfill('0') << (uint32_t)mac[i];
if(i != mac.size() - 1)
oss << ':';
}
return oss.str();
};
if (auto destMAC = ethMessage->getDestinationMAC(); destMAC.has_value()) {
std::cout << "\t\t Destination:\t" << printMAC(*destMAC) << "\n";
} else {
std::cout << "\t\t Destination:\t N/A\n";
}
if (auto srcMAC = ethMessage->getSourceMAC(); srcMAC.has_value()) {
std::cout << "\t\t Source:\t" << printMAC(*srcMAC) << "\n";
} else {
std::cout << "\t\t Source:\t N/A\n";
}
if (auto etherType = ethMessage->getEtherType(); etherType.has_value()) {
std::cout << "\t\t EtherType:\t" << std::hex << std::setw(4) << std::setfill('0') << *etherType << "\n";
} else {
std::cout << "\t\t EtherType:\t N/A\n";
}
// Print the data
for(size_t i = 0; i < ethMessage->data.size(); i++) {
+7
View File
@@ -15,6 +15,13 @@ int main() {
// You now hold the shared_ptrs for these devices, you are considered to "own" these devices from a memory perspective
std::cout << "OK, " << devices.size() << " device" << (devices.size() == 1 ? "" : "s") << " found" << std::endl;
if(devices.empty()) {
auto lastError = icsneo::GetLastError();
if(lastError.getType() != icsneo::APIEvent::Type::NoErrorFound)
std::cout << lastError << std::endl;
return 0;
}
// List off the devices
for(auto& device : devices)
std::cout << '\t' << device->describe() << " @ Handle " << device->getNeoDevice().handle << std::endl;
+38 -14
View File
@@ -14,6 +14,13 @@ int main() {
auto devices = icsneo::FindAllDevices(); // This is type std::vector<std::shared_ptr<icsneo::Device>>
std::cout << "OK, " << devices.size() << " device" << (devices.size() == 1 ? "" : "s") << " found" << std::endl;
if(devices.empty()) {
auto lastError = icsneo::GetLastError();
if(lastError.getType() != icsneo::APIEvent::Type::NoErrorFound)
std::cout << lastError << std::endl;
return 0;
}
// List off the devices
for(auto& device : devices)
std::cout << '\t' << device->describe() << " @ Handle " << device->getNeoDevice().handle << std::endl;
@@ -29,7 +36,7 @@ int main() {
}
std::cout << "OK" << std::endl;
// Create a subscription message for the GPS signals
// Create a subscription message for the GPS signals and TIME_SINCE_MSG
std::cout << "\tSending a live data subscribe command... ";
auto msg = std::make_shared<icsneo::LiveDataCommandMessage>();
msg->appendSignalArg(icsneo::LiveDataValueType::GPS_LATITUDE);
@@ -37,6 +44,7 @@ int main() {
msg->appendSignalArg(icsneo::LiveDataValueType::GPS_ACCURACY);
msg->appendSignalArg(icsneo::LiveDataValueType::DAQ_ENABLE);
msg->appendSignalArg(icsneo::LiveDataValueType::MANUAL_TRIGGER);
msg->appendSignalArg(icsneo::LiveDataValueType::TIME_SINCE_MSG);
msg->cmd = icsneo::LiveDataCommand::SUBSCRIBE;
msg->handle = icsneo::LiveDataUtil::getNewHandle();
msg->updatePeriod = std::chrono::milliseconds(100);
@@ -44,6 +52,9 @@ int main() {
// Transmit the subscription message
ret = device->subscribeLiveData(msg);
std::cout << (ret ? "OK" : "FAIL") << std::endl;
if (!ret) {
std::cout << "\t\tError: " << icsneo::GetLastError() << std::endl;
}
// Register a handler that uses the data after it arrives every ~100ms
std::cout << "\tStreaming messages for 3 seconds... " << std::endl << std::endl;
@@ -53,19 +64,21 @@ int main() {
switch(ldMsg->cmd) {
case icsneo::LiveDataCommand::STATUS: {
auto msg2 = std::dynamic_pointer_cast<icsneo::LiveDataStatusMessage>(message);
std::cout << "[Handle] " << ldMsg->handle << std::endl;
std::cout << "[Requested Command] " << msg2->requestedCommand << std::endl;
std::cout << "[Status] " << msg2->status << std::endl << std::endl;
std::cout << "[STATUS Message]" << std::endl;
std::cout << " Handle: " << ldMsg->handle << std::endl;
std::cout << " Requested Command: " << msg2->requestedCommand << std::endl;
std::cout << " Status: " << msg2->status << std::endl << std::endl;
break;
}
case icsneo::LiveDataCommand::RESPONSE: {
auto valueMsg = std::dynamic_pointer_cast<icsneo::LiveDataValueMessage>(message);
if((valueMsg->handle == msg->handle) && (valueMsg->values.size() == msg->args.size()))
{
std::cout << "[Handle] " << msg->handle << std::endl;
std::cout << "[Values] " << valueMsg->numArgs << std::endl;
std::cout << "[Response Message]" << std::endl;
std::cout << " Handle: " << msg->handle << std::endl;
std::cout << " Number of Values: " << valueMsg->numArgs << std::endl;
for(uint32_t i = 0; i < valueMsg->numArgs; ++i) {
std::cout << "[" << msg->args[i]->valueType << "] ";
std::cout << " [" << msg->args[i]->valueType << "] ";
auto scaledValue = icsneo::LiveDataUtil::liveDataValueToDouble(*valueMsg->values[i]);
std::cout << scaledValue << std::endl;
}
@@ -86,22 +99,33 @@ int main() {
setValMsg->cmd = icsneo::LiveDataCommand::SET_VALUE;
setValMsg->handle = msg->handle;
// Convert the value format
icsneo::LiveDataValue ldValueDAQEnable;
icsneo::LiveDataValue ldValueManTrig;
if (!icsneo::LiveDataUtil::liveDataDoubleToValue(val / 3, ldValueDAQEnable) ||
!icsneo::LiveDataUtil::liveDataDoubleToValue(val, ldValueManTrig)) {
auto ldValueDAQEnable = icsneo::LiveDataUtil::liveDataDoubleToValue(val / 3);
auto ldValueManTrig = icsneo::LiveDataUtil::liveDataDoubleToValue(val);
auto ldValueTimeSinceMsg = icsneo::LiveDataUtil::liveDataDoubleToValue(val);
if (!ldValueDAQEnable || !ldValueManTrig || !ldValueTimeSinceMsg) {
std::cout << "\tError: Failed to convert values" << std::endl;
break;
}
setValMsg->appendSetValue(icsneo::LiveDataValueType::DAQ_ENABLE, ldValueDAQEnable);
setValMsg->appendSetValue(icsneo::LiveDataValueType::MANUAL_TRIGGER, ldValueManTrig);
device->setValueLiveData(setValMsg);
setValMsg->appendSetValue(icsneo::LiveDataValueType::DAQ_ENABLE, *ldValueDAQEnable);
setValMsg->appendSetValue(icsneo::LiveDataValueType::MANUAL_TRIGGER, *ldValueManTrig);
setValMsg->appendSetValue(icsneo::LiveDataValueType::TIME_SINCE_MSG, *ldValueTimeSinceMsg);
std::cout << "\tSetting values: DAQ_ENABLE=" << (val / 3)
<< ", MANUAL_TRIGGER=" << val
<< ", TIME_SINCE_MSG=" << val << std::endl;
if (!device->setValueLiveData(setValMsg)) {
std::cout << "\tError setting values: " << icsneo::GetLastError() << std::endl;
}
++val;
// Run handler for three seconds to observe the signal data
std::this_thread::sleep_for(std::chrono::seconds(3));
}
// Unsubscribe from the GPS signals and run handler for one more second
// Unsubscription only requires a valid in-use handle, in this case from our previous subscription
std::cout << "\tUnsubscribing... ";
ret = device->unsubscribeLiveData(msg->handle);
std::cout << (ret ? "OK" : "FAIL") << std::endl;
// The handler should no longer print values
std::this_thread::sleep_for(std::chrono::seconds(1));
device->removeMessageCallback(handler);
+4 -2
View File
@@ -9,8 +9,10 @@ int main(int, char**) {
auto devices = icsneo::FindAllDevices();
if(devices.size() == 0) {
std::cout << "No device found" << std::endl;
if(devices.empty()) {
auto lastError = icsneo::GetLastError();
if(lastError.getType() != icsneo::APIEvent::Type::NoErrorFound)
std::cout << lastError << std::endl;
return -1;
}
+7
View File
@@ -48,6 +48,13 @@ int main()
// You now hold the shared_ptrs for these devices, you are considered to "own" these devices from a memory perspective
std::cout << "OK, " << devices.size() << " device" << (devices.size() == 1 ? "" : "s") << " found" << std::endl;
if(devices.empty()) {
auto lastError = icsneo::GetLastError();
if(lastError.getType() != icsneo::APIEvent::Type::NoErrorFound)
std::cout << lastError << std::endl;
return 0;
}
// List off the devices
for (auto &device : devices)
std::cout << '\t' << device->describe() << " @ Handle " << device->getNeoDevice().handle << std::endl;
+7
View File
@@ -76,6 +76,13 @@ int main() {
// You now hold the shared_ptrs for these devices, you are considered to "own" these devices from a memory perspective
std::cout << "OK, " << devices.size() << " device" << (devices.size() == 1 ? "" : "s") << " found" << std::endl;
if(devices.empty()) {
auto lastError = icsneo::GetLastError();
if(lastError.getType() != icsneo::APIEvent::Type::NoErrorFound)
std::cout << lastError << std::endl;
return 0;
}
// List off the devices
for(auto& device : devices)
std::cout << '\t' << device->describe() << " @ Handle " << device->getNeoDevice().handle << std::endl;
+28 -3
View File
@@ -22,6 +22,13 @@ int main() {
// You now hold the shared_ptrs for these devices, you are considered to "own" these devices from a memory perspective
std::cout << "OK, " << devices.size() << " device" << (devices.size() == 1 ? "" : "s") << " found" << std::endl;
if(devices.empty()) {
auto lastError = icsneo::GetLastError();
if(lastError.getType() != icsneo::APIEvent::Type::NoErrorFound)
std::cout << lastError << std::endl;
return 0;
}
// List off the devices
for(auto& device : devices)
std::cout << '\t' << device->describe() << " @ Handle " << device->getNeoDevice().handle << std::endl;
@@ -208,8 +215,26 @@ int main() {
std::cout << "\t\t Timestamped:\t"<< ethMessage->timestamp << " ns since 1/1/2007\n";
// The MACAddress may be printed directly or accessed with the `data` member
std::cout << "\t\t Source:\t" << ethMessage->getSourceMAC() << "\n";
std::cout << "\t\t Destination:\t" << ethMessage->getDestinationMAC();
// The MACAddress may be printed directly or accessed with the `data` member
auto printMAC = [](const icsneo::MACAddress& mac) {
std::ostringstream oss;
for(size_t i = 0; i < mac.size(); i++) {
oss << std::hex << std::setw(2) << std::setfill('0') << (uint32_t)mac[i];
if(i != mac.size() - 1)
oss << ':';
}
return oss.str();
};
if (auto destMAC = ethMessage->getDestinationMAC(); destMAC.has_value()) {
std::cout << "\t\t Destination:\t" << printMAC(*destMAC) << "\n";
} else {
std::cout << "\t\t Destination:\t N/A\n";
}
if (auto srcMAC = ethMessage->getSourceMAC(); srcMAC.has_value()) {
std::cout << "\t\t Source:\t" << printMAC(*srcMAC) << "\n";
} else {
std::cout << "\t\t Source:\t N/A\n";
}
// Print the data
for(size_t i = 0; i < ethMessage->data.size(); i++) {
@@ -321,7 +346,7 @@ int main() {
if(val.has_value())
std::cout << " - OK (" << val.value() << "V)" << std::endl;
else
std::cout << " - FAIL, it may need to be enabled in neoVI Explorer (" << icsneo::GetLastError() << ")" << std::endl;
std::cout << " - FAIL, it may need to be enabled in ICS Device Manager (" << icsneo::GetLastError() << ")" << std::endl;
}
}
+3
View File
@@ -86,6 +86,9 @@ int main(int argc, const char** argv) {
}
if(!device) {
std::cerr << "Failed to find device" << std::endl;
auto lastError = icsneo::GetLastError();
if(lastError.getType() != icsneo::APIEvent::Type::NoErrorFound)
std::cerr << lastError << std::endl;
std::cerr << usage;
return -1;
}
+5
View File
@@ -0,0 +1,5 @@
add_executable(libicsneocpp-t1s-settings src/T1SSettingsExample.cpp)
target_link_libraries(libicsneocpp-t1s-settings icsneocpp)
add_executable(libicsneocpp-t1s-symbol-decoding src/T1SSymbolDecodingExample.cpp)
target_link_libraries(libicsneocpp-t1s-symbol-decoding icsneocpp)

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