61 Commits
Author SHA1 Message Date
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
149 changed files with 20409 additions and 1083 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
+76 -27
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;
}
@@ -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,8 @@ 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";
static constexpr const char* SERVD_NO_DEVICES_FOUND = "Servd is running but no devices found";
// DXX
static constexpr const char* DXX_ERROR_SYS = "System error, check errno/GetLastError()";
@@ -186,6 +176,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 +304,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 +314,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 +373,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 +440,10 @@ 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;
case Type::ServdNoDevicesFound:
return SERVD_NO_DEVICES_FOUND;
// DXX
case Type::DXXErrorSys:
@@ -437,13 +458,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
+2
View File
@@ -126,6 +126,8 @@ 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("ServdNoDevicesFound", APIEvent::Type::ServdNoDevicesFound)
.value("DXXErrorSys", APIEvent::Type::DXXErrorSys)
.value("DXXErrorInt", APIEvent::Type::DXXErrorInt)
.value("DXXErrorOverflow", APIEvent::Type::DXXErrorOverflow)
@@ -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::classh<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
@@ -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
+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);
}
@@ -12,7 +12,6 @@ namespace icsneo {
struct DeviceSettingsNamespace {
using EthLinkMode = AELinkMode;
using LinkSpeed = EthLinkSpeed;
};
void init_idevicesettings(pybind11::module_& m) {
@@ -23,24 +22,107 @@ void init_idevicesettings(pybind11::module_& m) {
.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
@@ -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
+5 -1
View File
@@ -64,6 +64,7 @@ void init_extension(pybind11::classh<FlexRayNamespace>& c) {
.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::classh<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)
@@ -114,6 +116,7 @@ void init_extension(pybind11::classh<FlexRayNamespace>& c) {
.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,7 +162,8 @@ 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
}
+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());
+65 -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. */
@@ -285,14 +285,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 +618,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 +663,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 +767,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 neoVI Explorer 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;
}
+2
View File
@@ -0,0 +1,2 @@
add_executable(libicsneocpp-analog-out src/analog_out.cpp)
target_link_libraries(libicsneocpp-analog-out icsneocpp)
+157
View File
@@ -0,0 +1,157 @@
/**
* 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;
return -1;
}
} else {
// Use first available device
auto devices = icsneo::FindAllDevices();
if(devices.empty()) {
std::cerr << "No devices found" << 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;
}
+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,145 @@
#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()) {
std::cout << "error: no devices found" << 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;
}
@@ -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++) {
+31 -14
View File
@@ -29,7 +29,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 +37,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 +45,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 +57,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 +92,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);
+20 -2
View File
@@ -208,8 +208,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++) {
+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)
+327
View File
@@ -0,0 +1,327 @@
#include <iostream>
#include <iomanip>
#include <vector>
#include <optional>
#include <string>
#include <limits>
#include <sstream>
#include <algorithm>
#include "icsneo/icsneocpp.h"
template<typename T>
std::string optToString(const std::optional<T>& opt) {
if (!opt.has_value())
return "N/A";
if constexpr (std::is_same_v<T, bool>)
return opt.value() ? "true" : "false";
else
return std::to_string(opt.value());
}
bool getUserConfirmation(const std::string& prompt) {
std::string input;
std::cout << prompt << " (y/n): " << std::flush;
std::getline(std::cin, input);
if (!input.empty()) {
char c = static_cast<char>(std::tolower(input[0]));
return (c == 'y');
}
return false;
}
std::vector<icsneo::Network::NetID> selectNetworks(const std::vector<icsneo::Network::NetID>& availableNetworks) {
std::vector<icsneo::Network::NetID> selectedNetworks;
std::cout << "\n" << std::string(70, '=') << std::endl;
std::cout << "Select T1S Networks to Configure" << std::endl;
std::cout << std::string(70, '=') << std::endl;
for (size_t i = 0; i < availableNetworks.size(); i++) {
std::cout << " [" << (i + 1) << "] " << icsneo::Network(availableNetworks[i]) << std::endl;
}
std::cout << "\nEnter network numbers to configure (e.g., '1,3' or '1-3' or 'all'): " << std::flush;
std::string input;
std::getline(std::cin, input);
if (input.empty())
return selectedNetworks;
std::transform(input.begin(), input.end(), input.begin(),
[](unsigned char c) { return static_cast<char>(std::tolower(c)); });
if (input == "all") {
return availableNetworks;
}
std::stringstream ss(input);
std::string token;
while (std::getline(ss, token, ',')) {
token.erase(0, token.find_first_not_of(" \t"));
token.erase(token.find_last_not_of(" \t") + 1);
size_t dashPos = token.find('-');
if (dashPos != std::string::npos) {
try {
int start = std::stoi(token.substr(0, dashPos));
int end = std::stoi(token.substr(dashPos + 1));
for (int i = start; i <= end; i++) {
if (i >= 1 && i <= (int)availableNetworks.size()) {
selectedNetworks.push_back(availableNetworks[i - 1]);
}
}
} catch (...) {}
} else {
try {
int num = std::stoi(token);
if (num >= 1 && num <= (int)availableNetworks.size()) {
selectedNetworks.push_back(availableNetworks[num - 1]);
}
} catch (...) {}
}
}
return selectedNetworks;
}
uint8_t getUint8Input(const std::string& prompt, uint8_t defaultValue) {
std::string input;
std::cout << prompt << " [" << (int)defaultValue << "]: " << std::flush;
std::getline(std::cin, input);
if (input.empty())
return defaultValue;
try {
int val = std::stoi(input);
if (val >= 0 && val <= 255)
return static_cast<uint8_t>(val);
} catch (...) {}
return defaultValue;
}
uint16_t getUint16Input(const std::string& prompt, uint16_t defaultValue) {
std::string input;
std::cout << prompt << " [" << (int)defaultValue << "]: " << std::flush;
std::getline(std::cin, input);
if (input.empty())
return defaultValue;
try {
int val = std::stoi(input);
if (val >= 0 && val <= 65535)
return static_cast<uint16_t>(val);
} catch (...) {}
return defaultValue;
}
void displayT1SSettings(const std::shared_ptr<icsneo::Device>& device, icsneo::Network::NetID netId) {
std::cout << "\t" << icsneo::Network(netId) << " T1S Settings:" << std::endl;
std::cout << "\t PLCA Enabled: " << optToString(device->settings->isT1SPLCAEnabledFor(netId)) << std::endl;
std::cout << "\t Local ID: " << optToString(device->settings->getT1SLocalIDFor(netId)) << std::endl;
std::cout << "\t Max Nodes: " << optToString(device->settings->getT1SMaxNodesFor(netId)) << std::endl;
std::cout << "\t TX Opp Timer: " << optToString(device->settings->getT1STxOppTimerFor(netId)) << std::endl;
std::cout << "\t Max Burst: " << optToString(device->settings->getT1SMaxBurstFor(netId)) << std::endl;
std::cout << "\t Burst Timer: " << optToString(device->settings->getT1SBurstTimerFor(netId)) << std::endl;
auto termEnabled = device->settings->isT1STerminationEnabledFor(netId);
if (termEnabled.has_value())
std::cout << "\t Termination: " << optToString(termEnabled) << std::endl;
auto localIdAlt = device->settings->getT1SLocalIDAlternateFor(netId);
if (localIdAlt.has_value()) {
std::cout << "\t Local ID Alternate: " << optToString(localIdAlt) << std::endl;
std::cout << "\t Bus Dec Beacons: " << optToString(device->settings->isT1SBusDecodingBeaconsEnabledFor(netId)) << std::endl;
std::cout << "\t Bus Dec All: " << optToString(device->settings->isT1SBusDecodingAllEnabledFor(netId)) << std::endl;
auto multiIdMask = device->settings->getT1SMultiIDEnableMaskFor(netId);
if (multiIdMask.has_value()) {
std::cout << "\t Multi-ID Mask: 0x" << std::hex << std::setw(2) << std::setfill('0')
<< (int)multiIdMask.value() << std::dec << std::endl;
std::cout << "\t Multi-IDs: ";
for (uint8_t i = 0; i < 7; i++) {
if (i > 0) std::cout << ", ";
auto multiId = device->settings->getT1SMultiIDFor(netId, i);
std::cout << "[" << (int)i << "]=" << optToString(multiId);
}
std::cout << std::endl;
}
}
std::cout << std::endl;
}
void configureT1SNetwork(std::shared_ptr<icsneo::Device>& device, icsneo::Network::NetID netId) {
std::cout << "\n" << std::string(70, '=') << std::endl;
std::cout << "Configuring T1S Network: " << icsneo::Network(netId) << std::endl;
std::cout << std::string(70, '=') << std::endl;
std::cout << "\n--- Basic PLCA Settings ---" << std::endl;
bool plcaEnabled = getUserConfirmation("Enable PLCA");
device->settings->setT1SPLCAFor(netId, plcaEnabled);
uint8_t localId = getUint8Input("Local ID (0-255)", 1);
device->settings->setT1SLocalIDFor(netId, localId);
uint8_t maxNodes = getUint8Input("Max Nodes (0-255)", 8);
device->settings->setT1SMaxNodesFor(netId, maxNodes);
uint8_t txOppTimer = getUint8Input("TX Opportunity Timer (0-255)", 20);
device->settings->setT1STxOppTimerFor(netId, txOppTimer);
uint8_t maxBurst = getUint8Input("Max Burst (0-255)", 128);
device->settings->setT1SMaxBurstFor(netId, maxBurst);
uint8_t burstTimer = getUint8Input("Burst Timer (0-255)", 64);
device->settings->setT1SBurstTimerFor(netId, burstTimer);
if (device->settings->isT1STerminationEnabledFor(netId).has_value()) {
std::cout << "\n--- Termination Settings ---" << std::endl;
bool termEnabled = getUserConfirmation("Enable Termination");
device->settings->setT1STerminationFor(netId, termEnabled);
}
if (device->settings->getT1SLocalIDAlternateFor(netId).has_value()) {
std::cout << "\n--- Extended Settings ---" << std::endl;
uint8_t localIdAlt = getUint8Input("Local ID Alternate (0-255)", 0);
device->settings->setT1SLocalIDAlternateFor(netId, localIdAlt);
bool busDecBeacons = getUserConfirmation("Enable Bus Decoding (Beacons)");
device->settings->setT1SBusDecodingBeaconsFor(netId, busDecBeacons);
bool busDecAll = getUserConfirmation("Enable Bus Decoding (All Symbols)");
device->settings->setT1SBusDecodingAllFor(netId, busDecAll);
if (getUserConfirmation("Configure Multi-ID settings?")) {
uint8_t multiIdMask = getUint8Input("Multi-ID Enable Mask (0x00-0xFF, hex)", 0x00);
device->settings->setT1SMultiIDEnableMaskFor(netId, multiIdMask);
std::cout << "Configure Multi-IDs (7 slots):" << std::endl;
for (uint8_t i = 0; i < 7; i++) {
uint8_t multiId = getUint8Input(" Multi-ID [" + std::to_string(i) + "]", 0);
device->settings->setT1SMultiIDFor(netId, i, multiId);
}
}
}
std::cout << "\n✓ Configuration complete for " << icsneo::Network(netId) << std::endl;
}
int main() {
std::cout << "\n" << std::string(70, '=') << std::endl;
std::cout << "10BASE-T1S SETTINGS CONFIGURATION EXAMPLE" << std::endl;
std::cout << std::string(70, '=') << std::endl;
std::cout << "libicsneo " << icsneo::GetVersion() << std::endl;
std::cout << std::string(70, '=') << 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()) {
std::cout << "No devices found!" << std::endl;
return 1;
}
for(auto& device : devices)
std::cout << " " << device->describe() << std::endl;
std::shared_ptr<icsneo::Device> selectedDevice;
for(auto& device : devices) {
if (device->getType() == icsneo::DeviceType::RADComet3) {
selectedDevice = device;
break;
}
}
if (!selectedDevice && !devices.empty())
selectedDevice = devices[0];
if (!selectedDevice) {
std::cout << "No suitable device found!" << std::endl;
return 1;
}
std::cout << "\nSelected device: " << selectedDevice->describe() << std::endl;
std::cout << "Serial: " << selectedDevice->getSerial() << std::endl;
std::cout << "\nOpening device... " << std::flush;
if (!selectedDevice->open()) {
std::cout << "✗ Failed" << std::endl;
std::cout << icsneo::GetLastError() << std::endl;
return 1;
}
std::cout << "" << std::endl;
std::vector<icsneo::Network::NetID> candidateNetworks = {
icsneo::Network::NetID::AE_01, icsneo::Network::NetID::AE_02,
icsneo::Network::NetID::AE_03, icsneo::Network::NetID::AE_04,
icsneo::Network::NetID::AE_05, icsneo::Network::NetID::AE_06,
icsneo::Network::NetID::AE_07, icsneo::Network::NetID::AE_08,
icsneo::Network::NetID::AE_09, icsneo::Network::NetID::AE_10
};
std::vector<icsneo::Network::NetID> t1sNetworks;
for (auto netId : candidateNetworks) {
auto localId = selectedDevice->settings->getT1SLocalIDFor(netId);
if (localId.has_value())
t1sNetworks.push_back(netId);
}
if (t1sNetworks.empty()) {
std::cout << "No T1S networks found on this device" << std::endl;
selectedDevice->close();
return 1;
}
std::cout << "\nFound " << t1sNetworks.size() << " T1S network"
<< (t1sNetworks.size() == 1 ? "" : "s") << ":" << std::endl;
for (size_t i = 0; i < t1sNetworks.size(); i++)
std::cout << " [" << (i + 1) << "] " << icsneo::Network(t1sNetworks[i]) << std::endl;
std::cout << "\n" << std::string(70, '-') << std::endl;
std::cout << "Current T1S Settings:" << std::endl;
std::cout << std::string(70, '-') << std::endl;
for (auto netId : t1sNetworks)
displayT1SSettings(selectedDevice, netId);
auto networksToConfig = selectNetworks(t1sNetworks);
if (networksToConfig.empty()) {
std::cout << "\nNo networks selected for configuration." << std::endl;
std::cout << "Closing device... " << std::flush;
selectedDevice->close();
std::cout << "" << std::endl;
return 0;
}
std::cout << "\nConfiguring " << networksToConfig.size() << " network"
<< (networksToConfig.size() == 1 ? "" : "s") << "..." << std::endl;
for (auto netId : networksToConfig)
configureT1SNetwork(selectedDevice, netId);
std::cout << "\n" << std::string(70, '=') << std::endl;
bool saveToEEPROM = getUserConfirmation("Save settings to EEPROM (permanent)?");
std::cout << std::string(70, '=') << std::endl;
std::cout << "\nApplying settings" << (saveToEEPROM ? " to EEPROM" : " temporarily") << "... " << std::flush;
bool success = selectedDevice->settings->apply(!saveToEEPROM);
if (!success) {
std::cout << "✗ Failed" << std::endl;
std::cout << icsneo::GetLastError() << std::endl;
selectedDevice->close();
return 1;
}
std::cout << "" << std::endl;
std::cout << "\n" << std::string(70, '-') << std::endl;
std::cout << "Updated T1S Settings:" << std::endl;
std::cout << std::string(70, '-') << std::endl;
for (auto netId : t1sNetworks)
displayT1SSettings(selectedDevice, netId);
std::cout << "Closing device... " << std::flush;
selectedDevice->close();
std::cout << "" << std::endl;
return 0;
}
@@ -0,0 +1,357 @@
// 10BASE-T1S Symbol Decoding Example
// Demonstrates T1S bus symbol decoding and analysis
#include <iostream>
#include <iomanip>
#include <thread>
#include <chrono>
#include <map>
#include <string>
#include <atomic>
#include "icsneo/icsneocpp.h"
enum class T1SSymbol : uint8_t {
SSD = 0x04,
ESDOK = 0x07,
BEACON = 0x08,
ESD = 0x0D,
ESDERR = 0x11,
SYNC = 0x18,
ESDJAB = 0x19,
SILENCE = 0x1F
};
std::string getSymbolName(uint8_t value) {
switch(static_cast<T1SSymbol>(value)) {
case T1SSymbol::SSD: return "SSD";
case T1SSymbol::ESDOK: return "ESDOK";
case T1SSymbol::BEACON: return "BEACON";
case T1SSymbol::ESD: return "ESD";
case T1SSymbol::ESDERR: return "ESDERR";
case T1SSymbol::SYNC: return "SYNC";
case T1SSymbol::ESDJAB: return "ESDJAB";
case T1SSymbol::SILENCE: return "SILENCE";
default:
if (value <= 0x0F) {
std::stringstream ss;
ss << "DATA(0x" << std::hex << std::uppercase << (int)value << ")";
return ss.str();
}
std::stringstream ss;
ss << "UNKNOWN(0x" << std::hex << std::uppercase << std::setw(2)
<< std::setfill('0') << (int)value << std::setfill(' ') << ")";
return ss.str();
}
}
struct T1SStatistics {
std::atomic<uint64_t> symbolCount{0};
std::atomic<uint64_t> beaconCount{0};
std::atomic<uint64_t> wakeCount{0};
std::atomic<uint64_t> burstCount{0};
std::atomic<uint64_t> dataFrameCount{0};
std::map<std::string, uint64_t> symbolStats;
void reset() {
symbolCount = 0;
beaconCount = 0;
wakeCount = 0;
burstCount = 0;
dataFrameCount = 0;
symbolStats.clear();
}
void print() const {
std::cout << std::setfill(' ');
std::cout << "\n" << std::string(70, '=') << std::endl;
std::cout << "T1S SYMBOL DECODING STATISTICS" << std::endl;
std::cout << std::string(70, '=') << std::endl;
std::cout << "Total Symbols: " << symbolCount << std::endl;
std::cout << "Total Beacons: " << beaconCount << std::endl;
std::cout << "Total Wake Signals: " << wakeCount << std::endl;
std::cout << "Total Bursts: " << burstCount << std::endl;
std::cout << "Total Data Frames: " << dataFrameCount << std::endl;
if (!symbolStats.empty()) {
std::cout << "\n" << std::string(70, '-') << std::endl;
std::cout << "Symbol Type Breakdown:" << std::endl;
std::cout << std::string(70, '-') << std::endl;
std::vector<std::pair<std::string, uint64_t>> sortedStats(
symbolStats.begin(), symbolStats.end());
std::sort(sortedStats.begin(), sortedStats.end(),
[](const auto& a, const auto& b) { return a.second > b.second; });
for (const auto& [name, count] : sortedStats) {
std::cout << " " << std::left << std::setw(20) << name
<< std::right << std::setw(10) << count << std::endl;
}
}
std::cout << std::string(70, '=') << std::endl;
}
};
bool getUserConfirmation(const std::string& prompt) {
std::string input;
std::cout << prompt << " (y/n): " << std::flush;
std::getline(std::cin, input);
if (!input.empty()) {
char c = static_cast<char>(std::tolower(input[0]));
return (c == 'y');
}
return false;
}
bool configureT1SDecoding(std::shared_ptr<icsneo::Device>& device, icsneo::Network::NetID network,
bool enableSymbols, bool enableBeacons) {
std::cout << "\nConfiguring T1S decoding on network " << icsneo::Network(network) << "..." << std::endl;
if (!device->settings->setT1SBusDecodingAllFor(network, enableSymbols)) {
std::cerr << " ✗ Failed to set T1S symbol decoding" << std::endl;
return false;
}
if (enableSymbols) {
std::cout << " ✓ Enabled decoding of all T1S symbols" << std::endl;
} else {
std::cout << " • T1S symbol decoding disabled" << std::endl;
}
if (!device->settings->setT1SBusDecodingBeaconsFor(network, enableBeacons)) {
std::cerr << " ✗ Failed to set T1S beacon decoding" << std::endl;
return false;
}
if (enableBeacons) {
std::cout << " ✓ Enabled T1S beacon decoding" << std::endl;
} else {
std::cout << " • T1S beacon decoding disabled" << std::endl;
}
if (!device->settings->apply(true)) {
std::cerr << " ✗ Failed to apply settings to device" << std::endl;
std::cerr << " " << icsneo::GetLastError() << std::endl;
return false;
}
std::cout << " ✓ Settings applied successfully" << std::endl;
return true;
}
void setupSymbolMonitoring(std::shared_ptr<icsneo::Device>& device,
icsneo::Network::NetID network,
T1SStatistics& stats) {
auto callback = std::make_shared<icsneo::MessageCallback>(
icsneo::MessageFilter(network),
[&stats](std::shared_ptr<icsneo::Message> message) {
if (message->type != icsneo::Message::Type::Frame)
return;
auto frame = std::static_pointer_cast<icsneo::Frame>(message);
auto netType = frame->network.getType();
if (netType != icsneo::Network::Type::Ethernet && netType != icsneo::Network::Type::AutomotiveEthernet)
return;
auto ethMsg = std::static_pointer_cast<icsneo::EthernetMessage>(frame);
if (!ethMsg->t1s)
return;
double timestamp_ms = ethMsg->timestamp / 1000000.0;
if (ethMsg->t1s->isSymbol) {
size_t numSymbols = ethMsg->data.size();
std::cout << std::fixed << std::setprecision(3)
<< "[" << std::setw(12) << timestamp_ms << " ms] "
<< "T1S Symbols";
if (numSymbols > 0) {
std::cout << " (" << numSymbols << " symbol" << (numSymbols > 1 ? "s" : "") << ")";
}
std::cout << " | Node ID: " << (int)ethMsg->t1s->nodeId << std::endl;
for (size_t i = 0; i < numSymbols; i++) {
uint8_t symbolValue = ethMsg->data[i];
std::string symbolName = getSymbolName(symbolValue);
stats.symbolCount++;
stats.symbolStats[symbolName]++;
if (symbolValue == static_cast<uint8_t>(T1SSymbol::BEACON)) {
stats.beaconCount++;
}
std::cout << " [" << i << "] " << std::left << std::setw(10) << symbolName << std::right
<< " = 0x" << std::hex << std::uppercase << std::setw(2)
<< std::setfill('0') << (int)symbolValue << std::setfill(' ')
<< std::dec << std::endl;
}
if (numSymbols == 0 && ethMsg->t1s->symbolType != 0) {
uint8_t symbolValue = ethMsg->t1s->symbolType;
std::string symbolName = getSymbolName(symbolValue);
stats.symbolCount++;
stats.symbolStats[symbolName]++;
if (symbolValue == static_cast<uint8_t>(T1SSymbol::BEACON)) {
stats.beaconCount++;
}
std::cout << " " << std::left << std::setw(10) << symbolName << std::right
<< " = 0x" << std::hex << std::uppercase << std::setw(2)
<< std::setfill('0') << (int)symbolValue << std::setfill(' ')
<< std::dec << " (from t1sSymbolType field)" << std::endl;
}
}
else if (ethMsg->t1s->isBurst) {
stats.burstCount++;
std::cout << std::fixed << std::setprecision(3)
<< "[" << std::setw(12) << timestamp_ms << " ms] "
<< "BURST | "
<< "Node ID: " << (int)ethMsg->t1s->nodeId << " | "
<< "Burst Count: " << (int)ethMsg->t1s->burstCount << std::endl;
}
else if (ethMsg->t1s->isWake) {
stats.wakeCount++;
std::cout << std::fixed << std::setprecision(3)
<< "[" << std::setw(12) << timestamp_ms << " ms] "
<< "WAKE signal detected | "
<< "Node ID: " << (int)ethMsg->t1s->nodeId << std::endl;
}
else {
stats.dataFrameCount++;
std::cout << std::fixed << std::setprecision(3)
<< "[" << std::setw(12) << timestamp_ms << " ms] "
<< "T1S Data Frame | "
<< "Length: " << ethMsg->data.size() << " bytes | "
<< "Node ID: " << (int)ethMsg->t1s->nodeId << std::endl;
if (!ethMsg->data.empty()) {
std::cout << " Data: ";
size_t preview_len = std::min(ethMsg->data.size(), size_t(16));
for (size_t i = 0; i < preview_len; i++) {
std::cout << std::hex << std::uppercase << std::setw(2)
<< std::setfill('0') << (int)ethMsg->data[i] << " ";
}
if (ethMsg->data.size() > 16)
std::cout << "...";
std::cout << std::setfill(' ') << std::dec << std::endl;
}
}
}
);
device->addMessageCallback(callback);
}
int main() {
const icsneo::Network::NetID MONITOR_NETWORK = icsneo::Network::NetID::AE_02;
const int MONITOR_DURATION_SECONDS = 30;
std::cout << "\n" << std::string(70, '=') << std::endl;
std::cout << "10BASE-T1S SYMBOL DECODING EXAMPLE" << std::endl;
std::cout << std::string(70, '=') << std::endl;
std::cout << "libicsneo " << icsneo::GetVersion() << std::endl;
std::cout << std::string(70, '=') << 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()) {
std::cerr << "No devices found!" << std::endl;
return 1;
}
// List devices
for (const auto& device : devices) {
std::cout << " " << device->describe() << std::endl;
}
std::shared_ptr<icsneo::Device> device;
for (auto& dev : devices) {
if (dev->getType() == icsneo::DeviceType::RADComet3) {
device = dev;
break;
}
}
if (!device && !devices.empty())
device = devices[0];
if (!device) {
std::cerr << "No suitable device found!" << std::endl;
return 1;
}
std::cout << "\nSelected device: " << device->describe() << std::endl;
std::cout << "Serial: " << device->getSerial() << std::endl;
std::cout << "\n" << std::string(70, '-') << std::endl;
std::cout << "T1S DECODING CONFIGURATION" << std::endl;
std::cout << std::string(70, '-') << std::endl;
bool enableSymbols = getUserConfirmation("Enable T1S symbol decoding (all symbols)");
bool enableBeacons = getUserConfirmation("Enable T1S beacon decoding");
std::cout << std::string(70, '-') << std::endl;
std::cout << "\nOpening device... " << std::flush;
if (!device->open()) {
std::cerr << "✗ Failed" << std::endl;
std::cerr << " " << icsneo::GetLastError() << std::endl;
return 1;
}
std::cout << "" << std::endl;
std::cout << "Enabling message polling... " << std::flush;
if (!device->enableMessagePolling()) {
std::cerr << "✗ Failed" << std::endl;
std::cerr << " " << icsneo::GetLastError() << std::endl;
device->close();
return 1;
}
device->setPollingMessageLimit(100000);
std::cout << "" << std::endl;
if (!configureT1SDecoding(device, MONITOR_NETWORK, enableSymbols, enableBeacons)) {
device->close();
return 1;
}
std::cout << "Going online... " << std::flush;
if (!device->goOnline()) {
std::cerr << "✗ Failed" << std::endl;
std::cerr << " " << icsneo::GetLastError() << std::endl;
device->close();
return 1;
}
std::cout << "" << std::endl;
T1SStatistics stats;
setupSymbolMonitoring(device, MONITOR_NETWORK, stats);
std::cout << "\n" << std::string(70, '-') << std::endl;
std::cout << "Monitoring T1S traffic for " << MONITOR_DURATION_SECONDS << " seconds..." << std::endl;
std::cout << std::string(70, '-') << std::endl;
auto startTime = std::chrono::steady_clock::now();
std::vector<std::shared_ptr<icsneo::Message>> messages;
messages.reserve(10000);
while (std::chrono::steady_clock::now() - startTime < std::chrono::seconds(MONITOR_DURATION_SECONDS)) {
device->getMessages(messages);
messages.clear();
std::this_thread::sleep_for(std::chrono::milliseconds(10));
}
std::cout << "\n" << std::string(70, '-') << std::endl;
std::cout << "Closing device... " << std::flush;
device->close();
std::this_thread::sleep_for(std::chrono::milliseconds(100));
std::cout << "" << std::endl;
stats.print();
return 0;
}
@@ -0,0 +1,107 @@
"""
Basic analog output control example using icsneopy library.
Demonstrates how to configure and control analog outputs on supported devices.
Usage: python analog_out_basic.py <pin> <voltage> [--yes]
Arguments:
pin: Pin number (1-3 for RAD Galaxy)
voltage: Voltage level (0-5)
--yes: Skip confirmation prompt
"""
import sys
import icsneopy
def analog_output_example(pin: int, voltage: int, skip_confirm: bool = False):
"""Configure and control analog outputs."""
# Confirmation prompt
if not skip_confirm:
print(f"WARNING: This will set analog output pin {pin} to {voltage}V")
print("Make sure nothing sensitive is connected to this pin.")
response = input("Continue? (yes/no): ")
if response.lower() != "yes":
print("Aborted.")
return
devices = icsneopy.find_all_devices()
if not devices:
raise RuntimeError("No devices found")
device = devices[0]
try:
if not device.open():
raise RuntimeError("Failed to open device")
settings = device.settings
if not settings:
raise RuntimeError("Device settings not available")
print("Refreshing device settings...")
if not settings.refresh():
raise RuntimeError("Failed to refresh settings")
# Enable analog output on specified pin
print(f"Enabling analog output on pin {pin}...")
if not settings.set_misc_io_analog_output_enabled(pin, True):
raise RuntimeError(f"Failed to enable analog output on pin {pin}")
# Map voltage level to enum
voltage_map = {
0: icsneopy.Settings.MiscIOAnalogVoltage.V0,
1: icsneopy.Settings.MiscIOAnalogVoltage.V1,
2: icsneopy.Settings.MiscIOAnalogVoltage.V2,
3: icsneopy.Settings.MiscIOAnalogVoltage.V3,
4: icsneopy.Settings.MiscIOAnalogVoltage.V4,
5: icsneopy.Settings.MiscIOAnalogVoltage.V5
}
voltage_enum = voltage_map[voltage]
# Set pin to specified voltage
print(f"Setting pin {pin} to {voltage}V...")
if not settings.set_misc_io_analog_output(pin, voltage_enum):
raise RuntimeError(f"Failed to set voltage on pin {pin}")
# Apply settings
print("Applying settings...")
if not settings.apply():
raise RuntimeError("Failed to apply settings")
print("Analog output configured successfully!")
print(f"Pin {pin}: Enabled at {voltage}V")
finally:
device.close()
if __name__ == "__main__":
if len(sys.argv) < 3:
print("Error: Missing required arguments\n")
print("Usage: python analog_out_basic.py <pin> <voltage> [--yes]")
print("\nArguments:")
print(" pin: Pin number (1-3 for RAD Galaxy)")
print(" voltage: Voltage level (0-5)")
print(" --yes: Skip confirmation prompt")
sys.exit(1)
try:
pin = int(sys.argv[1])
if pin < 1 or pin > 3:
print("Error: Invalid pin number (must be 1-3)")
sys.exit(1)
voltage = int(sys.argv[2])
if voltage < 0 or voltage > 5:
print("Error: Invalid voltage level (must be 0-5)")
sys.exit(1)
skip_confirm = "--yes" in sys.argv
analog_output_example(pin, voltage, skip_confirm)
except ValueError:
print("Error: Pin and voltage must be integers")
sys.exit(1)
@@ -0,0 +1,114 @@
import sys
import icsneopy
def disk_format_example():
devices = icsneopy.find_all_devices()
if not devices:
print("error: no devices found")
return False
print(f"Found {len(devices)} device(s):")
for i, d in enumerate(devices):
print(f" [{i}] {d}")
if len(devices) == 1:
choice = 0
else:
try:
choice = int(input(f"Select a device [0-{len(devices)-1}]: "))
except (ValueError, EOFError):
print("error: invalid selection")
return False
if choice < 0 or choice >= len(devices):
print("error: invalid selection")
return False
device = devices[choice]
print(f"\nOpening {device}... ", end="", flush=True)
if not device.open():
print("FAIL")
print(f"error: {icsneopy.get_last_error().describe()}")
return False
print("OK")
if not device.supports_disk_formatting():
print(f"error: {device} does not support disk formatting")
device.close()
return False
print(f"Disk count: {device.get_disk_count()}")
# Query current disk state
print("\nQuerying disk details... ", end="", flush=True)
details = device.get_disk_details()
if details is None:
print("FAIL")
print(f"error: {icsneopy.get_last_error().describe()}")
device.close()
return False
print("OK")
layout_name = "RAID0" if details.layout == icsneopy.DiskLayout.RAID0 else "Spanned"
print(f" Layout : {layout_name}")
for i, disk in enumerate(details.disks):
print(f" Disk [{i}]:")
print(f" Present : {'yes' if disk.present else 'no'}")
print(f" Initialized : {'yes' if disk.initialized else 'no'}")
print(f" Formatted : {'yes' if disk.formatted else 'no'}")
if disk.present:
mb = disk.size() // (1024 * 1024)
print(f" Size : {mb} MB ({disk.sectors} sectors x {disk.bytes_per_sector} bytes)")
any_present = any(d.present for d in details.disks)
if not any_present:
print("\nerror: no disks are present in the device")
device.close()
return False
# Build format config from the queried state
fmt = icsneopy.DiskDetails()
fmt.layout = details.layout
fmt.full_format = False # Quick format; set True for a full (slow) format
fmt.disks = details.disks
for disk in fmt.disks:
if disk.present:
disk.formatted = True # mark for formatting
confirm = input(
f"\nThis will format the disk(s) in {device}.\n"
"All existing data will be lost. Continue? [y/N]: "
).strip()
if confirm.lower() != "y":
print("Aborted.")
device.close()
return True
print("\nStarting format...")
state = {"total": 0}
ok = device.format_disk(fmt)
print() # newline after progress line
if not ok:
print(f"error: format failed: {icsneopy.get_last_error().describe()}")
device.close()
return False
print("Format complete!")
# Verify
print("\nVerifying disk state after format... ", end="", flush=True)
post = device.get_disk_details()
if post is None:
print("FAIL (could not re-query disk details)")
else:
print("OK")
for i, disk in enumerate(post.disks):
print(f" Disk [{i}] formatted: {'yes' if disk.formatted else 'no'}")
device.close()
return True
if __name__ == "__main__":
sys.exit(0 if disk_format_example() else 1)
@@ -47,14 +47,23 @@ def setup_ethernet_reception(device):
def frame_handler(frame):
nonlocal frame_count
frame_count += 1
dst = frame.get_destination_mac()
src = frame.get_source_mac()
et = frame.get_ether_type()
dst_str = ":".join(f"{b:02x}" for b in dst) if dst is not None else "N/A"
src_str = ":".join(f"{b:02x}" for b in src) if src is not None else "N/A"
et_str = f"0x{et:04x}" if et is not None else "N/A"
print(f"[RX {frame_count}], "
f"Data: {[hex(b) for b in frame.data]}, "
f"Length: {len(frame.data)}")
frame_filter = icsneopy.MessageFilter(icsneopy.Network.NetID.ETHERNET_01)
f"dst={dst_str}, src={src_str}, ethertype={et_str}, "
f"Data: {[hex(b) for b in frame.data]}, "
f"Length: {len(frame.data)}")
frame_filter = icsneopy.MessageFilter(icsneopy.Network.NetID.ETHERNET_02)
callback = icsneopy.MessageCallback(frame_handler, frame_filter)
device.add_message_callback(callback)
print("CAN frame reception configured")
print("Ethernet frame reception configured")
return 0
@@ -0,0 +1,218 @@
"""
FlexRay coldstart example using icsneopy library.
Demonstrates coldstart capability where one FlexRay device can start
the network without needing other devices connected.
CRITICAL COLDSTART REQUIREMENTS:
1. key_slot_used_for_startup = True
2. key_slot_used_for_sync = True
3. set_allow_coldstart(True)
4. Each controller needs a unique key_slot_id
5. Proper bus termination (required for FlexRay)
"""
import icsneopy
import time
def get_coldstart_controller_config(slot_id):
"""
Create FlexRay controller configuration for COLDSTART.
The three critical settings for coldstart are marked below.
"""
config = icsneopy.FlexRay.Controller.Configuration()
config.accept_startup_range_microticks = 160
config.allow_halt_due_to_clock = True
config.allow_passive_to_active_cycle_pairs = 15
config.cluster_drift_damping = 2
config.channel_a = True
config.channel_b = True
config.decoding_correction_microticks = 56
config.delay_compensation_a_microticks = 28
config.delay_compensation_b_microticks = 28
config.extern_offset_correction_control = 0
config.extern_rate_correction_control = 0
config.extern_offset_correction_microticks = 0
config.extern_rate_correction_microticks = 0
# CRITICAL FOR COLDSTART: Set the key slot ID
config.key_slot_id = slot_id
config.key_slot_only_enabled = False
# CRITICAL FOR COLDSTART: Enable startup and sync on key slot
config.key_slot_used_for_startup = True # Required for coldstart
config.key_slot_used_for_sync = True # Required for coldstart
config.latest_tx_minislot = 226
config.listen_timeout = 401202
config.macro_initial_offset_a = 7
config.macro_initial_offset_b = 7
config.micro_initial_offset_a = 36
config.micro_initial_offset_b = 36
config.micro_per_cycle = 200000
config.mts_on_a = False
config.mts_on_b = False
config.offset_correction_out_microticks = 189
config.rate_correction_out_microticks = 601
config.second_key_slot_id = 0
config.two_key_slot_mode = False
config.wakeup_pattern = 55
config.wakeup_on_channel_b = False
return config
def get_cluster_config():
"""Create FlexRay cluster configuration."""
config = icsneopy.FlexRay.Cluster.Configuration()
config.speed = icsneopy.FlexRay.Cluster.SpeedType.FLEXRAY_BAUDRATE_10M
config.strobe_point_position = icsneopy.FlexRay.Cluster.SPPType.FLEXRAY_SPP_5
config.action_point_offset = 4
config.casr_x_low_max = 64
config.cold_start_attempts = 8
config.cycle_duration_micro_sec = 5000
config.dynamic_slot_idle_phase_minislots = 1
config.listen_noise_macroticks = 4
config.macroticks_per_cycle = 5000
config.macrotick_duration_micro_sec = 1
config.max_without_clock_correction_fatal = 2
config.max_without_clock_correction_passive = 2
config.minislot_action_point_offset_macroticks = 4
config.minislot_duration_macroticks = 10
config.network_idle_time_macroticks = 40
config.network_management_vector_length_bytes = 1
config.number_of_minislots = 0
config.number_of_static_slots = 32
config.offset_correction_start_macroticks = 4991
config.payload_length_of_static_slot_in_words = 67
config.static_slot_macroticks = 155
config.symbol_window_macroticks = 0
config.symbol_window_action_point_offset_macroticks = 0
config.sync_frame_id_count_max = 15
config.transmission_start_sequence_duration_bits = 11
config.wakeup_rx_idle_bits = 40
config.wakeup_rx_low_bits = 40
config.wakeup_rx_window_bits = 301
config.wakeup_tx_active_bits = 60
config.wakeup_tx_idle_bits = 180
return config
def flexray_coldstart():
"""Perform FlexRay coldstart operation."""
devices = icsneopy.find_all_devices()
if not devices:
raise RuntimeError("No devices found")
# 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")
print(f"Using device: {device.get_product_name()} {device.get_serial()}")
try:
# Get FlexRay controllers
controllers = device.get_flexray_controllers()
if not controllers:
raise RuntimeError("Device has no FlexRay controllers")
print(f"Device has {len(controllers)} FlexRay controller(s)")
# Configure controllers for coldstart
cluster_config = get_cluster_config()
base_slot_id = 1
for i, controller in enumerate(controllers):
slot_id = base_slot_id + i
controller_config = get_coldstart_controller_config(slot_id)
print(f"\nConfiguring controller {i} for COLDSTART:")
print(f" Key Slot ID: {slot_id}")
print(f" Key Slot Used for Startup: {controller_config.key_slot_used_for_startup}")
print(f" Key Slot Used for Sync: {controller_config.key_slot_used_for_sync}")
# CRITICAL FOR COLDSTART: Enable coldstart capability
controller.set_allow_coldstart(True)
print(f" Allow Coldstart: True")
# Configure to start when going online
controller.set_start_when_going_online(True)
# Set the configuration
controller.set_configuration(cluster_config, controller_config)
# Open device
print("\nOpening device...")
if not device.open():
raise RuntimeError("Failed to open device")
print("Device opened successfully")
# Go online - this triggers coldstart
print("\nGoing online (coldstart will initiate)...")
if not device.go_online():
raise RuntimeError("Failed to go online - check bus termination and configuration")
print("Device online successfully!")
print("\n" + "=" * 60)
print("✓ FlexRay network started via COLDSTART")
print("=" * 60)
# Transmit test messages on the coldstart key slot
print("\nTransmitting initial test messages...")
for i in range(5):
frame = icsneopy.FlexRayMessage()
frame.network = icsneopy.Network(icsneopy.Network.NetID.FLEXRAY_01)
frame.slotid = base_slot_id # Use the first key slot
frame.cycle = 0
frame.cycle_repetition = 1
frame.channel = icsneopy.FlexRay.Channel.AB
frame.data = (0xAA, 0xBB, 0xCC, 0xDD, i, i+1, i+2, i+3)
if device.transmit(frame):
print(f" ✓ Transmitted message {i+1}")
else:
print(f" ✗ Failed to transmit message {i+1}")
time.sleep(0.1)
print("\n" + "=" * 60)
print("Network is now active and will stay alive.")
print("You can now run transmit/receive examples in another terminal.")
print("Press Ctrl+C to stop and shut down the network.")
print("=" * 60)
# Keep transmitting periodically to maintain network presence
counter = 0
try:
while True:
frame = icsneopy.FlexRayMessage()
frame.network = icsneopy.Network(icsneopy.Network.NetID.FLEXRAY_01)
frame.slotid = base_slot_id
frame.cycle = 0
frame.cycle_repetition = 1
frame.channel = icsneopy.FlexRay.Channel.AB
frame.data = (0xCA, 0xFE, 0xBA, 0xBE, counter & 0xFF,
(counter >> 8) & 0xFF, (counter >> 16) & 0xFF, (counter >> 24) & 0xFF)
device.transmit(frame)
counter += 1
time.sleep(1) # Transmit every second
except KeyboardInterrupt:
print("\n\nStopping coldstart node...")
print("\n✓ Coldstart example completed successfully!")
finally:
device.close()
if __name__ == "__main__":
flexray_coldstart()
@@ -0,0 +1,188 @@
# Basic FlexRay frame reception example using icsneopy library.
import icsneopy
import time
import signal
import sys
def get_controller_config(slot_id):
"""Create a FlexRay controller configuration matching the network.
Args:
slot_id: The key slot ID for this node (must be unique per node)
Returns:
FlexRay.Controller.Configuration with all parameters set
Note:
For passive listening on an existing network, set:
- key_slot_used_for_startup = False
- Remove set_allow_coldstart(True) call below
"""
config = icsneopy.FlexRay.Controller.Configuration()
config.accept_startup_range_microticks = 160
config.allow_halt_due_to_clock = True
config.allow_passive_to_active_cycle_pairs = 15
config.cluster_drift_damping = 2
# Physical channel configuration (Channel A only for this example)
config.channel_a = True
config.channel_b = False # Single channel A only
config.decoding_correction_microticks = 56
config.delay_compensation_a_microticks = 28
config.delay_compensation_b_microticks = 28
config.extern_offset_correction_control = 0
config.extern_rate_correction_control = 0
config.extern_offset_correction_microticks = 0
config.extern_rate_correction_microticks = 0
# KEY SLOT CONFIGURATION - Critical for FlexRay operation
config.key_slot_id = slot_id # Must be unique per node
config.key_slot_only_enabled = False
config.key_slot_used_for_startup = True # True = participate in coldstart
config.key_slot_used_for_sync = True # True = synchronize with network
config.latest_tx_minislot = 226
config.listen_timeout = 401202
config.macro_initial_offset_a = 7
config.macro_initial_offset_b = 7
config.micro_initial_offset_a = 36
config.micro_initial_offset_b = 36
config.micro_per_cycle = 200000
config.mts_on_a = False
config.mts_on_b = False
config.offset_correction_out_microticks = 189
config.rate_correction_out_microticks = 601
config.second_key_slot_id = 0
config.two_key_slot_mode = False
config.wakeup_pattern = 55
config.wakeup_on_channel_b = False
return config
def get_cluster_config():
"""Create a FlexRay cluster configuration matching the network."""
config = icsneopy.FlexRay.Cluster.Configuration()
config.speed = icsneopy.FlexRay.Cluster.SpeedType.FLEXRAY_BAUDRATE_10M
config.strobe_point_position = icsneopy.FlexRay.Cluster.SPPType.FLEXRAY_SPP_5
config.action_point_offset = 4
config.casr_x_low_max = 64
config.cold_start_attempts = 8
config.cycle_duration_micro_sec = 5000
config.dynamic_slot_idle_phase_minislots = 1
config.listen_noise_macroticks = 4
config.macroticks_per_cycle = 5000
config.macrotick_duration_micro_sec = 1
config.max_without_clock_correction_fatal = 2
config.max_without_clock_correction_passive = 2
config.minislot_action_point_offset_macroticks = 4
config.minislot_duration_macroticks = 10
config.network_idle_time_macroticks = 40
config.network_management_vector_length_bytes = 1
config.number_of_minislots = 0
config.number_of_static_slots = 32
config.offset_correction_start_macroticks = 4991
config.payload_length_of_static_slot_in_words = 67
config.static_slot_macroticks = 155
config.symbol_window_macroticks = 0
config.symbol_window_action_point_offset_macroticks = 0
config.sync_frame_id_count_max = 15
config.transmission_start_sequence_duration_bits = 11
config.wakeup_rx_idle_bits = 40
config.wakeup_rx_low_bits = 40
config.wakeup_rx_window_bits = 301
config.wakeup_tx_active_bits = 60
config.wakeup_tx_idle_bits = 180
return config
def receive_flexray_frames():
"""Receive FlexRay frames as passive node with callback handling."""
devices = icsneopy.find_all_devices()
if not devices:
raise RuntimeError("No devices found")
# 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")
frame_count = 0
running = True
def on_frame(frame):
nonlocal frame_count
if isinstance(frame, icsneopy.FlexRayMessage):
# Only show frames from slot 1 (filter out null frames)
if frame.slotid == 1:
frame_count += 1
# Nice formatted view of the frame
payload_hex = ' '.join([f'{b:02X}' for b in frame.data[:8]])
payload_dec = ' '.join([f'{b:3d}' for b in frame.data[:8]])
print(f"[Frame {frame_count:4d}] Slot: {frame.slotid:2d} | Cycle: {frame.cycle:2d} | "
f"Channel: {str(frame.channel):10s}")
print(f" Hex: [{payload_hex}]")
print(f" Dec: [{payload_dec}]\n")
def signal_handler(sig, frame):
nonlocal running
print("\nShutting down...")
running = False
signal.signal(signal.SIGINT, signal_handler)
signal.signal(signal.SIGTERM, signal_handler)
frame_filter = icsneopy.MessageFilter(icsneopy.Network.NetID.FLEXRAY_02)
callback = icsneopy.MessageCallback(on_frame, frame_filter)
try:
# Configure FlexRay controller 1 (FLEXRAY_02) as passive node
controllers = device.get_flexray_controllers()
if len(controllers) < 2:
raise RuntimeError("Device needs at least 2 FlexRay controllers")
controller = controllers[1] # Use controller 1
cluster_config = get_cluster_config()
controller_config = get_controller_config(slot_id=2)
# Enable coldstart so this node transmits and coldstart node sees activity
controller.set_allow_coldstart(True)
controller.set_configuration(cluster_config, controller_config)
controller.set_start_when_going_online(True)
if not device.open():
raise RuntimeError("Failed to open device")
if not device.go_online():
raise RuntimeError("Failed to go online")
device.add_message_callback(callback)
print("="*60)
print("FlexRay Receive Node - Coldstart Config Loaded")
print("="*60)
print(f"Controller: FLEXRAY_02 | Slot ID: 2 | Channel: A")
print(f"Listening for frames...")
print(f"Start the transmit script now to begin communication")
print("="*60)
print("Press Ctrl+C to stop\n")
while running:
time.sleep(0.1)
print(f"\nTotal frames received: {frame_count}")
finally:
device.close()
if __name__ == "__main__":
receive_flexray_frames()
@@ -0,0 +1,218 @@
# Basic FlexRay frame transmission example using icsneopy library.
import icsneopy
import time
import signal
import sys
import random
def get_controller_config(slot_id, is_coldstart=False):
"""Create a FlexRay controller configuration matching the network.
Args:
slot_id: The key slot ID for this node (must be unique per node)
is_coldstart: True if this node participates in coldstart
Returns:
FlexRay.Controller.Configuration with all parameters set
"""
config = icsneopy.FlexRay.Controller.Configuration()
config.accept_startup_range_microticks = 160
config.allow_halt_due_to_clock = True
config.allow_passive_to_active_cycle_pairs = 15
config.cluster_drift_damping = 2
# Physical channel configuration (Channel A only for this example)
config.channel_a = True
config.channel_b = False # Single channel A only
config.decoding_correction_microticks = 56
config.delay_compensation_a_microticks = 28
config.delay_compensation_b_microticks = 28
config.extern_offset_correction_control = 0
config.extern_rate_correction_control = 0
config.extern_offset_correction_microticks = 0
config.extern_rate_correction_microticks = 0
# KEY SLOT CONFIGURATION - Critical for FlexRay operation
config.key_slot_id = slot_id # Must be unique per node
config.key_slot_only_enabled = False
config.key_slot_used_for_startup = is_coldstart # True = coldstart node
config.key_slot_used_for_sync = is_coldstart # True = provides sync
config.latest_tx_minislot = 226
config.listen_timeout = 401202
config.macro_initial_offset_a = 7
config.macro_initial_offset_b = 7
config.micro_initial_offset_a = 36
config.micro_initial_offset_b = 36
config.micro_per_cycle = 200000
config.mts_on_a = False
config.mts_on_b = False
config.offset_correction_out_microticks = 189
config.rate_correction_out_microticks = 601
config.second_key_slot_id = 0
config.two_key_slot_mode = False
config.wakeup_pattern = 55
config.wakeup_on_channel_b = False
return config
def get_cluster_config():
"""Create a FlexRay cluster configuration matching the network.
All nodes on the FlexRay network must have identical cluster parameters.
These define the timing and structure of the FlexRay communication cycle.
Key parameters:
- cycle_duration_micro_sec: 5000 = 5ms cycle time
- macroticks_per_cycle: 5000 macroticks per cycle
- number_of_static_slots: 32 static slots for guaranteed transmission
- payload_length_of_static_slot_in_words: 67 words = 134 bytes max payload
Returns:
FlexRay.Cluster.Configuration with all timing parameters set
"""
config = icsneopy.FlexRay.Cluster.Configuration()
config.speed = icsneopy.FlexRay.Cluster.SpeedType.FLEXRAY_BAUDRATE_10M
config.strobe_point_position = icsneopy.FlexRay.Cluster.SPPType.FLEXRAY_SPP_5
config.action_point_offset = 4
config.casr_x_low_max = 64
config.cold_start_attempts = 8
config.cycle_duration_micro_sec = 5000
config.dynamic_slot_idle_phase_minislots = 1
config.listen_noise_macroticks = 4
config.macroticks_per_cycle = 5000
config.macrotick_duration_micro_sec = 1
config.max_without_clock_correction_fatal = 2
config.max_without_clock_correction_passive = 2
config.minislot_action_point_offset_macroticks = 4
config.minislot_duration_macroticks = 10
config.network_idle_time_macroticks = 40
config.network_management_vector_length_bytes = 1
config.number_of_minislots = 0
config.number_of_static_slots = 32
config.offset_correction_start_macroticks = 4991
config.payload_length_of_static_slot_in_words = 67
config.static_slot_macroticks = 155
config.symbol_window_macroticks = 0
config.symbol_window_action_point_offset_macroticks = 0
config.sync_frame_id_count_max = 15
config.transmission_start_sequence_duration_bits = 11
config.wakeup_rx_idle_bits = 40
config.wakeup_rx_low_bits = 40
config.wakeup_rx_window_bits = 301
config.wakeup_tx_active_bits = 60
config.wakeup_tx_idle_bits = 180
return config
def transmit_flexray_frame():
"""Transmit FlexRay frames as coldstart node."""
devices = icsneopy.find_all_devices()
if not devices:
raise RuntimeError("No devices found")
# 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")
running = True
def signal_handler(sig, frame):
nonlocal running
print("\nShutting down...")
running = False
signal.signal(signal.SIGINT, signal_handler)
signal.signal(signal.SIGTERM, signal_handler)
try:
# Configure FlexRay controller 0 (FLEXRAY_01) as coldstart node
controllers = device.get_flexray_controllers()
if not controllers:
raise RuntimeError("Device has no FlexRay controllers")
controller = controllers[0] # Use controller 0
cluster_config = get_cluster_config()
controller_config = get_controller_config(slot_id=1, is_coldstart=True)
# Enable coldstart capability
controller.set_allow_coldstart(True)
controller.set_configuration(cluster_config, controller_config)
controller.set_start_when_going_online(True)
if not device.open():
raise RuntimeError("Failed to open device")
if not device.go_online():
raise RuntimeError("Failed to go online")
print("="*60)
print("FlexRay Transmit Node - Starting Network")
print("="*60)
print(f"Controller: FLEXRAY_01 | Slot ID: 1 | Channel: A")
print(f"Transmitting frames continuously...")
print("="*60)
print("Press Ctrl+C to stop\n")
# Transmit frames continuously starting immediately
counter = 0
sensor_temp = 20.0 # Simulated temperature sensor
sensor_pressure = 100.0 # Simulated pressure sensor
while running:
# Create new frame each time (important for FlexRay)
frame = icsneopy.FlexRayMessage()
frame.network = icsneopy.Network(icsneopy.Network.NetID.FLEXRAY_01)
frame.slotid = 1
frame.cycle = 0
frame.cycle_repetition = 1
frame.channel = icsneopy.FlexRay.Channel.A
# Simulate realistic sensor data
sensor_temp += random.uniform(-0.5, 0.5) # Temperature varies
sensor_pressure += random.uniform(-2.0, 2.0) # Pressure varies
# Pack data: [status, counter, temp_high, temp_low, pressure_high, pressure_low, checksum_placeholder, sequence]
status_byte = 0xA0 | (counter % 16) # Status with rolling bits
temp_int = int(sensor_temp * 10) & 0xFFFF
pressure_int = int(sensor_pressure * 10) & 0xFFFF
frame.data = (
status_byte,
counter & 0xFF,
(temp_int >> 8) & 0xFF,
temp_int & 0xFF,
(pressure_int >> 8) & 0xFF,
pressure_int & 0xFF,
random.randint(0, 255), # Random data
(counter >> 8) & 0xFF
)
success = device.transmit(frame)
if counter % 100 == 0: # Print every 100th to reduce spam
if success:
print(f" [TX {counter}] Temp: {sensor_temp:.1f}°C | Pressure: {sensor_pressure:.1f} kPa")
else:
print(f" Frame {counter}: Failed to transmit")
counter += 1
time.sleep(0.005) # 5ms per cycle
print("\nTransmission complete!")
finally:
device.close()
if __name__ == "__main__":
transmit_flexray_frame()
@@ -0,0 +1,130 @@
"""
LiveData subscription and monitoring example using icsneopy library.
"""
import icsneopy
import time
from datetime import timedelta
def livedata_example():
"""Subscribe to and monitor LiveData signals."""
devices = icsneopy.find_all_devices()
if not devices:
raise RuntimeError("No devices found")
device = devices[0]
print(f"Using device: {device}")
try:
if not device.open():
raise RuntimeError("Failed to open device")
if not device.go_online():
raise RuntimeError("Failed to go online")
device.enable_message_polling()
# Create subscription message
msg = icsneopy.LiveDataCommandMessage()
msg.handle = icsneopy.get_new_handle()
msg.cmd = icsneopy.LiveDataCommand.SUBSCRIBE
msg.update_period = timedelta(milliseconds=500)
msg.expiration_time = timedelta(milliseconds=0)
# Subscribe to various LiveData signals
msg.append_signal_arg(icsneopy.LiveDataValueType.GPS_LATITUDE)
msg.append_signal_arg(icsneopy.LiveDataValueType.GPS_LONGITUDE)
msg.append_signal_arg(icsneopy.LiveDataValueType.GPS_ACCURACY)
msg.append_signal_arg(icsneopy.LiveDataValueType.DAQ_ENABLE)
msg.append_signal_arg(icsneopy.LiveDataValueType.MANUAL_TRIGGER)
msg.append_signal_arg(icsneopy.LiveDataValueType.TIME_SINCE_MSG)
print("\nSubscribing to LiveData signals...")
if not device.subscribe_live_data(msg):
raise RuntimeError(f"Subscription failed: {icsneopy.get_last_error()}")
print("Subscription successful")
print("\nMonitoring LiveData for 5 seconds...")
response_count = 0
start_time = time.time()
while time.time() - start_time < 5:
result = device.get_messages()
messages = result[0] if isinstance(result, tuple) else result
for m in messages:
if isinstance(m, icsneopy.LiveDataStatusMessage):
if m.handle == msg.handle:
print(f"\n[Status] Command: {m.requested_command}, Status: {m.status}")
elif isinstance(m, icsneopy.LiveDataValueMessage):
if m.handle == msg.handle:
response_count += 1
print(f"\n[Response #{response_count}]")
signal_names = ["GPS_LAT", "GPS_LON", "GPS_ACC",
"DAQ_EN", "MAN_TRIG", "TIME_SINCE"]
for idx, val in enumerate(m.values):
value = icsneopy.livedata_value_to_double(val)
name = signal_names[idx] if idx < len(signal_names) else f"Signal_{idx}"
print(f" {name:12s}: {value:10.2f}")
time.sleep(0.1)
print(f"\nReceived {response_count} response messages")
# Demonstrate setting values
print("\nSetting custom values...")
set_msg = icsneopy.LiveDataSetValueMessage()
set_msg.handle = icsneopy.get_new_handle()
set_msg.cmd = icsneopy.LiveDataCommand.SET_VALUE
# Set DAQ_ENABLE
value = icsneopy.livedata_double_to_value(1.0)
if value:
set_msg.append_set_value(icsneopy.LiveDataValueType.DAQ_ENABLE, value)
# Set MANUAL_TRIGGER
value = icsneopy.livedata_double_to_value(1.0)
if value:
set_msg.append_set_value(icsneopy.LiveDataValueType.MANUAL_TRIGGER, value)
if device.set_value_live_data(set_msg):
print("Values set successfully")
time.sleep(0.5)
# Check the results
result = device.get_messages()
messages = result[0] if isinstance(result, tuple) else result
for m in messages:
if isinstance(m, icsneopy.LiveDataStatusMessage):
if m.handle == set_msg.handle:
print(f" Set status: {m.status}")
# Keep device awake by resetting TIME_SINCE_MSG
print("\nResetting TIME_SINCE_MSG to keep device awake...")
reset_msg = icsneopy.LiveDataSetValueMessage()
reset_msg.handle = icsneopy.get_new_handle()
reset_msg.cmd = icsneopy.LiveDataCommand.SET_VALUE
value = icsneopy.livedata_double_to_value(0.0)
if value:
reset_msg.append_set_value(icsneopy.LiveDataValueType.TIME_SINCE_MSG, value)
if device.set_value_live_data(reset_msg):
print("TIME_SINCE_MSG reset to 0")
# Unsubscribe
print("\nUnsubscribing...")
if device.unsubscribe_live_data(msg.handle):
print("Unsubscribed successfully")
finally:
device.close()
print("\nDevice closed")
if __name__ == "__main__":
livedata_example()
+315
View File
@@ -0,0 +1,315 @@
"""
10BASE-T1S Settings Configuration Example
Demonstrates interactive T1S network configuration
"""
import icsneopy
def get_user_confirmation(prompt):
"""Get yes/no confirmation from user."""
response = input(f"{prompt} (y/n): ").strip().lower()
return response == 'y'
def select_networks(available_networks):
"""Let user select which networks to configure."""
print("\n" + "=" * 70)
print("Select T1S Networks to Configure")
print("=" * 70)
for i, net_id in enumerate(available_networks, 1):
print(f" [{i}] {net_id}")
response = input("\nEnter network numbers to configure (e.g., '1,3' or '1-3' or 'all'): ").strip().lower()
if not response:
return []
if response == 'all':
return available_networks
selected = []
tokens = response.split(',')
for token in tokens:
token = token.strip()
if '-' in token:
try:
parts = token.split('-')
start = int(parts[0])
end = int(parts[1])
for i in range(start, end + 1):
if 1 <= i <= len(available_networks):
selected.append(available_networks[i - 1])
except (ValueError, IndexError):
pass
else:
try:
num = int(token)
if 1 <= num <= len(available_networks):
selected.append(available_networks[num - 1])
except ValueError:
pass
return selected
def get_uint8_input(prompt, default_value):
"""Get uint8 input from user with default."""
response = input(f"{prompt} [{default_value}]: ").strip()
if not response:
return default_value
try:
val = int(response)
if 0 <= val <= 255:
return val
except ValueError:
pass
return default_value
def get_uint16_input(prompt, default_value):
"""Get uint16 input from user with default."""
response = input(f"{prompt} [{default_value}]: ").strip()
if not response:
return default_value
try:
val = int(response)
if 0 <= val <= 65535:
return val
except ValueError:
pass
return default_value
def opt_to_string(opt):
"""Convert optional value to string for display."""
if opt is None:
return "N/A"
if isinstance(opt, bool):
return "true" if opt else "false"
return str(opt)
def display_t1s_settings(device, network):
"""Display T1S settings for a network."""
print(f"\t{network} T1S Settings:")
settings = device.settings
if not settings:
print("\t Unable to read settings")
return
print(f"\t PLCA Enabled: {opt_to_string(settings.is_t1s_plca_enabled(network))}")
print(f"\t Local ID: {opt_to_string(settings.get_t1s_local_id(network))}")
print(f"\t Max Nodes: {opt_to_string(settings.get_t1s_max_nodes(network))}")
print(f"\t TX Opp Timer: {opt_to_string(settings.get_t1s_tx_opp_timer(network))}")
print(f"\t Max Burst: {opt_to_string(settings.get_t1s_max_burst(network))}")
print(f"\t Burst Timer: {opt_to_string(settings.get_t1s_burst_timer(network))}")
term_enabled = settings.is_t1s_termination_enabled(network)
if term_enabled is not None:
print(f"\t Termination: {opt_to_string(term_enabled)}")
local_id_alt = settings.get_t1s_local_id_alternate(network)
if local_id_alt is not None:
print(f"\t Local ID Alternate: {opt_to_string(local_id_alt)}")
print(f"\t Bus Dec Beacons: {opt_to_string(settings.is_t1s_bus_decoding_beacons_enabled(network))}")
print(f"\t Bus Dec All: {opt_to_string(settings.is_t1s_bus_decoding_all_enabled(network))}")
multi_id_mask = settings.get_t1s_multi_id_enable_mask(network)
if multi_id_mask is not None:
print(f"\t Multi-ID Mask: 0x{multi_id_mask:02X}")
print("\t Multi-IDs: ", end="")
multi_ids = []
for i in range(7):
multi_id = settings.get_t1s_multi_id(network, i)
multi_ids.append(f"[{i}]={opt_to_string(multi_id)}")
print(", ".join(multi_ids))
print()
def configure_t1s_network(device, network):
"""Interactively configure T1S settings for a network."""
print("\n" + "=" * 70)
print(f"Configuring T1S Network: {network}")
print("=" * 70)
settings = device.settings
if not settings:
print("Unable to read settings")
return
print("\n--- Basic PLCA Settings ---")
plca_enabled = get_user_confirmation("Enable PLCA")
settings.set_t1s_plca(network, plca_enabled)
local_id = get_uint8_input("Local ID (0-255)", 1)
settings.set_t1s_local_id(network, local_id)
max_nodes = get_uint8_input("Max Nodes (0-255)", 8)
settings.set_t1s_max_nodes(network, max_nodes)
tx_opp_timer = get_uint8_input("TX Opportunity Timer (0-255)", 20)
settings.set_t1s_tx_opp_timer(network, tx_opp_timer)
max_burst = get_uint16_input("Max Burst (0-65535)", 128)
settings.set_t1s_max_burst(network, max_burst)
burst_timer = get_uint16_input("Burst Timer (0-65535)", 64)
settings.set_t1s_burst_timer(network, burst_timer)
if settings.is_t1s_termination_enabled(network) is not None:
print("\n--- Termination Settings ---")
term_enabled = get_user_confirmation("Enable Termination")
settings.set_t1s_termination(network, term_enabled)
if settings.get_t1s_local_id_alternate(network) is not None:
print("\n--- Extended Settings ---")
local_id_alt = get_uint8_input("Local ID Alternate (0-255)", 0)
settings.set_t1s_local_id_alternate(network, local_id_alt)
bus_dec_beacons = get_user_confirmation("Enable Bus Decoding (Beacons)")
settings.set_t1s_bus_decoding_beacons(network, bus_dec_beacons)
bus_dec_all = get_user_confirmation("Enable Bus Decoding (All Symbols)")
settings.set_t1s_bus_decoding_all(network, bus_dec_all)
if get_user_confirmation("Configure Multi-ID settings?"):
multi_id_mask = get_uint8_input("Multi-ID Enable Mask (0x00-0xFF, hex)", 0x00)
settings.set_t1s_multi_id_enable_mask(network, multi_id_mask)
print("Configure Multi-IDs (7 slots):")
for i in range(7):
multi_id = get_uint8_input(f" Multi-ID [{i}]", 0)
settings.set_t1s_multi_id(network, i, multi_id)
print(f"\n[OK] Configuration staged for {network}")
def main():
"""Main T1S settings configuration example."""
device = None
try:
print("\n" + "=" * 70)
print("10BASE-T1S SETTINGS CONFIGURATION EXAMPLE")
print("=" * 70)
print(f"libicsneo {icsneopy.get_version()}")
print("=" * 70)
print("\nFinding devices... ", end="", flush=True)
devices = icsneopy.find_all_devices()
print(f"OK, {len(devices)} device{'s' if len(devices) != 1 else ''} found")
if not devices:
print("No devices found!")
return 1
for d in devices:
print(f" {d}")
device = None
for d in devices:
if d.get_type().get_device_type() == icsneopy.DeviceType.Enum.RADComet3:
device = d
break
if not device and devices:
device = devices[0]
if not device:
print("No suitable device found!")
return 1
print(f"\nSelected device: {device}")
print(f"Serial: {device.get_serial()}")
print("\nOpening device... ", end="", flush=True)
if not device.open():
print("FAIL")
return 1
print("OK")
settings = device.settings
t1s_networks = []
for net in device.get_supported_tx_networks():
if net.get_type() != icsneopy.Network.Type.AutomotiveEthernet:
continue
if settings.get_t1s_local_id(net) is not None:
t1s_networks.append(net)
if not t1s_networks:
print("No T1S networks found on this device")
device.close()
return 1
print(f"\nFound {len(t1s_networks)} T1S network{'s' if len(t1s_networks) != 1 else ''}:")
for i, net_id in enumerate(t1s_networks, 1):
print(f" [{i}] {net_id}")
print("\n" + "-" * 70)
print("Current T1S Settings:")
print("-" * 70)
for net_id in t1s_networks:
display_t1s_settings(device, net_id)
networks_to_config = select_networks(t1s_networks)
if not networks_to_config:
print("\nNo networks selected for configuration.")
print("Closing device... ", end="", flush=True)
device.close()
print("OK")
return 0
print(f"\nConfiguring {len(networks_to_config)} network{'s' if len(networks_to_config) != 1 else ''}...")
for net_id in networks_to_config:
configure_t1s_network(device, net_id)
print("\n" + "=" * 70)
save_to_eeprom = get_user_confirmation("Save settings to EEPROM (permanent)?")
print("=" * 70)
settings = device.settings
print(f"\nApplying settings{' to EEPROM' if save_to_eeprom else ' temporarily'}... ", end="", flush=True)
success = settings.apply(not save_to_eeprom)
if not success:
print("FAIL")
device.close()
return 1
print("OK")
print("\n" + "-" * 70)
print("Updated T1S Settings:")
print("-" * 70)
for net_id in t1s_networks:
display_t1s_settings(device, net_id)
print("Closing device... ", end="", flush=True)
device.close()
print("OK")
except KeyboardInterrupt:
print("\n\nInterrupted by user")
return 1
except Exception as e:
print(f"\nError: {e}")
import traceback
traceback.print_exc()
return 1
finally:
if device and device.is_open():
device.close()
return 0
if __name__ == "__main__":
exit(main())
+291
View File
@@ -0,0 +1,291 @@
"""
10BASE-T1S Symbol Decoding Example
Demonstrates T1S bus symbol decoding and analysis
"""
import icsneopy
import time
from enum import IntEnum
class T1SSymbol(IntEnum):
"""10BASE-T1S Symbol Types"""
SSD = 0x04
ESDOK = 0x07
BEACON = 0x08
ESD = 0x0D
ESDERR = 0x11
SYNC = 0x18
ESDJAB = 0x19
SILENCE = 0x1F
@classmethod
def get_name(cls, value):
"""Get human-readable name for symbol value."""
try:
return cls(value).name
except ValueError:
if 0x00 <= value <= 0x0F:
return f"DATA(0x{value:X})"
return f"UNKNOWN(0x{value:02X})"
def get_user_confirmation(prompt):
"""Get yes/no confirmation from user."""
response = input(f"{prompt} (y/n): ").strip().lower()
return response == 'y'
def configure_t1s_decoding(device, network, enable_symbols, enable_beacons):
"""Configure T1S bus decoding settings."""
settings = device.settings
if not settings:
raise RuntimeError("Failed to get device settings")
print(f"\nConfiguring T1S decoding on network {network}...")
if not settings.set_t1s_bus_decoding_all(network, enable_symbols):
raise RuntimeError("Failed to set T1S symbol decoding")
print(f" [{'X' if enable_symbols else ' '}] Decoding of all T1S symbols")
if not settings.set_t1s_bus_decoding_beacons(network, enable_beacons):
raise RuntimeError("Failed to set T1S beacon decoding")
print(f" [{'X' if enable_beacons else ' '}] T1S beacon decoding")
if not settings.apply(True):
raise RuntimeError("Failed to apply settings to device")
print(" [OK] Settings applied successfully")
def setup_symbol_monitoring(device, network):
"""Setup callback to monitor and decode T1S symbols."""
state = {
'symbol_count': 0,
'beacon_count': 0,
'wake_count': 0,
'burst_count': 0,
'symbol_stats': {},
'data_frame_count': 0
}
def symbol_handler(msg):
"""Handle incoming T1S messages."""
if not isinstance(msg, icsneopy.EthernetMessage):
return
if not msg.t1s:
return
timestamp_ms = msg.timestamp / 1000000.0
if msg.t1s.isSymbol:
num_symbols = len(msg.data)
print(f"[{timestamp_ms:12.3f} ms] T1S Symbols", end="")
if num_symbols > 0:
print(f" ({num_symbols} symbol{'s' if num_symbols > 1 else ''})", end="")
print(f" | Node ID: {msg.t1s.nodeId}")
for i, symbol_value in enumerate(msg.data):
symbol_name = T1SSymbol.get_name(symbol_value)
state['symbol_count'] += 1
if symbol_name not in state['symbol_stats']:
state['symbol_stats'][symbol_name] = 0
state['symbol_stats'][symbol_name] += 1
if symbol_value == T1SSymbol.BEACON:
state['beacon_count'] += 1
print(f" [{i}] {symbol_name:10s} = 0x{symbol_value:02X}")
if num_symbols == 0 and msg.t1s.symbolType != 0:
symbol_value = msg.t1s.symbolType
symbol_name = T1SSymbol.get_name(symbol_value)
state['symbol_count'] += 1
if symbol_name not in state['symbol_stats']:
state['symbol_stats'][symbol_name] = 0
state['symbol_stats'][symbol_name] += 1
if symbol_value == T1SSymbol.BEACON:
state['beacon_count'] += 1
print(f" {symbol_name:10s} = 0x{symbol_value:02X} (from t1sSymbolType field)")
elif msg.t1s.isBurst:
state['burst_count'] += 1
print(f"[{timestamp_ms:12.3f} ms] BURST | "
f"Node ID: {msg.t1s.nodeId} | "
f"Burst Count: {msg.t1s.burstCount}")
elif msg.t1s.isWake:
state['wake_count'] += 1
print(f"[{timestamp_ms:12.3f} ms] WAKE signal detected | "
f"Node ID: {msg.t1s.nodeId}")
else:
state['data_frame_count'] += 1
print(f"[{timestamp_ms:12.3f} ms] T1S Data Frame | "
f"Length: {len(msg.data)} bytes | "
f"Node ID: {msg.t1s.nodeId}")
if msg.data and len(msg.data) > 0:
preview = ' '.join([f"{b:02X}" for b in msg.data[:16]])
if len(msg.data) > 16:
preview += " ..."
print(f" Data: {preview}")
frame_filter = icsneopy.MessageFilter(network.get_net_id())
callback = icsneopy.MessageCallback(symbol_handler, frame_filter)
device.add_message_callback(callback)
return state
def print_statistics(state):
"""Print monitoring statistics."""
print("\n" + "=" * 70)
print("T1S SYMBOL DECODING STATISTICS")
print("=" * 70)
print(f"Total Symbols: {state['symbol_count']}")
print(f"Total Beacons: {state['beacon_count']}")
print(f"Total Wake Signals: {state['wake_count']}")
print(f"Total Bursts: {state['burst_count']}")
print(f"Total Data Frames: {state['data_frame_count']}")
if state['symbol_stats']:
print("\n" + "-" * 70)
print("Symbol Type Breakdown:")
print("-" * 70)
for symbol_name, count in sorted(state['symbol_stats'].items(),
key=lambda x: x[1], reverse=True):
print(f" {symbol_name:20s}{count:>10d}")
print("=" * 70)
def main():
"""Main T1S symbol decoding example."""
device = None
try:
MONITOR_DURATION = 30
print("\n" + "=" * 70)
print("10BASE-T1S SYMBOL DECODING EXAMPLE")
print("=" * 70)
print(f"libicsneo {icsneopy.get_version()}")
print("=" * 70)
print("\nFinding devices... ", end="", flush=True)
devices = icsneopy.find_all_devices()
print(f"OK, {len(devices)} device{'s' if len(devices) != 1 else ''} found")
if not devices:
print("No devices found!")
return 1
for d in devices:
print(f" {d}")
device = None
for d in devices:
if d.get_type().get_device_type() == icsneopy.DeviceType.Enum.RADComet3:
device = d
break
if not device and devices:
device = devices[0]
if not device:
print("No suitable device found!")
return 1
print(f"\nSelected device: {device}")
print(f"Serial: {device.get_serial()}")
print("\n" + "-" * 70)
print("T1S DECODING CONFIGURATION")
print("-" * 70)
enable_symbols = get_user_confirmation("Enable T1S symbol decoding (all symbols)")
enable_beacons = get_user_confirmation("Enable T1S beacon decoding")
print("-" * 70)
print("\nOpening device... ", end="", flush=True)
if not device.open():
print("FAIL")
return 1
print("OK")
print("Enabling message polling... ", end="", flush=True)
if not device.enable_message_polling():
print("FAIL")
device.close()
return 1
device.set_polling_message_limit(100000)
print("OK")
monitor_network = None
settings = device.settings
for net in device.get_supported_rx_networks():
if net.get_type() != icsneopy.Network.Type.AutomotiveEthernet:
continue
if settings.get_t1s_local_id(net) is not None:
monitor_network = net
break
if monitor_network is None:
print("No T1S network found on this device")
device.close()
return 1
print(f"Monitoring network: {monitor_network}")
configure_t1s_decoding(device, monitor_network, enable_symbols, enable_beacons)
print("Going online... ", end="", flush=True)
if not device.go_online():
print("FAIL")
device.close()
return 1
print("OK")
state = setup_symbol_monitoring(device, monitor_network)
print("\n" + "-" * 70)
print(f"Monitoring T1S traffic for {MONITOR_DURATION} seconds...")
print("-" * 70)
start_time = time.time()
while time.time() - start_time < MONITOR_DURATION:
device.get_messages()
time.sleep(0.01)
print("\n" + "-" * 70)
print("Closing device... ", end="", flush=True)
device.close()
time.sleep(0.1)
print("OK")
print_statistics(state)
except KeyboardInterrupt:
print("\n\nMonitoring interrupted by user")
if 'state' in locals():
print_statistics(state)
except Exception as e:
print(f"\nError: {e}")
import traceback
traceback.print_exc()
return 1
finally:
if device and device.is_open():
device.close()
return 0
if __name__ == "__main__":
exit(main())
+2
View File
@@ -165,6 +165,8 @@ public:
ServdPollError = ServdBindError + 8,
ServdNoDataError = ServdBindError + 9,
ServdJoinMulticastError = ServdBindError + 10,
ServdNotReachable = ServdBindError + 11,
ServdNoDevicesFound = ServdBindError + 12,
// DXX
DXXErrorSys = 0x6100,
+1
View File
@@ -55,6 +55,7 @@ enum class ExtendedCommand : uint16_t {
GetSupportedFeatures = 0x0018,
GetGPTPStatus = 0x0019,
GetComponentVersions = 0x001A,
SoftwareUpdate = 0x001B,
Reboot = 0x001C,
SetRootFSEntryFlags = 0x0027,
TransmitCoreminiMessage = 0x0028,
+8 -6
View File
@@ -1,6 +1,8 @@
#ifndef __ICSNEO_IO_H_
#define __ICSNEO_IO_H_
#include <icsneo/icsneoc2types.h>
typedef struct _neomiscio_t {
size_t number;
bool supportsDigitalIn;
@@ -19,12 +21,12 @@ namespace icsneo {
using MiscIO = neomiscio_t;
enum class IO {
EthernetActivation = 0, // The DoIP activation line, 0 is HiZ and 1 is pulled up to VBAT
USBHostPower = 1,
BackupPowerEnabled = 2, // The FIRE 2's backup super capacitor
BackupPowerGood = 3, // Whether or not the FIRE 2's backup super capacitor is charged (read only)
Misc = 4, // General purpose IO on the device
EMisc = 5, // Extended general purpose IO on the device
EthernetActivation = icsneoc2_io_type_eth_activation, // The DoIP activation line, 0 is HiZ and 1 is pulled up to VBAT
USBHostPower = icsneoc2_io_type_usb_host_power,
BackupPowerEnabled = icsneoc2_io_type_backup_power_en, // The FIRE 2's backup super capacitor
BackupPowerGood = icsneoc2_io_type_backup_power_good, // Whether or not the FIRE 2's backup super capacitor is charged (read only)
Misc = icsneoc2_io_type_misc, // General purpose IO on the device
EMisc = icsneoc2_io_type_emisc, // Extended general purpose IO on the device
};
// Note that the C API does a static cast between this and neoio_t so keep them in sync!
+2 -1
View File
@@ -5,6 +5,7 @@
#include <cstdint>
#include <vector>
#include <memory>
#include <optional>
#include "icsneo/communication/command.h"
#include "icsneo/api/eventmanager.h"
@@ -157,7 +158,7 @@ namespace LiveDataUtil
LiveDataHandle getNewHandle();
double liveDataValueToDouble(const LiveDataValue& val);
bool liveDataDoubleToValue(const double& dFloat, LiveDataValue& value);
std::optional<LiveDataValue> liveDataDoubleToValue(const double& dFloat);
static constexpr uint32_t LiveDataVersion = 1;
} // namespace LiveDataUtil
@@ -4,24 +4,24 @@
#ifdef __cplusplus
#include "icsneo/communication/message/message.h"
#include "icsneo/icsneoc2types.h"
namespace icsneo {
enum class CANErrorCode : uint8_t
enum class CANErrorCode : icsneoc2_can_error_code_t
{
NoError = 0,
StuffError = 1,
FormError = 2,
AckError = 3,
Bit1Error = 4,
Bit0Error = 5,
CRCError = 6,
NoChange = 7
NoError = icsneoc2_can_error_code_no_error,
StuffError = icsneoc2_can_error_code_stuff_error,
FormError = icsneoc2_can_error_code_form_error,
AckError = icsneoc2_can_error_code_ack_error,
Bit1Error = icsneoc2_can_error_code_bit1_error,
Bit0Error = icsneoc2_can_error_code_bit0_error,
CRCError = icsneoc2_can_error_code_crc_error,
NoChange = icsneoc2_can_error_code_no_change
};
class CANErrorMessage : public Message {
class CANErrorMessage : public RawMessage {
public:
CANErrorMessage() : Message(Type::CANError) {}
Network network;
CANErrorMessage() : RawMessage(Type::CANError) {}
uint8_t transmitErrorCount;
uint8_t receiveErrorCount;
bool busOff;
@@ -16,6 +16,9 @@ public:
bool isCANFD = false;
bool baudrateSwitch = false; // CAN FD only
bool errorStateIndicator = false; // CAN FD only
bool txAborted = false;
bool txLostArb = false;
bool txError = false;
};
}
@@ -4,49 +4,89 @@
#ifdef __cplusplus
#include "icsneo/communication/message/message.h"
// Used for MACAddress.toString() only
#include <array>
#include <string>
#include <vector>
#include <sstream>
#include <iomanip>
#include <cstring>
#include <optional>
namespace icsneo {
struct MACAddress {
uint8_t data[6];
// Helpers
std::string toString() const {
std::stringstream ss;
for(size_t i = 0; i < 6; i++) {
ss << std::hex << std::setw(2) << std::setfill('0') << (int)data[i];
if(i != 5)
ss << ':';
}
return ss.str();
}
friend std::ostream& operator<<(std::ostream& os, const MACAddress& mac) {
os << mac.toString();
return os;
}
};
using MACAddress = std::array<uint8_t, 6>;
class EthernetMessage : public Frame {
public:
bool preemptionEnabled = false;
uint8_t preemptionFlags = 0;
// Standard Ethernet fields
// Frame Check Sequence
std::optional<uint32_t> fcs;
bool frameTooShort = false;
bool noPadding = false;
bool fcsVerified = false;
bool txAborted = false;
bool crcError = false;
// T1S-specific fields
struct T1S {
T1S() {}
// Accessors
const MACAddress& getDestinationMAC() const { return *(const MACAddress*)(data.data() + 0); }
const MACAddress& getSourceMAC() const { return *(const MACAddress*)(data.data() + 6); }
uint16_t getEtherType() const { return (data[12] << 8) | data[13]; }
bool isSymbol = false;
bool isBurst = false;
bool txCollision = false;
bool isWake = false;
uint8_t nodeId = 0;
uint8_t burstCount = 0;
uint8_t symbolType = 0;
};
std::optional<T1S> t1s;
// TSN-specific fields
// If we expand TSN we should probably do something similar to what we did above with T1S.
// IEEE 802.1Qbu frame preemption
std::optional<uint8_t> preemptionFlags;
// Helper functions to extract Destination MAC from the data payload
// returns std::nullopt if the data payload is not large enough
std::optional<MACAddress> getDestinationMAC() const {
if(data.size() < 6) {
return std::nullopt;
}
MACAddress mac;
std::copy(data.begin(), data.begin() + 6, mac.begin());
return mac;
}
// Helper functions to extract Source MAC from the data payload
// returns std::nullopt if the data payload is not large enough
std::optional<MACAddress> getSourceMAC() const {
if(data.size() < 12) {
return std::nullopt;
}
MACAddress mac;
std::copy(data.begin() + 6, data.begin() + 12, mac.begin());
return mac;
}
// Helper function to extract EtherType from the data payload
//
// EtherType is a two-octet field in an Ethernet frame (big-endian).
// It is used to indicate which protocol is encapsulated in the payload of the frame
// and is used at the receiving end by the data link layer to determine how the payload is processed.
// For example, an EtherType of 0x0800 indicates that the payload is an IPv4 packet, while 0x86DD indicates an IPv6 packet.
//
// returns std::nullopt if the data payload is not large enough
std::optional<uint16_t> getEtherType() const {
if(data.size() < 14) {
return std::nullopt;
}
// EtherType is stored in a 2-byte network byte order (big-endian)
return static_cast<uint16_t>((uint16_t(data[12]) << 8) | uint16_t(data[13]));
}
};
}
#endif // __cplusplus
#endif
#endif // __ETHERNETMESSAGE_H_
@@ -10,8 +10,8 @@ namespace icsneo {
class ExtendedResponseMessage : public Message {
public:
ExtendedResponseMessage(ExtendedCommand cmd, ExtendedResponse resp = ExtendedResponse::OK)
: Message(Message::Type::ExtendedResponse), command(cmd), response(resp) {}
ExtendedResponseMessage(ExtendedCommand cmd, ExtendedResponse resp = ExtendedResponse::OK, const std::vector<uint8_t>& buf = {})
: Message(Message::Type::ExtendedResponse), command(cmd), response(resp), data(buf) {}
const ExtendedCommand command;
const ExtendedResponse response;

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